length proof working

This commit is contained in:
jude 2023-04-26 14:49:10 +01:00
parent 7591c84823
commit 9e4a57605d
4 changed files with 147 additions and 18 deletions

View File

@ -322,16 +322,131 @@ export function proveBitLength(cipherText) {
m >>= 1n; m >>= 1n;
} }
// TODO finish this let bitProofs = [];
for (let bitCommitment of bitCommitments) {
let p = proveOneOfTwo(bitCommitment);
bitProofs.push(p);
}
return { return {
cipherText: cipherText,
bitCommitments: bitCommitments, bitCommitments: bitCommitments,
bitProof: prod.proveNI(), prodProof: prod.proveNI(),
bitProofs: bitProofs,
}; };
} }
window.proveBitLength = proveBitLength; window.proveBitLength = proveBitLength;
export function verifyBitLength(obj, key) {
// Check product is fine
let prod = new ReadOnlyCiphertext(key, BigInt(obj.cipherText));
let m = 1n;
for (let bit of obj.bitCommitments) {
let cBit = new ReadOnlyCiphertext(key, BigInt(bit));
cBit.mul(m);
prod.update(cBit);
m >>= 1n;
}
let p = prod.verifyNI(obj.prodProof);
if (p !== 0n) {
return null;
}
for (let proof of obj.bitProofs) {
let r = verifyOneOfTwo(proof, key);
if (!r) {
return null;
}
}
return obj.bitCommitments.length;
}
window.verifyBitLength = verifyBitLength;
/**
* Prove that a ciphertext is either a 0 or a -1
*/
function proveOneOfTwo(cipherText) {
let key = cipherText.pubKey;
let proofs = [];
for (let x = 0; x < ROUNDS; x++) {
proofs.push({
cs: cryptoShuffle([key.encrypt(0n), key.encrypt(1n)]),
});
}
let verifications = [];
let coins = getCoins(JSON.stringify(proofs));
for (let x = 0; x < ROUNDS; x++) {
let coin = coins[x];
let proof = proofs[x];
if (coin === 1) {
verifications.push({
cProofs: proof.cs.map((p) => p.proveNI()),
});
} else {
let c1Index = proof.cs.findIndex((c) => c.plainText === 1n);
let c1 = proof.cs[c1Index].clone();
c1.update(cipherText);
verifications.push({
csIndex: c1Index,
zeroProof: c1.proveNI(),
});
}
}
return {
cipherText: cipherText,
proofs: proofs,
verifications: verifications,
};
}
window.proveOneOfTwo = proveOneOfTwo;
function verifyOneOfTwo(obj, key) {
let coins = getCoins(JSON.stringify(obj.proofs));
for (let x = 0; x < ROUNDS; x++) {
let coin = coins[x];
let proof = obj.proofs[x];
let verification = obj.verifications[x];
if (coin === 1) {
let c1 = new ReadOnlyCiphertext(key, BigInt(proof.cs[0]));
let p1 = c1.verifyNI(verification.cProofs[0]);
let c2 = new ReadOnlyCiphertext(key, BigInt(proof.cs[1]));
let p2 = c2.verifyNI(verification.cProofs[1]);
if (!(p1 === 0n && p2 === 1n) && !(p2 === 0n && p1 === 1n)) {
return false;
}
} else {
let c = new ReadOnlyCiphertext(key, BigInt(proof.cs[verification.csIndex]));
c.update(obj.cipherText);
let p = c.verifyNI(verification.zeroProof);
if (p !== 0n) {
return false;
}
}
}
return true;
}
window.verifyOneOfTwo = verifyOneOfTwo;
/** /**
* - We prove that the set contains |S| - 2 zeros, with the final pair summing to zero and sums with the original * - We prove that the set contains |S| - 2 zeros, with the final pair summing to zero and sums with the original
* set are zero. * set are zero.

View File

@ -450,10 +450,18 @@ doi={10.1109/SP.2014.36}}
@INPROCEEDINGS{upnp, @INPROCEEDINGS{upnp,
author={Esnaashari, Shadi and Welch, Ian and Komisarczuk, Peter}, author={Esnaashari, Shadi and Welch, Ian and Komisarczuk, Peter},
booktitle={2013 27th International Conference on Advanced Information Networking and Applications Workshops}, booktitle={2013 27th International Conference on Advanced Information Networking and Applications Workshops},
title={Determining Home Users' Vulnerability to Universal Plug and Play (UPnP) Attacks}, title={Determining Home Users' Vulnerability to Universal Plug and Play (UPnP) Attacks},
year={2013}, year={2013},
volume={}, volume={},
number={}, number={},
pages={725-729}, pages={725-729},
doi={10.1109/WAINA.2013.225}} doi={10.1109/WAINA.2013.225}}
@phdthesis{bulletproofs,
author = {Hasan, Jahid and Xu, Minghai},
year = {2020},
month = {06},
pages = {},
title = {Bulletproofs: A Non-Interactive Zero Knowledge Proof Protocol For Blockchain Security}
}

Binary file not shown.

View File

@ -90,7 +90,7 @@
\vspace*{0.1\paperheight} \vspace*{0.1\paperheight}
\begin{center} \begin{center}
"Never create anything, it will be misinterpreted, it will chain you and follow you for the rest of your life." - Hunter S. Thompson "Never create anything, it will be misinterpreted, it will chain you and follow you for the rest of your life." - Hunter S. Thompson
\vspace*{0.05\paperheight} \vspace*{0.05\paperheight}
Artefact available at \url{https://gitea.jellypro.xyz/jude/Riskless} Artefact available at \url{https://gitea.jellypro.xyz/jude/Riskless}
\end{center} \end{center}
@ -232,7 +232,17 @@ These are utilised to construct and verify transactions called \texttt{POUR}s. A
Zerocash then uses zk-SNARKs as a means to prove that the value of the inputs into a \texttt{POUR} is the same as the value of the outputs. This prevents users from generating "debt", or from generating value without going through a minting process (also defined in the Zerocash spec). Zerocash then uses zk-SNARKs as a means to prove that the value of the inputs into a \texttt{POUR} is the same as the value of the outputs. This prevents users from generating "debt", or from generating value without going through a minting process (also defined in the Zerocash spec).
A similar issue appears in the proposed system: a cheating player could update the weights on their graph to cause a region to be "in debt". Therefore, we need the protocol to ensure players prove that the sum of all edges is equal to how many units the player has in play (a well-known value). A similar issue appears in the proposed system: a cheating player could update the weights on their graph to cause a region to be "in debt". This can be achieved by using range proofs.
The BCDG range proof proves that a commitment to a plaintext in the interval $[0, \ell]$ lies within the interval $[-\ell, 2\ell]$, where $\ell$ is some well-known value \cite[Section~2]{bcdg1987}.
The distinction between the soundness and completeness intervals in the BCDG proof is important, as through selection of specific private inputs, a prover can create a proof for a plaintext $m$ in the soundness interval and not the completeness interval. In this case, the proof is also not in zero-knowledge, as the verifier may be able to infer a stronger upper or lower bound on $m$. This is a major downside to this protocol.
The state of the art in range proofs is Bulletproofs \cite{bulletproofs}. Bulletproofs are utilised by the Monero blockchain ledger, and use linear algebraic properties to allow multiple verifying parties to process a single prover's proof.
Bulletproofs have advantages in size and "batch verification", where a verifier can verify multiple proofs simultaneously. However, the proofs are very complex, and a multi-round approach that borrows some of the concepts used in Bulletproofs could be used instead.
In general, this approach uses a decomposition of the plaintext message $m$ into its bits. This allows a verifying party to reconstruct an encryption of $m$, and check the bit length, without discovering $m$ \cite[Section~1.2.1]{Boudot2000EfficientPT}.
\subsubsection{Additive homomorphic cryptosystems} \subsubsection{Additive homomorphic cryptosystems}
@ -770,11 +780,7 @@ In practice, as we are using Jurik's form of Paillier, this is computational zer
\subsection{Range proof} \subsection{Range proof}
The BCDG proof proves that an encryption of a plaintext in the interval $[0, \ell]$ lies within the interval $[-\ell, 2\ell]$, where $\ell$ is some well-known value \cite[Section~2]{bcdg1987}. The range proof we use proves an upper bound on $|m|$ by constructing commitments to the bits of $m$, and using homomorphic properties \cite[Section~1.2.1]{Boudot2000EfficientPT}. Given valid encryptions of a sequence of bits, we can reconstruct the number: let $b_1, \dots, b_{|m|}$ be the bits of $m$ ($b_1$ being the LSB), and $c_i = E(b_i) = g^{b_i} r^n \mod n^2$. Then, we can construct an encryption of $m$ as \begin{align*}
The distinction between the soundness and completeness intervals is important, as through selection of specific private inputs, a prover can create a proof for a plaintext $m$ in the soundness interval and not the completeness interval. In this case, the proof is also not in zero-knowledge, as the verifier may be able to infer a stronger upper or lower bound on $m$.
An alternative approach involves proving an upper bound on $|m|$ by constructing commitments to the bits of $m$, and using homomorphic properties \cite[Section~1.2.1]{Boudot2000EfficientPT}. Given valid encryptions of a sequence of bits, we can reconstruct the number: let $b_1, \dots, b_{|m|}$ be the bits of $m$ ($b_1$ being the LSB), and $c_i = E(b_i) = g^{b_i} r^n \mod n^2$. Then, we can construct an encryption of $m$ as \begin{align*}
E(m) = (c_1)^{(2^0)} \cdot (c_2)^{(2^1)} \cdot (c_3)^{(2^2)} \cdot \ldots \cdot (c_{|m|})^{(2^{|m| - 1})}. E(m) = (c_1)^{(2^0)} \cdot (c_2)^{(2^1)} \cdot (c_3)^{(2^2)} \cdot \ldots \cdot (c_{|m|})^{(2^{|m| - 1})}.
\end{align*} \end{align*}
@ -782,18 +788,18 @@ Validating $E(m)$ is done with the proof of zero. Then it remains to prove that
\begin{protocol}\label{protocol4} \begin{protocol}\label{protocol4}
The prover transmits $c = E(m)$, and encryptions of the bits $c_1, \dots, c_{|m|}$, except using $-1$ in place of $1$. The prover transmits $c = E(m)$, and encryptions of the bits $c_1, \dots, c_{|m|}$, except using $-1$ in place of $1$.
\begin{enumerate} \begin{enumerate}
\item The verifier computes \begin{align*} \item The verifier computes \begin{align*}
c \cdot \prod_i^{|m|} (c_i)^{(2^{i-1})} c \cdot \prod_i^{|m|} (c_i)^{(2^{i-1})}
\end{align*} and requests a proof of zero. \end{align*} and requests a proof of zero.
\item Perform $t$ times for each $i$: \begin{enumerate} \item Perform $t$ times for each $i$: \begin{enumerate}
\item Prover transmits $S = \{ E(0), E(1) \}$. \item Prover transmits $S = \{ E(0), E(1) \}$.
\item Verifier picks $a \in_R \{ 0, 1 \}$. \begin{enumerate} \item Verifier picks $a \in_R \{ 0, 1 \}$. \begin{enumerate}
\item If $a = 0$, the verifier requests a proof that $S = \{ 0, 1 \}$. \item If $a = 0$, the verifier requests a proof that $S = \{ 0, 1 \}$.
\item If $a = 1$, the verifier requests a proof that $c_i \cdot s_i$ is zero for one of the $s_i \in S$. \item If $a = 1$, the verifier requests a proof that $c_i \cdot s_i$ is zero for one of the $s_i \in S$.
\end{enumerate} \end{enumerate}
\end{enumerate} \end{enumerate}
@ -907,7 +913,7 @@ We combine some ideas from the graph isomorphism proofs with ideas from before t
\begin{enumerate} \begin{enumerate}
\item Prover transmits $\{ (\psi(R_i), E(-n_i, r_i^*)) \mid 0 < i \leq N \}$ where $\psi$ is a random bijection on the regions, and $\{ H(R_i, R_j, s_{ij}) \mid R_i \text{ neighbours } R_j \}$ where $s_{ij}$ is a random salt. \item Prover transmits $\{ (\psi(R_i), E(-n_i, r_i^*)) \mid 0 < i \leq N \}$ where $\psi$ is a random bijection on the regions, and $\{ H(R_i, R_j, s_{ij}) \mid R_i \text{ neighbours } R_j \}$ where $s_{ij}$ is a random salt.
\item Verifier chooses a random $c \in \{0, 1\}$. \begin{enumerate} \item Verifier chooses a random $c \in \{0, 1\}$. \begin{enumerate}
\item If $c = 0$, the verifier requests the definition of $\psi$ and each salt. They check that the resulting graph is isomorphic to the original graph. They then compute $E(n_i, r_i) \cdot E(-n_i, r_i^*)$ for each $i$ and request a proof that each is zero. Finally, they compute each edge hash and check that there are precisely the correct number of hashes. \item If $c = 0$, the verifier requests the definition of $\psi$ and each salt. They check that the resulting graph is isomorphic to the original graph. They then compute $E(n_i, r_i) \cdot E(-n_i, r_i^*)$ for each $i$ and request a proof that each is zero. Finally, they compute each edge hash and check that there are precisely the correct number of hashes.
@ -1076,7 +1082,7 @@ All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, u
\section{Contributions} \section{Contributions}
This project has contributed an implementation of an optimised form of Paillier that is compatible with modern web browsers. It is evident that, considering current hardware, Paillier in Jurik's form is a viable cryptosystem. This project has contributed an implementation of an optimised form of Paillier that is compatible with modern web browsers. It is evident that, considering current hardware, Paillier in Jurik's form is a viable cryptosystem.
The Paillier implementation provides means for Schnorr-style proofs of knowledge and also multi-round proofs of knowledge, which serialise to JSON. These are made non-interactive by applying the SHAKE cryptographic hash suite to reduce program complexity and communication cost. The Paillier implementation provides means for Schnorr-style proofs of knowledge and also multi-round proofs of knowledge, which serialise to JSON. These are made non-interactive by applying the SHAKE cryptographic hash suite to reduce program complexity and communication cost.