add validity proof generation and verification

This commit is contained in:
Sam Kim 2021-12-12 08:51:22 -05:00 committed by Michael Vines
parent dcc961ae00
commit 725781eaa7
4 changed files with 200 additions and 6 deletions

View File

@ -59,8 +59,7 @@ impl EqualityProof {
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();
// record public key, ciphertext, and commitment in transcript and generate challenge
// scalar
// record masking factors in transcript
transcript.append_point(b"Y_0", &Y_0);
transcript.append_point(b"Y_1", &Y_1);
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_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 w = transcript.challenge_scalar(b"w");
let ww = w * w;
// 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(
vec![
self.z_s,

View File

@ -110,6 +110,7 @@ impl CloseAccountProof {
transcript.append_point(b"Y_P", &Y_P);
transcript.append_point(b"Y_D", &Y_D);
let c = transcript.challenge_scalar(b"c");
transcript.challenge_scalar(b"w");
// compute the masked secret key
let z = c * s + y;

View File

@ -11,6 +11,8 @@ mod errors;
mod range_proof;
#[cfg(not(target_arch = "bpf"))]
mod transcript;
#[cfg(not(target_arch = "bpf"))]
mod validity_proof;
mod instruction;
pub mod zk_token_elgamal;

View File

@ -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());
}
}