diff --git a/benches/circuit.rs b/benches/circuit.rs index faf7f3c5f..579a34675 100644 --- a/benches/circuit.rs +++ b/benches/circuit.rs @@ -68,7 +68,7 @@ fn criterion_benchmark(c: &mut Criterion) { b.iter(|| { bundle .authorization() - .create_proof(&pk, &instances, rng) + .create_proof::(&pk, &instances, rng) .unwrap() }); }); diff --git a/src/builder.rs b/src/builder.rs index 4c232293d..61cc2aa0e 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -32,8 +32,8 @@ use { crate::{ action::Action, bundle::derive_bvk, - circuit::{Circuit, Instance, ProvingKey, Witnesses}, - orchard_flavor::{Flavor, OrchardFlavor, OrchardVanilla, OrchardZSA}, + circuit::{Circuit, Instance, OrchardCircuit, ProvingKey, Witnesses}, + orchard_flavor::OrchardFlavor, }, nonempty::NonEmpty, }; @@ -500,10 +500,10 @@ impl ActionInfo { /// /// Panics if the asset types of the spent and output notes do not match. #[cfg(feature = "circuit")] - fn build( + fn build( self, mut rng: impl RngCore, - ) -> (Action, Witnesses) { + ) -> (Action, Witnesses) { assert_eq!( self.spend.note.asset(), self.output.asset, @@ -528,7 +528,7 @@ impl ActionInfo { parts: SigningParts { ak, alpha }, }, ), - Witnesses::from_action_context_unchecked(self.spend, note, alpha, self.rcv), + Witnesses::from_action_context_unchecked::(self.spend, note, alpha, self.rcv), ) } @@ -931,10 +931,7 @@ pub fn bundle, FL: OrchardFlavor>( burn_vec, anchor, InProgress { - proof: Unproven { - witnesses, - circuit_flavor: FL::FLAVOR, - }, + proof: Unproven { witnesses }, sigs: Unauthorized { bsk }, }, ), @@ -1153,44 +1150,30 @@ impl Authorization for InProgress #[derive(Clone, Debug)] pub struct Unproven { witnesses: Vec, - circuit_flavor: Flavor, } #[cfg(feature = "circuit")] impl InProgress { /// Creates the proof for this bundle. - pub fn create_proof( + /// + /// The `OrchardCircuit` type parameter must match the circuit used when generating the witnesses + /// contained in this `Unproven` structure to ensure consistency and correctness of the proof. + pub fn create_proof( &self, pk: &ProvingKey, instances: &[Instance], rng: impl RngCore, ) -> Result { - match self.proof.circuit_flavor { - Flavor::OrchardVanillaFlavor => { - let circuits = self - .proof - .witnesses - .iter() - .map(|witnesses| Circuit:: { - witnesses: witnesses.clone(), - phantom: core::marker::PhantomData, - }) - .collect::>>(); - Proof::create(pk, &circuits, instances, rng) - } - Flavor::OrchardZSAFlavor => { - let circuits = self - .proof - .witnesses - .iter() - .map(|witnesses| Circuit:: { - witnesses: witnesses.clone(), - phantom: core::marker::PhantomData, - }) - .collect::>>(); - Proof::create(pk, &circuits, instances, rng) - } - } + let circuits = self + .proof + .witnesses + .iter() + .map(|witnesses| Circuit:: { + witnesses: witnesses.clone(), + phantom: core::marker::PhantomData, + }) + .collect::>>(); + Proof::create(pk, &circuits, instances, rng) } } @@ -1211,7 +1194,7 @@ impl Bundle(pk, &instances, &mut rng)?; Ok(InProgress { proof, sigs: auth.sigs, diff --git a/src/circuit.rs b/src/circuit.rs index 6800d42b0..ae6f1931f 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -6,12 +6,6 @@ use alloc::vec::Vec; use group::{Curve, GroupEncoding}; -use halo2_gadgets::{ - ecc::chip::EccConfig, - poseidon::Pow5Config as PoseidonConfig, - sinsemilla::{chip::SinsemillaConfig, merkle::chip::MerkleConfig}, - utilities::lookup_range_check::PallasLookupRangeCheck, -}; use halo2_proofs::{ circuit::{floor_planner, Layouter, Value}, plonk::{ @@ -44,6 +38,12 @@ use crate::{ tree::{Anchor, MerkleHashOrchard}, value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, }; +use halo2_gadgets::{ + ecc::chip::EccConfig, + poseidon::Pow5Config as PoseidonConfig, + sinsemilla::{chip::SinsemillaConfig, merkle::chip::MerkleConfig}, + utilities::lookup_range_check::PallasLookupRangeCheck, +}; mod circuit_vanilla; mod circuit_zsa; @@ -110,6 +110,14 @@ pub trait OrchardCircuit: Sized + Default { config: Self::Config, layouter: impl Layouter, ) -> Result<(), plonk::Error>; + + /// Builds the ZSA-specific witnesses for the circuit. + /// For OrchardVanilla circuits, it should return `Value::unknown()`. + fn build_additional_zsa_witnesses( + psi_nf: pallas::Base, + asset: AssetBase, + split_flag: bool, + ) -> Value; } impl plonk::Circuit for Circuit { @@ -135,9 +143,27 @@ impl plonk::Circuit for Circuit { /// The Orchard Action circuit. #[derive(Clone, Debug, Default)] -pub struct Circuit { +pub struct Circuit { pub(crate) witnesses: Witnesses, - pub(crate) phantom: core::marker::PhantomData, + pub(crate) phantom: core::marker::PhantomData, +} + +/// The ZSA-specific witnesses. +#[derive(Clone, Debug)] +pub struct AdditionalZsaWitnesses { + pub(crate) psi_nf: pallas::Base, + pub(crate) asset: AssetBase, + pub(crate) split_flag: bool, +} + +fn unpack( + zsa_values: Value, +) -> (Value, Value, Value) { + ( + zsa_values.clone().map(|values| values.psi_nf), + zsa_values.clone().map(|values| values.asset), + zsa_values.map(|values| values.split_flag), + ) } /// The Orchard Action witnesses @@ -152,7 +178,6 @@ pub struct Witnesses { pub(crate) psi_old: Value, pub(crate) rcm_old: Value, pub(crate) cm_old: Value, - pub(crate) psi_nf: Value, pub(crate) alpha: Value, pub(crate) ak: Value, pub(crate) nk: Value, @@ -163,8 +188,10 @@ pub struct Witnesses { pub(crate) psi_new: Value, pub(crate) rcm_new: Value, pub(crate) rcv: Value, - pub(crate) asset: Value, - pub(crate) split_flag: Value, + + // The ZSA-specific witnesses. + // For OrchardVanilla circuits, this field should be initialized to `Value::unknown()`. + pub(crate) additional_zsa_witnesses: Value, } impl Witnesses { @@ -183,17 +210,17 @@ impl Witnesses { /// /// [`SpendInfo`]: crate::builder::SpendInfo /// [`Builder`]: crate::builder::Builder - pub fn from_action_context( + pub fn from_action_context( spend: SpendInfo, output_note: Note, alpha: pallas::Scalar, rcv: ValueCommitTrapdoor, ) -> Option { (Rho::from_nf_old(spend.note.nullifier(&spend.fvk)) == output_note.rho()) - .then(|| Self::from_action_context_unchecked(spend, output_note, alpha, rcv)) + .then(|| Self::from_action_context_unchecked::(spend, output_note, alpha, rcv)) } - pub(crate) fn from_action_context_unchecked( + pub(crate) fn from_action_context_unchecked( spend: SpendInfo, output_note: Note, alpha: pallas::Scalar, @@ -204,13 +231,15 @@ impl Witnesses { let psi_old = spend.note.rseed().psi(&rho_old); let rcm_old = spend.note.rseed().rcm(&rho_old); - let nf_rseed = spend.note.rseed_split_note().unwrap_or(*spend.note.rseed()); - let psi_nf = nf_rseed.psi(&rho_old); - let rho_new = output_note.rho(); let psi_new = output_note.rseed().psi(&rho_new); let rcm_new = output_note.rseed().rcm(&rho_new); + let nf_rseed = spend.note.rseed_split_note().unwrap_or(*spend.note.rseed()); + let psi_nf = nf_rseed.psi(&rho_old); + let additional_zsa_witnesses = + C::build_additional_zsa_witnesses(psi_nf, spend.note.asset(), spend.split_flag); + Witnesses { path: Value::known(spend.merkle_path.auth_path()), pos: Value::known(spend.merkle_path.position()), @@ -221,7 +250,6 @@ impl Witnesses { psi_old: Value::known(psi_old), rcm_old: Value::known(rcm_old), cm_old: Value::known(spend.note.commitment()), - psi_nf: Value::known(psi_nf), alpha: Value::known(alpha), ak: Value::known(spend.fvk.clone().into()), nk: Value::known(*spend.fvk.nk()), @@ -232,8 +260,8 @@ impl Witnesses { psi_new: Value::known(psi_new), rcm_new: Value::known(rcm_new), rcv: Value::known(rcv), - asset: Value::known(spend.note.asset()), - split_flag: Value::known(spend.split_flag), + + additional_zsa_witnesses, } } } diff --git a/src/circuit/circuit_vanilla.rs b/src/circuit/circuit_vanilla.rs index be472ea5f..d9132677a 100644 --- a/src/circuit/circuit_vanilla.rs +++ b/src/circuit/circuit_vanilla.rs @@ -30,6 +30,7 @@ use crate::{ circuit::value_commit_orchard::gadgets::value_commit_orchard, circuit::{Config, Witnesses}, constants::{OrchardFixedBases, OrchardFixedBasesFull, OrchardHashDomains}, + note::AssetBase, orchard_flavor::OrchardVanilla, }; @@ -37,8 +38,8 @@ use super::{ commit_ivk::CommitIvkChip, gadget::{add_chip::AddChip, assign_free_advice}, note_commit::NoteCommitChip, - OrchardCircuit, ANCHOR, CMX, CV_NET_X, CV_NET_Y, ENABLE_OUTPUT, ENABLE_SPEND, NF_OLD, RK_X, - RK_Y, + AdditionalZsaWitnesses, OrchardCircuit, ANCHOR, CMX, CV_NET_X, CV_NET_Y, ENABLE_OUTPUT, + ENABLE_SPEND, NF_OLD, RK_X, RK_Y, }; impl OrchardCircuit for OrchardVanilla { @@ -379,7 +380,7 @@ impl OrchardCircuit for OrchardVanilla { // Nullifier integrity (https://p.z.cash/ZKS:action-nullifier-integrity). let nf_old = { let nf_old = derive_nullifier( - &mut layouter.namespace(|| "nf_old = DeriveNullifier_nk(rho_old, psi_old, cm_old)"), + layouter.namespace(|| "nf_old = DeriveNullifier_nk(rho_old, psi_old, cm_old)"), config.poseidon_chip(), config.add_chip(), ecc_chip.clone(), @@ -609,6 +610,24 @@ impl OrchardCircuit for OrchardVanilla { Ok(()) } + + /// For OrchardVanilla circuits, `build_additional_zsa_witnesses` returns `Value::unknown()`. + /// + /// # Panics + /// Panics if the asset is not a native asset or if `split_flag` is true. + fn build_additional_zsa_witnesses( + _: pallas::Base, + asset: AssetBase, + split_flag: bool, + ) -> Value { + if !(bool::from(asset.is_native())) { + panic!("asset must be native asset in OrchardVanilla circuit"); + } + if split_flag { + panic!("split_flag must be false in OrchardVanilla circuit"); + } + Value::unknown() + } } #[cfg(test)] @@ -632,9 +651,7 @@ mod tests { value::{ValueCommitTrapdoor, ValueCommitment}, }; - type OrchardCircuitVanilla = Circuit; - - fn generate_circuit_instance(mut rng: R) -> (OrchardCircuitVanilla, Instance) { + fn generate_circuit_instance(mut rng: R) -> (Circuit, Instance) { let (_, fvk, spent_note) = Note::dummy(&mut rng, None, AssetBase::native()); let sender_address = spent_note.recipient(); @@ -656,10 +673,8 @@ mod tests { let path = MerklePath::dummy(&mut rng); let anchor = path.root(spent_note.commitment().into()); - let psi_old = spent_note.rseed().psi(&spent_note.rho()); - ( - OrchardCircuitVanilla { + Circuit { witnesses: Witnesses { path: Value::known(path.auth_path()), pos: Value::known(path.position()), @@ -670,8 +685,6 @@ mod tests { psi_old: Value::known(spent_note.rseed().psi(&spent_note.rho())), rcm_old: Value::known(spent_note.rseed().rcm(&spent_note.rho())), cm_old: Value::known(spent_note.commitment()), - // For non split note, psi_nf is equal to psi_old - psi_nf: Value::known(psi_old), alpha: Value::known(alpha), ak: Value::known(ak), nk: Value::known(nk), @@ -682,8 +695,8 @@ mod tests { psi_new: Value::known(output_note.rseed().psi(&output_note.rho())), rcm_new: Value::known(output_note.rseed().rcm(&output_note.rho())), rcv: Value::known(rcv), - asset: Value::known(spent_note.asset()), - split_flag: Value::known(false), + + ..Witnesses::default() }, phantom: core::marker::PhantomData, }, @@ -860,7 +873,7 @@ mod tests { .titled("Orchard Action Circuit", ("sans-serif", 60)) .unwrap(); - let circuit = OrchardCircuitVanilla { + let circuit = Circuit:: { witnesses: Witnesses::default(), phantom: core::marker::PhantomData, }; diff --git a/src/circuit/circuit_zsa.rs b/src/circuit/circuit_zsa.rs index a15e6da0c..37be7e8f4 100644 --- a/src/circuit/circuit_zsa.rs +++ b/src/circuit/circuit_zsa.rs @@ -32,9 +32,10 @@ use super::{ derive_nullifier::ZsaNullifierParams, gadget::{add_chip::AddChip, assign_free_advice, assign_is_native_asset, assign_split_flag}, note_commit::NoteCommitChip, + unpack, value_commit_orchard::ZsaValueCommitParams, - OrchardCircuit, ANCHOR, CMX, CV_NET_X, CV_NET_Y, ENABLE_OUTPUT, ENABLE_SPEND, ENABLE_ZSA, - NF_OLD, RK_X, RK_Y, + AdditionalZsaWitnesses, OrchardCircuit, ANCHOR, CMX, CV_NET_X, CV_NET_Y, ENABLE_OUTPUT, + ENABLE_SPEND, ENABLE_ZSA, NF_OLD, RK_X, RK_Y, }; use crate::{ circuit::commit_ivk::gadgets::commit_ivk, @@ -335,6 +336,10 @@ impl OrchardCircuit for OrchardZSA { // Load the Sinsemilla generator lookup table used by the whole circuit. SinsemillaChip::load(config.sinsemilla_config_1.clone(), &mut layouter)?; + // Unpack the ZSA witnesses. + let (psi_nf_value, asset_value, split_flag_value) = + unpack(circuit.additional_zsa_witnesses.clone()); + // Construct the ECC chip. let ecc_chip = config.ecc_chip(); @@ -344,7 +349,7 @@ impl OrchardCircuit for OrchardZSA { let psi_nf = assign_free_advice( layouter.namespace(|| "witness psi_nf"), config.advices[0], - circuit.psi_nf, + psi_nf_value, )?; // Witness psi_old @@ -408,7 +413,7 @@ impl OrchardCircuit for OrchardZSA { let asset = NonIdentityPoint::new( ecc_chip.clone(), layouter.namespace(|| "witness asset"), - circuit.asset.map(|asset| asset.cv_base().to_affine()), + asset_value.map(|asset| asset.cv_base().to_affine()), )?; ( @@ -420,7 +425,7 @@ impl OrchardCircuit for OrchardZSA { let split_flag = assign_split_flag( layouter.namespace(|| "witness split_flag"), config.advices[0], - circuit.split_flag, + split_flag_value, )?; // Witness is_native_asset which is equal to @@ -429,7 +434,7 @@ impl OrchardCircuit for OrchardZSA { let is_native_asset = assign_is_native_asset( layouter.namespace(|| "witness is_native_asset"), config.advices[0], - circuit.asset, + asset_value, )?; // Merkle path validity check. @@ -457,7 +462,7 @@ impl OrchardCircuit for OrchardZSA { // v_net is equal to // (-v_new) if split_flag = true // v_old - v_new if split_flag = false - let v_net = circuit.split_flag.and_then(|split_flag| { + let v_net = split_flag_value.and_then(|split_flag| { if split_flag { Value::known(crate::value::NoteValue::zero()) - circuit.v_new } else { @@ -523,7 +528,7 @@ impl OrchardCircuit for OrchardZSA { // [zip226]: https://zips.z.cash/zip-0226 let nf_old = { let nf_old = derive_nullifier( - &mut layouter.namespace(|| "nf_old = DeriveNullifier_nk(rho_old, psi_nf, cm_old)"), + layouter.namespace(|| "nf_old = DeriveNullifier_nk(rho_old, psi_nf, cm_old)"), config.poseidon_chip(), config.add_chip(), ecc_chip.clone(), @@ -788,7 +793,7 @@ impl OrchardCircuit for OrchardZSA { config.advices[2], 1, || { - circuit.asset.map(|asset| { + asset_value.map(|asset| { let asset_x = *asset.cv_base().to_affine().coordinates().unwrap().x(); let native_asset_x = *AssetBase::native() .cv_base() @@ -812,7 +817,7 @@ impl OrchardCircuit for OrchardZSA { config.advices[3], 1, || { - circuit.asset.map(|asset| { + asset_value.map(|asset| { let asset_y = *asset.cv_base().to_affine().coordinates().unwrap().y(); let native_asset_y = *AssetBase::native() .cv_base() @@ -849,6 +854,18 @@ impl OrchardCircuit for OrchardZSA { Ok(()) } + + fn build_additional_zsa_witnesses( + psi_nf: pallas::Base, + asset: AssetBase, + split_flag: bool, + ) -> Value { + Value::known(AdditionalZsaWitnesses { + psi_nf, + asset, + split_flag, + }) + } } #[cfg(test)] @@ -863,11 +880,13 @@ mod tests { use rand::{rngs::OsRng, RngCore}; use rand_core::CryptoRngCore; - use crate::circuit::Witnesses; use crate::{ builder::SpendInfo, bundle::Flags, - circuit::{Circuit, Instance, Proof, ProvingKey, VerifyingKey, K}, + circuit::{ + AdditionalZsaWitnesses, Circuit, Instance, Proof, ProvingKey, VerifyingKey, Witnesses, + K, + }, keys::{FullViewingKey, Scope, SpendValidatingKey, SpendingKey}, note::{commitment::NoteCommitTrapdoor, AssetBase, Note, NoteCommitment, Nullifier, Rho}, orchard_flavor::OrchardZSA, @@ -876,9 +895,7 @@ mod tests { value::{NoteValue, ValueCommitTrapdoor, ValueCommitment}, }; - type OrchardCircuitZSA = Circuit; - - fn generate_dummy_circuit_instance(mut rng: R) -> (OrchardCircuitZSA, Instance) { + fn generate_dummy_circuit_instance(mut rng: R) -> (Circuit, Instance) { let (_, fvk, spent_note) = Note::dummy(&mut rng, None, AssetBase::native()); let sender_address = spent_note.recipient(); @@ -903,7 +920,7 @@ mod tests { let psi_old = spent_note.rseed().psi(&spent_note.rho()); ( - OrchardCircuitZSA { + Circuit { witnesses: Witnesses { path: Value::known(path.auth_path()), pos: Value::known(path.position()), @@ -914,8 +931,6 @@ mod tests { psi_old: Value::known(psi_old), rcm_old: Value::known(spent_note.rseed().rcm(&spent_note.rho())), cm_old: Value::known(spent_note.commitment()), - // For non split note, psi_nf is equal to psi_old - psi_nf: Value::known(psi_old), alpha: Value::known(alpha), ak: Value::known(ak), nk: Value::known(nk), @@ -926,8 +941,12 @@ mod tests { psi_new: Value::known(output_note.rseed().psi(&output_note.rho())), rcm_new: Value::known(output_note.rseed().rcm(&output_note.rho())), rcv: Value::known(rcv), - asset: Value::known(spent_note.asset()), - split_flag: Value::known(false), + + additional_zsa_witnesses: Value::known(AdditionalZsaWitnesses { + psi_nf: psi_old, + asset: spent_note.asset(), + split_flag: false, + }), }, phantom: core::marker::PhantomData, }, @@ -1106,7 +1125,7 @@ mod tests { .titled("Orchard Action Circuit", ("sans-serif", 60)) .unwrap(); - let circuit = OrchardCircuitZSA { + let circuit = Circuit:: { witnesses: Witnesses::default(), phantom: core::marker::PhantomData, }; @@ -1118,7 +1137,7 @@ mod tests { } fn check_proof_of_orchard_circuit( - circuit: &OrchardCircuitZSA, + circuit: &Circuit, instance: &Instance, should_pass: bool, ) { @@ -1144,7 +1163,7 @@ mod tests { is_native_asset: bool, split_flag: bool, mut rng: R, - ) -> (OrchardCircuitZSA, Instance) { + ) -> (Circuit, Instance) { // Create asset let asset_base = if is_native_asset { AssetBase::native() @@ -1224,8 +1243,8 @@ mod tests { }; ( - OrchardCircuitZSA { - witnesses: Witnesses::from_action_context_unchecked( + Circuit { + witnesses: Witnesses::from_action_context_unchecked::( spend_info, output_note, alpha, @@ -1302,7 +1321,7 @@ mod tests { // Set cm_old to be a random NoteCommitment // The proof should fail - let circuit_wrong_cm_old = OrchardCircuitZSA { + let circuit_wrong_cm_old = Circuit { witnesses: Witnesses { path: circuit.witnesses.path, pos: circuit.witnesses.pos, @@ -1313,7 +1332,6 @@ mod tests { psi_old: circuit.witnesses.psi_old, rcm_old: circuit.witnesses.rcm_old.clone(), cm_old: Value::known(random_note_commitment(&mut rng)), - psi_nf: circuit.witnesses.psi_nf, alpha: circuit.witnesses.alpha, ak: circuit.witnesses.ak.clone(), nk: circuit.witnesses.nk, @@ -1324,8 +1342,11 @@ mod tests { psi_new: circuit.witnesses.psi_new, rcm_new: circuit.witnesses.rcm_new.clone(), rcv: circuit.witnesses.rcv, - asset: circuit.witnesses.asset, - split_flag: circuit.witnesses.split_flag, + + additional_zsa_witnesses: circuit + .witnesses + .additional_zsa_witnesses + .clone(), }, phantom: core::marker::PhantomData, }; @@ -1362,7 +1383,7 @@ mod tests { // If split_flag = 0 , set psi_nf to be a random Pallas base element // The proof should fail if !split_flag { - let circuit_wrong_psi_nf = OrchardCircuitZSA { + let circuit_wrong_psi_nf = Circuit { witnesses: Witnesses { path: circuit.witnesses.path, pos: circuit.witnesses.pos, @@ -1373,7 +1394,6 @@ mod tests { psi_old: circuit.witnesses.psi_old, rcm_old: circuit.witnesses.rcm_old.clone(), cm_old: circuit.witnesses.cm_old.clone(), - psi_nf: Value::known(pallas::Base::random(&mut rng)), alpha: circuit.witnesses.alpha, ak: circuit.witnesses.ak.clone(), nk: circuit.witnesses.nk, @@ -1384,8 +1404,15 @@ mod tests { psi_new: circuit.witnesses.psi_new, rcm_new: circuit.witnesses.rcm_new.clone(), rcv: circuit.witnesses.rcv, - asset: circuit.witnesses.asset, - split_flag: circuit.witnesses.split_flag, + + additional_zsa_witnesses: circuit + .witnesses + .additional_zsa_witnesses + .clone() + .map(|zsa_values| AdditionalZsaWitnesses { + psi_nf: pallas::Base::random(&mut rng), + ..zsa_values + }), }, phantom: core::marker::PhantomData, }; diff --git a/src/circuit/derive_nullifier.rs b/src/circuit/derive_nullifier.rs index f2f65517a..10f3d269d 100644 --- a/src/circuit/derive_nullifier.rs +++ b/src/circuit/derive_nullifier.rs @@ -40,7 +40,7 @@ pub(in crate::circuit) mod gadgets { Var = AssignedCell, >, >( - layouter: &mut impl Layouter, + mut layouter: impl Layouter, poseidon_chip: PoseidonChip, add_chip: AddChip, ecc_chip: EccChip, diff --git a/src/circuit/gadget.rs b/src/circuit/gadget.rs index 2675fef13..23fcebf73 100644 --- a/src/circuit/gadget.rs +++ b/src/circuit/gadget.rs @@ -1,38 +1,26 @@ //! Common gadgets and functions used in the Orchard circuit. use ff::Field; -use halo2_gadgets::{ - ecc::chip::EccChip, - poseidon::Pow5Chip as PoseidonChip, - sinsemilla::{chip::SinsemillaChip, merkle::chip::MerkleChip}, - utilities::{cond_swap::CondSwapChip, lookup_range_check::PallasLookupRangeCheck}, -}; use pasta_curves::pallas; +use super::{commit_ivk::CommitIvkChip, note_commit::NoteCommitChip, Config}; use crate::{ - circuit::{commit_ivk::CommitIvkChip, note_commit::NoteCommitChip, Config}, constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains}, note::AssetBase, }; +use halo2_gadgets::{ + ecc::chip::EccChip, + poseidon::Pow5Chip as PoseidonChip, + sinsemilla::{chip::SinsemillaChip, merkle::chip::MerkleChip}, + utilities::{cond_swap::CondSwapChip, lookup_range_check::PallasLookupRangeCheck}, +}; use halo2_proofs::{ - circuit::Value, - circuit::{AssignedCell, Chip, Layouter}, + circuit::{AssignedCell, Chip, Layouter, Value}, plonk::{self, Advice, Assigned, Column}, }; pub(in crate::circuit) mod add_chip; -/// An instruction set for adding two circuit words (field elements). -pub(in crate::circuit) trait AddInstruction: Chip { - /// Constraints `a + b` and returns the sum. - fn add( - &self, - layouter: impl Layouter, - a: &AssignedCell, - b: &AssignedCell, - ) -> Result, plonk::Error>; -} - impl Config { pub(super) fn add_chip(&self) -> add_chip::AddChip { add_chip::AddChip::construct(self.add_config.clone()) @@ -87,6 +75,17 @@ impl Config { } } +/// An instruction set for adding two circuit words (field elements). +pub(in crate::circuit) trait AddInstruction: Chip { + /// Constraints `a + b` and returns the sum. + fn add( + &self, + layouter: impl Layouter, + a: &AssignedCell, + b: &AssignedCell, + ) -> Result, plonk::Error>; +} + /// Witnesses the given value in a standalone region. /// /// Usages of this helper are technically superfluous, as the single-cell region is only diff --git a/src/circuit/gadget/add_chip.rs b/src/circuit/gadget/add_chip.rs index 9c0fb5dad..41b90b1f1 100644 --- a/src/circuit/gadget/add_chip.rs +++ b/src/circuit/gadget/add_chip.rs @@ -1,4 +1,4 @@ -//! 'Add' chip implemetation. +//! `Add` chip implemetation. use halo2_proofs::{ circuit::{AssignedCell, Chip, Layouter}, diff --git a/src/circuit/note_commit.rs b/src/circuit/note_commit.rs index 945840207..2c437f197 100644 --- a/src/circuit/note_commit.rs +++ b/src/circuit/note_commit.rs @@ -1,11 +1,19 @@ //! Note commitment logic for the Orchard circuit. +use core::iter; + +use group::ff::PrimeField; +use halo2_proofs::{ + circuit::{AssignedCell, Chip, Layouter, Value}, + plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, + poly::Rotation, +}; +use pasta_curves::pallas; + use crate::{ constants::{OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, T_P}, value::NoteValue, }; -use core::iter; -use group::ff::PrimeField; use halo2_gadgets::{ ecc::{ chip::{EccChip, NonIdentityEccPoint}, @@ -20,12 +28,6 @@ use halo2_gadgets::{ FieldValue, RangeConstrained, }, }; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use pasta_curves::pallas; type NoteCommitPiece = MessagePiece< pallas::Affine, @@ -1755,7 +1757,7 @@ pub struct NoteCommitConfigForZsaCircuit { #[derive(Clone, Debug)] pub struct NoteCommitChip { - pub config: NoteCommitConfig, + config: NoteCommitConfig, } impl NoteCommitChip { @@ -2047,7 +2049,6 @@ pub(in crate::circuit) mod gadgets { g_d.y(), b_2, )?; - // Check decomposition of `y(pk_d)`. let d_1 = y_canonicity( &lookup_config, @@ -2611,9 +2612,10 @@ mod tests { use core::iter; use crate::{ - circuit::gadget::{assign_free_advice, assign_is_native_asset}, - circuit::note_commit::gadgets, - circuit::note_commit::{NoteCommitChip, NoteCommitConfig}, + circuit::{ + gadget::{assign_free_advice, assign_is_native_asset}, + note_commit::{gadgets, NoteCommitChip, NoteCommitConfig, ZsaNoteCommitParams}, + }, constants::{ fixed_bases::NOTE_COMMITMENT_PERSONALIZATION, OrchardCommitDomains, OrchardFixedBases, OrchardHashDomains, L_ORCHARD_BASE, L_VALUE, T_Q, @@ -2645,7 +2647,6 @@ mod tests { }; use pasta_curves::{arithmetic::CurveAffine, pallas, EpAffine}; - use crate::circuit::note_commit::ZsaNoteCommitParams; use rand::{rngs::OsRng, RngCore}; #[test] @@ -2746,10 +2747,10 @@ mod tests { // Load the Sinsemilla generator lookup table used by the whole circuit. SinsemillaChip::< - OrchardHashDomains, - OrchardCommitDomains, - OrchardFixedBases, - >::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?; + OrchardHashDomains, + OrchardCommitDomains, + OrchardFixedBases, + >::load(note_commit_config.sinsemilla_config.clone(), &mut layouter)?; // Construct a Sinsemilla chip let sinsemilla_chip = diff --git a/src/orchard_flavor.rs b/src/orchard_flavor.rs index a2c646d36..f0459abf0 100644 --- a/src/orchard_flavor.rs +++ b/src/orchard_flavor.rs @@ -11,30 +11,12 @@ pub struct OrchardVanilla; #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct OrchardZSA; -/// Represents the flavor of the Orchard protocol. -/// -/// This enables conditional execution during runtime based on the flavor of the Orchard protocol. -#[derive(Clone, Debug)] -pub enum Flavor { - /// The "Vanilla" flavor of the Orchard protocol. - OrchardVanillaFlavor, - /// The "ZSA" flavor of the Orchard protocol. - OrchardZSAFlavor, -} - /// A trait binding the common functionality between different Orchard protocol flavors. #[cfg(feature = "circuit")] -pub trait OrchardFlavor: OrchardDomainCommon + OrchardCircuit { - /// Flavor of the Orchard protocol. - const FLAVOR: Flavor; -} +pub trait OrchardFlavor: OrchardDomainCommon + OrchardCircuit {} #[cfg(feature = "circuit")] -impl OrchardFlavor for OrchardVanilla { - const FLAVOR: Flavor = Flavor::OrchardVanillaFlavor; -} +impl OrchardFlavor for OrchardVanilla {} #[cfg(feature = "circuit")] -impl OrchardFlavor for OrchardZSA { - const FLAVOR: Flavor = Flavor::OrchardZSAFlavor; -} +impl OrchardFlavor for OrchardZSA {} diff --git a/src/pczt/prover.rs b/src/pczt/prover.rs index e89fd1199..a11f7b035 100644 --- a/src/pczt/prover.rs +++ b/src/pczt/prover.rs @@ -86,7 +86,7 @@ impl super::Bundle { .ok_or(ProverError::MissingSpendAuthRandomizer)?; let rcv = action.rcv.ok_or(ProverError::MissingValueCommitTrapdoor)?; - Witnesses::from_action_context(spend, output_note, alpha, rcv) + Witnesses::from_action_context::(spend, output_note, alpha, rcv) .ok_or(ProverError::RhoMismatch) .map(|witnesses| Circuit:: { witnesses,