diff --git a/taiga_halo2/Cargo.toml b/taiga_halo2/Cargo.toml index 4ba7da56..7cdca7e8 100644 --- a/taiga_halo2/Cargo.toml +++ b/taiga_halo2/Cargo.toml @@ -18,7 +18,7 @@ subtle = { version = "2.3", default-features = false } dyn-clone = "1.0" reddsa = { git = "https://github.com/heliaxdev/reddsa.git", branch = "taiga" } vamp-ir = { git = "https://github.com/anoma/vamp-ir.git", rev = "6d401f8a479951727586ef0c44c42edab3139090" } -bincode = "2.0.0-rc.3" +bincode = "1.3.3" byteorder = "1.4" num-bigint = "0.4" @@ -47,7 +47,7 @@ name = "tx_examples" required-features = ["examples"] [features] -default = [] +default = ["serde"] nif = ["dep:rustler", "borsh", "pasta_curves/repr-erlang"] serde = ["dep:serde", "pasta_curves/serde"] borsh = ["dep:borsh"] diff --git a/taiga_halo2/src/circuit/resource_logic_bytecode.rs b/taiga_halo2/src/circuit/resource_logic_bytecode.rs index c805788b..2d9fec2c 100644 --- a/taiga_halo2/src/circuit/resource_logic_bytecode.rs +++ b/taiga_halo2/src/circuit/resource_logic_bytecode.rs @@ -16,14 +16,9 @@ use crate::{ ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, VampIRResourceLogicCircuit, }, constant::{ - RESOURCE_LOGIC_CIRCUIT_NULLIFIER_ONE_PUBLIC_INPUT_IDX, - RESOURCE_LOGIC_CIRCUIT_NULLIFIER_TWO_PUBLIC_INPUT_IDX, - RESOURCE_LOGIC_CIRCUIT_OUTPUT_CM_ONE_PUBLIC_INPUT_IDX, - RESOURCE_LOGIC_CIRCUIT_OUTPUT_CM_TWO_PUBLIC_INPUT_IDX, + RESOURCE_LOGIC_CIRCUIT_RESOURCE_MERKLE_ROOT_IDX, RESOURCE_LOGIC_CIRCUIT_SELF_RESOURCE_ID_IDX, }, - nullifier::Nullifier, - resource::ResourceCommitment, }; #[cfg(feature = "borsh")] @@ -131,8 +126,7 @@ impl ResourceLogicByteCode { // Verify resource_logic circuit transparently and return self resource id for further checking pub fn verify_transparently( &self, - compliance_nfs: &[Nullifier], - compliance_cms: &[ResourceCommitment], + compliance_resource_merkle_root: &pallas::Base, ) -> Result { // check resource logic transparently let public_inputs = match &self.circuit { @@ -189,33 +183,12 @@ impl ResourceLogicByteCode { _ => return Err(TransactionError::InvalidResourceLogicRepresentation), }; - // check nullifiers - // Check the resource_logic actually uses the input resources from compliance circuits. - let resource_logic_nfs = [ - public_inputs.get_from_index(RESOURCE_LOGIC_CIRCUIT_NULLIFIER_ONE_PUBLIC_INPUT_IDX), - public_inputs.get_from_index(RESOURCE_LOGIC_CIRCUIT_NULLIFIER_TWO_PUBLIC_INPUT_IDX), - ]; + // check resource merkle root + let logic_resource_merkle_root = + public_inputs.get_from_index(RESOURCE_LOGIC_CIRCUIT_RESOURCE_MERKLE_ROOT_IDX); - if !((compliance_nfs[0].inner() == resource_logic_nfs[0] - && compliance_nfs[1].inner() == resource_logic_nfs[1]) - || (compliance_nfs[0].inner() == resource_logic_nfs[1] - && compliance_nfs[1].inner() == resource_logic_nfs[0])) - { - return Err(TransactionError::InconsistentNullifier); - } - - // check resource_commitments - // Check the resource_logic actually uses the output resources from compliance circuits. - let resource_logic_cms = [ - public_inputs.get_from_index(RESOURCE_LOGIC_CIRCUIT_OUTPUT_CM_ONE_PUBLIC_INPUT_IDX), - public_inputs.get_from_index(RESOURCE_LOGIC_CIRCUIT_OUTPUT_CM_TWO_PUBLIC_INPUT_IDX), - ]; - if !((compliance_cms[0].inner() == resource_logic_cms[0] - && compliance_cms[1].inner() == resource_logic_cms[1]) - || (compliance_cms[0].inner() == resource_logic_cms[1] - && compliance_cms[1].inner() == resource_logic_cms[0])) - { - return Err(TransactionError::InconsistentOutputResourceCommitment); + if logic_resource_merkle_root != *compliance_resource_merkle_root { + return Err(TransactionError::InconsistentResourceMerkleRoot); } Ok(public_inputs.get_from_index(RESOURCE_LOGIC_CIRCUIT_SELF_RESOURCE_ID_IDX)) @@ -251,14 +224,13 @@ impl ApplicationByteCode { // Verify resource_logic circuits transparently and return owned resource PubID for further checking pub fn verify_transparently( &self, - compliance_nfs: &[Nullifier], - compliance_cms: &[ResourceCommitment], + compliance_root: &pallas::Base, ) -> Result { let self_resource_id = self .app_resource_logic_bytecode - .verify_transparently(compliance_nfs, compliance_cms)?; + .verify_transparently(compliance_root)?; for dynamic_resource_logic in self.dynamic_resource_logic_bytecode.iter() { - let id = dynamic_resource_logic.verify_transparently(compliance_nfs, compliance_cms)?; + let id = dynamic_resource_logic.verify_transparently(compliance_root)?; // check: the app_resource_logic and dynamic_resource_logics belong to the resource if id != self_resource_id { return Err(TransactionError::InconsistentSelfResourceID); diff --git a/taiga_halo2/src/circuit/resource_logic_examples.rs b/taiga_halo2/src/circuit/resource_logic_examples.rs index cebe9037..c478da2b 100644 --- a/taiga_halo2/src/circuit/resource_logic_examples.rs +++ b/taiga_halo2/src/circuit/resource_logic_examples.rs @@ -69,6 +69,7 @@ lazy_static! { // TrivialResourceLogicCircuit with empty custom constraints. #[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TrivialResourceLogicCircuit { self_resource: ResourceExistenceWitness, } @@ -85,50 +86,12 @@ impl TrivialResourceLogicCircuit { ResourceLogicByteCode::new(ResourceLogicRepresentation::Trivial, self.to_bytes()) } - // Only for test - #[cfg(feature = "borsh")] pub fn to_bytes(&self) -> Vec { - borsh::to_vec(&self).unwrap() + bincode::serialize(&self).unwrap() } - // Only for test - #[cfg(feature = "borsh")] pub fn from_bytes(bytes: &Vec) -> Self { - BorshDeserialize::deserialize(&mut bytes.as_ref()).unwrap() - } -} - -#[cfg(feature = "borsh")] -impl BorshSerialize for TrivialResourceLogicCircuit { - fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - use ff::PrimeField; - writer.write_all(&self.self_resource_id.to_repr())?; - for input in self.input_resources.iter() { - input.serialize(writer)?; - } - - for output in self.output_resources.iter() { - output.serialize(writer)?; - } - Ok(()) - } -} - -#[cfg(feature = "borsh")] -impl BorshDeserialize for TrivialResourceLogicCircuit { - fn deserialize_reader(reader: &mut R) -> std::io::Result { - let self_resource_id = crate::utils::read_base_field(reader)?; - let input_resources: Vec<_> = (0..NUM_RESOURCE) - .map(|_| Resource::deserialize_reader(reader)) - .collect::>()?; - let output_resources: Vec<_> = (0..NUM_RESOURCE) - .map(|_| Resource::deserialize_reader(reader)) - .collect::>()?; - Ok(Self { - self_resource_id, - input_resources: input_resources.try_into().unwrap(), - output_resources: output_resources.try_into().unwrap(), - }) + bincode::deserialize(bytes).unwrap() } } diff --git a/taiga_halo2/src/constant.rs b/taiga_halo2/src/constant.rs index 6e0c9a46..7f39a186 100644 --- a/taiga_halo2/src/constant.rs +++ b/taiga_halo2/src/constant.rs @@ -77,12 +77,7 @@ pub const RESOURCE_LOGIC_CIRCUIT_CUSTOM_PUBLIC_INPUT_NUM: usize = 2; pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_PUBLIC_INPUT_NUM: usize = RESOURCE_ENCRYPTION_CIPHERTEXT_NUM + 2; // ciphertext(12) + public_key(2) -// TODO: Get rid of the outdated indexs -pub const RESOURCE_LOGIC_CIRCUIT_NULLIFIER_ONE_PUBLIC_INPUT_IDX: usize = 0; -pub const RESOURCE_LOGIC_CIRCUIT_OUTPUT_CM_ONE_PUBLIC_INPUT_IDX: usize = 1; -pub const RESOURCE_LOGIC_CIRCUIT_NULLIFIER_TWO_PUBLIC_INPUT_IDX: usize = 2; -pub const RESOURCE_LOGIC_CIRCUIT_OUTPUT_CM_TWO_PUBLIC_INPUT_IDX: usize = 3; - +// resource logic public input index pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_MERKLE_ROOT_IDX: usize = 0; pub const RESOURCE_LOGIC_CIRCUIT_SELF_RESOURCE_ID_IDX: usize = 1; pub const RESOURCE_LOGIC_CIRCUIT_FIRST_DYNAMIC_RESOURCE_LOGIC_CM_1: usize = 2; diff --git a/taiga_halo2/src/executable.rs b/taiga_halo2/src/executable.rs index 6db77b43..a4b732bc 100644 --- a/taiga_halo2/src/executable.rs +++ b/taiga_halo2/src/executable.rs @@ -2,7 +2,7 @@ use pasta_curves::pallas; use crate::{ delta_commitment::DeltaCommitment, error::TransactionError, merkle_tree::Anchor, - nullifier::Nullifier, resource::ResourceCommitment, + nullifier::Nullifier, resource::ResourceCommitment, resource_tree::ResourceMerkleTreeLeaves, }; // Executable is an unified interface for partial transaction, which is the atomic executable uinit. @@ -12,5 +12,16 @@ pub trait Executable { fn get_output_cms(&self) -> Vec; fn get_delta_commitments(&self) -> Vec; fn get_anchors(&self) -> Vec; - fn get_resource_merkle_root(&self) -> pallas::Base; + fn get_resource_merkle_root(&self) -> pallas::Base { + let mut leaves = vec![]; + self.get_nullifiers() + .iter() + .zip(self.get_output_cms()) + .for_each(|(nf, cm)| { + leaves.push(nf.inner()); + leaves.push(cm.inner()); + }); + let tree = ResourceMerkleTreeLeaves::new(leaves); + tree.root() + } } diff --git a/taiga_halo2/src/resource_tree.rs b/taiga_halo2/src/resource_tree.rs index 44ed9873..320626e1 100644 --- a/taiga_halo2/src/resource_tree.rs +++ b/taiga_halo2/src/resource_tree.rs @@ -7,6 +7,7 @@ use crate::{ use pasta_curves::pallas; #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ResourceExistenceWitness { resource: Resource, merkle_path: [(pallas::Base, LR); TAIGA_RESOURCE_TREE_DEPTH], diff --git a/taiga_halo2/src/shielded_ptx.rs b/taiga_halo2/src/shielded_ptx.rs index 2fef67f6..8ed315c9 100644 --- a/taiga_halo2/src/shielded_ptx.rs +++ b/taiga_halo2/src/shielded_ptx.rs @@ -11,7 +11,6 @@ use crate::merkle_tree::Anchor; use crate::nullifier::Nullifier; use crate::proof::Proof; use crate::resource::{ResourceCommitment, ResourceLogics}; -use crate::resource_tree::ResourceMerkleTreeLeaves; use halo2_proofs::plonk::Error; use pasta_curves::pallas; use rand::RngCore; @@ -303,19 +302,6 @@ impl Executable for ShieldedPartialTransaction { .map(|compliance| compliance.compliance_instance.anchor) .collect() } - - fn get_resource_merkle_root(&self) -> pallas::Base { - let mut leaves = vec![]; - self.get_nullifiers() - .iter() - .zip(self.get_output_cms()) - .for_each(|(nf, cm)| { - leaves.push(nf.inner()); - leaves.push(cm.inner()); - }); - let tree = ResourceMerkleTreeLeaves::new(leaves); - tree.root() - } } #[cfg(feature = "borsh")] diff --git a/taiga_halo2/src/taiga_api.rs b/taiga_halo2/src/taiga_api.rs index e2840b3c..74d93c06 100644 --- a/taiga_halo2/src/taiga_api.rs +++ b/taiga_halo2/src/taiga_api.rs @@ -228,7 +228,7 @@ pub fn verify_shielded_partial_transaction(ptx_bytes: Vec) -> Result<(), Tra pub mod tests { use crate::{ nullifier::tests::random_nullifier_key_commitment, resource::tests::random_resource, - taiga_api::*, + resource_tree::ResourceMerkleTreeLeaves, taiga_api::*, }; use rand::rngs::OsRng; @@ -264,7 +264,6 @@ pub mod tests { // construct resources let input_resource_1 = random_resource(&mut rng); - let input_resource_1_nf = input_resource_1.get_nf().unwrap(); let mut output_resource_1 = random_resource(&mut rng); let merkle_path_1 = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); let compliance_1 = ComplianceInfo::new( @@ -276,7 +275,6 @@ pub mod tests { ); let input_resource_2 = random_resource(&mut rng); - let input_resource_2_nf = input_resource_2.get_nf().unwrap(); let mut output_resource_2 = random_resource(&mut rng); let merkle_path_2 = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); let compliance_2 = ComplianceInfo::new( @@ -287,45 +285,57 @@ pub mod tests { &mut rng, ); + // Collect resource merkle leaves + let input_resource_nf_1 = input_resource_1.get_nf().unwrap().inner(); + let output_resource_cm_1 = output_resource_1.commitment().inner(); + let input_resource_nf_2 = input_resource_2.get_nf().unwrap().inner(); + let output_resource_cm_2 = output_resource_2.commitment().inner(); + let resource_merkle_tree = ResourceMerkleTreeLeaves::new(vec![ + input_resource_nf_1, + output_resource_cm_1, + input_resource_nf_2, + output_resource_cm_2, + ]); + // construct applications let input_resource_1_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - input_resource_1_nf.inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let input_resource_path_1 = resource_merkle_tree + .generate_path(input_resource_nf_1) + .unwrap(); + let input_resource_application_logic_1 = + TrivialResourceLogicCircuit::new(input_resource_1, input_resource_path_1); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(input_resource_application_logic_1.to_bytecode(), vec![]) }; let input_resource_2_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - input_resource_2_nf.inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let input_resource_path_2 = resource_merkle_tree + .generate_path(input_resource_nf_2) + .unwrap(); + let input_resource_application_logic_2 = + TrivialResourceLogicCircuit::new(input_resource_2, input_resource_path_2); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(input_resource_application_logic_2.to_bytecode(), vec![]) }; let output_resource_1_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - output_resource_1.commitment().inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let output_resource_path_1 = resource_merkle_tree + .generate_path(output_resource_cm_1) + .unwrap(); + let output_resource_application_logic_1 = + TrivialResourceLogicCircuit::new(output_resource_1, output_resource_path_1); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(output_resource_application_logic_1.to_bytecode(), vec![]) }; let output_resource_2_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - output_resource_2.commitment().inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let output_resource_path_2 = resource_merkle_tree + .generate_path(output_resource_cm_2) + .unwrap(); + let output_resource_application_logic_2 = + TrivialResourceLogicCircuit::new(output_resource_2, output_resource_path_2); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(output_resource_application_logic_2.to_bytecode(), vec![]) }; // construct ptx diff --git a/taiga_halo2/src/transparent_ptx.rs b/taiga_halo2/src/transparent_ptx.rs index 4a629a21..f479d337 100644 --- a/taiga_halo2/src/transparent_ptx.rs +++ b/taiga_halo2/src/transparent_ptx.rs @@ -47,9 +47,10 @@ impl Executable for TransparentPartialTransaction { // check resource logics, nullifiers, and resource commitments let compliance_nfs = self.get_nullifiers(); let compliance_cms = self.get_output_cms(); + let compliance_resource_merkle_root = self.get_resource_merkle_root(); for (resource_logic, nf) in self.input_resource_app.iter().zip(compliance_nfs.iter()) { let self_resource_id = - resource_logic.verify_transparently(&compliance_nfs, &compliance_cms)?; + resource_logic.verify_transparently(&compliance_resource_merkle_root)?; // Make sure all resource logics are checked if self_resource_id != nf.inner() { return Err(TransactionError::InconsistentSelfResourceID); @@ -58,7 +59,7 @@ impl Executable for TransparentPartialTransaction { for (resource_logic, cm) in self.output_resource_app.iter().zip(compliance_cms.iter()) { let self_resource_id = - resource_logic.verify_transparently(&compliance_nfs, &compliance_cms)?; + resource_logic.verify_transparently(&compliance_resource_merkle_root)?; // Make sure all resource logics are checked if self_resource_id != cm.inner() { return Err(TransactionError::InconsistentSelfResourceID); @@ -99,11 +100,6 @@ impl Executable for TransparentPartialTransaction { .map(|compliance| compliance.calculate_root()) .collect() } - - // We don't need it for transparent ptxs - fn get_resource_merkle_root(&self) -> pallas::Base { - unimplemented!() - } } #[cfg(test)] @@ -112,7 +108,8 @@ pub mod testing { use crate::{ circuit::resource_logic_examples::TrivialResourceLogicCircuit, constant::TAIGA_COMMITMENT_TREE_DEPTH, merkle_tree::MerklePath, - resource::tests::random_resource, transparent_ptx::*, + resource::tests::random_resource, resource_tree::ResourceMerkleTreeLeaves, + transparent_ptx::*, }; use rand::rngs::OsRng; @@ -151,45 +148,57 @@ pub mod testing { &mut rng, ); + // Collect resource merkle leaves + let input_resource_nf_1 = input_resource_1.get_nf().unwrap().inner(); + let output_resource_cm_1 = output_resource_1.commitment().inner(); + let input_resource_nf_2 = input_resource_2.get_nf().unwrap().inner(); + let output_resource_cm_2 = output_resource_2.commitment().inner(); + let resource_merkle_tree = ResourceMerkleTreeLeaves::new(vec![ + input_resource_nf_1, + output_resource_cm_1, + input_resource_nf_2, + output_resource_cm_2, + ]); + // construct applications let input_resource_1_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - input_resource_1.get_nf().unwrap().inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let input_resource_path_1 = resource_merkle_tree + .generate_path(input_resource_nf_1) + .unwrap(); + let input_resource_application_logic_1 = + TrivialResourceLogicCircuit::new(input_resource_1, input_resource_path_1); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(input_resource_application_logic_1.to_bytecode(), vec![]) }; let input_resource_2_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - input_resource_2.get_nf().unwrap().inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let input_resource_path_2 = resource_merkle_tree + .generate_path(input_resource_nf_2) + .unwrap(); + let input_resource_application_logic_2 = + TrivialResourceLogicCircuit::new(input_resource_2, input_resource_path_2); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(input_resource_application_logic_2.to_bytecode(), vec![]) }; let output_resource_1_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - output_resource_1.commitment().inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let output_resource_path_1 = resource_merkle_tree + .generate_path(output_resource_cm_1) + .unwrap(); + let output_resource_application_logic_1 = + TrivialResourceLogicCircuit::new(output_resource_1, output_resource_path_1); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(output_resource_application_logic_1.to_bytecode(), vec![]) }; let output_resource_2_app = { - let app_resource_logic = TrivialResourceLogicCircuit::new( - output_resource_2.commitment().inner(), - [input_resource_1, input_resource_2], - [output_resource_1, output_resource_2], - ); + let output_resource_path_2 = resource_merkle_tree + .generate_path(output_resource_cm_2) + .unwrap(); + let output_resource_application_logic_2 = + TrivialResourceLogicCircuit::new(output_resource_2, output_resource_path_2); - ApplicationByteCode::new(app_resource_logic.to_bytecode(), vec![]) + ApplicationByteCode::new(output_resource_application_logic_2.to_bytecode(), vec![]) }; TransparentPartialTransaction::new(