refactor: CloseAccount now uses zero-balance-proof
This commit is contained in:
parent
c26fa1d0e9
commit
584c63bcc4
|
@ -5,22 +5,13 @@ use {
|
|||
#[cfg(not(target_arch = "bpf"))]
|
||||
use {
|
||||
crate::{
|
||||
encryption::{
|
||||
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
|
||||
pedersen::PedersenBase,
|
||||
},
|
||||
encryption::elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
|
||||
errors::ProofError,
|
||||
instruction::Verifiable,
|
||||
sigma_proofs::zero_balance_proof::ZeroBalanceProof,
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
curve25519_dalek::{
|
||||
ristretto::RistrettoPoint,
|
||||
scalar::Scalar,
|
||||
traits::{IsIdentity, MultiscalarMul},
|
||||
},
|
||||
merlin::Transcript,
|
||||
rand::rngs::OsRng,
|
||||
std::convert::TryInto,
|
||||
};
|
||||
|
||||
|
@ -84,42 +75,15 @@ impl CloseAccountProof {
|
|||
|
||||
pub fn new(source_keypair: &ElGamalKeypair, balance: &ElGamalCiphertext) -> Self {
|
||||
let mut transcript = Self::transcript_new();
|
||||
// TODO: Add ciphertext to transcript
|
||||
|
||||
// add a domain separator to record the start of the protocol
|
||||
transcript.close_account_proof_domain_sep();
|
||||
|
||||
|
||||
|
||||
// extract the relevant scalar and Ristretto points from the input
|
||||
let P = source_keypair.public.get_point();
|
||||
let s = source_keypair.secret.get_scalar();
|
||||
|
||||
let C = balance.message_comm.get_point();
|
||||
let D = balance.decrypt_handle.get_point();
|
||||
|
||||
// record ElGamal pubkey and ciphertext in the transcript
|
||||
transcript.append_point(b"P", &P.compress());
|
||||
transcript.append_point(b"C", &C.compress());
|
||||
transcript.append_point(b"D", &D.compress());
|
||||
|
||||
// generate a random masking factor that also serves as a nonce
|
||||
let y = Scalar::random(&mut OsRng);
|
||||
let Y_P = (y * P).compress();
|
||||
let Y_D = (y * D).compress();
|
||||
|
||||
// record Y in transcript and receive a challenge scalar
|
||||
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;
|
||||
let proof = ZeroBalanceProof::new(source_keypair, balance, &mut transcript);
|
||||
|
||||
CloseAccountProof {
|
||||
Y_P: Y_P.into(),
|
||||
Y_D: Y_D.into(),
|
||||
z: z.into(),
|
||||
proof: proof.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,44 +97,9 @@ impl CloseAccountProof {
|
|||
// add a domain separator to record the start of the protocol
|
||||
transcript.close_account_proof_domain_sep();
|
||||
|
||||
// extract the relevant scalar and Ristretto points from the input
|
||||
let P = elgamal_pubkey.get_point();
|
||||
let C = balance.message_comm.get_point();
|
||||
let D = balance.decrypt_handle.get_point();
|
||||
|
||||
let H = PedersenBase::default().H;
|
||||
|
||||
let Y_P = self.Y_P.into();
|
||||
let Y_D = self.Y_D.into();
|
||||
let z = self.z.into();
|
||||
|
||||
// record ElGamal pubkey and ciphertext in the transcript
|
||||
transcript.validate_and_append_point(b"P", &P.compress())?;
|
||||
transcript.append_point(b"C", &C.compress());
|
||||
transcript.append_point(b"D", &D.compress());
|
||||
|
||||
// record Y in transcript and receive challenge scalars
|
||||
transcript.validate_and_append_point(b"Y_P", &Y_P)?;
|
||||
transcript.append_point(b"Y_D", &Y_D);
|
||||
|
||||
let c = transcript.challenge_scalar(b"c");
|
||||
let w = transcript.challenge_scalar(b"w"); // w used for multiscalar multiplication verification
|
||||
|
||||
// decompress R or return verification error
|
||||
let Y_P = Y_P.decompress().ok_or(ProofError::VerificationError)?;
|
||||
let Y_D = Y_D.decompress().ok_or(ProofError::VerificationError)?;
|
||||
|
||||
// check the required algebraic relation
|
||||
let check = RistrettoPoint::multiscalar_mul(
|
||||
vec![z, -c, -Scalar::one(), w * z, -w * c, -w],
|
||||
vec![P, H, Y_P, D, C, Y_D],
|
||||
);
|
||||
|
||||
if check.is_identity() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ProofError::VerificationError)
|
||||
}
|
||||
// verify zero balance proof
|
||||
let proof: ZeroBalanceProof = self.proof.try_into()?;
|
||||
proof.verify(elgamal_pubkey, balance, &mut transcript)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ use {
|
|||
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey},
|
||||
pedersen::{Pedersen, PedersenCommitment, PedersenDecryptHandle, PedersenOpening},
|
||||
},
|
||||
sigma_proofs::{equality_proof::EqualityProof, validity_proof::ValidityProof},
|
||||
errors::ProofError,
|
||||
instruction::{Role, Verifiable},
|
||||
range_proof::RangeProof,
|
||||
sigma_proofs::{equality_proof::EqualityProof, validity_proof::ValidityProof},
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
curve25519_dalek::scalar::Scalar,
|
||||
|
|
|
@ -9,10 +9,10 @@ use {
|
|||
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
|
||||
pedersen::{Pedersen, PedersenCommitment, PedersenOpening},
|
||||
},
|
||||
sigma_proofs::equality_proof::EqualityProof,
|
||||
errors::ProofError,
|
||||
instruction::Verifiable,
|
||||
range_proof::RangeProof,
|
||||
sigma_proofs::equality_proof::EqualityProof,
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
merlin::Transcript,
|
||||
|
|
|
@ -34,7 +34,6 @@ impl ZeroBalanceProof {
|
|||
elgamal_ciphertext: &ElGamalCiphertext,
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
|
||||
// extract the relevant scalar and Ristretto points from the input
|
||||
let P = elgamal_keypair.public.get_point();
|
||||
let s = elgamal_keypair.secret.get_scalar();
|
||||
|
@ -61,11 +60,7 @@ impl ZeroBalanceProof {
|
|||
// compute the masked secret key
|
||||
let z = c * s + y;
|
||||
|
||||
Self {
|
||||
Y_P,
|
||||
Y_D,
|
||||
z,
|
||||
}
|
||||
Self { Y_P, Y_D, z }
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
|
@ -128,18 +123,17 @@ impl ZeroBalanceProof {
|
|||
|
||||
let z = Scalar::from_canonical_bytes(*z).ok_or(ProofError::FormatError)?;
|
||||
|
||||
Ok(ZeroBalanceProof {
|
||||
Y_P,
|
||||
Y_D,
|
||||
z,
|
||||
})
|
||||
Ok(ZeroBalanceProof { Y_P, Y_D, z })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::encryption::{elgamal::ElGamalKeypair, pedersen::Pedersen};
|
||||
use crate::encryption::{
|
||||
elgamal::ElGamalKeypair,
|
||||
pedersen::{Pedersen, PedersenDecryptHandle, PedersenOpening},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_zero_balance_proof() {
|
||||
|
@ -150,18 +144,34 @@ mod test {
|
|||
|
||||
// general case: encryption of 0
|
||||
let elgamal_ciphertext = source_keypair.public.encrypt(0_u64);
|
||||
let proof = ZeroBalanceProof::new(&source_keypair, &elgamal_ciphertext, &mut transcript_prover);
|
||||
assert!(proof.verify(&source_keypair.public, &elgamal_ciphertext, &mut transcript_verifier).is_ok());
|
||||
let proof =
|
||||
ZeroBalanceProof::new(&source_keypair, &elgamal_ciphertext, &mut transcript_prover);
|
||||
assert!(proof
|
||||
.verify(
|
||||
&source_keypair.public,
|
||||
&elgamal_ciphertext,
|
||||
&mut transcript_verifier
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
// general case: encryption of > 0
|
||||
let elgamal_ciphertext = source_keypair.public.encrypt(1_u64);
|
||||
let proof = ZeroBalanceProof::new(&source_keypair, &elgamal_ciphertext, &mut transcript_prover);
|
||||
assert!(proof.verify(&source_keypair.public, &elgamal_ciphertext, &mut transcript_verifier).is_err());
|
||||
let proof =
|
||||
ZeroBalanceProof::new(&source_keypair, &elgamal_ciphertext, &mut transcript_prover);
|
||||
assert!(proof
|
||||
.verify(
|
||||
&source_keypair.public,
|
||||
&elgamal_ciphertext,
|
||||
&mut transcript_verifier
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// // edge case: all zero ciphertext - such ciphertext should always be a valid encryption of 0
|
||||
let zeroed_ct = ElGamalCiphertext::default();
|
||||
let proof = ZeroBalanceProof::new(&source_keypair, &zeroed_ct, &mut transcript_prover);
|
||||
assert!(proof.verify(&source_keypair.public, &zeroed_ct, &mut transcript_verifier).is_ok());
|
||||
assert!(proof
|
||||
.verify(&source_keypair.public, &zeroed_ct, &mut transcript_verifier)
|
||||
.is_ok());
|
||||
|
||||
// edge cases: only C or D is zero - such ciphertext is always invalid
|
||||
let zeroed_comm = Pedersen::with(0_u64, &PedersenOpening::default());
|
||||
|
@ -172,9 +182,17 @@ mod test {
|
|||
decrypt_handle: handle,
|
||||
};
|
||||
|
||||
let proof = ZeroBalanceProof::new(&source_keypair, &zeroed_comm_ciphertext, &mut transcript_prover);
|
||||
let proof = ZeroBalanceProof::new(
|
||||
&source_keypair,
|
||||
&zeroed_comm_ciphertext,
|
||||
&mut transcript_prover,
|
||||
);
|
||||
assert!(proof
|
||||
.verify(&source_keypair.public, &zeroed_comm_ciphertext, &mut transcript_verifier)
|
||||
.verify(
|
||||
&source_keypair.public,
|
||||
&zeroed_comm_ciphertext,
|
||||
&mut transcript_verifier
|
||||
)
|
||||
.is_err());
|
||||
|
||||
let (zero_comm, _) = Pedersen::new(0_u64);
|
||||
|
@ -183,9 +201,17 @@ mod test {
|
|||
decrypt_handle: PedersenDecryptHandle::default(),
|
||||
};
|
||||
|
||||
let proof = ZeroBalanceProof::new(&source_keypair, &zeroed_handle_ciphertext, &mut transcript_prover);
|
||||
let proof = ZeroBalanceProof::new(
|
||||
&source_keypair,
|
||||
&zeroed_handle_ciphertext,
|
||||
&mut transcript_prover,
|
||||
);
|
||||
assert!(proof
|
||||
.verify(&source_keypair.public, &zeroed_handle_ciphertext, &mut transcript_verifier)
|
||||
.verify(
|
||||
&source_keypair.public,
|
||||
&zeroed_handle_ciphertext,
|
||||
&mut transcript_verifier
|
||||
)
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,12 @@ mod target_arch {
|
|||
elgamal::{ElGamalCiphertext, ElGamalPubkey},
|
||||
pedersen::{PedersenCommitment, PedersenDecryptHandle},
|
||||
},
|
||||
sigma_proofs::{equality_proof::EqualityProof, validity_proof::ValidityProof, zero_balance_proof::ZeroBalanceProof},
|
||||
errors::ProofError,
|
||||
range_proof::RangeProof,
|
||||
sigma_proofs::{
|
||||
equality_proof::EqualityProof, validity_proof::ValidityProof,
|
||||
zero_balance_proof::ZeroBalanceProof,
|
||||
},
|
||||
},
|
||||
curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar},
|
||||
std::convert::TryFrom,
|
||||
|
|
|
@ -72,7 +72,7 @@ unsafe impl Pod for ValidityProof {}
|
|||
/// Serialization of zero balance proofs
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct ZeroBalanceProof(pub [u8; 160]);
|
||||
pub struct ZeroBalanceProof(pub [u8; 96]);
|
||||
|
||||
// `ZeroBalanceProof` is a Pod and Zeroable.
|
||||
// Add the marker traits manually because `bytemuck` only adds them for some `u8` arrays
|
||||
|
|
Loading…
Reference in New Issue