Skip to content

Commit

Permalink
[zk-token-sdk] Re-organize error types (solana-labs#34034)
Browse files Browse the repository at this point in the history
* add deserialization error type for encryption

* re-organize sigma proof error types

* re-organize range proof error types

* update pod conversion module

* update instruction error types

* clippy

* fix `thiserror` visibility

* Apply suggestions from code review

Co-authored-by: Jon Cinque <[email protected]>

---------

Co-authored-by: Jon Cinque <[email protected]>
  • Loading branch information
samkim-crypto and joncinque authored Nov 16, 2023
1 parent 2c71d21 commit 0fd4762
Show file tree
Hide file tree
Showing 41 changed files with 450 additions and 358 deletions.
2 changes: 2 additions & 0 deletions zk-token-sdk/src/encryption/auth_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ pub enum AuthenticatedEncryptionError {
SeedLengthTooShort,
#[error("seed length too long for derivation")]
SeedLengthTooLong,
#[error("failed to deserialize")]
Deserialization,
}

struct AuthenticatedEncryption;
Expand Down
4 changes: 4 additions & 0 deletions zk-token-sdk/src/encryption/elgamal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ pub enum ElGamalError {
SeedLengthTooShort,
#[error("seed length too long for derivation")]
SeedLengthTooLong,
#[error("failed to deserialize ciphertext")]
CiphertextDeserialization,
#[error("failed to deserialize public key")]
PubkeyDeserialization,
}

/// Algorithm handle for the twisted ElGamal encryption scheme
Expand Down
107 changes: 48 additions & 59 deletions zk-token-sdk/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,55 +1,50 @@
//! Errors related to proving and verifying proofs.
use {
crate::{range_proof::errors::RangeProofError, sigma_proofs::errors::*},
crate::{
encryption::elgamal::ElGamalError,
range_proof::errors::{RangeProofGenerationError, RangeProofVerificationError},
sigma_proofs::errors::*,
},
thiserror::Error,
};

#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum ProofError {
#[error("invalid transfer amount range")]
TransferAmount,
#[error("proof generation failed")]
Generation,
#[error("proof verification failed")]
VerificationError(ProofType, ProofVerificationError),
#[error("failed to decrypt ciphertext")]
Decryption,
#[error("invalid ciphertext data")]
CiphertextDeserialization,
#[error("invalid pubkey data")]
PubkeyDeserialization,
#[error("ciphertext does not exist in instruction data")]
MissingCiphertext,
pub enum ProofGenerationError {
#[error("not enough funds in account")]
NotEnoughFunds,
#[error("transfer fee calculation error")]
FeeCalculation,
#[error("illegal number of commitments")]
IllegalCommitmentLength,
#[error("illegal amount bit length")]
IllegalAmountBitLength,
#[error("invalid commitment")]
InvalidCommitment,
#[error("range proof generation failed")]
RangeProof(#[from] RangeProofGenerationError),
#[error("unexpected proof length")]
ProofLength,
}

#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum ProofVerificationError {
#[error("range proof verification failed")]
RangeProof(#[from] RangeProofVerificationError),
#[error("sigma proof verification failed")]
SigmaProof(SigmaProofType, SigmaProofVerificationError),
#[error("ElGamal ciphertext or public key error")]
ElGamal(#[from] ElGamalError),
#[error("Invalid proof context")]
ProofContext,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ProofType {
pub enum SigmaProofType {
EqualityProof,
ValidityProof,
ZeroBalanceProof,
FeeSigmaProof,
PubkeyValidityProof,
RangeProof,
}

#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum ProofVerificationError {
#[error("required algebraic relation does not hold")]
AlgebraicRelation,
#[error("malformed proof")]
Deserialization,
#[error("multiscalar multiplication failed")]
MultiscalarMul,
#[error("transcript failed to produce a challenge")]
Transcript(#[from] TranscriptError),
#[error(
"attempted to verify range proof with a non-power-of-two bit size or bit size is too big"
)]
InvalidBitSize,
#[error("insufficient generators for the proof")]
InvalidGeneratorsLength,
#[error("number of blinding factors do not match the number of values")]
WrongNumBlindingFactors,
}

#[derive(Error, Clone, Debug, Eq, PartialEq)]
Expand All @@ -58,37 +53,31 @@ pub enum TranscriptError {
ValidationError,
}

impl From<RangeProofError> for ProofError {
fn from(err: RangeProofError) -> Self {
Self::VerificationError(ProofType::RangeProof, err.0)
}
}

impl From<EqualityProofError> for ProofError {
fn from(err: EqualityProofError) -> Self {
Self::VerificationError(ProofType::EqualityProof, err.0)
impl From<EqualityProofVerificationError> for ProofVerificationError {
fn from(err: EqualityProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::EqualityProof, err.0)
}
}

impl From<FeeSigmaProofError> for ProofError {
fn from(err: FeeSigmaProofError) -> Self {
Self::VerificationError(ProofType::FeeSigmaProof, err.0)
impl From<FeeSigmaProofVerificationError> for ProofVerificationError {
fn from(err: FeeSigmaProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::FeeSigmaProof, err.0)
}
}

impl From<ZeroBalanceProofError> for ProofError {
fn from(err: ZeroBalanceProofError) -> Self {
Self::VerificationError(ProofType::ZeroBalanceProof, err.0)
impl From<ZeroBalanceProofVerificationError> for ProofVerificationError {
fn from(err: ZeroBalanceProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::ZeroBalanceProof, err.0)
}
}
impl From<ValidityProofError> for ProofError {
fn from(err: ValidityProofError) -> Self {
Self::VerificationError(ProofType::ValidityProof, err.0)
impl From<ValidityProofVerificationError> for ProofVerificationError {
fn from(err: ValidityProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::ValidityProof, err.0)
}
}

impl From<PubkeyValidityProofError> for ProofError {
fn from(err: PubkeyValidityProofError) -> Self {
Self::VerificationError(ProofType::PubkeyValidityProof, err.0)
impl From<PubkeyValidityProofVerificationError> for ProofVerificationError {
fn from(err: PubkeyValidityProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::PubkeyValidityProof, err.0)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use {
elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
pedersen::PedersenOpening,
},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::batched_grouped_ciphertext_validity_proof::BatchedGroupedCiphertext2HandlesValidityProof,
transcript::TranscriptProtocol,
},
Expand Down Expand Up @@ -69,7 +69,7 @@ impl BatchedGroupedCiphertext2HandlesValidityProofData {
amount_hi: u64,
opening_lo: &PedersenOpening,
opening_hi: &PedersenOpening,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
let pod_destination_pubkey = pod::ElGamalPubkey(destination_pubkey.to_bytes());
let pod_auditor_pubkey = pod::ElGamalPubkey(auditor_pubkey.to_bytes());
let pod_grouped_ciphertext_lo = (*grouped_ciphertext_lo).into();
Expand Down Expand Up @@ -106,7 +106,7 @@ impl ZkProofData<BatchedGroupedCiphertext2HandlesValidityProofContext>
}

#[cfg(not(target_os = "solana"))]
fn verify_proof(&self) -> Result<(), ProofError> {
fn verify_proof(&self) -> Result<(), ProofVerificationError> {
let mut transcript = self.context.new_transcript();

let destination_pubkey = self.context.destination_pubkey.try_into()?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
},
std::convert::TryInto,
Expand Down Expand Up @@ -39,26 +39,29 @@ impl BatchedRangeProofU128Data {
amounts: Vec<u64>,
bit_lengths: Vec<usize>,
openings: Vec<&PedersenOpening>,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
// the sum of the bit lengths must be 64
let batched_bit_length = bit_lengths
.iter()
.try_fold(0_usize, |acc, &x| acc.checked_add(x))
.ok_or(ProofError::Generation)?;
.ok_or(ProofGenerationError::IllegalAmountBitLength)?;

// `u64::BITS` is 128, which fits in a single byte and should not overflow to `usize` for
// an overwhelming number of platforms. However, to be extra cautious, use `try_from` and
// `unwrap` here. A simple case `u128::BITS as usize` can silently overflow.
let expected_bit_length = usize::try_from(u128::BITS).unwrap();
if batched_bit_length != expected_bit_length {
return Err(ProofError::Generation);
return Err(ProofGenerationError::IllegalAmountBitLength);
}

let context =
BatchedRangeProofContext::new(&commitments, &amounts, &bit_lengths, &openings)?;

let mut transcript = context.new_transcript();
let proof = RangeProof::new(amounts, bit_lengths, openings, &mut transcript).try_into()?;
let proof: pod::RangeProofU128 =
RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?;

Ok(Self { context, proof })
}
Expand All @@ -72,7 +75,7 @@ impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU128Data {
}

#[cfg(not(target_os = "solana"))]
fn verify_proof(&self) -> Result<(), ProofError> {
fn verify_proof(&self) -> Result<(), ProofVerificationError> {
let (commitments, bit_lengths) = self.context.try_into()?;
let mut transcript = self.context_data().new_transcript();
let proof: RangeProof = self.proof.try_into()?;
Expand All @@ -88,8 +91,8 @@ mod test {
use {
super::*,
crate::{
encryption::pedersen::Pedersen,
errors::{ProofType, ProofVerificationError},
encryption::pedersen::Pedersen, errors::ProofVerificationError,
range_proof::errors::RangeProofVerificationError,
},
};

Expand Down Expand Up @@ -179,10 +182,7 @@ mod test {

assert_eq!(
proof_data.verify_proof().unwrap_err(),
ProofError::VerificationError(
ProofType::RangeProof,
ProofVerificationError::AlgebraicRelation
),
ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
},
std::convert::TryInto,
Expand Down Expand Up @@ -42,21 +42,23 @@ impl BatchedRangeProofU256Data {
amounts: Vec<u64>,
bit_lengths: Vec<usize>,
openings: Vec<&PedersenOpening>,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
// the sum of the bit lengths must be 64
let batched_bit_length = bit_lengths
.iter()
.try_fold(0_usize, |acc, &x| acc.checked_add(x))
.ok_or(ProofError::Generation)?;
.ok_or(ProofGenerationError::IllegalAmountBitLength)?;
if batched_bit_length != BATCHED_RANGE_PROOF_U256_BIT_LENGTH {
return Err(ProofError::Generation);
return Err(ProofGenerationError::IllegalAmountBitLength);
}

let context =
BatchedRangeProofContext::new(&commitments, &amounts, &bit_lengths, &openings)?;

let mut transcript = context.new_transcript();
let proof = RangeProof::new(amounts, bit_lengths, openings, &mut transcript).try_into()?;
let proof = RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?;

Ok(Self { context, proof })
}
Expand All @@ -70,7 +72,7 @@ impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU256Data {
}

#[cfg(not(target_os = "solana"))]
fn verify_proof(&self) -> Result<(), ProofError> {
fn verify_proof(&self) -> Result<(), ProofVerificationError> {
let (commitments, bit_lengths) = self.context.try_into()?;
let mut transcript = self.context_data().new_transcript();
let proof: RangeProof = self.proof.try_into()?;
Expand All @@ -86,8 +88,8 @@ mod test {
use {
super::*,
crate::{
encryption::pedersen::Pedersen,
errors::{ProofType, ProofVerificationError},
encryption::pedersen::Pedersen, errors::ProofVerificationError,
range_proof::errors::RangeProofVerificationError,
},
};

Expand Down Expand Up @@ -177,10 +179,7 @@ mod test {

assert_eq!(
proof_data.verify_proof().unwrap_err(),
ProofError::VerificationError(
ProofType::RangeProof,
ProofVerificationError::AlgebraicRelation
),
ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
);
}
}
Loading

0 comments on commit 0fd4762

Please sign in to comment.