diff --git a/Cargo.lock b/Cargo.lock index 120c3524..7e0cfe42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -343,6 +343,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm/Cargo.toml b/arm/Cargo.toml index ace9962e..293e7abf 100644 --- a/arm/Cargo.toml +++ b/arm/Cargo.toml @@ -17,6 +17,7 @@ bincode = "1.3.3" hex = "0.4" lazy_static = "1.5.0" rustler = { version = "0.36.2", optional = true } +bytemuck = { version = "1.12", features = ["derive"] } [features] default = ["transaction"] diff --git a/arm/elfs/compliance-guest.bin b/arm/elfs/compliance-guest.bin index 3dd69efc..6355a900 100644 Binary files a/arm/elfs/compliance-guest.bin and b/arm/elfs/compliance-guest.bin differ diff --git a/arm/elfs/trivial-logic-guest.bin b/arm/elfs/trivial-logic-guest.bin index 549e41b8..3deba943 100644 Binary files a/arm/elfs/trivial-logic-guest.bin and b/arm/elfs/trivial-logic-guest.bin differ diff --git a/arm/src/action.rs b/arm/src/action.rs index 810bc00f..8628e276 100644 --- a/arm/src/action.rs +++ b/arm/src/action.rs @@ -4,19 +4,15 @@ use crate::{ compliance_unit::ComplianceUnit, delta_proof::DeltaWitness, logic_proof::{LogicProof, LogicProver}, - merkle_path::Leaf, merkle_path::COMMITMENT_TREE_DEPTH, nullifier_key::NullifierKey, resource::Resource, resource_logic::TrivialLogicWitness, }; use k256::ProjectivePoint; -use serde::{Deserialize, Serialize}; #[cfg(feature = "nif")] -use { - rustler::types::map::map_new, - rustler::{Atom, Decoder, Encoder, Env, NifResult, NifStruct, Term}, -}; +use rustler::NifStruct; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Serialize)] #[cfg_attr(feature = "nif", derive(NifStruct))] @@ -59,15 +55,15 @@ impl Action { .collect::>(); // Construct the action tree - let tags = compliance_intances + let tags: Vec> = compliance_intances .iter() .flat_map(|instance| { vec![ - instance.consumed_nullifier.clone().into(), - instance.created_commitment.clone().into(), + instance.consumed_nullifier.clone(), + instance.created_commitment.clone(), ] }) - .collect::>(); + .collect(); let logics = compliance_intances .iter() .flat_map(|instance| { @@ -77,7 +73,7 @@ impl Action { ] }) .collect::>(); - let action_tree = MerkleTree::new(tags.clone()); + let action_tree = MerkleTree::from(tags.clone()); let root = action_tree.root(); for proof in &self.logic_verifier_inputs { @@ -87,8 +83,7 @@ impl Action { return false; } - let instance_tag: Leaf = instance.tag.clone().into(); - if let Some(index) = tags.iter().position(|tag| tag == &instance_tag) { + if let Some(index) = tags.iter().position(|tag| *tag == instance.tag) { if proof.verifying_key != logics[index] { return false; } @@ -134,7 +129,7 @@ pub fn create_an_action(nonce: u8) -> (Action, DeltaWitness) { let consumed_resource_nf = consumed_resource.nullifier(&nf_key).unwrap(); let mut created_resource = consumed_resource.clone(); - created_resource.set_nonce(consumed_resource_nf.clone()); + created_resource.set_nonce(consumed_resource_nf.as_bytes().to_vec()); let compliance_witness = ComplianceWitness::::with_fixed_rcv( consumed_resource.clone(), @@ -144,10 +139,7 @@ pub fn create_an_action(nonce: u8) -> (Action, DeltaWitness) { let compliance_receipt = ComplianceUnit::create(&compliance_witness); let created_resource_cm = created_resource.commitment(); - let action_tree = MerkleTree::new(vec![ - consumed_resource_nf.clone().into(), - created_resource_cm.clone().into(), - ]); + let action_tree = MerkleTree::new(vec![consumed_resource_nf, created_resource_cm]); let consumed_resource_path = action_tree.generate_path(&consumed_resource_nf).unwrap(); let created_resource_path = action_tree.generate_path(&created_resource_cm).unwrap(); diff --git a/arm/src/action_tree.rs b/arm/src/action_tree.rs index 0fc06e8f..30df6915 100644 --- a/arm/src/action_tree.rs +++ b/arm/src/action_tree.rs @@ -1,4 +1,7 @@ -use crate::merkle_path::{Hashable, Leaf, MerklePath}; +use crate::{ + merkle_path::{MerklePath, PADDING_LEAF}, + utils::hash_two, +}; use risc0_zkvm::sha::Digest; #[cfg(feature = "nif")] @@ -11,34 +14,36 @@ pub const ACTION_TREE_DEPTH: usize = 4; #[cfg_attr(feature = "nif", derive(NifStruct))] #[cfg_attr(feature = "nif", module = "Anoma.Arm.MerkleTree")] pub struct MerkleTree { - leaves: Vec, + leaves: Vec>, } impl MerkleTree { - pub fn new(leaves: Vec) -> Self { + pub fn new(leaves: Vec) -> Self { assert!( leaves.len() <= ACTION_TREE_MAX_NUM, "The number of leaves exceeds the ACTION_TREE_MAX_NUM" ); + let leaves = leaves + .into_iter() + .map(|digest| digest.as_words().to_vec()) + .collect(); MerkleTree { leaves } } - pub fn insert(&mut self, value: Leaf) { - self.leaves.push(value) + pub fn insert(&mut self, value: Digest) { + self.leaves.push(value.as_words().to_vec()) } - pub fn root(&self) -> Vec { + pub fn root(&self) -> Vec { let mut cur_layer = self.leaves.clone(); - cur_layer.resize(ACTION_TREE_MAX_NUM, Digest::blank().into()); + cur_layer.resize(ACTION_TREE_MAX_NUM, PADDING_LEAF.as_words().to_vec()); while cur_layer.len() > 1 { cur_layer = cur_layer .chunks(2) - .map(|pair| { - Digest::combine(&pair[0].clone().into(), &pair[1].clone().into()).into() - }) + .map(|pair| hash_two(&pair[0], &pair[1])) .collect(); } - cur_layer[0].inner().to_vec() + cur_layer[0].clone() } // Generate the merkle path for the current leave @@ -56,18 +61,15 @@ impl MerkleTree { /// - A `bool` indicating whether the sibling is on the left (`true`) or right (`false`). /// /// Returns `None` if the leaf is not found in the tree. - pub fn generate_path(&self, cur_leave: &[u8]) -> Option> { + pub fn generate_path(&self, cur_leave: &Digest) -> Option> { let mut cur_layer = self.leaves.clone(); - cur_layer.resize(ACTION_TREE_MAX_NUM, Digest::blank().into()); - if let Some(position) = cur_layer - .iter() - .position(|v| v == &cur_leave.to_vec().into()) - { + cur_layer.resize(ACTION_TREE_MAX_NUM, PADDING_LEAF.as_words().to_vec()); + if let Some(position) = cur_layer.iter().position(|v| v == cur_leave.as_words()) { let mut merkle_path = Vec::new(); fn build_merkle_path_inner( - cur_layer: Vec, + cur_layer: Vec>, position: usize, - path: &mut Vec<(Leaf, bool)>, + path: &mut Vec<(Vec, bool)>, ) { if cur_layer.len() > 1 { let sibling = { @@ -83,9 +85,7 @@ impl MerkleTree { let prev_layer = cur_layer .chunks(2) - .map(|pair| { - Digest::combine(&pair[0].clone().into(), &pair[1].clone().into()).into() - }) + .map(|pair| hash_two(&pair[0], &pair[1])) .collect(); build_merkle_path_inner(prev_layer, position / 2, path); @@ -103,3 +103,15 @@ impl MerkleTree { } } } + +impl From> for MerkleTree { + fn from(leaves: Vec) -> Self { + MerkleTree::new(leaves) + } +} + +impl From>> for MerkleTree { + fn from(leaves: Vec>) -> Self { + MerkleTree { leaves } + } +} diff --git a/arm/src/compliance.rs b/arm/src/compliance.rs index 81df079a..f1991777 100644 --- a/arm/src/compliance.rs +++ b/arm/src/compliance.rs @@ -1,4 +1,9 @@ -use crate::{merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource}; +use crate::{ + merkle_path::MerklePath, + nullifier_key::NullifierKey, + resource::Resource, + utils::{bytes_to_words, words_to_bytes}, +}; use hex::FromHex; use k256::{ elliptic_curve::{ @@ -21,13 +26,13 @@ lazy_static! { #[cfg_attr(feature = "nif", derive(NifStruct))] #[cfg_attr(feature = "nif", module = "Anoma.Arm.ComplianceInstance")] pub struct ComplianceInstance { - pub consumed_nullifier: Vec, - pub consumed_logic_ref: Vec, - pub consumed_commitment_tree_root: Vec, - pub created_commitment: Vec, - pub created_logic_ref: Vec, - pub delta_x: Vec, - pub delta_y: Vec, + pub consumed_nullifier: Vec, + pub consumed_logic_ref: Vec, + pub consumed_commitment_tree_root: Vec, + pub created_commitment: Vec, + pub created_logic_ref: Vec, + pub delta_x: Vec, + pub delta_y: Vec, } #[derive(Clone, serde::Serialize, serde::Deserialize)] @@ -39,7 +44,7 @@ pub struct ComplianceWitness { /// The path from the consumed commitment to the root in the commitment tree pub merkle_path: MerklePath, /// The existing root for the ephemeral resource - pub ephemeral_root: Vec, + pub ephemeral_root: Vec, /// Nullifier key of the consumed resource pub nf_key: NullifierKey, /// The created resource @@ -64,7 +69,7 @@ impl ComplianceWitness::default(), rcv: Scalar::random(&mut rng).to_bytes().to_vec(), nf_key, - ephemeral_root: INITIAL_ROOT.as_bytes().to_vec(), + ephemeral_root: INITIAL_ROOT.as_words().to_vec(), } } @@ -81,7 +86,7 @@ impl ComplianceWitness ComplianceWitness::default(), rcv: Scalar::ONE.to_bytes().to_vec(), nf_key, - ephemeral_root: INITIAL_ROOT.as_bytes().to_vec(), + ephemeral_root: INITIAL_ROOT.as_words().to_vec(), } } @@ -112,46 +117,47 @@ impl ComplianceWitness Vec { - self.consumed_resource.logic_ref.clone() + pub fn consumed_resource_logic(&self) -> Digest { + Digest::from_bytes(self.consumed_resource.logic_ref.clone().try_into().unwrap()) } - pub fn created_resource_logic(&self) -> Vec { - self.created_resource.logic_ref.clone() + pub fn created_resource_logic(&self) -> Digest { + Digest::from_bytes(self.created_resource.logic_ref.clone().try_into().unwrap()) } - pub fn consumed_commitment(&self) -> Vec { + pub fn consumed_commitment(&self) -> Digest { self.consumed_resource.commitment() } - pub fn created_commitment(&self) -> Vec { + pub fn created_commitment(&self) -> Digest { self.created_resource.commitment() } - pub fn consumed_nullifier(&self, cm: &[u8]) -> Vec { + pub fn consumed_nullifier(&self, cm: &Digest) -> Digest { self.consumed_resource .nullifier_from_commitment(&self.nf_key, cm) .unwrap() } - pub fn consumed_commitment_tree_root(&self, cm: &[u8]) -> Vec { + pub fn consumed_commitment_tree_root(&self, cm: &Digest) -> Vec { if self.consumed_resource.is_ephemeral { self.ephemeral_root.clone() } else { @@ -159,7 +165,7 @@ impl ComplianceWitness (Vec, Vec) { + pub fn delta(&self) -> (Vec, Vec) { // Compute delta and make delta commitment public let rcv_array: [u8; 32] = self .rcv @@ -172,9 +178,10 @@ impl ComplianceWitness Default for ComplianceWitness Default for ComplianceWitness Default for ComplianceWitness ProjectivePoint { - let x: [u8; 32] = self - .delta_x - .clone() + let x: [u8; 32] = words_to_bytes(&self.delta_x) .try_into() .expect("delta_x must be 32 bytes"); - let y: [u8; 32] = self - .delta_y - .clone() + let y: [u8; 32] = words_to_bytes(&self.delta_y) .try_into() .expect("delta_y must be 32 bytes"); let encoded_point = EncodedPoint::from_affine_coordinates(&x.into(), &y.into(), false); @@ -240,8 +243,8 @@ impl ComplianceInstance { pub fn delta_msg(&self) -> Vec { let mut msg = Vec::new(); - msg.extend_from_slice(&self.consumed_nullifier); - msg.extend_from_slice(&self.created_commitment); + msg.extend_from_slice(words_to_bytes(&self.consumed_nullifier)); + msg.extend_from_slice(words_to_bytes(&self.created_commitment)); msg } } diff --git a/arm/src/constants.rs b/arm/src/constants.rs index cfd186c9..7dd602ef 100644 --- a/arm/src/constants.rs +++ b/arm/src/constants.rs @@ -10,11 +10,11 @@ pub const PADDING_LOGIC_PK: &[u8] = include_bytes!("../elfs/trivial-logic-guest. lazy_static! { // compliance verification key / compliance image id pub static ref COMPLIANCE_VK: Digest = - Digest::from_hex("ab5a67860b67f0bc448c1ac55d71561e837601a85591581055cf80e216ddc216") + Digest::from_hex("2c10d71e919b8b6359bfc167294c9994c1699e3eeb851d4b7775edb67b54a327") .unwrap(); // compliance verification key / compliance image id pub static ref PADDING_LOGIC_VK: Digest = - Digest::from_hex("95c8992a13f68d6d969e4e1558c2aa2fdcbe05900a4f531b3b49b397e79b8a44") + Digest::from_hex("f8047dc2cf6cbe45137a588a3f019814218e7d7199b1b86a57b51c310e04fae9") .unwrap(); } diff --git a/arm/src/encryption.rs b/arm/src/encryption.rs index d20e3be4..23c99927 100644 --- a/arm/src/encryption.rs +++ b/arm/src/encryption.rs @@ -1,3 +1,4 @@ +use crate::utils::{bytes_to_words, words_to_bytes}; use aes_gcm::{aead::Aead, Aes256Gcm, Key, KeyInit}; use k256::{ elliptic_curve::{group::GroupEncoding, Field}, @@ -28,12 +29,26 @@ impl SecretKey { pub struct Ciphertext(Vec); impl Ciphertext { - pub fn new(cipher: Vec) -> Self { + pub fn from_bytes(cipher: Vec) -> Self { Ciphertext(cipher) } - pub fn inner(&self) -> Vec { - self.0.clone() + pub fn from_words(words: &[u32]) -> Self { + Ciphertext(words_to_bytes(words).to_vec()) + } + + pub fn inner(&self) -> &[u8] { + &self.0 + } + + pub fn as_words(&self) -> Vec { + let mut padded = self.inner().to_vec(); + let len = self.inner().len(); + let rem = len % 4; + if rem != 0 { + padded.resize(len + (4 - rem), 0); + } + bytes_to_words(&padded) } pub fn encrypt( @@ -63,7 +78,7 @@ impl Ciphertext { return Err(aes_gcm::Error); } let cipher: InnerCiphert = - bincode::deserialize(&self.inner()).expect("deserialization failure"); + bincode::deserialize(self.inner()).expect("deserialization failure"); // Generate the secret key using Diffie-Hellman exchange let inner_secret_key = InnerSecretKey::from_dh_exchange(&cipher.pk, sk.inner()); @@ -131,6 +146,10 @@ fn test_encryption() { // Decryption let decryption = cipher.decrypt(&receiver_sk).unwrap(); - assert_eq!(message, decryption); + + let cipher_words = cipher.as_words(); + let cipher_from_words = Ciphertext::from_words(&cipher_words); + let decrypted_from_words = cipher_from_words.decrypt(&receiver_sk).unwrap(); + assert_eq!(message, decrypted_from_words); } diff --git a/arm/src/lib.rs b/arm/src/lib.rs index 10a76c71..713cfccd 100644 --- a/arm/src/lib.rs +++ b/arm/src/lib.rs @@ -24,3 +24,4 @@ pub mod resource; pub mod resource_logic; #[cfg(feature = "transaction")] pub mod transaction; +pub mod utils; diff --git a/arm/src/logic_instance.rs b/arm/src/logic_instance.rs index 6ef44d2f..ca38ae02 100644 --- a/arm/src/logic_instance.rs +++ b/arm/src/logic_instance.rs @@ -1,16 +1,58 @@ +#[cfg(feature = "nif")] +use rustler::NifStruct; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(feature = "nif", derive(NifStruct))] +#[cfg_attr(feature = "nif", module = "Anoma.Arm.LogicInstance")] pub struct LogicInstance { - pub tag: Vec, + pub tag: Vec, pub is_consumed: bool, - pub root: Vec, - pub cipher: Vec, - pub app_data: Vec, + pub root: Vec, + pub app_data: AppData, } #[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(feature = "nif", derive(NifStruct))] +#[cfg_attr(feature = "nif", module = "Anoma.Arm.AppData")] +pub struct AppData { + pub resource_payload: Vec, + pub discovery_payload: Vec, + pub external_payload: Vec, + pub application_payload: Vec, +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(feature = "nif", derive(NifStruct))] +#[cfg_attr(feature = "nif", module = "Anoma.Arm.ExpirableBlob")] pub struct ExpirableBlob { - pub blob: Vec, - pub deletion_criterion: u8, + pub blob: Vec, + pub deletion_criterion: u32, +} + +impl AppData { + pub fn new() -> Self { + AppData { + resource_payload: Vec::new(), + discovery_payload: Vec::new(), + external_payload: Vec::new(), + application_payload: Vec::new(), + } + } + + pub fn add_resource_payload(&mut self, blob: ExpirableBlob) { + self.resource_payload.push(blob); + } + + pub fn add_discovery_payload(&mut self, blob: ExpirableBlob) { + self.discovery_payload.push(blob); + } + + pub fn add_external_payload(&mut self, blob: ExpirableBlob) { + self.external_payload.push(blob); + } + + pub fn add_application_payload(&mut self, blob: ExpirableBlob) { + self.application_payload.push(blob); + } } diff --git a/arm/src/logic_proof.rs b/arm/src/logic_proof.rs index 06b618d4..df71bdcc 100644 --- a/arm/src/logic_proof.rs +++ b/arm/src/logic_proof.rs @@ -9,7 +9,7 @@ use crate::{ resource_logic::TrivialLogicWitness, }; use rand::Rng; -use risc0_zkvm::Digest; +use risc0_zkvm::sha::{Digest, DIGEST_WORDS}; #[cfg(feature = "nif")] use rustler::NifStruct; use serde::{Deserialize, Serialize}; @@ -33,7 +33,7 @@ pub trait LogicProver: Default + Clone + Serialize + for<'de> Deserialize<'de> { // TODO: handle the unwrap properly proof, instance, - verifying_key: Self::verifying_key_as_bytes(), + verifying_key: Self::verifying_key().as_words().to_vec(), } } } @@ -44,13 +44,14 @@ pub trait LogicProver: Default + Clone + Serialize + for<'de> Deserialize<'de> { pub struct LogicProof { pub proof: Vec, pub instance: Vec, - pub verifying_key: Vec, + pub verifying_key: Vec, } impl LogicProof { pub fn verify(&self) -> bool { - let vk = if self.verifying_key.len() == 32 { - Digest::from_bytes(self.verifying_key.clone().try_into().unwrap()) + let vk = if self.verifying_key.len() == DIGEST_WORDS { + let words: [u32; DIGEST_WORDS] = self.verifying_key.clone().try_into().unwrap(); + Digest::from(words) } else { return false; // Invalid verifying key length }; diff --git a/arm/src/merkle_path.rs b/arm/src/merkle_path.rs index c2ba8d98..5a83d58b 100644 --- a/arm/src/merkle_path.rs +++ b/arm/src/merkle_path.rs @@ -1,127 +1,53 @@ +use crate::utils::hash_two; use hex::FromHex; use lazy_static::lazy_static; -use risc0_zkvm::sha::{Digest, Impl, Sha256, DIGEST_BYTES}; +use risc0_zkvm::sha::{Digest, DIGEST_WORDS}; #[cfg(feature = "nif")] -use rustler::{NifStruct, NifTuple}; +use rustler::NifStruct; use serde::{Deserialize, Serialize}; lazy_static! { - pub static ref PADDING_LEAVE: Digest = + pub static ref PADDING_LEAF: Digest = Digest::from_hex("cc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06") .unwrap(); } pub const COMMITMENT_TREE_DEPTH: usize = 32; -/// A hashable node within a Merkle tree. -pub trait Hashable: Clone + Copy { - /// Returns the parent node within the tree of the two given nodes. - fn combine(_: &Self, _: &Self) -> Self; - - /// Returns a blank leaf node. - fn blank() -> Self; -} - -impl Hashable for Digest { - /// Returns a blank leaf node. - fn blank() -> Self { - *PADDING_LEAVE - } - - /// Returns the parent node within the tree of the two given nodes. - fn combine(lhs: &Self, rhs: &Self) -> Self { - let mut bytes = [0u8; 2 * DIGEST_BYTES]; - let mut offset: usize = 0; - // Write the left child - bytes[offset..offset + DIGEST_BYTES].clone_from_slice(lhs.as_ref()); - offset += DIGEST_BYTES; - // Write the right child - bytes[offset..offset + DIGEST_BYTES].clone_from_slice(rhs.as_ref()); - offset += DIGEST_BYTES; - assert_eq!(offset, 2 * DIGEST_BYTES); - // Now produce the hash - *Impl::hash_bytes(&bytes) - } -} - /// A path from a position in a particular commitment tree to the root of that tree. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "nif", derive(NifStruct))] #[cfg_attr(feature = "nif", module = "Anoma.Arm.MerklePath")] pub struct MerklePath { - auth_path: Vec<(Leaf, bool)>, + auth_path: Vec<(Vec, bool)>, } impl MerklePath { /// Constructs a Merkle path directly from a path and position. - pub fn from_path(auth_path: [(Leaf, bool); TREE_DEPTH]) -> Self { + pub fn from_path(auth_path: [(Vec, bool); TREE_DEPTH]) -> Self { MerklePath { auth_path: auth_path.to_vec(), } } /// Returns the root of the tree corresponding to this path applied to `leaf`. - pub fn root(&self, leaf: &[u8]) -> Vec { + pub fn root(&self, leaf: &Digest) -> Vec { if self.auth_path.len() != TREE_DEPTH { panic!("Merkle path length does not match TREE_DEPTH"); } - let leaf: Digest = if leaf.len() == DIGEST_BYTES { - Digest::from_bytes(leaf.try_into().unwrap()) - } else { - // If the leaf is not the correct size, we pad it to the correct size. - let mut padded_leaf = [0u8; DIGEST_BYTES]; - padded_leaf[..leaf.len()].copy_from_slice(leaf); - Digest::from_bytes(padded_leaf) - }; self.auth_path .iter() - .fold(leaf, |root, (p, leaf_is_on_right)| { - let p_digest: Digest = Digest::from(p.clone()); - match leaf_is_on_right { - false => Digest::combine(&root, &p_digest), - true => Digest::combine(&p_digest, &root), - } - }) - .as_bytes() - .to_vec() + .fold( + leaf.as_words().to_vec(), + |root, (p, leaf_is_on_right)| match leaf_is_on_right { + false => hash_two(&root, p), + true => hash_two(p, &root), + }, + ) } } impl Default for MerklePath { fn default() -> Self { MerklePath { - auth_path: vec![(Leaf::default(), false); TREE_DEPTH], + auth_path: vec![(vec![0u32; DIGEST_WORDS], false); TREE_DEPTH], } } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(feature = "nif", derive(NifTuple))] -pub struct Leaf(Vec); - -impl Leaf { - /// Returns the inner bytes of the leaf. - pub fn inner(&self) -> &[u8] { - &self.0 - } -} - -impl From> for Leaf { - fn from(value: Vec) -> Self { - Leaf(value) - } -} - -impl From for Digest { - fn from(leaf: Leaf) -> Self { - Digest::from_bytes(leaf.0.try_into().unwrap()) - } -} - -impl From for Leaf { - fn from(digest: Digest) -> Self { - Leaf(digest.as_bytes().to_vec()) - } -} - -impl Default for Leaf { - fn default() -> Self { - Leaf(vec![0u8; DIGEST_BYTES]) - } -} diff --git a/arm/src/resource.rs b/arm/src/resource.rs index b195a8f7..c1a6727c 100644 --- a/arm/src/resource.rs +++ b/arm/src/resource.rs @@ -21,6 +21,7 @@ use k256::{ }; use rand::Rng; use risc0_zkvm::sha::{rust_crypto::Sha256 as Sha256Type, Impl, Sha256, DIGEST_BYTES}; +use risc0_zkvm::Digest; #[cfg(feature = "nif")] use rustler::NifStruct; use serde::{Deserialize, Serialize}; @@ -132,7 +133,7 @@ impl Resource { } // Compute the commitment to the resource - pub fn commitment(&self) -> Vec { + pub fn commitment(&self) -> Digest { // Concatenate all the components of this resource let mut bytes = [0u8; RESOURCE_BYTES]; let mut offset: usize = 0; @@ -163,16 +164,16 @@ impl Resource { offset += DEFAULT_BYTES; assert_eq!(offset, RESOURCE_BYTES); // Now produce the hash - Impl::hash_bytes(&bytes).as_bytes().to_vec() + *Impl::hash_bytes(&bytes) } // Compute the nullifier of the resource - pub fn nullifier(&self, nf_key: &NullifierKey) -> Option> { + pub fn nullifier(&self, nf_key: &NullifierKey) -> Option { let cm = self.commitment(); self.nullifier_from_commitment(nf_key, &cm) } - pub fn nullifier_from_commitment(&self, nf_key: &NullifierKey, cm: &[u8]) -> Option> { + pub fn nullifier_from_commitment(&self, nf_key: &NullifierKey, cm: &Digest) -> Option { // Make sure that the nullifier public key corresponds to the secret key if self.nk_commitment == nf_key.commit() { let mut bytes = [0u8; 4 * DIGEST_BYTES]; @@ -187,12 +188,12 @@ impl Resource { bytes[offset..offset + DIGEST_BYTES].clone_from_slice(self.psi().as_ref()); offset += DIGEST_BYTES; // Write the resource commitment - bytes[offset..offset + DIGEST_BYTES].clone_from_slice(cm.as_ref()); + bytes[offset..offset + DIGEST_BYTES].clone_from_slice(cm.as_bytes()); offset += DIGEST_BYTES; assert_eq!(offset, 4 * DIGEST_BYTES); - Some(Impl::hash_bytes(&bytes).as_bytes().to_vec()) + Some(*Impl::hash_bytes(&bytes)) } else { None } @@ -226,10 +227,10 @@ impl Resource { pub fn set_nonce_from_nf(&mut self, resource: &Resource, nf_key: &NullifierKey) { let nf = resource.nullifier(nf_key).unwrap(); - self.nonce = nf; + self.nonce = nf.as_bytes().to_vec(); } - pub fn tag(&self, is_consumed: bool, nf_key: &NullifierKey) -> Vec { + pub fn tag(&self, is_consumed: bool, nf_key: &NullifierKey) -> Digest { let cm = self.commitment(); if is_consumed { self.nullifier_from_commitment(nf_key, &cm).unwrap() diff --git a/arm/src/resource_logic.rs b/arm/src/resource_logic.rs index 23d78bf0..258371ea 100644 --- a/arm/src/resource_logic.rs +++ b/arm/src/resource_logic.rs @@ -1,6 +1,6 @@ use crate::{ - action_tree::ACTION_TREE_DEPTH, logic_instance::LogicInstance, merkle_path::MerklePath, - nullifier_key::NullifierKey, resource::Resource, + action_tree::ACTION_TREE_DEPTH, logic_instance::AppData, logic_instance::LogicInstance, + merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource, }; use serde::{Deserialize, Serialize}; @@ -40,11 +40,10 @@ impl LogicCircuit for TrivialLogicWitness { assert!(self.resource.is_ephemeral); LogicInstance { - tag, + tag: tag.as_words().to_vec(), is_consumed: self.is_consumed, // It can be either consumed or created to reduce padding resources root, - cipher: vec![], - app_data: vec![], + app_data: AppData::default(), // No app data for trivial logic } } } diff --git a/arm/src/utils.rs b/arm/src/utils.rs new file mode 100644 index 00000000..09abb5df --- /dev/null +++ b/arm/src/utils.rs @@ -0,0 +1,38 @@ +use risc0_zkvm::sha::{Impl, Sha256, DIGEST_WORDS}; + +pub fn bytes_to_words(bytes: &[u8]) -> Vec { + let mut words = Vec::new(); + for chunk in bytes.chunks_exact(4) { + let mut word = 0u32; + for &byte in chunk { + word = (word << 8) | (byte as u32); + } + words.push(u32::from_be(word)); + } + words +} + +pub fn words_to_bytes(words: &[u32]) -> &[u8] { + bytemuck::cast_slice(words) +} + +pub fn hash_two(left: &[u32], right: &[u32]) -> Vec { + let mut words = Vec::with_capacity(2 * DIGEST_WORDS); + words.extend_from_slice(left); + words.extend_from_slice(right); + Impl::hash_words(&words).as_words().to_vec() +} + +#[test] +fn test_bytes_to_words() { + let bytes = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]; + let words = bytes_to_words(&bytes); + assert_eq!(bytes, words_to_bytes(&words)); +} + +#[test] +fn test_words_to_bytes() { + let words = vec![0x01020304, 0x05060708]; + let bytes = words_to_bytes(&words); + assert_eq!(words, bytes_to_words(bytes)); +} diff --git a/arm_circuits/Cargo.lock b/arm_circuits/Cargo.lock index 04b9e827..66bde92d 100644 --- a/arm_circuits/Cargo.lock +++ b/arm_circuits/Cargo.lock @@ -305,6 +305,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm_circuits/compliance/methods/guest/Cargo.lock b/arm_circuits/compliance/methods/guest/Cargo.lock index b8acd612..34f1fa0d 100644 --- a/arm_circuits/compliance/methods/guest/Cargo.lock +++ b/arm_circuits/compliance/methods/guest/Cargo.lock @@ -281,6 +281,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm_circuits/counter/methods/guest/Cargo.lock b/arm_circuits/counter/methods/guest/Cargo.lock index ef1fc8d6..e0d44a5d 100644 --- a/arm_circuits/counter/methods/guest/Cargo.lock +++ b/arm_circuits/counter/methods/guest/Cargo.lock @@ -281,6 +281,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm_circuits/kudo_main/methods/guest/Cargo.lock b/arm_circuits/kudo_main/methods/guest/Cargo.lock index 9bf55103..f8c7a61c 100644 --- a/arm_circuits/kudo_main/methods/guest/Cargo.lock +++ b/arm_circuits/kudo_main/methods/guest/Cargo.lock @@ -305,6 +305,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm_circuits/simple_kudo_denomination/methods/guest/Cargo.lock b/arm_circuits/simple_kudo_denomination/methods/guest/Cargo.lock index 29388dee..c71f7dff 100644 --- a/arm_circuits/simple_kudo_denomination/methods/guest/Cargo.lock +++ b/arm_circuits/simple_kudo_denomination/methods/guest/Cargo.lock @@ -305,6 +305,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm_circuits/simple_kudo_receive/methods/guest/Cargo.lock b/arm_circuits/simple_kudo_receive/methods/guest/Cargo.lock index d2b0f69f..34a6e76c 100644 --- a/arm_circuits/simple_kudo_receive/methods/guest/Cargo.lock +++ b/arm_circuits/simple_kudo_receive/methods/guest/Cargo.lock @@ -305,6 +305,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/arm_circuits/trivial_logic/methods/guest/Cargo.lock b/arm_circuits/trivial_logic/methods/guest/Cargo.lock index 24e51117..a06281c3 100644 --- a/arm_circuits/trivial_logic/methods/guest/Cargo.lock +++ b/arm_circuits/trivial_logic/methods/guest/Cargo.lock @@ -305,6 +305,7 @@ version = "0.2.0" dependencies = [ "aes-gcm", "bincode", + "bytemuck", "hex", "k256", "lazy_static", diff --git a/examples/kudo_application/app/elfs/kudo-main-guest.bin b/examples/kudo_application/app/elfs/kudo-main-guest.bin index 147715e0..b48af3ce 100644 Binary files a/examples/kudo_application/app/elfs/kudo-main-guest.bin and b/examples/kudo_application/app/elfs/kudo-main-guest.bin differ diff --git a/examples/kudo_application/app/elfs/simple-kudo-denomination-guest.bin b/examples/kudo_application/app/elfs/simple-kudo-denomination-guest.bin index e5c68b68..7a92df4b 100644 Binary files a/examples/kudo_application/app/elfs/simple-kudo-denomination-guest.bin and b/examples/kudo_application/app/elfs/simple-kudo-denomination-guest.bin differ diff --git a/examples/kudo_application/app/elfs/simple-kudo-receive-guest.bin b/examples/kudo_application/app/elfs/simple-kudo-receive-guest.bin index 9baae1b6..199733b8 100644 Binary files a/examples/kudo_application/app/elfs/simple-kudo-receive-guest.bin and b/examples/kudo_application/app/elfs/simple-kudo-receive-guest.bin differ diff --git a/examples/kudo_application/app/src/burn_tx.rs b/examples/kudo_application/app/src/burn_tx.rs index 0a98db1c..69ad58bf 100644 --- a/examples/kudo_application/app/src/burn_tx.rs +++ b/examples/kudo_application/app/src/burn_tx.rs @@ -7,7 +7,7 @@ use arm::{ nullifier_key::NullifierKey, resource::Resource, }; -use arm::{logic_proof::LogicProver, transaction::Transaction}; +use arm::{logic_proof::LogicProver, transaction::Transaction, utils::words_to_bytes}; use kudo_logic_witness::{ kudo_main_witness::KudoMainWitness, simple_denomination_witness::SimpleDenominationLogicWitness, @@ -40,7 +40,7 @@ pub fn build_burn_tx( let mut ephemeral_kudo_resource = burned_kudo_resource.clone(); ephemeral_kudo_resource.is_ephemeral = true; ephemeral_kudo_resource.reset_randomness(); - ephemeral_kudo_resource.set_nonce(burned_kudo_resource_nf.clone()); + ephemeral_kudo_resource.set_nonce(burned_kudo_resource_nf.as_bytes().to_vec()); let ephemeral_kudo_resource_cm = ephemeral_kudo_resource.commitment(); // Construct the ephemeral denomination resource @@ -49,7 +49,7 @@ pub fn build_burn_tx( let nonce: [u8; 32] = rng.gen(); // Random nonce for the ephemeral resource let ephemeral_denomination_resource = Resource::create( denomination_logic.clone(), - ephemeral_kudo_resource_cm.clone(), // Use the ephemeral kudo commitment as the label + ephemeral_kudo_resource_cm.as_bytes().to_vec(), // Use the ephemeral kudo commitment as the label 0, [0u8; 32].into(), true, @@ -63,23 +63,24 @@ pub fn build_burn_tx( // Construct the burned denomination resource let burned_denomination_resource = Resource::create( denomination_logic.clone(), - burned_kudo_resource_nf.clone(), // Use the burned kudo nullifier as the label + burned_kudo_resource_nf.as_bytes().to_vec(), // Use the burned kudo nullifier as the label 0, [0u8; 32].into(), true, - ephemeral_denomination_resource_nf.clone(), + ephemeral_denomination_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let burned_denomination_resource_cm = burned_denomination_resource.commitment(); // Construct the action tree let action_tree = MerkleTree::new(vec![ - burned_kudo_resource_nf.clone().into(), - ephemeral_kudo_resource_cm.clone().into(), - ephemeral_denomination_resource_nf.clone().into(), - burned_denomination_resource_cm.clone().into(), + burned_kudo_resource_nf, + ephemeral_kudo_resource_cm, + ephemeral_denomination_resource_nf, + burned_denomination_resource_cm, ]); let root = action_tree.root(); + let root_bytes = words_to_bytes(&root); // Generate paths let burned_kudo_existence_path = action_tree.generate_path(&burned_kudo_resource_nf).unwrap(); @@ -108,7 +109,7 @@ pub fn build_burn_tx( let burned_kudo_info = KudoMainInfo::new(burned_kudo_logic_witness, Some(burned_kudo_path)); // Construct the denomination witness corresponding to the consumed kudo resource - let consumption_signature = owner_sk.sign(&root); + let consumption_signature = owner_sk.sign(root_bytes); let burned_denomination_logic_witness = SimpleDenominationLogicWitness::generate_denomimation_witness( burned_denomination_resource, @@ -138,7 +139,7 @@ pub fn build_burn_tx( let ephemeral_kudo_info = KudoMainInfo::new(ephemeral_kudo_logic_witness, None); // Construct the denomination witness, corresponding to the ephemeral kudo resource - let burn_signature = issuer_sk.sign(&root); + let burn_signature = issuer_sk.sign(root_bytes); let ephemeral_denomination_logic_witness = SimpleDenominationLogicWitness::generate_burned_ephemeral_witness( ephemeral_denomination_resource, diff --git a/examples/kudo_application/app/src/issue_tx.rs b/examples/kudo_application/app/src/issue_tx.rs index 439549cb..186c0d2c 100644 --- a/examples/kudo_application/app/src/issue_tx.rs +++ b/examples/kudo_application/app/src/issue_tx.rs @@ -7,6 +7,7 @@ use arm::{ authorization::{AuthorizationSignature, AuthorizationSigningKey, AuthorizationVerifyingKey}, nullifier_key::{NullifierKey, NullifierKeyCommitment}, resource::Resource, + utils::words_to_bytes, }; use arm::{ logic_proof::{LogicProver, PaddingResourceLogic}, @@ -55,7 +56,7 @@ pub fn build_issue_tx( quantity, kudo_value, false, - ephemeral_kudo_resource_nf.clone(), + ephemeral_kudo_resource_nf.as_bytes().to_vec(), receiver_nk_commitment.clone(), ); let issued_kudo_resource_cm = issued_kudo_resource.commitment(); @@ -64,7 +65,7 @@ pub fn build_issue_tx( let nonce: [u8; 32] = rng.gen(); // Random nonce for the ephemeral resource let issued_receive_resource = Resource::create( SimpleReceiveInfo::verifying_key_as_bytes(), - issued_kudo_resource_cm.clone(), + issued_kudo_resource_cm.as_bytes().to_vec(), 0, [0u8; 32].into(), true, @@ -77,11 +78,11 @@ pub fn build_issue_tx( let denomination_logic = SimpleDenominationInfo::verifying_key_as_bytes(); let issued_denomination_resource = Resource::create( denomination_logic.clone(), - issued_kudo_resource_cm.clone(), // Use the issued kudo commitment as the label + issued_kudo_resource_cm.as_bytes().to_vec(), // Use the issued kudo commitment as the label 0, [0u8; 32].into(), true, - issued_receive_resource_nf.clone(), + issued_receive_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let issued_denomination_resource_cm = issued_denomination_resource.commitment(); @@ -94,25 +95,26 @@ pub fn build_issue_tx( // Construct the ephemeral denomination resource let ephemeral_denomination_resource = Resource::create( denomination_logic, - ephemeral_kudo_resource_nf.clone(), // Use the ephemeral kudo nullifier as the label + ephemeral_kudo_resource_nf.as_bytes().to_vec(), // Use the ephemeral kudo nullifier as the label 0, [0u8; 32].into(), true, - padding_resource_nf.clone(), + padding_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let ephemeral_denomination_resource_cm = ephemeral_denomination_resource.commitment(); // Construct the action tree let action_tree = MerkleTree::new(vec![ - ephemeral_kudo_resource_nf.clone().into(), - issued_kudo_resource_cm.clone().into(), - issued_receive_resource_nf.clone().into(), - issued_denomination_resource_cm.clone().into(), - padding_resource_nf.clone().into(), - ephemeral_denomination_resource_cm.clone().into(), + ephemeral_kudo_resource_nf, + issued_kudo_resource_cm, + issued_receive_resource_nf, + issued_denomination_resource_cm, + padding_resource_nf, + ephemeral_denomination_resource_cm, ]); let root = action_tree.root(); + let root_bytes = words_to_bytes(&root); // Generate paths let ephemeral_kudo_existence_path = action_tree @@ -184,7 +186,7 @@ pub fn build_issue_tx( let ephemeral_kudo = KudoMainInfo::new(ephemeral_kudo_logic_witness, None); // Construct the ephemeral denomination witness - let signature = issuer_sk.sign(&root); + let signature = issuer_sk.sign(root_bytes); let ephemeral_denomination_logic_witness = SimpleDenominationLogicWitness::generate_issued_ephemeral_witness( ephemeral_denomination_resource.clone(), diff --git a/examples/kudo_application/app/src/kudo_main.rs b/examples/kudo_application/app/src/kudo_main.rs index cbc660f4..71aa4fb1 100644 --- a/examples/kudo_application/app/src/kudo_main.rs +++ b/examples/kudo_application/app/src/kudo_main.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; pub const KUDO_LOGIC_ELF: &[u8] = include_bytes!("../elfs/kudo-main-guest.bin"); lazy_static! { pub static ref KUDO_LOGIC_ID: Digest = - Digest::from_hex("1aaa5b40929dfafc79a39fe62ccacae10c71b484694668ebadc2a7b155eba195") + Digest::from_hex("639d1ed04c420c224fe1f4d751b207fd6586ef36a673c220f62c23e47f95981e") .unwrap(); } diff --git a/examples/kudo_application/app/src/simple_denomination.rs b/examples/kudo_application/app/src/simple_denomination.rs index 9eaeb2db..0aa5faa2 100644 --- a/examples/kudo_application/app/src/simple_denomination.rs +++ b/examples/kudo_application/app/src/simple_denomination.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; pub const DENOMINATION_ELF: &[u8] = include_bytes!("../elfs/simple-kudo-denomination-guest.bin"); lazy_static! { pub static ref DENOMINATION_ID: Digest = - Digest::from_hex("d46988fd32c4f0980466f6a04bdf9afce475687dfd884203df0e440a8e74af42") + Digest::from_hex("2074ae290e5ca64511ff2b329408e48cc4202b8e3538af9eb92155dd3779b8eb") .unwrap(); } diff --git a/examples/kudo_application/app/src/simple_receive.rs b/examples/kudo_application/app/src/simple_receive.rs index 30a15e5e..82b7b253 100644 --- a/examples/kudo_application/app/src/simple_receive.rs +++ b/examples/kudo_application/app/src/simple_receive.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; pub const RECEIVE_ELF: &[u8] = include_bytes!("../elfs/simple-kudo-receive-guest.bin"); lazy_static! { pub static ref RECEIVE_ID: Digest = - Digest::from_hex("acd43e2ef5e369481758499d0f83108ac6a2a536fa8955593231c777706857bf") + Digest::from_hex("9801521c4cfcd46de698a6137fab70a14f88a4e95fd32e3e34fb7b80952d205a") .unwrap(); } diff --git a/examples/kudo_application/app/src/swap_tx.rs b/examples/kudo_application/app/src/swap_tx.rs index 2d93eb82..4d5b32ea 100644 --- a/examples/kudo_application/app/src/swap_tx.rs +++ b/examples/kudo_application/app/src/swap_tx.rs @@ -9,6 +9,7 @@ use arm::{ merkle_path::COMMITMENT_TREE_DEPTH, nullifier_key::NullifierKey, resource::Resource, + utils::words_to_bytes, }; use arm::{ logic_proof::{LogicProver, PaddingResourceLogic}, @@ -52,7 +53,7 @@ pub fn build_swap_tx( created_kudo_quantity, kudo_value, // use the same kudo value as the consumed kudo resource false, - consumed_kudo_nf.clone(), + consumed_kudo_nf.as_bytes().to_vec(), consumed_kudo_resource.nk_commitment.clone(), // use the same nk_commitment as the consumed kudo resource ); let created_kudo_value_cm = created_kudo_resource.commitment(); @@ -63,7 +64,7 @@ pub fn build_swap_tx( let nonce: [u8; 32] = rng.gen(); // Random nonce for the ephemeral resource let consumed_denomination_resource = Resource::create( denomination_logic.clone(), - consumed_kudo_nf.clone(), // Use the consumed kudo nullifier as the label + consumed_kudo_nf.as_bytes().to_vec(), // Use the consumed kudo nullifier as the label 0, [0u8; 32].into(), true, @@ -77,11 +78,11 @@ pub fn build_swap_tx( // Construct the denomination resource corresponding to the created kudo resource let created_denomination_resource = Resource::create( denomination_logic.clone(), - created_kudo_value_cm.clone(), // Use the created kudo commitment as the label + created_kudo_value_cm.as_bytes().to_vec(), // Use the created kudo commitment as the label 0, [0u8; 32].into(), true, - consumed_denomination_resource_nf.clone(), + consumed_denomination_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let created_denomination_resource_cm = created_denomination_resource.commitment(); @@ -94,25 +95,26 @@ pub fn build_swap_tx( // Construct the receive logic resource let receive_resource = Resource::create( SimpleReceiveInfo::verifying_key_as_bytes(), - created_kudo_value_cm.clone(), + created_kudo_value_cm.as_bytes().to_vec(), 0, [0u8; 32].into(), true, - padding_resource_nf.clone(), + padding_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let receive_resource_cm = receive_resource.commitment(); // Construct the action tree let action_tree = MerkleTree::new(vec![ - consumed_kudo_nf.clone().into(), - created_kudo_value_cm.clone().into(), - consumed_denomination_resource_nf.clone().into(), - created_denomination_resource_cm.clone().into(), - padding_resource_nf.clone().into(), - receive_resource_cm.clone().into(), + consumed_kudo_nf, + created_kudo_value_cm, + consumed_denomination_resource_nf, + created_denomination_resource_cm, + padding_resource_nf, + receive_resource_cm, ]); let root = action_tree.root(); + let root_bytes = words_to_bytes(&root); // Generate paths let consumed_kudo_existence_path = action_tree.generate_path(&consumed_kudo_nf).unwrap(); @@ -141,7 +143,7 @@ pub fn build_swap_tx( let consumed_kudo = KudoMainInfo::new(consumed_kudo_logic_witness, Some(consumed_kudo_path)); // Construct the denomination witness corresponding to the consumed kudo resource - let consumption_signature = owner_sk.sign(&root); + let consumption_signature = owner_sk.sign(root_bytes); let consumed_denomination_logic_witness = SimpleDenominationLogicWitness::generate_denomimation_witness( consumed_denomination_resource.clone(), diff --git a/examples/kudo_application/app/src/transfer_tx.rs b/examples/kudo_application/app/src/transfer_tx.rs index 0ef1ab12..3c76f5b4 100644 --- a/examples/kudo_application/app/src/transfer_tx.rs +++ b/examples/kudo_application/app/src/transfer_tx.rs @@ -9,6 +9,7 @@ use arm::{ merkle_path::COMMITMENT_TREE_DEPTH, nullifier_key::{NullifierKey, NullifierKeyCommitment}, resource::Resource, + utils::words_to_bytes, }; use arm::{ logic_proof::{LogicProver, PaddingResourceLogic}, @@ -55,7 +56,7 @@ pub fn build_transfer_tx( created_kudo_resource.set_value_ref(created_kudo_value); // Reset the randomness and nonce created_kudo_resource.reset_randomness(); - created_kudo_resource.set_nonce(consumed_kudo_nf.clone()); + created_kudo_resource.set_nonce(consumed_kudo_nf.as_bytes().to_vec()); let created_kudo_cm = created_kudo_resource.commitment(); // Construct the denomination resource corresponding to the consumed kudo resource @@ -64,7 +65,7 @@ pub fn build_transfer_tx( let nonce: [u8; 32] = rng.gen(); // Random nonce for the ephemeral resource let consumed_denomination_resource = Resource::create( denomination_logic.clone(), - consumed_kudo_nf.clone(), // Use the consumed kudo nullifier as the label + consumed_kudo_nf.as_bytes().to_vec(), // Use the consumed kudo nullifier as the label 0, [0u8; 32].into(), true, @@ -78,11 +79,11 @@ pub fn build_transfer_tx( // Construct the denomination resource corresponding to the created kudo resource let created_denomination_resource = Resource::create( denomination_logic.clone(), - created_kudo_cm.clone(), // Use the created kudo commitment as the label + created_kudo_cm.as_bytes().to_vec(), // Use the created kudo commitment as the label 0, [0u8; 32].into(), true, - consumed_denomination_resource_nf.clone(), + consumed_denomination_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let created_denomination_resource_cm = created_denomination_resource.commitment(); @@ -95,25 +96,26 @@ pub fn build_transfer_tx( // Construct the receive logic resource let receive_resource = Resource::create( SimpleReceiveInfo::verifying_key_as_bytes(), - created_kudo_cm.clone(), + created_kudo_cm.as_bytes().to_vec(), 0, [0u8; 32].into(), true, - padding_resource_nf.clone(), + padding_resource_nf.as_bytes().to_vec(), instant_nk_commitment.clone(), ); let receive_resource_cm = receive_resource.commitment(); // Construct the action tree let action_tree = MerkleTree::new(vec![ - consumed_kudo_nf.clone().into(), - created_kudo_cm.clone().into(), - consumed_denomination_resource_nf.clone().into(), - created_denomination_resource_cm.clone().into(), - padding_resource_nf.clone().into(), - receive_resource_cm.clone().into(), + consumed_kudo_nf, + created_kudo_cm, + consumed_denomination_resource_nf, + created_denomination_resource_cm, + padding_resource_nf, + receive_resource_cm, ]); let root = action_tree.root(); + let root_bytes = words_to_bytes(&root); // Generate paths let consumed_kudo_existence_path = action_tree.generate_path(&consumed_kudo_nf).unwrap(); @@ -142,7 +144,7 @@ pub fn build_transfer_tx( let consumed_kudo = KudoMainInfo::new(consumed_kudo_logic_witness, Some(consumed_kudo_path)); // Construct the denomination witness corresponding to the consumed kudo resource - let consumption_signature = owner_sk.sign(&root); + let consumption_signature = owner_sk.sign(root_bytes); let consumed_denomination_logic_witness = SimpleDenominationLogicWitness::generate_denomimation_witness( consumed_denomination_resource.clone(), diff --git a/examples/kudo_application/logic_witness/src/kudo_main_witness.rs b/examples/kudo_application/logic_witness/src/kudo_main_witness.rs index dd49a700..08764d3b 100644 --- a/examples/kudo_application/logic_witness/src/kudo_main_witness.rs +++ b/examples/kudo_application/logic_witness/src/kudo_main_witness.rs @@ -4,7 +4,7 @@ use arm::{ action_tree::ACTION_TREE_DEPTH, authorization::{AuthorizationSignature, AuthorizationVerifyingKey}, encryption::{Ciphertext, SecretKey}, - logic_instance::LogicInstance, + logic_instance::{AppData, ExpirableBlob, LogicInstance}, merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource, @@ -60,7 +60,8 @@ impl LogicCircuit for KudoMainWitness { assert_eq!(root, dr_root); // Check denomination.label = kudo_resource.tag - assert_eq!(self.denomination_resource.label_ref, tag); + let tag_bytes = tag.as_bytes().to_vec(); + assert_eq!(self.denomination_resource.label_ref, tag_bytes); // Decode label of the kudo resource and check the correspondence between the // kudo resource and the domination resource @@ -89,7 +90,7 @@ impl LogicCircuit for KudoMainWitness { ); // Check receive_resource.label = kudo_resource.tag - assert_eq!(self.receive_resource.label_ref, tag); + assert_eq!(self.receive_resource.label_ref, tag_bytes); // Verify signature let mut receive_logic_and_owner_bytes = self.receive_resource.logic_ref.clone(); @@ -101,14 +102,23 @@ impl LogicCircuit for KudoMainWitness { } // Generate the ciphertext - let cipher = self.generate_ciphertext().inner(); + let cipher = self.generate_ciphertext().as_words(); + let cipher_expirable_blob = ExpirableBlob { + blob: cipher, + deletion_criterion: 1, + }; + let app_data = AppData { + resource_payload: vec![cipher_expirable_blob], + discovery_payload: Vec::new(), + external_payload: Vec::new(), + application_payload: Vec::new(), + }; LogicInstance { - tag, + tag: tag.as_words().to_vec(), is_consumed: self.kudo_is_consumed, root, - cipher, - app_data: Vec::new(), + app_data, } } } diff --git a/examples/kudo_application/logic_witness/src/simple_denomination_witness.rs b/examples/kudo_application/logic_witness/src/simple_denomination_witness.rs index 318ea521..2f40014b 100644 --- a/examples/kudo_application/logic_witness/src/simple_denomination_witness.rs +++ b/examples/kudo_application/logic_witness/src/simple_denomination_witness.rs @@ -3,11 +3,11 @@ pub use arm::resource_logic::LogicCircuit; use arm::{ action_tree::ACTION_TREE_DEPTH, authorization::{AuthorizationSignature, AuthorizationVerifyingKey}, - encryption::Ciphertext, - logic_instance::LogicInstance, + logic_instance::{AppData, LogicInstance}, merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource, + utils::words_to_bytes, }; use serde::{Deserialize, Serialize}; @@ -60,9 +60,10 @@ impl LogicCircuit for SimpleDenominationLogicWitness { }; let kudo_root = self.kudo_existence_path.root(&kudo_tag); assert_eq!(root, kudo_root); + let root_bytes = words_to_bytes(&root); // Check denomination.label = kudo_resource.tag - assert_eq!(self.denomination_resource.label_ref, kudo_tag); + assert_eq!(self.denomination_resource.label_ref, kudo_tag.as_bytes()); // Decode label of the kudo resource and check the correspondence between the // kudo resource and the domination resource @@ -75,7 +76,7 @@ impl LogicCircuit for SimpleDenominationLogicWitness { // Both insurance and burn should verify the issuer's signature. It // implies that only the issuer can burn resouces in this example. // It makes more sense to let the owner burn resources in practice? - assert!(self.kudo_issuer.verify(&root, &self.signature).is_ok()); + assert!(self.kudo_issuer.verify(root_bytes, &self.signature).is_ok()); // The issuer must be the owner when burning the resource. if !self.kudo_is_consumed { @@ -84,15 +85,14 @@ impl LogicCircuit for SimpleDenominationLogicWitness { } else if self.kudo_is_consumed { // Constrain persistent kudo resource consumption // Verify the owner's signature - assert!(self.kudo_owner.verify(&root, &self.signature,).is_ok()); + assert!(self.kudo_owner.verify(root_bytes, &self.signature).is_ok()); } LogicInstance { - tag: denomination_tag, + tag: denomination_tag.as_words().to_vec(), is_consumed: self.denomination_is_consumed, root, - cipher: Ciphertext::default().inner(), // no cipher needed - app_data: Vec::new(), // no app data needed + app_data: AppData::default(), // no app data needed } } } diff --git a/examples/kudo_application/logic_witness/src/simple_receive_witness.rs b/examples/kudo_application/logic_witness/src/simple_receive_witness.rs index b77423a9..1637ef69 100644 --- a/examples/kudo_application/logic_witness/src/simple_receive_witness.rs +++ b/examples/kudo_application/logic_witness/src/simple_receive_witness.rs @@ -1,7 +1,10 @@ pub use arm::resource_logic::LogicCircuit; use arm::{ - action_tree::ACTION_TREE_DEPTH, encryption::Ciphertext, logic_instance::LogicInstance, - merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource, + action_tree::ACTION_TREE_DEPTH, + logic_instance::{AppData, LogicInstance}, + merkle_path::MerklePath, + nullifier_key::NullifierKey, + resource::Resource, }; use serde::{Deserialize, Serialize}; @@ -36,16 +39,15 @@ impl LogicCircuit for SimpleReceiveLogicWitness { // Check if receive_resource.label equals kudo_resource.cm to ensure the // target kudo is loaded. - assert_eq!(self.receive_resource.label_ref, kudo_cm); + assert_eq!(self.receive_resource.label_ref, kudo_cm.as_bytes()); // TODO: add custom receive logic LogicInstance { - tag, + tag: tag.as_words().to_vec(), is_consumed: self.is_consumed, // It can be either consumed or created to reduce padding resources root, - cipher: Ciphertext::default().inner(), // no cipher needed - app_data: Vec::new(), // no app data needed + app_data: AppData::default(), // no app data needed } } } diff --git a/examples/simple_counter_application/app/elf/counter-guest.bin b/examples/simple_counter_application/app/elf/counter-guest.bin index dabc9e0e..f4de3553 100644 Binary files a/examples/simple_counter_application/app/elf/counter-guest.bin and b/examples/simple_counter_application/app/elf/counter-guest.bin differ diff --git a/examples/simple_counter_application/app/src/lib.rs b/examples/simple_counter_application/app/src/lib.rs index 5a8033da..1b3872e4 100644 --- a/examples/simple_counter_application/app/src/lib.rs +++ b/examples/simple_counter_application/app/src/lib.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; pub const SIMPLE_COUNTER_ELF: &[u8] = include_bytes!("../elf/counter-guest.bin"); lazy_static! { pub static ref SIMPLE_COUNTER_ID: Digest = - Digest::from_hex("09ce55f36b407aab2e27e6e8545d364a65fd0d325cd800ab4832c98590398b5f") + Digest::from_hex("7c6769ff60895aca5e1f45f5865137bac92afb76e63f75e92b4546f4a3a21499") .unwrap(); } @@ -99,10 +99,7 @@ pub fn generate_logic_proofs( let consumed_counter_nf = consumed_counter.nullifier(&nf_key).unwrap(); let created_counter_cm = created_counter.commitment(); - let action_tree = MerkleTree::new(vec![ - consumed_counter_nf.clone().into(), - created_counter_cm.clone().into(), - ]); + let action_tree = MerkleTree::new(vec![consumed_counter_nf, created_counter_cm]); let consumed_counter_path = action_tree.generate_path(&consumed_counter_nf).unwrap(); let created_counter_path = action_tree.generate_path(&created_counter_cm).unwrap(); diff --git a/examples/simple_counter_application/counter_witness/src/lib.rs b/examples/simple_counter_application/counter_witness/src/lib.rs index e6461a62..6824b6e8 100644 --- a/examples/simple_counter_application/counter_witness/src/lib.rs +++ b/examples/simple_counter_application/counter_witness/src/lib.rs @@ -1,7 +1,10 @@ pub use arm::resource_logic::LogicCircuit; use arm::{ - action_tree::ACTION_TREE_DEPTH, logic_instance::LogicInstance, merkle_path::MerklePath, - nullifier_key::NullifierKey, resource::Resource, + action_tree::ACTION_TREE_DEPTH, + logic_instance::{AppData, LogicInstance}, + merkle_path::MerklePath, + nullifier_key::NullifierKey, + resource::Resource, }; use serde::{Deserialize, Serialize}; #[derive(Clone, Default, Serialize, Deserialize)] @@ -44,11 +47,10 @@ impl LogicCircuit for CounterWitness { let tag = if self.is_consumed { old_nf } else { new_cm }; LogicInstance { - tag, + tag: tag.as_words().to_vec(), is_consumed: self.is_consumed, root: old_counter_root, - cipher: vec![], - app_data: vec![], + app_data: AppData::default(), } } }