Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce PackedProofs to semaphore-rs #85

Merged
merged 4 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ bincode = "1.3.3"
# TODO: Remove
ethers-core = { git = "https://github.com/gakonst/ethers-rs", default-features = false }
bytemuck = "1.13.1"
ethabi = "18.0.0"

[dev-dependencies]
serial_test = "3"
Expand Down
5 changes: 2 additions & 3 deletions benches/lazy_merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,17 @@ fn bench_restore_dense_mmap_tree(criterion: &mut Criterion) {
create_values_for_tree(14),
];


let mut group = criterion.benchmark_group("bench_restore_dense_mmap_tree");

(0..3).zip(tree_values).for_each(|(id, value)| {

let file = tempfile::NamedTempFile::new().unwrap();
let path = file.path().to_str().unwrap();
{
let _tree = LazyMerkleTree::<PoseidonHash, Canonical>::new_mmapped_with_dense_prefix_with_init_values(value.depth, value.prefix_depth, &value.empty_value, &value.initial_values, path).unwrap();
let _root = _tree.root();
}

group.bench_with_input(
BenchmarkId::from_parameter(format!("restore_dense_mmap_tree_depth_{}", value.depth)),
&(id, value),
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod hash;
pub mod identity;
pub mod lazy_merkle_tree;
pub mod merkle_tree;
pub mod packed_proof;
pub mod poseidon;
pub mod poseidon_tree;
pub mod protocol;
Expand Down
113 changes: 113 additions & 0 deletions src/packed_proof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use std::{
fmt::Display,
str::{from_utf8, FromStr},
};

use crate::protocol::Proof;
use ethabi::{decode, encode, ParamType, Token};
use ethers_core::types::U256;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::util::{bytes_from_hex, bytes_to_hex, deserialize_bytes, serialize_bytes};

/// A packed proof is a representation of the ZKP in a single attribute (as
/// opposed to array of arrays) which is easier to transport
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PackedProof(pub [u8; 256]);

impl From<Proof> for PackedProof {
fn from(proof: Proof) -> Self {
let tokens = Token::FixedArray(vec![
Token::Uint(proof.0 .0),
Token::Uint(proof.0 .1),
Token::Uint(proof.1 .0[0]),
Token::Uint(proof.1 .0[1]),
Token::Uint(proof.1 .1[0]),
Token::Uint(proof.1 .1[1]),
Token::Uint(proof.2 .0),
Token::Uint(proof.2 .1),
]);

let bytes = encode(&[tokens]);
let mut encoded = [0u8; 256];
encoded.copy_from_slice(&bytes[..256]);
Self(encoded)
}
}

impl From<PackedProof> for Proof {
fn from(proof: PackedProof) -> Self {
let decoded = decode(&vec![ParamType::Uint(256); 8], &proof.0).unwrap();
let decoded_uint_array = decoded
.into_iter()
.map(|x| x.into_uint().unwrap())
.collect::<Vec<U256>>();

let a = (decoded_uint_array[0], decoded_uint_array[1]);
let b = ([decoded_uint_array[2], decoded_uint_array[3]], [
decoded_uint_array[4],
decoded_uint_array[5],
]);
let c = (decoded_uint_array[6], decoded_uint_array[7]);
Self(a, b, c)
}
}

impl Display for PackedProof {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let hex = bytes_to_hex::<256, 514>(&self.0);
write!(
f,
"{}",
from_utf8(&hex).expect("failed to convert to string")
)
}
}

impl FromStr for PackedProof {
type Err = hex::FromHexError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
bytes_from_hex::<256>(s).map(Self)
}
}

impl Serialize for PackedProof {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serialize_bytes::<256, 514, S>(serializer, &self.0)
}
}

impl<'de> Deserialize<'de> for PackedProof {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let bytes = deserialize_bytes::<256, _>(deserializer)?;
Ok(Self(bytes))
}
}

#[cfg(test)]
pub mod test {
use super::*;

#[test]
fn test_serializing_proof_into_packed_proof() {
let proof = Proof(
(U256::from(1), U256::from(2)),
([U256::from(3), U256::from(4)], [
U256::from(5),
U256::from(6),
]),
(U256::from(7), U256::from(8)),
);

let packed_proof = PackedProof::from(proof);

assert_eq!(packed_proof.to_string(), "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008");
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a test that parses from string (with or without 0x)?

And another that serializes/deserializes to json?


dbg!(packed_proof.to_string());

let proof2 = Proof::from(packed_proof);

assert_eq!(proof, proof2);
}
}
Loading