Update withdraw instruction to use equality proof

This commit is contained in:
Sam Kim 2021-12-08 12:06:18 -05:00 committed by Michael Vines
parent 6c329e2431
commit 30e12aef9a
2 changed files with 75 additions and 66 deletions

View File

@ -6,12 +6,10 @@ use {
},
curve25519_dalek::traits::MultiscalarMul,
rand::rngs::OsRng,
subtle::{Choice, ConditionallySelectable},
};
use {
crate::{errors::ProofError, transcript::TranscriptProtocol},
arrayref::{array_ref, array_refs},
core::iter,
curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
@ -37,7 +35,6 @@ impl EqualityProof {
pub fn new(
elgamal_keypair: &ElGamalKeypair,
ciphertext: &ElGamalCiphertext,
commitment: &PedersenCommitment,
message: u64,
opening: &PedersenOpening,
transcript: &mut Transcript,
@ -47,11 +44,8 @@ impl EqualityProof {
let H = PedersenBase::default().H;
let P_EG = elgamal_keypair.public.get_point();
let C_EG = ciphertext.message_comm.get_point();
let D_EG = ciphertext.decrypt_handle.get_point();
let C_Ped = commitment.get_point();
let s = elgamal_keypair.secret.get_scalar();
let x = Scalar::from(message);
let r = opening.get_scalar();
@ -67,7 +61,6 @@ impl EqualityProof {
// record public key, ciphertext, and commitment in transcript and generate challenge
// scalar
transcript.append_point(b"Y_0", &Y_0);
transcript.append_point(b"Y_1", &Y_1);
transcript.append_point(b"Y_2", &Y_2);
@ -107,6 +100,7 @@ impl EqualityProof {
let C_Ped = commitment.get_point();
// 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)?;
@ -119,7 +113,8 @@ impl EqualityProof {
let w = transcript.challenge_scalar(b"w");
let ww = w * w;
let check = RistrettoPoint::multiscalar_mul(
// check that the required algebraic condition holds
let check = RistrettoPoint::vartime_multiscalar_mul(
vec![
self.z_s,
-c,
@ -143,7 +138,7 @@ impl EqualityProof {
}
}
pub fn to_bytes(self) -> [u8; 192] {
pub fn to_bytes(&self) -> [u8; 192] {
let mut buf = [0_u8; 192];
buf[..32].copy_from_slice(self.Y_0.as_bytes());
buf[32..64].copy_from_slice(self.Y_1.as_bytes());
@ -197,7 +192,6 @@ mod test {
let proof = EqualityProof::new(
&elgamal_keypair,
&ciphertext,
&commitment,
message,
&opening,
&mut transcript_prover,
@ -226,7 +220,6 @@ mod test {
let proof = EqualityProof::new(
&elgamal_keypair,
&ciphertext,
&commitment,
message,
&opening,
&mut transcript_prover,
@ -240,6 +233,5 @@ mod test {
&mut transcript_verifier
)
.is_err());
}
}

View File

@ -6,8 +6,8 @@ use {
use {
crate::{
encryption::{
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey},
pedersen::{Pedersen, PedersenBase, PedersenOpening},
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
pedersen::{Pedersen, PedersenCommitment, PedersenOpening},
},
equality_proof::EqualityProof,
errors::ProofError,
@ -15,9 +15,7 @@ use {
range_proof::RangeProof,
transcript::TranscriptProtocol,
},
curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul},
merlin::Transcript,
rand::rngs::OsRng,
std::convert::TryInto,
};
@ -31,11 +29,14 @@ use {
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
pub struct WithdrawData {
/// The source account ElGamal pubkey
pub elgamal_pubkey: pod::ElGamalPubkey, // 32 bytes
/// The source account available balance *after* the withdraw (encrypted by
/// `source_pk`
pub final_balance_ct: pod::ElGamalCiphertext, // 64 bytes
/// Proof that the account is solvent
/// Range proof
pub proof: WithdrawProof, // 736 bytes
}
@ -62,6 +63,7 @@ impl WithdrawData {
let proof = WithdrawProof::new(source_keypair, final_balance, &final_balance_ct);
Self {
elgamal_pubkey: source_keypair.public.into(),
final_balance_ct: final_balance_ct.into(),
proof,
}
@ -71,8 +73,9 @@ impl WithdrawData {
#[cfg(not(target_arch = "bpf"))]
impl Verifiable for WithdrawData {
fn verify(&self) -> Result<(), ProofError> {
let elgamal_pubkey = self.elgamal_pubkey.try_into()?;
let final_balance_ct = self.final_balance_ct.try_into()?;
self.proof.verify(&final_balance_ct)
self.proof.verify(&elgamal_pubkey, &final_balance_ct)
}
}
@ -82,6 +85,9 @@ impl Verifiable for WithdrawData {
#[repr(C)]
#[allow(non_snake_case)]
pub struct WithdrawProof {
/// New Pedersen commitment
pub commitment: pod::PedersenCommitment,
/// Associated equality proof
pub equality_proof: pod::EqualityProof,
@ -115,6 +121,7 @@ impl WithdrawProof {
let D_EG = final_balance_ct.decrypt_handle.get_point();
let C_Ped = commitment.get_point();
// append all current state to the transcript
transcript.append_point(b"P_EG", &P_EG.compress());
transcript.append_point(b"C_EG", &C_EG.compress());
transcript.append_point(b"D_EG", &D_EG.compress());
@ -124,7 +131,6 @@ impl WithdrawProof {
let equality_proof = EqualityProof::new(
source_keypair,
final_balance_ct,
&commitment,
final_balance,
&opening,
&mut transcript,
@ -138,36 +144,52 @@ impl WithdrawProof {
);
WithdrawProof {
commitment: commitment.into(),
equality_proof: equality_proof.try_into().expect("equality proof"),
range_proof: range_proof.try_into().expect("range proof"),
}
}
pub fn verify(&self, final_balance_ct: &ElGamalCiphertext) -> Result<(), ProofError> {
// let mut transcript = Self::transcript_new();
pub fn verify(
&self,
source_pk: &ElGamalPubkey,
final_balance_ct: &ElGamalCiphertext,
) -> Result<(), ProofError> {
let mut transcript = Self::transcript_new();
// // Add a domain separator to record the start of the protocol
// transcript.withdraw_proof_domain_sep();
let commitment: PedersenCommitment = self.commitment.try_into()?;
let equality_proof: EqualityProof = self.equality_proof.try_into()?;
let range_proof: RangeProof = self.range_proof.try_into()?;
// // Extract the relevant scalar and Ristretto points from the input
// let C = final_balance_ct.message_comm.get_point();
// let D = final_balance_ct.decrypt_handle.get_point();
// add a domain separator to record the start of the protocol
transcript.withdraw_proof_domain_sep();
// let R = self.R.into();
// let z: Scalar = self.z.into();
// extract the relevant scalar and Ristretto points from the inputs
let P_EG = source_pk.get_point();
let C_EG = final_balance_ct.message_comm.get_point();
let D_EG = final_balance_ct.decrypt_handle.get_point();
let C_Ped = commitment.get_point();
// // generate a challenge scalar
// transcript.validate_and_append_point(b"R", &R)?;
// let c = transcript.challenge_scalar(b"c");
// append all current state to the transcript
transcript.append_point(b"P_EG", &P_EG.compress());
transcript.append_point(b"C_EG", &C_EG.compress());
transcript.append_point(b"D_EG", &D_EG.compress());
transcript.append_point(b"C_Ped", &C_Ped.compress());
// // decompress R or return verification error
// let R = R.decompress().ok_or(ProofError::VerificationError)?;
// verify equality proof
//
// TODO: we can also consider verifying equality and range proof in a batch
equality_proof.verify(source_pk, final_balance_ct, &commitment, &mut transcript)?;
// // compute new Pedersen commitment to verify range proof with
// let new_comm = RistrettoPoint::multiscalar_mul(vec![Scalar::one(), -z, c], vec![C, D, R]);
// verify range proof
//
// TODO: double compressing here - consider modifying range proof input type to `PedersenCommitment`
range_proof.verify(
vec![&commitment.get_point().compress()],
vec![64_usize],
&mut transcript,
)?;
// let range_proof: RangeProof = self.range_proof.try_into()?;
// range_proof.verify(vec![&new_comm.compress()], vec![64_usize], &mut transcript)
Ok(())
}
}
@ -176,37 +198,32 @@ impl WithdrawProof {
mod test {
use {super::*, crate::encryption::elgamal::ElGamalKeypair};
// #[test]
// #[ignore]
// fn test_withdraw_correctness() {
// // generate and verify proof for the proper setting
// let ElGamalKeypair { public, secret } = ElGamalKeypair::default();
#[test]
fn test_withdraw_correctness() {
// generate and verify proof for the proper setting
let elgamal_keypair = ElGamalKeypair::default();
// let current_balance: u64 = 77;
// let current_balance_ct = public.encrypt(current_balance);
let current_balance: u64 = 77;
let current_balance_ct = elgamal_keypair.public.encrypt(current_balance);
// let withdraw_amount: u64 = 55;
let withdraw_amount: u64 = 55;
// let data = WithdrawData::new(
// withdraw_amount,
// public,
// &secret,
// current_balance,
// current_balance_ct,
// );
// assert!(data.verify().is_ok());
let data = WithdrawData::new(
withdraw_amount,
&elgamal_keypair,
current_balance,
current_balance_ct,
);
assert!(data.verify().is_ok());
// // generate and verify proof with wrong balance
// let wrong_balance: u64 = 99;
// let data = WithdrawData::new(
// withdraw_amount,
// public,
// &secret,
// wrong_balance,
// current_balance_ct,
// );
// assert!(data.verify().is_err());
// // TODO: test for ciphertexts that encrypt numbers outside the 0, 2^64 range
// }
// generate and verify proof with wrong balance
let wrong_balance: u64 = 99;
let data = WithdrawData::new(
withdraw_amount,
&elgamal_keypair,
wrong_balance,
current_balance_ct,
);
assert!(data.verify().is_err());
}
}