Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,47 @@ and this project adheres to Rust's notion of

### Added
- `orchard::pczt::Action::apply_signature`
- `orchard::value::BalanceError`
- `impl std::error::Error` for the following errors:
- `orchard::pczt`:
- `IoFinalizerError`
- `ParseError`
- `ProverError`
- `SignerError`
- `TxExtractorError`
- `UpdaterError`
- `VerifyError`
- `orchard::zip32::Error`

### Changed
- `orchard::builder::BuildError::ValueSum` variant now contains
`orchard::value::BalanceError`.
- `orchard::pczt::SignerError` has added variants:
- `InvalidExternalSignature`
- All error enums in this crate are now `#[non_exhaustive]`, to allow future
error variants to be added without a SemVer break:
Comment thread
str4d marked this conversation as resolved.
- `orchard::builder`:
- `BuildError`
- `SpendError`
- `orchard::pczt`:
- `IoFinalizerError`
- `ParseError`
- `ProverError`
- `SignerError`
- `TxExtractorError`
- `UpdaterError`
- `VerifyError`
- `orchard::zip32::Error`
- `orchard::builder::OutputError` has been changed from a zero-sized struct to
a `#[non_exhaustive]` enum with (for now) a single variant.

### Removed
- `orchard::value::OverflowError` (use `BalanceError` instead).

## [0.10.2] - 2025-05-08

### Fixed
- Fixes problems in test compilation under `--no-default-features`

## [0.11.0] - 2025-02-20

Expand Down
25 changes: 8 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 3 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ nonempty = { version = "0.11", default-features = false }
poseidon = { package = "halo2_poseidon", version = "0.1" }
serde = { version = "1.0", default-features = false, features = ["derive"] }
sinsemilla = "0.1"
subtle = { version = "2.3", default-features = false }
subtle = { version = "2.6", default-features = false }
zcash_note_encryption = "0.4"
incrementalmerkletree = "0.8.1"
zcash_spec = "0.2.1"
zip32 = { version = "0.2.0", default-features = false }
visibility = "0.1.1"

# Circuit
halo2_gadgets = { version = "0.3", optional = true, default-features = false }
halo2_gadgets = { version = "0.4", optional = true, default-features = false }
halo2_proofs = { version = "0.3", optional = true, default-features = false, features = ["batch", "floor-planner-v1-legacy-pdqsort"] }

# Boilerplate
Expand All @@ -67,7 +67,7 @@ plotters = { version = "0.3.0", optional = true }

[dev-dependencies]
criterion = "0.4" # 0.5 depends on clap 4 which has MSRV 1.70
halo2_gadgets = { version = "0.3", features = ["test-dependencies"] }
halo2_gadgets = { version = "0.4", features = ["test-dependencies"] }
hex = "0.4"
proptest = ">=1.0.0, <1.7.0"
zcash_note_encryption = { version = "0.4", features = ["pre-zip-212"] }
Expand Down Expand Up @@ -107,7 +107,3 @@ debug = true

[profile.bench]
debug = true

[patch.crates-io]
halo2_gadgets = { git = "https://github.com/zcash/halo2", rev = "2308caf68c48c02468b66cfc452dad54e355e32f" }
halo2_proofs = { git = "https://github.com/zcash/halo2", rev = "2308caf68c48c02468b66cfc452dad54e355e32f" }
38 changes: 24 additions & 14 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
note_encryption::OrchardNoteEncryption,
primitives::redpallas::{self, Binding, SpendAuth},
tree::{Anchor, MerklePath},
value::{self, NoteValue, OverflowError, ValueCommitTrapdoor, ValueCommitment, ValueSum},
value::{self, BalanceError, NoteValue, ValueCommitTrapdoor, ValueCommitment, ValueSum},
Proof,
};

Expand Down Expand Up @@ -117,6 +117,7 @@ impl BundleType {

/// An error type for the kinds of errors that can occur during bundle construction.
#[derive(Debug)]
#[non_exhaustive]
pub enum BuildError {
/// Spends are disabled for the provided bundle type.
SpendsDisabled,
Expand All @@ -131,7 +132,7 @@ pub enum BuildError {
Proof(halo2_proofs::plonk::Error),
/// An overflow error occurred while attempting to construct the value
/// for a bundle.
ValueSum(value::OverflowError),
ValueSum(value::BalanceError),
/// External signature is not valid.
InvalidExternalSignature,
/// A signature is valid for more than one input. This should never happen if `alpha`
Expand Down Expand Up @@ -173,14 +174,15 @@ impl From<halo2_proofs::plonk::Error> for BuildError {
}
}

impl From<value::OverflowError> for BuildError {
fn from(e: value::OverflowError) -> Self {
impl From<value::BalanceError> for BuildError {
fn from(e: value::BalanceError) -> Self {
BuildError::ValueSum(e)
}
}

/// An error type for adding a spend to the builder.
#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum SpendError {
/// Spends aren't enabled for this builder.
SpendsDisabled,
Expand All @@ -204,13 +206,20 @@ impl fmt::Display for SpendError {
#[cfg(feature = "std")]
impl std::error::Error for SpendError {}

/// The only error that can occur here is if outputs are disabled for this builder.
/// An error type for adding an output to the builder.
#[derive(Debug, PartialEq, Eq)]
pub struct OutputError;
#[non_exhaustive]
pub enum OutputError {
/// Outputs aren't enabled for this builder.
OutputsDisabled,
}

impl fmt::Display for OutputError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Outputs are not enabled for this builder")
use OutputError::*;
f.write_str(match self {
OutputsDisabled => "Outputs are not enabled for this builder",
})
}
}

Expand Down Expand Up @@ -594,7 +603,7 @@ impl Builder {
) -> Result<(), OutputError> {
let flags = self.bundle_type.flags();
if !flags.outputs_enabled() {
return Err(OutputError);
return Err(OutputError::OutputsDisabled);
}

self.outputs
Expand Down Expand Up @@ -625,7 +634,7 @@ impl Builder {
///
/// [added]: https://zips.z.cash/protocol/protocol.pdf#orchardbalance
/// [must not have a negative value]: https://zips.z.cash/protocol/protocol.pdf#transactions
pub fn value_balance<V: TryFrom<i64>>(&self) -> Result<V, value::OverflowError> {
pub fn value_balance<V: TryFrom<i64>>(&self) -> Result<V, value::BalanceError> {
let value_balance = self
.spends
.iter()
Expand All @@ -636,8 +645,9 @@ impl Builder {
.map(|output| NoteValue::zero() - output.value),
)
.try_fold(ValueSum::zero(), |acc, note_value| acc + note_value)
.ok_or(OverflowError)?;
i64::try_from(value_balance).and_then(|i| V::try_from(i).map_err(|_| value::OverflowError))
.ok_or(BalanceError::Overflow)?;
i64::try_from(value_balance)
.and_then(|i| V::try_from(i).map_err(|_| value::BalanceError::Overflow))
}

/// Builds a bundle containing the given spent notes and outputs.
Expand Down Expand Up @@ -715,7 +725,7 @@ pub fn bundle<V: TryFrom<i64>>(
let result_value_balance: V = i64::try_from(value_balance)
.map_err(BuildError::ValueSum)
.and_then(|i| {
V::try_from(i).map_err(|_| BuildError::ValueSum(value::OverflowError))
V::try_from(i).map_err(|_| BuildError::ValueSum(value::BalanceError::Overflow))
})?;

// Compute the transaction binding signing key.
Expand Down Expand Up @@ -833,7 +843,7 @@ fn build_bundle<B, R: RngCore>(
let value_balance = pre_actions
.iter()
.try_fold(ValueSum::zero(), |acc, action| acc + action.value_sum())
.ok_or(OverflowError)?;
.ok_or(BalanceError::Overflow)?;

finisher(pre_actions, flags, value_balance, bundle_meta, rng)
}
Expand Down Expand Up @@ -1271,7 +1281,7 @@ pub mod testing {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "circuit"))]
mod tests {
use rand::rngs::OsRng;

Expand Down
2 changes: 1 addition & 1 deletion src/constants/sinsemilla.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ impl CommitDomains<pallas::Affine, OrchardFixedBases, OrchardHashDomains> for Or
}
}

#[cfg(test)]
#[cfg(all(test, feature = "circuit"))]
mod tests {
use super::*;
use crate::constants::{
Expand Down
2 changes: 1 addition & 1 deletion src/pczt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl Zip32Derivation {
}
}

#[cfg(test)]
#[cfg(all(test, feature = "circuit"))]
mod tests {
use ff::{Field, PrimeField};
use incrementalmerkletree::{Marking, Retention};
Expand Down
24 changes: 24 additions & 0 deletions src/pczt/io_finalizer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::fmt;

use alloc::vec::Vec;

use rand::{CryptoRng, RngCore};
Expand Down Expand Up @@ -60,6 +62,7 @@ impl super::Bundle {

/// Errors that can occur while finalizing the I/O for a PCZT bundle.
#[derive(Debug)]
#[non_exhaustive]
pub enum IoFinalizerError {
/// An error occurred while signing a dummy spend.
DummySignature(SignerError),
Expand All @@ -69,3 +72,24 @@ pub enum IoFinalizerError {
/// inconsistent.
ValueCommitMismatch,
}

impl fmt::Display for IoFinalizerError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IoFinalizerError::DummySignature(e) => {
write!(f, "An error occurred while signing a dummy spend: {e}")
}
IoFinalizerError::MissingValueCommitTrapdoor => write!(
f,
"The IO Finalizer role requires all `rcv` fields to be set"
),
IoFinalizerError::ValueCommitMismatch => write!(
f,
"`cv_net`, `rcv`, and `value_sum` within the Orchard bundle are inconsistent."
),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for IoFinalizerError {}
34 changes: 34 additions & 0 deletions src/pczt/parse.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::fmt;

use alloc::collections::BTreeMap;
use alloc::string::String;
use alloc::vec::Vec;
Expand Down Expand Up @@ -294,6 +296,7 @@ impl Zip32Derivation {

/// Errors that can occur while parsing a PCZT bundle.
#[derive(Debug)]
#[non_exhaustive]
pub enum ParseError {
/// An invalid anchor was provided.
InvalidAnchor,
Expand Down Expand Up @@ -334,3 +337,34 @@ pub enum ParseError {
/// The provided `flags` field had unexpected bits set.
UnexpectedFlagBitsSet,
}

impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ParseError::InvalidAnchor => write!(f, "invalid anchor"),
ParseError::InvalidBindingSignatureSigningKey => write!(f, "invalid `bsk`"),
ParseError::InvalidDummySpendingKey => write!(f, "invalid `dummy_sk`"),
ParseError::InvalidEncCiphertext => write!(f, "invalid `enc_ciphertext`"),
ParseError::InvalidExtractedNoteCommitment => write!(f, "invalid `cmx`"),
ParseError::InvalidFullViewingKey => write!(f, "invalid `fvk`"),
ParseError::InvalidNullifier => write!(f, "invalid `nullifier`"),
ParseError::InvalidOutCiphertext => write!(f, "invalid `out_ciphertext`"),
ParseError::InvalidRandomizedKey => write!(f, "invalid `rk`"),
ParseError::InvalidRandomSeed => write!(f, "invalid `rseed`"),
ParseError::InvalidRecipient => write!(f, "invalid `recipient`"),
ParseError::InvalidRho => write!(f, "invalid `rho`"),
ParseError::InvalidSpendAuthRandomizer => write!(f, "invalid `alpha`"),
ParseError::InvalidValueCommitment => write!(f, "invalid `cv_net`"),
ParseError::InvalidValueCommitTrapdoor => write!(f, "invalid `rcv`"),
ParseError::InvalidWitness => write!(f, "invalid `witness`"),
ParseError::InvalidZip32Derivation => write!(f, "invalid `zip32_derivation`"),
ParseError::MissingRho => {
write!(f, "`rho` must be provided whenever `rseed` is provided")
}
ParseError::UnexpectedFlagBitsSet => write!(f, "`flags` field had unexpected bits set"),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for ParseError {}
Loading
Loading