[zk-token-sdk] Refactor ciphertext validity sigma proof and rename `ValidityProof` to `GroupedCiphertextValidityProof` (#32040)
* rename `CiphertextValidityProof` to `GroupedCiphertext2HandlesValidityProof` * rename `AggregatedValidityProof` to `BatchedGroupedCiphertext2HandlesValidityProof` * refactor `validity_proof` module into separate modules * update test names * update `aggregated` variable names * update transcript function names * Update zk-token-sdk/src/sigma_proofs/batched_grouped_ciphertext_validity_proof.rs Co-authored-by: Tyera <teulberg@gmail.com> * Update zk-token-sdk/src/sigma_proofs/grouped_ciphertext_validity_proof.rs Co-authored-by: Tyera <teulberg@gmail.com> * Reword constructor docs --------- Co-authored-by: Tyera <teulberg@gmail.com>
This commit is contained in:
parent
57a89a7ec8
commit
84e28c27f3
|
@ -20,7 +20,7 @@ use {
|
|||
pedersen::PedersenOpening,
|
||||
},
|
||||
errors::ProofError,
|
||||
sigma_proofs::validity_proof::AggregatedValidityProof,
|
||||
sigma_proofs::batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
merlin::Transcript,
|
||||
|
@ -43,7 +43,7 @@ use {
|
|||
pub struct BatchedGroupedCiphertext2HandlesValidityProofData {
|
||||
pub context: BatchedGroupedCiphertext2HandlesValidityProofContext,
|
||||
|
||||
pub proof: pod::AggregatedValidityProof,
|
||||
pub proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
|
@ -84,7 +84,7 @@ impl BatchedGroupedCiphertext2HandlesValidityProofData {
|
|||
|
||||
let mut transcript = context.new_transcript();
|
||||
|
||||
let proof = AggregatedValidityProof::new(
|
||||
let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
(amount_lo, amount_hi),
|
||||
(opening_lo, opening_hi),
|
||||
|
@ -122,7 +122,7 @@ impl ZkProofData<BatchedGroupedCiphertext2HandlesValidityProofContext>
|
|||
let destination_handle_hi = grouped_ciphertext_hi.handles.get(0).unwrap();
|
||||
let auditor_handle_hi = grouped_ciphertext_hi.handles.get(1).unwrap();
|
||||
|
||||
let proof: AggregatedValidityProof = self.proof.try_into()?;
|
||||
let proof: BatchedGroupedCiphertext2HandlesValidityProof = self.proof.try_into()?;
|
||||
|
||||
proof
|
||||
.verify(
|
||||
|
|
|
@ -18,7 +18,7 @@ use {
|
|||
pedersen::PedersenOpening,
|
||||
},
|
||||
errors::ProofError,
|
||||
sigma_proofs::validity_proof::ValidityProof,
|
||||
sigma_proofs::grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof,
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
merlin::Transcript,
|
||||
|
@ -41,7 +41,7 @@ use {
|
|||
pub struct GroupedCiphertext2HandlesValidityProofData {
|
||||
pub context: GroupedCiphertext2HandlesValidityProofContext,
|
||||
|
||||
pub proof: pod::ValidityProof,
|
||||
pub proof: pod::GroupedCiphertext2HandlesValidityProof,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Pod, Zeroable)]
|
||||
|
@ -75,7 +75,7 @@ impl GroupedCiphertext2HandlesValidityProofData {
|
|||
|
||||
let mut transcript = context.new_transcript();
|
||||
|
||||
let proof = ValidityProof::new(
|
||||
let proof = GroupedCiphertext2HandlesValidityProof::new(
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
amount,
|
||||
opening,
|
||||
|
@ -108,7 +108,7 @@ impl ZkProofData<GroupedCiphertext2HandlesValidityProofContext>
|
|||
let destination_handle = grouped_ciphertext.handles.get(0).unwrap();
|
||||
let auditor_handle = grouped_ciphertext.handles.get(1).unwrap();
|
||||
|
||||
let proof: ValidityProof = self.proof.try_into()?;
|
||||
let proof: GroupedCiphertext2HandlesValidityProof = self.proof.try_into()?;
|
||||
|
||||
proof
|
||||
.verify(
|
||||
|
|
|
@ -14,8 +14,9 @@ use {
|
|||
},
|
||||
range_proof::RangeProof,
|
||||
sigma_proofs::{
|
||||
batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
|
||||
fee_proof::FeeSigmaProof, validity_proof::AggregatedValidityProof,
|
||||
fee_proof::FeeSigmaProof,
|
||||
},
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
|
@ -399,9 +400,9 @@ pub struct TransferWithFeeProof {
|
|||
pub new_source_commitment: pod::PedersenCommitment,
|
||||
pub claimed_commitment: pod::PedersenCommitment,
|
||||
pub equality_proof: pod::CiphertextCommitmentEqualityProof,
|
||||
pub ciphertext_amount_validity_proof: pod::AggregatedValidityProof,
|
||||
pub ciphertext_amount_validity_proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
pub fee_sigma_proof: pod::FeeSigmaProof,
|
||||
pub fee_ciphertext_validity_proof: pod::AggregatedValidityProof,
|
||||
pub fee_ciphertext_validity_proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
pub range_proof: pod::RangeProofU256,
|
||||
}
|
||||
|
||||
|
@ -443,7 +444,7 @@ impl TransferWithFeeProof {
|
|||
);
|
||||
|
||||
// generate ciphertext validity proof
|
||||
let ciphertext_amount_validity_proof = AggregatedValidityProof::new(
|
||||
let ciphertext_amount_validity_proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
(transfer_amount_lo, transfer_amount_hi),
|
||||
(opening_lo, opening_hi),
|
||||
|
@ -496,7 +497,7 @@ impl TransferWithFeeProof {
|
|||
);
|
||||
|
||||
// generate ciphertext validity proof for fee ciphertexts
|
||||
let fee_ciphertext_validity_proof = AggregatedValidityProof::new(
|
||||
let fee_ciphertext_validity_proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
|
||||
(destination_pubkey, withdraw_withheld_authority_pubkey),
|
||||
(fee_amount_lo, fee_amount_hi),
|
||||
(opening_fee_lo, opening_fee_hi),
|
||||
|
@ -565,10 +566,10 @@ impl TransferWithFeeProof {
|
|||
let claimed_commitment: PedersenCommitment = self.claimed_commitment.try_into()?;
|
||||
|
||||
let equality_proof: CiphertextCommitmentEqualityProof = self.equality_proof.try_into()?;
|
||||
let ciphertext_amount_validity_proof: AggregatedValidityProof =
|
||||
let ciphertext_amount_validity_proof: BatchedGroupedCiphertext2HandlesValidityProof =
|
||||
self.ciphertext_amount_validity_proof.try_into()?;
|
||||
let fee_sigma_proof: FeeSigmaProof = self.fee_sigma_proof.try_into()?;
|
||||
let fee_ciphertext_validity_proof: AggregatedValidityProof =
|
||||
let fee_ciphertext_validity_proof: BatchedGroupedCiphertext2HandlesValidityProof =
|
||||
self.fee_ciphertext_validity_proof.try_into()?;
|
||||
let range_proof: RangeProof = self.range_proof.try_into()?;
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ use {
|
|||
},
|
||||
range_proof::RangeProof,
|
||||
sigma_proofs::{
|
||||
batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
|
||||
validity_proof::AggregatedValidityProof,
|
||||
},
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
|
@ -267,7 +267,7 @@ pub struct TransferProof {
|
|||
pub equality_proof: pod::CiphertextCommitmentEqualityProof,
|
||||
|
||||
/// Associated ciphertext validity proof
|
||||
pub validity_proof: pod::AggregatedValidityProof,
|
||||
pub validity_proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
|
||||
// Associated range proof
|
||||
pub range_proof: pod::RangeProofU128,
|
||||
|
@ -301,7 +301,7 @@ impl TransferProof {
|
|||
);
|
||||
|
||||
// generate ciphertext validity proof
|
||||
let validity_proof = AggregatedValidityProof::new(
|
||||
let validity_proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
(transfer_amount_lo, transfer_amount_hi),
|
||||
(opening_lo, opening_hi),
|
||||
|
@ -363,7 +363,8 @@ impl TransferProof {
|
|||
|
||||
let commitment: PedersenCommitment = self.new_source_commitment.try_into()?;
|
||||
let equality_proof: CiphertextCommitmentEqualityProof = self.equality_proof.try_into()?;
|
||||
let aggregated_validity_proof: AggregatedValidityProof = self.validity_proof.try_into()?;
|
||||
let aggregated_validity_proof: BatchedGroupedCiphertext2HandlesValidityProof =
|
||||
self.validity_proof.try_into()?;
|
||||
let range_proof: RangeProof = self.range_proof.try_into()?;
|
||||
|
||||
// verify equality proof
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
//! The ciphertext validity sigma proof system.
|
||||
//!
|
||||
//! The ciphertext validity proof is defined with respect to a Pedersen commitment and two
|
||||
//! decryption handles. The proof certifies that a given Pedersen commitment can be decrypted using
|
||||
//! ElGamal private keys that are associated with each of the two decryption handles. To generate
|
||||
//! the proof, a prover must provide the Pedersen opening associated with the commitment.
|
||||
//!
|
||||
//! The protocol guarantees computational soundness (by the hardness of discrete log) and perfect
|
||||
//! zero-knowledge in the random oracle model.
|
||||
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
use crate::encryption::{
|
||||
elgamal::{DecryptHandle, ElGamalPubkey},
|
||||
pedersen::{PedersenCommitment, PedersenOpening},
|
||||
};
|
||||
use {
|
||||
crate::{
|
||||
sigma_proofs::{
|
||||
errors::ValidityProofError,
|
||||
grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof,
|
||||
},
|
||||
transcript::TranscriptProtocol,
|
||||
},
|
||||
curve25519_dalek::scalar::Scalar,
|
||||
merlin::Transcript,
|
||||
};
|
||||
|
||||
/// Batched grouped ciphertext validity proof with two handles.
|
||||
///
|
||||
/// A batched grouped ciphertext validity proof certifies the validity of two instances of a
|
||||
/// standard ciphertext validity proof. An instance of a standard validity proof consists of one
|
||||
/// ciphertext and two decryption handles: `(commitment, destination_handle, auditor_handle)`. An
|
||||
/// instance of a batched ciphertext validity proof is a pair `(commitment_0,
|
||||
/// destination_handle_0, auditor_handle_0)` and `(commitment_1, destination_handle_1,
|
||||
/// auditor_handle_1)`. The proof certifies the analogous decryptable properties for each one of
|
||||
/// these pairs of commitment and decryption handles.
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct BatchedGroupedCiphertext2HandlesValidityProof(GroupedCiphertext2HandlesValidityProof);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl BatchedGroupedCiphertext2HandlesValidityProof {
|
||||
/// Batched grouped ciphertext validity proof constructor.
|
||||
///
|
||||
/// The function simply batches the input openings and invokes the standard grouped ciphertext
|
||||
/// validity proof constructor.
|
||||
pub fn new<T: Into<Scalar>>(
|
||||
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
|
||||
(amount_lo, amount_hi): (T, T),
|
||||
(opening_lo, opening_hi): (&PedersenOpening, &PedersenOpening),
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
transcript.batched_grouped_ciphertext_validity_proof_domain_sep();
|
||||
|
||||
let t = transcript.challenge_scalar(b"t");
|
||||
|
||||
let batched_message = amount_lo.into() + amount_hi.into() * t;
|
||||
let batched_opening = opening_lo + &(opening_hi * &t);
|
||||
|
||||
BatchedGroupedCiphertext2HandlesValidityProof(GroupedCiphertext2HandlesValidityProof::new(
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
batched_message,
|
||||
&batched_opening,
|
||||
transcript,
|
||||
))
|
||||
}
|
||||
|
||||
/// Batched grouped ciphertext validity proof verifier.
|
||||
///
|
||||
/// The function does *not* hash the public keys, commitment, or decryption handles into the
|
||||
/// transcript. For security, the caller (the main protocol) should hash these public
|
||||
/// components prior to invoking this constructor.
|
||||
///
|
||||
/// This function is randomized. It uses `OsRng` internally to generate random scalars.
|
||||
pub fn verify(
|
||||
self,
|
||||
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
|
||||
(commitment_lo, commitment_hi): (&PedersenCommitment, &PedersenCommitment),
|
||||
(destination_handle_lo, destination_handle_hi): (&DecryptHandle, &DecryptHandle),
|
||||
(auditor_handle_lo, auditor_handle_hi): (&DecryptHandle, &DecryptHandle),
|
||||
transcript: &mut Transcript,
|
||||
) -> Result<(), ValidityProofError> {
|
||||
transcript.batched_grouped_ciphertext_validity_proof_domain_sep();
|
||||
|
||||
let t = transcript.challenge_scalar(b"t");
|
||||
|
||||
let batched_commitment = commitment_lo + commitment_hi * t;
|
||||
let destination_batched_handle = destination_handle_lo + destination_handle_hi * t;
|
||||
let auditor_batched_handle = auditor_handle_lo + auditor_handle_hi * t;
|
||||
|
||||
let BatchedGroupedCiphertext2HandlesValidityProof(validity_proof) = self;
|
||||
|
||||
validity_proof.verify(
|
||||
&batched_commitment,
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
(&destination_batched_handle, &auditor_batched_handle),
|
||||
transcript,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 160] {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofError> {
|
||||
GroupedCiphertext2HandlesValidityProof::from_bytes(bytes).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {
|
||||
super::*,
|
||||
crate::encryption::{elgamal::ElGamalKeypair, pedersen::Pedersen},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_batched_grouped_ciphertext_validity_proof() {
|
||||
let destination_pubkey = ElGamalKeypair::new_rand().public;
|
||||
let auditor_pubkey = ElGamalKeypair::new_rand().public;
|
||||
|
||||
let amount_lo: u64 = 55;
|
||||
let amount_hi: u64 = 77;
|
||||
|
||||
let (commitment_lo, open_lo) = Pedersen::new(amount_lo);
|
||||
let (commitment_hi, open_hi) = Pedersen::new(amount_hi);
|
||||
|
||||
let destination_handle_lo = destination_pubkey.decrypt_handle(&open_lo);
|
||||
let destination_handle_hi = destination_pubkey.decrypt_handle(&open_hi);
|
||||
|
||||
let auditor_handle_lo = auditor_pubkey.decrypt_handle(&open_lo);
|
||||
let auditor_handle_hi = auditor_pubkey.decrypt_handle(&open_hi);
|
||||
|
||||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
(amount_lo, amount_hi),
|
||||
(&open_lo, &open_hi),
|
||||
&mut prover_transcript,
|
||||
);
|
||||
|
||||
assert!(proof
|
||||
.verify(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
(&commitment_lo, &commitment_hi),
|
||||
(&destination_handle_lo, &destination_handle_hi),
|
||||
(&auditor_handle_lo, &auditor_handle_hi),
|
||||
&mut verifier_transcript,
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
|
@ -32,12 +32,12 @@ use {
|
|||
merlin::Transcript,
|
||||
};
|
||||
|
||||
/// The ciphertext validity proof.
|
||||
/// The grouped ciphertext validity proof for 2 handles.
|
||||
///
|
||||
/// Contains all the elliptic curve and scalar components that make up the sigma protocol.
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct ValidityProof {
|
||||
pub struct GroupedCiphertext2HandlesValidityProof {
|
||||
Y_0: CompressedRistretto,
|
||||
Y_1: CompressedRistretto,
|
||||
Y_2: CompressedRistretto,
|
||||
|
@ -47,8 +47,8 @@ pub struct ValidityProof {
|
|||
|
||||
#[allow(non_snake_case)]
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl ValidityProof {
|
||||
/// The ciphertext validity proof constructor.
|
||||
impl GroupedCiphertext2HandlesValidityProof {
|
||||
/// Creates a grouped ciphertext validity proof for 2 handles.
|
||||
///
|
||||
/// The function does *not* hash the public keys, commitment, or decryption handles into the
|
||||
/// transcript. For security, the caller (the main protocol) should hash these public
|
||||
|
@ -70,7 +70,7 @@ impl ValidityProof {
|
|||
opening: &PedersenOpening,
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
transcript.validity_proof_domain_sep();
|
||||
transcript.grouped_ciphertext_validity_proof_domain_sep();
|
||||
|
||||
// extract the relevant scalar and Ristretto points from the inputs
|
||||
let P_dest = destination_pubkey.get_point();
|
||||
|
@ -111,7 +111,7 @@ impl ValidityProof {
|
|||
}
|
||||
}
|
||||
|
||||
/// The ciphertext validity proof verifier.
|
||||
/// Verifies a grouped ciphertext validity proof for 2 handles.
|
||||
///
|
||||
/// * `commitment` - The Pedersen commitment
|
||||
/// * `(destination_pubkey, auditor_pubkey)` - The ElGamal pubkeys associated with the decryption
|
||||
|
@ -125,7 +125,7 @@ impl ValidityProof {
|
|||
(destination_handle, auditor_handle): (&DecryptHandle, &DecryptHandle),
|
||||
transcript: &mut Transcript,
|
||||
) -> Result<(), ValidityProofError> {
|
||||
transcript.validity_proof_domain_sep();
|
||||
transcript.grouped_ciphertext_validity_proof_domain_sep();
|
||||
|
||||
// include Y_0, Y_1, Y_2 to transcript and extract challenges
|
||||
transcript.validate_and_append_point(b"Y_0", &self.Y_0)?;
|
||||
|
@ -221,7 +221,7 @@ impl ValidityProof {
|
|||
let z_x =
|
||||
Scalar::from_canonical_bytes(*z_x).ok_or(ProofVerificationError::Deserialization)?;
|
||||
|
||||
Ok(ValidityProof {
|
||||
Ok(GroupedCiphertext2HandlesValidityProof {
|
||||
Y_0,
|
||||
Y_1,
|
||||
Y_2,
|
||||
|
@ -231,89 +231,6 @@ impl ValidityProof {
|
|||
}
|
||||
}
|
||||
|
||||
/// Aggregated ciphertext validity proof.
|
||||
///
|
||||
/// An aggregated ciphertext validity proof certifies the validity of two instances of a standard
|
||||
/// ciphertext validity proof. An instance of a standard validity proof consist of one ciphertext
|
||||
/// and two decryption handles `(commitment, destination_handle, auditor_handle)`. An instance of an
|
||||
/// aggregated ciphertext validity proof is a pair `(commitment_0, destination_handle_0,
|
||||
/// auditor_handle_0)` and `(commitment_1, destination_handle_1, auditor_handle_1)`. The proof certifies
|
||||
/// the analogous decryptable properties for each one of these pair of commitment and decryption
|
||||
/// handles.
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct AggregatedValidityProof(ValidityProof);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl AggregatedValidityProof {
|
||||
/// Aggregated ciphertext validity proof constructor.
|
||||
///
|
||||
/// The function simples aggregates the input openings and invokes the standard ciphertext
|
||||
/// validity proof constructor.
|
||||
pub fn new<T: Into<Scalar>>(
|
||||
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
|
||||
(amount_lo, amount_hi): (T, T),
|
||||
(opening_lo, opening_hi): (&PedersenOpening, &PedersenOpening),
|
||||
transcript: &mut Transcript,
|
||||
) -> Self {
|
||||
transcript.aggregated_validity_proof_domain_sep();
|
||||
|
||||
let t = transcript.challenge_scalar(b"t");
|
||||
|
||||
let aggregated_message = amount_lo.into() + amount_hi.into() * t;
|
||||
let aggregated_opening = opening_lo + &(opening_hi * &t);
|
||||
|
||||
AggregatedValidityProof(ValidityProof::new(
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
aggregated_message,
|
||||
&aggregated_opening,
|
||||
transcript,
|
||||
))
|
||||
}
|
||||
|
||||
/// Aggregated ciphertext validity proof verifier.
|
||||
///
|
||||
/// The function does *not* hash the public keys, commitment, or decryption handles into the
|
||||
/// transcript. For security, the caller (the main protocol) should hash these public
|
||||
/// components prior to invoking this constructor.
|
||||
///
|
||||
/// This function is randomized. It uses `OsRng` internally to generate random scalars.
|
||||
pub fn verify(
|
||||
self,
|
||||
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
|
||||
(commitment_lo, commitment_hi): (&PedersenCommitment, &PedersenCommitment),
|
||||
(destination_handle_lo, destination_handle_hi): (&DecryptHandle, &DecryptHandle),
|
||||
(auditor_handle_lo, auditor_handle_hi): (&DecryptHandle, &DecryptHandle),
|
||||
transcript: &mut Transcript,
|
||||
) -> Result<(), ValidityProofError> {
|
||||
transcript.aggregated_validity_proof_domain_sep();
|
||||
|
||||
let t = transcript.challenge_scalar(b"t");
|
||||
|
||||
let aggregated_commitment = commitment_lo + commitment_hi * t;
|
||||
let destination_aggregated_handle = destination_handle_lo + destination_handle_hi * t;
|
||||
let auditor_aggregated_handle = auditor_handle_lo + auditor_handle_hi * t;
|
||||
|
||||
let AggregatedValidityProof(validity_proof) = self;
|
||||
|
||||
validity_proof.verify(
|
||||
&aggregated_commitment,
|
||||
(destination_pubkey, auditor_pubkey),
|
||||
(&destination_aggregated_handle, &auditor_aggregated_handle),
|
||||
transcript,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> [u8; 160] {
|
||||
self.0.to_bytes()
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofError> {
|
||||
ValidityProof::from_bytes(bytes).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use {
|
||||
|
@ -322,7 +239,7 @@ mod test {
|
|||
};
|
||||
|
||||
#[test]
|
||||
fn test_validity_proof_correctness() {
|
||||
fn test_grouped_ciphertext_validity_proof_correctness() {
|
||||
let destination_pubkey = ElGamalKeypair::new_rand().public;
|
||||
let auditor_pubkey = ElGamalKeypair::new_rand().public;
|
||||
|
||||
|
@ -335,7 +252,7 @@ mod test {
|
|||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = ValidityProof::new(
|
||||
let proof = GroupedCiphertext2HandlesValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
amount,
|
||||
&opening,
|
||||
|
@ -353,7 +270,7 @@ mod test {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_validity_proof_edge_cases() {
|
||||
fn test_grouped_ciphertext_validity_proof_edge_cases() {
|
||||
// if destination public key zeroed, then the proof should always reject
|
||||
let destination_pubkey = ElGamalPubkey::from_bytes(&[0u8; 32]).unwrap();
|
||||
let auditor_pubkey = ElGamalKeypair::new_rand().public;
|
||||
|
@ -367,7 +284,7 @@ mod test {
|
|||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = ValidityProof::new(
|
||||
let proof = GroupedCiphertext2HandlesValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
amount,
|
||||
&opening,
|
||||
|
@ -396,7 +313,7 @@ mod test {
|
|||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = ValidityProof::new(
|
||||
let proof = GroupedCiphertext2HandlesValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
amount,
|
||||
&opening,
|
||||
|
@ -426,7 +343,7 @@ mod test {
|
|||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = ValidityProof::new(
|
||||
let proof = GroupedCiphertext2HandlesValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
amount,
|
||||
&opening,
|
||||
|
@ -455,7 +372,7 @@ mod test {
|
|||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = ValidityProof::new(
|
||||
let proof = GroupedCiphertext2HandlesValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
amount,
|
||||
&opening,
|
||||
|
@ -471,42 +388,4 @@ mod test {
|
|||
)
|
||||
.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aggregated_validity_proof() {
|
||||
let destination_pubkey = ElGamalKeypair::new_rand().public;
|
||||
let auditor_pubkey = ElGamalKeypair::new_rand().public;
|
||||
|
||||
let amount_lo: u64 = 55;
|
||||
let amount_hi: u64 = 77;
|
||||
|
||||
let (commitment_lo, open_lo) = Pedersen::new(amount_lo);
|
||||
let (commitment_hi, open_hi) = Pedersen::new(amount_hi);
|
||||
|
||||
let destination_handle_lo = destination_pubkey.decrypt_handle(&open_lo);
|
||||
let destination_handle_hi = destination_pubkey.decrypt_handle(&open_hi);
|
||||
|
||||
let auditor_handle_lo = auditor_pubkey.decrypt_handle(&open_lo);
|
||||
let auditor_handle_hi = auditor_pubkey.decrypt_handle(&open_hi);
|
||||
|
||||
let mut prover_transcript = Transcript::new(b"Test");
|
||||
let mut verifier_transcript = Transcript::new(b"Test");
|
||||
|
||||
let proof = AggregatedValidityProof::new(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
(amount_lo, amount_hi),
|
||||
(&open_lo, &open_hi),
|
||||
&mut prover_transcript,
|
||||
);
|
||||
|
||||
assert!(proof
|
||||
.verify(
|
||||
(&destination_pubkey, &auditor_pubkey),
|
||||
(&commitment_lo, &commitment_hi),
|
||||
(&destination_handle_lo, &destination_handle_hi),
|
||||
(&auditor_handle_lo, &auditor_handle_hi),
|
||||
&mut verifier_transcript,
|
||||
)
|
||||
.is_ok());
|
||||
}
|
||||
}
|
|
@ -15,10 +15,11 @@
|
|||
//! We refer to the zk-token paper for the formal details and security proofs of these argument
|
||||
//! systems.
|
||||
|
||||
pub mod batched_grouped_ciphertext_validity_proof;
|
||||
pub mod ciphertext_ciphertext_equality_proof;
|
||||
pub mod ciphertext_commitment_equality_proof;
|
||||
pub mod errors;
|
||||
pub mod fee_proof;
|
||||
pub mod grouped_ciphertext_validity_proof;
|
||||
pub mod pubkey_proof;
|
||||
pub mod validity_proof;
|
||||
pub mod zero_balance_proof;
|
||||
|
|
|
@ -56,11 +56,11 @@ pub trait TranscriptProtocol {
|
|||
/// Append a domain separator for zero-balance proof.
|
||||
fn zero_balance_proof_domain_sep(&mut self);
|
||||
|
||||
/// Append a domain separator for validity proof.
|
||||
fn validity_proof_domain_sep(&mut self);
|
||||
/// Append a domain separator for grouped ciphertext validity proof.
|
||||
fn grouped_ciphertext_validity_proof_domain_sep(&mut self);
|
||||
|
||||
/// Append a domain separator for aggregated validity proof.
|
||||
fn aggregated_validity_proof_domain_sep(&mut self);
|
||||
/// Append a domain separator for batched grouped ciphertext validity proof.
|
||||
fn batched_grouped_ciphertext_validity_proof_domain_sep(&mut self);
|
||||
|
||||
/// Append a domain separator for fee sigma proof.
|
||||
fn fee_sigma_proof_domain_sep(&mut self);
|
||||
|
@ -168,12 +168,12 @@ impl TranscriptProtocol for Transcript {
|
|||
self.append_message(b"dom-sep", b"zero-balance-proof")
|
||||
}
|
||||
|
||||
fn validity_proof_domain_sep(&mut self) {
|
||||
fn grouped_ciphertext_validity_proof_domain_sep(&mut self) {
|
||||
self.append_message(b"dom-sep", b"validity-proof")
|
||||
}
|
||||
|
||||
fn aggregated_validity_proof_domain_sep(&mut self) {
|
||||
self.append_message(b"dom-sep", b"aggregated-validity-proof")
|
||||
fn batched_grouped_ciphertext_validity_proof_domain_sep(&mut self) {
|
||||
self.append_message(b"dom-sep", b"batched-validity-proof")
|
||||
}
|
||||
|
||||
fn fee_sigma_proof_domain_sep(&mut self) {
|
||||
|
|
|
@ -23,9 +23,9 @@ pub use {
|
|||
pedersen::PedersenCommitment,
|
||||
range_proof::{RangeProofU128, RangeProofU256, RangeProofU64},
|
||||
sigma_proofs::{
|
||||
AggregatedValidityProof, CiphertextCiphertextEqualityProof,
|
||||
CiphertextCommitmentEqualityProof, FeeSigmaProof, PubkeyValidityProof, ValidityProof,
|
||||
ZeroBalanceProof,
|
||||
BatchedGroupedCiphertext2HandlesValidityProof, CiphertextCiphertextEqualityProof,
|
||||
CiphertextCommitmentEqualityProof, FeeSigmaProof, GroupedCiphertext2HandlesValidityProof,
|
||||
PubkeyValidityProof, ZeroBalanceProof,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -2,15 +2,12 @@
|
|||
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
use crate::sigma_proofs::{
|
||||
batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof as DecodedBatchedGroupedCiphertext2HandlesValidityProof,
|
||||
ciphertext_ciphertext_equality_proof::CiphertextCiphertextEqualityProof as DecodedCiphertextCiphertextEqualityProof,
|
||||
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof as DecodedCiphertextCommitmentEqualityProof,
|
||||
errors::*,
|
||||
fee_proof::FeeSigmaProof as DecodedFeeSigmaProof,
|
||||
errors::*, fee_proof::FeeSigmaProof as DecodedFeeSigmaProof,
|
||||
grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof as DecodedGroupedCiphertext2HandlesValidityProof,
|
||||
pubkey_proof::PubkeyValidityProof as DecodedPubkeyValidityProof,
|
||||
validity_proof::{
|
||||
AggregatedValidityProof as DecodedAggregatedValidityProof,
|
||||
ValidityProof as DecodedValidityProof,
|
||||
},
|
||||
zero_balance_proof::ZeroBalanceProof as DecodedZeroBalanceProof,
|
||||
};
|
||||
use crate::zk_token_elgamal::pod::{Pod, Zeroable};
|
||||
|
@ -57,44 +54,54 @@ impl TryFrom<CiphertextCiphertextEqualityProof> for DecodedCiphertextCiphertextE
|
|||
}
|
||||
}
|
||||
|
||||
/// The `ValidityProof` type as a `Pod`.
|
||||
/// The `GroupedCiphertext2HandlesValidityProof` type as a `Pod`.
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct ValidityProof(pub [u8; 160]);
|
||||
pub struct GroupedCiphertext2HandlesValidityProof(pub [u8; 160]);
|
||||
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl From<DecodedValidityProof> for ValidityProof {
|
||||
fn from(decoded_proof: DecodedValidityProof) -> Self {
|
||||
impl From<DecodedGroupedCiphertext2HandlesValidityProof>
|
||||
for GroupedCiphertext2HandlesValidityProof
|
||||
{
|
||||
fn from(decoded_proof: DecodedGroupedCiphertext2HandlesValidityProof) -> Self {
|
||||
Self(decoded_proof.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl TryFrom<ValidityProof> for DecodedValidityProof {
|
||||
impl TryFrom<GroupedCiphertext2HandlesValidityProof>
|
||||
for DecodedGroupedCiphertext2HandlesValidityProof
|
||||
{
|
||||
type Error = ValidityProofError;
|
||||
|
||||
fn try_from(pod_proof: ValidityProof) -> Result<Self, Self::Error> {
|
||||
fn try_from(pod_proof: GroupedCiphertext2HandlesValidityProof) -> Result<Self, Self::Error> {
|
||||
Self::from_bytes(&pod_proof.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// The `AggregatedValidityProof` type as a `Pod`.
|
||||
/// The `BatchedGroupedCiphertext2HandlesValidityProof` type as a `Pod`.
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct AggregatedValidityProof(pub [u8; 160]);
|
||||
pub struct BatchedGroupedCiphertext2HandlesValidityProof(pub [u8; 160]);
|
||||
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl From<DecodedAggregatedValidityProof> for AggregatedValidityProof {
|
||||
fn from(decoded_proof: DecodedAggregatedValidityProof) -> Self {
|
||||
impl From<DecodedBatchedGroupedCiphertext2HandlesValidityProof>
|
||||
for BatchedGroupedCiphertext2HandlesValidityProof
|
||||
{
|
||||
fn from(decoded_proof: DecodedBatchedGroupedCiphertext2HandlesValidityProof) -> Self {
|
||||
Self(decoded_proof.to_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "solana"))]
|
||||
impl TryFrom<AggregatedValidityProof> for DecodedAggregatedValidityProof {
|
||||
impl TryFrom<BatchedGroupedCiphertext2HandlesValidityProof>
|
||||
for DecodedBatchedGroupedCiphertext2HandlesValidityProof
|
||||
{
|
||||
type Error = ValidityProofError;
|
||||
|
||||
fn try_from(pod_proof: AggregatedValidityProof) -> Result<Self, Self::Error> {
|
||||
fn try_from(
|
||||
pod_proof: BatchedGroupedCiphertext2HandlesValidityProof,
|
||||
) -> Result<Self, Self::Error> {
|
||||
Self::from_bytes(&pod_proof.0)
|
||||
}
|
||||
}
|
||||
|
@ -171,11 +178,11 @@ unsafe impl Pod for CiphertextCommitmentEqualityProof {}
|
|||
unsafe impl Zeroable for CiphertextCiphertextEqualityProof {}
|
||||
unsafe impl Pod for CiphertextCiphertextEqualityProof {}
|
||||
|
||||
unsafe impl Zeroable for ValidityProof {}
|
||||
unsafe impl Pod for ValidityProof {}
|
||||
unsafe impl Zeroable for GroupedCiphertext2HandlesValidityProof {}
|
||||
unsafe impl Pod for GroupedCiphertext2HandlesValidityProof {}
|
||||
|
||||
unsafe impl Zeroable for AggregatedValidityProof {}
|
||||
unsafe impl Pod for AggregatedValidityProof {}
|
||||
unsafe impl Zeroable for BatchedGroupedCiphertext2HandlesValidityProof {}
|
||||
unsafe impl Pod for BatchedGroupedCiphertext2HandlesValidityProof {}
|
||||
|
||||
unsafe impl Zeroable for ZeroBalanceProof {}
|
||||
unsafe impl Pod for ZeroBalanceProof {}
|
||||
|
|
Loading…
Reference in New Issue