[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:
parent
2c71d21fad
commit
0fd4762399
|
@ -52,6 +52,8 @@ pub enum AuthenticatedEncryptionError {
|
|||
SeedLengthTooShort,
|
||||
#[error("seed length too long for derivation")]
|
||||
SeedLengthTooLong,
|
||||
#[error("failed to deserialize")]
|
||||
Deserialization,
|
||||
}
|
||||
|
||||
struct AuthenticatedEncryption;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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())?;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()?))
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue