diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 47466f3e1..e3da9b415 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run tests - run: cargo test --verbose + run: cargo test --workspace --verbose - name: Verify working directory is clean run: git diff --exit-code @@ -32,7 +32,7 @@ jobs: - name: Remove lockfile to build with latest dependencies run: rm Cargo.lock - name: Build crate - run: cargo build --all-features --verbose + run: cargo build --workspace --all-features --verbose - name: Verify working directory is clean (excluding lockfile) run: git diff --exit-code ':!Cargo.lock' @@ -67,9 +67,9 @@ jobs: - name: Add lazy_static with the spin_no_std feature working-directory: ./ci-build run: cargo add lazy_static --no-default-features --features "spin_no_std" - - name: Add typenum with the no_std feature + - name: Add typenum with no default features working-directory: ./ci-build - run: cargo add typenum --no-default-features --features "no_std" + run: cargo add typenum --no-default-features - name: Show Cargo.toml for the synthetic crate working-directory: ./ci-build run: cat Cargo.toml @@ -89,7 +89,7 @@ jobs: - uses: actions/checkout@v4 # Build benchmarks to prevent bitrot - name: Build benchmarks - run: cargo build --benches + run: cargo build --workspace --benches book: name: Book tests @@ -113,7 +113,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Generate coverage report - run: cargo tarpaulin --engine llvm --all-features --release --timeout 600 --out xml + run: cargo tarpaulin --workspace --engine llvm --all-features --release --timeout 600 --out xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v3.1.4 @@ -126,7 +126,7 @@ jobs: # Requires #![deny(rustdoc::broken_intra_doc_links)] in crates. - run: sudo apt-get -y install libfontconfig1-dev - name: Check intra-doc links - run: cargo doc --all-features --document-private-items + run: cargo doc --workspace --all-features --document-private-items fmt: name: Rustfmt diff --git a/.github/workflows/lints-stable.yml b/.github/workflows/lints-stable.yml index 05bd37e8e..3877879d6 100644 --- a/.github/workflows/lints-stable.yml +++ b/.github/workflows/lints-stable.yml @@ -47,9 +47,9 @@ jobs: - name: Add lazy_static with the spin_no_std feature working-directory: ./ci-build run: cargo add lazy_static --no-default-features --features "spin_no_std" - - name: Add typenum with the no_std feature + - name: Add typenum with no default features working-directory: ./ci-build - run: cargo add typenum --no-default-features --features "no_std" + run: cargo add typenum --no-default-features - name: Show Cargo.toml for the synthetic crate working-directory: ./ci-build run: cat Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index 9821bb151..5dc68d402 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1436,6 +1436,17 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "orchard" version = "0.12.0" +dependencies = [ + "incrementalmerkletree", + "orchard_internal", + "rand", + "shardtree", + "zcash_note_encryption", +] + +[[package]] +name = "orchard_internal" +version = "0.12.0" dependencies = [ "aes", "bitvec", diff --git a/Cargo.toml b/Cargo.toml index 4d88e702f..31ab4da09 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,20 +1,25 @@ +[workspace] +members = [".", "public"] + +[workspace.dependencies] +__impl = { version = "=0.12.0", path = ".", package = "orchard_internal", default-features = false } + [package] -name = "orchard" +name = "orchard_internal" version = "0.12.0" authors = [ - "Sean Bowe", - "Jack Grigg ", + "Sean Bowe ", + "Jack Grigg ", "Daira-Emma Hopwood ", "Ying Tong Lai", - "Kris Nuttycombe ", + "Kris Nuttycombe ", ] edition = "2021" rust-version = "1.85.1" description = "The Orchard shielded transaction protocol" license = "MIT OR Apache-2.0" repository = "https://github.com/zcash/orchard" -documentation = "https://docs.rs/orchard" -readme = "README.md" +readme = "INTERNAL-README.md" categories = ["cryptography::cryptocurrencies"] keywords = ["zcash"] diff --git a/INTERNAL-README.md b/INTERNAL-README.md new file mode 100644 index 000000000..32da28f87 --- /dev/null +++ b/INTERNAL-README.md @@ -0,0 +1,3 @@ +# orchard_internal + +This is the implementation crate for the Orchard shielded transaction protocol. It is not intended to be used directly. Depend on the [`orchard`](https://crates.io/crates/orchard) crate instead, which re-exports the public API from this crate. diff --git a/LICENSE-MIT b/LICENSE-MIT index 3a617be2b..b369e0615 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2020-2023 The Electric Coin Company +Copyright (c) 2020-2025 The Electric Coin Company +Copyright (c) 2026 Zcash Open Development Lab Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 5eb787f7c..eca52b606 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # orchard [![Crates.io](https://img.shields.io/crates/v/orchard.svg)](https://crates.io/crates/orchard) # -Requires Rust 1.66+. +Requires Rust 1.85.1+. ## Documentation @@ -10,13 +10,9 @@ Requires Rust 1.66+. ## `no_std` compatibility In order to take advantage of `no_std` builds, downstream users of this crate -must enable: - -* the `spin_no_std` feature of the `lazy_static` crate; and -* the `no_std` feature of the `typenum` crate. - -This is needed because the `--no-default-features` builds of these crates still -rely on `std`. +must enable the `spin_no_std` feature of the `lazy_static` crate. This is +needed because the `--no-default-features` build of `lazy_static` still relies +on `std`. ## License diff --git a/benches/circuit.rs b/benches/circuit.rs index 22f43eb51..79ef9e9a2 100644 --- a/benches/circuit.rs +++ b/benches/circuit.rs @@ -6,7 +6,7 @@ use criterion::{BenchmarkId, Criterion}; #[cfg(unix)] use pprof::criterion::{Output, PProfProfiler}; -use orchard::{ +use orchard_internal::{ builder::{Builder, BundleType}, circuit::{ProvingKey, VerifyingKey}, keys::{FullViewingKey, Scope, SpendingKey}, diff --git a/benches/note_decryption.rs b/benches/note_decryption.rs index 920ccbffd..519336b6a 100644 --- a/benches/note_decryption.rs +++ b/benches/note_decryption.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; -use orchard::{ +use orchard_internal::{ builder::{Builder, BundleType}, circuit::ProvingKey, keys::{FullViewingKey, PreparedIncomingViewingKey, Scope, SpendingKey}, diff --git a/benches/small.rs b/benches/small.rs index daeec5cbe..14b8d9ce1 100644 --- a/benches/small.rs +++ b/benches/small.rs @@ -1,5 +1,5 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use orchard::keys::{FullViewingKey, Scope, SpendingKey}; +use orchard_internal::keys::{FullViewingKey, Scope, SpendingKey}; fn key_derivation(c: &mut Criterion) { // Meaningless random spending key. diff --git a/public/Cargo.toml b/public/Cargo.toml new file mode 100644 index 000000000..174a42669 --- /dev/null +++ b/public/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "orchard" +version = "0.12.0" +authors = [ + "Sean Bowe ", + "Jack Grigg ", + "Daira-Emma Hopwood ", + "Ying Tong Lai", + "Kris Nuttycombe ", +] +edition = "2021" +rust-version = "1.70" +description = "The Orchard shielded transaction protocol" +license = "MIT OR Apache-2.0" +repository = "https://github.com/zcash/orchard" +documentation = "https://docs.rs/orchard" +readme = "README.md" +categories = ["cryptography::cryptocurrencies"] +keywords = ["zcash"] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] + +[dependencies] +__impl = { workspace = true } + +[features] +default = ["circuit", "multicore", "std"] +std = ["__impl/std"] +circuit = ["__impl/circuit"] +multicore = ["__impl/multicore"] +unstable-frost = ["__impl/unstable-frost"] +dev-graph = ["__impl/dev-graph"] +test-dependencies = ["__impl/test-dependencies"] + +[dev-dependencies] +incrementalmerkletree = "0.8.1" +rand = "0.8" +shardtree = "0.6" +zcash_note_encryption = "0.4" diff --git a/public/LICENSE-APACHE b/public/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/public/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/public/LICENSE-MIT b/public/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/public/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/public/README.md b/public/README.md new file mode 120000 index 000000000..32d46ee88 --- /dev/null +++ b/public/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/public/katex-header.html b/public/katex-header.html new file mode 120000 index 000000000..810e68dcb --- /dev/null +++ b/public/katex-header.html @@ -0,0 +1 @@ +../katex-header.html \ No newline at end of file diff --git a/public/src/lib.rs b/public/src/lib.rs new file mode 100644 index 000000000..081e156b4 --- /dev/null +++ b/public/src/lib.rs @@ -0,0 +1,253 @@ +//! # orchard +//! +//! ## Nomenclature +//! +//! All types in the `orchard` crate, unless otherwise specified, are Orchard-specific +//! types. For example, [`Address`] is documented as being a shielded payment address; we +//! implicitly mean it is an Orchard payment address (as opposed to e.g. a Sapling payment +//! address, which is also shielded). + +#![no_std] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] +#![forbid(unsafe_code)] + +// Root-level re-exports. +#[doc(inline)] +pub use __impl::Action; +#[doc(inline)] +pub use __impl::Address; +#[doc(inline)] +pub use __impl::Anchor; +#[doc(inline)] +pub use __impl::Bundle; +#[doc(inline)] +pub use __impl::Note; +#[doc(inline)] +pub use __impl::Proof; +#[doc(inline)] +pub use __impl::NOTE_COMMITMENT_TREE_DEPTH; + +/// Logic for building Orchard components of transactions. +pub mod builder { + #[doc(inline)] + pub use __impl::builder::{ + BuildError, Builder, BundleMetadata, BundleType, InProgress, InProgressSignatures, + InputView, MaybeSigned, OutputError, OutputInfo, OutputView, PartiallyAuthorized, + SigningMetadata, SigningParts, SpendError, SpendInfo, Unauthorized, + }; + + #[cfg(feature = "circuit")] + #[doc(inline)] + pub use __impl::builder::{bundle, UnauthorizedBundle, Unproven}; + + /// Generators for property testing. + #[cfg(all(feature = "circuit", feature = "test-dependencies"))] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::builder::testing::{arb_bundle, arb_bundle_with_key}; + } +} + +/// Structs related to bundles of Orchard actions. +pub mod bundle { + #[doc(inline)] + pub use __impl::bundle::{ + Authorization, Authorized, Bundle, BundleAuthorizingCommitment, BundleCommitment, + EffectsOnly, Flags, + }; + + #[cfg(feature = "circuit")] + #[doc(inline)] + pub use __impl::bundle::BatchValidator; + + /// Utility functions for computing bundle commitments + pub mod commitments { + #[doc(inline)] + pub use __impl::bundle::commitments::{hash_bundle_auth_empty, hash_bundle_txid_empty}; + } + + /// Generators for property testing. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::bundle::testing::{ + arb_action, arb_action_n, arb_bundle, arb_flags, arb_unauthorized_action, + arb_unauthorized_action_n, arb_unauthorized_bundle, Unauthorized, + }; + } +} + +/// The Orchard Action circuit implementation. +#[cfg(feature = "circuit")] +#[cfg_attr(docsrs, doc(cfg(feature = "circuit")))] +pub mod circuit { + #[doc(inline)] + pub use __impl::circuit::{Circuit, Config, Instance, Proof, ProvingKey, VerifyingKey}; + + /// Gadgets used in the Orchard circuit. + pub mod gadget {} +} + +/// Key structures for Orchard. +pub mod keys { + #[doc(inline)] + pub use __impl::keys::{ + DiversifiedTransmissionKey, Diversifier, DiversifierIndex, EphemeralPublicKey, + EphemeralSecretKey, FullViewingKey, IncomingViewingKey, OutgoingViewingKey, + PreparedEphemeralPublicKey, PreparedIncomingViewingKey, Scope, SharedSecret, + SpendAuthorizingKey, SpendValidatingKey, SpendingKey, + }; + + /// Generators for property testing. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::keys::testing::{arb_diversifier_index, arb_esk, arb_spending_key}; + } +} + +/// Data structures used for note construction. +pub mod note { + #[doc(inline)] + pub use __impl::note::{ + ExtractedNoteCommitment, Note, NoteCommitment, Nullifier, RandomSeed, Rho, + TransmittedNoteCiphertext, + }; + + /// Generators for property testing. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::note::testing::arb_note; + } +} + +/// In-band secret distribution for Orchard bundles. +pub mod note_encryption { + #[doc(inline)] + pub use __impl::note_encryption::{CompactAction, OrchardDomain, OrchardNoteEncryption}; + + /// Utilities for constructing test data. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::note_encryption::testing::fake_compact_action; + } +} + +/// PCZT support for Orchard. +pub mod pczt { + #[doc(inline)] + pub use __impl::pczt::{ + Action, ActionUpdater, Bundle, IoFinalizerError, Output, ParseError, SignerError, Spend, + TxExtractorError, Unbound, Updater, UpdaterError, VerifyError, Zip32Derivation, + }; + + #[cfg(feature = "circuit")] + #[doc(inline)] + pub use __impl::pczt::ProverError; +} + +/// Primitives used in the Orchard protocol. +pub mod primitives { + /// A minimal RedPallas implementation for use in Zcash. + pub mod redpallas { + #[doc(inline)] + pub use __impl::primitives::redpallas::{ + Binding, SigType, Signature, SigningKey, SpendAuth, VerificationKey, + }; + + #[cfg(feature = "std")] + #[doc(inline)] + pub use __impl::primitives::redpallas::batch; + + /// Generators for property testing. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::primitives::redpallas::testing::{ + arb_binding_signing_key, arb_binding_verification_key, arb_spendauth_signing_key, + arb_spendauth_verification_key, + }; + } + } +} + +/// Types related to Orchard note commitment trees and anchors. +pub mod tree { + #[doc(inline)] + pub use __impl::tree::{Anchor, MerkleHashOrchard, MerklePath}; + + /// Test utilities available under the `test-dependencies` feature flag. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing {} +} + +/// Monetary values within the Orchard shielded pool. +/// +/// Values are represented in three places within the Orchard protocol: +/// - [`NoteValue`](value::NoteValue), the value of an individual note. It is an unsigned +/// 64-bit integer (with maximum value [`MAX_NOTE_VALUE`](value::MAX_NOTE_VALUE)), and is +/// serialized in a note plaintext. +/// - [`ValueSum`](value::ValueSum), the sum of note values within an Orchard [`Action`] or +/// [`Bundle`]. It is a signed 64-bit integer (with range +/// [`VALUE_SUM_RANGE`](value::VALUE_SUM_RANGE)). +/// - `valueBalanceOrchard`, which is a signed 63-bit integer. This is represented +/// by a user-defined type parameter on [`Bundle`], returned by +/// [`Bundle::value_balance`] and [`Builder::value_balance`](builder::Builder::value_balance). +/// +/// If your specific instantiation of the Orchard protocol requires a smaller bound on +/// valid note values (for example, Zcash's `MAX_MONEY` fits into a 51-bit integer), you +/// should enforce this in two ways: +/// +/// - Define your `valueBalanceOrchard` type to enforce your valid value range. This can +/// be checked in its `TryFrom` implementation. +/// - Define your own "amount" type for note values, and convert it to `NoteValue` prior +/// to calling [`Builder::add_output`](builder::Builder::add_output). +/// +/// # Caution! +/// +/// An `i64` is _not_ a signed 64-bit integer! The [Rust documentation] calls `i64` the +/// 64-bit signed integer type, which is true in the sense that its encoding in memory +/// takes up 64 bits. Numerically, however, `i64` is a signed 63-bit integer. +/// +/// Fortunately, users of this crate should never need to construct +/// [`ValueSum`](value::ValueSum) directly; you should only need to interact with +/// [`NoteValue`](value::NoteValue) (which can be safely constructed from a `u64`) and +/// `valueBalanceOrchard` (which can be represented as an `i64`). +/// +/// [Rust documentation]: https://doc.rust-lang.org/stable/std/primitive.i64.html +pub mod value { + #[doc(inline)] + pub use __impl::value::{ + BalanceError, NoteValue, Sign, ValueCommitTrapdoor, ValueCommitment, ValueSum, + MAX_NOTE_VALUE, VALUE_SUM_RANGE, + }; + + /// Generators for property testing. + #[cfg(feature = "test-dependencies")] + #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] + pub mod testing { + #[doc(inline)] + pub use __impl::value::testing::{ + arb_note_value, arb_note_value_bounded, arb_positive_note_value, arb_scalar, + arb_trapdoor, arb_value_sum, arb_value_sum_bounded, + }; + } +} + +/// Key structures for Orchard. +pub mod zip32 { + #[doc(inline)] + pub use __impl::zip32::{ChildIndex, Error}; +} diff --git a/tests/builder.rs b/public/tests/builder.rs similarity index 100% rename from tests/builder.rs rename to public/tests/builder.rs diff --git a/src/address.rs b/src/address.rs index 6b643ad35..781be95e4 100644 --- a/src/address.rs +++ b/src/address.rs @@ -10,6 +10,7 @@ use crate::{ /// # Examples /// /// ``` +/// # use orchard_internal as orchard; /// use orchard::keys::{SpendingKey, FullViewingKey, Scope}; /// /// let sk = SpendingKey::from_bytes([7; 32]).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 3a52af5c6..2664aab6e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,6 @@ -//! # orchard +//! Implementation crate for the Orchard shielded transaction protocol. //! -//! ## Nomenclature -//! -//! All types in the `orchard` crate, unless otherwise specified, are Orchard-specific -//! types. For example, [`Address`] is documented as being a shielded payment address; we -//! implicitly mean it is an Orchard payment address (as opposed to e.g. a Sapling payment -//! address, which is also shielded). +//! This crate is re-exported by the public `orchard` crate. Depend on `orchard` instead. #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] @@ -15,7 +10,7 @@ #![deny(rustdoc::broken_intra_doc_links)] #![deny(missing_debug_implementations)] #![deny(missing_docs)] -#![deny(unsafe_code)] +#![forbid(unsafe_code)] #[macro_use] extern crate alloc; diff --git a/src/value.rs b/src/value.rs index 053ad5838..718aa5f02 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,41 +1,4 @@ -//! Monetary values within the Orchard shielded pool. -//! -//! Values are represented in three places within the Orchard protocol: -//! - [`NoteValue`], the value of an individual note. It is an unsigned 64-bit integer -//! (with maximum value [`MAX_NOTE_VALUE`]), and is serialized in a note plaintext. -//! - [`ValueSum`], the sum of note values within an Orchard [`Action`] or [`Bundle`]. -//! It is a signed 64-bit integer (with range [`VALUE_SUM_RANGE`]). -//! - `valueBalanceOrchard`, which is a signed 63-bit integer. This is represented -//! by a user-defined type parameter on [`Bundle`], returned by -//! [`Bundle::value_balance`] and [`Builder::value_balance`]. -//! -//! If your specific instantiation of the Orchard protocol requires a smaller bound on -//! valid note values (for example, Zcash's `MAX_MONEY` fits into a 51-bit integer), you -//! should enforce this in two ways: -//! -//! - Define your `valueBalanceOrchard` type to enforce your valid value range. This can -//! be checked in its `TryFrom` implementation. -//! - Define your own "amount" type for note values, and convert it to `NoteValue` prior -//! to calling [`Builder::add_output`]. -//! -//! Inside the circuit, note values are constrained to be unsigned 64-bit integers. -//! -//! # Caution! -//! -//! An `i64` is _not_ a signed 64-bit integer! The [Rust documentation] calls `i64` the -//! 64-bit signed integer type, which is true in the sense that its encoding in memory -//! takes up 64 bits. Numerically, however, `i64` is a signed 63-bit integer. -//! -//! Fortunately, users of this crate should never need to construct [`ValueSum`] directly; -//! you should only need to interact with [`NoteValue`] (which can be safely constructed -//! from a `u64`) and `valueBalanceOrchard` (which can be represented as an `i64`). -//! -//! [`Action`]: crate::action::Action -//! [`Bundle`]: crate::bundle::Bundle -//! [`Bundle::value_balance`]: crate::bundle::Bundle::value_balance -//! [`Builder::value_balance`]: crate::builder::Builder::value_balance -//! [`Builder::add_output`]: crate::builder::Builder::add_output -//! [Rust documentation]: https://doc.rust-lang.org/stable/std/primitive.i64.html +//! Monetary value types and value commitments for the Orchard shielded pool. use core::fmt::{self, Debug}; use core::iter::Sum;