From 5452c0ac21e4a117a5950f349208f48586948716 Mon Sep 17 00:00:00 2001 From: Xuyang Song Date: Mon, 26 Aug 2024 20:17:13 +0800 Subject: [PATCH] update the token exmaple --- taiga_halo2/Cargo.toml | 2 +- taiga_halo2/examples/tx_examples/main.rs | 12 +- taiga_halo2/examples/tx_examples/token.rs | 84 +++----- .../src/circuit/resource_logic_bytecode.rs | 48 ++--- .../src/circuit/resource_logic_examples.rs | 10 +- .../resource_logic_examples/field_addition.rs | 2 +- .../receiver_resource_logic.rs | 199 +++++------------- .../signature_verification.rs | 128 +++-------- .../circuit/resource_logic_examples/token.rs | 170 +++++---------- taiga_halo2/src/constant.rs | 11 +- taiga_halo2/src/resource_tree.rs | 47 +++++ taiga_halo2/src/shielded_ptx.rs | 102 ++------- taiga_halo2/src/transparent_ptx.rs | 9 +- 13 files changed, 269 insertions(+), 555 deletions(-) diff --git a/taiga_halo2/Cargo.toml b/taiga_halo2/Cargo.toml index 7266d5fd..7cdca7e8 100644 --- a/taiga_halo2/Cargo.toml +++ b/taiga_halo2/Cargo.toml @@ -47,7 +47,7 @@ name = "tx_examples" required-features = ["examples"] [features] -default = ["serde", "examples"] +default = ["serde"] nif = ["dep:rustler", "borsh", "pasta_curves/repr-erlang"] serde = ["dep:serde", "pasta_curves/serde"] borsh = ["dep:borsh"] diff --git a/taiga_halo2/examples/tx_examples/main.rs b/taiga_halo2/examples/tx_examples/main.rs index e0cf8fb7..dec144be 100644 --- a/taiga_halo2/examples/tx_examples/main.rs +++ b/taiga_halo2/examples/tx_examples/main.rs @@ -1,6 +1,6 @@ -mod partial_fulfillment_token_swap; +// mod partial_fulfillment_token_swap; mod token; -mod token_swap_with_intent; +// mod token_swap_with_intent; mod token_swap_without_intent; fn main() { use rand::rngs::OsRng; @@ -9,9 +9,9 @@ fn main() { let tx = token_swap_without_intent::create_token_swap_transaction(rng); tx.execute().unwrap(); - let tx = token_swap_with_intent::create_token_swap_intent_transaction(rng); - tx.execute().unwrap(); + // let tx = token_swap_with_intent::create_token_swap_intent_transaction(rng); + // tx.execute().unwrap(); - let tx = partial_fulfillment_token_swap::create_token_swap_transaction(rng); - tx.execute().unwrap(); + // let tx = partial_fulfillment_token_swap::create_token_swap_transaction(rng); + // tx.execute().unwrap(); } diff --git a/taiga_halo2/examples/tx_examples/token.rs b/taiga_halo2/examples/tx_examples/token.rs index 5a6c74bd..9352c8e1 100644 --- a/taiga_halo2/examples/tx_examples/token.rs +++ b/taiga_halo2/examples/tx_examples/token.rs @@ -1,5 +1,3 @@ -use halo2_proofs::arithmetic::Field; - use pasta_curves::pallas; use rand::RngCore; @@ -10,8 +8,8 @@ use taiga_halo2::{ }, compliance::ComplianceInfo, constant::TAIGA_COMMITMENT_TREE_DEPTH, - merkle_tree::{Anchor, MerklePath}, - resource::{Resource, ResourceLogics}, + merkle_tree::MerklePath, + resource_tree::ResourceMerkleTreeLeaves, shielded_ptx::ShieldedPartialTransaction, }; @@ -36,10 +34,6 @@ pub fn create_token_swap_ptx( let mut output_resource = output_token.create_random_output_token_resource(&mut rng, output_npk, &output_auth); - // padding the zero resources - let padding_input_resource = Resource::random_padding_resource(&mut rng); - let mut padding_output_resource = Resource::random_padding_resource(&mut rng); - // Generate proving info let merkle_path = MerklePath::random(&mut rng, TAIGA_COMMITMENT_TREE_DEPTH); @@ -53,66 +47,42 @@ pub fn create_token_swap_ptx( &mut rng, ); - // Fetch a valid anchor for padding input resources - let anchor = Anchor::from(pallas::Base::random(&mut rng)); - let compliance_2 = ComplianceInfo::new( - padding_input_resource, - merkle_path, - Some(anchor), - &mut padding_output_resource, - &mut rng, - ); - vec![compliance_1, compliance_2] + vec![compliance_1] }; - // Create resource logics - let (input_resource_logics, output_resource_logics) = { - let input_resources = [*input_resource.resource(), padding_input_resource]; - let output_resources = [*output_resource.resource(), padding_output_resource]; - // Create resource_logics for the input token - let input_token_resource_logics = input_resource.generate_input_token_resource_logics( + // Collect resource merkle leaves + let input_resource_nf_1 = input_resource.get_nf().unwrap().inner(); + let output_resource_cm_1 = output_resource.commitment().inner(); + let resource_merkle_tree = + ResourceMerkleTreeLeaves::new(vec![input_resource_nf_1, output_resource_cm_1]); + + // Create resource logics for the input resource + + let input_token_resource_logics = { + let merkle_path = resource_merkle_tree + .generate_path(input_resource_nf_1) + .unwrap(); + input_resource.generate_input_token_resource_logics( &mut rng, input_auth, input_auth_sk, - input_resources, - output_resources, - ); - - // Create resource logics for the output token - let output_token_resource_logics = output_resource.generate_output_token_resource_logics( - &mut rng, - output_auth, - input_resources, - output_resources, - ); - - // Create resource logics for the padding input - let padding_input_resource_logics = - ResourceLogics::create_input_padding_resource_resource_logics( - &padding_input_resource, - input_resources, - output_resources, - ); - - // Create resource logics for the padding output - let padding_output_resource_logics = - ResourceLogics::create_output_padding_resource_resource_logics( - &padding_output_resource, - input_resources, - output_resources, - ); - - ( - vec![input_token_resource_logics, padding_input_resource_logics], - vec![output_token_resource_logics, padding_output_resource_logics], + merkle_path, ) }; + // Create resource logics for the output resource + let output_token_resource_logics = { + let merkle_path = resource_merkle_tree + .generate_path(output_resource_cm_1) + .unwrap(); + output_resource.generate_output_token_resource_logics(&mut rng, output_auth, merkle_path) + }; + // Create shielded partial tx ShieldedPartialTransaction::build( compliances, - input_resource_logics, - output_resource_logics, + vec![input_token_resource_logics], + vec![output_token_resource_logics], vec![], &mut rng, ) diff --git a/taiga_halo2/src/circuit/resource_logic_bytecode.rs b/taiga_halo2/src/circuit/resource_logic_bytecode.rs index c5a3bb26..c80d046b 100644 --- a/taiga_halo2/src/circuit/resource_logic_bytecode.rs +++ b/taiga_halo2/src/circuit/resource_logic_bytecode.rs @@ -2,8 +2,8 @@ use crate::circuit::resource_logic_examples::TrivialResourceLogicCircuit; #[cfg(feature = "examples")] use crate::circuit::resource_logic_examples::{ - or_relation_intent::OrRelationIntentResourceLogicCircuit, - partial_fulfillment_intent::PartialFulfillmentIntentResourceLogicCircuit, + // or_relation_intent::OrRelationIntentResourceLogicCircuit, + // partial_fulfillment_intent::PartialFulfillmentIntentResourceLogicCircuit, receiver_resource_logic::ReceiverResourceLogicCircuit, signature_verification::SignatureVerificationResourceLogicCircuit, token::TokenResourceLogicCircuit, @@ -101,17 +101,17 @@ impl ResourceLogicByteCode { let resource_logic = ReceiverResourceLogicCircuit::from_bytes(&self.inputs); Ok(resource_logic.get_verifying_info()) } - #[cfg(feature = "examples")] - ResourceLogicRepresentation::PartialFulfillmentIntent => { - let resource_logic = - PartialFulfillmentIntentResourceLogicCircuit::from_bytes(&self.inputs); - Ok(resource_logic.get_verifying_info()) - } - #[cfg(feature = "examples")] - ResourceLogicRepresentation::OrRelationIntent => { - let resource_logic = OrRelationIntentResourceLogicCircuit::from_bytes(&self.inputs); - Ok(resource_logic.get_verifying_info()) - } + // #[cfg(feature = "examples")] + // ResourceLogicRepresentation::PartialFulfillmentIntent => { + // let resource_logic = + // PartialFulfillmentIntentResourceLogicCircuit::from_bytes(&self.inputs); + // Ok(resource_logic.get_verifying_info()) + // } + // #[cfg(feature = "examples")] + // ResourceLogicRepresentation::OrRelationIntent => { + // let resource_logic = OrRelationIntentResourceLogicCircuit::from_bytes(&self.inputs); + // Ok(resource_logic.get_verifying_info()) + // } #[allow(unreachable_patterns)] _ => Err(TransactionError::InvalidResourceLogicRepresentation), } @@ -157,17 +157,17 @@ impl ResourceLogicByteCode { let resource_logic = ReceiverResourceLogicCircuit::from_bytes(&self.inputs); resource_logic.verify_transparently()? } - #[cfg(feature = "examples")] - ResourceLogicRepresentation::PartialFulfillmentIntent => { - let resource_logic = - PartialFulfillmentIntentResourceLogicCircuit::from_bytes(&self.inputs); - resource_logic.verify_transparently()? - } - #[cfg(feature = "examples")] - ResourceLogicRepresentation::OrRelationIntent => { - let resource_logic = OrRelationIntentResourceLogicCircuit::from_bytes(&self.inputs); - resource_logic.verify_transparently()? - } + // #[cfg(feature = "examples")] + // ResourceLogicRepresentation::PartialFulfillmentIntent => { + // let resource_logic = + // PartialFulfillmentIntentResourceLogicCircuit::from_bytes(&self.inputs); + // resource_logic.verify_transparently()? + // } + // #[cfg(feature = "examples")] + // ResourceLogicRepresentation::OrRelationIntent => { + // let resource_logic = OrRelationIntentResourceLogicCircuit::from_bytes(&self.inputs); + // resource_logic.verify_transparently()? + // } #[allow(unreachable_patterns)] _ => return Err(TransactionError::InvalidResourceLogicRepresentation), }; diff --git a/taiga_halo2/src/circuit/resource_logic_examples.rs b/taiga_halo2/src/circuit/resource_logic_examples.rs index 17e77170..1abc4bba 100644 --- a/taiga_halo2/src/circuit/resource_logic_examples.rs +++ b/taiga_halo2/src/circuit/resource_logic_examples.rs @@ -33,11 +33,11 @@ mod field_addition; // pub mod or_relation_intent; // #[cfg(feature = "examples")] // pub mod partial_fulfillment_intent; -// #[cfg(feature = "examples")] -// pub mod receiver_resource_logic; -// #[cfg(feature = "examples")] -// pub mod signature_verification; -// #[cfg(feature = "examples")] +#[cfg(feature = "examples")] +pub mod receiver_resource_logic; +#[cfg(feature = "examples")] +pub mod signature_verification; +#[cfg(feature = "examples")] pub mod token; lazy_static! { diff --git a/taiga_halo2/src/circuit/resource_logic_examples/field_addition.rs b/taiga_halo2/src/circuit/resource_logic_examples/field_addition.rs index a9fd7135..6634fe36 100644 --- a/taiga_halo2/src/circuit/resource_logic_examples/field_addition.rs +++ b/taiga_halo2/src/circuit/resource_logic_examples/field_addition.rs @@ -13,7 +13,7 @@ use crate::{ constant::{RESOURCE_LOGIC_CIRCUIT_CUSTOM_PUBLIC_INPUT_BEGIN_IDX, SETUP_PARAMS_MAP}, error::TransactionError, proof::Proof, - resource::{RandomSeed, Resource}, + resource::RandomSeed, resource_logic_commitment::ResourceLogicCommitment, resource_logic_vk::ResourceLogicVerifyingKey, resource_tree::ResourceExistenceWitness, diff --git a/taiga_halo2/src/circuit/resource_logic_examples/receiver_resource_logic.rs b/taiga_halo2/src/circuit/resource_logic_examples/receiver_resource_logic.rs index fe55d0f9..3d5fd15a 100644 --- a/taiga_halo2/src/circuit/resource_logic_examples/receiver_resource_logic.rs +++ b/taiga_halo2/src/circuit/resource_logic_examples/receiver_resource_logic.rs @@ -1,25 +1,23 @@ use crate::{ circuit::{ blake2s::publicize_default_dynamic_resource_logic_commitments, - gadgets::{ - add::AddChip, assign_free_advice, poseidon_hash::poseidon_hash_gadget, - target_resource_variable::get_owned_resource_variable, - }, + gadgets::{add::AddChip, assign_free_advice, poseidon_hash::poseidon_hash_gadget}, resource_encryption_circuit::resource_encryption_gadget, resource_logic_bytecode::{ResourceLogicByteCode, ResourceLogicRepresentation}, resource_logic_circuit::{ - BasicResourceLogicVariables, ResourceLogicCircuit, ResourceLogicConfig, - ResourceLogicPublicInputs, ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, + ResourceLogicCircuit, ResourceLogicConfig, ResourceLogicPublicInputs, + ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, ResourceStatus, }, resource_logic_examples::signature_verification::COMPRESSED_TOKEN_AUTH_VK, }, - constant::{GENERATOR, NUM_RESOURCE, SETUP_PARAMS_MAP}, + constant::{GENERATOR, SETUP_PARAMS_MAP}, error::TransactionError, proof::Proof, - resource::{RandomSeed, Resource}, + resource::RandomSeed, resource_encryption::{ResourceCiphertext, ResourcePlaintext, SecretKey}, resource_logic_commitment::ResourceLogicCommitment, resource_logic_vk::ResourceLogicVerifyingKey, + resource_tree::ResourceExistenceWitness, utils::{mod_r_p, read_base_field, read_point}, }; use borsh::{BorshDeserialize, BorshSerialize}; @@ -46,9 +44,7 @@ lazy_static! { // ReceiverResourceLogicCircuit is used in the token resource_logic as dynamic resource_logic and contains the resource encryption constraints. #[derive(Clone, Debug)] pub struct ReceiverResourceLogicCircuit { - pub self_resource_id: pallas::Base, - pub input_resources: [Resource; NUM_RESOURCE], - pub output_resources: [Resource; NUM_RESOURCE], + pub self_resource: ResourceExistenceWitness, pub resource_logic_vk: pallas::Base, pub encrypt_nonce: pallas::Base, pub sk: pallas::Base, @@ -73,9 +69,7 @@ impl ReceiverResourceLogicCircuit { impl Default for ReceiverResourceLogicCircuit { fn default() -> Self { Self { - self_resource_id: pallas::Base::zero(), - input_resources: [(); NUM_RESOURCE].map(|_| Resource::default()), - output_resources: [(); NUM_RESOURCE].map(|_| Resource::default()), + self_resource: ResourceExistenceWitness::default(), resource_logic_vk: pallas::Base::zero(), encrypt_nonce: pallas::Base::zero(), sk: pallas::Base::zero(), @@ -91,7 +85,7 @@ impl ResourceLogicCircuit for ReceiverResourceLogicCircuit { &self, config: Self::Config, mut layouter: impl Layouter, - basic_variables: BasicResourceLogicVariables, + self_resource: ResourceStatus, ) -> Result<(), Error> { let encrypt_nonce = assign_free_advice( layouter.namespace(|| "witness encrypt_nonce"), @@ -114,14 +108,6 @@ impl ResourceLogicCircuit for ReceiverResourceLogicCircuit { Value::known(self.rcv_pk.to_affine()), )?; - let self_resource_id = basic_variables.get_self_resource_id(); - let value = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource value"), - &self_resource_id, - &basic_variables.get_value_searchable_pairs(), - )?; - let auth_resource_logic_vk = assign_free_advice( layouter.namespace(|| "witness auth resource_logic vk"), config.advices[0], @@ -147,70 +133,20 @@ impl ResourceLogicCircuit for ReceiverResourceLogicCircuit { layouter.assign_region( || "check value encoding", - |mut region| region.constrain_equal(encoded_value.cell(), value.cell()), - )?; - - // search target resource and get the label - let label = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource label"), - &self_resource_id, - &basic_variables.get_label_searchable_pairs(), - )?; - - // search target resource and get the logic - let logic = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource logic"), - &self_resource_id, - &basic_variables.get_logic_searchable_pairs(), - )?; - - // search target resource and get the quantity - let quantity = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource quantity"), - &self_resource_id, - &basic_variables.get_quantity_searchable_pairs(), - )?; - - let nonce = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource nonce"), - &self_resource_id, - &basic_variables.get_nonce_searchable_pairs(), - )?; - - let npk = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource npk"), - &self_resource_id, - &basic_variables.get_npk_searchable_pairs(), - )?; - - let is_ephemeral = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource is_ephemeral"), - &self_resource_id, - &basic_variables.get_is_ephemeral_searchable_pairs(), - )?; - - let rseed = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource rseed"), - &self_resource_id, - &basic_variables.get_rseed_searchable_pairs(), + |mut region| { + region.constrain_equal(encoded_value.cell(), self_resource.resource.value.cell()) + }, )?; let mut message = vec![ - logic, - label, - value, - quantity, - nonce, - npk, - is_ephemeral, - rseed, + self_resource.resource.logic, + self_resource.resource.label, + self_resource.resource.value, + self_resource.resource.quantity, + self_resource.resource.nonce, + self_resource.resource.npk, + self_resource.resource.is_ephemeral, + self_resource.resource.rseed, ]; let add_chip = AddChip::::construct(config.add_config.clone(), ()); @@ -239,14 +175,6 @@ impl ResourceLogicCircuit for ReceiverResourceLogicCircuit { Ok(()) } - fn get_input_resources(&self) -> &[Resource; NUM_RESOURCE] { - &self.input_resources - } - - fn get_output_resources(&self) -> &[Resource; NUM_RESOURCE] { - &self.output_resources - } - fn get_public_inputs(&self, rng: impl RngCore) -> ResourceLogicPublicInputs { let mut public_inputs = self.get_mandatory_public_inputs(); let default_resource_logic_cm: [pallas::Base; 2] = @@ -259,22 +187,17 @@ impl ResourceLogicCircuit for ReceiverResourceLogicCircuit { &RandomSeed::random(rng), ); public_inputs.extend(custom_public_input_padding.iter()); - assert_eq!(NUM_RESOURCE, 2); - let target_resource = - if self.get_self_resource_id() == self.get_output_resources()[0].commitment().inner() { - self.get_output_resources()[0] - } else { - self.get_output_resources()[1] - }; + + let self_resource = self.self_resource.get_resource(); let message = vec![ - target_resource.kind.logic, - target_resource.kind.label, - target_resource.value, - pallas::Base::from(target_resource.quantity), - target_resource.nonce.inner(), - target_resource.get_npk(), - pallas::Base::from(target_resource.is_ephemeral as u64), - target_resource.rseed, + self_resource.kind.logic, + self_resource.kind.label, + self_resource.value, + pallas::Base::from(self_resource.quantity), + self_resource.nonce.inner(), + self_resource.get_npk(), + pallas::Base::from(self_resource.is_ephemeral as u64), + self_resource.rseed, ]; let plaintext = ResourcePlaintext::padding(&message); let key = SecretKey::from_dh_exchange(&self.rcv_pk, &mod_r_p(self.sk)); @@ -289,8 +212,8 @@ impl ResourceLogicCircuit for ReceiverResourceLogicCircuit { public_inputs.into() } - fn get_self_resource_id(&self) -> pallas::Base { - self.self_resource_id + fn get_self_resource(&self) -> ResourceExistenceWitness { + self.self_resource } } @@ -299,15 +222,7 @@ resource_logic_verifying_info_impl!(ReceiverResourceLogicCircuit); impl BorshSerialize for ReceiverResourceLogicCircuit { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - 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)?; - } - + self.self_resource.serialize(writer)?; writer.write_all(&self.resource_logic_vk.to_repr())?; writer.write_all(&self.encrypt_nonce.to_repr())?; writer.write_all(&self.sk.to_repr())?; @@ -320,22 +235,14 @@ impl BorshSerialize for ReceiverResourceLogicCircuit { impl BorshDeserialize for ReceiverResourceLogicCircuit { fn deserialize_reader(reader: &mut R) -> std::io::Result { - let self_resource_id = 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::>()?; + let self_resource = ResourceExistenceWitness::deserialize_reader(reader)?; let resource_logic_vk = read_base_field(reader)?; let encrypt_nonce = read_base_field(reader)?; let sk = read_base_field(reader)?; let rcv_pk = read_point(reader)?; let auth_resource_logic_vk = read_base_field(reader)?; Ok(Self { - self_resource_id, - input_resources: input_resources.try_into().unwrap(), - output_resources: output_resources.try_into().unwrap(), + self_resource, resource_logic_vk, encrypt_nonce, sk, @@ -347,7 +254,8 @@ impl BorshDeserialize for ReceiverResourceLogicCircuit { #[test] fn test_halo2_receiver_resource_logic_circuit() { - use crate::constant::RESOURCE_LOGIC_CIRCUIT_PARAMS_SIZE; + use crate::constant::{RESOURCE_LOGIC_CIRCUIT_PARAMS_SIZE, TAIGA_RESOURCE_TREE_DEPTH}; + use crate::merkle_tree::LR; use crate::{resource::tests::random_resource, utils::poseidon_hash_n}; use ff::{Field, PrimeField}; use halo2_proofs::dev::MockProver; @@ -355,26 +263,25 @@ fn test_halo2_receiver_resource_logic_circuit() { let mut rng = OsRng; let (circuit, rcv_sk) = { - let input_resources = [(); NUM_RESOURCE].map(|_| random_resource(&mut rng)); - let mut output_resources = [(); NUM_RESOURCE].map(|_| random_resource(&mut rng)); + // Create an output resource + let mut resource = random_resource(&mut rng); let encrypt_nonce = pallas::Base::from_u128(23333u128); let sk = pallas::Base::random(&mut rng); let rcv_sk = pallas::Base::random(&mut rng); let generator = GENERATOR.to_curve(); let rcv_pk = generator * mod_r_p(rcv_sk); let rcv_pk_coord = rcv_pk.to_affine().coordinates().unwrap(); - output_resources[0].value = poseidon_hash_n([ + resource.value = poseidon_hash_n([ *rcv_pk_coord.x(), *rcv_pk_coord.y(), *COMPRESSED_TOKEN_AUTH_VK, *COMPRESSED_RECEIVER_VK, ]); - let self_resource_id = output_resources[0].commitment().inner(); + let merkle_path = [(pallas::Base::zero(), LR::L); TAIGA_RESOURCE_TREE_DEPTH]; + let self_resource = ResourceExistenceWitness::new(resource, merkle_path); ( ReceiverResourceLogicCircuit { - self_resource_id, - input_resources, - output_resources, + self_resource, resource_logic_vk: *COMPRESSED_RECEIVER_VK, encrypt_nonce, sk, @@ -402,18 +309,16 @@ fn test_halo2_receiver_resource_logic_circuit() { assert_eq!(prover.verify(), Ok(())); let de_cipher = public_inputs.decrypt(rcv_sk).unwrap(); - assert_eq!(de_cipher[0], circuit.output_resources[0].get_logic()); - assert_eq!(de_cipher[1], circuit.output_resources[0].get_label()); - assert_eq!(de_cipher[2], circuit.output_resources[0].value); - assert_eq!( - de_cipher[3], - pallas::Base::from(circuit.output_resources[0].quantity) - ); - assert_eq!(de_cipher[4], circuit.output_resources[0].nonce.inner()); - assert_eq!(de_cipher[5], circuit.output_resources[0].get_npk()); + let original_resource = circuit.self_resource.get_resource(); + assert_eq!(de_cipher[0], original_resource.get_logic()); + assert_eq!(de_cipher[1], original_resource.get_label()); + assert_eq!(de_cipher[2], original_resource.value); + assert_eq!(de_cipher[3], pallas::Base::from(original_resource.quantity)); + assert_eq!(de_cipher[4], original_resource.nonce.inner()); + assert_eq!(de_cipher[5], original_resource.get_npk()); assert_eq!( de_cipher[6], - pallas::Base::from(circuit.output_resources[0].is_ephemeral) + pallas::Base::from(original_resource.is_ephemeral) ); - assert_eq!(de_cipher[7], circuit.output_resources[0].rseed); + assert_eq!(de_cipher[7], original_resource.rseed); } diff --git a/taiga_halo2/src/circuit/resource_logic_examples/signature_verification.rs b/taiga_halo2/src/circuit/resource_logic_examples/signature_verification.rs index 3c5c2976..3ce98ea6 100644 --- a/taiga_halo2/src/circuit/resource_logic_examples/signature_verification.rs +++ b/taiga_halo2/src/circuit/resource_logic_examples/signature_verification.rs @@ -1,22 +1,20 @@ use crate::{ circuit::{ blake2s::publicize_default_dynamic_resource_logic_commitments, - gadgets::{ - assign_free_advice, poseidon_hash::poseidon_hash_gadget, - target_resource_variable::get_owned_resource_variable, - }, + gadgets::{assign_free_advice, poseidon_hash::poseidon_hash_gadget}, resource_logic_bytecode::{ResourceLogicByteCode, ResourceLogicRepresentation}, resource_logic_circuit::{ - BasicResourceLogicVariables, ResourceLogicCircuit, ResourceLogicConfig, - ResourceLogicPublicInputs, ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, + ResourceLogicCircuit, ResourceLogicConfig, ResourceLogicPublicInputs, + ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, ResourceStatus, }, }, - constant::{TaigaFixedBasesFull, NUM_RESOURCE, SETUP_PARAMS_MAP}, + constant::{TaigaFixedBasesFull, SETUP_PARAMS_MAP}, error::TransactionError, proof::Proof, - resource::{RandomSeed, Resource}, + resource::RandomSeed, resource_logic_commitment::ResourceLogicCommitment, resource_logic_vk::ResourceLogicVerifyingKey, + resource_tree::ResourceExistenceWitness, utils::{mod_r_p, poseidon_hash_n, read_base_field, read_point, read_scalar_field}, }; use borsh::{BorshDeserialize, BorshSerialize}; @@ -35,8 +33,8 @@ use pasta_curves::{ use rand::rngs::OsRng; use rand::RngCore; -// The message contains the input resource nullifiers and output resource commitments -const MESSAGE_LEN: usize = NUM_RESOURCE * 2; +// Use the merkle root as message. +const MESSAGE_LEN: usize = 1; const POSEIDON_HASH_LEN: usize = MESSAGE_LEN + 4; lazy_static! { pub static ref TOKEN_AUTH_VK: ResourceLogicVerifyingKey = @@ -45,6 +43,7 @@ lazy_static! { } #[derive(Clone, Debug)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SchnorrSignature { // public key pk: pallas::Point, @@ -82,9 +81,6 @@ impl SchnorrSignature { *pk_coord.x(), *pk_coord.y(), message[0], - message[1], - message[2], - message[3], ])); let s = z + h * sk; Self { pk, r, s } @@ -93,10 +89,9 @@ impl SchnorrSignature { // SignatureVerificationResourceLogicCircuit uses the schnorr signature. #[derive(Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SignatureVerificationResourceLogicCircuit { - pub self_resource_id: pallas::Base, - pub input_resources: [Resource; NUM_RESOURCE], - pub output_resources: [Resource; NUM_RESOURCE], + pub self_resource: ResourceExistenceWitness, pub resource_logic_vk: pallas::Base, pub signature: SchnorrSignature, pub receiver_resource_logic_vk: pallas::Base, @@ -104,17 +99,13 @@ pub struct SignatureVerificationResourceLogicCircuit { impl SignatureVerificationResourceLogicCircuit { pub fn new( - self_resource_id: pallas::Base, - input_resources: [Resource; NUM_RESOURCE], - output_resources: [Resource; NUM_RESOURCE], + self_resource: ResourceExistenceWitness, resource_logic_vk: pallas::Base, signature: SchnorrSignature, receiver_resource_logic_vk: pallas::Base, ) -> Self { Self { - self_resource_id, - input_resources, - output_resources, + self_resource, resource_logic_vk, signature, receiver_resource_logic_vk, @@ -123,29 +114,15 @@ impl SignatureVerificationResourceLogicCircuit { pub fn from_sk_and_sign( mut rng: R, - self_resource_id: pallas::Base, - input_resources: [Resource; NUM_RESOURCE], - output_resources: [Resource; NUM_RESOURCE], + self_resource: ResourceExistenceWitness, resource_logic_vk: pallas::Base, sk: pallas::Scalar, receiver_resource_logic_vk: pallas::Base, ) -> Self { - assert_eq!(NUM_RESOURCE, 2); - let mut message = vec![]; - input_resources - .iter() - .zip(output_resources.iter()) - .for_each(|(input_resource, output_resource)| { - let nf = input_resource.get_nf().unwrap().inner(); - message.push(nf); - let cm = output_resource.commitment(); - message.push(cm.inner()); - }); + let message = vec![self_resource.get_root()]; let signature = SchnorrSignature::sign(&mut rng, sk, message); Self { - self_resource_id, - input_resources, - output_resources, + self_resource, resource_logic_vk, signature, receiver_resource_logic_vk, @@ -174,7 +151,7 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { &self, config: Self::Config, mut layouter: impl Layouter, - basic_variables: BasicResourceLogicVariables, + self_resource: ResourceStatus, ) -> Result<(), Error> { // Construct an ECC chip let ecc_chip = EccChip::construct(config.ecc_config); @@ -185,15 +162,6 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { Value::known(self.signature.pk.to_affine()), )?; - // search target resource and get the value - let self_resource_id = basic_variables.get_self_resource_id(); - let value = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource value"), - &self_resource_id, - &basic_variables.get_value_searchable_pairs(), - )?; - let auth_resource_logic_vk = assign_free_advice( layouter.namespace(|| "witness auth resource_logic vk"), config.advices[0], @@ -219,7 +187,9 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { layouter.assign_region( || "check value encoding", - |mut region| region.constrain_equal(encoded_value.cell(), value.cell()), + |mut region| { + region.constrain_equal(encoded_value.cell(), self_resource.resource.value.cell()) + }, )?; let r = NonIdentityPoint::new( @@ -241,9 +211,6 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { // Hash(r||P||m) let h_scalar = { - let nfs = basic_variables.get_input_resource_nfs(); - let cms = basic_variables.get_output_resource_cms(); - assert_eq!(NUM_RESOURCE, 2); let h = poseidon_hash_gadget( config.poseidon_config, layouter.namespace(|| "Poseidon_hash(r, P, m)"), @@ -252,10 +219,7 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { r.inner().y(), pk.inner().x(), pk.inner().y(), - nfs[0].clone(), - cms[0].clone(), - nfs[1].clone(), - cms[1].clone(), + self_resource.resource_merkle_root, ], )?; @@ -280,14 +244,6 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { Ok(()) } - fn get_input_resources(&self) -> &[Resource; NUM_RESOURCE] { - &self.input_resources - } - - fn get_output_resources(&self) -> &[Resource; NUM_RESOURCE] { - &self.output_resources - } - fn get_public_inputs(&self, mut rng: impl RngCore) -> ResourceLogicPublicInputs { let mut public_inputs = self.get_mandatory_public_inputs(); let default_resource_logic_cm: [pallas::Base; 2] = @@ -302,8 +258,8 @@ impl ResourceLogicCircuit for SignatureVerificationResourceLogicCircuit { public_inputs.into() } - fn get_self_resource_id(&self) -> pallas::Base { - self.self_resource_id + fn get_self_resource(&self) -> ResourceExistenceWitness { + self.self_resource } } @@ -312,15 +268,7 @@ resource_logic_verifying_info_impl!(SignatureVerificationResourceLogicCircuit); impl BorshSerialize for SignatureVerificationResourceLogicCircuit { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - 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)?; - } - + self.self_resource.serialize(writer)?; writer.write_all(&self.resource_logic_vk.to_repr())?; self.signature.serialize(writer)?; writer.write_all(&self.receiver_resource_logic_vk.to_repr())?; @@ -331,20 +279,12 @@ impl BorshSerialize for SignatureVerificationResourceLogicCircuit { impl BorshDeserialize for SignatureVerificationResourceLogicCircuit { fn deserialize_reader(reader: &mut R) -> std::io::Result { - let self_resource_id = 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::>()?; + let self_resource = ResourceExistenceWitness::deserialize_reader(reader)?; let resource_logic_vk = read_base_field(reader)?; let signature = SchnorrSignature::deserialize_reader(reader)?; let receiver_resource_logic_vk = read_base_field(reader)?; Ok(Self { - self_resource_id, - input_resources: input_resources.try_into().unwrap(), - output_resources: output_resources.try_into().unwrap(), + self_resource, resource_logic_vk, signature, receiver_resource_logic_vk, @@ -376,25 +316,25 @@ fn test_halo2_sig_verification_resource_logic_circuit() { use crate::circuit::resource_logic_examples::{ receiver_resource_logic::COMPRESSED_RECEIVER_VK, token::TokenAuthorization, }; - use crate::constant::RESOURCE_LOGIC_CIRCUIT_PARAMS_SIZE; + use crate::constant::{RESOURCE_LOGIC_CIRCUIT_PARAMS_SIZE, TAIGA_RESOURCE_TREE_DEPTH}; + use crate::merkle_tree::LR; use crate::resource::tests::random_resource; use halo2_proofs::dev::MockProver; use rand::rngs::OsRng; let mut rng = OsRng; let circuit = { - let mut input_resources = [(); NUM_RESOURCE].map(|_| random_resource(&mut rng)); - let output_resources = [(); NUM_RESOURCE].map(|_| random_resource(&mut rng)); + // Create an input resource + let mut resource = random_resource(&mut rng); let sk = pallas::Scalar::random(&mut rng); let auth_vk = pallas::Base::random(&mut rng); let auth = TokenAuthorization::from_sk_vk(&sk, &auth_vk); - input_resources[0].value = auth.to_value(); - let self_resource_id = input_resources[0].get_nf().unwrap().inner(); + resource.value = auth.to_value(); + let merkle_path = [(pallas::Base::zero(), LR::R); TAIGA_RESOURCE_TREE_DEPTH]; + let resource_witness = ResourceExistenceWitness::new(resource, merkle_path); SignatureVerificationResourceLogicCircuit::from_sk_and_sign( &mut rng, - self_resource_id, - input_resources, - output_resources, + resource_witness, auth_vk, sk, *COMPRESSED_RECEIVER_VK, diff --git a/taiga_halo2/src/circuit/resource_logic_examples/token.rs b/taiga_halo2/src/circuit/resource_logic_examples/token.rs index bcd1224f..cbed5492 100644 --- a/taiga_halo2/src/circuit/resource_logic_examples/token.rs +++ b/taiga_halo2/src/circuit/resource_logic_examples/token.rs @@ -1,15 +1,11 @@ use crate::{ circuit::{ blake2s::{resource_logic_commitment_gadget, Blake2sChip}, - gadgets::{ - assign_free_advice, assign_free_constant, - poseidon_hash::poseidon_hash_gadget, - target_resource_variable::{get_is_input_resource_flag, get_owned_resource_variable}, - }, + gadgets::{assign_free_advice, assign_free_constant, poseidon_hash::poseidon_hash_gadget}, resource_logic_bytecode::{ResourceLogicByteCode, ResourceLogicRepresentation}, resource_logic_circuit::{ - BasicResourceLogicVariables, ResourceLogicCircuit, ResourceLogicConfig, - ResourceLogicPublicInputs, ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, + ResourceLogicCircuit, ResourceLogicConfig, ResourceLogicPublicInputs, + ResourceLogicVerifyingInfo, ResourceLogicVerifyingInfoTrait, ResourceStatus, }, resource_logic_examples::receiver_resource_logic::{ ReceiverResourceLogicCircuit, COMPRESSED_RECEIVER_VK, @@ -19,18 +15,21 @@ use crate::{ }, }, constant::{ - NUM_RESOURCE, PRF_EXPAND_DYNAMIC_RESOURCE_LOGIC_1_CM_R, + PRF_EXPAND_DYNAMIC_RESOURCE_LOGIC_1_CM_R, RESOURCE_LOGIC_CIRCUIT_FIRST_DYNAMIC_RESOURCE_LOGIC_CM_1, RESOURCE_LOGIC_CIRCUIT_FIRST_DYNAMIC_RESOURCE_LOGIC_CM_2, RESOURCE_LOGIC_CIRCUIT_SECOND_DYNAMIC_RESOURCE_LOGIC_CM_1, RESOURCE_LOGIC_CIRCUIT_SECOND_DYNAMIC_RESOURCE_LOGIC_CM_2, SETUP_PARAMS_MAP, + TAIGA_RESOURCE_TREE_DEPTH, }, error::TransactionError, + merkle_tree::LR, nullifier::Nullifier, proof::Proof, resource::{RandomSeed, Resource, ResourceLogics}, resource_logic_commitment::ResourceLogicCommitment, resource_logic_vk::ResourceLogicVerifyingKey, + resource_tree::ResourceExistenceWitness, utils::{poseidon_hash_n, read_base_field, read_point}, }; use borsh::{BorshDeserialize, BorshSerialize}; @@ -187,20 +186,13 @@ impl TokenResource { mut rng: R, auth: TokenAuthorization, auth_sk: pallas::Scalar, - input_resources: [Resource; NUM_RESOURCE], - output_resources: [Resource; NUM_RESOURCE], + merkle_path: [(pallas::Base, LR); TAIGA_RESOURCE_TREE_DEPTH], ) -> ResourceLogics { - let TokenResource { - token_name, - resource, - } = self; // token resource logic - let nf = resource.get_nf().unwrap().inner(); + let self_resource = ResourceExistenceWitness::new(self.resource, merkle_path); let token_resource_logic = TokenResourceLogicCircuit { - self_resource_id: nf, - input_resources, - output_resources, - token_name: token_name.clone(), + self_resource, + token_name: self.token_name.clone(), auth, receiver_resource_logic_vk: *COMPRESSED_RECEIVER_VK, rseed: RandomSeed::random(&mut rng), @@ -209,9 +201,7 @@ impl TokenResource { // token auth resource logic let token_auth_resource_logic = SignatureVerificationResourceLogicCircuit::from_sk_and_sign( &mut rng, - nf, - input_resources, - output_resources, + self_resource, auth.vk, auth_sk, *COMPRESSED_RECEIVER_VK, @@ -227,21 +217,12 @@ impl TokenResource { &self, mut rng: R, auth: TokenAuthorization, - input_resources: [Resource; NUM_RESOURCE], - output_resources: [Resource; NUM_RESOURCE], + merkle_path: [(pallas::Base, LR); TAIGA_RESOURCE_TREE_DEPTH], ) -> ResourceLogics { - let TokenResource { - token_name, - resource, - } = self; - - let self_resource_id = resource.commitment().inner(); - // token resource logic + let self_resource = ResourceExistenceWitness::new(self.resource, merkle_path); let token_resource_logic = TokenResourceLogicCircuit { - self_resource_id, - input_resources, - output_resources, - token_name: token_name.clone(), + self_resource, + token_name: self.token_name.clone(), auth, receiver_resource_logic_vk: *COMPRESSED_RECEIVER_VK, rseed: RandomSeed::random(&mut rng), @@ -249,9 +230,7 @@ impl TokenResource { // receiver resource logic let receiver_resource_logic = ReceiverResourceLogicCircuit { - self_resource_id, - input_resources, - output_resources, + self_resource, resource_logic_vk: *COMPRESSED_RECEIVER_VK, encrypt_nonce: pallas::Base::from_u128(rng.gen()), sk: pallas::Base::random(&mut rng), @@ -269,9 +248,7 @@ impl TokenResource { // TokenResourceLogicCircuit #[derive(Clone, Debug)] pub struct TokenResourceLogicCircuit { - pub self_resource_id: pallas::Base, - pub input_resources: [Resource; NUM_RESOURCE], - pub output_resources: [Resource; NUM_RESOURCE], + self_resource: ResourceExistenceWitness, // The token_name goes to label. It can be extended to a list and embedded to label. pub token_name: TokenName, // The auth goes to value and defines how to consume and create the resource. @@ -313,9 +290,7 @@ impl TokenResourceLogicCircuit { impl Default for TokenResourceLogicCircuit { fn default() -> Self { Self { - self_resource_id: pallas::Base::zero(), - input_resources: [(); NUM_RESOURCE].map(|_| Resource::default()), - output_resources: [(); NUM_RESOURCE].map(|_| Resource::default()), + self_resource: ResourceExistenceWitness::default(), token_name: TokenName("Token_name".to_string()), auth: TokenAuthorization::default(), receiver_resource_logic_vk: pallas::Base::zero(), @@ -330,10 +305,8 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { &self, config: Self::Config, mut layouter: impl Layouter, - basic_variables: BasicResourceLogicVariables, + self_resource: ResourceStatus, ) -> Result<(), Error> { - let self_resource_id = basic_variables.get_self_resource_id(); - let token_property = assign_free_advice( layouter.namespace(|| "witness token_property"), config.advices[0], @@ -342,18 +315,12 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { // We can add more constraints on token_property or extend the token_properties. - // search target resource and get the label - let label = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource label"), - &self_resource_id, - &basic_variables.get_label_searchable_pairs(), - )?; - // check label layouter.assign_region( || "check label", - |mut region| region.constrain_equal(token_property.cell(), label.cell()), + |mut region| { + region.constrain_equal(token_property.cell(), self_resource.resource.label.cell()) + }, )?; // Construct an ECC chip @@ -371,14 +338,6 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { Value::known(self.auth.vk), )?; - // search target resource and get the value - let value = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get owned resource value"), - &self_resource_id, - &basic_variables.get_value_searchable_pairs(), - )?; - let receiver_resource_logic_vk = assign_free_advice( layouter.namespace(|| "witness receiver resource_logic vk"), config.advices[0], @@ -399,16 +358,12 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { layouter.assign_region( || "check value encoding", - |mut region| region.constrain_equal(encoded_value.cell(), value.cell()), + |mut region| { + region.constrain_equal(encoded_value.cell(), self_resource.resource.value.cell()) + }, )?; // check the is_ephemeral flag - let is_ephemeral = get_owned_resource_variable( - config.get_owned_resource_variable_config, - layouter.namespace(|| "get is_ephemeral"), - &self_resource_id, - &basic_variables.get_is_ephemeral_searchable_pairs(), - )?; let constant_zero = assign_free_constant( layouter.namespace(|| "zero"), config.advices[0], @@ -416,25 +371,23 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { )?; layouter.assign_region( || "check is_ephemeral", - |mut region| region.constrain_equal(is_ephemeral.cell(), constant_zero.cell()), + |mut region| { + region.constrain_equal( + self_resource.resource.is_ephemeral.cell(), + constant_zero.cell(), + ) + }, )?; // Resource Logic Commitment // Commt the sender(authorization method included) resource_logic if it's an input resource; // Commit the receiver(resource encryption constraints included) resource_logic if it's an output resource. let first_dynamic_resource_logic = { - let is_input_resource = get_is_input_resource_flag( - config.get_is_input_resource_flag_config, - layouter.namespace(|| "get is_input_resource_flag"), - &self_resource_id, - &basic_variables.get_input_resource_nfs(), - &basic_variables.get_output_resource_cms(), - )?; layouter.assign_region( || "conditional select: ", |mut region| { config.conditional_select_config.assign_region( - &is_input_resource, + &self_resource.is_input, &auth_resource_logic_vk, &receiver_resource_logic_vk, 0, @@ -500,23 +453,12 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { Ok(()) } - fn get_input_resources(&self) -> &[Resource; NUM_RESOURCE] { - &self.input_resources - } - - fn get_output_resources(&self) -> &[Resource; NUM_RESOURCE] { - &self.output_resources - } - fn get_public_inputs(&self, mut rng: impl RngCore) -> ResourceLogicPublicInputs { let mut public_inputs = self.get_mandatory_public_inputs(); - let dynamic_resource_logic = if self.self_resource_id - == self.output_resources[0].commitment().inner() - || self.self_resource_id == self.output_resources[1].commitment().inner() - { - self.receiver_resource_logic_vk - } else { + let dynamic_resource_logic = if self.get_self_resource().is_input() { self.auth.vk + } else { + self.receiver_resource_logic_vk }; let resource_logic_com_r = self @@ -538,8 +480,8 @@ impl ResourceLogicCircuit for TokenResourceLogicCircuit { public_inputs.into() } - fn get_self_resource_id(&self) -> pallas::Base { - self.self_resource_id + fn get_self_resource(&self) -> ResourceExistenceWitness { + self.self_resource } } @@ -548,15 +490,7 @@ resource_logic_verifying_info_impl!(TokenResourceLogicCircuit); impl BorshSerialize for TokenResourceLogicCircuit { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { - 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)?; - } - + self.self_resource.serialize(writer)?; self.token_name.serialize(writer)?; self.auth.serialize(writer)?; writer.write_all(&self.receiver_resource_logic_vk.to_repr())?; @@ -568,21 +502,13 @@ impl BorshSerialize for TokenResourceLogicCircuit { impl BorshDeserialize for TokenResourceLogicCircuit { fn deserialize_reader(reader: &mut R) -> std::io::Result { - let self_resource_id = 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::>()?; + let self_resource = ResourceExistenceWitness::deserialize_reader(reader)?; let token_name = TokenName::deserialize_reader(reader)?; let auth = TokenAuthorization::deserialize_reader(reader)?; let receiver_resource_logic_vk = read_base_field(reader)?; let rseed = RandomSeed::deserialize_reader(reader)?; Ok(Self { - self_resource_id, - input_resources: input_resources.try_into().unwrap(), - output_resources: output_resources.try_into().unwrap(), + self_resource, token_name, auth, receiver_resource_logic_vk, @@ -646,16 +572,16 @@ fn test_halo2_token_resource_logic_circuit() { let mut rng = OsRng; let circuit = { - let mut input_resources = [(); NUM_RESOURCE].map(|_| random_resource(&mut rng)); - let output_resources = [(); NUM_RESOURCE].map(|_| random_resource(&mut rng)); + // Create an input resource + let mut resource = random_resource(&mut rng); let token_name = TokenName("Token_name".to_string()); let auth = TokenAuthorization::random(&mut rng); - input_resources[0].kind.label = token_name.encode(); - input_resources[0].value = auth.to_value(); + resource.kind.label = token_name.encode(); + resource.value = auth.to_value(); + let merkle_path = [(pallas::Base::zero(), LR::R); TAIGA_RESOURCE_TREE_DEPTH]; + let self_resource = ResourceExistenceWitness::new(resource, merkle_path); TokenResourceLogicCircuit { - self_resource_id: input_resources[0].get_nf().unwrap().inner(), - input_resources, - output_resources, + self_resource, token_name, auth, receiver_resource_logic_vk: *COMPRESSED_RECEIVER_VK, diff --git a/taiga_halo2/src/constant.rs b/taiga_halo2/src/constant.rs index 7f39a186..152d06bc 100644 --- a/taiga_halo2/src/constant.rs +++ b/taiga_halo2/src/constant.rs @@ -51,9 +51,6 @@ pub const TAIGA_RESOURCE_TREE_LEAVES_NUM: usize = 1 << TAIGA_RESOURCE_TREE_DEPTH pub const BASE_BITS_NUM: usize = 255; -/// The number of resources in a (partial)tx. -pub const NUM_RESOURCE: usize = 2; - pub const COMPLIANCE_NF_PUBLIC_INPUT_ROW_IDX: usize = 0; pub const COMPLIANCE_ANCHOR_PUBLIC_INPUT_ROW_IDX: usize = 1; pub const COMPLIANCE_OUTPUT_CM_PUBLIC_INPUT_ROW_IDX: usize = 2; @@ -89,10 +86,10 @@ pub const RESOURCE_LOGIC_CIRCUIT_CUSTOM_PUBLIC_INPUT_BEGIN_IDX: usize = pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_PUBLIC_INPUT_BEGIN_IDX: usize = RESOURCE_LOGIC_CIRCUIT_MANDATORY_PUBLIC_INPUT_NUM + RESOURCE_LOGIC_CIRCUIT_CUSTOM_PUBLIC_INPUT_NUM; -pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_NONCE_IDX: usize = 21; -pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_MAC_IDX: usize = 22; -pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_PK_X_IDX: usize = 23; -pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_PK_Y_IDX: usize = 24; +pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_NONCE_IDX: usize = 18; +pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_MAC_IDX: usize = 19; +pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_PK_X_IDX: usize = 20; +pub const RESOURCE_LOGIC_CIRCUIT_RESOURCE_ENCRYPTION_PK_Y_IDX: usize = 21; // Resource encryption pub const RESOURCE_ENCRYPTION_PLAINTEXT_NUM: usize = 10; diff --git a/taiga_halo2/src/resource_tree.rs b/taiga_halo2/src/resource_tree.rs index 320626e1..8b61b20c 100644 --- a/taiga_halo2/src/resource_tree.rs +++ b/taiga_halo2/src/resource_tree.rs @@ -4,6 +4,8 @@ use crate::{ resource::Resource, utils::poseidon_hash, }; +#[cfg(feature = "borsh")] +use borsh::{BorshDeserialize, BorshSerialize}; use pasta_curves::pallas; #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] @@ -54,6 +56,51 @@ impl ResourceExistenceWitness { let node = Node::from(id); MerklePath::from(self.get_path()).root(node).inner() } + + // TODO: handle the error + pub fn to_bytes(&self) -> Vec { + bincode::serialize(&self).unwrap() + } + + pub fn from_bytes(bytes: &Vec) -> Self { + bincode::deserialize(bytes).unwrap() + } +} + +#[cfg(feature = "borsh")] +impl BorshSerialize for ResourceExistenceWitness { + fn serialize(&self, writer: &mut W) -> std::io::Result<()> { + use byteorder::WriteBytesExt; + use ff::PrimeField; + self.resource.serialize(writer)?; + for node in self.merkle_path { + writer.write_all(&node.0.to_repr())?; + writer.write_u8(if node.1.is_left() { 1 } else { 0 })?; + } + + Ok(()) + } +} + +#[cfg(feature = "borsh")] +impl BorshDeserialize for ResourceExistenceWitness { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + use crate::utils::read_base_field; + use byteorder::ReadBytesExt; + let resource = Resource::deserialize_reader(reader)?; + let mut path = vec![]; + for _ in 0..TAIGA_RESOURCE_TREE_DEPTH { + let v = read_base_field(reader)?; + let byte = reader.read_u8()?; + let b = if byte == 0x01 { LR::L } else { LR::R }; + path.push((v, b)); + } + + Ok(Self { + resource, + merkle_path: path.try_into().unwrap(), + }) + } } impl ResourceMerkleTreeLeaves { diff --git a/taiga_halo2/src/shielded_ptx.rs b/taiga_halo2/src/shielded_ptx.rs index 8ed315c9..18ed1a98 100644 --- a/taiga_halo2/src/shielded_ptx.rs +++ b/taiga_halo2/src/shielded_ptx.rs @@ -2,7 +2,7 @@ use crate::circuit::resource_logic_circuit::{ResourceLogic, ResourceLogicVerifyi use crate::compliance::{ComplianceInfo, CompliancePublicInputs}; use crate::constant::{ COMPLIANCE_CIRCUIT_PARAMS_SIZE, COMPLIANCE_PROVING_KEY, COMPLIANCE_VERIFYING_KEY, - MAX_DYNAMIC_RESOURCE_LOGIC_NUM, NUM_RESOURCE, SETUP_PARAMS_MAP, + MAX_DYNAMIC_RESOURCE_LOGIC_NUM, SETUP_PARAMS_MAP, }; use crate::delta_commitment::DeltaCommitment; use crate::error::TransactionError; @@ -29,10 +29,12 @@ use ff::PrimeField; #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "nif", derive(NifStruct))] +#[cfg_attr(feature = "nif", module = "Taiga.Shielded.PTX")] pub struct ShieldedPartialTransaction { - compliances: [ComplianceVerifyingInfo; NUM_RESOURCE], - inputs: [ResourceLogicVerifyingInfoSet; NUM_RESOURCE], - outputs: [ResourceLogicVerifyingInfoSet; NUM_RESOURCE], + compliances: Vec, + inputs: Vec, + outputs: Vec, binding_sig_r: Option, hints: Vec, } @@ -59,18 +61,6 @@ pub struct ResourceLogicVerifyingInfoSet { // When the verifier proof is added, we may need to reconsider the structure of `ResourceLogicVerifyingInfo` } -// Is easier to derive traits for -#[derive(Debug, Clone)] -#[cfg_attr(feature = "nif", derive(NifStruct))] -#[cfg_attr(feature = "nif", module = "Taiga.Shielded.PTX")] -struct ShieldedPartialTransactionProxy { - compliances: Vec, - inputs: Vec, - outputs: Vec, - binding_sig_r: Option, - hints: Vec, -} - impl ShieldedPartialTransaction { pub fn from_bytecode( compliances: Vec, @@ -135,9 +125,9 @@ impl ShieldedPartialTransaction { .collect(); Ok(Self { - compliances: compliances.try_into().unwrap(), - inputs: inputs.try_into().unwrap(), - outputs: outputs.try_into().unwrap(), + compliances, + inputs, + outputs, binding_sig_r: Some(rcv_sum), hints, }) @@ -226,17 +216,6 @@ impl ShieldedPartialTransaction { Ok(()) } - // Conversion to the generic length proxy - fn to_proxy(&self) -> ShieldedPartialTransactionProxy { - ShieldedPartialTransactionProxy { - compliances: self.compliances.to_vec(), - inputs: self.inputs.to_vec(), - outputs: self.outputs.to_vec(), - binding_sig_r: self.binding_sig_r, - hints: self.hints.clone(), - } - } - pub fn get_binding_sig_r(&self) -> Option { self.binding_sig_r } @@ -251,21 +230,6 @@ impl ShieldedPartialTransaction { } } -impl ShieldedPartialTransactionProxy { - fn to_concrete(&self) -> Option { - let compliances = self.compliances.clone().try_into().ok()?; - let inputs = self.inputs.clone().try_into().ok()?; - let outputs = self.outputs.clone().try_into().ok()?; - Some(ShieldedPartialTransaction { - compliances, - inputs, - outputs, - binding_sig_r: self.binding_sig_r, - hints: self.hints.clone(), - }) - } -} - impl Executable for ShieldedPartialTransaction { fn execute(&self) -> Result<(), TransactionError> { self.verify_proof()?; @@ -308,17 +272,9 @@ impl Executable for ShieldedPartialTransaction { impl BorshSerialize for ShieldedPartialTransaction { fn serialize(&self, writer: &mut W) -> std::io::Result<()> { use byteorder::WriteBytesExt; - for compliance in self.compliances.iter() { - compliance.serialize(writer)?; - } - - for input in self.inputs.iter() { - input.serialize(writer)?; - } - - for output in self.outputs.iter() { - output.serialize(writer)?; - } + self.compliances.serialize(writer)?; + self.inputs.serialize(writer)?; + self.outputs.serialize(writer)?; // Write binding_sig_r match self.binding_sig_r { @@ -341,15 +297,9 @@ impl BorshSerialize for ShieldedPartialTransaction { impl BorshDeserialize for ShieldedPartialTransaction { fn deserialize_reader(reader: &mut R) -> std::io::Result { use byteorder::ReadBytesExt; - let compliances: Vec<_> = (0..NUM_RESOURCE) - .map(|_| ComplianceVerifyingInfo::deserialize_reader(reader)) - .collect::>()?; - let inputs: Vec<_> = (0..NUM_RESOURCE) - .map(|_| ResourceLogicVerifyingInfoSet::deserialize_reader(reader)) - .collect::>()?; - let outputs: Vec<_> = (0..NUM_RESOURCE) - .map(|_| ResourceLogicVerifyingInfoSet::deserialize_reader(reader)) - .collect::>()?; + let compliances = Vec::::deserialize_reader(reader)?; + let inputs = Vec::::deserialize_reader(reader)?; + let outputs = Vec::::deserialize_reader(reader)?; let binding_sig_r_type = reader.read_u8()?; let binding_sig_r = if binding_sig_r_type == 0 { None @@ -360,31 +310,15 @@ impl BorshDeserialize for ShieldedPartialTransaction { let hints = Vec::::deserialize_reader(reader)?; Ok(ShieldedPartialTransaction { - compliances: compliances.try_into().unwrap(), - inputs: inputs.try_into().unwrap(), - outputs: outputs.try_into().unwrap(), + compliances, + inputs, + outputs, binding_sig_r, hints, }) } } -#[cfg(feature = "nif")] -impl Encoder for ShieldedPartialTransaction { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - self.to_proxy().encode(env) - } -} - -#[cfg(feature = "nif")] -impl<'a> Decoder<'a> for ShieldedPartialTransaction { - fn decode(term: Term<'a>) -> NifResult { - let val: ShieldedPartialTransactionProxy = Decoder::decode(term)?; - val.to_concrete() - .ok_or(rustler::Error::RaiseAtom("Could not decode proxy")) - } -} - impl ComplianceVerifyingInfo { pub fn create(compliance_info: &ComplianceInfo, mut rng: R) -> Result { let (compliance_instance, circuit) = compliance_info.build(); diff --git a/taiga_halo2/src/transparent_ptx.rs b/taiga_halo2/src/transparent_ptx.rs index f479d337..ce38ab31 100644 --- a/taiga_halo2/src/transparent_ptx.rs +++ b/taiga_halo2/src/transparent_ptx.rs @@ -1,8 +1,7 @@ use crate::{ circuit::resource_logic_bytecode::ApplicationByteCode, compliance::ComplianceInfo, - constant::NUM_RESOURCE, delta_commitment::DeltaCommitment, error::TransactionError, - executable::Executable, merkle_tree::Anchor, nullifier::Nullifier, - resource::ResourceCommitment, + delta_commitment::DeltaCommitment, error::TransactionError, executable::Executable, + merkle_tree::Anchor, nullifier::Nullifier, resource::ResourceCommitment, }; use pasta_curves::pallas; @@ -29,10 +28,6 @@ impl TransparentPartialTransaction { output_resource_app: Vec, hints: Vec, ) -> Self { - assert_eq!(compliances.len(), NUM_RESOURCE); - assert_eq!(input_resource_app.len(), NUM_RESOURCE); - assert_eq!(output_resource_app.len(), NUM_RESOURCE); - Self { compliances, input_resource_app,