[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:
samkim-crypto 2023-06-13 12:06:24 +09:00 committed by GitHub
parent 57a89a7ec8
commit 84e28c27f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 232 additions and 188 deletions

View File

@ -20,7 +20,7 @@ use {
pedersen::PedersenOpening, pedersen::PedersenOpening,
}, },
errors::ProofError, errors::ProofError,
sigma_proofs::validity_proof::AggregatedValidityProof, sigma_proofs::batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
transcript::TranscriptProtocol, transcript::TranscriptProtocol,
}, },
merlin::Transcript, merlin::Transcript,
@ -43,7 +43,7 @@ use {
pub struct BatchedGroupedCiphertext2HandlesValidityProofData { pub struct BatchedGroupedCiphertext2HandlesValidityProofData {
pub context: BatchedGroupedCiphertext2HandlesValidityProofContext, pub context: BatchedGroupedCiphertext2HandlesValidityProofContext,
pub proof: pod::AggregatedValidityProof, pub proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
} }
#[derive(Clone, Copy, Pod, Zeroable)] #[derive(Clone, Copy, Pod, Zeroable)]
@ -84,7 +84,7 @@ impl BatchedGroupedCiphertext2HandlesValidityProofData {
let mut transcript = context.new_transcript(); let mut transcript = context.new_transcript();
let proof = AggregatedValidityProof::new( let proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
(destination_pubkey, auditor_pubkey), (destination_pubkey, auditor_pubkey),
(amount_lo, amount_hi), (amount_lo, amount_hi),
(opening_lo, opening_hi), (opening_lo, opening_hi),
@ -122,7 +122,7 @@ impl ZkProofData<BatchedGroupedCiphertext2HandlesValidityProofContext>
let destination_handle_hi = grouped_ciphertext_hi.handles.get(0).unwrap(); let destination_handle_hi = grouped_ciphertext_hi.handles.get(0).unwrap();
let auditor_handle_hi = grouped_ciphertext_hi.handles.get(1).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 proof
.verify( .verify(

View File

@ -18,7 +18,7 @@ use {
pedersen::PedersenOpening, pedersen::PedersenOpening,
}, },
errors::ProofError, errors::ProofError,
sigma_proofs::validity_proof::ValidityProof, sigma_proofs::grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof,
transcript::TranscriptProtocol, transcript::TranscriptProtocol,
}, },
merlin::Transcript, merlin::Transcript,
@ -41,7 +41,7 @@ use {
pub struct GroupedCiphertext2HandlesValidityProofData { pub struct GroupedCiphertext2HandlesValidityProofData {
pub context: GroupedCiphertext2HandlesValidityProofContext, pub context: GroupedCiphertext2HandlesValidityProofContext,
pub proof: pod::ValidityProof, pub proof: pod::GroupedCiphertext2HandlesValidityProof,
} }
#[derive(Clone, Copy, Pod, Zeroable)] #[derive(Clone, Copy, Pod, Zeroable)]
@ -75,7 +75,7 @@ impl GroupedCiphertext2HandlesValidityProofData {
let mut transcript = context.new_transcript(); let mut transcript = context.new_transcript();
let proof = ValidityProof::new( let proof = GroupedCiphertext2HandlesValidityProof::new(
(destination_pubkey, auditor_pubkey), (destination_pubkey, auditor_pubkey),
amount, amount,
opening, opening,
@ -108,7 +108,7 @@ impl ZkProofData<GroupedCiphertext2HandlesValidityProofContext>
let destination_handle = grouped_ciphertext.handles.get(0).unwrap(); let destination_handle = grouped_ciphertext.handles.get(0).unwrap();
let auditor_handle = grouped_ciphertext.handles.get(1).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 proof
.verify( .verify(

View File

@ -14,8 +14,9 @@ use {
}, },
range_proof::RangeProof, range_proof::RangeProof,
sigma_proofs::{ sigma_proofs::{
batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof, ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
fee_proof::FeeSigmaProof, validity_proof::AggregatedValidityProof, fee_proof::FeeSigmaProof,
}, },
transcript::TranscriptProtocol, transcript::TranscriptProtocol,
}, },
@ -399,9 +400,9 @@ pub struct TransferWithFeeProof {
pub new_source_commitment: pod::PedersenCommitment, pub new_source_commitment: pod::PedersenCommitment,
pub claimed_commitment: pod::PedersenCommitment, pub claimed_commitment: pod::PedersenCommitment,
pub equality_proof: pod::CiphertextCommitmentEqualityProof, 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_sigma_proof: pod::FeeSigmaProof,
pub fee_ciphertext_validity_proof: pod::AggregatedValidityProof, pub fee_ciphertext_validity_proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
pub range_proof: pod::RangeProofU256, pub range_proof: pod::RangeProofU256,
} }
@ -443,7 +444,7 @@ impl TransferWithFeeProof {
); );
// generate ciphertext validity proof // generate ciphertext validity proof
let ciphertext_amount_validity_proof = AggregatedValidityProof::new( let ciphertext_amount_validity_proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
(destination_pubkey, auditor_pubkey), (destination_pubkey, auditor_pubkey),
(transfer_amount_lo, transfer_amount_hi), (transfer_amount_lo, transfer_amount_hi),
(opening_lo, opening_hi), (opening_lo, opening_hi),
@ -496,7 +497,7 @@ impl TransferWithFeeProof {
); );
// generate ciphertext validity proof for fee ciphertexts // 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), (destination_pubkey, withdraw_withheld_authority_pubkey),
(fee_amount_lo, fee_amount_hi), (fee_amount_lo, fee_amount_hi),
(opening_fee_lo, opening_fee_hi), (opening_fee_lo, opening_fee_hi),
@ -565,10 +566,10 @@ impl TransferWithFeeProof {
let claimed_commitment: PedersenCommitment = self.claimed_commitment.try_into()?; let claimed_commitment: PedersenCommitment = self.claimed_commitment.try_into()?;
let equality_proof: CiphertextCommitmentEqualityProof = self.equality_proof.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()?; self.ciphertext_amount_validity_proof.try_into()?;
let fee_sigma_proof: FeeSigmaProof = self.fee_sigma_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()?; self.fee_ciphertext_validity_proof.try_into()?;
let range_proof: RangeProof = self.range_proof.try_into()?; let range_proof: RangeProof = self.range_proof.try_into()?;

View File

@ -11,8 +11,8 @@ use {
}, },
range_proof::RangeProof, range_proof::RangeProof,
sigma_proofs::{ sigma_proofs::{
batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof, ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
validity_proof::AggregatedValidityProof,
}, },
transcript::TranscriptProtocol, transcript::TranscriptProtocol,
}, },
@ -267,7 +267,7 @@ pub struct TransferProof {
pub equality_proof: pod::CiphertextCommitmentEqualityProof, pub equality_proof: pod::CiphertextCommitmentEqualityProof,
/// Associated ciphertext validity proof /// Associated ciphertext validity proof
pub validity_proof: pod::AggregatedValidityProof, pub validity_proof: pod::BatchedGroupedCiphertext2HandlesValidityProof,
// Associated range proof // Associated range proof
pub range_proof: pod::RangeProofU128, pub range_proof: pod::RangeProofU128,
@ -301,7 +301,7 @@ impl TransferProof {
); );
// generate ciphertext validity proof // generate ciphertext validity proof
let validity_proof = AggregatedValidityProof::new( let validity_proof = BatchedGroupedCiphertext2HandlesValidityProof::new(
(destination_pubkey, auditor_pubkey), (destination_pubkey, auditor_pubkey),
(transfer_amount_lo, transfer_amount_hi), (transfer_amount_lo, transfer_amount_hi),
(opening_lo, opening_hi), (opening_lo, opening_hi),
@ -363,7 +363,8 @@ impl TransferProof {
let commitment: PedersenCommitment = self.new_source_commitment.try_into()?; let commitment: PedersenCommitment = self.new_source_commitment.try_into()?;
let equality_proof: CiphertextCommitmentEqualityProof = self.equality_proof.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()?; let range_proof: RangeProof = self.range_proof.try_into()?;
// verify equality proof // verify equality proof

View File

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

View File

@ -32,12 +32,12 @@ use {
merlin::Transcript, 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. /// Contains all the elliptic curve and scalar components that make up the sigma protocol.
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[derive(Clone)] #[derive(Clone)]
pub struct ValidityProof { pub struct GroupedCiphertext2HandlesValidityProof {
Y_0: CompressedRistretto, Y_0: CompressedRistretto,
Y_1: CompressedRistretto, Y_1: CompressedRistretto,
Y_2: CompressedRistretto, Y_2: CompressedRistretto,
@ -47,8 +47,8 @@ pub struct ValidityProof {
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[cfg(not(target_os = "solana"))] #[cfg(not(target_os = "solana"))]
impl ValidityProof { impl GroupedCiphertext2HandlesValidityProof {
/// The ciphertext validity proof constructor. /// Creates a grouped ciphertext validity proof for 2 handles.
/// ///
/// The function does *not* hash the public keys, commitment, or decryption handles into the /// 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 /// transcript. For security, the caller (the main protocol) should hash these public
@ -70,7 +70,7 @@ impl ValidityProof {
opening: &PedersenOpening, opening: &PedersenOpening,
transcript: &mut Transcript, transcript: &mut Transcript,
) -> Self { ) -> Self {
transcript.validity_proof_domain_sep(); transcript.grouped_ciphertext_validity_proof_domain_sep();
// extract the relevant scalar and Ristretto points from the inputs // extract the relevant scalar and Ristretto points from the inputs
let P_dest = destination_pubkey.get_point(); 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 /// * `commitment` - The Pedersen commitment
/// * `(destination_pubkey, auditor_pubkey)` - The ElGamal pubkeys associated with the decryption /// * `(destination_pubkey, auditor_pubkey)` - The ElGamal pubkeys associated with the decryption
@ -125,7 +125,7 @@ impl ValidityProof {
(destination_handle, auditor_handle): (&DecryptHandle, &DecryptHandle), (destination_handle, auditor_handle): (&DecryptHandle, &DecryptHandle),
transcript: &mut Transcript, transcript: &mut Transcript,
) -> Result<(), ValidityProofError> { ) -> 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 // 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_0", &self.Y_0)?;
@ -221,7 +221,7 @@ impl ValidityProof {
let z_x = let z_x =
Scalar::from_canonical_bytes(*z_x).ok_or(ProofVerificationError::Deserialization)?; Scalar::from_canonical_bytes(*z_x).ok_or(ProofVerificationError::Deserialization)?;
Ok(ValidityProof { Ok(GroupedCiphertext2HandlesValidityProof {
Y_0, Y_0,
Y_1, Y_1,
Y_2, 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)] #[cfg(test)]
mod test { mod test {
use { use {
@ -322,7 +239,7 @@ mod test {
}; };
#[test] #[test]
fn test_validity_proof_correctness() { fn test_grouped_ciphertext_validity_proof_correctness() {
let destination_pubkey = ElGamalKeypair::new_rand().public; let destination_pubkey = ElGamalKeypair::new_rand().public;
let auditor_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 prover_transcript = Transcript::new(b"Test");
let mut verifier_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), (&destination_pubkey, &auditor_pubkey),
amount, amount,
&opening, &opening,
@ -353,7 +270,7 @@ mod test {
} }
#[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 // if destination public key zeroed, then the proof should always reject
let destination_pubkey = ElGamalPubkey::from_bytes(&[0u8; 32]).unwrap(); let destination_pubkey = ElGamalPubkey::from_bytes(&[0u8; 32]).unwrap();
let auditor_pubkey = ElGamalKeypair::new_rand().public; let auditor_pubkey = ElGamalKeypair::new_rand().public;
@ -367,7 +284,7 @@ mod test {
let mut prover_transcript = Transcript::new(b"Test"); let mut prover_transcript = Transcript::new(b"Test");
let mut verifier_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), (&destination_pubkey, &auditor_pubkey),
amount, amount,
&opening, &opening,
@ -396,7 +313,7 @@ mod test {
let mut prover_transcript = Transcript::new(b"Test"); let mut prover_transcript = Transcript::new(b"Test");
let mut verifier_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), (&destination_pubkey, &auditor_pubkey),
amount, amount,
&opening, &opening,
@ -426,7 +343,7 @@ mod test {
let mut prover_transcript = Transcript::new(b"Test"); let mut prover_transcript = Transcript::new(b"Test");
let mut verifier_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), (&destination_pubkey, &auditor_pubkey),
amount, amount,
&opening, &opening,
@ -455,7 +372,7 @@ mod test {
let mut prover_transcript = Transcript::new(b"Test"); let mut prover_transcript = Transcript::new(b"Test");
let mut verifier_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), (&destination_pubkey, &auditor_pubkey),
amount, amount,
&opening, &opening,
@ -471,42 +388,4 @@ mod test {
) )
.is_ok()); .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());
}
} }

View File

@ -15,10 +15,11 @@
//! We refer to the zk-token paper for the formal details and security proofs of these argument //! We refer to the zk-token paper for the formal details and security proofs of these argument
//! systems. //! systems.
pub mod batched_grouped_ciphertext_validity_proof;
pub mod ciphertext_ciphertext_equality_proof; pub mod ciphertext_ciphertext_equality_proof;
pub mod ciphertext_commitment_equality_proof; pub mod ciphertext_commitment_equality_proof;
pub mod errors; pub mod errors;
pub mod fee_proof; pub mod fee_proof;
pub mod grouped_ciphertext_validity_proof;
pub mod pubkey_proof; pub mod pubkey_proof;
pub mod validity_proof;
pub mod zero_balance_proof; pub mod zero_balance_proof;

View File

@ -56,11 +56,11 @@ pub trait TranscriptProtocol {
/// Append a domain separator for zero-balance proof. /// Append a domain separator for zero-balance proof.
fn zero_balance_proof_domain_sep(&mut self); fn zero_balance_proof_domain_sep(&mut self);
/// Append a domain separator for validity proof. /// Append a domain separator for grouped ciphertext validity proof.
fn validity_proof_domain_sep(&mut self); fn grouped_ciphertext_validity_proof_domain_sep(&mut self);
/// Append a domain separator for aggregated validity proof. /// Append a domain separator for batched grouped ciphertext validity proof.
fn aggregated_validity_proof_domain_sep(&mut self); fn batched_grouped_ciphertext_validity_proof_domain_sep(&mut self);
/// Append a domain separator for fee sigma proof. /// Append a domain separator for fee sigma proof.
fn fee_sigma_proof_domain_sep(&mut self); 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") 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") self.append_message(b"dom-sep", b"validity-proof")
} }
fn aggregated_validity_proof_domain_sep(&mut self) { fn batched_grouped_ciphertext_validity_proof_domain_sep(&mut self) {
self.append_message(b"dom-sep", b"aggregated-validity-proof") self.append_message(b"dom-sep", b"batched-validity-proof")
} }
fn fee_sigma_proof_domain_sep(&mut self) { fn fee_sigma_proof_domain_sep(&mut self) {

View File

@ -23,9 +23,9 @@ pub use {
pedersen::PedersenCommitment, pedersen::PedersenCommitment,
range_proof::{RangeProofU128, RangeProofU256, RangeProofU64}, range_proof::{RangeProofU128, RangeProofU256, RangeProofU64},
sigma_proofs::{ sigma_proofs::{
AggregatedValidityProof, CiphertextCiphertextEqualityProof, BatchedGroupedCiphertext2HandlesValidityProof, CiphertextCiphertextEqualityProof,
CiphertextCommitmentEqualityProof, FeeSigmaProof, PubkeyValidityProof, ValidityProof, CiphertextCommitmentEqualityProof, FeeSigmaProof, GroupedCiphertext2HandlesValidityProof,
ZeroBalanceProof, PubkeyValidityProof, ZeroBalanceProof,
}, },
}; };

View File

@ -2,15 +2,12 @@
#[cfg(not(target_os = "solana"))] #[cfg(not(target_os = "solana"))]
use crate::sigma_proofs::{ use crate::sigma_proofs::{
batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof as DecodedBatchedGroupedCiphertext2HandlesValidityProof,
ciphertext_ciphertext_equality_proof::CiphertextCiphertextEqualityProof as DecodedCiphertextCiphertextEqualityProof, ciphertext_ciphertext_equality_proof::CiphertextCiphertextEqualityProof as DecodedCiphertextCiphertextEqualityProof,
ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof as DecodedCiphertextCommitmentEqualityProof, ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof as DecodedCiphertextCommitmentEqualityProof,
errors::*, errors::*, fee_proof::FeeSigmaProof as DecodedFeeSigmaProof,
fee_proof::FeeSigmaProof as DecodedFeeSigmaProof, grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof as DecodedGroupedCiphertext2HandlesValidityProof,
pubkey_proof::PubkeyValidityProof as DecodedPubkeyValidityProof, pubkey_proof::PubkeyValidityProof as DecodedPubkeyValidityProof,
validity_proof::{
AggregatedValidityProof as DecodedAggregatedValidityProof,
ValidityProof as DecodedValidityProof,
},
zero_balance_proof::ZeroBalanceProof as DecodedZeroBalanceProof, zero_balance_proof::ZeroBalanceProof as DecodedZeroBalanceProof,
}; };
use crate::zk_token_elgamal::pod::{Pod, Zeroable}; 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)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct ValidityProof(pub [u8; 160]); pub struct GroupedCiphertext2HandlesValidityProof(pub [u8; 160]);
#[cfg(not(target_os = "solana"))] #[cfg(not(target_os = "solana"))]
impl From<DecodedValidityProof> for ValidityProof { impl From<DecodedGroupedCiphertext2HandlesValidityProof>
fn from(decoded_proof: DecodedValidityProof) -> Self { for GroupedCiphertext2HandlesValidityProof
{
fn from(decoded_proof: DecodedGroupedCiphertext2HandlesValidityProof) -> Self {
Self(decoded_proof.to_bytes()) Self(decoded_proof.to_bytes())
} }
} }
#[cfg(not(target_os = "solana"))] #[cfg(not(target_os = "solana"))]
impl TryFrom<ValidityProof> for DecodedValidityProof { impl TryFrom<GroupedCiphertext2HandlesValidityProof>
for DecodedGroupedCiphertext2HandlesValidityProof
{
type Error = ValidityProofError; 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) Self::from_bytes(&pod_proof.0)
} }
} }
/// The `AggregatedValidityProof` type as a `Pod`. /// The `BatchedGroupedCiphertext2HandlesValidityProof` type as a `Pod`.
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(transparent)] #[repr(transparent)]
pub struct AggregatedValidityProof(pub [u8; 160]); pub struct BatchedGroupedCiphertext2HandlesValidityProof(pub [u8; 160]);
#[cfg(not(target_os = "solana"))] #[cfg(not(target_os = "solana"))]
impl From<DecodedAggregatedValidityProof> for AggregatedValidityProof { impl From<DecodedBatchedGroupedCiphertext2HandlesValidityProof>
fn from(decoded_proof: DecodedAggregatedValidityProof) -> Self { for BatchedGroupedCiphertext2HandlesValidityProof
{
fn from(decoded_proof: DecodedBatchedGroupedCiphertext2HandlesValidityProof) -> Self {
Self(decoded_proof.to_bytes()) Self(decoded_proof.to_bytes())
} }
} }
#[cfg(not(target_os = "solana"))] #[cfg(not(target_os = "solana"))]
impl TryFrom<AggregatedValidityProof> for DecodedAggregatedValidityProof { impl TryFrom<BatchedGroupedCiphertext2HandlesValidityProof>
for DecodedBatchedGroupedCiphertext2HandlesValidityProof
{
type Error = ValidityProofError; 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) Self::from_bytes(&pod_proof.0)
} }
} }
@ -171,11 +178,11 @@ unsafe impl Pod for CiphertextCommitmentEqualityProof {}
unsafe impl Zeroable for CiphertextCiphertextEqualityProof {} unsafe impl Zeroable for CiphertextCiphertextEqualityProof {}
unsafe impl Pod for CiphertextCiphertextEqualityProof {} unsafe impl Pod for CiphertextCiphertextEqualityProof {}
unsafe impl Zeroable for ValidityProof {} unsafe impl Zeroable for GroupedCiphertext2HandlesValidityProof {}
unsafe impl Pod for ValidityProof {} unsafe impl Pod for GroupedCiphertext2HandlesValidityProof {}
unsafe impl Zeroable for AggregatedValidityProof {} unsafe impl Zeroable for BatchedGroupedCiphertext2HandlesValidityProof {}
unsafe impl Pod for AggregatedValidityProof {} unsafe impl Pod for BatchedGroupedCiphertext2HandlesValidityProof {}
unsafe impl Zeroable for ZeroBalanceProof {} unsafe impl Zeroable for ZeroBalanceProof {}
unsafe impl Pod for ZeroBalanceProof {} unsafe impl Pod for ZeroBalanceProof {}