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

@ -457,3 +457,11 @@ doi={10.1109/SP.2014.36}}
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

@ -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*}