compact serialization (#46)

This commit is contained in:
Giacomo Pasini 2025-01-02 14:42:49 +01:00 committed by GitHub
parent edec3632f1
commit 236a0d0d47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 129 additions and 13 deletions

View File

@ -19,7 +19,7 @@ pub fn leaf(data: &[u8]) -> [u8; 32] {
hasher.finalize().into()
}
pub fn node(a: [u8; 32], b: [u8; 32]) -> [u8; 32] {
pub fn node(a: impl AsRef<[u8]>, b: impl AsRef<[u8]>) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(b"NOMOS_MERKLE_NODE");
hasher.update(a);
@ -55,12 +55,12 @@ pub fn path_root(leaf: [u8; 32], path: &[PathNode]) -> [u8; 32] {
let mut computed_hash = leaf;
for path_node in path {
match path_node {
match &path_node {
PathNode::Left(sibling_hash) => {
computed_hash = node(*sibling_hash, computed_hash);
computed_hash = node(sibling_hash, computed_hash);
}
PathNode::Right(sibling_hash) => {
computed_hash = node(computed_hash, *sibling_hash);
computed_hash = node(computed_hash, sibling_hash);
}
}
}

View File

@ -1,6 +1,8 @@
use std::collections::BTreeMap;
use ledger_proof_statements::ledger::{LedgerBundleWitness, LedgerProofPrivate, LedgerProofPublic};
use ledger_proof_statements::ledger::{
CompactNullifierProofs, LedgerBundleWitness, LedgerProofPrivate, LedgerProofPublic,
};
use crate::bundle::ProvedBundle;
use cl::zone_layer::{ledger::LedgerState, notes::ZoneId};
@ -49,7 +51,7 @@ impl ProvedLedgerTransition {
let ledger_bundle = LedgerBundleWitness {
bundle,
cm_root_proofs,
nf_proofs,
nf_proofs: CompactNullifierProofs::from_paths(nf_proofs),
};
witness.bundles.push(ledger_bundle)
@ -93,3 +95,5 @@ impl ProvedLedgerTransition {
.is_ok()
}
}

View File

@ -6,4 +6,4 @@ edition = "2021"
[dependencies]
cl = { path = "../cl" }
serde = { version = "1.0", features = ["derive"] }
sha2 = "0.10"
sha2 = "0.10"

View File

@ -29,7 +29,7 @@ pub struct LedgerProofPrivate {
pub struct LedgerBundleWitness {
pub bundle: BundlePublic,
pub cm_root_proofs: BTreeMap<[u8; 32], merkle::Path>,
pub nf_proofs: Vec<merkle::Path>,
pub nf_proofs: CompactNullifierProofs,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -37,3 +37,104 @@ pub struct CrossZoneBundle {
pub id: BundleId,
pub zones: Vec<ZoneId>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CompactNullifierProofs {
pub siblings: Vec<u8>,
pub paths: Vec<[u8; 32]>,
}
impl CompactNullifierProofs {
pub fn from_paths(input: Vec<merkle::Path>) -> Self {
let mut siblings = Vec::with_capacity(input.len());
let mut paths = Vec::with_capacity(input.len());
for path in input {
let mut path_bits = [0u8; 32];
assert_eq!(path.len(), 256);
for (i, node) in path.iter().enumerate().rev() {
match node {
merkle::PathNode::Left(sibling) => {
siblings.extend(sibling.into_iter());
}
merkle::PathNode::Right(sibling) => {
siblings.extend(sibling.into_iter());
set_bit(i as u8, &mut path_bits);
}
}
}
paths.push(path_bits);
}
Self { siblings, paths }
}
pub fn len(&self) -> usize {
self.paths.len()
}
}
impl IntoIterator for CompactNullifierProofs {
type Item = merkle::Path;
type IntoIter = CompactNfIterator;
fn into_iter(self) -> CompactNfIterator {
CompactNfIterator {
siblings: self.siblings,
paths: self.paths,
}
}
}
pub struct CompactNfIterator {
pub siblings: Vec<u8>,
pub paths: Vec<[u8; 32]>,
}
impl<'a> Iterator for CompactNfIterator {
type Item = merkle::Path;
fn next(&mut self) -> Option<Self::Item> {
if self.paths.is_empty() {
return None;
}
let path = self.paths.pop().unwrap();
let mut res = Vec::with_capacity(256);
for i in 0..=255 {
if get_bit(i, path) {
res.push(merkle::PathNode::Right(
self.siblings[self.siblings.len() - 32..]
.try_into()
.unwrap(),
))
} else {
res.push(merkle::PathNode::Left(
self.siblings[self.siblings.len() - 32..]
.try_into()
.unwrap(),
))
};
self.siblings.truncate(self.siblings.len() - 32);
}
Some(res)
}
}
fn get_bit(idx: u8, elem: [u8; 32]) -> bool {
let byte = idx / 8;
let bit_in_byte = idx - byte * 8;
(elem[byte as usize] & (1 << bit_in_byte)) != 0
}
fn set_bit(idx: u8, elem: &mut [u8; 32]) {
let byte = idx / 8;
let bit_in_byte = idx - byte * 8;
elem[byte as usize] |= 1 << bit_in_byte;
}

View File

@ -1,6 +1,6 @@
use cl::cl::merkle;
use ledger_proof_statements::{
ledger::{CrossZoneBundle, LedgerProofPrivate, LedgerProofPublic, LedgerBundleWitness},
use ledger_proof_statements::ledger::{
CrossZoneBundle, LedgerBundleWitness, LedgerProofPrivate, LedgerProofPublic,
};
use risc0_zkvm::{guest::env, serde};
@ -15,12 +15,23 @@ fn main() {
let mut cross_bundles = vec![];
let mut outputs = vec![];
for LedgerBundleWitness { bundle, cm_root_proofs, nf_proofs } in bundles {
env::verify(nomos_cl_bundle_risc0_proof::BUNDLE_ID, &serde::to_vec(&bundle).unwrap()).unwrap();
for LedgerBundleWitness {
bundle,
cm_root_proofs,
nf_proofs,
} in bundles
{
env::verify(
nomos_cl_bundle_risc0_proof::BUNDLE_ID,
&serde::to_vec(&bundle).unwrap(),
)
.unwrap();
if let Some(ledger_update) = bundle.zone_ledger_updates.get(&id) {
for past_cm_root in &ledger_update.cm_roots {
let past_cm_root_proof = cm_root_proofs.get(past_cm_root).expect("missing cm root proof");
let past_cm_root_proof = cm_root_proofs
.get(past_cm_root)
.expect("missing cm root proof");
let expected_current_cm_root = merkle::path_root(*past_cm_root, past_cm_root_proof);
assert!(old_ledger.valid_cm_root(expected_current_cm_root))
}