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 safe_tree_circuit;
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 crate::circuits::safe_tree_circuit::{MerkleTreeCircuit, MerkleTreeTargets};
// 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)
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;
use crate::circuits::utils::usize_to_bits_le_padded;
use crate::circuits::params::{MAX_DEPTH, BOT_DEPTH, N_FIELD_ELEMS_PER_CELL, N_CELLS_IN_BLOCKS, N_BLOCKS, N_CELLS, HF};
// ------ 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
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 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;
@ -186,18 +176,18 @@ impl<F: RichField, H: Hasher<F>> SlotTree<F, H> {
return block_tree;
}
/// 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> {
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
}
// /// 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> {
// 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
// }
}
//------- single cell struct ------
@ -329,14 +319,14 @@ impl<
}
// 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() {
pw.set_bool_target(targets.path_bits[i], *bit);
}
// get `last_index` (nleaves - 1) in binary bits and assign
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() {
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 plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
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::{KEY_NONE,KEY_BOTTOM_LAYER};
@ -144,14 +145,14 @@ impl<
pw.set_hash_target(targets.leaf, leaf_hash);
// 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() {
pw.set_bool_target(targets.path_bits[i], *bit);
}
// get `last_index` (nleaves - 1) in binary bits and assign
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() {
pw.set_bool_target(targets.last_bits[i], *bit);
}
@ -234,25 +235,25 @@ impl<
}
// --------- helper functions ---------
impl<
F: RichField + Extendable<D> + Poseidon2,
C: GenericConfig<D, F = F>,
const D: usize,
H: Hasher<F> + AlgebraicHasher<F>,
> MerkleTreeCircuit<F, C, D, H> {
/// 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> {
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
}
}
// impl<
// F: RichField + Extendable<D> + Poseidon2,
// C: GenericConfig<D, F = F>,
// const D: usize,
// H: Hasher<F> + AlgebraicHasher<F>,
// > MerkleTreeCircuit<F, C, D, H> {
// /// 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> {
// 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
// }
// }
// 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::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};
// constatnts and types
const DATASET_DEPTH: usize = 2;
const N_SAMPLES: usize = 5;
type HF = PoseidonHash;
// ------ Dataset Tree --------
///dataset tree containing all slot trees
#[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 --------------
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);

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
}