feat: add separate error types for sigma proofs

This commit is contained in:
Sam Kim 2022-01-04 08:13:54 -05:00 committed by Michael Vines
parent 7439d2424b
commit 1cbcda71cb
8 changed files with 109 additions and 62 deletions

View File

@ -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<RangeProofError> for ProofError {
fn from(err: RangeProofError) -> Self {
Self::RangeProofError
}
}

View File

@ -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],

View File

@ -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],

View File

@ -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")]

View File

@ -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<Scalar>, Vec<Scalar>, Vec<Scalar>), ProofError> {
) -> Result<(Vec<Scalar>, Vec<Scalar>, Vec<Scalar>), 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<<lg_n below.
return Err(ProofError::VerificationError);
return Err(RangeProofError::InvalidBitsize);
}
if n != (1 << lg_n) {
return Err(ProofError::VerificationError);
return Err(RangeProofError::InvalidBitsize);
}
transcript.innerproduct_domain_sep(n as u64);
@ -266,7 +266,7 @@ impl InnerProductProof {
G: &[RistrettoPoint],
H: &[RistrettoPoint],
transcript: &mut Transcript,
) -> Result<(), ProofError>
) -> Result<(), RangeProofError>
where
IG: IntoIterator,
IG::Item: Borrow<Scalar>,
@ -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::<Result<Vec<_>, _>>()?;
let Rs = self
.R_vec
.iter()
.map(|p| p.decompress().ok_or(ProofError::VerificationError))
.map(|p| p.decompress().ok_or(RangeProofError::FormatError))
.collect::<Result<Vec<_>, _>>()?;
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<InnerProductProof64, ProofError> {
// 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<Item = u8> + '_ {
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<InnerProductProof, ProofError> {
pub fn from_bytes(slice: &[u8]) -> Result<InnerProductProof, RangeProofError> {
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<CompressedRistretto> = 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 })
}

View File

@ -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<usize>,
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<Scalar> = 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<RangeProof, ProofError> {
pub fn from_bytes(slice: &[u8]) -> Result<RangeProof, RangeProofError> {
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],

View File

@ -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<TranscriptError> 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<TranscriptError> 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<TranscriptError> for ZeroBalanceProof {
fn from(err: TranscriptError) -> Self {
Self::TranscriptError
}
}

View File

@ -1,4 +1,5 @@
pub mod equality_proof;
pub mod errors;
pub mod fee_proof;
pub mod validity_proof;
pub mod zero_balance_proof;