diff --git a/Cargo.lock b/Cargo.lock index 669abd1c..72f6ace3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -612,6 +612,7 @@ dependencies = [ "risc0-zkvm", "rustler", "serde", + "serde_bytes", "sha3", ] @@ -1105,6 +1106,7 @@ dependencies = [ "arm", "rand 0.8.5", "serde", + "serde_bytes", ] [[package]] @@ -2546,6 +2548,7 @@ dependencies = [ "rand 0.8.5", "risc0-zkvm", "serde", + "serde_bytes", ] [[package]] @@ -4452,18 +4455,38 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -4618,6 +4641,7 @@ dependencies = [ "arm", "rand 0.8.5", "serde", + "serde_bytes", ] [[package]] diff --git a/arm/Cargo.toml b/arm/Cargo.toml index 9ca83985..8db90488 100644 --- a/arm/Cargo.toml +++ b/arm/Cargo.toml @@ -20,6 +20,7 @@ rustler = { version = "0.36.2", optional = true } bytemuck = { version = "1.12", features = ["derive"] } alloy-primitives = "1.0.23" alloy-sol-types = "1.0.23" +serde_bytes = "0.11.19" [features] default = ["transaction", "prove"] diff --git a/arm/src/action.rs b/arm/src/action.rs index fcb19451..cd711ae8 100644 --- a/arm/src/action.rs +++ b/arm/src/action.rs @@ -14,6 +14,7 @@ use crate::{ }; #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.Action"))] pub struct Action { pub compliance_units: Vec, pub logic_verifier_inputs: Vec, diff --git a/arm/src/action_tree.rs b/arm/src/action_tree.rs index 10b111d2..e3644140 100644 --- a/arm/src/action_tree.rs +++ b/arm/src/action_tree.rs @@ -1,14 +1,42 @@ +use crate::utils::{bytes_to_words, words_to_bytes}; use crate::{ merkle_path::{MerklePath, PADDING_LEAF}, utils::hash_two, }; use risc0_zkvm::sha::Digest; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde_bytes::ByteBuf; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Clone, PartialEq, Eq, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.MerkleTree"))] pub struct MerkleTree { + #[serde( + deserialize_with = "deserialize_leaves", + serialize_with = "serialize_leaves" + )] pub leaves: Vec>, } +pub fn serialize_leaves(t: &[Vec], s: S) -> Result +where + S: Serializer, +{ + t.iter() + .map(|t| ByteBuf::from(words_to_bytes(t))) + .collect::>() + .serialize(s) +} + +pub fn deserialize_leaves<'de, D>(deserializer: D) -> Result>, D::Error> +where + D: Deserializer<'de>, +{ + Ok(Vec::::deserialize(deserializer)? + .into_iter() + .map(|t| bytes_to_words(&t.into_vec())) + .collect()) +} + impl MerkleTree { pub fn new(leaves: Vec) -> Self { let leaves = leaves diff --git a/arm/src/compliance.rs b/arm/src/compliance.rs index 158634b0..b745f990 100644 --- a/arm/src/compliance.rs +++ b/arm/src/compliance.rs @@ -2,7 +2,7 @@ use crate::{ merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource, - utils::{bytes_to_words, words_to_bytes}, + utils::{bytes_to_words, vec_u32, words_to_bytes}, }; use hex::FromHex; use k256::{ @@ -21,29 +21,40 @@ lazy_static! { } #[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.ComplianceInstance"))] pub struct ComplianceInstance { + #[serde(with = "vec_u32")] pub consumed_nullifier: Vec, + #[serde(with = "vec_u32")] pub consumed_logic_ref: Vec, + #[serde(with = "vec_u32")] pub consumed_commitment_tree_root: Vec, + #[serde(with = "vec_u32")] pub created_commitment: Vec, + #[serde(with = "vec_u32")] pub created_logic_ref: Vec, + #[serde(with = "vec_u32")] pub delta_x: Vec, + #[serde(with = "vec_u32")] pub delta_y: Vec, } #[derive(Clone, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.ComplianceWitness"))] pub struct ComplianceWitness { /// The consumed resource pub consumed_resource: Resource, /// The path from the consumed commitment to the root in the commitment tree pub merkle_path: MerklePath, /// The existing root for the ephemeral resource + #[serde(with = "vec_u32")] pub ephemeral_root: Vec, /// Nullifier key of the consumed resource pub nf_key: NullifierKey, /// The created resource pub created_resource: Resource, /// Random scalar for delta commitment + #[serde(with = "serde_bytes")] pub rcv: Vec, // TODO: If we want to add function privacy, include: // pub input_resource_logic_cm_r: [u8; DATA_BYTES], diff --git a/arm/src/compliance_unit.rs b/arm/src/compliance_unit.rs index 6c092c79..4962faf1 100644 --- a/arm/src/compliance_unit.rs +++ b/arm/src/compliance_unit.rs @@ -10,9 +10,12 @@ use serde::{Deserialize, Serialize}; use crate::{compliance::ComplianceWitness, constants::COMPLIANCE_PK, proving_system::prove}; #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.ComplianceUnit"))] pub struct ComplianceUnit { // vk is a constant in the compliance unit, so we don't place it here. + #[serde(with = "serde_bytes")] pub proof: Vec, + #[serde(with = "serde_bytes")] pub instance: Vec, } diff --git a/arm/src/delta_proof.rs b/arm/src/delta_proof.rs index 77ae044a..999030df 100644 --- a/arm/src/delta_proof.rs +++ b/arm/src/delta_proof.rs @@ -2,21 +2,81 @@ use k256::ecdsa::{Error, RecoveryId, Signature, SigningKey, VerifyingKey}; use k256::{ elliptic_curve::PublicKey, elliptic_curve::ScalarPrimitive, ProjectivePoint, Scalar, SecretKey, }; -use serde::{Deserialize, Serialize}; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use serde_bytes::ByteArray; use sha3::{Digest, Keccak256}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.DeltaProof"))] pub struct DeltaProof { + #[serde( + deserialize_with = "deserialize_signature", + serialize_with = "serialize_signature" + )] pub signature: Signature, + #[serde( + deserialize_with = "deserialize_recovery_id", + serialize_with = "serialize_recovery_id" + )] pub recid: RecoveryId, } -#[derive(Clone, Debug)] +fn serialize_signature(t: &Signature, s: S) -> Result +where + S: Serializer, +{ + ByteArray::<64>::new(t.to_bytes().into()).serialize(s) +} + +fn deserialize_signature<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let b: [u8; 64] = ByteArray::deserialize(deserializer)?.into_array(); + Signature::from_bytes(&b.into()).map_err(de::Error::custom) +} + +fn serialize_recovery_id(t: &RecoveryId, s: S) -> Result +where + S: Serializer, +{ + s.serialize_u8(t.to_byte()) +} + +fn deserialize_recovery_id<'de, D>(d: D) -> Result +where + D: Deserializer<'de>, +{ + let s: u8 = de::Deserialize::deserialize(d)?; + RecoveryId::try_from(s).map_err(de::Error::custom) +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.DeltaWitness"))] pub struct DeltaWitness { + #[serde( + deserialize_with = "deserialize_signing_key", + serialize_with = "serialize_signing_key" + )] pub signing_key: SigningKey, } +fn serialize_signing_key(t: &SigningKey, s: S) -> Result +where + S: Serializer, +{ + ByteArray::<32>::new(t.to_bytes().into()).serialize(s) +} + +fn deserialize_signing_key<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let b: [u8; 32] = ByteArray::deserialize(deserializer)?.into_array(); + SigningKey::from_bytes(&b.into()).map_err(de::Error::custom) +} + pub struct DeltaInstance { pub verifying_key: VerifyingKey, } @@ -123,49 +183,6 @@ impl DeltaInstance { } } -impl Serialize for DeltaProof { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_bytes(&self.to_bytes()) - } -} - -impl<'de> Deserialize<'de> for DeltaProof { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let bytes: Vec = Vec::deserialize(deserializer)?; - if bytes.len() != 65 { - return Err(serde::de::Error::custom( - "Invalid byte length for DeltaProof", - )); - } - Ok(DeltaProof::from_bytes(&bytes)) - } -} - -impl Serialize for DeltaWitness { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_bytes(&self.to_bytes()) - } -} - -impl<'de> Deserialize<'de> for DeltaWitness { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let bytes = <[u8; 32]>::deserialize(deserializer)?; - Ok(DeltaWitness::from_bytes(&bytes)) - } -} - #[test] fn test_delta_proof() { use k256::elliptic_curve::rand_core::OsRng; diff --git a/arm/src/encryption.rs b/arm/src/encryption.rs index caa735e9..b8c97768 100644 --- a/arm/src/encryption.rs +++ b/arm/src/encryption.rs @@ -27,7 +27,7 @@ impl SecretKey { } #[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct Ciphertext(Vec); +pub struct Ciphertext(#[serde(with = "serde_bytes")] Vec); impl Ciphertext { pub fn from_bytes(cipher: Vec) -> Self { @@ -88,8 +88,10 @@ impl Ciphertext { #[derive(Debug, Clone, Default, Serialize, Deserialize)] struct InnerCiphert { // AES GCM encrypted message + #[serde(with = "serde_bytes")] pub cipher: Vec, // 96-bits; unique per message + #[serde(with = "serde_bytes")] pub nonce: [u8; 12], // Sender's public key pub pk: AffinePoint, diff --git a/arm/src/lib.rs b/arm/src/lib.rs index b57383b9..c33ea70f 100644 --- a/arm/src/lib.rs +++ b/arm/src/lib.rs @@ -21,8 +21,6 @@ pub mod nullifier_key; pub mod proving_system; pub mod resource; pub mod resource_logic; -#[cfg(feature = "nif")] -pub mod rustler_util; #[cfg(feature = "transaction")] pub mod test_logic; #[cfg(feature = "transaction")] diff --git a/arm/src/logic_instance.rs b/arm/src/logic_instance.rs index 80ff3bb2..36b2d6b5 100644 --- a/arm/src/logic_instance.rs +++ b/arm/src/logic_instance.rs @@ -1,18 +1,19 @@ -#[cfg(feature = "nif")] -use rustler::NifStruct; +use crate::utils::vec_u32; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] -#[cfg_attr(feature = "nif", derive(NifStruct))] -#[cfg_attr(feature = "nif", module = "Anoma.Arm.LogicInstance")] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.LogicInstance"))] pub struct LogicInstance { + #[serde(with = "vec_u32")] pub tag: Vec, pub is_consumed: bool, + #[serde(with = "vec_u32")] pub root: Vec, pub app_data: AppData, } #[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.AppData"))] pub struct AppData { pub resource_payload: Vec, pub discovery_payload: Vec, @@ -21,7 +22,9 @@ pub struct AppData { } #[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.ExpirableBlob"))] pub struct ExpirableBlob { + #[serde(with = "vec_u32")] pub blob: Vec, pub deletion_criterion: u32, } diff --git a/arm/src/logic_proof.rs b/arm/src/logic_proof.rs index 0a66145d..ff6e54cf 100644 --- a/arm/src/logic_proof.rs +++ b/arm/src/logic_proof.rs @@ -8,7 +8,7 @@ use crate::{ resource::Resource, resource_logic::TrivialLogicWitness, test_logic::TestLogicWitness, - utils::words_to_bytes, + utils::{vec_u32, words_to_bytes}, }; use rand::Rng; use risc0_zkvm::{ @@ -46,17 +46,28 @@ pub trait LogicProver: Default + Clone + Serialize + for<'de> Deserialize<'de> { } #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.LogicVerifier"))] pub struct LogicVerifier { + #[serde(with = "serde_bytes")] pub proof: Vec, + #[serde(with = "serde_bytes")] pub instance: Vec, + #[serde(with = "vec_u32")] pub verifying_key: Vec, } #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr( + feature = "nif", + serde(rename = "Elixir.Anoma.Arm.LogicVerifierInputs") +)] pub struct LogicVerifierInputs { + #[serde(with = "vec_u32")] pub tag: Vec, + #[serde(with = "vec_u32")] pub verifying_key: Vec, pub app_data: AppData, + #[serde(with = "serde_bytes")] pub proof: Vec, } diff --git a/arm/src/merkle_path.rs b/arm/src/merkle_path.rs index 8f310b94..11c56c1e 100644 --- a/arm/src/merkle_path.rs +++ b/arm/src/merkle_path.rs @@ -1,8 +1,9 @@ -use crate::utils::hash_two; +use crate::utils::{bytes_to_words, hash_two, words_to_bytes}; use hex::FromHex; use lazy_static::lazy_static; use risc0_zkvm::sha::{Digest, DIGEST_WORDS}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde_bytes::ByteBuf; lazy_static! { pub static ref PADDING_LEAF: Digest = Digest::from_hex("cc1d2f838445db7aec431df9ee8a871f40e7aa5e064fc056633ef8c60fab7b06") @@ -11,7 +12,33 @@ lazy_static! { /// A path from a position in a particular commitment tree to the root of that tree. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct MerklePath(pub Vec<(Vec, bool)>); +pub struct MerklePath( + #[serde( + deserialize_with = "deserialize_merkle_path", + serialize_with = "serialize_merkle_path" + )] + pub Vec<(Vec, bool)>, +); + +pub fn serialize_merkle_path(t: &[(Vec, bool)], s: S) -> Result +where + S: Serializer, +{ + t.iter() + .map(|(t, b)| (ByteBuf::from(words_to_bytes(t)), *b)) + .collect::>() + .serialize(s) +} + +pub fn deserialize_merkle_path<'de, D>(deserializer: D) -> Result, bool)>, D::Error> +where + D: Deserializer<'de>, +{ + Ok(Vec::<(ByteBuf, bool)>::deserialize(deserializer)? + .into_iter() + .map(|(t, b)| (bytes_to_words(&t.into_vec()), b)) + .collect()) +} impl MerklePath { /// Constructs a Merkle path directly from a path and position. diff --git a/arm/src/nullifier_key.rs b/arm/src/nullifier_key.rs index 87678679..29f1ce93 100644 --- a/arm/src/nullifier_key.rs +++ b/arm/src/nullifier_key.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; /// Nullifier key #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct NullifierKey(Vec); +pub struct NullifierKey(#[serde(with = "serde_bytes")] Vec); impl NullifierKey { pub fn new(nf_key: &[u8]) -> NullifierKey { @@ -40,7 +40,7 @@ impl Default for NullifierKey { /// Commitment to nullifier key #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] -pub struct NullifierKeyCommitment(Vec); +pub struct NullifierKeyCommitment(#[serde(with = "serde_bytes")] Vec); impl NullifierKeyCommitment { pub fn inner(&self) -> &[u8] { diff --git a/arm/src/resource.rs b/arm/src/resource.rs index 44e626bd..3e796ef9 100644 --- a/arm/src/resource.rs +++ b/arm/src/resource.rs @@ -26,22 +26,28 @@ use serde::{Deserialize, Serialize}; /// A resource that can be created and consumed #[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.Resource"))] pub struct Resource { // a succinct representation of the predicate associated with the resource + #[serde(with = "serde_bytes")] pub logic_ref: Vec, // specifies the fungibility domain for the resource + #[serde(with = "serde_bytes")] pub label_ref: Vec, // number representing the quantity of the resource pub quantity: u128, // the fungible value reference of the resource + #[serde(with = "serde_bytes")] pub value_ref: Vec, // flag that reflects the resource ephemerality pub is_ephemeral: bool, // guarantees the uniqueness of the resource computable components + #[serde(with = "serde_bytes")] pub nonce: Vec, // commitment to nullifier key pub nk_commitment: NullifierKeyCommitment, // randomness seed used to derive whatever randomness needed + #[serde(with = "serde_bytes")] pub rand_seed: Vec, } diff --git a/arm/src/resource_logic.rs b/arm/src/resource_logic.rs index 64847bee..de346984 100644 --- a/arm/src/resource_logic.rs +++ b/arm/src/resource_logic.rs @@ -4,9 +4,6 @@ use crate::{ }; use serde::{Deserialize, Serialize}; -#[cfg(feature = "nif")] -use rustler::NifStruct; - /// This is a trait for logic constraints implementation. pub trait LogicCircuit: Default + Clone + Serialize + for<'de> Deserialize<'de> { // In general, it's implemented as `Self::default()` @@ -19,8 +16,10 @@ pub trait LogicCircuit: Default + Clone + Serialize + for<'de> Deserialize<'de> } #[derive(Clone, Default, Serialize, Deserialize)] -#[cfg_attr(feature = "nif", derive(NifStruct))] -#[cfg_attr(feature = "nif", module = "Anoma.Arm.TrivialLogicWitness")] +#[cfg_attr( + feature = "nif", + serde(rename = "Elixir.Anoma.Arm.TrivialLogicWitness") +)] pub struct TrivialLogicWitness { pub resource: Resource, pub receive_existence_path: MerklePath, diff --git a/arm/src/rustler_util.rs b/arm/src/rustler_util.rs deleted file mode 100644 index a71481aa..00000000 --- a/arm/src/rustler_util.rs +++ /dev/null @@ -1,1173 +0,0 @@ -#![cfg(feature = "nif")] -// This module defines conversions from Rust to Rustler. -// Some of these are obvious, but we expect Vec and so on to be encoded/decoded as Elixir binaries -// which Rustler does not do for us. -// So even when an encoding/decoding can be derived using the module attribute, it's probably a bad idea. -use crate::action::Action; -use crate::action_tree::MerkleTree; -use crate::compliance::{ComplianceInstance, ComplianceWitness}; -use crate::compliance_unit::ComplianceUnit; -use crate::delta_proof::{DeltaProof, DeltaWitness}; -use crate::encryption::{Ciphertext, SecretKey}; -use crate::logic_instance::{AppData, ExpirableBlob}; -use crate::logic_proof::{LogicVerifier, LogicVerifierInputs}; -use crate::merkle_path::MerklePath; -use crate::nullifier_key::{NullifierKey, NullifierKeyCommitment}; -use crate::resource::Resource; -use crate::transaction::{Delta, Transaction}; -use crate::utils::{bytes_to_words, words_to_bytes}; -use bincode; -use k256::ecdsa::{RecoveryId, Signature, SigningKey}; -use k256::elliptic_curve::PrimeField; -use k256::{AffinePoint, Scalar}; -use rustler::types::map::map_new; -use rustler::{atoms, Binary, Decoder, Encoder, NifResult}; -use rustler::{Env, Error, OwnedBinary, Term}; -use std::io::Write; - -atoms! { - at_nil = "nil", - at_true = "true", - at_false = "false", - at_value = "value", - at_key = "key", - at_proof = "proof", - at_instance = "instance", - at_struct = "__struct__", - at_deletion_criteria = "deletion_criteria", - at_blob = "blob", - at_compliance_unit = "Elixir.Anoma.Arm.ComplianceUnit", - at_expirable_blob = "Elixir.Anoma.Arm.ExpirableBlob", - at_app_data = "Elixir.Anoma.Arm.AppData", - at_resource_payload = "resource_payload", - at_discovery_payload = "discovery_payload", - at_external_payload = "external_payload", - at_application_payload = "application_payload", - at_logic_verifier_inputs = "Elixir.Anoma.Arm.LogicVerifierInputs", - at_tag = "tag", - at_verifying_key = "verifying_key", - at_app_data_key = "app_data", - at_action = "Elixir.Anoma.Arm.Action", - at_compliance_units = "compliance_units", - at_logic_verifier_inputs_key = "logic_verifier_inputs", - at_merkle_tree = "Elixir.Anoma.Arm.MerkleTree", - at_leaves = "leaves", - at_compliance_instance = "Elixir.Anoma.Arm.ComplianceInstance", - at_consumed_nullifier = "consumed_nullifier", - at_consumed_logic_ref = "consumed_logic_ref", - at_consumed_commitment_tree_root = "consumed_commitment_tree_root", - at_created_commitment = "created_commitment", - at_created_logic_ref = "created_logic_ref", - at_delta_x = "delta_x", - at_delta_y = "delta_y", - at_compliance_witness = "Elixir.Anoma.Arm.ComplianceWitness", - at_consumed_resource = "consumed_resource", - at_merkle_path = "merkle_path", - at_ephemeral_root = "ephemeral_root", - at_nf_key = "nf_key", - at_created_resource = "created_resource", - at_rcv = "rcv", - at_resource = "Elixir.Anoma.Arm.Resource", - at_logic_ref = "logic_ref", - at_label_ref = "label_ref", - at_quantity = "quantity", - at_value_ref = "value_ref", - at_is_ephemeral = "is_ephemeral", - at_nonce = "nonce", - at_nk_commitment = "nk_commitment", - at_rand_seed = "rand_seed", - at_delta_proof = "Elixir.Anoma.Arm.DeltaProof", - at_signature = "signature", - at_recid = "recid", - at_delta_witness = "Elixir.Anoma.Arm.DeltaWitness", - at_signing_key = "signing_key", - at_logic_verifier = "Elixir.Anoma.Arm.LogicVerifier", - at_transaction = "Elixir.Anoma.Arm.Transaction", - at_actions = "actions", - at_delta_proof_field = "delta_proof", - at_expected_balance = "expected_balance", - at_witness = "witness" -} - -pub trait RustlerEncoder { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error>; -} - -pub trait RustlerDecoder<'a>: Sized + 'a { - fn rustler_decode(term: Term<'a>) -> NifResult; -} - -impl RustlerEncoder for Vec { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let mut erl_bin = OwnedBinary::new(self.len()) - .ok_or("could not create OwnedBinary") - .expect("could not allocate binary"); - let _ = erl_bin.as_mut_slice().write_all(&self.as_slice()); - Ok(erl_bin.release(env).to_term(env)) - } -} - -impl<'a> RustlerDecoder<'a> for Vec { - fn rustler_decode(term: Term<'a>) -> NifResult { - let binary: Binary = term.decode().expect("failed to decode binary"); - Ok(binary.as_slice().to_vec()) - } -} - -impl RustlerEncoder for Vec { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let mut erl_bin: OwnedBinary = OwnedBinary::new(self.len() * 4) - .ok_or("could not create OwnedBinary") - .expect("could not allocate binary"); - let bytes: &[u8] = words_to_bytes(self.as_slice()); - let _ = erl_bin.as_mut_slice().write_all(bytes); - Ok(erl_bin.release(env).to_term(env)) - } -} - -impl<'a> RustlerDecoder<'a> for Vec { - fn rustler_decode(term: Term<'a>) -> NifResult { - let binary: Binary = term.decode().expect("failed to decode binary"); - let bytes: &[u8] = binary.as_slice(); - let words: Vec = bytes_to_words(bytes); - Ok(words) - } -} - -impl RustlerEncoder for AffinePoint { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - bincode::serialize(self) - .expect("failed to encode AffinePoint") - .rustler_encode(env) - } -} - -impl<'a> RustlerDecoder<'a> for AffinePoint { - fn rustler_decode(term: Term<'a>) -> NifResult { - let binary: Vec = RustlerDecoder::rustler_decode(term)?; - let affine_point = bincode::deserialize::(binary.as_slice()); - Ok(affine_point.unwrap()) - } -} - -impl RustlerEncoder for Signature { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - bincode::serialize(self) - .expect("failed to encode Signature") - .rustler_encode(env) - } -} - -impl<'a> RustlerDecoder<'a> for Signature { - fn rustler_decode(term: Term<'a>) -> NifResult { - let binary: Vec = RustlerDecoder::rustler_decode(term)?; - let signature = bincode::deserialize::(binary.as_slice()); - Ok(signature.unwrap()) - } -} - -impl RustlerEncoder for RecoveryId { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let byte: u8 = self.to_byte(); - Ok(byte.encode(env)) - } -} - -impl<'a> RustlerDecoder<'a> for RecoveryId { - fn rustler_decode(term: Term<'a>) -> NifResult { - let byte: u8 = term.decode()?; - Ok(RecoveryId::from_byte(byte).expect("invalid RecoveryId")) - } -} - -//-------------------------------------------------------------------------------------------------- -// CipherText - -impl RustlerEncoder for Ciphertext { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let bytes = self.as_words(); - Ok(bytes.rustler_encode(env)?) - } -} - -impl<'a> RustlerDecoder<'a> for Ciphertext { - fn rustler_decode(term: Term<'a>) -> NifResult { - let words: Vec = RustlerDecoder::rustler_decode(term)?; - let cipher_text: Ciphertext = Ciphertext::from_words(words.as_slice()); - Ok(cipher_text) - } -} - -impl Encoder for Ciphertext { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - self.rustler_encode(env) - .expect("failed to encode SecretKey") - } -} - -impl<'a> Decoder<'a> for Ciphertext { - fn decode(term: Term<'a>) -> NifResult { - Ciphertext::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// SecretKey - -impl RustlerEncoder for SecretKey { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let bytes = self.inner().to_bytes().as_slice().to_vec(); - Ok(bytes.rustler_encode(env)?) - } -} - -impl<'a> RustlerDecoder<'a> for SecretKey { - fn rustler_decode(term: Term<'a>) -> NifResult { - let secret_key_vec: Vec = RustlerDecoder::rustler_decode(term)?; - let secret_key_slice: [u8; 32] = secret_key_vec.try_into().unwrap(); - let sk = SecretKey::new(Scalar::from_repr(secret_key_slice.into()).unwrap()); - Ok(sk) - } -} - -impl Encoder for SecretKey { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - self.rustler_encode(env) - .expect("failed to encode SecretKey") - } -} - -impl<'a> Decoder<'a> for SecretKey { - fn decode(term: Term<'a>) -> NifResult { - SecretKey::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// SigningKey - -impl RustlerEncoder for SigningKey { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let bytes = self.to_bytes(); - let bytez = bytes.to_vec(); - RustlerEncoder::rustler_encode(&bytez, env) - } -} - -impl<'a> RustlerDecoder<'a> for SigningKey { - fn rustler_decode(term: Term<'a>) -> NifResult { - let bytez: Vec = RustlerDecoder::rustler_decode(term)?; - Ok(SigningKey::from_slice(&bytez).expect("invalid SigningKey")) - } -} - -//-------------------------------------------------------------------------------------------------- -// ComplianceUnit - -impl RustlerEncoder for ComplianceUnit { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_compliance_unit().encode(env))? - .map_put(at_proof().encode(env), self.proof.rustler_encode(env)?)? - .map_put( - at_instance().encode(env), - self.instance.rustler_encode(env)?, - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for ComplianceUnit { - fn rustler_decode(term: Term<'a>) -> NifResult { - let proof_term = term.map_get(at_proof().encode(term.get_env())); - let proof: Vec = RustlerDecoder::rustler_decode(proof_term?)?; - let instance_term = term.map_get(at_instance().encode(term.get_env())); - let instance: Vec = RustlerDecoder::rustler_decode(instance_term?)?; - Ok(ComplianceUnit { proof, instance }) - } -} - -impl Encoder for ComplianceUnit { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode ComplianceUnit") - } -} - -impl<'a> Decoder<'a> for ComplianceUnit { - fn decode(term: Term<'a>) -> NifResult { - ComplianceUnit::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// ExpirableBlob - -impl RustlerEncoder for ExpirableBlob { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_expirable_blob().encode(env))? - .map_put(at_blob().encode(env), self.blob.rustler_encode(env)?)? - .map_put( - at_deletion_criteria().encode(env), - self.deletion_criterion.encode(env), - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for ExpirableBlob { - fn rustler_decode(term: Term<'a>) -> NifResult { - let blob_term = term.map_get(at_blob().encode(term.get_env())); - let blob: Vec = RustlerDecoder::rustler_decode(blob_term?)?; - let deletion_criteria_term = term.map_get(at_deletion_criteria().encode(term.get_env())); - let deletion_criterion: u32 = deletion_criteria_term?.decode()?; - Ok(ExpirableBlob { - blob, - deletion_criterion, - }) - } -} - -impl Encoder for ExpirableBlob { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode ExpirableBlob") - } -} - -impl<'a> Decoder<'a> for ExpirableBlob { - fn decode(term: Term<'a>) -> NifResult { - ExpirableBlob::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// AppData - -impl RustlerEncoder for AppData { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_app_data().encode(env))? - .map_put( - at_resource_payload().encode(env), - self.resource_payload.encode(env), - )? - .map_put( - at_discovery_payload().encode(env), - self.discovery_payload.encode(env), - )? - .map_put( - at_external_payload().encode(env), - self.external_payload.encode(env), - )? - .map_put( - at_application_payload().encode(env), - self.application_payload.encode(env), - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for AppData { - fn rustler_decode(term: Term<'a>) -> NifResult { - let resource_payload_term = term.map_get(at_resource_payload().encode(term.get_env()))?; - let resource_payload = resource_payload_term.decode()?; - let discovery_payload_term = term.map_get(at_discovery_payload().encode(term.get_env()))?; - let discovery_payload = discovery_payload_term.decode()?; - let external_payload_term = term.map_get(at_external_payload().encode(term.get_env()))?; - let external_payload = external_payload_term.decode()?; - let app_payload_term = term.map_get(at_application_payload().encode(term.get_env()))?; - let application_payload = app_payload_term.decode()?; - - Ok(AppData { - resource_payload, - discovery_payload, - external_payload, - application_payload, - }) - } -} - -impl Encoder for AppData { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode AppData") - } -} - -impl<'a> Decoder<'a> for AppData { - fn decode(term: Term<'a>) -> NifResult { - AppData::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// LogicVerifierInputs - -impl RustlerEncoder for LogicVerifierInputs { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put( - at_struct().encode(env), - at_logic_verifier_inputs().encode(env), - )? - .map_put(at_tag().encode(env), self.tag.rustler_encode(env)?)? - .map_put( - at_verifying_key().encode(env), - self.verifying_key.rustler_encode(env)?, - )? - .map_put(at_app_data_key().encode(env), self.app_data.encode(env))? - .map_put(at_proof().encode(env), self.proof.rustler_encode(env)?)?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for LogicVerifierInputs { - fn rustler_decode(term: Term<'a>) -> NifResult { - let tag_term = term.map_get(at_tag().encode(term.get_env()))?; - let tag: Vec = RustlerDecoder::rustler_decode(tag_term)?; - let verifying_key_term = term.map_get(at_verifying_key().encode(term.get_env()))?; - let verifying_key: Vec = RustlerDecoder::rustler_decode(verifying_key_term)?; - let app_data_term = term.map_get(at_app_data_key().encode(term.get_env()))?; - let app_data: AppData = app_data_term.decode()?; - let proof_term = term.map_get(at_proof().encode(term.get_env()))?; - let proof: Vec = RustlerDecoder::rustler_decode(proof_term)?; - - Ok(LogicVerifierInputs { - tag, - verifying_key, - app_data, - proof, - }) - } -} - -impl Encoder for LogicVerifierInputs { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode LogicVerifierInputs") - } -} - -impl<'a> Decoder<'a> for LogicVerifierInputs { - fn decode(term: Term<'a>) -> NifResult { - LogicVerifierInputs::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// Action - -impl RustlerEncoder for Action { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_action().encode(env))? - .map_put( - at_compliance_units().encode(env), - self.compliance_units.encode(env), - )? - .map_put( - at_logic_verifier_inputs_key().encode(env), - self.logic_verifier_inputs.encode(env), - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for Action { - fn rustler_decode(term: Term<'a>) -> NifResult { - let compliance_units_term = term.map_get(at_compliance_units().encode(term.get_env()))?; - let compliance_units: Vec = compliance_units_term.decode()?; - let logic_verifier_inputs_term = - term.map_get(at_logic_verifier_inputs_key().encode(term.get_env()))?; - let logic_verifier_inputs: Vec = - logic_verifier_inputs_term.decode()?; - - Ok(Action { - compliance_units, - logic_verifier_inputs, - }) - } -} - -impl Encoder for Action { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode Action") - } -} - -impl<'a> Decoder<'a> for Action { - fn decode(term: Term<'a>) -> NifResult { - Action::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// MerkleTree - -impl RustlerEncoder for MerkleTree { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - // encode the leaves separately. - // each leaf is a vec and we have to encode those as a binary individually. - let encoded_vec: Term = self - .leaves - .iter() - .map(|leaf: &Vec| { - leaf.rustler_encode(env) - .expect("could not encode MerkleTree leaf") - }) - .collect::>() - .encode(env); - - let map = map_new(env) - .map_put(at_struct().encode(env), at_merkle_tree().encode(env))? - .map_put(at_leaves().encode(env), encoded_vec)?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for MerkleTree { - fn rustler_decode(term: Term<'a>) -> NifResult { - let leaves_term = term.map_get(at_leaves().encode(term.get_env()))?; - let leaves_terms = - Vec::::decode(leaves_term).expect("failed to decode MerkleTree leaves"); - - let leaves: Vec> = leaves_terms - .iter() - .map(|term| RustlerDecoder::rustler_decode(*term).expect("failed to decode leaf")) - .collect(); - - Ok(MerkleTree { leaves }) - } -} - -impl Encoder for MerkleTree { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode MerkleTree") - } -} - -impl<'a> Decoder<'a> for MerkleTree { - fn decode(term: Term<'a>) -> NifResult { - MerkleTree::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// MerklePath - -impl RustlerEncoder for MerklePath { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let encoded_vec: Vec = self - .0 - .iter() - .map(|(hash, is_right)| { - let hash_term = hash - .rustler_encode(env) - .expect("could not encode MerklePath hash"); - let is_right_term = is_right.encode(env); - (hash_term, is_right_term).encode(env) - }) - .collect(); - - Ok(encoded_vec.encode(env)) - } -} - -impl<'a> RustlerDecoder<'a> for MerklePath { - fn rustler_decode(term: Term<'a>) -> NifResult { - let path_terms = Vec::::decode(term).expect("failed to decode MerklePath list"); - - let path: Vec<(Vec, bool)> = path_terms - .iter() - .map(|term| { - let tuple: (Term, Term) = term.decode().expect("failed to decode MerklePath tuple"); - let hash: Vec = RustlerDecoder::rustler_decode(tuple.0) - .expect("failed to decode MerklePath hash"); - let is_right: bool = tuple - .1 - .decode() - .expect("failed to decode MerklePath boolean"); - (hash, is_right) - }) - .collect(); - - Ok(MerklePath(path)) - } -} - -impl Encoder for MerklePath { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode MerklePath") - } -} - -impl<'a> Decoder<'a> for MerklePath { - fn decode(term: Term<'a>) -> NifResult { - MerklePath::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// ComplianceInstance - -impl RustlerEncoder for ComplianceInstance { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put( - at_struct().encode(env), - at_compliance_instance().encode(env), - )? - .map_put( - at_consumed_nullifier().encode(env), - self.consumed_nullifier.rustler_encode(env)?, - )? - .map_put( - at_consumed_logic_ref().encode(env), - self.consumed_logic_ref.rustler_encode(env)?, - )? - .map_put( - at_consumed_commitment_tree_root().encode(env), - self.consumed_commitment_tree_root.rustler_encode(env)?, - )? - .map_put( - at_created_commitment().encode(env), - self.created_commitment.rustler_encode(env)?, - )? - .map_put( - at_created_logic_ref().encode(env), - self.created_logic_ref.rustler_encode(env)?, - )? - .map_put(at_delta_x().encode(env), self.delta_x.rustler_encode(env)?)? - .map_put(at_delta_y().encode(env), self.delta_y.rustler_encode(env)?)?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for ComplianceInstance { - fn rustler_decode(term: Term<'a>) -> NifResult { - let consumed_nullifier_term = - term.map_get(at_consumed_nullifier().encode(term.get_env()))?; - let consumed_nullifier: Vec = RustlerDecoder::rustler_decode(consumed_nullifier_term)?; - - let consumed_logic_ref_term = - term.map_get(at_consumed_logic_ref().encode(term.get_env()))?; - let consumed_logic_ref: Vec = RustlerDecoder::rustler_decode(consumed_logic_ref_term)?; - - let consumed_commitment_tree_root_term = - term.map_get(at_consumed_commitment_tree_root().encode(term.get_env()))?; - let consumed_commitment_tree_root: Vec = - RustlerDecoder::rustler_decode(consumed_commitment_tree_root_term)?; - - let created_commitment_term = - term.map_get(at_created_commitment().encode(term.get_env()))?; - let created_commitment: Vec = RustlerDecoder::rustler_decode(created_commitment_term)?; - - let created_logic_ref_term = term.map_get(at_created_logic_ref().encode(term.get_env()))?; - let created_logic_ref: Vec = RustlerDecoder::rustler_decode(created_logic_ref_term)?; - - let delta_x_term = term.map_get(at_delta_x().encode(term.get_env()))?; - let delta_x: Vec = RustlerDecoder::rustler_decode(delta_x_term)?; - - let delta_y_term = term.map_get(at_delta_y().encode(term.get_env()))?; - let delta_y: Vec = RustlerDecoder::rustler_decode(delta_y_term)?; - - Ok(ComplianceInstance { - consumed_nullifier, - consumed_logic_ref, - consumed_commitment_tree_root, - created_commitment, - created_logic_ref, - delta_x, - delta_y, - }) - } -} - -impl Encoder for ComplianceInstance { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode ComplianceInstance") - } -} - -impl<'a> Decoder<'a> for ComplianceInstance { - fn decode(term: Term<'a>) -> NifResult { - ComplianceInstance::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// ComplianceWitness - -impl RustlerEncoder for ComplianceWitness { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_compliance_witness().encode(env))? - .map_put( - at_consumed_resource().encode(env), - self.consumed_resource.encode(env), - )? - .map_put( - at_merkle_path().encode(env), - self.merkle_path.rustler_encode(env)?, - )? - .map_put( - at_ephemeral_root().encode(env), - self.ephemeral_root.rustler_encode(env)?, - )? - .map_put(at_nf_key().encode(env), self.nf_key.encode(env))? - .map_put( - at_created_resource().encode(env), - self.created_resource.encode(env), - )? - .map_put(at_rcv().encode(env), self.rcv.rustler_encode(env)?)?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for ComplianceWitness { - fn rustler_decode(term: Term<'a>) -> NifResult { - let consumed_resource_term = term.map_get(at_consumed_resource().encode(term.get_env()))?; - let consumed_resource: Resource = consumed_resource_term.decode()?; - - let merkle_path_term = term.map_get(at_merkle_path().encode(term.get_env()))?; - let merkle_path: MerklePath = RustlerDecoder::rustler_decode(merkle_path_term)?; - - let ephemeral_root_term = term.map_get(at_ephemeral_root().encode(term.get_env()))?; - let ephemeral_root: Vec = RustlerDecoder::rustler_decode(ephemeral_root_term)?; - - let nf_key_term = term.map_get(at_nf_key().encode(term.get_env()))?; - let nf_key: NullifierKey = nf_key_term.decode()?; - - let created_resource_term = term.map_get(at_created_resource().encode(term.get_env()))?; - let created_resource: Resource = created_resource_term.decode()?; - - let rcv_term = term.map_get(at_rcv().encode(term.get_env()))?; - let rcv: Vec = RustlerDecoder::rustler_decode(rcv_term)?; - - Ok(ComplianceWitness { - consumed_resource, - merkle_path, - ephemeral_root, - nf_key, - created_resource, - rcv, - }) - } -} - -impl Encoder for ComplianceWitness { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode ComplianceWitness") - } -} - -impl<'a> Decoder<'a> for ComplianceWitness { - fn decode(term: Term<'a>) -> NifResult { - ComplianceWitness::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// NullifierKeyCommitment - -impl RustlerEncoder for NullifierKeyCommitment { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let inner_bytes = self.inner().to_vec(); - inner_bytes.rustler_encode(env) - } -} - -impl<'a> RustlerDecoder<'a> for NullifierKeyCommitment { - fn rustler_decode(term: Term<'a>) -> NifResult { - let bytes: Vec = RustlerDecoder::rustler_decode(term)?; - Ok(NullifierKeyCommitment::from_bytes(&bytes)) - } -} - -impl Encoder for NullifierKeyCommitment { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode NullifierKeyCommitment") - } -} - -impl<'a> Decoder<'a> for NullifierKeyCommitment { - fn decode(term: Term<'a>) -> NifResult { - NullifierKeyCommitment::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// NullifierKey - -impl RustlerEncoder for NullifierKey { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let inner_bytes = self.inner().to_vec(); - inner_bytes.rustler_encode(env) - } -} - -impl<'a> RustlerDecoder<'a> for NullifierKey { - fn rustler_decode(term: Term<'a>) -> NifResult { - let bytes: Vec = RustlerDecoder::rustler_decode(term)?; - Ok(NullifierKey::from_bytes(&bytes)) - } -} - -impl Encoder for NullifierKey { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode NullifierKey") - } -} - -impl<'a> Decoder<'a> for NullifierKey { - fn decode(term: Term<'a>) -> NifResult { - NullifierKey::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// Resource - -impl RustlerEncoder for Resource { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_resource().encode(env))? - .map_put( - at_logic_ref().encode(env), - self.logic_ref.rustler_encode(env)?, - )? - .map_put( - at_label_ref().encode(env), - self.label_ref.rustler_encode(env)?, - )? - .map_put(at_quantity().encode(env), self.quantity.encode(env))? - .map_put( - at_value_ref().encode(env), - self.value_ref.rustler_encode(env)?, - )? - .map_put(at_is_ephemeral().encode(env), self.is_ephemeral.encode(env))? - .map_put(at_nonce().encode(env), self.nonce.rustler_encode(env)?)? - .map_put( - at_nk_commitment().encode(env), - self.nk_commitment.rustler_encode(env)?, - )? - .map_put( - at_rand_seed().encode(env), - self.rand_seed.rustler_encode(env)?, - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for Resource { - fn rustler_decode(term: Term<'a>) -> NifResult { - let logic_ref_term = term.map_get(at_logic_ref().encode(term.get_env()))?; - let logic_ref: Vec = RustlerDecoder::rustler_decode(logic_ref_term)?; - - let label_ref_term = term.map_get(at_label_ref().encode(term.get_env()))?; - let label_ref: Vec = RustlerDecoder::rustler_decode(label_ref_term)?; - - let quantity_term = term.map_get(at_quantity().encode(term.get_env()))?; - let quantity: u128 = quantity_term.decode()?; - - let value_ref_term = term.map_get(at_value_ref().encode(term.get_env()))?; - let value_ref: Vec = RustlerDecoder::rustler_decode(value_ref_term)?; - - let is_ephemeral_term = term.map_get(at_is_ephemeral().encode(term.get_env()))?; - let is_ephemeral: bool = is_ephemeral_term.decode()?; - - let nonce_term = term.map_get(at_nonce().encode(term.get_env()))?; - let nonce: Vec = RustlerDecoder::rustler_decode(nonce_term)?; - - let nk_commitment_term = term.map_get(at_nk_commitment().encode(term.get_env()))?; - let nk_commitment: NullifierKeyCommitment = - RustlerDecoder::rustler_decode(nk_commitment_term)?; - - let rand_seed_term = term.map_get(at_rand_seed().encode(term.get_env()))?; - let rand_seed: Vec = RustlerDecoder::rustler_decode(rand_seed_term)?; - - Ok(Resource { - logic_ref, - label_ref, - quantity, - value_ref, - is_ephemeral, - nonce, - nk_commitment, - rand_seed, - }) - } -} - -impl Encoder for Resource { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode Resource") - } -} - -impl<'a> Decoder<'a> for Resource { - fn decode(term: Term<'a>) -> NifResult { - Resource::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// DeltaProof - -impl RustlerEncoder for DeltaProof { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_delta_proof().encode(env))? - .map_put( - at_signature().encode(env), - self.signature.rustler_encode(env)?, - )? - .map_put(at_recid().encode(env), self.recid.rustler_encode(env)?)?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for DeltaProof { - fn rustler_decode(term: Term<'a>) -> NifResult { - let signature_term = term.map_get(at_signature().encode(term.get_env()))?; - let signature: Signature = RustlerDecoder::rustler_decode(signature_term)?; - - let recid_term = term.map_get(at_recid().encode(term.get_env()))?; - let recid: RecoveryId = RustlerDecoder::rustler_decode(recid_term)?; - - Ok(DeltaProof { signature, recid }) - } -} - -impl Encoder for DeltaProof { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode DeltaProof") - } -} - -impl<'a> Decoder<'a> for DeltaProof { - fn decode(term: Term<'a>) -> NifResult { - DeltaProof::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// DeltaWitness - -impl RustlerEncoder for DeltaWitness { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_delta_witness().encode(env))? - .map_put( - at_signing_key().encode(env), - self.signing_key.rustler_encode(env)?, - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for DeltaWitness { - fn rustler_decode(term: Term<'a>) -> NifResult { - let signing_key_term = term.map_get(at_signing_key().encode(term.get_env()))?; - let signing_key: SigningKey = RustlerDecoder::rustler_decode(signing_key_term)?; - - Ok(DeltaWitness { signing_key }) - } -} - -impl Encoder for DeltaWitness { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode DeltaWitness") - } -} - -impl<'a> Decoder<'a> for DeltaWitness { - fn decode(term: Term<'a>) -> NifResult { - DeltaWitness::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// LogicVerifier - -impl RustlerEncoder for LogicVerifier { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let map = map_new(env) - .map_put(at_struct().encode(env), at_logic_verifier().encode(env))? - .map_put(at_proof().encode(env), self.proof.rustler_encode(env)?)? - .map_put( - at_instance().encode(env), - self.instance.rustler_encode(env)?, - )? - .map_put( - at_verifying_key().encode(env), - self.verifying_key.rustler_encode(env)?, - )?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for LogicVerifier { - fn rustler_decode(term: Term<'a>) -> NifResult { - let proof_term = term.map_get(at_proof().encode(term.get_env()))?; - let proof: Vec = RustlerDecoder::rustler_decode(proof_term)?; - - let instance_term = term.map_get(at_instance().encode(term.get_env()))?; - let instance: Vec = RustlerDecoder::rustler_decode(instance_term)?; - - let verifying_key_term = term.map_get(at_verifying_key().encode(term.get_env()))?; - let verifying_key: Vec = RustlerDecoder::rustler_decode(verifying_key_term)?; - - Ok(LogicVerifier { - proof, - instance, - verifying_key, - }) - } -} - -impl Encoder for LogicVerifier { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode LogicVerifier") - } -} - -impl<'a> Decoder<'a> for LogicVerifier { - fn decode(term: Term<'a>) -> NifResult { - LogicVerifier::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// Transaction - -impl RustlerEncoder for Transaction { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - let balance_term: Term; - match &self.expected_balance { - None => balance_term = at_nil().encode(env), - Some(vec) => balance_term = RustlerEncoder::rustler_encode(vec, env)?, - }; - - let map = map_new(env) - .map_put(at_struct().encode(env), at_transaction().encode(env))? - .map_put(at_actions().encode(env), self.actions.encode(env))? - .map_put( - at_delta_proof_field().encode(env), - self.delta_proof.encode(env), - )? - .map_put(at_expected_balance().encode(env), balance_term)?; - - Ok(map) - } -} - -impl<'a> RustlerDecoder<'a> for Transaction { - fn rustler_decode(term: Term<'a>) -> NifResult { - let actions_term = term.map_get(at_actions().encode(term.get_env()))?; - let actions: Vec = actions_term.decode()?; - - let delta_proof_term = term.map_get(at_delta_proof_field().encode(term.get_env()))?; - let delta_proof: Delta = delta_proof_term.decode()?; - - let expected_balance_term = term.map_get(at_expected_balance().encode(term.get_env()))?; - let mut expected_balance: Option> = None; - - if expected_balance_term.is_atom() { - println!("expected balance is an atom"); - }; - - if expected_balance_term.is_binary() { - println!("expected balance is a binary"); - let expected_balance_vec: Vec = - RustlerDecoder::rustler_decode(expected_balance_term)?; - expected_balance = Some(expected_balance_vec); - } - - Ok(Transaction { - actions, - delta_proof, - expected_balance, - }) - } -} - -impl Encoder for Transaction { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - let encoded = self.rustler_encode(env); - encoded.expect("failed to encode Transaction") - } -} - -impl<'a> Decoder<'a> for Transaction { - fn decode(term: Term<'a>) -> NifResult { - Transaction::rustler_decode(term) - } -} - -//-------------------------------------------------------------------------------------------------- -// Delta - -impl RustlerEncoder for Delta { - fn rustler_encode<'a>(&self, env: Env<'a>) -> Result, Error> { - Ok(self.encode(env)) - } -} - -impl<'a> RustlerDecoder<'a> for Delta { - fn rustler_decode(term: Term<'a>) -> NifResult { - let tuple: (Term, Term) = term.decode()?; - let tag = tuple.0; - let value = tuple.1; - - if tag.atom_to_string()? == "proof" { - let proof: DeltaProof = value.decode()?; - Ok(Delta::Proof(proof)) - } else if tag.atom_to_string()? == "witness" { - let witness: DeltaWitness = value.decode()?; - Ok(Delta::Witness(witness)) - } else { - Err(rustler::Error::BadArg) - } - } -} - -impl Encoder for Delta { - fn encode<'a>(&self, env: Env<'a>) -> Term<'a> { - match self { - Delta::Witness(witness) => (at_witness(), witness).encode(env), - Delta::Proof(proof) => (at_proof(), proof).encode(env), - } - } -} - -impl<'a> Decoder<'a> for Delta { - fn decode(term: Term<'a>) -> NifResult { - Delta::rustler_decode(term) - } -} diff --git a/arm/src/test_logic.rs b/arm/src/test_logic.rs index b2b1ede1..5c877069 100644 --- a/arm/src/test_logic.rs +++ b/arm/src/test_logic.rs @@ -12,12 +12,8 @@ use crate::{ use k256::AffinePoint; use serde::{Deserialize, Serialize}; -#[cfg(feature = "nif")] -use rustler::NifStruct; - #[derive(Clone, Serialize, Deserialize)] -#[cfg_attr(feature = "nif", derive(NifStruct))] -#[cfg_attr(feature = "nif", module = "Anoma.Arm.TestLogicWitness")] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.TestLogicWitness"))] pub struct TestLogicWitness { pub resource: Resource, pub receive_existence_path: MerklePath, diff --git a/arm/src/transaction.rs b/arm/src/transaction.rs index ba99cf0f..3041727e 100644 --- a/arm/src/transaction.rs +++ b/arm/src/transaction.rs @@ -2,21 +2,44 @@ use crate::{ action::Action, delta_proof::{DeltaInstance, DeltaProof, DeltaWitness}, }; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use serde_bytes::ByteBuf; #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.Transaction"))] pub struct Transaction { pub actions: Vec, // delta verification is a deterministic process, so we don't need a // separate delta_vk here. pub delta_proof: Delta, // We can't support unbalanced transactions, so this is just a placeholder. + #[serde( + deserialize_with = "deserialize_expected_balance", + serialize_with = "serialize_expected_balance" + )] pub expected_balance: Option>, } +fn serialize_expected_balance(t: &Option>, s: S) -> Result +where + S: Serializer, +{ + t.clone().map(ByteBuf::from).serialize(s) +} + +fn deserialize_expected_balance<'de, D>(deserializer: D) -> Result>, D::Error> +where + D: Deserializer<'de>, +{ + Ok(Option::::deserialize(deserializer)?.map(|x| x.into_vec())) +} + #[derive(Clone, Debug, Deserialize, Serialize)] +#[cfg_attr(feature = "nif", serde(rename = "Elixir.Anoma.Arm.Delta"))] pub enum Delta { + #[cfg_attr(feature = "nif", serde(rename = "witness"))] Witness(DeltaWitness), + #[cfg_attr(feature = "nif", serde(rename = "proof"))] Proof(DeltaProof), } diff --git a/arm/src/utils.rs b/arm/src/utils.rs index 605e7069..cf054f8f 100644 --- a/arm/src/utils.rs +++ b/arm/src/utils.rs @@ -28,6 +28,28 @@ pub fn words_to_bytes(words: &[u32]) -> &[u8] { bytemuck::cast_slice(words) } +pub mod vec_u32 { + use crate::utils::{bytes_to_words, words_to_bytes}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use serde_bytes::ByteBuf; + + pub fn serialize(t: &[u32], s: S) -> Result + where + S: Serializer, + { + ByteBuf::from(words_to_bytes(t)).serialize(s) + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + Ok(bytes_to_words( + &ByteBuf::deserialize(deserializer)?.into_vec(), + )) + } +} + pub fn hash_two(left: &[u32], right: &[u32]) -> Vec { let mut words = Vec::with_capacity(2 * DIGEST_WORDS); words.extend_from_slice(left); diff --git a/examples/kudo_application/logic_witness/Cargo.toml b/examples/kudo_application/logic_witness/Cargo.toml index 69444560..0bb942f9 100644 --- a/examples/kudo_application/logic_witness/Cargo.toml +++ b/examples/kudo_application/logic_witness/Cargo.toml @@ -6,5 +6,6 @@ edition = "2021" [dependencies] arm = { path = "../../../arm", default-features = false } serde = { version = "1.0.197", default-features = false } +serde_bytes = { version = "0.11.19", default-features = false } risc0-zkvm = { version = "3.0.3", default-features = false, features = ["std", "unstable"] } rand = "0.8" \ No newline at end of file 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 0e2e6dd6..6696e817 100644 --- a/examples/kudo_application/logic_witness/src/kudo_main_witness.rs +++ b/examples/kudo_application/logic_witness/src/kudo_main_witness.rs @@ -21,6 +21,7 @@ pub struct KudoMainWitness { pub kudo_nf_key: NullifierKey, pub issuer: AuthorizationVerifyingKey, pub encryption_sk: SecretKey, + #[serde(with = "serde_bytes")] pub encryption_nonce: [u8; 12], // Denomination related fields diff --git a/examples/simple_counter_application/counter_witness/Cargo.toml b/examples/simple_counter_application/counter_witness/Cargo.toml index f16276fe..a13bc917 100644 --- a/examples/simple_counter_application/counter_witness/Cargo.toml +++ b/examples/simple_counter_application/counter_witness/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" [dependencies] arm = { path = "../../../arm", default-features = false } serde = { version = "1.0.197", default-features = false } +serde_bytes = { version = "0.11.19", default-features = false } rand = "0.8" diff --git a/examples/simple_counter_application/counter_witness/src/lib.rs b/examples/simple_counter_application/counter_witness/src/lib.rs index fb50d3d7..08439e55 100644 --- a/examples/simple_counter_application/counter_witness/src/lib.rs +++ b/examples/simple_counter_application/counter_witness/src/lib.rs @@ -18,6 +18,7 @@ pub struct CounterWitness { pub new_counter_existence_path: MerklePath, pub discovery_pk: AffinePoint, // From the receiver pub discovery_sk: SecretKey, // randomly generated + #[serde(with = "serde_bytes")] pub discovery_nonce: [u8; 12], // randomly generated } diff --git a/examples/simple_transfer_application/simple_transfer_witness/Cargo.toml b/examples/simple_transfer_application/simple_transfer_witness/Cargo.toml index 2e691c73..1f74eaf4 100644 --- a/examples/simple_transfer_application/simple_transfer_witness/Cargo.toml +++ b/examples/simple_transfer_application/simple_transfer_witness/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" [dependencies] arm = { path = "../../../arm", default-features = false } serde = { version = "1.0.197", default-features = false } +serde_bytes = { version = "0.11.19", default-features = false } rand = "0.8" diff --git a/examples/simple_transfer_application/simple_transfer_witness/src/lib.rs b/examples/simple_transfer_application/simple_transfer_witness/src/lib.rs index 66d16c88..5ad723f4 100644 --- a/examples/simple_transfer_application/simple_transfer_witness/src/lib.rs +++ b/examples/simple_transfer_application/simple_transfer_witness/src/lib.rs @@ -10,7 +10,7 @@ use arm::{ merkle_path::MerklePath, nullifier_key::NullifierKey, resource::Resource, - utils::{bytes_to_words, hash_bytes, words_to_bytes}, + utils::{bytes_to_words, hash_bytes, vec_u32, words_to_bytes}, }; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] @@ -39,24 +39,32 @@ pub struct EncryptionInfo { // randomly generated for persistent resource_ciphertext pub sender_sk: SecretKey, // randomly generated for persistent resource_ciphertext(12 bytes) + #[serde(with = "serde_bytes")] pub encryption_nonce: Vec, // The discovery ciphertext for the resource + #[serde(with = "vec_u32")] pub discovery_cipher: Vec, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ForwarderInfo { pub call_type: CallType, + #[serde(with = "serde_bytes")] pub forwarder_addr: Vec, + #[serde(with = "serde_bytes")] pub token_addr: Vec, + #[serde(with = "serde_bytes")] pub user_addr: Vec, pub permit_info: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PermitInfo { + #[serde(with = "serde_bytes")] pub permit_nonce: Vec, + #[serde(with = "serde_bytes")] pub permit_deadline: Vec, + #[serde(with = "serde_bytes")] pub permit_sig: Vec, }