diff --git a/Cargo.toml b/Cargo.toml index 3d3fef3..ddb0fd7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,18 +9,13 @@ repository = "https://github.com/arnaucube/fri-commitment" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -ark-std = "0.3.0" -ark-ff = "0.3.0" -ark-poly = "0.3.0" -ark-bn254 = { version = "^0.3.0", default-features = false } -ark-ed-on-bn254 = { version = "^0.3.0", default-features = true } -ark-crypto-primitives = { version = "^0.3.0", default-features = true } +ark-std = "0.4.0" +ark-ff = "0.4.0" +ark-poly = "0.4.0" +ark-bn254 = { version = "0.4.0", default-features = false } +ark-ed-on-bn254 = { version = "0.4.0", default-features = true } +ark-crypto-primitives = { version = "0.4.0", default-features = true } +ark-serialize = { version = "0.4.0", default-features = false, features = [ "derive" ] } rand = { version = "0.8", features = [ "std", "std_rng" ] } - -# poseidon related -arkworks-utils = { git = "https://github.com/aragonzkresearch/arkworks-gadgets", name="arkworks-utils", features=["poseidon_bn254_x5_4"] } -arkworks-native-gadgets = { git = "https://github.com/aragonzkresearch/arkworks-gadgets", name="arkworks-native-gadgets"} - -# transcript related +sha3 = "0.10.6" merlin = { version = "3.0.0" } -ark-serialize = { version = "^0.3.0", default-features = false, features = [ "derive" ] } diff --git a/src/lib.rs b/src/lib.rs index dc9d5e1..6ce5758 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,13 @@ #![allow(non_upper_case_globals)] pub mod merkletree; -use merkletree::MerkleTreePoseidon as MT; +use merkletree::{Hash, MerkleTree}; pub mod transcript; use transcript::Transcript; use ark_ff::PrimeField; use ark_poly::{ - univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain, UVPolynomial, + univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, GeneralEvaluationDomain, }; use ark_std::cfg_into_iter; @@ -19,20 +19,22 @@ use ark_std::ops::Mul; // rho^-1 const rho1: usize = 8; // WIP -pub struct FRI_LDT> { +pub struct FRI_LDT, H: Hash> { _f: PhantomData, _poly: PhantomData

, + _h: PhantomData, } -impl> FRI_LDT { +impl, H: Hash> FRI_LDT { pub fn new() -> Self { Self { _f: PhantomData, _poly: PhantomData, + _h: PhantomData, } } - pub fn split(p: &P) -> (P, P) { + fn split(p: &P) -> (P, P) { // let d = p.degree() + 1; let d = p.coeffs().len(); if (d != 0) && (d & (d - 1) != 0) { @@ -57,7 +59,7 @@ impl> FRI_LDT { let d = p.degree(); let mut commitments: Vec = Vec::new(); - let mut mts: Vec> = Vec::new(); + let mut mts: Vec> = Vec::new(); // f_0(x) = fL_0(x^2) + x fR_0(x^2) let mut f_i1 = p.clone(); @@ -85,8 +87,8 @@ impl> FRI_LDT { .map(|k| f_i1.evaluate(&eval_sub_domain.element(k))) .collect(); - // commit to f_{i+1}(x) = fL_i(x) + alpha_i * fR_i(x) - let (cm_i, mt_i) = MT::commit(&subdomain_evaluations); // commit to the evaluation domain instead + // commit to f_{i+1}(x) = fL_i(x) + alpha_i * fR_i(x), commit to the evaluation domain + let (cm_i, mt_i) = MerkleTree::::commit(&subdomain_evaluations); commitments.push(cm_i); mts.push(mt_i); transcript.add(b"root_i", &cm_i); @@ -181,7 +183,7 @@ impl> FRI_LDT { transcript.add(b"f_i(-z^{2^i})", &evals[i + 1]); // check commitment opening - if !MT::verify( + if !MerkleTree::::verify( commitments[i_z], F::from(z_pos as u32), evals[i], @@ -220,6 +222,7 @@ mod tests { use ark_poly::univariate::DensePolynomial; use ark_poly::Polynomial; use ark_std::log2; + use merkletree::Keccak256Hash; #[test] fn test_split() { @@ -228,7 +231,7 @@ mod tests { let p = DensePolynomial::::rand(deg, &mut rng); assert_eq!(p.degree(), deg); - type FRID = FRI_LDT>; + type FRID = FRI_LDT, Keccak256Hash>; let (pL, pR) = FRID::split(&p); // check that f(z) == fL(x^2) + x * fR(x^2), for a rand z @@ -248,7 +251,7 @@ mod tests { assert_eq!(p.degree(), deg); // println!("p {:?}", p); - type FRID = FRI_LDT>; + type FRID = FRI_LDT, Keccak256Hash>; let (commitments, mtproofs, evals, constvals) = FRID::prove(&p); // commitments contains the commitments to each f_0, f_1, ..., f_n, with n=log2(d) diff --git a/src/merkletree.rs b/src/merkletree.rs index 7297929..f0d4fa7 100644 --- a/src/merkletree.rs +++ b/src/merkletree.rs @@ -4,40 +4,59 @@ // https://github.com/vocdoni/arbo). use ark_ff::{BigInteger, PrimeField}; +use ark_serialize::CanonicalSerialize; use ark_std::log2; -use arkworks_native_gadgets::poseidon; -use arkworks_native_gadgets::poseidon::FieldHasher; -use arkworks_utils::{ - bytes_matrix_to_f, bytes_vec_to_f, poseidon_params::setup_poseidon_params, Curve, -}; +use ark_std::marker::PhantomData; +use sha3::{Digest, Keccak256}; -pub struct Params { - pub poseidon_hash: poseidon::Poseidon, +// abstraction to set the hash function used +pub trait Hash: Clone { + fn hash(_in: &[F]) -> F; +} + +#[derive(Clone, Copy, Debug)] +pub struct Keccak256Hash { + phantom: PhantomData, +} +impl Hash for Keccak256Hash { + fn hash(_in: &[F]) -> F { + let mut buf = vec![]; + _in.serialize_uncompressed(&mut buf).unwrap(); + + let mut h = Keccak256::default(); + h.update(buf); + let r = h.finalize(); + let out = F::from_le_bytes_mod_order(&r); + out + } } #[derive(Clone, Debug)] -pub struct Node { +pub struct Node> { + phantom: PhantomData, hash: F, - left: Option>>, - right: Option>>, + left: Option>>, + right: Option>>, value: Option, } -impl Node { - pub fn new_leaf(params: &Params, v: F) -> Self { - let h = params.poseidon_hash.hash(&[v]).unwrap(); +impl> Node { + pub fn new_leaf(v: F) -> Self { + let h = H::hash(&[v]); Self { + phantom: PhantomData::, hash: h, left: None, right: None, value: Some(v), } } - pub fn new_node(params: &Params, l: Self, r: Self) -> Self { + pub fn new_node(l: Self, r: Self) -> Self { let left = Box::new(l); let right = Box::new(r); - let hash = params.poseidon_hash.hash(&[left.hash, right.hash]).unwrap(); + let hash = H::hash(&[left.hash, right.hash]); Self { + phantom: PhantomData::, hash, left: Some(left), right: Some(right), @@ -46,40 +65,39 @@ impl Node { } } -pub struct MerkleTree { - pub root: Node, +pub struct MerkleTree> { + pub root: Node, nlevels: u32, } -impl MerkleTree { - pub fn setup(poseidon_hash: &poseidon::Poseidon) -> Params { - Params { - poseidon_hash: poseidon_hash.clone(), - } - } - pub fn new(params: &Params, values: Vec) -> Self { +impl> MerkleTree { + pub fn commit(values: &[F]) -> (F, Self) { // for the moment assume that values length is a power of 2. if (values.len() != 0) && (values.len() & (values.len() - 1) != 0) { panic!("values.len() should be a power of 2"); } // prepare the leafs - let mut leaf_nodes: Vec> = Vec::new(); + let mut leaf_nodes: Vec> = Vec::new(); for i in 0..values.len() { - let node = Node::::new_leaf(¶ms, values[i]); + let node = Node::::new_leaf(values[i]); leaf_nodes.push(node); } // go up from the leafs to the root - let top_nodes = Self::up_from_nodes(¶ms, leaf_nodes); + let top_nodes = Self::up_from_nodes(leaf_nodes); - Self { - root: top_nodes[0].clone(), - nlevels: log2(values.len()), - } + ( + top_nodes[0].hash, + Self { + root: top_nodes[0].clone(), + nlevels: log2(values.len()), + }, + ) } - fn up_from_nodes(params: &Params, nodes: Vec>) -> Vec> { + fn up_from_nodes(nodes: Vec>) -> Vec> { if nodes.len() == 0 { - return [Node:: { + return [Node:: { + phantom: PhantomData::, hash: F::from(0_u32), left: None, right: None, @@ -90,22 +108,22 @@ impl MerkleTree { if nodes.len() == 1 { return nodes; } - let mut next_level_nodes: Vec> = Vec::new(); + let mut next_level_nodes: Vec> = Vec::new(); for i in (0..nodes.len()).step_by(2) { - let node = Node::::new_node(¶ms, nodes[i].clone(), nodes[i + 1].clone()); + let node = Node::::new_node(nodes[i].clone(), nodes[i + 1].clone()); next_level_nodes.push(node); } - return Self::up_from_nodes(params, next_level_nodes); + return Self::up_from_nodes(next_level_nodes); } fn get_path(num_levels: u32, value: F) -> Vec { - let value_bytes = value.into_repr().to_bytes_le(); + let value_bytes = value.into_bigint().to_bytes_le(); let mut path = Vec::new(); for i in 0..num_levels { path.push(value_bytes[(i / 8) as usize] & (1 << (i % 8)) != 0); } path } - pub fn gen_proof(&self, index: F) -> Vec { + pub fn open(&self, index: F) -> Vec { // start from root, and go down to the index, while getting the siblings at each level let path = Self::get_path(self.nlevels, index); // reverse path as we're going from up to down @@ -114,7 +132,7 @@ impl MerkleTree { siblings = Self::go_down(path_inv, self.root.clone(), siblings); return siblings; } - fn go_down(path: Vec, node: Node, mut siblings: Vec) -> Vec { + fn go_down(path: Vec, node: Node, mut siblings: Vec) -> Vec { if !node.value.is_none() { return siblings; } @@ -126,20 +144,14 @@ impl MerkleTree { return Self::go_down(path[1..].to_vec(), *node.right.unwrap(), siblings); } } - pub fn verify(params: &Params, root: F, index: F, value: F, siblings: Vec) -> bool { - let mut h = params.poseidon_hash.hash(&[value]).unwrap(); + pub fn verify(root: F, index: F, value: F, siblings: Vec) -> bool { + let mut h = H::hash(&[value]); let path = Self::get_path(siblings.len() as u32, index); for i in 0..siblings.len() { if !path[i] { - h = params - .poseidon_hash - .hash(&[h, siblings[siblings.len() - 1 - i]]) - .unwrap(); + h = H::hash(&[h, siblings[siblings.len() - 1 - i]]); } else { - h = params - .poseidon_hash - .hash(&[siblings[siblings.len() - 1 - i], h]) - .unwrap(); + h = H::hash(&[siblings[siblings.len() - 1 - i], h]); } } if h == root { @@ -149,47 +161,6 @@ impl MerkleTree { } } -pub struct MerkleTreePoseidon(MerkleTree); - -impl MerkleTreePoseidon { - pub fn commit(values: &[F]) -> (F, Self) { - let poseidon_params = poseidon_setup_params::(Curve::Bn254, 5, 4); - let poseidon_hash = poseidon::Poseidon::new(poseidon_params); - let params = MerkleTree::setup(&poseidon_hash); - let mt = MerkleTree::new(¶ms, values.to_vec()); - (mt.root.hash, MerkleTreePoseidon(mt)) - } - pub fn open(&self, index: F) -> Vec { - self.0.gen_proof(index) - } - pub fn verify(root: F, index: F, value: F, siblings: Vec) -> bool { - let poseidon_params = poseidon_setup_params::(Curve::Bn254, 5, 4); - let poseidon_hash = poseidon::Poseidon::new(poseidon_params); - let params = MerkleTree::setup(&poseidon_hash); - MerkleTree::verify(¶ms, root, index, value, siblings) - } -} - -pub fn poseidon_setup_params( - curve: Curve, - exp: i8, - width: u8, -) -> poseidon::PoseidonParameters { - let pos_data = setup_poseidon_params(curve, exp, width).unwrap(); - - let mds_f = bytes_matrix_to_f(&pos_data.mds); - let rounds_f = bytes_vec_to_f(&pos_data.rounds); - - poseidon::PoseidonParameters { - mds_matrix: mds_f, - round_keys: rounds_f, - full_rounds: pos_data.full_rounds, - partial_rounds: pos_data.partial_rounds, - sbox: poseidon::sbox::PoseidonSbox(pos_data.exp), - width: pos_data.width, - } -} - #[cfg(test)] mod tests { use super::*; @@ -199,47 +170,41 @@ mod tests { #[test] fn test_path() { assert_eq!( - MerkleTree::get_path(8, Fr::from(0_u32)), + MerkleTree::>::get_path(8, Fr::from(0_u32)), [false, false, false, false, false, false, false, false] ); assert_eq!( - MerkleTree::get_path(8, Fr::from(1_u32)), + MerkleTree::>::get_path(8, Fr::from(1_u32)), [true, false, false, false, false, false, false, false] ); assert_eq!( - MerkleTree::get_path(8, Fr::from(2_u32)), + MerkleTree::>::get_path(8, Fr::from(2_u32)), [false, true, false, false, false, false, false, false] ); assert_eq!( - MerkleTree::get_path(8, Fr::from(3_u32)), + MerkleTree::>::get_path(8, Fr::from(3_u32)), [true, true, false, false, false, false, false, false] ); assert_eq!( - MerkleTree::get_path(8, Fr::from(254_u32)), + MerkleTree::>::get_path(8, Fr::from(254_u32)), [false, true, true, true, true, true, true, true] ); assert_eq!( - MerkleTree::get_path(8, Fr::from(255_u32)), + MerkleTree::>::get_path(8, Fr::from(255_u32)), [true, true, true, true, true, true, true, true] ); } #[test] fn test_new_empty_tree() { - let poseidon_params = poseidon_setup_params::(Curve::Bn254, 5, 4); - let poseidon_hash = poseidon::Poseidon::new(poseidon_params); - - let params = MerkleTree::setup(&poseidon_hash); - let mt = MerkleTree::new(¶ms, Vec::new()); + let (root, mt) = MerkleTree::>::commit(&[]); assert_eq!(mt.root.hash, Fr::from(0_u32)); + assert_eq!(root, Fr::from(0_u32)); } #[test] fn test_proof() { - let poseidon_params = poseidon_setup_params::(Curve::Bn254, 5, 4); - let poseidon_hash = poseidon::Poseidon::new(poseidon_params); - - let params = MerkleTree::setup(&poseidon_hash); + type MT = MerkleTree>; let values = [ Fr::from(0_u32), @@ -252,32 +217,22 @@ mod tests { Fr::from(203_u32), ]; - let mt = MerkleTree::new(¶ms, values.to_vec()); + let (root, mt) = MT::commit(&values); assert_eq!( - mt.root.hash.to_string(), - "Fp256 \"(10E90845D7A113686E4F2F30D73B315BA891A5DB9A58782F1260C35F99660794)\"" + root.to_string(), + "6195952497672867974990959901930625199810318409246598214215524466855665265259" ); let index = 3; let index_F = Fr::from(index as u32); - let siblings = mt.gen_proof(index_F); + let siblings = mt.open(index_F); - assert!(MerkleTree::verify( - ¶ms, - mt.root.hash, - index_F, - values[index], - siblings - )); + assert!(MT::verify(root, index_F, values[index], siblings)); } #[test] fn test_proofs() { - let poseidon_params = poseidon_setup_params::(Curve::Bn254, 5, 4); - let poseidon_hash = poseidon::Poseidon::new(poseidon_params); - - let params = MerkleTree::setup(&poseidon_hash); - + type MT = MerkleTree>; let mut rng = ark_std::test_rng(); let n_values = 64; @@ -287,19 +242,13 @@ mod tests { values.push(v); } - let mt = MerkleTree::new(¶ms, values.to_vec()); + let (root, mt) = MT::commit(&values); assert_eq!(mt.nlevels, 6); for i in 0..n_values { let i_Fr = Fr::from(i as u32); - let siblings = mt.gen_proof(i_Fr); - assert!(MerkleTree::verify( - ¶ms, - mt.root.hash, - i_Fr, - values[i], - siblings - )); + let siblings = mt.open(i_Fr); + assert!(MT::verify(root, i_Fr, values[i], siblings)); } } } diff --git a/src/transcript.rs b/src/transcript.rs index 4389a1f..45a4243 100644 --- a/src/transcript.rs +++ b/src/transcript.rs @@ -20,7 +20,7 @@ impl Transcript { } pub fn add(&mut self, label: &'static [u8], r: &T) { let mut buf = vec![]; - r.serialize(&mut buf).unwrap(); + r.serialize_uncompressed(&mut buf).unwrap(); self.transcript.append_message(label, buf.as_ref()); } pub fn get_challenge(&mut self, label: &'static [u8]) -> F {