remove phantom date and refactor

This commit is contained in:
M Alghazwi 2024-11-03 11:45:20 +01:00
parent cba274b64b
commit c725043c4d
4 changed files with 98 additions and 155 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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()?;