From ff2ac96b247f5879b15ebbf09d0bd8fb36a69770 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Thu, 29 Jun 2023 13:03:27 +0200 Subject: [PATCH 01/18] Circuit: Add constraints (#77) Add the constraint: (split_flag=1) => (is_native_asset=0) Replace the constraint: (v_old=0) or (root=anchor) by the constraint: (v_old=0 and split_flag=0) or (root=anchor) Limit the version of half (< 2.3) because recent half versions required at least rust version 1.70. --- Cargo.toml | 1 + src/circuit.rs | 79 +++++++++++++++++++------- src/circuit_description | 96 +++++++++++++++++++++++++++++--- src/circuit_proof_test_case.bin | Bin 5250 -> 5250 bytes 4 files changed, 149 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0e7f64ea6..3ad6adfb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ plotters = { version = "0.3.0", optional = true } [dev-dependencies] bridgetree = "0.3" +half = ">= 1.8, < 2.3" criterion = "0.3" halo2_gadgets = { git = "https://github.com/QED-it/halo2", branch = "zsa1", features = ["test-dependencies"] } hex = "0.4" diff --git a/src/circuit.rs b/src/circuit.rs index 99a35b1d9..a8164c7bc 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -224,12 +224,13 @@ impl plonk::Circuit for Circuit { // Constrain split_flag to be boolean // Constrain v_old * (1 - split_flag) - v_new = magnitude * sign (https://p.z.cash/ZKS:action-cv-net-integrity?partial). - // Constrain v_old = 0 or calculated root = anchor (https://p.z.cash/ZKS:action-merkle-path-validity?partial). + // Constrain (v_old = 0 and split_flag = 0) or (calculated root = anchor) (https://p.z.cash/ZKS:action-merkle-path-validity?partial). // Constrain v_old = 0 or enable_spends = 1 (https://p.z.cash/ZKS:action-enable-spend). // Constrain v_new = 0 or enable_outputs = 1 (https://p.z.cash/ZKS:action-enable-output). // Constrain is_native_asset to be boolean // Constraint if is_native_asset = 1 then asset = native_asset else asset != native_asset // Constraint if split_flag = 0 then psi_old = psi_nf + // Constraint if split_flag = 1, then is_native_asset = 0 let q_orchard = meta.selector(); meta.create_gate("Orchard circuit checks", |meta| { let q_orchard = meta.query_selector(q_orchard); @@ -276,9 +277,13 @@ impl plonk::Circuit for Circuit { - v_new.clone() - magnitude * sign, ), + // We already checked that + // * split_flag is boolean (just above), and + // * v_old is a 64 bit integer (in the note commitment evaluation). + // So, split_flag + v_old = 0 only when (split_flag = 0 and v_old = 0), no overflow can occur. ( - "v_old = 0 or root = anchor", - v_old.clone() * (root - anchor), + "(v_old = 0 and split_flag = 0) or (root = anchor)", + (v_old.clone() + split_flag.clone()) * (root - anchor), ), ( "v_old = 0 or enable_spends = 1", @@ -307,13 +312,17 @@ impl plonk::Circuit for Circuit { // is not equal to zero, we will prove that it is invertible. ( "(is_native_asset = 0) => (asset != native_asset)", - (one.clone() - is_native_asset) + (one.clone() - is_native_asset.clone()) * (diff_asset_x * diff_asset_x_inv - one.clone()) * (diff_asset_y * diff_asset_y_inv - one.clone()), ), ( "(split_flag = 0) => (psi_old = psi_nf)", - (one - split_flag) * (psi_old - psi_nf), + (one - split_flag.clone()) * (psi_old - psi_nf), + ), + ( + "(split_flag = 1) => (is_native_asset = 0)", + split_flag * is_native_asset, ), ], ) @@ -1550,9 +1559,11 @@ mod tests { let (circuit, instance) = generate_circuit_instance(is_native_asset, split_flag, &mut rng); - check_proof_of_orchard_circuit(&circuit, &instance, true); + let should_pass = !(matches!((is_native_asset, split_flag), (true, true))); + + check_proof_of_orchard_circuit(&circuit, &instance, should_pass); - // Set cv_net to zero + // Set cv_net to be zero // The proof should fail let instance_wrong_cv_net = Instance { anchor: instance.anchor, @@ -1565,7 +1576,7 @@ mod tests { }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_cv_net, false); - // Set rk_pub to dummy VerificationKey + // Set rk_pub to be a dummy VerificationKey // The proof should fail let instance_wrong_rk = Instance { anchor: instance.anchor, @@ -1578,7 +1589,7 @@ mod tests { }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_rk, false); - // Set cm_old to random NoteCommitment + // Set cm_old to be a random NoteCommitment // The proof should fail let circuit_wrong_cm_old = Circuit { path: circuit.path, @@ -1606,7 +1617,7 @@ mod tests { }; check_proof_of_orchard_circuit(&circuit_wrong_cm_old, &instance, false); - // Set cmx_pub to random NoteCommitment + // Set cmx_pub to be a random NoteCommitment // The proof should fail let instance_wrong_cmx_pub = Instance { anchor: instance.anchor, @@ -1619,19 +1630,47 @@ mod tests { }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_cmx_pub, false); - // If split_flag=0, set nf_old_pub to random Nullifier + // Set nf_old_pub to be a random Nullifier + // The proof should fail + let instance_wrong_nf_old_pub = Instance { + anchor: instance.anchor, + cv_net: instance.cv_net.clone(), + nf_old: Nullifier::dummy(&mut rng), + rk: instance.rk.clone(), + cmx: instance.cmx, + enable_spend: instance.enable_spend, + enable_output: instance.enable_output, + }; + check_proof_of_orchard_circuit(&circuit, &instance_wrong_nf_old_pub, false); + + // If split_flag = 0 , set psi_nf to be a random Pallas base element // The proof should fail if !split_flag { - let instance_wrong_nf_old_pub = Instance { - anchor: instance.anchor, - cv_net: instance.cv_net, - nf_old: Nullifier::dummy(&mut rng), - rk: instance.rk, - cmx: instance.cmx, - enable_spend: instance.enable_spend, - enable_output: instance.enable_output, + let circuit_wrong_psi_nf = Circuit { + path: circuit.path, + pos: circuit.pos, + g_d_old: circuit.g_d_old, + pk_d_old: circuit.pk_d_old, + v_old: circuit.v_old, + rho_old: circuit.rho_old, + psi_old: circuit.psi_old, + rcm_old: circuit.rcm_old.clone(), + cm_old: circuit.cm_old.clone(), + psi_nf: Value::known(pallas::Base::random(&mut rng)), + alpha: circuit.alpha, + ak: circuit.ak.clone(), + nk: circuit.nk, + rivk: circuit.rivk, + g_d_new: circuit.g_d_new, + pk_d_new: circuit.pk_d_new, + v_new: circuit.v_new, + psi_new: circuit.psi_new, + rcm_new: circuit.rcm_new.clone(), + rcv: circuit.rcv, + asset: circuit.asset, + split_flag: circuit.split_flag, }; - check_proof_of_orchard_circuit(&circuit, &instance_wrong_nf_old_pub, false); + check_proof_of_orchard_circuit(&circuit_wrong_psi_nf, &instance, false); } } } diff --git a/src/circuit_description b/src/circuit_description index 8078e15f1..863c4e1e2 100644 --- a/src/circuit_description +++ b/src/circuit_description @@ -260,13 +260,22 @@ PinnedVerificationKey { ), ), Product( - Advice { - query_index: 0, - column_index: 0, - rotation: Rotation( - 0, - ), - }, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + ), Sum( Advice { query_index: 4, @@ -913,6 +922,79 @@ PinnedVerificationKey { ), ), ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Advice { + query_index: 8, + column_index: 8, + rotation: Rotation( + 0, + ), + }, + Advice { + query_index: 9, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), Product( Product( Product( diff --git a/src/circuit_proof_test_case.bin b/src/circuit_proof_test_case.bin index 695d163d99d1571649c59a9557e1362a49f391a5..5a8711554131107aeac547f3b033c40a9fc21d75 100644 GIT binary patch literal 5250 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 IeX+H@0}cNf+yDRo literal 5250 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 IYufqsJ*i3!z5oCK From 9067ca203dfd6ef316db405687bcf118704a47ae Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Mon, 24 Jul 2023 10:58:45 +0200 Subject: [PATCH 02/18] Validate burn of the Orchard bundles in BatchValidator --- Cargo.toml | 3 +- src/bundle.rs | 1 + src/bundle/batch.rs | 22 ++++- src/bundle/burn_validation.rs | 146 ++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 src/bundle/burn_validation.rs diff --git a/Cargo.toml b/Cargo.toml index 828085335..5910cd189 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,12 +37,13 @@ memuse = { version = "0.2.1", features = ["nonempty"] } pasta_curves = "0.5" proptest = { version = "1.0.0", optional = true } rand = "0.8" -reddsa = "0.5" +reddsa = "=0.5.0" nonempty = "0.7" serde = { version = "1.0", features = ["derive"] } subtle = "2.3" zcash_note_encryption = "0.4" incrementalmerkletree = "0.4" +dashmap = "=5.4.0" # Logging tracing = "0.1" diff --git a/src/bundle.rs b/src/bundle.rs index 2e5d5a034..29adad9c5 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -1,6 +1,7 @@ //! Structs related to bundles of Orchard actions. mod batch; +pub mod burn_validation; pub mod commitments; pub use batch::BatchValidator; diff --git a/src/bundle/batch.rs b/src/bundle/batch.rs index c60d0cd55..51ffcbfae 100644 --- a/src/bundle/batch.rs +++ b/src/bundle/batch.rs @@ -3,9 +3,10 @@ use pasta_curves::vesta; use rand::{CryptoRng, RngCore}; use tracing::debug; -use super::{Authorized, Bundle}; +use super::{burn_validation::validate_bundle_burn, Authorized, Bundle}; use crate::{ circuit::VerifyingKey, + note::AssetBase, primitives::redpallas::{self, Binding, SpendAuth}, }; @@ -23,6 +24,7 @@ struct BundleSignature { pub struct BatchValidator { proofs: plonk::BatchVerifier, signatures: Vec, + burns: Vec<(AssetBase, i64)>, } impl BatchValidator { @@ -31,10 +33,11 @@ impl BatchValidator { BatchValidator { proofs: plonk::BatchVerifier::new(), signatures: vec![], + burns: vec![], } } - /// Adds the proof and RedPallas signatures from the given bundle to the validator. + /// Adds the proof, RedPallas signatures and burn from the given bundle to the validator. pub fn add_bundle>( &mut self, bundle: &Bundle, @@ -58,6 +61,13 @@ impl BatchValidator { .authorization() .proof() .add_to_batch(&mut self.proofs, bundle.to_instances()); + + self.burns.extend( + bundle + .burn + .iter() + .map(|(asset, amount)| (*asset, (*amount).into())), + ); } /// Batch-validates the accumulated bundles. @@ -79,13 +89,19 @@ impl BatchValidator { validator.queue(sig.signature.clone()); } - match validator.verify(rng) { + let are_signatures_and_proofs_valid = match validator.verify(rng) { // If signatures are valid, check the proofs. Ok(()) => self.proofs.finalize(&vk.params, &vk.vk), Err(e) => { debug!("RedPallas batch validation failed: {}", e); false } + }; + + if !are_signatures_and_proofs_valid { + return false; } + + validate_bundle_burn(&self.burns).is_ok() } } diff --git a/src/bundle/burn_validation.rs b/src/bundle/burn_validation.rs new file mode 100644 index 000000000..d2b0c68d3 --- /dev/null +++ b/src/bundle/burn_validation.rs @@ -0,0 +1,146 @@ +//! Validating burn operations on asset bundles. +//! +//! The module provides a function `validate_bundle_burn` that can be used to validate a burn for a bundle. +//! +use std::fmt; + +use crate::note::AssetBase; + +/// Possible errors that can occur during bundle burn validation. +#[derive(Debug)] +#[cfg_attr(test, derive(PartialEq, Eq))] +pub enum BurnError { + /// Encountered a duplicate asset to burn. + DuplicateAsset, + /// Cannot burn a native asset. + NativeAsset, + /// Cannot burn an asset with a nonpositive amount. + NonPositiveAmount, +} + +impl fmt::Display for BurnError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + BurnError::DuplicateAsset => write!(f, "Encountered a duplicate asset to burn."), + BurnError::NativeAsset => write!(f, "Cannot burn a native asset."), + BurnError::NonPositiveAmount => { + write!(f, "Cannot burn an asset with a nonpositive amount.") + } + } + } +} + +/// Validates burn for a bundle by ensuring each asset is unique, non-native, and has a positive value. +/// +/// Each burn element is represented as a tuple of `AssetBase` and `i64` (amount for the burn). +/// +/// # Arguments +/// +/// * `burn` - A vector of assets, where each asset is represented as a tuple of `AssetBase` and `i64` (amount the burn). +/// +/// # Errors +/// +/// Returns a `BurnError` if: +/// * Any asset in the `burn` vector is not unique (`BurnError::DuplicateAsset`). +/// * Any asset in the `burn` vector is native (`BurnError::NativeAsset`). +/// * Any asset in the `burn` vector has a nonpositive amount (`BurnError::NonPositiveAmount`). +pub fn validate_bundle_burn(bundle_burn: &Vec<(AssetBase, i64)>) -> Result<(), BurnError> { + let mut asset_set = std::collections::HashSet::::new(); + + for (asset, amount) in bundle_burn { + if !asset_set.insert(*asset) { + return Err(BurnError::DuplicateAsset); + } + if asset.is_native().into() { + return Err(BurnError::NativeAsset); + } + if *amount <= 0 { + return Err(BurnError::NonPositiveAmount); + } + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Creates an item of bundle burn list for a given asset description and amount. + /// + /// This function is deterministic and guarantees that each call with the same parameters + /// will return the same result. It achieves determinism by using a static `IssuanceKey`. + /// + /// # Arguments + /// + /// * `asset_desc` - The asset description string. + /// * `amount` - The amount for the burn. + /// + /// # Returns + /// + /// A tuple `(AssetBase, Amount)` representing the burn list item. + /// + pub fn get_burn_tuple(asset_desc: &str, amount: i64) -> (AssetBase, i64) { + use crate::keys::{IssuanceAuthorizingKey, IssuanceKey, IssuanceValidatingKey}; + + let sk_iss = IssuanceKey::from_bytes([0u8; 32]).unwrap(); + let isk: IssuanceAuthorizingKey = (&sk_iss).into(); + + ( + AssetBase::derive(&IssuanceValidatingKey::from(&isk), asset_desc), + amount, + ) + } + + #[test] + fn validate_bundle_burn_success() { + let bundle_burn = vec![ + get_burn_tuple("Asset 1", 10), + get_burn_tuple("Asset 2", 20), + get_burn_tuple("Asset 3", 10), + ]; + + let result = validate_bundle_burn(&bundle_burn); + + assert!(result.is_ok()); + } + + #[test] + fn validate_bundle_burn_duplicate_asset() { + let bundle_burn = vec![ + get_burn_tuple("Asset 1", 10), + get_burn_tuple("Asset 1", 20), + get_burn_tuple("Asset 3", 10), + ]; + + let result = validate_bundle_burn(&bundle_burn); + + assert_eq!(result, Err(BurnError::DuplicateAsset)); + } + + #[test] + fn validate_bundle_burn_native_asset() { + let bundle_burn = vec![ + get_burn_tuple("Asset 1", 10), + (AssetBase::native(), 20), + get_burn_tuple("Asset 3", 10), + ]; + + let result = validate_bundle_burn(&bundle_burn); + + assert_eq!(result, Err(BurnError::NativeAsset)); + } + + #[test] + fn validate_bundle_burn_zero_amount() { + let bundle_burn = vec![ + get_burn_tuple("Asset 1", 10), + get_burn_tuple("Asset 2", 0), + get_burn_tuple("Asset 3", 10), + ]; + + let result = validate_bundle_burn(&bundle_burn); + + assert_eq!(result, Err(BurnError::NonPositiveAmount)); + } +} From 081513b3635e1bbec9de2424a3069898a23362ca Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Mon, 24 Jul 2023 16:53:10 +0200 Subject: [PATCH 03/18] Circuit: Fix balance violation (#78) To prevent balance violations, we have replaced the constraint "(v_old = 0 and split_flag = 0) or (root = anchor)" with the constraint "(v_old = 0 and is_native_asset = 1) or (root = anchor)". Previously, an adversary could use a zero-valued ZSA note to violate balance by setting v_old=0, v_new!=0, is_native_asset=0, split_flag=0. Limit the version of dashmap (< 5.5) because recent dashmap versions required rust version 1.64 or newer Limit the version of hashbrown (<0.13) because recent hashbrown versions required rust version 1.64 or newer --- Cargo.toml | 2 ++ src/circuit.rs | 12 ++++++------ src/circuit_description | 33 +++++++++++++++++++------------- src/circuit_proof_test_case.bin | Bin 5250 -> 5250 bytes 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ad6adfb9..a0929100c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,8 @@ zcash_note_encryption = { version = "0.4", features = ["pre-zip-212"] } incrementalmerkletree = { version = "0.4", features = ["test-dependencies"] } [target.'cfg(unix)'.dev-dependencies] +hashbrown = ">= 0.12, <0.13" +dashmap = ">= 5.4, <5.5" inferno = ">= 0.11, < 0.11.15" pprof = { version = "0.9", features = ["criterion", "flamegraph"] } # MSRV 1.56 diff --git a/src/circuit.rs b/src/circuit.rs index a8164c7bc..9d550e5d2 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -224,7 +224,7 @@ impl plonk::Circuit for Circuit { // Constrain split_flag to be boolean // Constrain v_old * (1 - split_flag) - v_new = magnitude * sign (https://p.z.cash/ZKS:action-cv-net-integrity?partial). - // Constrain (v_old = 0 and split_flag = 0) or (calculated root = anchor) (https://p.z.cash/ZKS:action-merkle-path-validity?partial). + // Constrain (v_old = 0 and is_native_asset = 1) or (calculated root = anchor) (https://p.z.cash/ZKS:action-merkle-path-validity?partial). // Constrain v_old = 0 or enable_spends = 1 (https://p.z.cash/ZKS:action-enable-spend). // Constrain v_new = 0 or enable_outputs = 1 (https://p.z.cash/ZKS:action-enable-output). // Constrain is_native_asset to be boolean @@ -278,12 +278,12 @@ impl plonk::Circuit for Circuit { - magnitude * sign, ), // We already checked that - // * split_flag is boolean (just above), and - // * v_old is a 64 bit integer (in the note commitment evaluation). - // So, split_flag + v_old = 0 only when (split_flag = 0 and v_old = 0), no overflow can occur. + // * is_native_asset is boolean (just below), and + // * v_old is a 64 bit unsigned integer (in the note commitment evaluation). + // So, 1 - is_native_asset + v_old = 0 only when (is_native_asset = 1 and v_old = 0), no overflow can occur. ( - "(v_old = 0 and split_flag = 0) or (root = anchor)", - (v_old.clone() + split_flag.clone()) * (root - anchor), + "(v_old = 0 and is_native_asset = 1) or (root = anchor)", + (v_old.clone() + one.clone() - is_native_asset.clone()) * (root - anchor), ), ( "v_old = 0 or enable_spends = 1", diff --git a/src/circuit_description b/src/circuit_description index 863c4e1e2..7a9d35f07 100644 --- a/src/circuit_description +++ b/src/circuit_description @@ -261,20 +261,27 @@ PinnedVerificationKey { ), Product( Sum( - Advice { - query_index: 0, - column_index: 0, - rotation: Rotation( - 0, - ), - }, - Advice { - query_index: 8, - column_index: 8, - rotation: Rotation( - 0, + Sum( + Advice { + query_index: 0, + column_index: 0, + rotation: Rotation( + 0, + ), + }, + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, ), - }, + ), + Negated( + Advice { + query_index: 9, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), ), Sum( Advice { diff --git a/src/circuit_proof_test_case.bin b/src/circuit_proof_test_case.bin index 5a8711554131107aeac547f3b033c40a9fc21d75..9005e06bc0beb164cc041c00bd0ac8707ebe8da9 100644 GIT binary patch literal 5250 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 I+uWQkC`hXiNdN!< literal 5250 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 IeX+H@0}cNf+yDRo From 5a16d932e3300d992ab2b850836d52dca3141073 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Mon, 21 Aug 2023 10:52:57 +0200 Subject: [PATCH 04/18] Fix reference to zcash_note_encryption in Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5910cd189..df235ad07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,4 +93,4 @@ debug = true debug = true [patch.crates-io] -zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization" } +zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } From 2f0f10ab8e8a4a081cda061a700998386e210c1b Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Mon, 21 Aug 2023 11:00:43 +0200 Subject: [PATCH 05/18] Minor refinements in burn_validation.rs --- src/bundle/burn_validation.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bundle/burn_validation.rs b/src/bundle/burn_validation.rs index d2b0c68d3..1b1c254f1 100644 --- a/src/bundle/burn_validation.rs +++ b/src/bundle/burn_validation.rs @@ -14,7 +14,7 @@ pub enum BurnError { DuplicateAsset, /// Cannot burn a native asset. NativeAsset, - /// Cannot burn an asset with a nonpositive amount. + /// Cannot burn an asset with a nonpositive value. NonPositiveAmount, } @@ -24,7 +24,7 @@ impl fmt::Display for BurnError { BurnError::DuplicateAsset => write!(f, "Encountered a duplicate asset to burn."), BurnError::NativeAsset => write!(f, "Cannot burn a native asset."), BurnError::NonPositiveAmount => { - write!(f, "Cannot burn an asset with a nonpositive amount.") + write!(f, "Cannot burn an asset with a nonpositive value.") } } } @@ -32,29 +32,29 @@ impl fmt::Display for BurnError { /// Validates burn for a bundle by ensuring each asset is unique, non-native, and has a positive value. /// -/// Each burn element is represented as a tuple of `AssetBase` and `i64` (amount for the burn). +/// Each burn element is represented as a tuple of `AssetBase` and `i64` (value for the burn). /// /// # Arguments /// -/// * `burn` - A vector of assets, where each asset is represented as a tuple of `AssetBase` and `i64` (amount the burn). +/// * `burn` - A vector of assets, where each asset is represented as a tuple of `AssetBase` and `i64` (value the burn). /// /// # Errors /// /// Returns a `BurnError` if: /// * Any asset in the `burn` vector is not unique (`BurnError::DuplicateAsset`). /// * Any asset in the `burn` vector is native (`BurnError::NativeAsset`). -/// * Any asset in the `burn` vector has a nonpositive amount (`BurnError::NonPositiveAmount`). +/// * Any asset in the `burn` vector has a nonpositive value (`BurnError::NonPositiveAmount`). pub fn validate_bundle_burn(bundle_burn: &Vec<(AssetBase, i64)>) -> Result<(), BurnError> { - let mut asset_set = std::collections::HashSet::::new(); + let mut asset_set = std::collections::HashSet::<&AssetBase>::new(); - for (asset, amount) in bundle_burn { - if !asset_set.insert(*asset) { + for (asset, value) in bundle_burn { + if !asset_set.insert(asset) { return Err(BurnError::DuplicateAsset); } if asset.is_native().into() { return Err(BurnError::NativeAsset); } - if *amount <= 0 { + if *value <= 0 { return Err(BurnError::NonPositiveAmount); } } @@ -66,7 +66,7 @@ pub fn validate_bundle_burn(bundle_burn: &Vec<(AssetBase, i64)>) -> Result<(), B mod tests { use super::*; - /// Creates an item of bundle burn list for a given asset description and amount. + /// Creates an item of bundle burn list for a given asset description and value. /// /// This function is deterministic and guarantees that each call with the same parameters /// will return the same result. It achieves determinism by using a static `IssuanceKey`. @@ -74,13 +74,13 @@ mod tests { /// # Arguments /// /// * `asset_desc` - The asset description string. - /// * `amount` - The amount for the burn. + /// * `value` - The value for the burn. /// /// # Returns /// /// A tuple `(AssetBase, Amount)` representing the burn list item. /// - pub fn get_burn_tuple(asset_desc: &str, amount: i64) -> (AssetBase, i64) { + pub fn get_burn_tuple(asset_desc: &str, value: i64) -> (AssetBase, i64) { use crate::keys::{IssuanceAuthorizingKey, IssuanceKey, IssuanceValidatingKey}; let sk_iss = IssuanceKey::from_bytes([0u8; 32]).unwrap(); @@ -88,7 +88,7 @@ mod tests { ( AssetBase::derive(&IssuanceValidatingKey::from(&isk), asset_desc), - amount, + value, ) } @@ -132,7 +132,7 @@ mod tests { } #[test] - fn validate_bundle_burn_zero_amount() { + fn validate_bundle_burn_zero_value() { let bundle_burn = vec![ get_burn_tuple("Asset 1", 10), get_burn_tuple("Asset 2", 0), From 9ef133181a927fdc0fa793da1d4338a046e57a7c Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Mon, 21 Aug 2023 11:02:26 +0200 Subject: [PATCH 06/18] Add call of validate_bundle_burn to Orchard bundle batch validator --- src/bundle/batch.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/bundle/batch.rs b/src/bundle/batch.rs index 51ffcbfae..290a4f836 100644 --- a/src/bundle/batch.rs +++ b/src/bundle/batch.rs @@ -77,6 +77,10 @@ impl BatchValidator { /// figure out which of the accumulated bundles might be invalid; if that information /// is desired, construct separate [`BatchValidator`]s for sub-batches of the bundles. pub fn validate(self, vk: &VerifyingKey, rng: R) -> bool { + if validate_bundle_burn(&self.burns).is_err() { + return false; + } + if self.signatures.is_empty() { // An empty batch is always valid, but is not free to run; skip it. // Note that a transaction has at least a binding signature, so if @@ -89,19 +93,13 @@ impl BatchValidator { validator.queue(sig.signature.clone()); } - let are_signatures_and_proofs_valid = match validator.verify(rng) { + match validator.verify(rng) { // If signatures are valid, check the proofs. Ok(()) => self.proofs.finalize(&vk.params, &vk.vk), Err(e) => { debug!("RedPallas batch validation failed: {}", e); false } - }; - - if !are_signatures_and_proofs_valid { - return false; } - - validate_bundle_burn(&self.burns).is_ok() } } From 5bc2dc4d1653c38bc753c794e596cfbcc00237dd Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Mon, 21 Aug 2023 11:03:08 +0200 Subject: [PATCH 07/18] Add BatchValidator for IssueBundle --- src/issuance.rs | 4 ++++ src/issuance/batch.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/issuance/batch.rs diff --git a/src/issuance.rs b/src/issuance.rs index 8eececbd0..e719ef231 100644 --- a/src/issuance.rs +++ b/src/issuance.rs @@ -26,6 +26,10 @@ use crate::{ use crate::supply_info::{AssetSupply, SupplyInfo}; +mod batch; + +pub use batch::BatchValidator; + /// A bundle of actions to be applied to the ledger. #[derive(Debug, Clone)] pub struct IssueBundle { diff --git a/src/issuance/batch.rs b/src/issuance/batch.rs new file mode 100644 index 000000000..41794f694 --- /dev/null +++ b/src/issuance/batch.rs @@ -0,0 +1,36 @@ +use std::collections::HashSet; + +use super::{verify_issue_bundle, AssetBase, IssueBundle, Signed}; + +/// Batch validation context for Issuance. +/// +#[derive(Debug, Default)] +pub struct BatchValidator { + bundles: Vec<(IssueBundle, [u8; 32])>, +} + +impl BatchValidator { + /// Constructs a new batch validation context. + pub fn new() -> Self { + BatchValidator { bundles: vec![] } + } + + /// Adds bundle to the validator. + pub fn add_bundle(&mut self, bundle: &IssueBundle, sighash: [u8; 32]) { + self.bundles.push((bundle.clone(), sighash)) + } + + /// Batch-validates the accumulated bundles. + /// + /// Returns `true` if every bundle added to the batch validator is valid, or `false` + /// if one or more are invalid. + pub fn validate(self) -> bool { + // FIXME: take/save finalization set from/to the global state + let finalized = HashSet::::new(); + + // FIXME: process resulting supply_info + self.bundles + .into_iter() + .all(|(bundle, sighash)| verify_issue_bundle(&bundle, sighash, &finalized).is_ok()) + } +} From 39582811544db25d89e1d347cce91ea1221291c0 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 11:54:33 +0200 Subject: [PATCH 08/18] Pin rustix dependency version to 0.37.20 as 0.38 requires Rust v1.63 --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index df235ad07..a2181f720 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ subtle = "2.3" zcash_note_encryption = "0.4" incrementalmerkletree = "0.4" dashmap = "=5.4.0" +rustix = "=0.37.20" # Logging tracing = "0.1" From 1342673c5029b7b387a645f3d6b79f1f988a4122 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 12:36:40 +0200 Subject: [PATCH 09/18] Pin tempfile dependency version to 3.6.0 as 3.8.0 requires Rust v1.63 --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a2181f720..2f950b85f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,8 @@ subtle = "2.3" zcash_note_encryption = "0.4" incrementalmerkletree = "0.4" dashmap = "=5.4.0" -rustix = "=0.37.20" +#rustix = "=0.37.20" +tempfile = "=3.6.0" # Logging tracing = "0.1" From 12497648870385afd3fe8d65fa544c9d6084d926 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 12:45:14 +0200 Subject: [PATCH 10/18] Pin backtrace dependency version to 0.3.67 as newer ones require Rust v1.63 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2f950b85f..7404df89b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,8 +44,8 @@ subtle = "2.3" zcash_note_encryption = "0.4" incrementalmerkletree = "0.4" dashmap = "=5.4.0" -#rustix = "=0.37.20" tempfile = "=3.6.0" +backtrace = "=0.3.67" # Logging tracing = "0.1" From 89776522c70f6fd98aaf350e136aca616375093b Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 12:52:20 +0200 Subject: [PATCH 11/18] Pin flate2 dependency version to 1.0.26 as newer ones require newer Rust version --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 7404df89b..17324e886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ incrementalmerkletree = "0.4" dashmap = "=5.4.0" tempfile = "=3.6.0" backtrace = "=0.3.67" +flate2 = "=1.0.26" # Logging tracing = "0.1" From e4a76d52bd715f5a65b6ba0aba6d5c33e075d9ab Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 13:11:33 +0200 Subject: [PATCH 12/18] Fix PartialOrd impl for VerificationKey id redpallas, to fix incorrect_partial_ord_impl_on_ord_type clippy error --- src/primitives/redpallas.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/primitives/redpallas.rs b/src/primitives/redpallas.rs index a414bf285..7690312a9 100644 --- a/src/primitives/redpallas.rs +++ b/src/primitives/redpallas.rs @@ -101,7 +101,7 @@ impl Eq for VerificationKey {} impl PartialOrd for VerificationKey { fn partial_cmp(&self, other: &Self) -> Option { - <[u8; 32]>::from(self).partial_cmp(&<[u8; 32]>::from(other)) + Some(self.cmp(other)) } } From 6ac8c65720ddcf4f774cb18a8bb11e5fe1fd9bd4 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 13:23:13 +0200 Subject: [PATCH 13/18] Sync Cargo.toml with PR #79 (except zcash_note_encryption) --- Cargo.toml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 17324e886..80ef101f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,28 +35,27 @@ hex = "0.4" lazy_static = "1" memuse = { version = "0.2.1", features = ["nonempty"] } pasta_curves = "0.5" +tempfile = "= 3.5.0" # Last version required rust 1.63 proptest = { version = "1.0.0", optional = true } rand = "0.8" -reddsa = "=0.5.0" +reddsa = "=0.5.0" # Last version required rust 1.65 nonempty = "0.7" serde = { version = "1.0", features = ["derive"] } subtle = "2.3" zcash_note_encryption = "0.4" incrementalmerkletree = "0.4" -dashmap = "=5.4.0" -tempfile = "=3.6.0" -backtrace = "=0.3.67" -flate2 = "=1.0.26" # Logging tracing = "0.1" # Developer tooling dependencies image = { version = ">= 0.24, < 0.24.5", optional = true } # 0.24.5 has MSRV 1.61 +flate2 = ">= 1.0, <1.0.27" # Clippy issues in last version plotters = { version = "0.3.0", optional = true } [dev-dependencies] bridgetree = "0.3" +half = ">= 1.8, < 2.3" criterion = "0.3" halo2_gadgets = { git = "https://github.com/QED-it/halo2", branch = "zsa1", features = ["test-dependencies"] } hex = "0.4" @@ -65,6 +64,8 @@ zcash_note_encryption = { version = "0.4", features = ["pre-zip-212"] } incrementalmerkletree = { version = "0.4", features = ["test-dependencies"] } [target.'cfg(unix)'.dev-dependencies] +hashbrown = ">= 0.12, <0.13" +dashmap = ">= 5.4, <5.5" inferno = ">= 0.11, < 0.11.15" pprof = { version = "0.9", features = ["criterion", "flamegraph"] } # MSRV 1.56 @@ -96,4 +97,4 @@ debug = true debug = true [patch.crates-io] -zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } +zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", tag = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } From 7a9e2dec351e7bcea960d47cdd7d849e46ad5cd4 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 14:23:17 +0200 Subject: [PATCH 14/18] Fix Cargo.toml for the previous commit --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 80ef101f3..0602b29bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,4 +97,5 @@ debug = true debug = true [patch.crates-io] -zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", tag = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } +zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } ++zcash_note_encryption = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } From a0278500bdabc89f454354c6be326e4bc835e8b2 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 14:28:19 +0200 Subject: [PATCH 15/18] Fix Cargo.toml for the previous commit 2 --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0602b29bd..0882a8d08 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,4 +98,3 @@ debug = true [patch.crates-io] zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } -+zcash_note_encryption = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } From 5cd3fa411fb0577c3f6588aa7c11cc3bf1b66d29 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 14:39:53 +0200 Subject: [PATCH 16/18] Pin backtrace dependency version to 0.3.67 as newer ones require Rust v1.65 --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 0882a8d08..3afdbe6aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ hashbrown = ">= 0.12, <0.13" dashmap = ">= 5.4, <5.5" inferno = ">= 0.11, < 0.11.15" pprof = { version = "0.9", features = ["criterion", "flamegraph"] } # MSRV 1.56 +backtrace = "=0.3.67" # Last version required rust 1.65 [lib] bench = false From c1a41a9f3bf2556e4d83cfb701372fd4838f42e6 Mon Sep 17 00:00:00 2001 From: Dmitry Demin Date: Wed, 23 Aug 2023 16:44:27 +0200 Subject: [PATCH 17/18] Fix Cargo.toml to use zcash_note_encryption (librustzcash) from zsa-bundle-in-v5-vector-serialization-with-burn-valid branch --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3afdbe6aa..fe5e841fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,4 +98,4 @@ debug = true debug = true [patch.crates-io] -zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization_with_burn_validation_new" } +zcash_note_encryption = { version = "0.4", git = "https://github.com/QED-it/librustzcash.git", branch = "zsa-bundle-in-v5-vector-serialization-with-burn-valid" } From 139ecca07939f5fec2c66a4cf452d8bd6765c8d6 Mon Sep 17 00:00:00 2001 From: Constance Beguier Date: Thu, 31 Aug 2023 09:23:44 +0200 Subject: [PATCH 18/18] Circuit: Add enable_zsa flag (#79) When enable_zsa flag is set to false, it is not possible to perform ZSA transactions (the circuit will fail). Fix the version of reddsa (=0.5.0) because recent versions required rust version 1.65 or newer Fix the version of tempfile (=3.5.0) because recent versions required rust version 1.63 or newer Limit the version of flate2 (<1.0.27) because recent versions raise some clippy issues --- Cargo.toml | 4 +- benches/circuit.rs | 2 +- benches/note_decryption.rs | 2 +- src/builder.rs | 4 +- src/bundle.rs | 28 +- src/circuit.rs | 70 ++++- src/circuit_description | 441 +++++++++++++++++++------------- src/circuit_proof_test_case.bin | Bin 5250 -> 5251 bytes tests/builder.rs | 4 +- tests/zsa.rs | 4 +- 10 files changed, 359 insertions(+), 200 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a0929100c..efcc06945 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,9 +35,10 @@ hex = "0.4" lazy_static = "1" memuse = { version = "0.2.1", features = ["nonempty"] } pasta_curves = "0.5" +tempfile = "= 3.5.0" # Last version required rust 1.63 proptest = { version = "1.0.0", optional = true } rand = "0.8" -reddsa = "0.5" +reddsa = "=0.5.0" # Last version required rust 1.65 nonempty = "0.7" serde = { version = "1.0", features = ["derive"] } subtle = "2.3" @@ -49,6 +50,7 @@ tracing = "0.1" # Developer tooling dependencies image = { version = ">= 0.24, < 0.24.5", optional = true } # 0.24.5 has MSRV 1.61 +flate2 = ">= 1.0, <1.0.27" # Clippy issues in last version plotters = { version = "0.3.0", optional = true } [dev-dependencies] diff --git a/benches/circuit.rs b/benches/circuit.rs index 03868a418..f26cc3507 100644 --- a/benches/circuit.rs +++ b/benches/circuit.rs @@ -28,7 +28,7 @@ fn criterion_benchmark(c: &mut Criterion) { let create_bundle = |num_recipients| { let mut builder = Builder::new( - Flags::from_parts(true, true), + Flags::from_parts(true, true, false), Anchor::from_bytes([0; 32]).unwrap(), ); for _ in 0..num_recipients { diff --git a/benches/note_decryption.rs b/benches/note_decryption.rs index 6bd6fa10f..ce051cf03 100644 --- a/benches/note_decryption.rs +++ b/benches/note_decryption.rs @@ -47,7 +47,7 @@ fn bench_note_decryption(c: &mut Criterion) { let bundle = { let mut builder = Builder::new( - Flags::from_parts(true, true), + Flags::from_parts(true, true, false), Anchor::from_bytes([0; 32]).unwrap(), ); // The builder pads to two actions, and shuffles their order. Add two recipients diff --git a/src/builder.rs b/src/builder.rs index 06b8a431a..bae73569b 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -947,7 +947,7 @@ pub mod testing { /// Create a bundle from the set of arbitrary bundle inputs. fn into_bundle + Copy + Into>(mut self) -> Bundle { let fvk = FullViewingKey::from(&self.sk); - let flags = Flags::from_parts(true, true); + let flags = Flags::from_parts(true, true, true); let mut builder = Builder::new(flags, self.anchor); for (note, path) in self.notes.into_iter() { @@ -1068,7 +1068,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let mut builder = Builder::new( - Flags::from_parts(true, true), + Flags::from_parts(true, true, false), EMPTY_ROOTS[MERKLE_DEPTH_ORCHARD].into(), ); diff --git a/src/bundle.rs b/src/bundle.rs index 2e5d5a034..23beb4a86 100644 --- a/src/bundle.rs +++ b/src/bundle.rs @@ -38,6 +38,7 @@ impl Action { cmx: *self.cmx(), enable_spend: flags.spends_enabled, enable_output: flags.outputs_enabled, + enable_zsa: flags.zsa_enabled, } } } @@ -57,18 +58,25 @@ pub struct Flags { /// guaranteed to be dummy notes. If `true`, the created notes may be either real or /// dummy notes. outputs_enabled: bool, + /// Flag denoting whether ZSA transaction is enabled. + /// + /// If `false`, all notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be notes with native asset. + zsa_enabled: bool, } const FLAG_SPENDS_ENABLED: u8 = 0b0000_0001; const FLAG_OUTPUTS_ENABLED: u8 = 0b0000_0010; -const FLAGS_EXPECTED_UNSET: u8 = !(FLAG_SPENDS_ENABLED | FLAG_OUTPUTS_ENABLED); +const FLAG_ZSA_ENABLED: u8 = 0b0000_0100; +const FLAGS_EXPECTED_UNSET: u8 = !(FLAG_SPENDS_ENABLED | FLAG_OUTPUTS_ENABLED | FLAG_ZSA_ENABLED); impl Flags { /// Construct a set of flags from its constituent parts - pub fn from_parts(spends_enabled: bool, outputs_enabled: bool) -> Self { + pub fn from_parts(spends_enabled: bool, outputs_enabled: bool, zsa_enabled: bool) -> Self { Flags { spends_enabled, outputs_enabled, + zsa_enabled, } } @@ -90,6 +98,14 @@ impl Flags { self.outputs_enabled } + /// Flag denoting whether ZSA transaction is enabled. + /// + /// If `false`, all notes within [`Action`]s in the transaction's [`Bundle`] are + /// guaranteed to be notes with native asset. + pub fn zsa_enabled(&self) -> bool { + self.zsa_enabled + } + /// Serialize flags to a byte as defined in [Zcash Protocol Spec § 7.1: Transaction /// Encoding And Consensus][txencoding]. /// @@ -102,6 +118,9 @@ impl Flags { if self.outputs_enabled { value |= FLAG_OUTPUTS_ENABLED; } + if self.zsa_enabled { + value |= FLAG_ZSA_ENABLED; + } value } @@ -116,6 +135,7 @@ impl Flags { Some(Self::from_parts( value & FLAG_SPENDS_ENABLED != 0, value & FLAG_OUTPUTS_ENABLED != 0, + value & FLAG_ZSA_ENABLED != 0, )) } else { None @@ -607,8 +627,8 @@ pub mod testing { prop_compose! { /// Create an arbitrary set of flags. - pub fn arb_flags()(spends_enabled in prop::bool::ANY, outputs_enabled in prop::bool::ANY) -> Flags { - Flags::from_parts(spends_enabled, outputs_enabled) + pub fn arb_flags()(spends_enabled in prop::bool::ANY, outputs_enabled in prop::bool::ANY, zsa_enabled in prop::bool::ANY) -> Flags { + Flags::from_parts(spends_enabled, outputs_enabled, zsa_enabled) } } diff --git a/src/circuit.rs b/src/circuit.rs index 9d550e5d2..d88bfa2a8 100644 --- a/src/circuit.rs +++ b/src/circuit.rs @@ -27,6 +27,7 @@ use self::{ }; use crate::{ builder::SpendInfo, + bundle::Flags, circuit::gadget::mux_chip::{MuxChip, MuxConfig}, constants::{ OrchardCommitDomains, OrchardFixedBases, OrchardFixedBasesFull, OrchardHashDomains, @@ -79,6 +80,7 @@ const RK_Y: usize = 5; const CMX: usize = 6; const ENABLE_SPEND: usize = 7; const ENABLE_OUTPUT: usize = 8; +const ENABLE_ZSA: usize = 9; /// Configuration needed to use the Orchard Action circuit. #[derive(Clone, Debug)] @@ -231,6 +233,7 @@ impl plonk::Circuit for Circuit { // Constraint if is_native_asset = 1 then asset = native_asset else asset != native_asset // Constraint if split_flag = 0 then psi_old = psi_nf // Constraint if split_flag = 1, then is_native_asset = 0 + // Constraint if enable_zsa = 0, then is_native_asset = 1 let q_orchard = meta.selector(); meta.create_gate("Orchard circuit checks", |meta| { let q_orchard = meta.query_selector(q_orchard); @@ -267,6 +270,8 @@ impl plonk::Circuit for Circuit { let psi_old = meta.query_advice(advices[4], Rotation::next()); let psi_nf = meta.query_advice(advices[5], Rotation::next()); + let enable_zsa = meta.query_advice(advices[6], Rotation::next()); + Constraints::with_selector( q_orchard, [ @@ -318,11 +323,15 @@ impl plonk::Circuit for Circuit { ), ( "(split_flag = 0) => (psi_old = psi_nf)", - (one - split_flag.clone()) * (psi_old - psi_nf), + (one.clone() - split_flag.clone()) * (psi_old - psi_nf), ), ( "(split_flag = 1) => (is_native_asset = 0)", - split_flag * is_native_asset, + split_flag * is_native_asset.clone(), + ), + ( + "(enable_zsa = 0) => (is_native_asset = 1)", + (one.clone() - enable_zsa) * (one - is_native_asset), ), ], ) @@ -942,6 +951,14 @@ impl plonk::Circuit for Circuit { psi_old.copy_advice(|| "psi_old", &mut region, config.advices[4], 1)?; psi_nf.copy_advice(|| "psi_nf", &mut region, config.advices[5], 1)?; + region.assign_advice_from_instance( + || "enable zsa", + config.primary, + ENABLE_ZSA, + config.advices[6], + 1, + )?; + config.q_orchard.enable(&mut region, 0) }, )?; @@ -999,6 +1016,7 @@ pub struct Instance { pub(crate) cmx: ExtractedNoteCommitment, pub(crate) enable_spend: bool, pub(crate) enable_output: bool, + pub(crate) enable_zsa: bool, } impl Instance { @@ -1015,8 +1033,7 @@ impl Instance { nf_old: Nullifier, rk: VerificationKey, cmx: ExtractedNoteCommitment, - enable_spend: bool, - enable_output: bool, + flags: Flags, ) -> Self { Instance { anchor, @@ -1024,13 +1041,14 @@ impl Instance { nf_old, rk, cmx, - enable_spend, - enable_output, + enable_spend: flags.spends_enabled(), + enable_output: flags.outputs_enabled(), + enable_zsa: flags.zsa_enabled(), } } - fn to_halo2_instance(&self) -> [[vesta::Scalar; 9]; 1] { - let mut instance = [vesta::Scalar::zero(); 9]; + fn to_halo2_instance(&self) -> [[vesta::Scalar; 10]; 1] { + let mut instance = [vesta::Scalar::zero(); 10]; instance[ANCHOR] = self.anchor.inner(); instance[CV_NET_X] = self.cv_net.x(); @@ -1048,6 +1066,7 @@ impl Instance { instance[CMX] = self.cmx.inner(); instance[ENABLE_SPEND] = vesta::Scalar::from(u64::from(self.enable_spend)); instance[ENABLE_OUTPUT] = vesta::Scalar::from(u64::from(self.enable_output)); + instance[ENABLE_ZSA] = vesta::Scalar::from(u64::from(self.enable_zsa)); [instance] } @@ -1167,6 +1186,7 @@ mod tests { use super::{Circuit, Instance, Proof, ProvingKey, VerifyingKey, K}; use crate::builder::SpendInfo; + use crate::bundle::Flags; use crate::note::commitment::NoteCommitTrapdoor; use crate::note::{AssetBase, Nullifier}; use crate::primitives::redpallas::VerificationKey; @@ -1234,6 +1254,7 @@ mod tests { cmx, enable_spend: true, enable_output: true, + enable_zsa: false, }, ) } @@ -1314,6 +1335,7 @@ mod tests { w.write_all(&[ if instance.enable_spend { 1 } else { 0 }, if instance.enable_output { 1 } else { 0 }, + if instance.enable_zsa { 1 } else { 0 }, ])?; w.write_all(proof.as_ref())?; @@ -1344,8 +1366,15 @@ mod tests { crate::note::ExtractedNoteCommitment::from_bytes(&read_32_bytes(&mut r)).unwrap(); let enable_spend = read_bool(&mut r); let enable_output = read_bool(&mut r); - let instance = - Instance::from_parts(anchor, cv_net, nf_old, rk, cmx, enable_spend, enable_output); + let enable_zsa = read_bool(&mut r); + let instance = Instance::from_parts( + anchor, + cv_net, + nf_old, + rk, + cmx, + Flags::from_parts(enable_spend, enable_output, enable_zsa), + ); let mut proof_bytes = vec![]; r.read_to_end(&mut proof_bytes)?; @@ -1533,6 +1562,7 @@ mod tests { cmx, enable_spend: true, enable_output: true, + enable_zsa: true, }, ) } @@ -1573,6 +1603,7 @@ mod tests { cmx: instance.cmx, enable_spend: instance.enable_spend, enable_output: instance.enable_output, + enable_zsa: instance.enable_zsa, }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_cv_net, false); @@ -1586,6 +1617,7 @@ mod tests { cmx: instance.cmx, enable_spend: instance.enable_spend, enable_output: instance.enable_output, + enable_zsa: instance.enable_zsa, }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_rk, false); @@ -1627,6 +1659,7 @@ mod tests { cmx: random_note_commitment(&mut rng).into(), enable_spend: instance.enable_spend, enable_output: instance.enable_output, + enable_zsa: instance.enable_zsa, }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_cmx_pub, false); @@ -1640,6 +1673,7 @@ mod tests { cmx: instance.cmx, enable_spend: instance.enable_spend, enable_output: instance.enable_output, + enable_zsa: instance.enable_zsa, }; check_proof_of_orchard_circuit(&circuit, &instance_wrong_nf_old_pub, false); @@ -1672,6 +1706,22 @@ mod tests { }; check_proof_of_orchard_circuit(&circuit_wrong_psi_nf, &instance, false); } + + // If asset is not equal to the native asset, set enable_zsa = 0 + // The proof should fail + if !is_native_asset { + let instance_wrong_enable_zsa = Instance { + anchor: instance.anchor, + cv_net: instance.cv_net.clone(), + nf_old: instance.nf_old, + rk: instance.rk.clone(), + cmx: instance.cmx, + enable_spend: instance.enable_spend, + enable_output: instance.enable_output, + enable_zsa: false, + }; + check_proof_of_orchard_circuit(&circuit, &instance_wrong_enable_zsa, false); + } } } } diff --git a/src/circuit_description b/src/circuit_description index 7a9d35f07..cffc54ff8 100644 --- a/src/circuit_description +++ b/src/circuit_description @@ -1002,6 +1002,93 @@ PinnedVerificationKey { }, ), ), + Product( + Product( + Product( + Product( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000002, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000003, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000004, + ), + Negated( + Fixed { + query_index: 18, + column_index: 18, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + Product( + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 16, + column_index: 6, + rotation: Rotation( + 1, + ), + }, + ), + ), + Sum( + Constant( + 0x0000000000000000000000000000000000000000000000000000000000000001, + ), + Negated( + Advice { + query_index: 9, + column_index: 9, + rotation: Rotation( + 0, + ), + }, + ), + ), + ), + ), Product( Product( Product( @@ -1146,7 +1233,7 @@ PinnedVerificationKey { Product( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -1155,7 +1242,7 @@ PinnedVerificationKey { 0x0000000000000000000000000000000000000000000000000000000000000400, ), Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -3764,7 +3851,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -3790,7 +3877,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -4008,7 +4095,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -4569,7 +4656,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -4595,7 +4682,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -4813,7 +4900,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -5312,7 +5399,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -5328,7 +5415,7 @@ PinnedVerificationKey { ), Sum( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -5339,14 +5426,14 @@ PinnedVerificationKey { Sum( Product( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, ), }, Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -5355,7 +5442,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -5647,7 +5734,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -5673,7 +5760,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -5875,7 +5962,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -5996,7 +6083,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -6148,7 +6235,7 @@ PinnedVerificationKey { }, Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -6235,7 +6322,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -6251,7 +6338,7 @@ PinnedVerificationKey { ), Sum( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -6262,14 +6349,14 @@ PinnedVerificationKey { Sum( Product( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, ), }, Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -6278,7 +6365,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -6404,7 +6491,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -6430,7 +6517,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -6648,7 +6735,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -6785,7 +6872,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -6953,7 +7040,7 @@ PinnedVerificationKey { }, Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -7037,7 +7124,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -7137,7 +7224,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -7149,7 +7236,7 @@ PinnedVerificationKey { 0x0000000000000000000000000000000000000000000000000000000000000002, ), Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -7165,7 +7252,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -7177,7 +7264,7 @@ PinnedVerificationKey { 0x0000000000000000000000000000000000000000000000000000000000000002, ), Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -7282,7 +7369,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -7294,7 +7381,7 @@ PinnedVerificationKey { 0x0000000000000000000000000000000000000000000000000000000000000002, ), Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -7313,7 +7400,7 @@ PinnedVerificationKey { }, Negated( Advice { - query_index: 21, + query_index: 22, column_index: 1, rotation: Rotation( -1, @@ -7330,7 +7417,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -7342,7 +7429,7 @@ PinnedVerificationKey { 0x0000000000000000000000000000000000000000000000000000000000000002, ), Advice { - query_index: 17, + query_index: 18, column_index: 9, rotation: Rotation( -1, @@ -7362,7 +7449,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 21, + query_index: 22, column_index: 1, rotation: Rotation( -1, @@ -7557,7 +7644,7 @@ PinnedVerificationKey { Sum( Sum( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -7757,7 +7844,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -7867,7 +7954,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -7878,7 +7965,7 @@ PinnedVerificationKey { ), ), Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -7977,7 +8064,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -8003,7 +8090,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -8118,7 +8205,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -8153,7 +8240,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -8287,7 +8374,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -8322,7 +8409,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -10684,7 +10771,7 @@ PinnedVerificationKey { }, Sum( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -10790,7 +10877,7 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -10799,7 +10886,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -10816,7 +10903,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -10825,7 +10912,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -10921,7 +11008,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -11341,7 +11428,7 @@ PinnedVerificationKey { Sum( Sum( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -11709,7 +11796,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -12054,7 +12141,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -12399,7 +12486,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -12939,7 +13026,7 @@ PinnedVerificationKey { Sum( Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -12949,7 +13036,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -12960,7 +13047,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -13095,7 +13182,7 @@ PinnedVerificationKey { Sum( Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -13105,7 +13192,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -13116,7 +13203,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -13251,7 +13338,7 @@ PinnedVerificationKey { Sum( Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -13261,7 +13348,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -13272,7 +13359,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -13359,7 +13446,7 @@ PinnedVerificationKey { Sum( Sum( Advice { - query_index: 20, + query_index: 21, column_index: 6, rotation: Rotation( -1, @@ -13375,7 +13462,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -13475,7 +13562,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -13566,7 +13653,7 @@ PinnedVerificationKey { }, Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -15156,14 +15243,14 @@ PinnedVerificationKey { Product( Sum( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -15183,14 +15270,14 @@ PinnedVerificationKey { Sum( Product( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, ), }, Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -15209,7 +15296,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -15250,7 +15337,7 @@ PinnedVerificationKey { 0x0000000000000000000000000000000000000000000000000000000000000002, ), Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -15767,7 +15854,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -15886,7 +15973,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -15898,7 +15985,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -16012,7 +16099,7 @@ PinnedVerificationKey { Sum( Sum( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -16130,7 +16217,7 @@ PinnedVerificationKey { ), Sum( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -16139,7 +16226,7 @@ PinnedVerificationKey { Negated( Sum( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -16147,7 +16234,7 @@ PinnedVerificationKey { }, Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -17543,7 +17630,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -17673,7 +17760,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -17779,7 +17866,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -17989,7 +18076,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -18001,7 +18088,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -18131,7 +18218,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -18142,7 +18229,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -18498,7 +18585,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -18509,7 +18596,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -18860,7 +18947,7 @@ PinnedVerificationKey { }, Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -18871,7 +18958,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -19204,7 +19291,7 @@ PinnedVerificationKey { ), Sum( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -19233,7 +19320,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -19699,7 +19786,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -19829,7 +19916,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -19928,7 +20015,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -20033,7 +20120,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -20138,14 +20225,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -20280,7 +20367,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -20438,7 +20525,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -20553,7 +20640,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -20674,14 +20761,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -20963,7 +21050,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -21121,7 +21208,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -21236,7 +21323,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -21357,14 +21444,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -21500,7 +21587,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -21511,7 +21598,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -21669,7 +21756,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -21784,14 +21871,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -21905,7 +21992,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -22026,14 +22113,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -22304,7 +22391,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -22589,7 +22676,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -22832,7 +22919,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -22953,7 +23040,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -23195,7 +23282,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -23207,7 +23294,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -23353,7 +23440,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -23364,7 +23451,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -23768,7 +23855,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -23779,7 +23866,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -24178,7 +24265,7 @@ PinnedVerificationKey { }, Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -24189,7 +24276,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -24570,7 +24657,7 @@ PinnedVerificationKey { ), Sum( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -24599,7 +24686,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -25129,7 +25216,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -25275,7 +25362,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -25390,7 +25477,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -25511,7 +25598,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -25632,14 +25719,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -25774,7 +25861,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -25932,7 +26019,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -26047,7 +26134,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -26168,14 +26255,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -26409,7 +26496,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -26519,7 +26606,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -26586,7 +26673,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -26659,14 +26746,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -26754,7 +26841,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -26765,7 +26852,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -26875,7 +26962,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -26942,14 +27029,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -27015,7 +27102,7 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -27088,14 +27175,14 @@ PinnedVerificationKey { ), Product( Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -27270,7 +27357,7 @@ PinnedVerificationKey { ), Scaled( Advice { - query_index: 22, + query_index: 16, column_index: 6, rotation: Rotation( 1, @@ -27459,7 +27546,7 @@ PinnedVerificationKey { ), Negated( Advice { - query_index: 19, + query_index: 20, column_index: 8, rotation: Rotation( 1, @@ -27606,7 +27693,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -27679,7 +27766,7 @@ PinnedVerificationKey { ), }, Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -27942,6 +28029,15 @@ PinnedVerificationKey { 1, ), ), + ( + Column { + index: 6, + column_type: Advice, + }, + Rotation( + 1, + ), + ), ( Column { index: 9, @@ -27996,15 +28092,6 @@ PinnedVerificationKey { -1, ), ), - ( - Column { - index: 6, - column_type: Advice, - }, - Rotation( - 1, - ), - ), ( Column { index: 7, @@ -28402,7 +28489,7 @@ PinnedVerificationKey { Negated( Scaled( Advice { - query_index: 16, + query_index: 17, column_index: 9, rotation: Rotation( 1, @@ -28762,7 +28849,7 @@ PinnedVerificationKey { ), ), Advice { - query_index: 18, + query_index: 19, column_index: 7, rotation: Rotation( 1, @@ -29006,14 +29093,14 @@ PinnedVerificationKey { ], permutation: VerifyingKey { commitments: [ - (0x3b61bede3f87e9208caf3626fbe7a645e1b9f9b241a96160c68b708196e86cbb, 0x0932e9c67d6bb593c9b3d6bd9697efe79bb2f81bee35abeaa8a2a0a828d8fcc6), + (0x26d7150d98acf5efa7739440641d97629e2d6553547920432e43d747b998d49e, 0x3223285fb44e1736e7216cd51276087bce39f7e5c0fdb1ef49ab4c6de26b256d), (0x07800024b352149368405f222a8dfbf373bd4603df89929a5d00f7ac9ffac504, 0x250be8a84de9a8ded91e85860f1b1751f6bd2c0aba96329ee2d6f0e377f4679f), (0x3384b0dbfa6553ad5adf0b218df2cbe6243c33102a97774b4e023ec1dc2d83e9, 0x2873fe49458cd70b9d72419e0d6a6ceadb8070f4b62a0bb47c58a89269e0b583), (0x38def0fd8f233ef8651a28ffb7ae6f1e4eaeb0acec19453a3e5a0d70b2058782, 0x0512c67736284a225f0b6617cabd76ac2e4a6805940af4480798ca884e02d277), (0x26b6d69fd8c13013c6ab5fb74bd3fbe85d01b0abb57e149ff53e77a535c6bf40, 0x05ae4f52e4ab72ff3cf2b64df6d371fda270f4f78ed0bccce8e3138d4e30e4a0), (0x3f1b6f3ea5a2b24646dbe1c6f7c7dbf797fe6602a344bed59668ba5413519631, 0x0401a6f6ed893aa112f234127f8c30ee6e09b45f75993351aea9974389b261d6), (0x2f34843015cfc9c9ff59c7ecab3cbb6aea69dcf6f5af79e166f25d90f70353d5, 0x2bcfde5880412d171705b41124b404a323697c4d1008b2e8b2bf9966e5809d3d), - (0x1241f0e0058575ff769809aa569ab0ff12d5b2d7d840eae76912c16433be00ff, 0x33339365e1edbdb387b0a0b7dc5a9212c0313bb0a131c9302bc57db36174f3b0), + (0x082e9af26adc31f97c38ce587ffde9af5d8238d16ad61a236bbd3c805515f144, 0x051d36eb85b6402dfb2a55ae1507b358319d016483d7ecf6be49793bbb64e79e), (0x240a361e73afa04a2e5cc578680e54bf28e3375dbb35a8918c3cdbc91f1bc25b, 0x161c53e65c1b6500b576d8fa982e2565dbe35954840b0bab8a3d912158b9dbe7), (0x32f883bbd63b0700f0150ea8d71f6f5d7cdcc4463289983d71e9bc104d4a5c28, 0x33aeb42bec794138b8db28696bd7cef4946a8a89edcbf3f8289655ff9f9129ee), (0x03f33d3064517ab1a8e538444013bd0d6b011f9923f8cb964763a88d6d7409e0, 0x16f534b6d12d9e011b951e374982f048f0bed808099fd3ed97cd827360f6fb65), diff --git a/src/circuit_proof_test_case.bin b/src/circuit_proof_test_case.bin index 9005e06bc0beb164cc041c00bd0ac8707ebe8da9..83ca7c0535ed0da94d2aca22e3f9553b7fad9eed 100644 GIT binary patch literal 5251 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 J7OYxF0|4IM93B7w literal 5250 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 I+uWQkC`hXiNdN!< diff --git a/tests/builder.rs b/tests/builder.rs index 506ef1154..5d69209ab 100644 --- a/tests/builder.rs +++ b/tests/builder.rs @@ -62,7 +62,7 @@ fn bundle_chain() { // Use the empty tree. let anchor = MerkleHashOrchard::empty_root(32.into()).into(); - let mut builder = Builder::new(Flags::from_parts(false, true), anchor); + let mut builder = Builder::new(Flags::from_parts(false, true, false), anchor); assert_eq!( builder.add_recipient( None, @@ -96,7 +96,7 @@ fn bundle_chain() { let (merkle_path, anchor) = build_merkle_path(¬e); - let mut builder = Builder::new(Flags::from_parts(true, true), anchor); + let mut builder = Builder::new(Flags::from_parts(true, true, false), anchor); assert_eq!(builder.add_spend(fvk, note, merkle_path), Ok(())); assert_eq!( builder.add_recipient( diff --git a/tests/zsa.rs b/tests/zsa.rs index 649d5e8cf..584b25b5b 100644 --- a/tests/zsa.rs +++ b/tests/zsa.rs @@ -189,7 +189,7 @@ fn create_native_note(keys: &Keychain) -> Note { // Use the empty tree. let anchor = MerkleHashOrchard::empty_root(32.into()).into(); - let mut builder = Builder::new(Flags::from_parts(false, true), anchor); + let mut builder = Builder::new(Flags::from_parts(false, true, false), anchor); assert_eq!( builder.add_recipient( None, @@ -244,7 +244,7 @@ fn build_and_verify_bundle( ) -> Result<(), String> { let rng = OsRng; let shielded_bundle: Bundle<_, i64> = { - let mut builder = Builder::new(Flags::from_parts(true, true), anchor); + let mut builder = Builder::new(Flags::from_parts(true, true, true), anchor); spends .iter()