refactor utils and params

This commit is contained in:
M Alghazwi 2024-10-17 09:12:27 +02:00
parent b1c13a9bc1
commit 5a13ac3650
6 changed files with 155 additions and 57 deletions

View File

@ -1,4 +1,6 @@
pub mod capped_tree_circuit; pub mod capped_tree_circuit;
pub mod safe_tree_circuit; pub mod safe_tree_circuit;
pub mod prove_single_cell; pub mod prove_single_cell;
pub mod sample_cells; pub mod sample_cells;
pub mod utils;
pub mod params;

View File

@ -0,0 +1,20 @@
// global params for the circuits
// only change params here
use plonky2::hash::poseidon::PoseidonHash;
// constants and types used throughout the circuit
pub const N_FIELD_ELEMS_PER_CELL: usize = 4;
pub const BOT_DEPTH: usize = 5; // block depth - depth of the block merkle tree
pub const MAX_DEPTH: usize = 16; // depth of big tree (slot tree depth + block tree depth)
pub const N_CELLS_IN_BLOCKS: usize = 1<<BOT_DEPTH; //2^BOT_DEPTH
pub const N_BLOCKS: usize = 1<<(MAX_DEPTH - BOT_DEPTH); // 2^(MAX_DEPTH - BOT_DEPTH)
pub const N_CELLS: usize = N_CELLS_IN_BLOCKS * N_BLOCKS;
pub const DATASET_DEPTH: usize = 2;
pub const N_SAMPLES: usize = 5;
// hash function used. this is hackish way of doing it because
// H::Hash is not consistent with HashOut<F> and causing a lot of headache
// will look into this later.
pub type HF = PoseidonHash;

View File

@ -29,18 +29,8 @@ use plonky2::plonk::config::PoseidonGoldilocksConfig;
use plonky2::hash::hashing::PlonkyPermutation; use plonky2::hash::hashing::PlonkyPermutation;
use crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets}; use crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets};
use crate::circuits::utils::usize_to_bits_le_padded;
// constants and types used throughout the circuit use crate::circuits::params::{MAX_DEPTH, BOT_DEPTH, N_FIELD_ELEMS_PER_CELL, N_CELLS_IN_BLOCKS, N_BLOCKS, N_CELLS, HF};
pub const N_FIELD_ELEMS_PER_CELL: usize = 4;
pub const BOT_DEPTH: usize = 5; // block depth - depth of the block merkle tree
pub const MAX_DEPTH: usize = 16; // depth of big tree (slot tree depth + block tree depth)
const N_CELLS_IN_BLOCKS: usize = 1<<BOT_DEPTH; //2^BOT_DEPTH
const N_BLOCKS: usize = 1<<(MAX_DEPTH - BOT_DEPTH); // 2^(MAX_DEPTH - BOT_DEPTH)
const N_CELLS: usize = N_CELLS_IN_BLOCKS * N_BLOCKS;
// hash function used. this is hackish way of doing it because
// H::Hash is not consistent with HashOut<F> and causing a lot of headache
// will look into this later.
type HF = PoseidonHash;
// ------ Slot Tree -------- // ------ Slot Tree --------
@ -157,9 +147,9 @@ impl<F: RichField, H: Hasher<F>> SlotTree<F, H> {
/// 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, H>, root: HashOut<F>) -> Result<bool>{
let mut block_path_bits = self.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 = self.usize_to_bits_le_padded(last_index, MAX_DEPTH); let mut block_last_bits = usize_to_bits_le_padded(last_index, MAX_DEPTH);
let split_point = BOT_DEPTH; let split_point = BOT_DEPTH;
@ -186,18 +176,18 @@ impl<F: RichField, H: Hasher<F>> SlotTree<F, H> {
return block_tree; return block_tree;
} }
/// Converts an index to a vector of bits (LSB first) with padding. // /// Converts an index to a vector of bits (LSB first) with padding.
pub(crate) fn usize_to_bits_le_padded(&self, index: usize, bit_length: usize) -> Vec<bool> { // pub(crate) fn usize_to_bits_le_padded(&self, index: usize, bit_length: usize) -> Vec<bool> {
let mut bits = Vec::with_capacity(bit_length); // let mut bits = Vec::with_capacity(bit_length);
for i in 0..bit_length { // for i in 0..bit_length {
bits.push(((index >> i) & 1) == 1); // bits.push(((index >> i) & 1) == 1);
} // }
// If index requires fewer bits, pad with `false` // // If index requires fewer bits, pad with `false`
while bits.len() < bit_length { // while bits.len() < bit_length {
bits.push(false); // bits.push(false);
} // }
bits // bits
} // }
} }
//------- single cell struct ------ //------- single cell struct ------
@ -329,14 +319,14 @@ impl<
} }
// Convert `leaf_index` to binary bits and assign as path_bits // Convert `leaf_index` to binary bits and assign as path_bits
let path_bits = self.usize_to_bits_le_padded(leaf_index, MAX_DEPTH); let path_bits = usize_to_bits_le_padded(leaf_index, MAX_DEPTH);
for (i, bit) in path_bits.iter().enumerate() { for (i, bit) in path_bits.iter().enumerate() {
pw.set_bool_target(targets.path_bits[i], *bit); pw.set_bool_target(targets.path_bits[i], *bit);
} }
// get `last_index` (nleaves - 1) in binary bits and assign // get `last_index` (nleaves - 1) in binary bits and assign
let last_index = N_CELLS - 1; let last_index = N_CELLS - 1;
let last_bits = self.usize_to_bits_le_padded(last_index, MAX_DEPTH); let last_bits = usize_to_bits_le_padded(last_index, MAX_DEPTH);
for (i, bit) in last_bits.iter().enumerate() { for (i, bit) in last_bits.iter().enumerate() {
pw.set_bool_target(targets.last_bits[i], *bit); pw.set_bool_target(targets.last_bits[i], *bit);
} }

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::utils::usize_to_bits_le_padded;
use crate::merkle_tree::merkle_safe::{MerkleTree, MerkleProofTarget}; use crate::merkle_tree::merkle_safe::{MerkleTree, MerkleProofTarget};
use crate::merkle_tree::merkle_safe::{KEY_NONE,KEY_BOTTOM_LAYER}; use crate::merkle_tree::merkle_safe::{KEY_NONE,KEY_BOTTOM_LAYER};
@ -144,14 +145,14 @@ impl<
pw.set_hash_target(targets.leaf, leaf_hash); pw.set_hash_target(targets.leaf, leaf_hash);
// Convert `leaf_index` to binary bits and assign as path_bits // Convert `leaf_index` to binary bits and assign as path_bits
let path_bits = self.usize_to_bits_le_padded(leaf_index, depth); let path_bits = usize_to_bits_le_padded(leaf_index, depth);
for (i, bit) in path_bits.iter().enumerate() { for (i, bit) in path_bits.iter().enumerate() {
pw.set_bool_target(targets.path_bits[i], *bit); pw.set_bool_target(targets.path_bits[i], *bit);
} }
// get `last_index` (nleaves - 1) in binary bits and assign // get `last_index` (nleaves - 1) in binary bits and assign
let last_index = nleaves - 1; let last_index = nleaves - 1;
let last_bits = self.usize_to_bits_le_padded(last_index, depth); let last_bits = usize_to_bits_le_padded(last_index, depth);
for (i, bit) in last_bits.iter().enumerate() { for (i, bit) in last_bits.iter().enumerate() {
pw.set_bool_target(targets.last_bits[i], *bit); pw.set_bool_target(targets.last_bits[i], *bit);
} }
@ -234,25 +235,25 @@ impl<
} }
// --------- helper functions --------- // --------- helper functions ---------
impl< // impl<
F: RichField + Extendable<D> + Poseidon2, // F: RichField + Extendable<D> + Poseidon2,
C: GenericConfig<D, F = F>, // C: GenericConfig<D, F = F>,
const D: usize, // const D: usize,
H: Hasher<F> + AlgebraicHasher<F>, // H: Hasher<F> + AlgebraicHasher<F>,
> MerkleTreeCircuit<F, C, D, H> { // > MerkleTreeCircuit<F, C, D, H> {
/// Converts an index to a vector of bits (LSB first) with padding. // /// Converts an index to a vector of bits (LSB first) with padding.
pub(crate) fn usize_to_bits_le_padded(&self, index: usize, bit_length: usize) -> Vec<bool> { // pub(crate) fn usize_to_bits_le_padded(&self, index: usize, bit_length: usize) -> Vec<bool> {
let mut bits = Vec::with_capacity(bit_length); // let mut bits = Vec::with_capacity(bit_length);
for i in 0..bit_length { // for i in 0..bit_length {
bits.push(((index >> i) & 1) == 1); // bits.push(((index >> i) & 1) == 1);
} // }
// If index requires fewer bits, pad with `false` // // If index requires fewer bits, pad with `false`
while bits.len() < bit_length { // while bits.len() < bit_length {
bits.push(false); // bits.push(false);
} // }
bits // bits
} // }
} // }
// NOTE: for now these tests don't check the reconstructed root is equal to expected_root // NOTE: for now these tests don't check the reconstructed root is equal to expected_root

View File

@ -27,15 +27,11 @@ use plonky2::field::goldilocks_field::GoldilocksField;
use plonky2::plonk::config::PoseidonGoldilocksConfig; use plonky2::plonk::config::PoseidonGoldilocksConfig;
use plonky2::hash::hashing::PlonkyPermutation; use plonky2::hash::hashing::PlonkyPermutation;
use crate::circuits::prove_single_cell::{MAX_DEPTH, SlotTree}; use crate::circuits::prove_single_cell::{SingleCellTargets, SlotTree};
use crate::circuits::params::{MAX_DEPTH, BOT_DEPTH, N_FIELD_ELEMS_PER_CELL, N_CELLS_IN_BLOCKS, N_BLOCKS, N_CELLS, HF, DATASET_DEPTH, N_SAMPLES};
use crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets}; use crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets};
// constatnts and types
const DATASET_DEPTH: usize = 2;
const N_SAMPLES: usize = 5;
type HF = PoseidonHash;
// ------ Dataset Tree -------- // ------ Dataset Tree --------
///dataset tree containing all slot trees ///dataset tree containing all slot trees
#[derive(Clone)] #[derive(Clone)]
@ -155,6 +151,78 @@ impl<F: RichField, H: Hasher<F>> DatasetTree<F, H> {
} }
} }
//------- single cell struct ------
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DatasetTargets<
F: RichField + Extendable<D> + Poseidon2,
C: GenericConfig<D, F = F>,
const D: usize,
H: Hasher<F> + AlgebraicHasher<F>,
> {
// pub expected_dataset_root_target: HashOutTarget,
// pub slot_index: Target,
// pub entropy_target: Target,
// pub slot_root: HashOutTarget,
pub slot_proofs: Vec<SingleCellTargets<F, C, D, H>>,
// pub proof_target: MerkleProofTarget,
// pub leaf_target: Vec<Target>,
// pub path_bits: Vec<BoolTarget>,
// pub last_bits: Vec<BoolTarget>,
_phantom: PhantomData<(C,H)>,
}
//------- circuit impl --------
impl<
F: RichField + Extendable<D> + Poseidon2,
C: GenericConfig<D, F=F>,
const D: usize,
H: Hasher<F> + AlgebraicHasher<F> + Hasher<F>,
> MerkleTreeCircuit<F, C, D, H> {
// the in-circuit sampling of a slot in a dataset
pub fn sample_slot_circuit(
&mut self,
builder: &mut CircuitBuilder::<F, D>,
)-> DatasetTargets<F,C,D,H>{
// Create virtual targets
// let slot_root = builder.add_virtual_hash();
let mut slot_proofs =vec![];
for i in 0..N_SAMPLES{
let proof_i = self.prove_single_cell2(builder);
slot_proofs.push(proof_i);
}
DatasetTargets::<F,C,D,H>{
// expected_dataset_root_target: HashOutTarget {},
// slot_index: Default::default(),
// entropy_target: Default::default(),
// slot_root: HashOutTarget {},
slot_proofs,
_phantom: Default::default(),
}
}
// assign the witnesses to the target
// takes the dataset tree, slot index, and entropy
pub fn sample_slot_assign_witness(
&mut self,
pw: &mut PartialWitness<F>,
targets: DatasetTargets<F,C,D,H>,
dataset_tree: DatasetTree<F,H>,
slot_index:usize,
entropy:usize,
){
}
}
// --------- helper functions -------------- // --------- helper functions --------------
fn calculate_cell_index_bits<F: RichField>(p0: usize, p1: HashOut<F>, p2: usize) -> Vec<bool> { fn calculate_cell_index_bits<F: RichField>(p0: usize, p1: HashOut<F>, p2: usize) -> Vec<bool> {
let p0_field = F::from_canonical_u64(p0 as u64); let p0_field = F::from_canonical_u64(p0 as u64);

View File

@ -0,0 +1,17 @@
// --------- helper functions ---------
/// Converts an index to a vector of bits (LSB first) with padding.
pub(crate) fn usize_to_bits_le_padded(index: usize, bit_length: usize) -> Vec<bool> {
let mut bits = Vec::with_capacity(bit_length);
for i in 0..bit_length {
bits.push(((index >> i) & 1) == 1);
}
// If index requires fewer bits, pad with `false`
while bits.len() < bit_length {
bits.push(false);
}
bits
}