[zk-token-sdk] Re-organize error types (#34034)

* 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 <me@jonc.dev>

---------

Co-authored-by: Jon Cinque <me@jonc.dev>
This commit is contained in:
samkim-crypto 2023-11-17 07:00:47 +09:00 committed by GitHub
parent 2c71d21fad
commit 0fd4762399
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 452 additions and 360 deletions

View File

@ -52,6 +52,8 @@ pub enum AuthenticatedEncryptionError {
SeedLengthTooShort,
#[error("seed length too long for derivation")]
SeedLengthTooLong,
#[error("failed to deserialize")]
Deserialization,
}
struct AuthenticatedEncryption;

View File

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

View File

@ -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)]
@ -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<EqualityProofVerificationError> for ProofVerificationError {
fn from(err: EqualityProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::EqualityProof, err.0)
}
}
impl From<EqualityProofError> for ProofError {
fn from(err: EqualityProofError) -> Self {
Self::VerificationError(ProofType::EqualityProof, err.0)
impl From<FeeSigmaProofVerificationError> for ProofVerificationError {
fn from(err: FeeSigmaProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::FeeSigmaProof, err.0)
}
}
impl From<FeeSigmaProofError> for ProofError {
fn from(err: FeeSigmaProofError) -> Self {
Self::VerificationError(ProofType::FeeSigmaProof, err.0)
impl From<ZeroBalanceProofVerificationError> for ProofVerificationError {
fn from(err: ZeroBalanceProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::ZeroBalanceProof, err.0)
}
}
impl From<ValidityProofVerificationError> for ProofVerificationError {
fn from(err: ValidityProofVerificationError) -> Self {
Self::SigmaProof(SigmaProofType::ValidityProof, err.0)
}
}
impl From<ZeroBalanceProofError> for ProofError {
fn from(err: ZeroBalanceProofError) -> Self {
Self::VerificationError(ProofType::ZeroBalanceProof, err.0)
}
}
impl From<ValidityProofError> for ProofError {
fn from(err: ValidityProofError) -> Self {
Self::VerificationError(ProofType::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)
}
}

View File

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

View File

@ -4,7 +4,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
},
std::convert::TryInto,
@ -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 })
}
@ -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()?;
@ -88,8 +91,8 @@ mod test {
use {
super::*,
crate::{
encryption::pedersen::Pedersen,
errors::{ProofType, ProofVerificationError},
encryption::pedersen::Pedersen, errors::ProofVerificationError,
range_proof::errors::RangeProofVerificationError,
},
};
@ -179,10 +182,7 @@ mod test {
assert_eq!(
proof_data.verify_proof().unwrap_err(),
ProofError::VerificationError(
ProofType::RangeProof,
ProofVerificationError::AlgebraicRelation
),
ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
);
}
}

View File

@ -4,7 +4,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
},
std::convert::TryInto,
@ -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 })
}
@ -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()?;
@ -86,8 +88,8 @@ mod test {
use {
super::*,
crate::{
encryption::pedersen::Pedersen,
errors::{ProofType, ProofVerificationError},
encryption::pedersen::Pedersen, errors::ProofVerificationError,
range_proof::errors::RangeProofVerificationError,
},
};
@ -177,10 +179,7 @@ mod test {
assert_eq!(
proof_data.verify_proof().unwrap_err(),
ProofError::VerificationError(
ProofType::RangeProof,
ProofVerificationError::AlgebraicRelation
),
ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
);
}
}

View File

@ -4,7 +4,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
},
std::convert::TryInto,
@ -39,26 +39,28 @@ impl BatchedRangeProofU64Data {
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 64, 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 `u64::BITS as usize` can silently overflow.
let expected_bit_length = usize::try_from(u64::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 = RangeProof::new(amounts, bit_lengths, openings, &mut transcript)?
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?;
Ok(Self { context, proof })
}
@ -72,7 +74,7 @@ impl ZkProofData<BatchedRangeProofContext> for BatchedRangeProofU64Data {
}
#[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()?;
@ -88,8 +90,8 @@ mod test {
use {
super::*,
crate::{
encryption::pedersen::Pedersen,
errors::{ProofType, ProofVerificationError},
encryption::pedersen::Pedersen, errors::ProofVerificationError,
range_proof::errors::RangeProofVerificationError,
},
};
@ -179,10 +181,7 @@ mod test {
assert_eq!(
proof_data.verify_proof().unwrap_err(),
ProofError::VerificationError(
ProofType::RangeProof,
ProofVerificationError::AlgebraicRelation
),
ProofVerificationError::RangeProof(RangeProofVerificationError::AlgebraicRelation),
);
}
}

View File

@ -28,7 +28,7 @@ use {
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
},
bytemuck::bytes_of,
curve25519_dalek::traits::IsIdentity,
@ -63,7 +63,7 @@ impl BatchedRangeProofContext {
amounts: &Vec<u64>,
bit_lengths: &Vec<usize>,
openings: &Vec<&PedersenOpening>,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
// the number of commitments is capped at 8
let num_commitments = commitments.len();
if num_commitments > MAX_COMMITMENTS
@ -71,14 +71,14 @@ impl BatchedRangeProofContext {
|| num_commitments != bit_lengths.len()
|| num_commitments != openings.len()
{
return Err(ProofError::Generation);
return Err(ProofGenerationError::IllegalCommitmentLength);
}
let mut pod_commitments = [pod::PedersenCommitment::zeroed(); MAX_COMMITMENTS];
for (i, commitment) in commitments.iter().enumerate() {
// all-zero commitment is invalid
if commitment.get_point().is_identity() {
return Err(ProofError::Generation);
return Err(ProofGenerationError::InvalidCommitment);
}
pod_commitments[i] = pod::PedersenCommitment(commitment.to_bytes());
}
@ -87,7 +87,7 @@ impl BatchedRangeProofContext {
for (i, bit_length) in bit_lengths.iter().enumerate() {
pod_bit_lengths[i] = (*bit_length)
.try_into()
.map_err(|_| ProofError::Generation)?;
.map_err(|_| ProofGenerationError::IllegalAmountBitLength)?;
}
Ok(BatchedRangeProofContext {
@ -99,7 +99,7 @@ impl BatchedRangeProofContext {
#[cfg(not(target_os = "solana"))]
impl TryInto<(Vec<PedersenCommitment>, Vec<usize>)> for BatchedRangeProofContext {
type Error = ProofError;
type Error = ProofVerificationError;
fn try_into(self) -> Result<(Vec<PedersenCommitment>, Vec<usize>), Self::Error> {
let commitments = self
@ -107,7 +107,8 @@ impl TryInto<(Vec<PedersenCommitment>, Vec<usize>)> for BatchedRangeProofContext
.into_iter()
.take_while(|commitment| *commitment != pod::PedersenCommitment::zeroed())
.map(|commitment| commitment.try_into())
.collect::<Result<Vec<PedersenCommitment>, _>>()?;
.collect::<Result<Vec<PedersenCommitment>, _>>()
.map_err(|_| ProofVerificationError::ProofContext)?;
let bit_lengths: Vec<_> = self
.bit_lengths

View File

@ -15,7 +15,7 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
pedersen::PedersenOpening,
},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::ciphertext_ciphertext_equality_proof::CiphertextCiphertextEqualityProof,
transcript::TranscriptProtocol,
},
@ -65,7 +65,7 @@ impl CiphertextCiphertextEqualityProofData {
destination_ciphertext: &ElGamalCiphertext,
destination_opening: &PedersenOpening,
amount: u64,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
let pod_source_pubkey = pod::ElGamalPubkey(source_keypair.pubkey().to_bytes());
let pod_destination_pubkey = pod::ElGamalPubkey(destination_pubkey.to_bytes());
let pod_source_ciphertext = pod::ElGamalCiphertext(source_ciphertext.to_bytes());
@ -104,7 +104,7 @@ impl ZkProofData<CiphertextCiphertextEqualityProofContext>
}
#[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 source_pubkey = self.context.source_pubkey.try_into()?;

View File

@ -12,7 +12,7 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair},
pedersen::{PedersenCommitment, PedersenOpening},
},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
transcript::TranscriptProtocol,
},
@ -60,7 +60,7 @@ impl CiphertextCommitmentEqualityProofData {
commitment: &PedersenCommitment,
opening: &PedersenOpening,
amount: u64,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
let context = CiphertextCommitmentEqualityProofContext {
pubkey: pod::ElGamalPubkey(keypair.pubkey().to_bytes()),
ciphertext: pod::ElGamalCiphertext(ciphertext.to_bytes()),
@ -91,7 +91,7 @@ impl ZkProofData<CiphertextCommitmentEqualityProofContext>
}
#[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 pubkey = self.context.pubkey.try_into()?;

View File

@ -0,0 +1,11 @@
#[cfg(not(target_os = "solana"))]
use thiserror::Error;
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[cfg(not(target_os = "solana"))]
pub enum InstructionError {
#[error("decryption error")]
Decryption,
#[error("missing ciphertext")]
MissingCiphertext,
}

View File

@ -12,7 +12,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::fee_proof::FeeSigmaProof,
transcript::TranscriptProtocol,
},
@ -72,7 +72,7 @@ impl FeeSigmaProofData {
fee_amount: u64,
delta_fee: u64,
max_fee: u64,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
let pod_fee_commitment = pod::PedersenCommitment(fee_commitment.to_bytes());
let pod_delta_commitment = pod::PedersenCommitment(delta_commitment.to_bytes());
let pod_claimed_commitment = pod::PedersenCommitment(claimed_commitment.to_bytes());
@ -108,7 +108,7 @@ impl ZkProofData<FeeSigmaProofContext> for FeeSigmaProofData {
}
#[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 fee_commitment = self.context.fee_commitment.try_into()?;

View File

@ -17,7 +17,7 @@ use {
elgamal::ElGamalPubkey, grouped_elgamal::GroupedElGamalCiphertext,
pedersen::PedersenOpening,
},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof,
transcript::TranscriptProtocol,
},
@ -62,7 +62,7 @@ impl GroupedCiphertext2HandlesValidityProofData {
grouped_ciphertext: &GroupedElGamalCiphertext<2>,
amount: u64,
opening: &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 = (*grouped_ciphertext).into();
@ -97,7 +97,7 @@ impl ZkProofData<GroupedCiphertext2HandlesValidityProofContext>
}
#[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()?;

View File

@ -6,6 +6,7 @@ pub mod batched_grouped_ciphertext_validity;
pub mod batched_range_proof;
pub mod ciphertext_ciphertext_equality;
pub mod ciphertext_commitment_equality;
pub mod errors;
pub mod fee_sigma;
pub mod grouped_ciphertext_validity;
pub mod pubkey_validity;
@ -15,7 +16,7 @@ pub mod withdraw;
pub mod zero_balance;
#[cfg(not(target_os = "solana"))]
use crate::errors::ProofError;
use crate::errors::ProofVerificationError;
use num_derive::{FromPrimitive, ToPrimitive};
pub use {
batched_grouped_ciphertext_validity::{
@ -75,5 +76,5 @@ pub trait ZkProofData<T: Pod> {
fn context_data(&self) -> &T;
#[cfg(not(target_os = "solana"))]
fn verify_proof(&self) -> Result<(), ProofError>;
fn verify_proof(&self) -> Result<(), ProofVerificationError>;
}

View File

@ -8,8 +8,10 @@
#[cfg(not(target_os = "solana"))]
use {
crate::{
encryption::elgamal::ElGamalKeypair, errors::ProofError,
sigma_proofs::pubkey_proof::PubkeyValidityProof, transcript::TranscriptProtocol,
encryption::elgamal::ElGamalKeypair,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::pubkey_proof::PubkeyValidityProof,
transcript::TranscriptProtocol,
},
merlin::Transcript,
std::convert::TryInto,
@ -47,7 +49,7 @@ pub struct PubkeyValidityProofContext {
#[cfg(not(target_os = "solana"))]
impl PubkeyValidityData {
pub fn new(keypair: &ElGamalKeypair) -> Result<Self, ProofError> {
pub fn new(keypair: &ElGamalKeypair) -> Result<Self, ProofGenerationError> {
let pod_pubkey = pod::ElGamalPubkey(keypair.pubkey().to_bytes());
let context = PubkeyValidityProofContext { pubkey: pod_pubkey };
@ -67,7 +69,7 @@ impl ZkProofData<PubkeyValidityProofContext> for PubkeyValidityData {
}
#[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 pubkey = self.context.pubkey.try_into()?;
let proof: PubkeyValidityProof = self.proof.try_into()?;

View File

@ -8,7 +8,7 @@
use {
crate::{
encryption::pedersen::{PedersenCommitment, PedersenOpening},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
transcript::TranscriptProtocol,
},
@ -50,7 +50,7 @@ impl RangeProofU64Data {
commitment: &PedersenCommitment,
amount: u64,
opening: &PedersenOpening,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
let pod_commitment = pod::PedersenCommitment(commitment.to_bytes());
let context = RangeProofContext {
@ -64,8 +64,9 @@ impl RangeProofU64Data {
// `unwrap` here. A simple case `u64::BITS as usize` can silently overflow.
let bit_size = usize::try_from(u64::BITS).unwrap();
let proof = RangeProof::new(vec![amount], vec![bit_size], vec![opening], &mut transcript)
.try_into()?;
let proof = RangeProof::new(vec![amount], vec![bit_size], vec![opening], &mut transcript)?
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?;
Ok(Self { context, proof })
}
@ -79,7 +80,7 @@ impl ZkProofData<RangeProofContext> for RangeProofU64Data {
}
#[cfg(not(target_os = "solana"))]
fn verify_proof(&self) -> Result<(), ProofError> {
fn verify_proof(&self) -> Result<(), ProofVerificationError> {
let mut transcript = self.context_data().new_transcript();
let commitment = self.context.commitment.try_into()?;
let proof: RangeProof = self.proof.try_into()?;

View File

@ -5,12 +5,15 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey},
pedersen::{Pedersen, PedersenCommitment, PedersenOpening},
},
errors::ProofError,
instruction::transfer::{
combine_lo_hi_ciphertexts, combine_lo_hi_commitments, combine_lo_hi_openings,
combine_lo_hi_u64,
encryption::{FeeEncryption, TransferAmountCiphertext},
split_u64, FeeParameters, Role,
errors::{ProofGenerationError, ProofVerificationError},
instruction::{
errors::InstructionError,
transfer::{
combine_lo_hi_ciphertexts, combine_lo_hi_commitments, combine_lo_hi_openings,
combine_lo_hi_u64,
encryption::{FeeEncryption, TransferAmountCiphertext},
split_u64, FeeParameters, Role,
},
},
range_proof::RangeProof,
sigma_proofs::{
@ -120,7 +123,7 @@ impl TransferWithFeeData {
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
fee_parameters: FeeParameters,
withdraw_withheld_authority_pubkey: &ElGamalPubkey,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
// split and encrypt transfer amount
let (amount_lo, amount_hi) = split_u64(transfer_amount, TRANSFER_AMOUNT_LO_BITS);
@ -140,7 +143,7 @@ impl TransferWithFeeData {
// subtract transfer amount from the spendable ciphertext
let new_spendable_balance = spendable_balance
.checked_sub(transfer_amount)
.ok_or(ProofError::Generation)?;
.ok_or(ProofGenerationError::NotEnoughFunds)?;
let transfer_amount_lo_source = ElGamalCiphertext {
commitment: *ciphertext_lo.get_commitment(),
@ -164,7 +167,7 @@ impl TransferWithFeeData {
// TODO: add comment on delta fee
let (fee_amount, delta_fee) =
calculate_fee(transfer_amount, fee_parameters.fee_rate_basis_points)
.ok_or(ProofError::Generation)?;
.ok_or(ProofGenerationError::FeeCalculation)?;
let below_max = u64::ct_gt(&fee_parameters.maximum_fee, &fee_amount);
let fee_to_encrypt =
@ -222,14 +225,18 @@ impl TransferWithFeeData {
withdraw_withheld_authority_pubkey,
fee_parameters,
&mut transcript,
);
)?;
Ok(Self { context, proof })
}
/// Extracts the lo ciphertexts associated with a transfer-with-fee data
fn ciphertext_lo(&self, role: Role) -> Result<ElGamalCiphertext, ProofError> {
let ciphertext_lo: TransferAmountCiphertext = self.context.ciphertext_lo.try_into()?;
fn ciphertext_lo(&self, role: Role) -> Result<ElGamalCiphertext, InstructionError> {
let ciphertext_lo: TransferAmountCiphertext = self
.context
.ciphertext_lo
.try_into()
.map_err(|_| InstructionError::Decryption)?;
let handle_lo = match role {
Role::Source => Some(ciphertext_lo.get_source_handle()),
@ -244,13 +251,17 @@ impl TransferWithFeeData {
handle: *handle,
})
} else {
Err(ProofError::MissingCiphertext)
Err(InstructionError::MissingCiphertext)
}
}
/// Extracts the lo ciphertexts associated with a transfer-with-fee data
fn ciphertext_hi(&self, role: Role) -> Result<ElGamalCiphertext, ProofError> {
let ciphertext_hi: TransferAmountCiphertext = self.context.ciphertext_hi.try_into()?;
fn ciphertext_hi(&self, role: Role) -> Result<ElGamalCiphertext, InstructionError> {
let ciphertext_hi: TransferAmountCiphertext = self
.context
.ciphertext_hi
.try_into()
.map_err(|_| InstructionError::Decryption)?;
let handle_hi = match role {
Role::Source => Some(ciphertext_hi.get_source_handle()),
@ -265,13 +276,17 @@ impl TransferWithFeeData {
handle: *handle,
})
} else {
Err(ProofError::MissingCiphertext)
Err(InstructionError::MissingCiphertext)
}
}
/// Extracts the lo fee ciphertexts associated with a transfer_with_fee data
fn fee_ciphertext_lo(&self, role: Role) -> Result<ElGamalCiphertext, ProofError> {
let fee_ciphertext_lo: FeeEncryption = self.context.fee_ciphertext_lo.try_into()?;
fn fee_ciphertext_lo(&self, role: Role) -> Result<ElGamalCiphertext, InstructionError> {
let fee_ciphertext_lo: FeeEncryption = self
.context
.fee_ciphertext_lo
.try_into()
.map_err(|_| InstructionError::Decryption)?;
let fee_handle_lo = match role {
Role::Source => None,
@ -288,13 +303,17 @@ impl TransferWithFeeData {
handle: *handle,
})
} else {
Err(ProofError::MissingCiphertext)
Err(InstructionError::MissingCiphertext)
}
}
/// Extracts the hi fee ciphertexts associated with a transfer_with_fee data
fn fee_ciphertext_hi(&self, role: Role) -> Result<ElGamalCiphertext, ProofError> {
let fee_ciphertext_hi: FeeEncryption = self.context.fee_ciphertext_hi.try_into()?;
fn fee_ciphertext_hi(&self, role: Role) -> Result<ElGamalCiphertext, InstructionError> {
let fee_ciphertext_hi: FeeEncryption = self
.context
.fee_ciphertext_hi
.try_into()
.map_err(|_| InstructionError::Decryption)?;
let fee_handle_hi = match role {
Role::Source => None,
@ -311,12 +330,16 @@ impl TransferWithFeeData {
handle: *handle,
})
} else {
Err(ProofError::MissingCiphertext)
Err(InstructionError::MissingCiphertext)
}
}
/// Decrypts transfer amount from transfer-with-fee data
pub fn decrypt_amount(&self, role: Role, sk: &ElGamalSecretKey) -> Result<u64, ProofError> {
pub fn decrypt_amount(
&self,
role: Role,
sk: &ElGamalSecretKey,
) -> Result<u64, InstructionError> {
let ciphertext_lo = self.ciphertext_lo(role)?;
let ciphertext_hi = self.ciphertext_hi(role)?;
@ -327,12 +350,16 @@ impl TransferWithFeeData {
let shifted_amount_hi = amount_hi << TRANSFER_AMOUNT_LO_BITS;
Ok(amount_lo + shifted_amount_hi)
} else {
Err(ProofError::Decryption)
Err(InstructionError::Decryption)
}
}
/// Decrypts transfer amount from transfer-with-fee data
pub fn decrypt_fee_amount(&self, role: Role, sk: &ElGamalSecretKey) -> Result<u64, ProofError> {
pub fn decrypt_fee_amount(
&self,
role: Role,
sk: &ElGamalSecretKey,
) -> Result<u64, InstructionError> {
let ciphertext_lo = self.fee_ciphertext_lo(role)?;
let ciphertext_hi = self.fee_ciphertext_hi(role)?;
@ -343,7 +370,7 @@ impl TransferWithFeeData {
let shifted_fee_amount_hi = fee_amount_hi << FEE_AMOUNT_LO_BITS;
Ok(fee_amount_lo + shifted_fee_amount_hi)
} else {
Err(ProofError::Decryption)
Err(InstructionError::Decryption)
}
}
}
@ -356,7 +383,7 @@ impl ZkProofData<TransferWithFeeProofContext> for TransferWithFeeData {
}
#[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 source_pubkey = self.context.transfer_with_fee_pubkeys.source.try_into()?;
@ -448,7 +475,7 @@ impl TransferWithFeeProof {
withdraw_withheld_authority_pubkey: &ElGamalPubkey,
fee_parameters: FeeParameters,
transcript: &mut Transcript,
) -> Self {
) -> Result<Self, ProofGenerationError> {
let (transfer_amount_lo, ciphertext_lo, opening_lo) = transfer_amount_lo_data;
let (transfer_amount_hi, ciphertext_hi, opening_hi) = transfer_amount_hi_data;
@ -559,17 +586,19 @@ impl TransferWithFeeProof {
opening_fee_hi,
],
transcript,
);
)?;
Self {
Ok(Self {
new_source_commitment: pod_new_source_commitment,
claimed_commitment: pod_claimed_commitment,
equality_proof: equality_proof.into(),
ciphertext_amount_validity_proof: ciphertext_amount_validity_proof.into(),
fee_sigma_proof: fee_sigma_proof.into(),
fee_ciphertext_validity_proof: fee_ciphertext_validity_proof.into(),
range_proof: range_proof.try_into().expect("range proof: length error"),
}
range_proof: range_proof
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?,
})
}
#[allow(clippy::too_many_arguments)]
@ -587,7 +616,7 @@ impl TransferWithFeeProof {
fee_ciphertext_hi: &FeeEncryption,
fee_parameters: FeeParameters,
transcript: &mut Transcript,
) -> Result<(), ProofError> {
) -> Result<(), ProofVerificationError> {
transcript.append_commitment(b"commitment-new-source", &self.new_source_commitment);
let new_source_commitment: PedersenCommitment = self.new_source_commitment.try_into()?;

View File

@ -5,9 +5,12 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey, ElGamalSecretKey},
pedersen::{Pedersen, PedersenCommitment, PedersenOpening},
},
errors::ProofError,
instruction::transfer::{
combine_lo_hi_ciphertexts, encryption::TransferAmountCiphertext, split_u64, Role,
errors::{ProofGenerationError, ProofVerificationError},
instruction::{
errors::InstructionError,
transfer::{
combine_lo_hi_ciphertexts, encryption::TransferAmountCiphertext, split_u64, Role,
},
},
range_proof::RangeProof,
sigma_proofs::{
@ -91,7 +94,7 @@ impl TransferData {
(spendable_balance, ciphertext_old_source): (u64, &ElGamalCiphertext),
source_keypair: &ElGamalKeypair,
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
// split and encrypt transfer amount
let (amount_lo, amount_hi) = split_u64(transfer_amount, TRANSFER_AMOUNT_LO_BITS);
@ -112,7 +115,7 @@ impl TransferData {
// subtract transfer amount from the spendable ciphertext
let new_spendable_balance = spendable_balance
.checked_sub(transfer_amount)
.ok_or(ProofError::Generation)?;
.ok_or(ProofGenerationError::NotEnoughFunds)?;
let transfer_amount_lo_source = ElGamalCiphertext {
commitment: *ciphertext_lo.get_commitment(),
@ -157,14 +160,18 @@ impl TransferData {
&opening_hi,
(new_spendable_balance, &new_source_ciphertext),
&mut transcript,
);
)?;
Ok(Self { context, proof })
}
/// Extracts the lo ciphertexts associated with a transfer data
fn ciphertext_lo(&self, role: Role) -> Result<ElGamalCiphertext, ProofError> {
let ciphertext_lo: TransferAmountCiphertext = self.context.ciphertext_lo.try_into()?;
fn ciphertext_lo(&self, role: Role) -> Result<ElGamalCiphertext, InstructionError> {
let ciphertext_lo: TransferAmountCiphertext = self
.context
.ciphertext_lo
.try_into()
.map_err(|_| InstructionError::Decryption)?;
let handle_lo = match role {
Role::Source => Some(ciphertext_lo.get_source_handle()),
@ -179,13 +186,17 @@ impl TransferData {
handle: *handle,
})
} else {
Err(ProofError::MissingCiphertext)
Err(InstructionError::MissingCiphertext)
}
}
/// Extracts the lo ciphertexts associated with a transfer data
fn ciphertext_hi(&self, role: Role) -> Result<ElGamalCiphertext, ProofError> {
let ciphertext_hi: TransferAmountCiphertext = self.context.ciphertext_hi.try_into()?;
fn ciphertext_hi(&self, role: Role) -> Result<ElGamalCiphertext, InstructionError> {
let ciphertext_hi: TransferAmountCiphertext = self
.context
.ciphertext_hi
.try_into()
.map_err(|_| InstructionError::Decryption)?;
let handle_hi = match role {
Role::Source => Some(ciphertext_hi.get_source_handle()),
@ -200,12 +211,16 @@ impl TransferData {
handle: *handle,
})
} else {
Err(ProofError::MissingCiphertext)
Err(InstructionError::MissingCiphertext)
}
}
/// Decrypts transfer amount from transfer data
pub fn decrypt_amount(&self, role: Role, sk: &ElGamalSecretKey) -> Result<u64, ProofError> {
pub fn decrypt_amount(
&self,
role: Role,
sk: &ElGamalSecretKey,
) -> Result<u64, InstructionError> {
let ciphertext_lo = self.ciphertext_lo(role)?;
let ciphertext_hi = self.ciphertext_hi(role)?;
@ -216,7 +231,7 @@ impl TransferData {
let two_power = 1 << TRANSFER_AMOUNT_LO_BITS;
Ok(amount_lo + two_power * amount_hi)
} else {
Err(ProofError::Decryption)
Err(InstructionError::Decryption)
}
}
}
@ -229,7 +244,7 @@ impl ZkProofData<TransferProofContext> for TransferData {
}
#[cfg(not(target_os = "solana"))]
fn verify_proof(&self) -> Result<(), ProofError> {
fn verify_proof(&self) -> Result<(), ProofVerificationError> {
// generate transcript and append all public inputs
let mut transcript = self.context.new_transcript();
@ -297,7 +312,7 @@ impl TransferProof {
opening_hi: &PedersenOpening,
(source_new_balance, new_source_ciphertext): (u64, &ElGamalCiphertext),
transcript: &mut Transcript,
) -> Self {
) -> Result<Self, ProofGenerationError> {
// generate a Pedersen commitment for the remaining balance in source
let (new_source_commitment, source_opening) = Pedersen::new(source_new_balance);
@ -354,14 +369,16 @@ impl TransferProof {
vec![&source_opening, opening_lo, &opening_lo_negated, opening_hi],
transcript,
)
};
}?;
Self {
Ok(Self {
new_source_commitment: pod_new_source_commitment,
equality_proof: equality_proof.into(),
validity_proof: validity_proof.into(),
range_proof: range_proof.try_into().expect("range proof: length error"),
}
range_proof: range_proof
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?,
})
}
pub fn verify(
@ -373,7 +390,7 @@ impl TransferProof {
ciphertext_hi: &TransferAmountCiphertext,
ciphertext_new_spendable: &ElGamalCiphertext,
transcript: &mut Transcript,
) -> Result<(), ProofError> {
) -> Result<(), ProofVerificationError> {
transcript.append_commitment(b"commitment-new-source", &self.new_source_commitment);
let commitment: PedersenCommitment = self.new_source_commitment.try_into()?;

View File

@ -5,7 +5,7 @@ use {
elgamal::{ElGamal, ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
pedersen::{Pedersen, PedersenCommitment},
},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
range_proof::RangeProof,
sigma_proofs::ciphertext_commitment_equality_proof::CiphertextCommitmentEqualityProof,
transcript::TranscriptProtocol,
@ -57,13 +57,13 @@ impl WithdrawData {
keypair: &ElGamalKeypair,
current_balance: u64,
current_ciphertext: &ElGamalCiphertext,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
// subtract withdraw amount from current balance
//
// errors if current_balance < amount
let final_balance = current_balance
.checked_sub(amount)
.ok_or(ProofError::Generation)?;
.ok_or(ProofGenerationError::NotEnoughFunds)?;
// encode withdraw amount as an ElGamal ciphertext and subtract it from
// current source balance
@ -78,7 +78,7 @@ impl WithdrawData {
};
let mut transcript = context.new_transcript();
let proof = WithdrawProof::new(keypair, final_balance, &final_ciphertext, &mut transcript);
let proof = WithdrawProof::new(keypair, final_balance, &final_ciphertext, &mut transcript)?;
Ok(Self { context, proof })
}
@ -92,7 +92,7 @@ impl ZkProofData<WithdrawProofContext> for WithdrawData {
}
#[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 elgamal_pubkey = self.context.pubkey.try_into()?;
@ -140,7 +140,7 @@ impl WithdrawProof {
final_balance: u64,
final_ciphertext: &ElGamalCiphertext,
transcript: &mut Transcript,
) -> Self {
) -> Result<Self, ProofGenerationError> {
// generate a Pedersen commitment for `final_balance`
let (commitment, opening) = Pedersen::new(final_balance);
let pod_commitment: pod::PedersenCommitment = commitment.into();
@ -157,13 +157,15 @@ impl WithdrawProof {
);
let range_proof =
RangeProof::new(vec![final_balance], vec![64], vec![&opening], transcript);
RangeProof::new(vec![final_balance], vec![64], vec![&opening], transcript)?;
Self {
Ok(Self {
commitment: pod_commitment,
equality_proof: equality_proof.into(),
range_proof: range_proof.try_into().expect("range proof"),
}
range_proof: range_proof
.try_into()
.map_err(|_| ProofGenerationError::ProofLength)?,
})
}
pub fn verify(
@ -171,7 +173,7 @@ impl WithdrawProof {
pubkey: &ElGamalPubkey,
final_ciphertext: &ElGamalCiphertext,
transcript: &mut Transcript,
) -> Result<(), ProofError> {
) -> Result<(), ProofVerificationError> {
transcript.append_commitment(b"commitment", &self.commitment);
let commitment: PedersenCommitment = self.commitment.try_into()?;

View File

@ -8,7 +8,7 @@
use {
crate::{
encryption::elgamal::{ElGamalCiphertext, ElGamalKeypair},
errors::ProofError,
errors::{ProofGenerationError, ProofVerificationError},
sigma_proofs::zero_balance_proof::ZeroBalanceProof,
transcript::TranscriptProtocol,
},
@ -53,7 +53,7 @@ impl ZeroBalanceProofData {
pub fn new(
keypair: &ElGamalKeypair,
ciphertext: &ElGamalCiphertext,
) -> Result<Self, ProofError> {
) -> Result<Self, ProofGenerationError> {
let pod_pubkey = pod::ElGamalPubkey(keypair.pubkey().to_bytes());
let pod_ciphertext = pod::ElGamalCiphertext(ciphertext.to_bytes());
@ -77,7 +77,7 @@ impl ZkProofData<ZeroBalanceProofContext> for ZeroBalanceProofData {
}
#[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 pubkey = self.context.pubkey.try_into()?;
let ciphertext = self.context.ciphertext.try_into()?;

View File

@ -74,13 +74,3 @@ macro_rules! define_mul_variants {
}
};
}
macro_rules! impl_from_transcript_error {
($sigma_error_type:ty) => {
impl From<TranscriptError> for $sigma_error_type {
fn from(err: TranscriptError) -> Self {
ProofVerificationError::Transcript(err).into()
}
}
};
}

View File

@ -1,10 +1,23 @@
//! Errors related to proving and verifying range proofs.
use {
crate::errors::{ProofVerificationError, TranscriptError},
thiserror::Error,
};
use {crate::errors::TranscriptError, thiserror::Error};
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[error("range proof verification failed: {0}")]
pub struct RangeProofError(#[from] pub(crate) ProofVerificationError);
impl_from_transcript_error!(RangeProofError);
pub enum RangeProofGenerationError {}
#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum RangeProofVerificationError {
#[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,
}

View File

@ -1,7 +1,6 @@
use {
crate::{
errors::ProofVerificationError,
range_proof::{errors::RangeProofError, util},
range_proof::{errors::RangeProofVerificationError, util},
transcript::TranscriptProtocol,
},
core::iter,
@ -204,15 +203,15 @@ impl InnerProductProof {
&self,
n: usize,
transcript: &mut Transcript,
) -> Result<(Vec<Scalar>, Vec<Scalar>, Vec<Scalar>), RangeProofError> {
) -> Result<(Vec<Scalar>, Vec<Scalar>, Vec<Scalar>), RangeProofVerificationError> {
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(ProofVerificationError::InvalidBitSize.into());
return Err(RangeProofVerificationError::InvalidBitSize);
}
if n != (1 << lg_n) {
return Err(ProofVerificationError::InvalidBitSize.into());
return Err(RangeProofVerificationError::InvalidBitSize);
}
transcript.innerproduct_domain_separator(n as u64);
@ -270,7 +269,7 @@ impl InnerProductProof {
G: &[RistrettoPoint],
H: &[RistrettoPoint],
transcript: &mut Transcript,
) -> Result<(), RangeProofError>
) -> Result<(), RangeProofVerificationError>
where
IG: IntoIterator,
IG::Item: Borrow<Scalar>,
@ -301,7 +300,7 @@ impl InnerProductProof {
.iter()
.map(|p| {
p.decompress()
.ok_or(ProofVerificationError::Deserialization)
.ok_or(RangeProofVerificationError::Deserialization)
})
.collect::<Result<Vec<_>, _>>()?;
@ -310,7 +309,7 @@ impl InnerProductProof {
.iter()
.map(|p| {
p.decompress()
.ok_or(ProofVerificationError::Deserialization)
.ok_or(RangeProofVerificationError::Deserialization)
})
.collect::<Result<Vec<_>, _>>()?;
@ -330,7 +329,7 @@ impl InnerProductProof {
if expect_P == *P {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(RangeProofVerificationError::AlgebraicRelation)
}
}
@ -364,21 +363,21 @@ impl InnerProductProof {
/// * \\(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, RangeProofError> {
pub fn from_bytes(slice: &[u8]) -> Result<InnerProductProof, RangeProofVerificationError> {
let b = slice.len();
if b % 32 != 0 {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let num_elements = b / 32;
if num_elements < 2 {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
if (num_elements - 2) % 2 != 0 {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let lg_n = (num_elements - 2) / 2;
if lg_n >= 32 {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let mut L_vec: Vec<CompressedRistretto> = Vec::with_capacity(lg_n);
@ -391,9 +390,9 @@ impl InnerProductProof {
let pos = 2 * lg_n * 32;
let a = Scalar::from_canonical_bytes(util::read32(&slice[pos..]))
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(RangeProofVerificationError::Deserialization)?;
let b = Scalar::from_canonical_bytes(util::read32(&slice[pos + 32..]))
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(RangeProofVerificationError::Deserialization)?;
Ok(InnerProductProof { L_vec, R_vec, a, b })
}

View File

@ -20,9 +20,10 @@ use {
use {
crate::{
encryption::pedersen::{G, H},
errors::ProofVerificationError,
range_proof::{
errors::RangeProofError, generators::BulletproofGens, inner_product::InnerProductProof,
errors::{RangeProofGenerationError, RangeProofVerificationError},
generators::BulletproofGens,
inner_product::InnerProductProof,
},
transcript::TranscriptProtocol,
},
@ -71,7 +72,7 @@ impl RangeProof {
bit_lengths: Vec<usize>,
openings: Vec<&PedersenOpening>,
transcript: &mut Transcript,
) -> Self {
) -> Result<Self, RangeProofGenerationError> {
// amounts, bit-lengths, openings must be same length vectors
let m = amounts.len();
assert_eq!(bit_lengths.len(), m);
@ -216,7 +217,7 @@ impl RangeProof {
transcript,
);
RangeProof {
Ok(RangeProof {
A,
S,
T_1,
@ -225,7 +226,7 @@ impl RangeProof {
t_x_blinding,
e_blinding,
ipp_proof,
}
})
}
#[allow(clippy::many_single_char_names)]
@ -234,7 +235,7 @@ impl RangeProof {
comms: Vec<&PedersenCommitment>,
bit_lengths: Vec<usize>,
transcript: &mut Transcript,
) -> Result<(), RangeProofError> {
) -> Result<(), RangeProofVerificationError> {
// commitments and bit-lengths must be same length vectors
assert_eq!(comms.len(), bit_lengths.len());
@ -243,7 +244,7 @@ impl RangeProof {
let bp_gens = BulletproofGens::new(nm);
if !nm.is_power_of_two() {
return Err(ProofVerificationError::InvalidBitSize.into());
return Err(RangeProofVerificationError::InvalidBitSize);
}
// append proof data to transcript and derive appropriate challenge scalars
@ -320,12 +321,12 @@ impl RangeProof {
.chain(bp_gens.H(nm).map(|&x| Some(x)))
.chain(comms.iter().map(|V| Some(*V.get_point()))),
)
.ok_or(ProofVerificationError::MultiscalarMul)?;
.ok_or(RangeProofVerificationError::MultiscalarMul)?;
if mega_check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(RangeProofVerificationError::AlgebraicRelation)
}
}
@ -346,12 +347,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, RangeProofError> {
pub fn from_bytes(slice: &[u8]) -> Result<RangeProof, RangeProofVerificationError> {
if slice.len() % 32 != 0 {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
if slice.len() < 7 * 32 {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let A = CompressedRistretto(util::read32(&slice[0..]));
@ -360,11 +361,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(ProofVerificationError::Deserialization)?;
.ok_or(RangeProofVerificationError::Deserialization)?;
let t_x_blinding = Scalar::from_canonical_bytes(util::read32(&slice[5 * 32..]))
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(RangeProofVerificationError::Deserialization)?;
let e_blinding = Scalar::from_canonical_bytes(util::read32(&slice[6 * 32..]))
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(RangeProofVerificationError::Deserialization)?;
let ipp_proof = InnerProductProof::from_bytes(&slice[7 * 32..])?;
@ -410,7 +411,8 @@ mod tests {
let mut transcript_create = Transcript::new(b"Test");
let mut transcript_verify = Transcript::new(b"Test");
let proof = RangeProof::new(vec![55], vec![32], vec![&open], &mut transcript_create);
let proof =
RangeProof::new(vec![55], vec![32], vec![&open], &mut transcript_create).unwrap();
assert!(proof
.verify(vec![&comm], vec![32], &mut transcript_verify)
@ -431,7 +433,8 @@ mod tests {
vec![64, 32, 32],
vec![&open_1, &open_2, &open_3],
&mut transcript_create,
);
)
.unwrap();
assert!(proof
.verify(

View File

@ -16,7 +16,7 @@ use crate::encryption::{
use {
crate::{
sigma_proofs::{
errors::ValidityProofError,
errors::ValidityProofVerificationError,
grouped_ciphertext_validity_proof::GroupedCiphertext2HandlesValidityProof,
},
transcript::TranscriptProtocol,
@ -80,7 +80,7 @@ impl BatchedGroupedCiphertext2HandlesValidityProof {
(destination_handle_lo, destination_handle_hi): (&DecryptHandle, &DecryptHandle),
(auditor_handle_lo, auditor_handle_hi): (&DecryptHandle, &DecryptHandle),
transcript: &mut Transcript,
) -> Result<(), ValidityProofError> {
) -> Result<(), ValidityProofVerificationError> {
transcript.batched_grouped_ciphertext_validity_proof_domain_separator();
let t = transcript.challenge_scalar(b"t");
@ -103,7 +103,7 @@ impl BatchedGroupedCiphertext2HandlesValidityProof {
self.0.to_bytes()
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofVerificationError> {
GroupedCiphertext2HandlesValidityProof::from_bytes(bytes).map(Self)
}
}

View File

@ -10,7 +10,6 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
pedersen::{PedersenOpening, G, H},
},
errors::ProofVerificationError,
sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
UNIT_LEN,
},
@ -19,7 +18,10 @@ use {
zeroize::Zeroize,
};
use {
crate::{sigma_proofs::errors::EqualityProofError, transcript::TranscriptProtocol},
crate::{
sigma_proofs::errors::{EqualityProofVerificationError, SigmaProofVerificationError},
transcript::TranscriptProtocol,
},
curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
@ -138,7 +140,7 @@ impl CiphertextCiphertextEqualityProof {
source_ciphertext: &ElGamalCiphertext,
destination_ciphertext: &ElGamalCiphertext,
transcript: &mut Transcript,
) -> Result<(), EqualityProofError> {
) -> Result<(), EqualityProofVerificationError> {
transcript.equality_proof_domain_separator();
// extract the relevant scalar and Ristretto points from the inputs
@ -169,19 +171,19 @@ impl CiphertextCiphertextEqualityProof {
let Y_0 = self
.Y_0
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_1 = self
.Y_1
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_2 = self
.Y_2
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_3 = self
.Y_3
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let check = RistrettoPoint::vartime_multiscalar_mul(
vec![
@ -221,7 +223,7 @@ impl CiphertextCiphertextEqualityProof {
if check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(SigmaProofVerificationError::AlgebraicRelation.into())
}
}
@ -240,7 +242,7 @@ impl CiphertextCiphertextEqualityProof {
buf
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, EqualityProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, EqualityProofVerificationError> {
let mut chunks = bytes.chunks(UNIT_LEN);
let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;

View File

@ -15,7 +15,6 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
pedersen::{PedersenCommitment, PedersenOpening, G, H},
},
errors::ProofVerificationError,
sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
UNIT_LEN,
},
@ -24,7 +23,10 @@ use {
zeroize::Zeroize,
};
use {
crate::{sigma_proofs::errors::EqualityProofError, transcript::TranscriptProtocol},
crate::{
sigma_proofs::errors::{EqualityProofVerificationError, SigmaProofVerificationError},
transcript::TranscriptProtocol,
},
curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
@ -136,7 +138,7 @@ impl CiphertextCommitmentEqualityProof {
source_ciphertext: &ElGamalCiphertext,
destination_commitment: &PedersenCommitment,
transcript: &mut Transcript,
) -> Result<(), EqualityProofError> {
) -> Result<(), EqualityProofVerificationError> {
transcript.equality_proof_domain_separator();
// extract the relevant scalar and Ristretto points from the inputs
@ -161,15 +163,15 @@ impl CiphertextCommitmentEqualityProof {
let Y_0 = self
.Y_0
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_1 = self
.Y_1
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_2 = self
.Y_2
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let check = RistrettoPoint::vartime_multiscalar_mul(
vec![
@ -203,7 +205,7 @@ impl CiphertextCommitmentEqualityProof {
if check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(SigmaProofVerificationError::AlgebraicRelation.into())
}
}
@ -219,7 +221,7 @@ impl CiphertextCommitmentEqualityProof {
buf
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, EqualityProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, EqualityProofVerificationError> {
let mut chunks = bytes.chunks(UNIT_LEN);
let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;
let Y_1 = ristretto_point_from_optional_slice(chunks.next())?;

View File

@ -1,30 +1,49 @@
//! Errors related to proving and verifying sigma proofs.
use {
crate::errors::{ProofVerificationError, TranscriptError},
thiserror::Error,
};
use {crate::errors::TranscriptError, thiserror::Error};
#[derive(Error, Clone, Debug, Eq, PartialEq)]
pub enum SigmaProofVerificationError {
#[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),
}
macro_rules! impl_from_transcript_error {
($sigma_error_type:ty) => {
impl From<TranscriptError> for $sigma_error_type {
fn from(err: TranscriptError) -> Self {
SigmaProofVerificationError::Transcript(err).into()
}
}
};
}
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[error("equality proof verification failed: {0}")]
pub struct EqualityProofError(#[from] pub(crate) ProofVerificationError);
impl_from_transcript_error!(EqualityProofError);
pub struct EqualityProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
impl_from_transcript_error!(EqualityProofVerificationError);
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[error("validity proof verification failed: {0}")]
pub struct ValidityProofError(#[from] pub(crate) ProofVerificationError);
impl_from_transcript_error!(ValidityProofError);
pub struct ValidityProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
impl_from_transcript_error!(ValidityProofVerificationError);
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[error("zero-balance proof verification failed: {0}")]
pub struct ZeroBalanceProofError(#[from] pub(crate) ProofVerificationError);
impl_from_transcript_error!(ZeroBalanceProofError);
pub struct ZeroBalanceProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
impl_from_transcript_error!(ZeroBalanceProofVerificationError);
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[error("fee sigma proof verification failed: {0}")]
pub struct FeeSigmaProofError(#[from] pub(crate) ProofVerificationError);
impl_from_transcript_error!(FeeSigmaProofError);
pub struct FeeSigmaProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
impl_from_transcript_error!(FeeSigmaProofVerificationError);
#[derive(Error, Clone, Debug, Eq, PartialEq)]
#[error("public key validity proof verification failed: {0}")]
pub struct PubkeyValidityProofError(#[from] pub(crate) ProofVerificationError);
impl_from_transcript_error!(PubkeyValidityProofError);
pub struct PubkeyValidityProofVerificationError(#[from] pub(crate) SigmaProofVerificationError);
impl_from_transcript_error!(PubkeyValidityProofVerificationError);

View File

@ -21,7 +21,7 @@ use {
};
use {
crate::{
errors::ProofVerificationError, sigma_proofs::errors::FeeSigmaProofError,
sigma_proofs::errors::{FeeSigmaProofVerificationError, SigmaProofVerificationError},
transcript::TranscriptProtocol,
},
curve25519_dalek::{
@ -313,7 +313,7 @@ impl FeeSigmaProof {
claimed_commitment: &PedersenCommitment,
max_fee: u64,
transcript: &mut Transcript,
) -> Result<(), FeeSigmaProofError> {
) -> Result<(), FeeSigmaProofVerificationError> {
// extract the relevant scalar and Ristretto points from the input
let m = Scalar::from(max_fee);
@ -329,19 +329,19 @@ impl FeeSigmaProof {
.fee_max_proof
.Y_max_proof
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let z_max = self.fee_max_proof.z_max_proof;
let Y_delta_real = self
.fee_equality_proof
.Y_delta
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_claimed = self
.fee_equality_proof
.Y_claimed
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let z_x = self.fee_equality_proof.z_x;
let z_delta_real = self.fee_equality_proof.z_delta;
let z_claimed = self.fee_equality_proof.z_claimed;
@ -387,7 +387,7 @@ impl FeeSigmaProof {
if check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(SigmaProofVerificationError::AlgebraicRelation.into())
}
}
@ -429,7 +429,7 @@ impl FeeSigmaProof {
buf
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FeeSigmaProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, FeeSigmaProofVerificationError> {
let mut chunks = bytes.chunks(UNIT_LEN);
let Y_max_proof = ristretto_point_from_optional_slice(chunks.next())?;
let z_max_proof = canonical_scalar_from_optional_slice(chunks.next())?;

View File

@ -15,7 +15,6 @@ use {
elgamal::{DecryptHandle, ElGamalPubkey},
pedersen::{PedersenCommitment, PedersenOpening, G, H},
},
errors::ProofVerificationError,
sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
UNIT_LEN,
},
@ -24,7 +23,10 @@ use {
zeroize::Zeroize,
};
use {
crate::{sigma_proofs::errors::ValidityProofError, transcript::TranscriptProtocol},
crate::{
sigma_proofs::errors::{SigmaProofVerificationError, ValidityProofVerificationError},
transcript::TranscriptProtocol,
},
curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
@ -128,7 +130,7 @@ impl GroupedCiphertext2HandlesValidityProof {
(destination_pubkey, auditor_pubkey): (&ElGamalPubkey, &ElGamalPubkey),
(destination_handle, auditor_handle): (&DecryptHandle, &DecryptHandle),
transcript: &mut Transcript,
) -> Result<(), ValidityProofError> {
) -> Result<(), ValidityProofVerificationError> {
transcript.grouped_ciphertext_validity_proof_domain_separator();
// include Y_0, Y_1, Y_2 to transcript and extract challenges
@ -148,15 +150,15 @@ impl GroupedCiphertext2HandlesValidityProof {
let Y_0 = self
.Y_0
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_1 = self
.Y_1
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_2 = self
.Y_2
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let P_dest = destination_pubkey.get_point();
let P_auditor = auditor_pubkey.get_point();
@ -195,7 +197,7 @@ impl GroupedCiphertext2HandlesValidityProof {
if check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(SigmaProofVerificationError::AlgebraicRelation.into())
}
}
@ -210,7 +212,7 @@ impl GroupedCiphertext2HandlesValidityProof {
buf
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ValidityProofVerificationError> {
let mut chunks = bytes.chunks(UNIT_LEN);
let Y_0 = ristretto_point_from_optional_slice(chunks.next())?;
let Y_1 = ristretto_point_from_optional_slice(chunks.next())?;

View File

@ -16,7 +16,7 @@ pub mod zero_balance_proof;
#[cfg(not(target_os = "solana"))]
use {
crate::{errors::ProofVerificationError, RISTRETTO_POINT_LEN, SCALAR_LEN},
crate::{sigma_proofs::errors::SigmaProofVerificationError, RISTRETTO_POINT_LEN, SCALAR_LEN},
curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar},
};
@ -27,11 +27,11 @@ use {
#[cfg(not(target_os = "solana"))]
fn ristretto_point_from_optional_slice(
optional_slice: Option<&[u8]>,
) -> Result<CompressedRistretto, ProofVerificationError> {
) -> Result<CompressedRistretto, SigmaProofVerificationError> {
optional_slice
.and_then(|slice| (slice.len() == RISTRETTO_POINT_LEN).then_some(slice))
.map(CompressedRistretto::from_slice)
.ok_or(ProofVerificationError::Deserialization)
.ok_or(SigmaProofVerificationError::Deserialization)
}
/// Deserializes an optional slice of bytes to a scalar.
@ -41,10 +41,10 @@ fn ristretto_point_from_optional_slice(
#[cfg(not(target_os = "solana"))]
fn canonical_scalar_from_optional_slice(
optional_slice: Option<&[u8]>,
) -> Result<Scalar, ProofVerificationError> {
) -> Result<Scalar, SigmaProofVerificationError> {
optional_slice
.and_then(|slice| (slice.len() == SCALAR_LEN).then_some(slice)) // if chunk is the wrong length, convert to None
.and_then(|slice| slice.try_into().ok()) // convert to array
.and_then(Scalar::from_canonical_bytes)
.ok_or(ProofVerificationError::Deserialization)
.ok_or(SigmaProofVerificationError::Deserialization)
}

View File

@ -18,7 +18,7 @@ use {
};
use {
crate::{
errors::ProofVerificationError, sigma_proofs::errors::PubkeyValidityProofError,
sigma_proofs::errors::{PubkeyValidityProofVerificationError, SigmaProofVerificationError},
transcript::TranscriptProtocol,
},
curve25519_dalek::{
@ -92,7 +92,7 @@ impl PubkeyValidityProof {
self,
elgamal_pubkey: &ElGamalPubkey,
transcript: &mut Transcript,
) -> Result<(), PubkeyValidityProofError> {
) -> Result<(), PubkeyValidityProofVerificationError> {
transcript.pubkey_proof_domain_separator();
// extract the relvant scalar and Ristretto points from the input
@ -106,7 +106,7 @@ impl PubkeyValidityProof {
let Y = self
.Y
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let check = RistrettoPoint::vartime_multiscalar_mul(
vec![&self.z, &(-&c), &(-&Scalar::one())],
@ -116,7 +116,7 @@ impl PubkeyValidityProof {
if check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(SigmaProofVerificationError::AlgebraicRelation.into())
}
}
@ -128,7 +128,7 @@ impl PubkeyValidityProof {
buf
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, PubkeyValidityProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, PubkeyValidityProofVerificationError> {
let mut chunks = bytes.chunks(UNIT_LEN);
let Y = ristretto_point_from_optional_slice(chunks.next())?;
let z = canonical_scalar_from_optional_slice(chunks.next())?;

View File

@ -10,7 +10,6 @@ use {
elgamal::{ElGamalCiphertext, ElGamalKeypair, ElGamalPubkey},
pedersen::H,
},
errors::ProofVerificationError,
sigma_proofs::{canonical_scalar_from_optional_slice, ristretto_point_from_optional_slice},
UNIT_LEN,
},
@ -19,7 +18,10 @@ use {
zeroize::Zeroize,
};
use {
crate::{sigma_proofs::errors::ZeroBalanceProofError, transcript::TranscriptProtocol},
crate::{
sigma_proofs::errors::{SigmaProofVerificationError, ZeroBalanceProofVerificationError},
transcript::TranscriptProtocol,
},
curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
scalar::Scalar,
@ -102,7 +104,7 @@ impl ZeroBalanceProof {
elgamal_pubkey: &ElGamalPubkey,
ciphertext: &ElGamalCiphertext,
transcript: &mut Transcript,
) -> Result<(), ZeroBalanceProofError> {
) -> Result<(), ZeroBalanceProofVerificationError> {
transcript.zero_balance_proof_domain_separator();
// extract the relevant scalar and Ristretto points from the input
@ -123,11 +125,11 @@ impl ZeroBalanceProof {
let Y_P = self
.Y_P
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
let Y_D = self
.Y_D
.decompress()
.ok_or(ProofVerificationError::Deserialization)?;
.ok_or(SigmaProofVerificationError::Deserialization)?;
// check the required algebraic relation
let check = RistrettoPoint::multiscalar_mul(
@ -152,7 +154,7 @@ impl ZeroBalanceProof {
if check.is_identity() {
Ok(())
} else {
Err(ProofVerificationError::AlgebraicRelation.into())
Err(SigmaProofVerificationError::AlgebraicRelation.into())
}
}
@ -165,7 +167,7 @@ impl ZeroBalanceProof {
buf
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ZeroBalanceProofError> {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ZeroBalanceProofVerificationError> {
let mut chunks = bytes.chunks(UNIT_LEN);
let Y_P = ristretto_point_from_optional_slice(chunks.next())?;
let Y_D = ristretto_point_from_optional_slice(chunks.next())?;

View File

@ -49,7 +49,7 @@ impl From<PodRistrettoPoint> for pod::DecryptHandle {
mod target_arch {
use {
super::pod,
crate::{curve25519::scalar::PodScalar, errors::ProofError},
crate::{curve25519::scalar::PodScalar, encryption::elgamal::ElGamalError},
curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar},
std::convert::TryFrom,
};
@ -61,10 +61,10 @@ mod target_arch {
}
impl TryFrom<PodScalar> for Scalar {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod: PodScalar) -> Result<Self, Self::Error> {
Scalar::from_canonical_bytes(pod.0).ok_or(ProofError::CiphertextDeserialization)
Scalar::from_canonical_bytes(pod.0).ok_or(ElGamalError::CiphertextDeserialization)
}
}
@ -101,7 +101,8 @@ mod tests {
let mut transcript_create = Transcript::new(b"Test");
let mut transcript_verify = Transcript::new(b"Test");
let proof = RangeProof::new(vec![55], vec![64], vec![&open], &mut transcript_create);
let proof =
RangeProof::new(vec![55], vec![64], vec![&open], &mut transcript_create).unwrap();
let proof_serialized: pod::RangeProofU64 = proof.try_into().unwrap();
let proof_deserialized: RangeProof = proof_serialized.try_into().unwrap();
@ -111,7 +112,8 @@ mod tests {
.is_ok());
// should fail to serialize to pod::RangeProof128
let proof = RangeProof::new(vec![55], vec![64], vec![&open], &mut transcript_create);
let proof =
RangeProof::new(vec![55], vec![64], vec![&open], &mut transcript_create).unwrap();
assert!(TryInto::<pod::RangeProofU128>::try_into(proof).is_err());
}
@ -130,7 +132,8 @@ mod tests {
vec![64, 32, 32],
vec![&open_1, &open_2, &open_3],
&mut transcript_create,
);
)
.unwrap();
let proof_serialized: pod::RangeProofU128 = proof.try_into().unwrap();
let proof_deserialized: RangeProof = proof_serialized.try_into().unwrap();
@ -149,7 +152,8 @@ mod tests {
vec![64, 32, 32],
vec![&open_1, &open_2, &open_3],
&mut transcript_create,
);
)
.unwrap();
assert!(TryInto::<pod::RangeProofU64>::try_into(proof).is_err());
}

View File

@ -1,7 +1,7 @@
//! Plain Old Data types for the AES128-GCM-SIV authenticated encryption scheme.
#[cfg(not(target_os = "solana"))]
use crate::{encryption::auth_encryption as decoded, errors::ProofError};
use crate::encryption::auth_encryption::{self as decoded, AuthenticatedEncryptionError};
use {
crate::zk_token_elgamal::pod::{Pod, Zeroable},
base64::{prelude::BASE64_STANDARD, Engine},
@ -49,9 +49,9 @@ impl From<decoded::AeCiphertext> for AeCiphertext {
#[cfg(not(target_os = "solana"))]
impl TryFrom<AeCiphertext> for decoded::AeCiphertext {
type Error = ProofError;
type Error = AuthenticatedEncryptionError;
fn try_from(pod_ciphertext: AeCiphertext) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_ciphertext.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_ciphertext.0).ok_or(AuthenticatedEncryptionError::Deserialization)
}
}

View File

@ -2,7 +2,7 @@
#[cfg(not(target_os = "solana"))]
use {
crate::{encryption::elgamal as decoded, errors::ProofError},
crate::encryption::elgamal::{self as decoded, ElGamalError},
curve25519_dalek::ristretto::CompressedRistretto,
};
use {
@ -55,10 +55,10 @@ impl From<decoded::ElGamalCiphertext> for ElGamalCiphertext {
#[cfg(not(target_os = "solana"))]
impl TryFrom<ElGamalCiphertext> for decoded::ElGamalCiphertext {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_ciphertext: ElGamalCiphertext) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_ciphertext.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_ciphertext.0).ok_or(ElGamalError::CiphertextDeserialization)
}
}
@ -88,10 +88,10 @@ impl From<decoded::ElGamalPubkey> for ElGamalPubkey {
#[cfg(not(target_os = "solana"))]
impl TryFrom<ElGamalPubkey> for decoded::ElGamalPubkey {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_pubkey: ElGamalPubkey) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_pubkey.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_pubkey.0).ok_or(ElGamalError::PubkeyDeserialization)
}
}
@ -123,9 +123,9 @@ impl From<DecryptHandle> for CompressedRistretto {
#[cfg(not(target_os = "solana"))]
impl TryFrom<DecryptHandle> for decoded::DecryptHandle {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_handle: DecryptHandle) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_handle.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_handle.0).ok_or(ElGamalError::CiphertextDeserialization)
}
}

View File

@ -1,7 +1,7 @@
//! Plain Old Data types for the Grouped ElGamal encryption scheme.
#[cfg(not(target_os = "solana"))]
use crate::{encryption::grouped_elgamal::GroupedElGamalCiphertext, errors::ProofError};
use crate::encryption::{elgamal::ElGamalError, grouped_elgamal::GroupedElGamalCiphertext};
use {
crate::zk_token_elgamal::pod::{
elgamal::DECRYPT_HANDLE_LEN, pedersen::PEDERSEN_COMMITMENT_LEN, Pod, Zeroable,
@ -42,10 +42,10 @@ impl From<GroupedElGamalCiphertext<2>> for GroupedElGamalCiphertext2Handles {
#[cfg(not(target_os = "solana"))]
impl TryFrom<GroupedElGamalCiphertext2Handles> for GroupedElGamalCiphertext<2> {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_ciphertext: GroupedElGamalCiphertext2Handles) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_ciphertext.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_ciphertext.0).ok_or(ElGamalError::CiphertextDeserialization)
}
}
@ -75,9 +75,9 @@ impl From<GroupedElGamalCiphertext<3>> for GroupedElGamalCiphertext3Handles {
#[cfg(not(target_os = "solana"))]
impl TryFrom<GroupedElGamalCiphertext3Handles> for GroupedElGamalCiphertext<3> {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_ciphertext: GroupedElGamalCiphertext3Handles) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_ciphertext.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_ciphertext.0).ok_or(ElGamalError::CiphertextDeserialization)
}
}

View File

@ -3,7 +3,7 @@ use crate::zk_token_elgamal::pod::{
Zeroable,
};
#[cfg(not(target_os = "solana"))]
use crate::{errors::ProofError, instruction::transfer as decoded};
use crate::{encryption::elgamal::ElGamalError, instruction::transfer as decoded};
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C)]
@ -18,7 +18,7 @@ impl From<decoded::TransferAmountCiphertext> for TransferAmountCiphertext {
#[cfg(not(target_os = "solana"))]
impl TryFrom<TransferAmountCiphertext> for decoded::TransferAmountCiphertext {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_ciphertext: TransferAmountCiphertext) -> Result<Self, Self::Error> {
Ok(Self(pod_ciphertext.0.try_into()?))
@ -38,7 +38,7 @@ impl From<decoded::FeeEncryption> for FeeEncryption {
#[cfg(not(target_os = "solana"))]
impl TryFrom<FeeEncryption> for decoded::FeeEncryption {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_ciphertext: FeeEncryption) -> Result<Self, Self::Error> {
Ok(Self(pod_ciphertext.0.try_into()?))

View File

@ -2,7 +2,7 @@
#[cfg(not(target_os = "solana"))]
use {
crate::{encryption::pedersen as decoded, errors::ProofError},
crate::encryption::{elgamal::ElGamalError, pedersen as decoded},
curve25519_dalek::ristretto::CompressedRistretto,
};
use {
@ -44,9 +44,9 @@ impl From<PedersenCommitment> for CompressedRistretto {
#[cfg(not(target_os = "solana"))]
impl TryFrom<PedersenCommitment> for decoded::PedersenCommitment {
type Error = ProofError;
type Error = ElGamalError;
fn try_from(pod_commitment: PedersenCommitment) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_commitment.0).ok_or(ProofError::CiphertextDeserialization)
Self::from_bytes(&pod_commitment.0).ok_or(ElGamalError::CiphertextDeserialization)
}
}

View File

@ -2,8 +2,7 @@
#[cfg(not(target_os = "solana"))]
use crate::{
errors::ProofVerificationError,
range_proof::{self as decoded, errors::RangeProofError},
range_proof::{self as decoded, errors::RangeProofVerificationError},
UNIT_LEN,
};
use crate::{
@ -42,11 +41,11 @@ pub struct RangeProofU64(pub [u8; RANGE_PROOF_U64_LEN]);
#[cfg(not(target_os = "solana"))]
impl TryFrom<decoded::RangeProof> for RangeProofU64 {
type Error = RangeProofError;
type Error = RangeProofVerificationError;
fn try_from(decoded_proof: decoded::RangeProof) -> Result<Self, Self::Error> {
if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U64_LEN {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let mut buf = [0_u8; RANGE_PROOF_U64_LEN];
@ -59,7 +58,7 @@ impl TryFrom<decoded::RangeProof> for RangeProofU64 {
#[cfg(not(target_os = "solana"))]
impl TryFrom<RangeProofU64> for decoded::RangeProof {
type Error = RangeProofError;
type Error = RangeProofVerificationError;
fn try_from(pod_proof: RangeProofU64) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -73,11 +72,11 @@ pub struct RangeProofU128(pub [u8; RANGE_PROOF_U128_LEN]);
#[cfg(not(target_os = "solana"))]
impl TryFrom<decoded::RangeProof> for RangeProofU128 {
type Error = RangeProofError;
type Error = RangeProofVerificationError;
fn try_from(decoded_proof: decoded::RangeProof) -> Result<Self, Self::Error> {
if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U128_LEN {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let mut buf = [0_u8; RANGE_PROOF_U128_LEN];
@ -90,7 +89,7 @@ impl TryFrom<decoded::RangeProof> for RangeProofU128 {
#[cfg(not(target_os = "solana"))]
impl TryFrom<RangeProofU128> for decoded::RangeProof {
type Error = RangeProofError;
type Error = RangeProofVerificationError;
fn try_from(pod_proof: RangeProofU128) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -104,11 +103,11 @@ pub struct RangeProofU256(pub [u8; RANGE_PROOF_U256_LEN]);
#[cfg(not(target_os = "solana"))]
impl TryFrom<decoded::RangeProof> for RangeProofU256 {
type Error = RangeProofError;
type Error = RangeProofVerificationError;
fn try_from(decoded_proof: decoded::RangeProof) -> Result<Self, Self::Error> {
if decoded_proof.ipp_proof.serialized_size() != INNER_PRODUCT_PROOF_U256_LEN {
return Err(ProofVerificationError::Deserialization.into());
return Err(RangeProofVerificationError::Deserialization);
}
let mut buf = [0_u8; RANGE_PROOF_U256_LEN];
@ -121,7 +120,7 @@ impl TryFrom<decoded::RangeProof> for RangeProofU256 {
#[cfg(not(target_os = "solana"))]
impl TryFrom<RangeProofU256> for decoded::RangeProof {
type Error = RangeProofError;
type Error = RangeProofVerificationError;
fn try_from(pod_proof: RangeProofU256) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)

View File

@ -47,7 +47,7 @@ impl From<DecodedCiphertextCommitmentEqualityProof> for CiphertextCommitmentEqua
#[cfg(not(target_os = "solana"))]
impl TryFrom<CiphertextCommitmentEqualityProof> for DecodedCiphertextCommitmentEqualityProof {
type Error = EqualityProofError;
type Error = EqualityProofVerificationError;
fn try_from(pod_proof: CiphertextCommitmentEqualityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -68,7 +68,7 @@ impl From<DecodedCiphertextCiphertextEqualityProof> for CiphertextCiphertextEqua
#[cfg(not(target_os = "solana"))]
impl TryFrom<CiphertextCiphertextEqualityProof> for DecodedCiphertextCiphertextEqualityProof {
type Error = EqualityProofError;
type Error = EqualityProofVerificationError;
fn try_from(pod_proof: CiphertextCiphertextEqualityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -95,7 +95,7 @@ impl From<DecodedGroupedCiphertext2HandlesValidityProof>
impl TryFrom<GroupedCiphertext2HandlesValidityProof>
for DecodedGroupedCiphertext2HandlesValidityProof
{
type Error = ValidityProofError;
type Error = ValidityProofVerificationError;
fn try_from(pod_proof: GroupedCiphertext2HandlesValidityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -122,7 +122,7 @@ impl From<DecodedBatchedGroupedCiphertext2HandlesValidityProof>
impl TryFrom<BatchedGroupedCiphertext2HandlesValidityProof>
for DecodedBatchedGroupedCiphertext2HandlesValidityProof
{
type Error = ValidityProofError;
type Error = ValidityProofVerificationError;
fn try_from(
pod_proof: BatchedGroupedCiphertext2HandlesValidityProof,
@ -145,7 +145,7 @@ impl From<DecodedZeroBalanceProof> for ZeroBalanceProof {
#[cfg(not(target_os = "solana"))]
impl TryFrom<ZeroBalanceProof> for DecodedZeroBalanceProof {
type Error = ZeroBalanceProofError;
type Error = ZeroBalanceProofVerificationError;
fn try_from(pod_proof: ZeroBalanceProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -166,7 +166,7 @@ impl From<DecodedFeeSigmaProof> for FeeSigmaProof {
#[cfg(not(target_os = "solana"))]
impl TryFrom<FeeSigmaProof> for DecodedFeeSigmaProof {
type Error = FeeSigmaProofError;
type Error = FeeSigmaProofVerificationError;
fn try_from(pod_proof: FeeSigmaProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)
@ -187,7 +187,7 @@ impl From<DecodedPubkeyValidityProof> for PubkeyValidityProof {
#[cfg(not(target_os = "solana"))]
impl TryFrom<PubkeyValidityProof> for DecodedPubkeyValidityProof {
type Error = PubkeyValidityProofError;
type Error = PubkeyValidityProofVerificationError;
fn try_from(pod_proof: PubkeyValidityProof) -> Result<Self, Self::Error> {
Self::from_bytes(&pod_proof.0)