diff --git a/static/js/modules/interface/proofs.js b/static/js/modules/interface/proofs.js index 70e2045..123bc15 100644 --- a/static/js/modules/interface/proofs.js +++ b/static/js/modules/interface/proofs.js @@ -322,16 +322,131 @@ export function proveBitLength(cipherText) { m >>= 1n; } - // TODO finish this + let bitProofs = []; + + for (let bitCommitment of bitCommitments) { + let p = proveOneOfTwo(bitCommitment); + bitProofs.push(p); + } return { + cipherText: cipherText, bitCommitments: bitCommitments, - bitProof: prod.proveNI(), + prodProof: prod.proveNI(), + bitProofs: bitProofs, }; } 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 * set are zero. diff --git a/whitepaper/Dissertation.bib b/whitepaper/Dissertation.bib index 4003bbb..51d744a 100644 --- a/whitepaper/Dissertation.bib +++ b/whitepaper/Dissertation.bib @@ -450,10 +450,18 @@ doi={10.1109/SP.2014.36}} @INPROCEEDINGS{upnp, author={Esnaashari, Shadi and Welch, Ian and Komisarczuk, Peter}, - booktitle={2013 27th International Conference on Advanced Information Networking and Applications Workshops}, - title={Determining Home Users' Vulnerability to Universal Plug and Play (UPnP) Attacks}, + booktitle={2013 27th International Conference on Advanced Information Networking and Applications Workshops}, + title={Determining Home Users' Vulnerability to Universal Plug and Play (UPnP) Attacks}, year={2013}, volume={}, number={}, pages={725-729}, - doi={10.1109/WAINA.2013.225}} \ No newline at end of file + 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} +} \ No newline at end of file diff --git a/whitepaper/Dissertation.pdf b/whitepaper/Dissertation.pdf index 684dc16..078f79b 100644 Binary files a/whitepaper/Dissertation.pdf and b/whitepaper/Dissertation.pdf differ diff --git a/whitepaper/Dissertation.tex b/whitepaper/Dissertation.tex index c1921d7..6b05495 100644 --- a/whitepaper/Dissertation.tex +++ b/whitepaper/Dissertation.tex @@ -90,7 +90,7 @@ \vspace*{0.1\paperheight} \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 - + \vspace*{0.05\paperheight} Artefact available at \url{https://gitea.jellypro.xyz/jude/Riskless} \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). -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} @@ -770,11 +780,7 @@ In practice, as we are using Jurik's form of Paillier, this is computational zer \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 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*} +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*} 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*} @@ -782,18 +788,18 @@ Validating $E(m)$ is done with the proof of zero. Then it remains to prove that \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$. - + \begin{enumerate} \item The verifier computes \begin{align*} c \cdot \prod_i^{|m|} (c_i)^{(2^{i-1})} \end{align*} and requests a proof of zero. - + \item Perform $t$ times for each $i$: \begin{enumerate} \item Prover transmits $S = \{ E(0), E(1) \}$. - + \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 = 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} @@ -907,7 +913,7 @@ We combine some ideas from the graph isomorphism proofs with ideas from before t \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 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. @@ -1076,7 +1082,7 @@ All measurements were taken on Brave 1.50.114 (Chromium 112.0.5615.49) 64-bit, u \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.