Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ This is a shielded resource machine implementation based on [Risc0-zkvm](https:/
- **`arm/`**: The main Anoma Shielded Resource Machine implementation providing the core functionality for Anoma SDK and Validator.

- **`arm_circuits/`**: Demonstration circuits for arms and applications:
- **compliance**: Basic compliance checking circuit
- **trivial_logic**: Minimal logic circuit example, also used in padding resources
- **compliance**: Compliance checking circuit
- **trivial_logic**: Minimal logic circuit example
- **proof aggregation (batch_aggregation, sequential_aggregation)**: Circuits for single-run aggregation and IVC-based aggregation, respectively
- **logic_test**: The logic circuit contains hardcoded data to cover all instance fields and is used only in tests
- **counter**: The simple counter logic circuit
Expand Down
3 changes: 1 addition & 2 deletions arm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ slab = "0.4.11"

[features]
default = ["transaction", "prove"]
transaction = ["compliance_circuit", "dep:sha3", "client"]
transaction = ["compliance_circuit", "dep:sha3"]
compliance_circuit = []
fast_prover = []
composite_prover = []
groth16_prover = []
nif = ["dep:rustler"]
prove = ["risc0-zkvm/prove"]
bonsai = ["risc0-zkvm/bonsai"]
client = ["risc0-zkvm/client"]
cuda = ["risc0-zkvm/cuda"]
test_circuit = []
test = ["transaction", "test_circuit"]
Expand Down
Binary file modified arm/elfs/batch_aggregation.bin
Binary file not shown.
Binary file modified arm/elfs/compliance-guest.bin
Binary file not shown.
94 changes: 52 additions & 42 deletions arm/src/action.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{
action_tree::MerkleTree,
compliance::ComplianceInstance,
compliance_unit::ComplianceUnit,
error::ArmError,
logic_proof::{LogicVerifier, LogicVerifierInputs},
Expand All @@ -11,27 +10,27 @@ use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Action {
pub compliance_units: Vec<ComplianceUnit>,
pub compliance_unit: ComplianceUnit,
pub logic_verifier_inputs: Vec<LogicVerifierInputs>,
}

impl Action {
pub fn new(
compliance_units: Vec<ComplianceUnit>,
compliance_unit: ComplianceUnit,
logic_verifiers: Vec<LogicVerifier>,
) -> Result<Self, ArmError> {
let logic_verifier_inputs: Vec<LogicVerifierInputs> = logic_verifiers
.into_iter()
.map(|lv| lv.try_into())
.collect::<Result<_, _>>()?;
Ok(Action {
compliance_units,
compliance_unit,
logic_verifier_inputs,
})
}

pub fn get_compliance_units(&self) -> &Vec<ComplianceUnit> {
&self.compliance_units
pub fn get_compliance_unit(&self) -> &ComplianceUnit {
&self.compliance_unit
}

pub fn get_logic_verifier_inputs(&self) -> &Vec<LogicVerifierInputs> {
Expand All @@ -41,42 +40,52 @@ impl Action {
pub(crate) fn get_logic_verifiers(&self) -> Result<Vec<LogicVerifier>, ArmError> {
let mut logic_verifiers = Vec::new();

let compliance_intances = self
.compliance_units
.iter()
.map(|unit| unit.get_instance())
.collect::<Result<Vec<ComplianceInstance>, ArmError>>()?;
let compliance_instance = self.compliance_unit.get_instance()?;

// Construct the action tree
let tags: Vec<Digest> = compliance_intances
// Compute the action tree root
let tags: Vec<Digest> = compliance_instance
.consumed_memorandums
.iter()
.flat_map(|instance| vec![instance.consumed_nullifier, instance.created_commitment])
.map(|memo| memo.resource_nullifier)
.chain(
compliance_instance
.created_memorandums
.iter()
.map(|memo| memo.resource_commitment),
)
.collect();
let logics = compliance_intances
.iter()
.flat_map(|instance| vec![instance.consumed_logic_ref, instance.created_logic_ref])
.collect::<Vec<_>>();
let action_tree = MerkleTree::from(tags.clone());
let root = action_tree.root();
let action_tree_root = Self::construct_action_tree(&tags).root();

// Match logic verifier inputs with the tags in the action tree
if tags.len() != self.logic_verifier_inputs.len() {
return Err(ArmError::TagNotFound);
}
for tag_verifyingkey_isconsumed in compliance_instance
.consumed_memorandums
.iter()
.map(|memo| (memo.resource_nullifier, memo.resource_logic_ref, true))
.chain(
compliance_instance
.created_memorandums
.iter()
.map(|memo| (memo.resource_commitment, memo.resource_logic_ref, false)),
)
{
let (tag, verifying_key, is_consumed) = tag_verifyingkey_isconsumed;

for (index, (tag, logic)) in tags.iter().zip(logics.iter()).enumerate() {
// Look up the tag in the `logic_verifier_inputs`.
if let Some(input) = self
.logic_verifier_inputs
.iter()
.find(|input| &input.tag == tag)
.find(|input| input.tag == tag)
{
if input.verifying_key != *logic {
if input.verifying_key != verifying_key {
return Err(ArmError::VerifyingKeyMismatch);
}

let is_consumed = index % 2 == 0;
let verifier = input.clone().to_logic_verifier(is_consumed, root)?;
let verifier = input
.clone()
.to_logic_verifier(is_consumed, action_tree_root)?;
logic_verifiers.push(verifier);
} else {
return Err(ArmError::TagNotFound);
Expand All @@ -86,10 +95,8 @@ impl Action {
Ok(logic_verifiers)
}

pub fn verify(self) -> Result<(), ArmError> {
for unit in &self.compliance_units {
unit.verify()?;
}
pub fn verify(&self) -> Result<(), ArmError> {
self.compliance_unit.verify()?;

let logic_verifiers = self.get_logic_verifiers()?;
for verifier in logic_verifiers.iter() {
Expand All @@ -99,25 +106,28 @@ impl Action {
Ok(())
}

// This function computes the delta of the action by summing up the deltas
// of each compliance unit.
/// Returns the delta of this action's compliance unit.
pub fn delta(&self) -> Result<ProjectivePoint, ArmError> {
self.compliance_units
.iter()
.try_fold(ProjectivePoint::IDENTITY, |acc, unit| {
Ok(acc + unit.delta()?)
})
self.compliance_unit.delta()
}

pub fn get_delta_msg(&self) -> Result<Vec<u8>, ArmError> {
let mut msg = Vec::new();
for unit in &self.compliance_units {
if let Ok(instance) = unit.get_instance() {
msg.extend_from_slice(&instance.delta_msg());
} else {
return Err(ArmError::InvalidComplianceInstance);
}
if let Ok(instance) = self.compliance_unit.get_instance() {
msg.extend_from_slice(&instance.delta_msg());
} else {
return Err(ArmError::InvalidComplianceInstance);
}
Ok(msg)
}

/// Computes the action tree from the passed tags (purported consumed nullifiers and created commitments).
/// A canonical ordering is settled by sorting. For consistency, should be used in both, creation
/// and verification of the action.
pub fn construct_action_tree(tags: &[Digest]) -> MerkleTree {
let mut ordered_tags = tags.to_vec();
ordered_tags.sort();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the compliance tag order to avoid adding sorting logic on both frontend and verifier sides


MerkleTree::new(ordered_tags)
}
}
31 changes: 10 additions & 21 deletions arm/src/aggregation/batch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::aggregation::{
constants::{BATCH_AGGREGATION_PK, BATCH_AGGREGATION_VK},
BatchCU, BatchLP,
};
use crate::compliance::ComplianceInstanceWords;
use crate::constants::COMPLIANCE_VK;
use crate::error::ArmError;
use crate::transaction::Transaction;
Expand All @@ -32,16 +31,11 @@ impl BatchAggregation {
receipts: lp_receipts,
} = tx.get_batch_lp()?;

let mut cu_instances_u32: Vec<ComplianceInstanceWords> = Vec::new();
for ci in cu_instances.iter() {
cu_instances_u32.push(ComplianceInstanceWords {
u32_words: bytes_to_words(ci).try_into().map_err(|_| {
ArmError::ProveFailed(
"Error converting compliance instance into fixed-size u32 words".into(),
)
})?,
});
}
let cu_instances_u32: Vec<Vec<u32>> = cu_instances
.iter()
.map(|bytes| bytes_to_words(bytes))
.collect();

let lp_instances_u32: Vec<Vec<u32>> = lp_instances
.iter()
.map(|bytes| bytes_to_words(bytes))
Expand Down Expand Up @@ -117,16 +111,11 @@ impl BatchAggregation {
receipts: _,
} = tx.get_batch_lp()?;

let mut compliance_instances_u32: Vec<ComplianceInstanceWords> = Vec::new();
for ci in compliance_instances.iter() {
compliance_instances_u32.push(ComplianceInstanceWords {
u32_words: bytes_to_words(ci).try_into().map_err(|_| {
ArmError::ProofVerificationFailed(
"Error converting compliance instance into fixed-size u32 words".into(),
)
})?,
});
}
let compliance_instances_u32: Vec<Vec<u32>> = compliance_instances
.iter()
.map(|bytes| bytes_to_words(bytes))
.collect();

let logic_instances_u32: Vec<Vec<u32>> = logic_instances
.iter()
.map(|bytes| bytes_to_words(bytes))
Expand Down
2 changes: 1 addition & 1 deletion arm/src/aggregation/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ lazy_static! {
Digest::from_hex("394cb1135c1434ad1e0c866da77d5c3eaa8692cb56848c573ac98907570b6815").unwrap();

// Batch aggregation verification key / Batch aggregation image id.
pub static ref BATCH_AGGREGATION_VK: Digest = Digest::from_hex("6927c46ff70ab6ea4000928c831515fdb735babfb59e07a7843606d98c62a5c9").unwrap();
pub static ref BATCH_AGGREGATION_VK: Digest = Digest::from_hex("cd075be94411c1f98c7524e16fca2b88c96ca6f3811c9a8a18ccde076e9110b6").unwrap();
}
4 changes: 2 additions & 2 deletions arm/src/aggregation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Transaction {
let cus: Vec<ComplianceUnit> = self
.actions
.iter()
.flat_map(|a| a.get_compliance_units().clone())
.map(|a| a.get_compliance_unit().clone())
.collect();

let cu_instances: Vec<Vec<u8>> = cus.iter().map(|cu| cu.instance.clone()).collect();
Expand Down Expand Up @@ -144,7 +144,7 @@ impl Transaction {
/// Returns `true` if any compliance or resource logic proof is `None`.
fn base_proofs_are_empty(&self) -> bool {
for a in self.actions.iter() {
if a.get_compliance_units().iter().any(|cu| cu.proof.is_none()) {
if a.get_compliance_unit().proof.is_none() {
return true;
}
if a.get_logic_verifier_inputs()
Expand Down
Loading
Loading