From a5f27e011ab4da1b85f03617042d1139c4fe39a6 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 13 Dec 2024 16:04:19 +0000 Subject: [PATCH] Move circuit and its dependencies behind a feature flag --- Cargo.lock | 31 +++++++++++++++++++++++-- Cargo.toml | 15 ++++++++---- src/builder.rs | 23 +++++++++++++++--- src/bundle.rs | 12 ++++++++-- src/circuit.rs | 45 ++---------------------------------- src/constants.rs | 2 +- src/constants/fixed_bases.rs | 7 ++++++ src/constants/sinsemilla.rs | 13 +++++++---- src/lib.rs | 44 ++++++++++++++++++++++++++++++++++- src/note/commitment.rs | 1 - src/note/nullifier.rs | 3 +-- src/pczt.rs | 2 ++ src/spec.rs | 7 ++++-- src/tree.rs | 2 +- src/value.rs | 2 ++ 15 files changed, 142 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5482a493e..0b49fd51b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -975,19 +975,21 @@ dependencies = [ [[package]] name = "halo2_gadgets" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126a150072b0c38c7b573fe3eaf0af944a7fed09e154071bf2436d3f016f7230" +checksum = "73a5e510d58a07d8ed238a5a8a436fe6c2c79e1bb2611f62688bc65007b4e6e7" dependencies = [ "arrayvec", "bitvec", "ff", "group", + "halo2_poseidon", "halo2_proofs", "lazy_static", "pasta_curves", "proptest", "rand", + "sinsemilla", "subtle", "uint", ] @@ -998,6 +1000,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47716fe1ae67969c5e0b2ef826f32db8c3be72be325e1aa3c1951d06b5575ec5" +[[package]] +name = "halo2_poseidon" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa3da60b81f02f9b33ebc6252d766f843291fb4d2247a07ae73d20b791fc56f" +dependencies = [ + "bitvec", + "ff", + "group", + "pasta_curves", +] + [[package]] name = "halo2_proofs" version = "0.3.0" @@ -1438,6 +1452,7 @@ dependencies = [ "getset", "group", "halo2_gadgets", + "halo2_poseidon", "halo2_proofs", "hex", "image", @@ -1453,6 +1468,7 @@ dependencies = [ "rand", "reddsa", "serde", + "sinsemilla", "subtle", "tracing", "visibility", @@ -2020,6 +2036,17 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "sinsemilla" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d268ae0ea06faafe1662e9967cd4f9022014f5eeb798e0c302c876df8b7af9c" +dependencies = [ + "group", + "pasta_curves", + "subtle", +] + [[package]] name = "smallvec" version = "1.11.0" diff --git a/Cargo.toml b/Cargo.toml index 8c014ecdf..04a9508d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,8 +29,6 @@ blake2b_simd = "1" ff = "0.13" fpe = "0.6" group = { version = "0.13", features = ["wnaf-memuse"] } -halo2_gadgets = "0.3" -halo2_proofs = { version = "0.3", default-features = false, features = ["batch", "floor-planner-v1-legacy-pdqsort"] } hex = "0.4" lazy_static = "1" memuse = { version = "0.2.1", features = ["nonempty"] } @@ -39,7 +37,9 @@ proptest = { version = "1.0.0", optional = true } rand = "0.8" reddsa = "0.5" nonempty = "0.7" +poseidon = { package = "halo2_poseidon", version = "0.1" } serde = { version = "1.0", features = ["derive"] } +sinsemilla = "0.1" subtle = "2.3" zcash_note_encryption = "0.4" incrementalmerkletree = "0.7" @@ -47,6 +47,10 @@ zcash_spec = "0.1" zip32 = "0.1" visibility = "0.1.1" +# Circuit +halo2_gadgets = { version = "0.3", optional = true } +halo2_proofs = { version = "0.3", optional = true, default-features = false, features = ["batch", "floor-planner-v1-legacy-pdqsort"] } + # Boilerplate getset = "0.1" @@ -74,10 +78,11 @@ pprof = { version = "0.11", features = ["criterion", "flamegraph"] } bench = false [features] -default = ["multicore"] +default = ["circuit", "multicore"] +circuit = ["dep:halo2_gadgets", "dep:halo2_proofs"] unstable-frost = [] -multicore = ["halo2_proofs/multicore"] -dev-graph = ["halo2_proofs/dev-graph", "image", "plotters"] +multicore = ["halo2_proofs?/multicore"] +dev-graph = ["halo2_proofs?/dev-graph", "image", "plotters"] test-dependencies = ["proptest"] [[bench]] diff --git a/src/builder.rs b/src/builder.rs index 7e7a1129d..622230cb1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -6,15 +6,12 @@ use std::collections::BTreeMap; use std::fmt::Display; use ff::Field; -use nonempty::NonEmpty; use pasta_curves::pallas; use rand::{prelude::SliceRandom, CryptoRng, RngCore}; use crate::{ - action::Action, address::Address, bundle::{Authorization, Authorized, Bundle, Flags}, - circuit::{Circuit, Instance, Proof, ProvingKey}, keys::{ FullViewingKey, OutgoingViewingKey, Scope, SpendAuthorizingKey, SpendValidatingKey, SpendingKey, @@ -24,6 +21,16 @@ use crate::{ primitives::redpallas::{self, Binding, SpendAuth}, tree::{Anchor, MerklePath}, value::{self, NoteValue, OverflowError, ValueCommitTrapdoor, ValueCommitment, ValueSum}, + Proof, +}; + +#[cfg(feature = "circuit")] +use { + crate::{ + action::Action, + circuit::{Circuit, Instance, ProvingKey}, + }, + nonempty::NonEmpty, }; const MIN_ACTIONS: usize = 2; @@ -120,6 +127,7 @@ pub enum BuildError { /// A bundle could not be built because required signatures were missing. MissingSignatures, /// An error occurred in the process of producing a proof for a bundle. + #[cfg(feature = "circuit")] Proof(halo2_proofs::plonk::Error), /// An overflow error occurred while attempting to construct the value /// for a bundle. @@ -138,6 +146,7 @@ impl Display for BuildError { use BuildError::*; match self { MissingSignatures => f.write_str("Required signatures were missing during build"), + #[cfg(feature = "circuit")] Proof(e) => f.write_str(&format!("Could not create proof: {}", e)), ValueSum(_) => f.write_str("Overflow occurred during value construction"), InvalidExternalSignature => f.write_str("External signature was invalid"), @@ -156,6 +165,7 @@ impl Display for BuildError { impl std::error::Error for BuildError {} +#[cfg(feature = "circuit")] impl From for BuildError { fn from(e: halo2_proofs::plonk::Error) -> Self { BuildError::Proof(e) @@ -423,6 +433,7 @@ impl ActionInfo { /// Defined in [Zcash Protocol Spec ยง 4.7.3: Sending Notes (Orchard)][orchardsend]. /// /// [orchardsend]: https://zips.z.cash/protocol/nu5.pdf#orchardsend + #[cfg(feature = "circuit")] fn build(self, mut rng: impl RngCore) -> (Action, Circuit) { let v_net = self.value_sum(); let cv_net = ValueCommitment::derive(v_net, self.rcv.clone()); @@ -465,6 +476,7 @@ impl ActionInfo { /// Type alias for an in-progress bundle that has no proofs or signatures. /// /// This is returned by [`Builder::build`]. +#[cfg(feature = "circuit")] pub type UnauthorizedBundle = Bundle, V>; /// Metadata about a bundle created by [`bundle`] or [`Builder::build`] that is not @@ -633,6 +645,7 @@ impl Builder { /// /// The returned bundle will have no proof or signatures; these can be applied with /// [`Bundle::create_proof`] and [`Bundle::apply_signatures`] respectively. + #[cfg(feature = "circuit")] pub fn build>( self, rng: impl RngCore, @@ -685,6 +698,7 @@ impl Builder { /// /// The returned bundle will have no proof or signatures; these can be applied with /// [`Bundle::create_proof`] and [`Bundle::apply_signatures`] respectively. +#[cfg(feature = "circuit")] pub fn bundle>( rng: impl RngCore, anchor: Anchor, @@ -847,11 +861,13 @@ impl Authorization for InProgress /// Marker for a bundle without a proof. /// /// This struct contains the private data needed to create a [`Proof`] for a [`Bundle`]. +#[cfg(feature = "circuit")] #[derive(Clone, Debug)] pub struct Unproven { circuits: Vec, } +#[cfg(feature = "circuit")] impl InProgress { /// Creates the proof for this bundle. pub fn create_proof( @@ -864,6 +880,7 @@ impl InProgress { } } +#[cfg(feature = "circuit")] impl Bundle, V> { /// Creates the proof for this bundle. pub fn create_proof( diff --git a/src/bundle.rs b/src/bundle.rs index e2bc9a356..36bc14fa9 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -1,8 +1,10 @@ //! Structs related to bundles of Orchard actions. -mod batch; pub mod commitments; +#[cfg(feature = "circuit")] +mod batch; +#[cfg(feature = "circuit")] pub use batch::BatchValidator; use core::fmt; @@ -16,15 +18,19 @@ use crate::{ action::Action, address::Address, bundle::commitments::{hash_bundle_auth_data, hash_bundle_txid_data}, - circuit::{Instance, Proof, VerifyingKey}, keys::{IncomingViewingKey, OutgoingViewingKey, PreparedIncomingViewingKey}, note::Note, note_encryption::OrchardDomain, primitives::redpallas::{self, Binding, SpendAuth}, tree::Anchor, value::{ValueCommitTrapdoor, ValueCommitment, ValueSum}, + Proof, }; +#[cfg(feature = "circuit")] +use crate::circuit::{Instance, VerifyingKey}; + +#[cfg(feature = "circuit")] impl Action { /// Prepares the public instance for this action, for creating and verifying the /// bundle proof. @@ -288,6 +294,7 @@ impl Bundle { }) } + #[cfg(feature = "circuit")] pub(crate) fn to_instances(&self) -> Vec { self.actions .iter() @@ -457,6 +464,7 @@ impl Bundle { } /// Verifies the proof for this bundle. + #[cfg(feature = "circuit")] pub fn verify_proof(&self, vk: &VerifyingKey) -> Result<(), halo2_proofs::plonk::Error> { self.authorization() .proof() diff --git a/src/circuit.rs b/src/circuit.rs index 567b60658..67715d639 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -1,7 +1,5 @@ //! The Orchard Action circuit implementation. -use core::fmt; - use group::{Curve, GroupEncoding}; use halo2_proofs::{ circuit::{floor_planner, Layouter, Value}, @@ -12,7 +10,6 @@ use halo2_proofs::{ poly::Rotation, transcript::{Blake2bRead, Blake2bWrite}, }; -use memuse::DynamicUsage; use pasta_curves::{arithmetic::CurveAffine, pallas, vesta}; use rand::RngCore; @@ -63,6 +60,8 @@ mod commit_ivk; pub mod gadget; mod note_commit; +pub use crate::Proof; + /// Size of the Orchard circuit. const K: u32 = 11; @@ -856,41 +855,6 @@ impl Instance { } } -/// A proof of the validity of an Orchard [`Bundle`]. -/// -/// [`Bundle`]: crate::bundle::Bundle -#[derive(Clone)] -pub struct Proof(Vec); - -impl fmt::Debug for Proof { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if f.alternate() { - f.debug_tuple("Proof").field(&self.0).finish() - } else { - // By default, only show the proof length, not its contents. - f.debug_tuple("Proof") - .field(&format_args!("{} bytes", self.0.len())) - .finish() - } - } -} - -impl AsRef<[u8]> for Proof { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -impl DynamicUsage for Proof { - fn dynamic_usage(&self) -> usize { - self.0.dynamic_usage() - } - - fn dynamic_usage_bounds(&self) -> (usize, Option) { - self.0.dynamic_usage_bounds() - } -} - impl Proof { /// Creates a proof for the given circuits and instances. pub fn create( @@ -951,11 +915,6 @@ impl Proof { batch.add_proof(instances, self.0.clone()); } - - /// Constructs a new Proof value. - pub fn new(bytes: Vec) -> Self { - Proof(bytes) - } } #[cfg(test)] diff --git a/src/constants.rs b/src/constants.rs index b64d114f5..7f40b5394 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -3,8 +3,8 @@ pub mod fixed_bases; pub mod sinsemilla; pub mod util; +pub use self::sinsemilla::{OrchardCommitDomains, OrchardHashDomains}; pub use fixed_bases::{NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV}; -pub use sinsemilla::{OrchardCommitDomains, OrchardHashDomains}; /// $\mathsf{MerkleDepth^{Orchard}}$ pub const MERKLE_DEPTH_ORCHARD: usize = 32; diff --git a/src/constants/fixed_bases.rs b/src/constants/fixed_bases.rs index af11e335f..23d110c26 100644 --- a/src/constants/fixed_bases.rs +++ b/src/constants/fixed_bases.rs @@ -1,10 +1,13 @@ //! Orchard fixed bases. use super::{L_ORCHARD_SCALAR, L_VALUE}; + +#[cfg(feature = "circuit")] use halo2_gadgets::ecc::{ chip::{BaseFieldElem, FixedPoint, FullScalar, ShortScalar}, FixedPoints, }; +#[cfg(feature = "circuit")] use pasta_curves::pallas; pub mod commit_ivk_r; @@ -91,12 +94,14 @@ pub struct NullifierK; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct ValueCommitV; +#[cfg(feature = "circuit")] impl FixedPoints for OrchardFixedBases { type FullScalar = OrchardFixedBasesFull; type Base = NullifierK; type ShortScalar = ValueCommitV; } +#[cfg(feature = "circuit")] impl FixedPoint for OrchardFixedBasesFull { type FixedScalarKind = FullScalar; @@ -128,6 +133,7 @@ impl FixedPoint for OrchardFixedBasesFull { } } +#[cfg(feature = "circuit")] impl FixedPoint for NullifierK { type FixedScalarKind = BaseFieldElem; @@ -144,6 +150,7 @@ impl FixedPoint for NullifierK { } } +#[cfg(feature = "circuit")] impl FixedPoint for ValueCommitV { type FixedScalarKind = ShortScalar; diff --git a/src/constants/sinsemilla.rs b/src/constants/sinsemilla.rs index f6c6ffba6..84198f39e 100644 --- a/src/constants/sinsemilla.rs +++ b/src/constants/sinsemilla.rs @@ -1,10 +1,13 @@ //! Sinsemilla generators -use super::{OrchardFixedBases, OrchardFixedBasesFull}; use crate::spec::i2lebsp; -use halo2_gadgets::sinsemilla::{CommitDomains, HashDomains}; -use group::ff::PrimeField; -use pasta_curves::{arithmetic::CurveAffine, pallas}; +#[cfg(feature = "circuit")] +use { + super::{OrchardFixedBases, OrchardFixedBasesFull}, + group::ff::PrimeField, + halo2_gadgets::sinsemilla::{CommitDomains, HashDomains}, + pasta_curves::{arithmetic::CurveAffine, pallas}, +}; /// Number of bits of each message piece in $\mathsf{SinsemillaHashToPoint}$ pub const K: usize = 10; @@ -82,6 +85,7 @@ pub enum OrchardHashDomains { MerkleCrh, } +#[cfg(feature = "circuit")] #[allow(non_snake_case)] impl HashDomains for OrchardHashDomains { fn Q(&self) -> pallas::Affine { @@ -111,6 +115,7 @@ pub enum OrchardCommitDomains { CommitIvk, } +#[cfg(feature = "circuit")] impl CommitDomains for OrchardCommitDomains { fn r(&self) -> OrchardFixedBasesFull { match self { diff --git a/src/lib.rs b/src/lib.rs index 54db6d4d4..2ac5dcecb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ mod action; mod address; pub mod builder; pub mod bundle; +#[cfg(feature = "circuit")] pub mod circuit; mod constants; pub mod keys; @@ -38,7 +39,48 @@ mod test_vectors; pub use action::Action; pub use address::Address; pub use bundle::Bundle; -pub use circuit::Proof; pub use constants::MERKLE_DEPTH_ORCHARD as NOTE_COMMITMENT_TREE_DEPTH; pub use note::Note; pub use tree::Anchor; + +/// A proof of the validity of an Orchard [`Bundle`]. +/// +/// [`Bundle`]: crate::bundle::Bundle +#[derive(Clone)] +pub struct Proof(Vec); + +impl core::fmt::Debug for Proof { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + if f.alternate() { + f.debug_tuple("Proof").field(&self.0).finish() + } else { + // By default, only show the proof length, not its contents. + f.debug_tuple("Proof") + .field(&format_args!("{} bytes", self.0.len())) + .finish() + } + } +} + +impl AsRef<[u8]> for Proof { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl memuse::DynamicUsage for Proof { + fn dynamic_usage(&self) -> usize { + self.0.dynamic_usage() + } + + fn dynamic_usage_bounds(&self) -> (usize, Option) { + self.0.dynamic_usage_bounds() + } +} + +impl Proof { + /// Constructs a new Proof value. + pub fn new(bytes: Vec) -> Self { + Proof(bytes) + } +} diff --git a/src/note/commitment.rs b/src/note/commitment.rs index 9de51d28e..5d0125874 100644 --- a/src/note/commitment.rs +++ b/src/note/commitment.rs @@ -2,7 +2,6 @@ use core::iter; use bitvec::{array::BitArray, order::Lsb0}; use group::ff::{PrimeField, PrimeFieldBits}; -use halo2_gadgets::sinsemilla::primitives as sinsemilla; use pasta_curves::pallas; use subtle::{ConstantTimeEq, CtOption}; diff --git a/src/note/nullifier.rs b/src/note/nullifier.rs index bde133995..15ac3699f 100644 --- a/src/note/nullifier.rs +++ b/src/note/nullifier.rs @@ -1,7 +1,6 @@ use group::{ff::PrimeField, Group}; -use halo2_proofs::arithmetic::CurveExt; use memuse::DynamicUsage; -use pasta_curves::pallas; +use pasta_curves::{arithmetic::CurveExt, pallas}; use rand::RngCore; use subtle::{ConstantTimeEq, CtOption}; diff --git a/src/pczt.rs b/src/pczt.rs index 3fcf72fe9..cebc3eab5 100644 --- a/src/pczt.rs +++ b/src/pczt.rs @@ -30,7 +30,9 @@ pub use io_finalizer::IoFinalizerError; mod updater; pub use updater::{ActionUpdater, Updater, UpdaterError}; +#[cfg(feature = "circuit")] mod prover; +#[cfg(feature = "circuit")] pub use prover::ProverError; mod signer; diff --git a/src/spec.rs b/src/spec.rs index 7f0224bff..d1365f1c5 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -5,10 +5,13 @@ use core::ops::Deref; use ff::{Field, FromUniformBytes, PrimeField, PrimeFieldBits}; use group::{Curve, Group, GroupEncoding, WnafBase, WnafScalar}; +#[cfg(feature = "circuit")] use halo2_gadgets::{poseidon::primitives as poseidon, sinsemilla::primitives as sinsemilla}; -use halo2_proofs::arithmetic::{CurveAffine, CurveExt}; use memuse::DynamicUsage; -use pasta_curves::pallas; +use pasta_curves::{ + arithmetic::{CurveAffine, CurveExt}, + pallas, +}; use subtle::{ConditionallySelectable, CtOption}; use crate::constants::{ diff --git a/src/tree.rs b/src/tree.rs index 046f5d924..98824ac83 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -10,9 +10,9 @@ use crate::{ note::commitment::ExtractedNoteCommitment, }; -use halo2_gadgets::sinsemilla::primitives::HashDomain; use incrementalmerkletree::{Hashable, Level}; use pasta_curves::pallas; +use sinsemilla::HashDomain; use ff::{Field, PrimeField, PrimeFieldBits}; use lazy_static::lazy_static; diff --git a/src/value.rs b/src/value.rs index 61c22337d..058feb103 100644 --- a/src/value.rs +++ b/src/value.rs @@ -44,6 +44,7 @@ use core::ops::{Add, RangeInclusive, Sub}; use bitvec::{array::BitArray, order::Lsb0}; use ff::{Field, PrimeField}; use group::{Curve, Group, GroupEncoding}; +#[cfg(feature = "circuit")] use halo2_proofs::plonk::Assigned; use pasta_curves::{ arithmetic::{CurveAffine, CurveExt}, @@ -118,6 +119,7 @@ impl NoteValue { } } +#[cfg(feature = "circuit")] impl From<&NoteValue> for Assigned { fn from(v: &NoteValue) -> Self { pallas::Base::from(v.inner()).into()