add validity proof generation and verification
This commit is contained in:
parent
dcc961ae00
commit
725781eaa7
|
@ -59,8 +59,7 @@ impl EqualityProof {
|
||||||
let Y_1 = RistrettoPoint::multiscalar_mul(vec![y_x, y_s], vec![G, D_EG]).compress();
|
let Y_1 = RistrettoPoint::multiscalar_mul(vec![y_x, y_s], vec![G, D_EG]).compress();
|
||||||
let Y_2 = RistrettoPoint::multiscalar_mul(vec![y_x, y_r], vec![G, H]).compress();
|
let Y_2 = RistrettoPoint::multiscalar_mul(vec![y_x, y_r], vec![G, H]).compress();
|
||||||
|
|
||||||
// record public key, ciphertext, and commitment in transcript and generate challenge
|
// record masking factors in transcript
|
||||||
// scalar
|
|
||||||
transcript.append_point(b"Y_0", &Y_0);
|
transcript.append_point(b"Y_0", &Y_0);
|
||||||
transcript.append_point(b"Y_1", &Y_1);
|
transcript.append_point(b"Y_1", &Y_1);
|
||||||
transcript.append_point(b"Y_2", &Y_2);
|
transcript.append_point(b"Y_2", &Y_2);
|
||||||
|
@ -105,15 +104,15 @@ impl EqualityProof {
|
||||||
transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
|
transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
|
||||||
transcript.validate_and_append_point(b"Y_2", &self.Y_2)?;
|
transcript.validate_and_append_point(b"Y_2", &self.Y_2)?;
|
||||||
|
|
||||||
let Y_0 = self.Y_0.decompress().ok_or(ProofError::VerificationError)?;
|
|
||||||
let Y_1 = self.Y_1.decompress().ok_or(ProofError::VerificationError)?;
|
|
||||||
let Y_2 = self.Y_2.decompress().ok_or(ProofError::VerificationError)?;
|
|
||||||
|
|
||||||
let c = transcript.challenge_scalar(b"c");
|
let c = transcript.challenge_scalar(b"c");
|
||||||
let w = transcript.challenge_scalar(b"w");
|
let w = transcript.challenge_scalar(b"w");
|
||||||
let ww = w * w;
|
let ww = w * w;
|
||||||
|
|
||||||
// check that the required algebraic condition holds
|
// check that the required algebraic condition holds
|
||||||
|
let Y_0 = self.Y_0.decompress().ok_or(ProofError::VerificationError)?;
|
||||||
|
let Y_1 = self.Y_1.decompress().ok_or(ProofError::VerificationError)?;
|
||||||
|
let Y_2 = self.Y_2.decompress().ok_or(ProofError::VerificationError)?;
|
||||||
|
|
||||||
let check = RistrettoPoint::vartime_multiscalar_mul(
|
let check = RistrettoPoint::vartime_multiscalar_mul(
|
||||||
vec![
|
vec![
|
||||||
self.z_s,
|
self.z_s,
|
||||||
|
|
|
@ -110,6 +110,7 @@ impl CloseAccountProof {
|
||||||
transcript.append_point(b"Y_P", &Y_P);
|
transcript.append_point(b"Y_P", &Y_P);
|
||||||
transcript.append_point(b"Y_D", &Y_D);
|
transcript.append_point(b"Y_D", &Y_D);
|
||||||
let c = transcript.challenge_scalar(b"c");
|
let c = transcript.challenge_scalar(b"c");
|
||||||
|
transcript.challenge_scalar(b"w");
|
||||||
|
|
||||||
// compute the masked secret key
|
// compute the masked secret key
|
||||||
let z = c * s + y;
|
let z = c * s + y;
|
||||||
|
|
|
@ -11,6 +11,8 @@ mod errors;
|
||||||
mod range_proof;
|
mod range_proof;
|
||||||
#[cfg(not(target_arch = "bpf"))]
|
#[cfg(not(target_arch = "bpf"))]
|
||||||
mod transcript;
|
mod transcript;
|
||||||
|
#[cfg(not(target_arch = "bpf"))]
|
||||||
|
mod validity_proof;
|
||||||
|
|
||||||
mod instruction;
|
mod instruction;
|
||||||
pub mod zk_token_elgamal;
|
pub mod zk_token_elgamal;
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
#[cfg(not(target_arch = "bpf"))]
|
||||||
|
use {
|
||||||
|
crate::encryption::{
|
||||||
|
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
|
||||||
|
pedersen::{PedersenBase, PedersenCommitment, PedersenDecryptHandle, PedersenOpening},
|
||||||
|
},
|
||||||
|
curve25519_dalek::traits::MultiscalarMul,
|
||||||
|
rand::rngs::OsRng,
|
||||||
|
};
|
||||||
|
use {
|
||||||
|
crate::{errors::ProofError, transcript::TranscriptProtocol},
|
||||||
|
arrayref::{array_ref, array_refs},
|
||||||
|
curve25519_dalek::{
|
||||||
|
ristretto::{CompressedRistretto, RistrettoPoint},
|
||||||
|
scalar::Scalar,
|
||||||
|
traits::{IsIdentity, VartimeMultiscalarMul},
|
||||||
|
},
|
||||||
|
merlin::Transcript,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ValidityProof {
|
||||||
|
pub Y_0: CompressedRistretto,
|
||||||
|
pub Y_1: CompressedRistretto,
|
||||||
|
pub Y_2: CompressedRistretto,
|
||||||
|
pub z_r: Scalar,
|
||||||
|
pub z_x: Scalar,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[cfg(not(target_arch = "bpf"))]
|
||||||
|
impl ValidityProof {
|
||||||
|
pub fn new(
|
||||||
|
elgamal_pubkey_dest: &ElGamalPubkey,
|
||||||
|
elgamal_pubkey_auditor: &ElGamalPubkey,
|
||||||
|
messages: (u64, u64),
|
||||||
|
openings: (&PedersenOpening, &PedersenOpening),
|
||||||
|
transcript: &mut Transcript,
|
||||||
|
) -> Self {
|
||||||
|
// extract the relevant scalar and Ristretto points from the inputs
|
||||||
|
let G = PedersenBase::default().G;
|
||||||
|
let H = PedersenBase::default().H;
|
||||||
|
|
||||||
|
let P_dest = elgamal_pubkey_dest.get_point();
|
||||||
|
let P_auditor = elgamal_pubkey_auditor.get_point();
|
||||||
|
|
||||||
|
// generate random masking factors that also serves as a nonce
|
||||||
|
let y_r = Scalar::random(&mut OsRng);
|
||||||
|
let y_x = Scalar::random(&mut OsRng);
|
||||||
|
|
||||||
|
let Y_0 = RistrettoPoint::multiscalar_mul(vec![y_r, y_x], vec![H, G]).compress();
|
||||||
|
let Y_1 = (y_r * P_dest).compress();
|
||||||
|
let Y_2 = (y_r * P_auditor).compress();
|
||||||
|
|
||||||
|
// record masking factors in transcript and get challenges
|
||||||
|
transcript.append_point(b"Y_0", &Y_0);
|
||||||
|
transcript.append_point(b"Y_1", &Y_1);
|
||||||
|
transcript.append_point(b"Y_2", &Y_2);
|
||||||
|
|
||||||
|
let t = transcript.challenge_scalar(b"t");
|
||||||
|
let c = transcript.challenge_scalar(b"c");
|
||||||
|
transcript.challenge_scalar(b"w");
|
||||||
|
|
||||||
|
println!("prover: {:?}", t);
|
||||||
|
|
||||||
|
// aggregate lo and hi messages and openings
|
||||||
|
let x = Scalar::from(messages.0) + t * Scalar::from(messages.1);
|
||||||
|
let r = openings.0.get_scalar() + t * openings.1.get_scalar();
|
||||||
|
|
||||||
|
// compute masked message and opening
|
||||||
|
let z_r = c * r + y_r;
|
||||||
|
let z_x = c * x + y_x;
|
||||||
|
|
||||||
|
Self {
|
||||||
|
Y_0,
|
||||||
|
Y_1,
|
||||||
|
Y_2,
|
||||||
|
z_r,
|
||||||
|
z_x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
self,
|
||||||
|
elgamal_pubkey_dest: &ElGamalPubkey,
|
||||||
|
elgamal_pubkey_auditor: &ElGamalPubkey,
|
||||||
|
commitments: (&PedersenCommitment, &PedersenCommitment),
|
||||||
|
handle_dest: (&PedersenDecryptHandle, &PedersenDecryptHandle),
|
||||||
|
handle_auditor: (&PedersenDecryptHandle, &PedersenDecryptHandle),
|
||||||
|
transcript: &mut Transcript,
|
||||||
|
) -> Result<(), ProofError> {
|
||||||
|
// extract the relevant scalar and Ristretto points from the inputs
|
||||||
|
let G = PedersenBase::default().G;
|
||||||
|
let H = PedersenBase::default().H;
|
||||||
|
|
||||||
|
// include Y_0, Y_1, Y_2 to transcript and extract challenges
|
||||||
|
transcript.validate_and_append_point(b"Y_0", &self.Y_0)?;
|
||||||
|
transcript.validate_and_append_point(b"Y_1", &self.Y_1)?;
|
||||||
|
transcript.validate_and_append_point(b"Y_2", &self.Y_2)?;
|
||||||
|
|
||||||
|
let t = transcript.challenge_scalar(b"t");
|
||||||
|
let c = transcript.challenge_scalar(b"c");
|
||||||
|
let w = transcript.challenge_scalar(b"w");
|
||||||
|
let ww = w * w;
|
||||||
|
|
||||||
|
println!("verifier: {:?}", t);
|
||||||
|
|
||||||
|
// check the required algebraic conditions
|
||||||
|
let Y_0 = self.Y_0.decompress().ok_or(ProofError::VerificationError)?;
|
||||||
|
let Y_1 = self.Y_1.decompress().ok_or(ProofError::VerificationError)?;
|
||||||
|
let Y_2 = self.Y_2.decompress().ok_or(ProofError::VerificationError)?;
|
||||||
|
|
||||||
|
let P_dest = elgamal_pubkey_dest.get_point();
|
||||||
|
let P_auditor = elgamal_pubkey_auditor.get_point();
|
||||||
|
|
||||||
|
let C = commitments.0.get_point() + t * commitments.1.get_point();
|
||||||
|
let D_dest = handle_dest.0.get_point() + t * handle_dest.1.get_point();
|
||||||
|
let D_auditor = handle_auditor.0.get_point() + t * handle_auditor.1.get_point();
|
||||||
|
|
||||||
|
let check = RistrettoPoint::vartime_multiscalar_mul(
|
||||||
|
vec![
|
||||||
|
self.z_r, self.z_x, -c, -Scalar::one(), w * self.z_r, -w * c, -w, ww * self.z_r, -ww * c, -ww,
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
H, G, C, Y_0, P_dest, D_dest, Y_1, P_auditor, D_auditor, Y_2,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
if check.is_identity() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(ProofError::VerificationError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pub fn to_bytes(&self) -> [u8; 192] {
|
||||||
|
// // TODO
|
||||||
|
// [0_u8; 192]
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn from_bytes(bytes: &[u8]) -> Result<Self, ProofError> {
|
||||||
|
// // TODO
|
||||||
|
// Ok(())
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use crate::encryption::pedersen::Pedersen;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_validity_proof() {
|
||||||
|
let elgamal_pubkey_dest = ElGamalKeypair::default().public;
|
||||||
|
let elgamal_pubkey_auditor = ElGamalKeypair::default().public;
|
||||||
|
|
||||||
|
let x_lo: u64 = 55;
|
||||||
|
let x_hi: u64 = 77;
|
||||||
|
|
||||||
|
let (commitment_lo, open_lo) = Pedersen::new(x_lo);
|
||||||
|
let (commitment_hi, open_hi) = Pedersen::new(x_hi);
|
||||||
|
|
||||||
|
let handle_lo_dest = elgamal_pubkey_dest.decrypt_handle(&open_lo);
|
||||||
|
let handle_hi_dest = elgamal_pubkey_dest.decrypt_handle(&open_hi);
|
||||||
|
|
||||||
|
let handle_lo_auditor = elgamal_pubkey_auditor.decrypt_handle(&open_lo);
|
||||||
|
let handle_hi_auditor = elgamal_pubkey_auditor.decrypt_handle(&open_hi);
|
||||||
|
|
||||||
|
let mut transcript_prover = Transcript::new(b"Test");
|
||||||
|
let mut transcript_verifier = Transcript::new(b"Test");
|
||||||
|
|
||||||
|
let proof = ValidityProof::new(
|
||||||
|
&elgamal_pubkey_dest,
|
||||||
|
&elgamal_pubkey_auditor,
|
||||||
|
(x_lo, x_hi),
|
||||||
|
(&open_lo, &open_hi),
|
||||||
|
&mut transcript_prover,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(proof.verify(
|
||||||
|
&elgamal_pubkey_dest,
|
||||||
|
&elgamal_pubkey_auditor,
|
||||||
|
(&commitment_lo, &commitment_hi),
|
||||||
|
(&handle_lo_dest, &handle_hi_dest),
|
||||||
|
(&handle_lo_auditor, &handle_hi_auditor),
|
||||||
|
&mut transcript_verifier,
|
||||||
|
).is_ok());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue