remove phantom date and refactor
This commit is contained in:
parent
cba274b64b
commit
c725043c4d
|
@ -36,21 +36,17 @@ use crate::circuits::params::{MAX_DEPTH, BOT_DEPTH, N_FIELD_ELEMS_PER_CELL, N_CE
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SlotTreeCircuit<
|
pub struct SlotTreeCircuit<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
|
||||||
> {
|
> {
|
||||||
pub tree: MerkleTreeCircuit<F,C,D,H>, // slot tree
|
pub tree: MerkleTreeCircuit<F,D>, // slot tree
|
||||||
pub block_trees: Vec<MerkleTreeCircuit<F,C,D,H>>, // vec of block trees
|
pub block_trees: Vec<MerkleTreeCircuit<F,D>>, // vec of block trees
|
||||||
pub cell_data: Vec<Vec<F>>, // cell data as field elements
|
pub cell_data: Vec<Vec<F>>, // cell data as field elements
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
> Default for SlotTreeCircuit<F,D>{
|
||||||
> Default for SlotTreeCircuit<F,C,D,H>{
|
|
||||||
/// slot tree with fake data, for testing only
|
/// slot tree with fake data, for testing only
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
// generate fake cell data
|
// generate fake cell data
|
||||||
|
@ -78,7 +74,7 @@ impl<
|
||||||
let start = i * N_CELLS_IN_BLOCKS;
|
let start = i * N_CELLS_IN_BLOCKS;
|
||||||
let end = (i + 1) * N_CELLS_IN_BLOCKS;
|
let end = (i + 1) * N_CELLS_IN_BLOCKS;
|
||||||
let b_tree = Self::get_block_tree(&leaves[start..end].to_vec()); // use helper function
|
let b_tree = Self::get_block_tree(&leaves[start..end].to_vec()); // use helper function
|
||||||
MerkleTreeCircuit::<F,C,D,H>{ tree:b_tree, _phantom:Default::default()}
|
MerkleTreeCircuit::<F,D>{ tree:b_tree}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
// get the roots or block trees
|
// get the roots or block trees
|
||||||
|
@ -88,10 +84,10 @@ impl<
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
// create slot tree
|
// create slot tree
|
||||||
let slot_tree = MerkleTree::<F, H>::new(&block_roots, zero).unwrap();
|
let slot_tree = MerkleTree::<F>::new(&block_roots, zero).unwrap();
|
||||||
|
|
||||||
Self{
|
Self{
|
||||||
tree: MerkleTreeCircuit::<F,C,D,H>{ tree:slot_tree, _phantom:Default::default()},
|
tree: MerkleTreeCircuit::<F,D>{ tree:slot_tree},
|
||||||
block_trees,
|
block_trees,
|
||||||
cell_data,
|
cell_data,
|
||||||
}
|
}
|
||||||
|
@ -100,10 +96,8 @@ impl<
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
> SlotTreeCircuit<F,D> {
|
||||||
> SlotTreeCircuit<F,C,D, H> {
|
|
||||||
|
|
||||||
/// Slot tree with fake data, for testing only
|
/// Slot tree with fake data, for testing only
|
||||||
pub fn new_for_testing() -> Self {
|
pub fn new_for_testing() -> Self {
|
||||||
|
@ -133,9 +127,9 @@ impl<
|
||||||
let b_tree = Self::get_block_tree(&leaves_block);
|
let b_tree = Self::get_block_tree(&leaves_block);
|
||||||
|
|
||||||
// Create a block tree circuit
|
// Create a block tree circuit
|
||||||
let block_tree_circuit = MerkleTreeCircuit::<F, C, D, H> {
|
let block_tree_circuit = MerkleTreeCircuit::<F, D> {
|
||||||
tree: b_tree,
|
tree: b_tree,
|
||||||
_phantom: Default::default(),
|
// _phantom: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Now replicate this block tree for all N_BLOCKS blocks
|
// Now replicate this block tree for all N_BLOCKS blocks
|
||||||
|
@ -148,16 +142,15 @@ impl<
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Create the slot tree from block roots
|
// Create the slot tree from block roots
|
||||||
let slot_tree = MerkleTree::<F, H>::new(&block_roots, zero).unwrap();
|
let slot_tree = MerkleTree::<F>::new(&block_roots, zero).unwrap();
|
||||||
|
|
||||||
// Create the full cell data and cell hash by repeating the block data
|
// Create the full cell data and cell hash by repeating the block data
|
||||||
let cell_data = vec![cell_data_block.clone(); N_BLOCKS].concat();
|
let cell_data = vec![cell_data_block.clone(); N_BLOCKS].concat();
|
||||||
|
|
||||||
// Return the constructed Self
|
// Return the constructed Self
|
||||||
Self {
|
Self {
|
||||||
tree: MerkleTreeCircuit::<F, C, D, H> {
|
tree: MerkleTreeCircuit::<F, D> {
|
||||||
tree: slot_tree,
|
tree: slot_tree,
|
||||||
_phantom: Default::default(),
|
|
||||||
},
|
},
|
||||||
block_trees,
|
block_trees,
|
||||||
cell_data,
|
cell_data,
|
||||||
|
@ -181,7 +174,7 @@ impl<
|
||||||
let start = i * N_CELLS_IN_BLOCKS;
|
let start = i * N_CELLS_IN_BLOCKS;
|
||||||
let end = (i + 1) * N_CELLS_IN_BLOCKS;
|
let end = (i + 1) * N_CELLS_IN_BLOCKS;
|
||||||
let b_tree = Self::get_block_tree(&leaves[start..end].to_vec());
|
let b_tree = Self::get_block_tree(&leaves[start..end].to_vec());
|
||||||
MerkleTreeCircuit::<F,C,D,H>{ tree:b_tree, _phantom:Default::default()}
|
MerkleTreeCircuit::<F,D>{ tree:b_tree}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let block_roots = block_trees.iter()
|
let block_roots = block_trees.iter()
|
||||||
|
@ -189,9 +182,9 @@ impl<
|
||||||
t.tree.root().unwrap()
|
t.tree.root().unwrap()
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let slot_tree = MerkleTree::<F, H>::new(&block_roots, zero).unwrap();
|
let slot_tree = MerkleTree::<F>::new(&block_roots, zero).unwrap();
|
||||||
Self{
|
Self{
|
||||||
tree: MerkleTreeCircuit::<F,C,D,H>{ tree:slot_tree, _phantom:Default::default()},
|
tree: MerkleTreeCircuit::<F,D>{ tree:slot_tree},
|
||||||
block_trees,
|
block_trees,
|
||||||
cell_data,
|
cell_data,
|
||||||
}
|
}
|
||||||
|
@ -199,7 +192,7 @@ impl<
|
||||||
|
|
||||||
/// generates a proof for given leaf index
|
/// generates a proof for given leaf index
|
||||||
/// the path in the proof is a combined block and slot path to make up the full path
|
/// the path in the proof is a combined block and slot path to make up the full path
|
||||||
pub fn get_proof(&self, index: usize) -> MerkleProof<F, H> {
|
pub fn get_proof(&self, index: usize) -> MerkleProof<F> {
|
||||||
let block_index = index/ N_CELLS_IN_BLOCKS;
|
let block_index = index/ N_CELLS_IN_BLOCKS;
|
||||||
let leaf_index = index % N_CELLS_IN_BLOCKS;
|
let leaf_index = index % N_CELLS_IN_BLOCKS;
|
||||||
let block_proof = self.block_trees[block_index].tree.get_proof(leaf_index).unwrap();
|
let block_proof = self.block_trees[block_index].tree.get_proof(leaf_index).unwrap();
|
||||||
|
@ -209,18 +202,17 @@ impl<
|
||||||
let mut combined_path = block_proof.path.clone();
|
let mut combined_path = block_proof.path.clone();
|
||||||
combined_path.extend(slot_proof.path.clone());
|
combined_path.extend(slot_proof.path.clone());
|
||||||
|
|
||||||
MerkleProof::<F, H> {
|
MerkleProof::<F> {
|
||||||
index: index,
|
index: index,
|
||||||
path: combined_path,
|
path: combined_path,
|
||||||
nleaves: self.cell_data.len(),
|
nleaves: self.cell_data.len(),
|
||||||
zero: block_proof.zero.clone(),
|
zero: block_proof.zero.clone(),
|
||||||
phantom_data: Default::default(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// verify the given proof for slot tree, checks equality with given root
|
/// verify the given proof for slot tree, checks equality with given root
|
||||||
pub fn verify_cell_proof(&self, proof: MerkleProof<F, H>, root: HashOut<F>) -> Result<bool>{
|
pub fn verify_cell_proof(&self, proof: MerkleProof<F>, root: HashOut<F>) -> Result<bool>{
|
||||||
let mut block_path_bits = usize_to_bits_le_padded(proof.index, MAX_DEPTH);
|
let mut block_path_bits = usize_to_bits_le_padded(proof.index, MAX_DEPTH);
|
||||||
let last_index = N_CELLS - 1;
|
let last_index = N_CELLS - 1;
|
||||||
let mut block_last_bits = usize_to_bits_le_padded(last_index, MAX_DEPTH);
|
let mut block_last_bits = usize_to_bits_le_padded(last_index, MAX_DEPTH);
|
||||||
|
@ -235,51 +227,42 @@ impl<
|
||||||
let mut block_path = proof.path;
|
let mut block_path = proof.path;
|
||||||
let slot_path = block_path.split_off(split_point);
|
let slot_path = block_path.split_off(split_point);
|
||||||
|
|
||||||
let block_res = MerkleProof::<F,H>::reconstruct_root2(leaf_hash,block_path_bits.clone(),block_last_bits.clone(),block_path);
|
let block_res = MerkleProof::<F>::reconstruct_root2(leaf_hash,block_path_bits.clone(),block_last_bits.clone(),block_path);
|
||||||
let reconstructed_root = MerkleProof::<F,H>::reconstruct_root2(block_res.unwrap(),slot_path_bits,slot_last_bits,slot_path);
|
let reconstructed_root = MerkleProof::<F>::reconstruct_root2(block_res.unwrap(),slot_path_bits,slot_last_bits,slot_path);
|
||||||
|
|
||||||
Ok(reconstructed_root.unwrap() == root)
|
Ok(reconstructed_root.unwrap() == root)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_block_tree(leaves: &Vec<HashOut<F>>) -> MerkleTree<F, H> {
|
fn get_block_tree(leaves: &Vec<HashOut<F>>) -> MerkleTree<F> {
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
elements: [F::ZERO; 4],
|
elements: [F::ZERO; 4],
|
||||||
};
|
};
|
||||||
// Build the Merkle tree
|
// Build the Merkle tree
|
||||||
let block_tree = MerkleTree::<F, H>::new(leaves, zero).unwrap();
|
let block_tree = MerkleTree::<F>::new(leaves, zero).unwrap();
|
||||||
return block_tree;
|
block_tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//------- single cell struct ------
|
//------- single cell struct ------
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct SingleCellTargets<
|
pub struct SingleCellTargets{
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
|
||||||
> {
|
|
||||||
pub expected_slot_root_target: HashOutTarget,
|
pub expected_slot_root_target: HashOutTarget,
|
||||||
pub proof_target: MerkleProofTarget,
|
pub proof_target: MerkleProofTarget,
|
||||||
pub leaf_target: Vec<Target>,
|
pub leaf_target: Vec<Target>,
|
||||||
pub path_bits: Vec<BoolTarget>,
|
pub path_bits: Vec<BoolTarget>,
|
||||||
pub last_bits: Vec<BoolTarget>,
|
pub last_bits: Vec<BoolTarget>,
|
||||||
_phantom: PhantomData<(C,H)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------- circuit impl --------
|
//------- circuit impl --------
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F=F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F> + Hasher<F>,
|
> SlotTreeCircuit<F, D> {
|
||||||
> SlotTreeCircuit<F, C, D, H> {
|
|
||||||
|
|
||||||
pub fn prove_single_cell(
|
pub fn prove_single_cell(
|
||||||
// &mut self,
|
|
||||||
builder: &mut CircuitBuilder::<F, D>
|
builder: &mut CircuitBuilder::<F, D>
|
||||||
) -> SingleCellTargets<F, C, D, H> {
|
) -> SingleCellTargets {
|
||||||
|
|
||||||
// Retrieve tree depth
|
// Retrieve tree depth
|
||||||
let depth = MAX_DEPTH;
|
let depth = MAX_DEPTH;
|
||||||
|
@ -289,7 +272,7 @@ impl<
|
||||||
|
|
||||||
let mut perm_inputs:Vec<Target>= Vec::new();
|
let mut perm_inputs:Vec<Target>= Vec::new();
|
||||||
perm_inputs.extend_from_slice(&leaf);
|
perm_inputs.extend_from_slice(&leaf);
|
||||||
let leaf_hash = builder.hash_n_to_hash_no_pad::<H>(perm_inputs);
|
let leaf_hash = builder.hash_n_to_hash_no_pad::<HF>(perm_inputs);
|
||||||
|
|
||||||
// path bits (binary decomposition of leaf_index)
|
// path bits (binary decomposition of leaf_index)
|
||||||
let mut block_path_bits = (0..BOT_DEPTH).map(|_| builder.add_virtual_bool_target_safe()).collect::<Vec<_>>();
|
let mut block_path_bits = (0..BOT_DEPTH).map(|_| builder.add_virtual_bool_target_safe()).collect::<Vec<_>>();
|
||||||
|
@ -315,11 +298,10 @@ impl<
|
||||||
path_bits:block_path_bits,
|
path_bits:block_path_bits,
|
||||||
last_bits: block_last_bits,
|
last_bits: block_last_bits,
|
||||||
merkle_path: block_merkle_path,
|
merkle_path: block_merkle_path,
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// reconstruct block root
|
// reconstruct block root
|
||||||
let block_root = MerkleTreeCircuit::<F,C,D,H>::reconstruct_merkle_root_circuit(builder, &mut block_targets);
|
let block_root = MerkleTreeCircuit::<F,D>::reconstruct_merkle_root_circuit(builder, &mut block_targets);
|
||||||
|
|
||||||
// create MerkleTreeTargets struct
|
// create MerkleTreeTargets struct
|
||||||
let mut slot_targets = MerkleTreeTargets {
|
let mut slot_targets = MerkleTreeTargets {
|
||||||
|
@ -327,11 +309,10 @@ impl<
|
||||||
path_bits:slot_path_bits,
|
path_bits:slot_path_bits,
|
||||||
last_bits:slot_last_bits,
|
last_bits:slot_last_bits,
|
||||||
merkle_path:slot_merkle_path,
|
merkle_path:slot_merkle_path,
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// reconstruct slot root with block root as leaf
|
// reconstruct slot root with block root as leaf
|
||||||
let slot_root = MerkleTreeCircuit::<F,C,D,H>::reconstruct_merkle_root_circuit(builder, &mut slot_targets);
|
let slot_root = MerkleTreeCircuit::<F,D>::reconstruct_merkle_root_circuit(builder, &mut slot_targets);
|
||||||
|
|
||||||
// check equality with expected root
|
// check equality with expected root
|
||||||
for i in 0..NUM_HASH_OUT_ELTS {
|
for i in 0..NUM_HASH_OUT_ELTS {
|
||||||
|
@ -355,7 +336,6 @@ impl<
|
||||||
leaf_target: leaf,
|
leaf_target: leaf,
|
||||||
path_bits,
|
path_bits,
|
||||||
last_bits,
|
last_bits,
|
||||||
_phantom: Default::default(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return MerkleTreeTargets
|
// Return MerkleTreeTargets
|
||||||
|
@ -368,10 +348,10 @@ impl<
|
||||||
pub fn single_cell_assign_witness(
|
pub fn single_cell_assign_witness(
|
||||||
&self,
|
&self,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
targets: &mut SingleCellTargets<F, C, D, H>,
|
targets: &mut SingleCellTargets,
|
||||||
leaf_index: usize,
|
leaf_index: usize,
|
||||||
leaf: &Vec<F>,
|
leaf: &Vec<F>,
|
||||||
proof: MerkleProof<F,H>,
|
proof: MerkleProof<F>,
|
||||||
)-> Result<()> {
|
)-> Result<()> {
|
||||||
|
|
||||||
// Assign the leaf to the leaf target
|
// Assign the leaf to the leaf target
|
||||||
|
@ -415,7 +395,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_leaf(builder: &mut CircuitBuilder<F, D >, leaf: &mut Vec<Target>){
|
fn hash_leaf(builder: &mut CircuitBuilder<F, D >, leaf: &mut Vec<Target>){
|
||||||
builder.hash_n_to_hash_no_pad::<H>(leaf.to_owned());
|
builder.hash_n_to_hash_no_pad::<HF>(leaf.to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,7 +415,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_single_cell(){
|
fn test_prove_single_cell(){
|
||||||
let slot_t = SlotTreeCircuit::<F,C,D,H>::default();
|
let slot_t = SlotTreeCircuit::<F,D>::default();
|
||||||
let index = 8;
|
let index = 8;
|
||||||
let proof = slot_t.get_proof(index);
|
let proof = slot_t.get_proof(index);
|
||||||
let res = slot_t.verify_cell_proof(proof,slot_t.tree.tree.root().unwrap()).unwrap();
|
let res = slot_t.verify_cell_proof(proof,slot_t.tree.tree.root().unwrap()).unwrap();
|
||||||
|
@ -445,7 +425,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cell_build_circuit() -> Result<()> {
|
fn test_cell_build_circuit() -> Result<()> {
|
||||||
|
|
||||||
let slot_t = SlotTreeCircuit::<F,C,D,H>::default();
|
let slot_t = SlotTreeCircuit::<F,D>::default();
|
||||||
|
|
||||||
// select leaf index to prove
|
// select leaf index to prove
|
||||||
let leaf_index: usize = 8;
|
let leaf_index: usize = 8;
|
||||||
|
@ -460,7 +440,7 @@ mod tests {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
|
||||||
let mut targets = SlotTreeCircuit::<F,C,D,H>::prove_single_cell(&mut builder);
|
let mut targets = SlotTreeCircuit::<F,D>::prove_single_cell(&mut builder);
|
||||||
|
|
||||||
// create a PartialWitness and assign
|
// create a PartialWitness and assign
|
||||||
let mut pw = PartialWitness::new();
|
let mut pw = PartialWitness::new();
|
||||||
|
|
|
@ -18,6 +18,7 @@ use plonky2::plonk::proof::{Proof, ProofWithPublicInputs};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use crate::circuits::params::HF;
|
||||||
use crate::circuits::utils::usize_to_bits_le_padded;
|
use crate::circuits::utils::usize_to_bits_le_padded;
|
||||||
|
|
||||||
use crate::merkle_tree::merkle_safe::{MerkleTree, MerkleProofTarget};
|
use crate::merkle_tree::merkle_safe::{MerkleTree, MerkleProofTarget};
|
||||||
|
@ -29,17 +30,11 @@ use crate::merkle_tree::merkle_safe::{KEY_NONE,KEY_BOTTOM_LAYER};
|
||||||
// uses the Plonk's permutation argument to check that two elements are equal.
|
// uses the Plonk's permutation argument to check that two elements are equal.
|
||||||
// TODO: double check the need for mask
|
// TODO: double check the need for mask
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MerkleTreeTargets<
|
pub struct MerkleTreeTargets{
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
|
||||||
> {
|
|
||||||
pub leaf: HashOutTarget,
|
pub leaf: HashOutTarget,
|
||||||
pub path_bits: Vec<BoolTarget>,
|
pub path_bits: Vec<BoolTarget>,
|
||||||
pub last_bits: Vec<BoolTarget>,
|
pub last_bits: Vec<BoolTarget>,
|
||||||
pub merkle_path: MerkleProofTarget,
|
pub merkle_path: MerkleProofTarget,
|
||||||
pub _phantom: PhantomData<(C, H)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merkle tree circuit contains the tree and functions for
|
/// Merkle tree circuit contains the tree and functions for
|
||||||
|
@ -47,26 +42,21 @@ pub struct MerkleTreeTargets<
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MerkleTreeCircuit<
|
pub struct MerkleTreeCircuit<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
|
||||||
> {
|
> {
|
||||||
pub tree: MerkleTree<F, H>,
|
pub tree: MerkleTree<F>,
|
||||||
pub _phantom: PhantomData<C>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F=F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
> MerkleTreeCircuit<F, D> {
|
||||||
> MerkleTreeCircuit<F, C, D, H> {
|
|
||||||
|
|
||||||
/// defines the computations inside the circuit and returns the targets used
|
/// defines the computations inside the circuit and returns the targets used
|
||||||
pub fn build_circuit(
|
pub fn build_circuit(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &mut CircuitBuilder::<F, D>
|
builder: &mut CircuitBuilder::<F, D>
|
||||||
) -> (MerkleTreeTargets<F, C, { D }, H>, HashOutTarget) {
|
) -> (MerkleTreeTargets, HashOutTarget) {
|
||||||
// Retrieve tree depth
|
// Retrieve tree depth
|
||||||
let depth = self.tree.depth();
|
let depth = self.tree.depth();
|
||||||
|
|
||||||
|
@ -85,12 +75,11 @@ impl<
|
||||||
};
|
};
|
||||||
|
|
||||||
// create MerkleTreeTargets struct
|
// create MerkleTreeTargets struct
|
||||||
let mut targets = MerkleTreeTargets {
|
let mut targets = MerkleTreeTargets{
|
||||||
leaf,
|
leaf,
|
||||||
path_bits,
|
path_bits,
|
||||||
last_bits,
|
last_bits,
|
||||||
merkle_path,
|
merkle_path,
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add Merkle proof verification constraints to the circuit
|
// Add Merkle proof verification constraints to the circuit
|
||||||
|
@ -105,7 +94,7 @@ impl<
|
||||||
pub fn assign_witness(
|
pub fn assign_witness(
|
||||||
&mut self,
|
&mut self,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
targets: &mut MerkleTreeTargets<F, C, D, H>,
|
targets: &mut MerkleTreeTargets,
|
||||||
leaf_index: usize,
|
leaf_index: usize,
|
||||||
)-> Result<()> {
|
)-> Result<()> {
|
||||||
// Get the total number of leaves and tree depth
|
// Get the total number of leaves and tree depth
|
||||||
|
@ -151,9 +140,8 @@ impl<
|
||||||
/// takes the params from the targets struct
|
/// takes the params from the targets struct
|
||||||
/// outputs the reconstructed merkle root
|
/// outputs the reconstructed merkle root
|
||||||
pub fn reconstruct_merkle_root_circuit(
|
pub fn reconstruct_merkle_root_circuit(
|
||||||
// &self,
|
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
targets: &mut MerkleTreeTargets<F, C, D, H>,
|
targets: &mut MerkleTreeTargets,
|
||||||
) -> HashOutTarget {
|
) -> HashOutTarget {
|
||||||
let max_depth = targets.path_bits.len();
|
let max_depth = targets.path_bits.len();
|
||||||
let mut state: HashOutTarget = targets.leaf;
|
let mut state: HashOutTarget = targets.leaf;
|
||||||
|
@ -200,7 +188,7 @@ impl<
|
||||||
perm_inputs.extend_from_slice(&left);
|
perm_inputs.extend_from_slice(&left);
|
||||||
perm_inputs.extend_from_slice(&right);
|
perm_inputs.extend_from_slice(&right);
|
||||||
perm_inputs.push(key);
|
perm_inputs.push(key);
|
||||||
state = builder.hash_n_to_hash_no_pad::<H>(perm_inputs);
|
state = builder.hash_n_to_hash_no_pad::<HF>(perm_inputs);
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +233,7 @@ mod tests {
|
||||||
let zero_hash = HashOut {
|
let zero_hash = HashOut {
|
||||||
elements: [GoldilocksField::ZERO; 4],
|
elements: [GoldilocksField::ZERO; 4],
|
||||||
};
|
};
|
||||||
let tree = MerkleTree::<F, H>::new(&leaves, zero_hash)?;
|
let tree = MerkleTree::<F>::new(&leaves, zero_hash)?;
|
||||||
|
|
||||||
// select leaf index to prove
|
// select leaf index to prove
|
||||||
let leaf_index: usize = 8;
|
let leaf_index: usize = 8;
|
||||||
|
@ -262,9 +250,9 @@ mod tests {
|
||||||
// create the circuit
|
// create the circuit
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
let mut circuit_instance = MerkleTreeCircuit::<F, C, D, H> {
|
let mut circuit_instance = MerkleTreeCircuit::<F, D> {
|
||||||
tree: tree.clone(),
|
tree: tree.clone(),
|
||||||
_phantom: PhantomData,
|
// _phantom: PhantomData,
|
||||||
};
|
};
|
||||||
let (mut targets, expected_root_target) = circuit_instance.build_circuit(&mut builder);
|
let (mut targets, expected_root_target) = circuit_instance.build_circuit(&mut builder);
|
||||||
|
|
||||||
|
@ -312,15 +300,14 @@ mod tests {
|
||||||
let zero_hash = HashOut {
|
let zero_hash = HashOut {
|
||||||
elements: [GoldilocksField::ZERO; 4],
|
elements: [GoldilocksField::ZERO; 4],
|
||||||
};
|
};
|
||||||
let tree = MerkleTree::<F, H>::new(&leaves, zero_hash)?;
|
let tree = MerkleTree::<F>::new(&leaves, zero_hash)?;
|
||||||
|
|
||||||
let expected_root = tree.root()?;
|
let expected_root = tree.root()?;
|
||||||
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
let mut circuit_instance = MerkleTreeCircuit::<F, C, D, H> {
|
let mut circuit_instance = MerkleTreeCircuit::<F, D> {
|
||||||
tree: tree.clone(),
|
tree: tree.clone(),
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
let (mut targets, expected_root_target) = circuit_instance.build_circuit(&mut builder);
|
let (mut targets, expected_root_target) = circuit_instance.build_circuit(&mut builder);
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ use plonky2::plonk::config::PoseidonGoldilocksConfig;
|
||||||
|
|
||||||
use plonky2::hash::hashing::PlonkyPermutation;
|
use plonky2::hash::hashing::PlonkyPermutation;
|
||||||
use crate::circuits::prove_single_cell::{SingleCellTargets, SlotTreeCircuit};
|
use crate::circuits::prove_single_cell::{SingleCellTargets, SlotTreeCircuit};
|
||||||
use crate::circuits::params::{BOT_DEPTH, DATASET_DEPTH, MAX_DEPTH, N_FIELD_ELEMS_PER_CELL, N_SAMPLES, TESTING_SLOT_INDEX};
|
use crate::circuits::params::{BOT_DEPTH, DATASET_DEPTH, HF, MAX_DEPTH, N_FIELD_ELEMS_PER_CELL, N_SAMPLES, TESTING_SLOT_INDEX};
|
||||||
|
|
||||||
use crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets};
|
use crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets};
|
||||||
use crate::circuits::utils::{bits_le_padded_to_usize, calculate_cell_index_bits};
|
use crate::circuits::utils::{bits_le_padded_to_usize, calculate_cell_index_bits};
|
||||||
|
@ -36,35 +36,31 @@ use crate::circuits::utils::{bits_le_padded_to_usize, calculate_cell_index_bits}
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DatasetTreeCircuit<
|
pub struct DatasetTreeCircuit<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
|
||||||
> {
|
> {
|
||||||
pub tree: MerkleTreeCircuit<F, C, D, H>, // dataset tree
|
pub tree: MerkleTreeCircuit<F, D>, // dataset tree
|
||||||
pub slot_trees: Vec<SlotTreeCircuit<F,C,D,H>>, // vec of slot trees
|
pub slot_trees: Vec<SlotTreeCircuit<F,D>>, // vec of slot trees
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dataset Merkle proof struct, containing the dataset proof and N_SAMPLES proofs.
|
/// Dataset Merkle proof struct, containing the dataset proof and N_SAMPLES proofs.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DatasetMerkleProof<F: RichField, H: Hasher<F>> {
|
pub struct DatasetMerkleProof<F: RichField> {
|
||||||
pub slot_index: usize,
|
pub slot_index: usize,
|
||||||
pub entropy: usize,
|
pub entropy: usize,
|
||||||
pub dataset_proof: MerkleProof<F,H>, // proof for dataset level tree
|
pub dataset_proof: MerkleProof<F>, // proof for dataset level tree
|
||||||
pub slot_proofs: Vec<MerkleProof<F,H>>, // proofs for sampled slot, contains N_SAMPLES proofs
|
pub slot_proofs: Vec<MerkleProof<F>>, // proofs for sampled slot, contains N_SAMPLES proofs
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
> Default for DatasetTreeCircuit<F,D> {
|
||||||
> Default for DatasetTreeCircuit<F,C,D,H> {
|
|
||||||
/// dataset tree with fake data, for testing only
|
/// dataset tree with fake data, for testing only
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut slot_trees = vec![];
|
let mut slot_trees = vec![];
|
||||||
let n_slots = 1<<DATASET_DEPTH;
|
let n_slots = 1<<DATASET_DEPTH;
|
||||||
for i in 0..n_slots {
|
for i in 0..n_slots {
|
||||||
slot_trees.push(SlotTreeCircuit::<F,C,D,H>::default());
|
slot_trees.push(SlotTreeCircuit::<F,D>::default());
|
||||||
}
|
}
|
||||||
// get the roots or slot trees
|
// get the roots or slot trees
|
||||||
let slot_roots = slot_trees.iter()
|
let slot_roots = slot_trees.iter()
|
||||||
|
@ -76,9 +72,9 @@ impl<
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
elements: [F::ZERO; 4],
|
elements: [F::ZERO; 4],
|
||||||
};
|
};
|
||||||
let dataset_tree = MerkleTree::<F, H>::new(&slot_roots, zero).unwrap();
|
let dataset_tree = MerkleTree::<F>::new(&slot_roots, zero).unwrap();
|
||||||
Self{
|
Self{
|
||||||
tree: MerkleTreeCircuit::<F,C,D,H>{ tree:dataset_tree, _phantom:Default::default()},
|
tree: MerkleTreeCircuit::<F,D>{ tree:dataset_tree},
|
||||||
slot_trees,
|
slot_trees,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,10 +83,8 @@ impl<
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
> DatasetTreeCircuit<F,D> {
|
||||||
> DatasetTreeCircuit<F,C,D,H> {
|
|
||||||
/// dataset tree with fake data, for testing only
|
/// dataset tree with fake data, for testing only
|
||||||
/// create data for only the TESTING_SLOT_INDEX in params file
|
/// create data for only the TESTING_SLOT_INDEX in params file
|
||||||
pub fn new_for_testing() -> Self {
|
pub fn new_for_testing() -> Self {
|
||||||
|
@ -100,17 +94,16 @@ impl<
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
elements: [F::ZERO; 4],
|
elements: [F::ZERO; 4],
|
||||||
};
|
};
|
||||||
let zero_slot = SlotTreeCircuit::<F,C,D,H>{
|
let zero_slot = SlotTreeCircuit::<F,D>{
|
||||||
tree: MerkleTreeCircuit {
|
tree: MerkleTreeCircuit {
|
||||||
tree: MerkleTree::<F,H>::new(&[zero.clone()], zero.clone()).unwrap(),
|
tree: MerkleTree::<F>::new(&[zero.clone()], zero.clone()).unwrap(),
|
||||||
_phantom: Default::default(),
|
|
||||||
},
|
},
|
||||||
block_trees: vec![],
|
block_trees: vec![],
|
||||||
cell_data: vec![],
|
cell_data: vec![],
|
||||||
};
|
};
|
||||||
for i in 0..n_slots {
|
for i in 0..n_slots {
|
||||||
if(i == TESTING_SLOT_INDEX) {
|
if(i == TESTING_SLOT_INDEX) {
|
||||||
slot_trees.push(SlotTreeCircuit::<F, C, D, H>::new_for_testing());
|
slot_trees.push(SlotTreeCircuit::<F, D>::new_for_testing());
|
||||||
}else{
|
}else{
|
||||||
slot_trees.push(zero_slot.clone());
|
slot_trees.push(zero_slot.clone());
|
||||||
}
|
}
|
||||||
|
@ -122,15 +115,15 @@ impl<
|
||||||
t.tree.tree.root().unwrap()
|
t.tree.tree.root().unwrap()
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let dataset_tree = MerkleTree::<F, H>::new(&slot_roots, zero).unwrap();
|
let dataset_tree = MerkleTree::<F>::new(&slot_roots, zero).unwrap();
|
||||||
Self{
|
Self{
|
||||||
tree: MerkleTreeCircuit::<F,C,D,H>{ tree:dataset_tree, _phantom:Default::default()},
|
tree: MerkleTreeCircuit::<F,D>{ tree:dataset_tree},
|
||||||
slot_trees,
|
slot_trees,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// same as default but with supplied slot trees
|
/// same as default but with supplied slot trees
|
||||||
pub fn new(slot_trees: Vec<SlotTreeCircuit<F,C,D,H>>) -> Self{
|
pub fn new(slot_trees: Vec<SlotTreeCircuit<F,D>>) -> Self{
|
||||||
// get the roots or slot trees
|
// get the roots or slot trees
|
||||||
let slot_roots = slot_trees.iter()
|
let slot_roots = slot_trees.iter()
|
||||||
.map(|t| {
|
.map(|t| {
|
||||||
|
@ -141,23 +134,23 @@ impl<
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
elements: [F::ZERO; 4],
|
elements: [F::ZERO; 4],
|
||||||
};
|
};
|
||||||
let dataset_tree = MerkleTree::<F, H>::new(&slot_roots, zero).unwrap();
|
let dataset_tree = MerkleTree::<F>::new(&slot_roots, zero).unwrap();
|
||||||
Self{
|
Self{
|
||||||
tree: MerkleTreeCircuit::<F,C,D,H>{ tree:dataset_tree, _phantom:Default::default()},
|
tree: MerkleTreeCircuit::<F,D>{ tree:dataset_tree},
|
||||||
slot_trees,
|
slot_trees,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates a dataset level proof for given slot index
|
/// generates a dataset level proof for given slot index
|
||||||
/// just a regular merkle tree proof
|
/// just a regular merkle tree proof
|
||||||
pub fn get_proof(&self, index: usize) -> MerkleProof<F, H> {
|
pub fn get_proof(&self, index: usize) -> MerkleProof<F> {
|
||||||
let dataset_proof = self.tree.tree.get_proof(index).unwrap();
|
let dataset_proof = self.tree.tree.get_proof(index).unwrap();
|
||||||
dataset_proof
|
dataset_proof
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates a proof for given slot index
|
/// generates a proof for given slot index
|
||||||
/// also takes entropy so it can use it sample the slot
|
/// also takes entropy so it can use it sample the slot
|
||||||
pub fn sample_slot(&self, index: usize, entropy: usize) -> DatasetMerkleProof<F, H> {
|
pub fn sample_slot(&self, index: usize, entropy: usize) -> DatasetMerkleProof<F> {
|
||||||
let dataset_proof = self.tree.tree.get_proof(index).unwrap();
|
let dataset_proof = self.tree.tree.get_proof(index).unwrap();
|
||||||
let slot = &self.slot_trees[index];
|
let slot = &self.slot_trees[index];
|
||||||
let slot_root = slot.tree.tree.root().unwrap();
|
let slot_root = slot.tree.tree.root().unwrap();
|
||||||
|
@ -178,7 +171,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify the sampling - non-circuit version
|
// verify the sampling - non-circuit version
|
||||||
pub fn verify_sampling(&self, proof: DatasetMerkleProof<F,H>) -> Result<bool>{
|
pub fn verify_sampling(&self, proof: DatasetMerkleProof<F>) -> Result<bool>{
|
||||||
let slot = &self.slot_trees[proof.slot_index];
|
let slot = &self.slot_trees[proof.slot_index];
|
||||||
let slot_root = slot.tree.tree.root().unwrap();
|
let slot_root = slot.tree.tree.root().unwrap();
|
||||||
// check dataset level proof
|
// check dataset level proof
|
||||||
|
@ -204,12 +197,7 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DatasetTargets<
|
pub struct DatasetTargets{
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
C: GenericConfig<D, F = F>,
|
|
||||||
const D: usize,
|
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
|
||||||
> {
|
|
||||||
pub dataset_proof: MerkleProofTarget, // proof that slot_root in dataset tree
|
pub dataset_proof: MerkleProofTarget, // proof that slot_root in dataset tree
|
||||||
pub dataset_root: HashOutTarget,
|
pub dataset_root: HashOutTarget,
|
||||||
|
|
||||||
|
@ -219,23 +207,20 @@ pub struct DatasetTargets<
|
||||||
pub slot_root: HashOutTarget,
|
pub slot_root: HashOutTarget,
|
||||||
pub slot_proofs: Vec<MerkleProofTarget>,
|
pub slot_proofs: Vec<MerkleProofTarget>,
|
||||||
|
|
||||||
_phantom: PhantomData<(C,H)>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------- circuit impl --------
|
//------- circuit impl --------
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
C: GenericConfig<D, F=F>,
|
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F> + Hasher<F>,
|
> DatasetTreeCircuit<F, D> {
|
||||||
> DatasetTreeCircuit<F, C, D, H> {
|
|
||||||
|
|
||||||
// in-circuit sampling
|
// in-circuit sampling
|
||||||
// TODO: make it more modular
|
// TODO: make it more modular
|
||||||
pub fn sample_slot_circuit(
|
pub fn sample_slot_circuit(
|
||||||
&mut self,
|
&mut self,
|
||||||
builder: &mut CircuitBuilder::<F, D>,
|
builder: &mut CircuitBuilder::<F, D>,
|
||||||
)-> DatasetTargets<F,C,D,H>{
|
)-> DatasetTargets {
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
let zero = builder.zero();
|
let zero = builder.zero();
|
||||||
|
@ -266,17 +251,16 @@ impl<
|
||||||
};
|
};
|
||||||
|
|
||||||
// create MerkleTreeTargets struct
|
// create MerkleTreeTargets struct
|
||||||
let mut d_targets = MerkleTreeTargets {
|
let mut d_targets = MerkleTreeTargets{
|
||||||
leaf: slot_root,
|
leaf: slot_root,
|
||||||
path_bits: d_path_bits,
|
path_bits: d_path_bits,
|
||||||
last_bits: d_last_bits,
|
last_bits: d_last_bits,
|
||||||
merkle_path: d_merkle_path,
|
merkle_path: d_merkle_path,
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// dataset reconstructed root
|
// dataset reconstructed root
|
||||||
let d_reconstructed_root =
|
let d_reconstructed_root =
|
||||||
MerkleTreeCircuit::<F,C,D,H>::reconstruct_merkle_root_circuit(builder, &mut d_targets);
|
MerkleTreeCircuit::<F,D>::reconstruct_merkle_root_circuit(builder, &mut d_targets);
|
||||||
|
|
||||||
// expected Merkle root
|
// expected Merkle root
|
||||||
let d_expected_root = builder.add_virtual_hash();
|
let d_expected_root = builder.add_virtual_hash();
|
||||||
|
@ -309,7 +293,7 @@ impl<
|
||||||
|
|
||||||
let mut perm_inputs:Vec<Target>= Vec::new();
|
let mut perm_inputs:Vec<Target>= Vec::new();
|
||||||
perm_inputs.extend_from_slice(&data_i);
|
perm_inputs.extend_from_slice(&data_i);
|
||||||
let data_i_hash = builder.hash_n_to_hash_no_pad::<H>(perm_inputs);
|
let data_i_hash = builder.hash_n_to_hash_no_pad::<HF>(perm_inputs);
|
||||||
// counter constant
|
// counter constant
|
||||||
let ctr_target = builder.constant(F::from_canonical_u64((i+1) as u64));
|
let ctr_target = builder.constant(F::from_canonical_u64((i+1) as u64));
|
||||||
let mut ctr = builder.add_virtual_hash();
|
let mut ctr = builder.add_virtual_hash();
|
||||||
|
@ -337,22 +321,20 @@ impl<
|
||||||
path_bits:b_path_bits,
|
path_bits:b_path_bits,
|
||||||
last_bits: b_last_bits.clone(),
|
last_bits: b_last_bits.clone(),
|
||||||
merkle_path: b_merkle_path,
|
merkle_path: b_merkle_path,
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// reconstruct block root
|
// reconstruct block root
|
||||||
let b_root = MerkleTreeCircuit::<F,C,D,H>::reconstruct_merkle_root_circuit(builder, &mut block_targets);
|
let b_root = MerkleTreeCircuit::<F,D>::reconstruct_merkle_root_circuit(builder, &mut block_targets);
|
||||||
|
|
||||||
let mut slot_targets = MerkleTreeTargets {
|
let mut slot_targets = MerkleTreeTargets {
|
||||||
leaf: b_root,
|
leaf: b_root,
|
||||||
path_bits:s_path_bits,
|
path_bits:s_path_bits,
|
||||||
last_bits:s_last_bits.clone(),
|
last_bits:s_last_bits.clone(),
|
||||||
merkle_path:s_merkle_path,
|
merkle_path:s_merkle_path,
|
||||||
_phantom: PhantomData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// reconstruct slot root with block root as leaf
|
// reconstruct slot root with block root as leaf
|
||||||
let slot_reconstructed_root = MerkleTreeCircuit::<F,C,D,H>::reconstruct_merkle_root_circuit(builder, &mut slot_targets);
|
let slot_reconstructed_root = MerkleTreeCircuit::<F,D>::reconstruct_merkle_root_circuit(builder, &mut slot_targets);
|
||||||
|
|
||||||
// check equality with expected root
|
// check equality with expected root
|
||||||
for i in 0..NUM_HASH_OUT_ELTS {
|
for i in 0..NUM_HASH_OUT_ELTS {
|
||||||
|
@ -370,7 +352,7 @@ impl<
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DatasetTargets::<F,C,D,H>{
|
DatasetTargets{
|
||||||
dataset_proof: d_targets.merkle_path,
|
dataset_proof: d_targets.merkle_path,
|
||||||
dataset_root: d_expected_root,
|
dataset_root: d_expected_root,
|
||||||
cell_data: data_targets,
|
cell_data: data_targets,
|
||||||
|
@ -378,7 +360,6 @@ impl<
|
||||||
slot_index,
|
slot_index,
|
||||||
slot_root: d_targets.leaf,
|
slot_root: d_targets.leaf,
|
||||||
slot_proofs: slot_sample_proofs,
|
slot_proofs: slot_sample_proofs,
|
||||||
_phantom: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +368,7 @@ impl<
|
||||||
hash_inputs.extend_from_slice(&entropy.elements);
|
hash_inputs.extend_from_slice(&entropy.elements);
|
||||||
hash_inputs.extend_from_slice(&slot_root.elements);
|
hash_inputs.extend_from_slice(&slot_root.elements);
|
||||||
hash_inputs.extend_from_slice(&ctr.elements);
|
hash_inputs.extend_from_slice(&ctr.elements);
|
||||||
let hash_out = builder.hash_n_to_hash_no_pad::<H>(hash_inputs);
|
let hash_out = builder.hash_n_to_hash_no_pad::<HF>(hash_inputs);
|
||||||
let cell_index_bits = builder.low_bits(hash_out.elements[0], MAX_DEPTH, 64);
|
let cell_index_bits = builder.low_bits(hash_out.elements[0], MAX_DEPTH, 64);
|
||||||
|
|
||||||
cell_index_bits
|
cell_index_bits
|
||||||
|
@ -396,7 +377,7 @@ impl<
|
||||||
pub fn sample_slot_assign_witness(
|
pub fn sample_slot_assign_witness(
|
||||||
&mut self,
|
&mut self,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
targets: &mut DatasetTargets<F,C,D,H>,
|
targets: &mut DatasetTargets,
|
||||||
slot_index:usize,
|
slot_index:usize,
|
||||||
entropy:usize,
|
entropy:usize,
|
||||||
){
|
){
|
||||||
|
@ -475,7 +456,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sample_cells() {
|
fn test_sample_cells() {
|
||||||
let dataset_t = DatasetTreeCircuit::<F,C,D,H>::default();
|
let dataset_t = DatasetTreeCircuit::<F,D>::default();
|
||||||
let slot_index = 2;
|
let slot_index = 2;
|
||||||
let entropy = 123;
|
let entropy = 123;
|
||||||
let proof = dataset_t.sample_slot(slot_index,entropy);
|
let proof = dataset_t.sample_slot(slot_index,entropy);
|
||||||
|
@ -488,7 +469,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sample_cells_circuit() -> Result<()> {
|
fn test_sample_cells_circuit() -> Result<()> {
|
||||||
|
|
||||||
let mut dataset_t = DatasetTreeCircuit::<F,C,D,H>::default();
|
let mut dataset_t = DatasetTreeCircuit::<F,D>::default();
|
||||||
|
|
||||||
let slot_index = 2;
|
let slot_index = 2;
|
||||||
let entropy = 123;
|
let entropy = 123;
|
||||||
|
@ -532,7 +513,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sample_cells_circuit_from_selected_slot() -> Result<()> {
|
fn test_sample_cells_circuit_from_selected_slot() -> Result<()> {
|
||||||
|
|
||||||
let mut dataset_t = DatasetTreeCircuit::<F,C,D,H>::new_for_testing();
|
let mut dataset_t = DatasetTreeCircuit::<F,D>::new_for_testing();
|
||||||
|
|
||||||
let slot_index = TESTING_SLOT_INDEX;
|
let slot_index = TESTING_SLOT_INDEX;
|
||||||
let entropy = 123;
|
let entropy = 123;
|
||||||
|
|
|
@ -25,24 +25,21 @@ type HF = PoseidonHash;
|
||||||
|
|
||||||
/// Merkle tree struct, containing the layers, compression function, and zero hash.
|
/// Merkle tree struct, containing the layers, compression function, and zero hash.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MerkleTree<F: RichField, H: Hasher<F>> {
|
pub struct MerkleTree<F: RichField> {
|
||||||
pub layers: Vec<Vec<HashOut<F>>>,
|
pub layers: Vec<Vec<HashOut<F>>>,
|
||||||
pub zero: HashOut<F>,
|
pub zero: HashOut<F>,
|
||||||
phantom_data: PhantomData<H>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: RichField, H: Hasher<F>> MerkleTree<F, H> {
|
impl<F: RichField> MerkleTree<F> {
|
||||||
/// Constructs a new Merkle tree from the given leaves.
|
/// Constructs a new Merkle tree from the given leaves.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
leaves: &[HashOut<F>],
|
leaves: &[HashOut<F>],
|
||||||
zero: HashOut<F>,
|
zero: HashOut<F>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let layers = merkle_tree_worker::<F,H>(leaves, zero, true)?;
|
let layers = merkle_tree_worker::<F>(leaves, zero, true)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
layers,
|
layers,
|
||||||
// compress,
|
|
||||||
zero,
|
zero,
|
||||||
phantom_data: Default::default(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +61,7 @@ impl<F: RichField, H: Hasher<F>> MerkleTree<F, H> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a Merkle proof for a given leaf index.
|
/// Generates a Merkle proof for a given leaf index.
|
||||||
pub fn get_proof(&self, index: usize) -> Result<MerkleProof<F, H>> {
|
pub fn get_proof(&self, index: usize) -> Result<MerkleProof<F>> {
|
||||||
let depth = self.depth();
|
let depth = self.depth();
|
||||||
let nleaves = self.leaves_count();
|
let nleaves = self.leaves_count();
|
||||||
|
|
||||||
|
@ -91,7 +88,6 @@ impl<F: RichField, H: Hasher<F>> MerkleTree<F, H> {
|
||||||
path,
|
path,
|
||||||
nleaves,
|
nleaves,
|
||||||
zero: self.zero,
|
zero: self.zero,
|
||||||
phantom_data: Default::default(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +103,7 @@ fn key_compress<F: RichField>(x: HashOut<F>, y: HashOut<F>, key: u64) -> HashOut
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the Merkle tree layers.
|
/// Build the Merkle tree layers.
|
||||||
fn merkle_tree_worker<F: RichField, H: Hasher<F>>(
|
fn merkle_tree_worker<F: RichField>(
|
||||||
xs: &[HashOut<F>],
|
xs: &[HashOut<F>],
|
||||||
zero: HashOut<F>,
|
zero: HashOut<F>,
|
||||||
is_bottom_layer: bool,
|
is_bottom_layer: bool,
|
||||||
|
@ -140,7 +136,7 @@ fn merkle_tree_worker<F: RichField, H: Hasher<F>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut layers = vec![xs.to_vec()];
|
let mut layers = vec![xs.to_vec()];
|
||||||
let mut upper_layers = merkle_tree_worker::<F,H>(&ys, zero, false)?;
|
let mut upper_layers = merkle_tree_worker::<F>(&ys, zero, false)?;
|
||||||
layers.append(&mut upper_layers);
|
layers.append(&mut upper_layers);
|
||||||
|
|
||||||
Ok(layers)
|
Ok(layers)
|
||||||
|
@ -148,12 +144,11 @@ fn merkle_tree_worker<F: RichField, H: Hasher<F>>(
|
||||||
|
|
||||||
/// Merkle proof struct, containing the index, path, and other necessary data.
|
/// Merkle proof struct, containing the index, path, and other necessary data.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct MerkleProof<F: RichField, H: Hasher<F>> {
|
pub struct MerkleProof<F: RichField> {
|
||||||
pub index: usize, // Index of the leaf
|
pub index: usize, // Index of the leaf
|
||||||
pub path: Vec<HashOut<F>>, // Sibling hashes from the leaf to the root
|
pub path: Vec<HashOut<F>>, // Sibling hashes from the leaf to the root
|
||||||
pub nleaves: usize, // Total number of leaves
|
pub nleaves: usize, // Total number of leaves
|
||||||
pub zero: HashOut<F>,
|
pub zero: HashOut<F>,
|
||||||
pub(crate) phantom_data: PhantomData<H>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -162,7 +157,7 @@ pub struct MerkleProofTarget {
|
||||||
pub path: Vec<HashOutTarget>,
|
pub path: Vec<HashOutTarget>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: RichField, H: Hasher<F>> MerkleProof<F, H> {
|
impl<F: RichField> MerkleProof<F> {
|
||||||
/// Reconstructs the root hash from the proof and the given leaf.
|
/// Reconstructs the root hash from the proof and the given leaf.
|
||||||
pub fn reconstruct_root(&self, leaf: HashOut<F>) -> Result<HashOut<F>> {
|
pub fn reconstruct_root(&self, leaf: HashOut<F>) -> Result<HashOut<F>> {
|
||||||
let mut m = self.nleaves;
|
let mut m = self.nleaves;
|
||||||
|
@ -271,7 +266,7 @@ mod tests {
|
||||||
fn make_tree(
|
fn make_tree(
|
||||||
data: &[F],
|
data: &[F],
|
||||||
zero: HashOut<F>,
|
zero: HashOut<F>,
|
||||||
) -> Result<MerkleTree<F, H>> {
|
) -> Result<MerkleTree<F>> {
|
||||||
// Hash the data to obtain leaf hashes
|
// Hash the data to obtain leaf hashes
|
||||||
let leaves: Vec<HashOut<GoldilocksField>> = data
|
let leaves: Vec<HashOut<GoldilocksField>> = data
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -281,7 +276,7 @@ mod tests {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
MerkleTree::<F, H>::new(&leaves, zero)
|
MerkleTree::<F>::new(&leaves, zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -304,7 +299,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build the Merkle tree
|
// Build the Merkle tree
|
||||||
let tree = MerkleTree::<F, H>::new(&leaves, zero)?;
|
let tree = MerkleTree::<F>::new(&leaves, zero)?;
|
||||||
|
|
||||||
// Get the root
|
// Get the root
|
||||||
let root = tree.root()?;
|
let root = tree.root()?;
|
||||||
|
@ -366,7 +361,7 @@ mod tests {
|
||||||
KEY_NONE,
|
KEY_NONE,
|
||||||
),
|
),
|
||||||
KEY_NONE,
|
KEY_NONE,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Build the tree
|
// Build the tree
|
||||||
let tree = make_tree(&data, zero)?;
|
let tree = make_tree(&data, zero)?;
|
||||||
|
@ -427,7 +422,7 @@ mod tests {
|
||||||
KEY_NONE,
|
KEY_NONE,
|
||||||
),
|
),
|
||||||
KEY_NONE,
|
KEY_NONE,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Build the tree
|
// Build the tree
|
||||||
let tree = make_tree(&data, zero)?;
|
let tree = make_tree(&data, zero)?;
|
||||||
|
@ -536,7 +531,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Build the tree
|
// Build the tree
|
||||||
let tree = MerkleTree::<F, H>::new(&leaf_hashes, zero)?;
|
let tree = MerkleTree::<F>::new(&leaf_hashes, zero)?;
|
||||||
|
|
||||||
// Get the root
|
// Get the root
|
||||||
let expected_root = tree.root()?;
|
let expected_root = tree.root()?;
|
||||||
|
|
Loading…
Reference in New Issue