feat: add separate error types for sigma proofs
This commit is contained in:
parent
7439d2424b
commit
1cbcda71cb
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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")]
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
pub mod equality_proof;
|
||||
pub mod errors;
|
||||
pub mod fee_proof;
|
||||
pub mod validity_proof;
|
||||
pub mod zero_balance_proof;
|
||||
|
|
Loading…
Reference in New Issue