diff --git a/zk-token-sdk/src/errors.rs b/zk-token-sdk/src/errors.rs index d494fde0c..5bd836370 100644 --- a/zk-token-sdk/src/errors.rs +++ b/zk-token-sdk/src/errors.rs @@ -1,10 +1,15 @@ //! Errors related to proving and verifying proofs. use thiserror::Error; +use crate::range_proof::errors::RangeProofError; #[derive(Error, Clone, Debug, Eq, PartialEq)] pub enum ProofError { #[error("proof failed to verify")] VerificationError, + #[error("range proof failed to verify")] + RangeProofError, + #[error("sigma proof failed to verify")] + SigmaProofError, #[error( "`zk_token_elgamal::pod::ElGamalCiphertext` contains invalid ElGamalCiphertext ciphertext" )] @@ -16,3 +21,9 @@ pub enum TranscriptError { #[error("point is the identity")] ValidationError, } + +impl From for ProofError { + fn from(err: RangeProofError) -> Self { + Self::RangeProofError + } +} diff --git a/zk-token-sdk/src/instruction/transfer.rs b/zk-token-sdk/src/instruction/transfer.rs index 08a9b4658..8a75f92f1 100644 --- a/zk-token-sdk/src/instruction/transfer.rs +++ b/zk-token-sdk/src/instruction/transfer.rs @@ -266,7 +266,7 @@ impl TransferProof { ValidityProof::new(dest_pk, auditor_pk, transfer_amt, openings, &mut transcript); // generate the range proof - let range_proof = RangeProof::create( + let range_proof = RangeProof::new( vec![source_new_balance, transfer_amt.0, transfer_amt.1], vec![64, 32, 32], vec![&source_open, openings.0, openings.1], diff --git a/zk-token-sdk/src/instruction/withdraw.rs b/zk-token-sdk/src/instruction/withdraw.rs index f62356a0f..4eed0b34e 100644 --- a/zk-token-sdk/src/instruction/withdraw.rs +++ b/zk-token-sdk/src/instruction/withdraw.rs @@ -136,7 +136,7 @@ impl WithdrawProof { &mut transcript, ); - let range_proof = RangeProof::create( + let range_proof = RangeProof::new( vec![final_balance], vec![64], vec![&opening], diff --git a/zk-token-sdk/src/range_proof/errors.rs b/zk-token-sdk/src/range_proof/errors.rs index f9f7b3410..70b32656d 100644 --- a/zk-token-sdk/src/range_proof/errors.rs +++ b/zk-token-sdk/src/range_proof/errors.rs @@ -1,4 +1,4 @@ -//! Errors related to proving and verifying proofs. +//! Errors related to proving and verifying range proofs. use thiserror::Error; use crate::errors::TranscriptError; @@ -8,10 +8,12 @@ pub enum RangeProofError { AlgebraicRelationError, #[error("malformed proof")] FormatError, - #[error("attempted to create a proof with a non-power-of-two bitsize")] + #[error("attempted to create a proof with a non-power-of-two bitsize or bitsize too big")] InvalidBitsize, #[error("insufficient generators for the proof")] InvalidGeneratorsLength, + #[error("multiscalar multiplication failed")] + MultiscalarMulError, #[error("transcript failed to produce a challenge")] TranscriptError, #[error("number of blinding factors do not match the number of values")] diff --git a/zk-token-sdk/src/range_proof/inner_product.rs b/zk-token-sdk/src/range_proof/inner_product.rs index bf8e14086..45d0310ad 100644 --- a/zk-token-sdk/src/range_proof/inner_product.rs +++ b/zk-token-sdk/src/range_proof/inner_product.rs @@ -1,5 +1,5 @@ use { - crate::{errors::ProofError, range_proof::util, transcript::TranscriptProtocol}, + crate::{range_proof::{errors::RangeProofError, util}, transcript::TranscriptProtocol}, core::iter, curve25519_dalek::{ ristretto::{CompressedRistretto, RistrettoPoint}, @@ -200,15 +200,15 @@ impl InnerProductProof { &self, n: usize, transcript: &mut Transcript, - ) -> Result<(Vec, Vec, Vec), ProofError> { + ) -> Result<(Vec, Vec, Vec), RangeProofError> { let lg_n = self.L_vec.len(); if lg_n >= 32 { // 4 billion multiplications should be enough for anyone // and this check prevents overflow in 1< Result<(), ProofError> + ) -> Result<(), RangeProofError> where IG: IntoIterator, IG::Item: Borrow, @@ -295,13 +295,13 @@ impl InnerProductProof { let Ls = self .L_vec .iter() - .map(|p| p.decompress().ok_or(ProofError::VerificationError)) + .map(|p| p.decompress().ok_or(RangeProofError::FormatError)) .collect::, _>>()?; let Rs = self .R_vec .iter() - .map(|p| p.decompress().ok_or(ProofError::VerificationError)) + .map(|p| p.decompress().ok_or(RangeProofError::FormatError)) .collect::, _>>()?; let expect_P = RistrettoPoint::vartime_multiscalar_mul( @@ -320,7 +320,7 @@ impl InnerProductProof { if expect_P == *P { Ok(()) } else { - Err(ProofError::VerificationError) + Err(RangeProofError::AlgebraicRelationError) } } @@ -348,55 +348,27 @@ impl InnerProductProof { buf } - // pub fn to_bytes_64(&self) -> Result { - // let mut bytes = [0u8; 448]; - - // self.L_vec.iter().chain(self.R_vec.iter()).enumerate().for_each( - // |(i, x)| bytes[i*32..(i+1)*32].copy_from_slice(x.as_bytes()) - // ); - // bytes[384..416].copy_from_slice(self.a.as_bytes()); - // bytes[416..448].copy_from_slice(self.a.as_bytes()); - // Ok(InnerProductProof64(bytes)) - // } - - /* - /// Converts the proof into a byte iterator over serialized view of the proof. - /// The layout of the inner product proof is: - /// * \\(n\\) pairs of compressed Ristretto points \\(L_0, R_0 \dots, L_{n-1}, R_{n-1}\\), - /// * two scalars \\(a, b\\). - #[inline] - pub(crate) fn to_bytes_iter(&self) -> impl Iterator + '_ { - self.L_vec - .iter() - .zip(self.R_vec.iter()) - .flat_map(|(l, r)| l.as_bytes().iter().chain(r.as_bytes())) - .chain(self.a.as_bytes()) - .chain(self.b.as_bytes()) - .copied() - } - */ - /// Deserializes the proof from a byte slice. /// Returns an error in the following cases: /// * the slice does not have \\(2n+2\\) 32-byte elements, /// * \\(n\\) is larger or equal to 32 (proof is too big), /// * any of \\(2n\\) points are not valid compressed Ristretto points, /// * any of 2 scalars are not canonical scalars modulo Ristretto group order. - pub fn from_bytes(slice: &[u8]) -> Result { + pub fn from_bytes(slice: &[u8]) -> Result { let b = slice.len(); if b % 32 != 0 { - return Err(ProofError::FormatError); + return Err(RangeProofError::FormatError); } let num_elements = b / 32; if num_elements < 2 { - return Err(ProofError::FormatError); + return Err(RangeProofError::FormatError); } if (num_elements - 2) % 2 != 0 { - return Err(ProofError::FormatError); + return Err(RangeProofError::FormatError); } let lg_n = (num_elements - 2) / 2; if lg_n >= 32 { - return Err(ProofError::FormatError); + return Err(RangeProofError::FormatError); } let mut L_vec: Vec = Vec::with_capacity(lg_n); @@ -409,9 +381,9 @@ impl InnerProductProof { let pos = 2 * lg_n * 32; let a = Scalar::from_canonical_bytes(util::read32(&slice[pos..])) - .ok_or(ProofError::FormatError)?; + .ok_or(RangeProofError::FormatError)?; let b = Scalar::from_canonical_bytes(util::read32(&slice[pos + 32..])) - .ok_or(ProofError::FormatError)?; + .ok_or(RangeProofError::FormatError)?; Ok(InnerProductProof { L_vec, R_vec, a, b }) } diff --git a/zk-token-sdk/src/range_proof/mod.rs b/zk-token-sdk/src/range_proof/mod.rs index 37fbd89f8..88e04add7 100644 --- a/zk-token-sdk/src/range_proof/mod.rs +++ b/zk-token-sdk/src/range_proof/mod.rs @@ -67,6 +67,7 @@ impl RangeProof { assert!(nm.is_power_of_two()); // TODO: precompute generators + // TODO: double check Pedersen generators and range proof generators does not interfere let bp_gens = BulletproofGens::new(nm); let G = PedersenBase::default().G; let H = PedersenBase::default().H; @@ -222,6 +223,9 @@ impl RangeProof { bit_lengths: Vec, transcript: &mut Transcript, ) -> Result<(), RangeProofError> { + // commitments and bit-lengths must be same length vectors + assert_eq!(comms.len(), bit_lengths.len()); + let G = PedersenBase::default().G; let H = PedersenBase::default().H; @@ -233,6 +237,7 @@ impl RangeProof { return Err(RangeProofError::InvalidBitsize); } + // append proof data to transcript and derive appropriate challenge scalars transcript.validate_and_append_point(b"A", &self.A)?; transcript.validate_and_append_point(b"S", &self.S)?; @@ -252,17 +257,16 @@ impl RangeProof { transcript.append_scalar(b"e_blinding", &self.e_blinding); let w = transcript.challenge_scalar(b"w"); + let c = transcript.challenge_scalar(b"c"); // challenge value for batching multiscalar mul - // Challenge value for batching statements to be verified - let c = transcript.challenge_scalar(b"c"); - + // verify inner product proof let (x_sq, x_inv_sq, s) = self.ipp_proof.verification_scalars(nm, transcript)?; let s_inv = s.iter().rev(); let a = self.ipp_proof.a; let b = self.ipp_proof.b; - // Construct concat_z_and_2, an iterator of the values of + // construct concat_z_and_2, an iterator of the values of // z^0 * \vec(2)^n || z^1 * \vec(2)^n || ... || z^(m-1) * \vec(2)^n let concat_z_and_2: Vec = util::exp_iter(z) .zip(bit_lengths.iter()) @@ -308,12 +312,12 @@ impl RangeProof { .chain(bp_gens.H(nm).map(|&x| Some(x))) .chain(comms.iter().map(|V| V.decompress())), ) - .ok_or(ProofError::VerificationError)?; + .ok_or(RangeProofError::MultiscalarMulError)?; if mega_check.is_identity() { - Ok((z, x)) + Ok(()) } else { - Err(ProofError::VerificationError) + Err(RangeProofError::AlgebraicRelationError) } } @@ -334,12 +338,12 @@ impl RangeProof { // Following the dalek rangeproof library signature for now. The exact method signature can be // changed. - pub fn from_bytes(slice: &[u8]) -> Result { + pub fn from_bytes(slice: &[u8]) -> Result { if slice.len() % 32 != 0 { - return Err(ProofError::FormatError); + return Err(RangeProofError::FormatError); } if slice.len() < 7 * 32 { - return Err(ProofError::FormatError); + return Err(RangeProofError::FormatError); } let A = CompressedRistretto(util::read32(&slice[0..])); @@ -348,11 +352,11 @@ impl RangeProof { let T_2 = CompressedRistretto(util::read32(&slice[3 * 32..])); let t_x = Scalar::from_canonical_bytes(util::read32(&slice[4 * 32..])) - .ok_or(ProofError::FormatError)?; + .ok_or(RangeProofError::FormatError)?; let t_x_blinding = Scalar::from_canonical_bytes(util::read32(&slice[5 * 32..])) - .ok_or(ProofError::FormatError)?; + .ok_or(RangeProofError::FormatError)?; let e_blinding = Scalar::from_canonical_bytes(util::read32(&slice[6 * 32..])) - .ok_or(ProofError::FormatError)?; + .ok_or(RangeProofError::FormatError)?; let ipp_proof = InnerProductProof::from_bytes(&slice[7 * 32..])?; @@ -398,7 +402,7 @@ mod tests { let mut transcript_create = Transcript::new(b"Test"); let mut transcript_verify = Transcript::new(b"Test"); - let proof = RangeProof::create(vec![55], vec![32], vec![&open], &mut transcript_create); + let proof = RangeProof::new(vec![55], vec![32], vec![&open], &mut transcript_create); assert!(proof .verify( @@ -418,7 +422,7 @@ mod tests { let mut transcript_create = Transcript::new(b"Test"); let mut transcript_verify = Transcript::new(b"Test"); - let proof = RangeProof::create( + let proof = RangeProof::new( vec![55, 77, 99], vec![64, 32, 32], vec![&open_1, &open_2, &open_3], diff --git a/zk-token-sdk/src/sigma_proofs/errors.rs b/zk-token-sdk/src/sigma_proofs/errors.rs new file mode 100644 index 000000000..68695ee88 --- /dev/null +++ b/zk-token-sdk/src/sigma_proofs/errors.rs @@ -0,0 +1,57 @@ +//! Errors related to proving and verifying sigma proofs. +use thiserror::Error; +use crate::errors::TranscriptError; + +#[derive(Error, Clone, Debug, Eq, PartialEq)] +pub enum EqualityProof { + #[error("the required algebraic relation does not hold")] + AlgebraicRelationError, + #[error("malformed proof")] + FormatError, + #[error("multiscalar multiplication failed")] + MultiscalarMulError, + #[error("transcript failed to produce a challenge")] + TranscriptError, +} + +impl From for EqualityProof { + fn from(err: TranscriptError) -> Self { + Self::TranscriptError + } +} + +#[derive(Error, Clone, Debug, Eq, PartialEq)] +pub enum ValidityProof { + #[error("the required algebraic relation does not hold")] + AlgebraicRelationError, + #[error("malformed proof")] + FormatError, + #[error("multiscalar multiplication failed")] + MultiscalarMulError, + #[error("transcript failed to produce a challenge")] + TranscriptError, +} + +impl From for ValidityProof { + fn from(err: TranscriptError) -> Self { + Self::TranscriptError + } +} + +#[derive(Error, Clone, Debug, Eq, PartialEq)] +pub enum ZeroBalanceProof { + #[error("the required algebraic relation does not hold")] + AlgebraicRelationError, + #[error("malformed proof")] + FormatError, + #[error("multiscalar multiplication failed")] + MultiscalarMulError, + #[error("transcript failed to produce a challenge")] + TranscriptError, +} + +impl From for ZeroBalanceProof { + fn from(err: TranscriptError) -> Self { + Self::TranscriptError + } +} diff --git a/zk-token-sdk/src/sigma_proofs/mod.rs b/zk-token-sdk/src/sigma_proofs/mod.rs index bb1abbd98..c7d731d9f 100644 --- a/zk-token-sdk/src/sigma_proofs/mod.rs +++ b/zk-token-sdk/src/sigma_proofs/mod.rs @@ -1,4 +1,5 @@ pub mod equality_proof; +pub mod errors; pub mod fee_proof; pub mod validity_proof; pub mod zero_balance_proof;