move proof-input and refactor
This commit is contained in:
parent
7a24f7d081
commit
cc14498c71
|
@ -10,7 +10,7 @@ use plonky2::hash::hash_types::RichField;
|
||||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
use codex_plonky2_circuits::circuits::params::TESTING_SLOT_INDEX;
|
use codex_plonky2_circuits::circuits::params::TESTING_SLOT_INDEX;
|
||||||
use codex_plonky2_circuits::circuits::sample_cells::DatasetTreeCircuit;
|
use codex_plonky2_circuits::circuits::sample_cells::SampleCircuit;
|
||||||
|
|
||||||
macro_rules! pretty_print {
|
macro_rules! pretty_print {
|
||||||
($($arg:tt)*) => {
|
($($arg:tt)*) => {
|
||||||
|
@ -28,12 +28,12 @@ fn prepare_data<
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
H: Hasher<F> + AlgebraicHasher<F>,
|
||||||
>() -> Result<(
|
>() -> Result<(
|
||||||
DatasetTreeCircuit<F, C, D, H>,
|
SampleCircuit<F, C, D, H>,
|
||||||
usize,
|
usize,
|
||||||
usize,
|
usize,
|
||||||
)> {
|
)> {
|
||||||
// Initialize the dataset tree with testing data
|
// Initialize the dataset tree with testing data
|
||||||
let mut dataset_t = DatasetTreeCircuit::<F,C,D,H>::new_for_testing();
|
let mut dataset_t = SampleCircuit::<F,C,D,H>::new_for_testing();
|
||||||
|
|
||||||
let slot_index = TESTING_SLOT_INDEX;
|
let slot_index = TESTING_SLOT_INDEX;
|
||||||
let entropy = 123;
|
let entropy = 123;
|
||||||
|
@ -47,7 +47,7 @@ fn build_circuit<
|
||||||
const D: usize,
|
const D: usize,
|
||||||
H: Hasher<F> + AlgebraicHasher<F>,
|
H: Hasher<F> + AlgebraicHasher<F>,
|
||||||
>(
|
>(
|
||||||
dataset_tree: &mut DatasetTreeCircuit<F, C, D, H>,
|
dataset_tree: &mut SampleCircuit<F, C, D, H>,
|
||||||
slot_index: usize,
|
slot_index: usize,
|
||||||
entropy: usize,
|
entropy: usize,
|
||||||
// proofs: &[MerkleProof<F, H>],
|
// proofs: &[MerkleProof<F, H>],
|
||||||
|
|
|
@ -9,7 +9,8 @@ use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
/// Compression function which takes two 256 bit inputs (HashOut) and u64 key (which is converted to field element in the function)
|
/// Compression function which takes two 256 bit inputs (HashOut) and u64 key (which is converted to field element in the function)
|
||||||
/// and returns a 256 bit output (HashOut).
|
/// and returns a 256 bit output (HashOut).
|
||||||
pub fn key_compress<
|
pub fn key_compress<
|
||||||
F: RichField,
|
F: RichField, //+ Extendable<D> + Poseidon2,
|
||||||
|
// const D: usize,
|
||||||
H:Hasher<F>
|
H:Hasher<F>
|
||||||
>(x: HashOut<F>, y: HashOut<F>, key: u64) -> HashOut<F> {
|
>(x: HashOut<F>, y: HashOut<F>, key: u64) -> HashOut<F> {
|
||||||
|
|
||||||
|
@ -55,5 +56,86 @@ pub fn key_compress_circuit<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use plonky2::hash::poseidon::PoseidonHash;
|
||||||
|
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||||
|
use plonky2_field::types::Field;
|
||||||
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2Hash;
|
||||||
|
use super::*;
|
||||||
|
// types
|
||||||
|
pub const D: usize = 2;
|
||||||
|
pub type C = PoseidonGoldilocksConfig;
|
||||||
|
pub type F = <C as GenericConfig<D>>::F; // this is the goldilocks field
|
||||||
|
pub type H = Poseidon2Hash;
|
||||||
|
|
||||||
|
/// tests the non-circuit key_compress with concrete cases
|
||||||
|
#[test]
|
||||||
|
pub fn test_key_compress(){
|
||||||
|
let ref_inp_1: [F; 4] = [
|
||||||
|
F::from_canonical_u64(0x0000000000000001),
|
||||||
|
F::from_canonical_u64(0x0000000000000002),
|
||||||
|
F::from_canonical_u64(0x0000000000000003),
|
||||||
|
F::from_canonical_u64(0x0000000000000004),
|
||||||
|
];
|
||||||
|
|
||||||
|
let ref_inp_2: [F; 4] = [
|
||||||
|
F::from_canonical_u64(0x0000000000000005),
|
||||||
|
F::from_canonical_u64(0x0000000000000006),
|
||||||
|
F::from_canonical_u64(0x0000000000000007),
|
||||||
|
F::from_canonical_u64(0x0000000000000008),
|
||||||
|
];
|
||||||
|
|
||||||
|
let ref_out_key_0: [F; 4] = [
|
||||||
|
F::from_canonical_u64(0xc4a4082f411ba790),
|
||||||
|
F::from_canonical_u64(0x98c2ed7546c44cce),
|
||||||
|
F::from_canonical_u64(0xc9404f373b78c979),
|
||||||
|
F::from_canonical_u64(0x65d6b3c998920f59),
|
||||||
|
];
|
||||||
|
|
||||||
|
let ref_out_key_1: [F; 4] = [
|
||||||
|
F::from_canonical_u64(0xca47449a05283778),
|
||||||
|
F::from_canonical_u64(0x08d3ced2020391ac),
|
||||||
|
F::from_canonical_u64(0xda461ea45670fb12),
|
||||||
|
F::from_canonical_u64(0x57f2c0b6c98a05c5),
|
||||||
|
];
|
||||||
|
|
||||||
|
let ref_out_key_2: [F; 4] = [
|
||||||
|
F::from_canonical_u64(0xe6fcec96a7a7f4b0),
|
||||||
|
F::from_canonical_u64(0x3002a22356daa551),
|
||||||
|
F::from_canonical_u64(0x899e2c1075a45f3f),
|
||||||
|
F::from_canonical_u64(0xf07e38ccb3ade312),
|
||||||
|
];
|
||||||
|
|
||||||
|
let ref_out_key_3: [F; 4] = [
|
||||||
|
F::from_canonical_u64(0x9930cff752b046fb),
|
||||||
|
F::from_canonical_u64(0x41570687cadcea0b),
|
||||||
|
F::from_canonical_u64(0x3ac093a5a92066c7),
|
||||||
|
F::from_canonical_u64(0xc45c75a3911cde87),
|
||||||
|
];
|
||||||
|
|
||||||
|
// `HashOut` for inputs
|
||||||
|
let inp1 = HashOut { elements: ref_inp_1 };
|
||||||
|
let inp2 = HashOut { elements: ref_inp_2 };
|
||||||
|
|
||||||
|
// Expected outputs
|
||||||
|
let expected_outputs = [
|
||||||
|
ref_out_key_0,
|
||||||
|
ref_out_key_1,
|
||||||
|
ref_out_key_2,
|
||||||
|
ref_out_key_3,
|
||||||
|
];
|
||||||
|
|
||||||
|
// Iterate over each key and test key_compress output
|
||||||
|
for (key, &expected) in expected_outputs.iter().enumerate() {
|
||||||
|
let output = key_compress::<F, H>(inp1, inp2, key as u64);
|
||||||
|
|
||||||
|
// Assert that output matches the expected result
|
||||||
|
assert_eq!(output.elements, expected, "Output mismatch for key: {}", key);
|
||||||
|
|
||||||
|
println!("Test passed for key {}", key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@ impl<
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> MerkleTreeCircuit<F, D> {
|
> MerkleTreeCircuit<F, D> {
|
||||||
|
|
||||||
|
|
||||||
pub fn new() -> Self{
|
pub fn new() -> Self{
|
||||||
Self{
|
Self{
|
||||||
phantom_data: Default::default(),
|
phantom_data: Default::default(),
|
||||||
|
@ -109,7 +110,7 @@ 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
|
||||||
/// this one uses the mask bits
|
/// this one uses the mask bits to select the right layer
|
||||||
pub fn reconstruct_merkle_root_circuit_with_mask(
|
pub fn reconstruct_merkle_root_circuit_with_mask(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder<F, D>,
|
||||||
targets: &mut MerkleTreeTargets,
|
targets: &mut MerkleTreeTargets,
|
||||||
|
@ -160,6 +161,7 @@ impl<
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// select the right layer using the mask bits
|
||||||
// another way to do this is to use builder.select
|
// another way to do this is to use builder.select
|
||||||
// but that might be less efficient & more constraints
|
// but that might be less efficient & more constraints
|
||||||
let mut reconstructed_root = HashOutTarget::from_vec([builder.zero();4].to_vec());
|
let mut reconstructed_root = HashOutTarget::from_vec([builder.zero();4].to_vec());
|
||||||
|
@ -169,8 +171,7 @@ impl<
|
||||||
add_assign_hash_out_target(builder,&mut reconstructed_root, &mul_result);
|
add_assign_hash_out_target(builder,&mut reconstructed_root, &mul_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// reconstructed_root
|
reconstructed_root
|
||||||
state[max_depth]
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,14 @@ use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2Hash;
|
||||||
// will look into this later.
|
// will look into this later.
|
||||||
pub type HF = PoseidonHash;
|
pub type HF = PoseidonHash;
|
||||||
|
|
||||||
|
// params used for the circuits
|
||||||
|
// should be defined prior to building the circuit
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct CircuitParams{
|
||||||
|
pub max_depth: usize,
|
||||||
|
pub max_log2_n_slots: usize,
|
||||||
|
pub block_tree_depth: usize,
|
||||||
|
pub n_field_elems_per_cell: usize,
|
||||||
|
pub n_samples: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,25 +5,23 @@
|
||||||
// - reconstruct the dataset merkle root using the slot root as leaf
|
// - reconstruct the dataset merkle root using the slot root as leaf
|
||||||
// - samples multiple cells by calling the sample_cells
|
// - samples multiple cells by calling the sample_cells
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use plonky2::field::extension::Extendable;
|
use plonky2::field::extension::Extendable;
|
||||||
use plonky2::hash::hash_types::{HashOut, HashOutTarget, NUM_HASH_OUT_ELTS, RichField};
|
use plonky2::hash::hash_types::{HashOut, HashOutTarget, NUM_HASH_OUT_ELTS, RichField};
|
||||||
use plonky2::iop::target::{BoolTarget, Target};
|
use plonky2::iop::target::{BoolTarget, Target};
|
||||||
use plonky2::iop::witness::{PartialWitness, WitnessWrite, Witness};
|
use plonky2::iop::witness::{PartialWitness, WitnessWrite};
|
||||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher, GenericHashOut};
|
use plonky2::plonk::config::GenericConfig;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
use plonky2::hash::hashing::PlonkyPermutation;
|
use plonky2::hash::hashing::PlonkyPermutation;
|
||||||
use crate::circuits::params::HF;
|
use crate::circuits::params::{CircuitParams, HF};
|
||||||
|
|
||||||
use crate::circuits::merkle_circuit::{MerkleTreeCircuit, MerkleTreeTargets, MerkleProofTarget};
|
use crate::circuits::merkle_circuit::{MerkleProofTarget, MerkleTreeCircuit, MerkleTreeTargets};
|
||||||
use crate::circuits::utils::{assign_hash_out_targets, bits_le_padded_to_usize, calculate_cell_index_bits};
|
use crate::circuits::utils::assign_hash_out_targets;
|
||||||
|
|
||||||
// ------ Dataset Tree --------
|
/// circuit for sampling a slot in a dataset merkle tree
|
||||||
///dataset tree containing all slot trees
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DatasetTreeCircuit<
|
pub struct SampleCircuit<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> {
|
> {
|
||||||
|
@ -34,7 +32,7 @@ pub struct DatasetTreeCircuit<
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> DatasetTreeCircuit<F, D> {
|
> SampleCircuit<F, D> {
|
||||||
pub fn new(params: CircuitParams) -> Self{
|
pub fn new(params: CircuitParams) -> Self{
|
||||||
Self{
|
Self{
|
||||||
params,
|
params,
|
||||||
|
@ -43,17 +41,8 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// params used for the circuits
|
/// struct of input to the circuit as targets
|
||||||
// should be defined prior to building the circuit
|
/// used to build the circuit and can be assigned after building
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CircuitParams{
|
|
||||||
pub max_depth: usize,
|
|
||||||
pub max_log2_n_slots: usize,
|
|
||||||
pub block_tree_depth: usize,
|
|
||||||
pub n_field_elems_per_cell: usize,
|
|
||||||
pub n_samples: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SampleTargets {
|
pub struct SampleTargets {
|
||||||
|
|
||||||
|
@ -65,13 +54,14 @@ pub struct SampleTargets {
|
||||||
pub n_cells_per_slot: Target,
|
pub n_cells_per_slot: Target,
|
||||||
pub n_slots_per_dataset: Target,
|
pub n_slots_per_dataset: Target,
|
||||||
|
|
||||||
pub slot_proof: MerkleProofTarget, // proof that slot_root in dataset tree
|
pub slot_proof: MerkleProofTarget,
|
||||||
|
|
||||||
pub cell_data: Vec<Vec<Target>>,
|
pub cell_data: Vec<CellTarget>,
|
||||||
pub merkle_paths: Vec<MerkleProofTarget>,
|
pub merkle_paths: Vec<MerkleProofTarget>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
/// circuit input as field elements
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct SampleCircuitInput<
|
pub struct SampleCircuitInput<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
|
@ -84,31 +74,42 @@ pub struct SampleCircuitInput<
|
||||||
pub n_cells_per_slot: F,
|
pub n_cells_per_slot: F,
|
||||||
pub n_slots_per_dataset: F,
|
pub n_slots_per_dataset: F,
|
||||||
|
|
||||||
pub slot_proof: Vec<HashOut<F>>, // proof that slot_root in dataset tree
|
pub slot_proof: Vec<HashOut<F>>,
|
||||||
|
|
||||||
pub cell_data: Vec<Vec<F>>,
|
pub cell_data: Vec<Cell<F,D>>,
|
||||||
pub merkle_paths: Vec<Vec<HashOut<F>>>,
|
pub merkle_paths: Vec<MerklePath<F,D>>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
/// merkle path from leaf to root as vec of HashOut (4 Goldilocks field elems)
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct MerklePath<
|
pub struct MerklePath<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> {
|
> {
|
||||||
path: Vec<HashOut<F>>
|
pub path: Vec<HashOut<F>>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
/// a vec of cell targets
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct CellTarget {
|
pub struct CellTarget {
|
||||||
pub data: Vec<Target>
|
pub data: Vec<Target>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// cell data as field elements
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Cell<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
|
const D: usize,
|
||||||
|
> {
|
||||||
|
pub data: Vec<F>,
|
||||||
|
}
|
||||||
|
|
||||||
//------- circuit impl --------
|
//------- circuit impl --------
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> DatasetTreeCircuit<F, D> {
|
> SampleCircuit<F, D> {
|
||||||
|
|
||||||
// in-circuit sampling
|
// in-circuit sampling
|
||||||
// TODO: make it more modular
|
// TODO: make it more modular
|
||||||
|
@ -145,7 +146,9 @@ impl<
|
||||||
// dataset last bits (binary decomposition of last_index = nleaves - 1)
|
// dataset last bits (binary decomposition of last_index = nleaves - 1)
|
||||||
let dataset_last_index = builder.sub(n_slots_per_dataset, one);
|
let dataset_last_index = builder.sub(n_slots_per_dataset, one);
|
||||||
let d_last_bits = builder.split_le(dataset_last_index,max_log2_n_slots);
|
let d_last_bits = builder.split_le(dataset_last_index,max_log2_n_slots);
|
||||||
let d_mask_bits = builder.split_le(dataset_last_index,max_log2_n_slots+1);
|
|
||||||
|
// dataset mask bits
|
||||||
|
let mut d_mask_bits = builder.split_le(dataset_last_index,max_log2_n_slots+1);
|
||||||
|
|
||||||
// dataset Merkle path (sibling hashes from leaf to root)
|
// dataset Merkle path (sibling hashes from leaf to root)
|
||||||
let d_merkle_path = MerkleProofTarget {
|
let d_merkle_path = MerkleProofTarget {
|
||||||
|
@ -182,25 +185,33 @@ impl<
|
||||||
// virtual target for n_cells_per_slot
|
// virtual target for n_cells_per_slot
|
||||||
let n_cells_per_slot = builder.add_virtual_target();
|
let n_cells_per_slot = builder.add_virtual_target();
|
||||||
|
|
||||||
|
// calculate last index = n_cells_per_slot-1
|
||||||
let slot_last_index = builder.sub(n_cells_per_slot, one);
|
let slot_last_index = builder.sub(n_cells_per_slot, one);
|
||||||
|
|
||||||
|
// create the mask bits
|
||||||
|
// TODO: reuse this for block and slot trees
|
||||||
|
let mask_bits = builder.split_le(slot_last_index,max_depth);
|
||||||
|
|
||||||
|
// last and mask bits for block tree
|
||||||
let mut b_last_bits = builder.split_le(slot_last_index,max_depth);
|
let mut b_last_bits = builder.split_le(slot_last_index,max_depth);
|
||||||
let mut b_mask_bits = builder.split_le(slot_last_index,max_depth);
|
let mut b_mask_bits = builder.split_le(slot_last_index,max_depth);
|
||||||
|
|
||||||
|
// last and mask bits for the slot tree
|
||||||
let mut s_last_bits = b_last_bits.split_off(block_tree_depth);
|
let mut s_last_bits = b_last_bits.split_off(block_tree_depth);
|
||||||
let mut s_mask_bits = b_mask_bits.split_off(block_tree_depth);
|
let mut s_mask_bits = b_mask_bits.split_off(block_tree_depth);
|
||||||
|
|
||||||
|
// pad mask bits with 0
|
||||||
b_mask_bits.push(BoolTarget::new_unsafe(zero.clone()));
|
b_mask_bits.push(BoolTarget::new_unsafe(zero.clone()));
|
||||||
s_mask_bits.push(BoolTarget::new_unsafe(zero.clone()));
|
s_mask_bits.push(BoolTarget::new_unsafe(zero.clone()));
|
||||||
|
|
||||||
for i in 0..n_samples{
|
for i in 0..n_samples{
|
||||||
// cell data targets
|
// cell data targets
|
||||||
let mut data_i = (0..n_field_elems_per_cell).map(|_| builder.add_virtual_target()).collect::<Vec<_>>();
|
let mut data_i = (0..n_field_elems_per_cell).map(|_| builder.add_virtual_target()).collect::<Vec<_>>();
|
||||||
|
// hash the cell data
|
||||||
let mut hash_inputs:Vec<Target>= Vec::new();
|
let mut hash_inputs:Vec<Target>= Vec::new();
|
||||||
hash_inputs.extend_from_slice(&data_i);
|
hash_inputs.extend_from_slice(&data_i);
|
||||||
let data_i_hash = builder.hash_n_to_hash_no_pad::<HF>(hash_inputs);
|
let data_i_hash = builder.hash_n_to_hash_no_pad::<HF>(hash_inputs);
|
||||||
// counter constant
|
// make the counter into hash digest
|
||||||
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();
|
||||||
for i in 0..ctr.elements.len() {
|
for i in 0..ctr.elements.len() {
|
||||||
|
@ -210,8 +221,8 @@ impl<
|
||||||
ctr.elements[i] = zero.clone();
|
ctr.elements[i] = zero.clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// paths
|
// paths for block and slot
|
||||||
let mut b_path_bits = self.calculate_cell_index_bits(builder, &entropy_target, &d_targets.leaf, &ctr);
|
let mut b_path_bits = self.calculate_cell_index_bits(builder, &entropy_target, &d_targets.leaf, &ctr, mask_bits.clone());
|
||||||
let mut s_path_bits = b_path_bits.split_off(block_tree_depth);
|
let mut s_path_bits = b_path_bits.split_off(block_tree_depth);
|
||||||
|
|
||||||
let mut b_merkle_path = MerkleProofTarget {
|
let mut b_merkle_path = MerkleProofTarget {
|
||||||
|
@ -255,7 +266,10 @@ impl<
|
||||||
};
|
};
|
||||||
slot_sample_proof_target.path.extend_from_slice(&slot_targets.merkle_path.path);
|
slot_sample_proof_target.path.extend_from_slice(&slot_targets.merkle_path.path);
|
||||||
|
|
||||||
data_targets.push(data_i);
|
let cell_i = CellTarget{
|
||||||
|
data: data_i
|
||||||
|
};
|
||||||
|
data_targets.push(cell_i);
|
||||||
slot_sample_proofs.push(slot_sample_proof_target);
|
slot_sample_proofs.push(slot_sample_proof_target);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -273,7 +287,8 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_cell_index_bits(&self, builder: &mut CircuitBuilder::<F, D>, entropy: &HashOutTarget, slot_root: &HashOutTarget, ctr: &HashOutTarget) -> Vec<BoolTarget> {
|
/// calculate the cell index = H( entropy | slotRoot | counter ) `mod` nCells
|
||||||
|
pub fn calculate_cell_index_bits(&self, builder: &mut CircuitBuilder::<F, D>, entropy: &HashOutTarget, slot_root: &HashOutTarget, ctr: &HashOutTarget, mask_bits: Vec<BoolTarget>) -> Vec<BoolTarget> {
|
||||||
let mut hash_inputs:Vec<Target>= Vec::new();
|
let mut hash_inputs:Vec<Target>= Vec::new();
|
||||||
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);
|
||||||
|
@ -281,9 +296,17 @@ impl<
|
||||||
let hash_out = builder.hash_n_to_hash_no_pad::<HF>(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], self.params.max_depth, 64);
|
let cell_index_bits = builder.low_bits(hash_out.elements[0], self.params.max_depth, 64);
|
||||||
|
|
||||||
cell_index_bits
|
let mut masked_cell_index_bits = vec![];
|
||||||
|
|
||||||
|
// extract the lowest 32 bits using the bit mask
|
||||||
|
for i in 0..self.params.max_depth{
|
||||||
|
masked_cell_index_bits.push(BoolTarget::new_unsafe(builder.mul(mask_bits[i].target, cell_index_bits[i].target)));
|
||||||
|
}
|
||||||
|
|
||||||
|
masked_cell_index_bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// helper method to assign the targets in the circuit to actual field elems
|
||||||
pub fn sample_slot_assign_witness(
|
pub fn sample_slot_assign_witness(
|
||||||
&self,
|
&self,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
|
@ -323,16 +346,13 @@ impl<
|
||||||
|
|
||||||
// do the sample N times
|
// do the sample N times
|
||||||
for i in 0..n_samples {
|
for i in 0..n_samples {
|
||||||
let cell_index_bits = calculate_cell_index_bits(&witnesses.entropy,witnesses.slot_root,i+1,max_depth);
|
|
||||||
let cell_index = bits_le_padded_to_usize(&cell_index_bits);
|
|
||||||
// assign cell data
|
// assign cell data
|
||||||
let leaf = witnesses.cell_data[i].clone();
|
let leaf = witnesses.cell_data[i].data.clone();
|
||||||
for j in 0..n_field_elems_per_cell{
|
for j in 0..n_field_elems_per_cell{
|
||||||
pw.set_target(targets.cell_data[i][j], leaf[j]);
|
pw.set_target(targets.cell_data[i].data[j], leaf[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign proof for that cell
|
// assign proof for that cell
|
||||||
let cell_proof = witnesses.merkle_paths[i].clone();
|
let cell_proof = witnesses.merkle_paths[i].path.clone();
|
||||||
for k in 0..max_depth {
|
for k in 0..max_depth {
|
||||||
pw.set_hash_target(targets.merkle_paths[i].path[k], cell_proof[k])
|
pw.set_hash_target(targets.merkle_paths[i].path[k], cell_proof[k])
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ pub(crate) fn usize_to_bits_le_padded(index: usize, bit_length: usize) -> Vec<bo
|
||||||
bits
|
bits
|
||||||
}
|
}
|
||||||
/// calculate the sampled cell index from entropy, slot root, and counter
|
/// calculate the sampled cell index from entropy, slot root, and counter
|
||||||
pub(crate) fn calculate_cell_index_bits<F: RichField>(entropy: &Vec<F>, slot_root: HashOut<F>, ctr: usize, depth: usize) -> Vec<bool> {
|
/// this is the non-circuit version for testing
|
||||||
|
pub(crate) fn calculate_cell_index_bits<F: RichField>(entropy: &Vec<F>, slot_root: HashOut<F>, ctr: usize, depth: usize, mask_bits: Vec<bool>) -> Vec<bool> {
|
||||||
let ctr_field = F::from_canonical_u64(ctr as u64);
|
let ctr_field = F::from_canonical_u64(ctr as u64);
|
||||||
let mut ctr_as_digest = HashOut::<F>::ZERO;
|
let mut ctr_as_digest = HashOut::<F>::ZERO;
|
||||||
ctr_as_digest.elements[0] = ctr_field;
|
ctr_as_digest.elements[0] = ctr_field;
|
||||||
|
@ -37,7 +38,14 @@ pub(crate) fn calculate_cell_index_bits<F: RichField>(entropy: &Vec<F>, slot_roo
|
||||||
let cell_index_bytes = hash_output.elements[0].to_canonical_u64();
|
let cell_index_bytes = hash_output.elements[0].to_canonical_u64();
|
||||||
|
|
||||||
let cell_index_bits = usize_to_bits_le_padded(cell_index_bytes as usize, depth);
|
let cell_index_bits = usize_to_bits_le_padded(cell_index_bytes as usize, depth);
|
||||||
cell_index_bits
|
|
||||||
|
let mut masked_cell_index_bits = vec![];
|
||||||
|
|
||||||
|
for i in 0..depth{
|
||||||
|
masked_cell_index_bits.push(cell_index_bits[i] && mask_bits[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
masked_cell_index_bits
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_n_bits_from_bytes(bytes: &[u8], n: usize) -> Vec<bool> {
|
pub(crate) fn take_n_bits_from_bytes(bytes: &[u8], n: usize) -> Vec<bool> {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
pub mod circuits;
|
pub mod circuits;
|
||||||
pub mod merkle_tree;
|
pub mod merkle_tree;
|
||||||
pub mod proof_input;
|
// pub mod proof_input;
|
||||||
pub mod tests;
|
pub mod tests;
|
|
@ -1,144 +1,101 @@
|
||||||
use anyhow::Result;
|
|
||||||
use plonky2::hash::hash_types::{HashOut, RichField};
|
use plonky2::hash::hash_types::{HashOut, RichField};
|
||||||
use plonky2::plonk::config::{GenericConfig, Hasher};
|
use plonky2::plonk::config::{GenericConfig, Hasher};
|
||||||
use plonky2_field::extension::Extendable;
|
use plonky2_field::extension::Extendable;
|
||||||
use plonky2_field::types::Field;
|
use plonky2_field::types::Field;
|
||||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
use crate::circuits::params::HF;
|
use crate::circuits::params::HF;
|
||||||
use crate::proof_input::test_params::{BOT_DEPTH, DATASET_DEPTH, MAX_DEPTH, N_BLOCKS, N_CELLS, N_CELLS_IN_BLOCKS, N_FIELD_ELEMS_PER_CELL, N_SAMPLES, TESTING_SLOT_INDEX};
|
use crate::proof_input::test_params::Params;
|
||||||
use crate::circuits::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, usize_to_bits_le_padded};
|
use crate::circuits::utils::{bits_le_padded_to_usize, calculate_cell_index_bits, usize_to_bits_le_padded};
|
||||||
use crate::merkle_tree::merkle_safe::{MerkleProof, MerkleTree};
|
use crate::merkle_tree::merkle_safe::{MerkleProof, MerkleTree};
|
||||||
|
use crate::circuits::sample_cells::Cell;
|
||||||
|
|
||||||
|
// #[derive(Clone)]
|
||||||
|
// pub struct Cell<
|
||||||
|
// F: RichField + Extendable<D> + Poseidon2,
|
||||||
|
// const D: usize,
|
||||||
|
// > {
|
||||||
|
// pub data: Vec<F>, // cell data as field elements
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<
|
||||||
|
// F: RichField + Extendable<D> + Poseidon2,
|
||||||
|
// const D: usize,
|
||||||
|
// > Cell<F, D> {
|
||||||
|
/// Create a new cell with random data, using the parameters from `Params`
|
||||||
|
pub fn new_random_cell<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
|
const D: usize,
|
||||||
|
>(params: &Params) -> Cell<F,D> {
|
||||||
|
let data = (0..params.n_field_elems_per_cell())
|
||||||
|
.map(|_| F::rand())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Cell::<F,D> {
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SlotTree<
|
pub struct SlotTree<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> {
|
> {
|
||||||
pub tree: MerkleTree<F>, // slot tree
|
pub tree: MerkleTree<F>, // slot tree
|
||||||
pub block_trees: Vec<MerkleTree<F>>, // vec of block trees
|
pub block_trees: Vec<MerkleTree<F>>, // vec of block trees
|
||||||
pub cell_data: Vec<Cell<F,D>>, // cell data as field elements
|
pub cell_data: Vec<Cell<F, D>>, // cell data as field elements
|
||||||
}
|
pub params: Params, // parameters
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Cell<
|
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
const D: usize,
|
|
||||||
> {
|
|
||||||
pub data: Vec<F>, // cell data as field elements
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
const D: usize,
|
|
||||||
> Default for Cell<F, D> {
|
|
||||||
/// default cell with random data
|
|
||||||
fn default() -> Self {
|
|
||||||
let data = (0..N_FIELD_ELEMS_PER_CELL)
|
|
||||||
.map(|j| F::rand())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Self{
|
|
||||||
data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
|
||||||
const D: usize,
|
|
||||||
> Default for SlotTree<F, D> {
|
|
||||||
/// slot tree with fake data, for testing only
|
|
||||||
fn default() -> Self {
|
|
||||||
// generate fake cell data
|
|
||||||
let mut cell_data = (0..N_CELLS)
|
|
||||||
.map(|i|{
|
|
||||||
Cell::<F,D>::default()
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
Self::new(cell_data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> SlotTree<F, D> {
|
> SlotTree<F, D> {
|
||||||
/// Slot tree with fake data, for testing only
|
/// Create a slot tree with fake data, for testing only
|
||||||
pub fn new_for_testing(cells: Vec<Cell<F, D>>) -> Self {
|
pub fn new_default(params: &Params) -> Self {
|
||||||
// Hash the cell data block to create leaves for one block
|
// generate fake cell data
|
||||||
let leaves_block: Vec<HashOut<F>> = cells
|
let cell_data = (0..params.n_cells)
|
||||||
.iter()
|
.map(|_| new_random_cell(params))
|
||||||
.map(|element| {
|
.collect::<Vec<_>>();
|
||||||
HF::hash_no_pad(&element.data)
|
Self::new(cell_data, params.clone())
|
||||||
})
|
}
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Zero hash
|
/// Create a new slot tree with the supplied cell data and parameters
|
||||||
|
pub fn new(cells: Vec<Cell<F, D>>, params: Params) -> Self {
|
||||||
|
let leaves: Vec<HashOut<F>> = cells
|
||||||
|
.iter()
|
||||||
|
.map(|element| HF::hash_no_pad(&element.data))
|
||||||
|
.collect();
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
elements: [F::ZERO; 4],
|
elements: [F::ZERO; 4],
|
||||||
};
|
};
|
||||||
|
let n_blocks = params.n_blocks_test();
|
||||||
|
let n_cells_in_blocks = params.n_cells_in_blocks();
|
||||||
|
|
||||||
// Create a block tree from the leaves of one block
|
let block_trees = (0..n_blocks)
|
||||||
let b_tree = Self::get_block_tree(&leaves_block);
|
.map(|i| {
|
||||||
|
let start = i * n_cells_in_blocks;
|
||||||
// Now replicate this block tree for all N_BLOCKS blocks
|
let end = (i + 1) * n_cells_in_blocks;
|
||||||
let block_trees = vec![b_tree; N_BLOCKS];
|
Self::get_block_tree(&leaves[start..end].to_vec())
|
||||||
|
})
|
||||||
// Get the roots of block trees
|
.collect::<Vec<_>>();
|
||||||
let block_roots = block_trees
|
let block_roots = block_trees
|
||||||
.iter()
|
.iter()
|
||||||
.map(|t| t.root().unwrap())
|
.map(|t| t.root().unwrap())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Create the slot tree from block roots
|
|
||||||
let slot_tree = MerkleTree::<F>::new(&block_roots, zero).unwrap();
|
|
||||||
|
|
||||||
// Create the full cell data and cell hash by repeating the block data
|
|
||||||
let cell_data = vec![cells.clone(); N_BLOCKS].concat();
|
|
||||||
|
|
||||||
// Return the constructed Self
|
|
||||||
Self {
|
|
||||||
tree: slot_tree,
|
|
||||||
block_trees,
|
|
||||||
cell_data,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// same as default but with supplied cell data
|
|
||||||
pub fn new(cells: Vec<Cell<F, D>>) -> Self {
|
|
||||||
let leaves: Vec<HashOut<F>> = cells
|
|
||||||
.iter()
|
|
||||||
.map(|element| {
|
|
||||||
HF::hash_no_pad(&element.data)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let zero = HashOut {
|
|
||||||
elements: [F::ZERO; 4],
|
|
||||||
};
|
|
||||||
let block_trees = (0..N_BLOCKS as usize)
|
|
||||||
.map(|i| {
|
|
||||||
let start = i * N_CELLS_IN_BLOCKS;
|
|
||||||
let end = (i + 1) * N_CELLS_IN_BLOCKS;
|
|
||||||
Self::get_block_tree(&leaves[start..end].to_vec())
|
|
||||||
// MerkleTree::<F> { tree: b_tree }
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let block_roots = block_trees.iter()
|
|
||||||
.map(|t| {
|
|
||||||
t.root().unwrap()
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let slot_tree = MerkleTree::<F>::new(&block_roots, zero).unwrap();
|
let slot_tree = MerkleTree::<F>::new(&block_roots, zero).unwrap();
|
||||||
Self {
|
Self {
|
||||||
tree: slot_tree,
|
tree: slot_tree,
|
||||||
block_trees,
|
block_trees,
|
||||||
cell_data: cells,
|
cell_data: cells,
|
||||||
|
params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates a proof for given leaf index
|
/// Generates a proof for the 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> {
|
pub fn get_proof(&self, index: usize) -> MerkleProof<F> {
|
||||||
let block_index = index / N_CELLS_IN_BLOCKS;
|
let block_index = index / self.params.n_cells_in_blocks();
|
||||||
let leaf_index = index % N_CELLS_IN_BLOCKS;
|
let leaf_index = index % self.params.n_cells_in_blocks();
|
||||||
let block_proof = self.block_trees[block_index].get_proof(leaf_index).unwrap();
|
let block_proof = self.block_trees[block_index].get_proof(leaf_index).unwrap();
|
||||||
let slot_proof = self.tree.get_proof(block_index).unwrap();
|
let slot_proof = self.tree.get_proof(block_index).unwrap();
|
||||||
|
|
||||||
|
@ -147,20 +104,20 @@ impl<
|
||||||
combined_path.extend(slot_proof.path.clone());
|
combined_path.extend(slot_proof.path.clone());
|
||||||
|
|
||||||
MerkleProof::<F> {
|
MerkleProof::<F> {
|
||||||
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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// verify the given proof for slot tree, checks equality with given root
|
/// Verify the given proof for slot tree, checks equality with the given root
|
||||||
pub fn verify_cell_proof(&self, proof: MerkleProof<F>, root: HashOut<F>) -> anyhow::Result<bool> {
|
pub fn verify_cell_proof(&self, proof: MerkleProof<F>, root: HashOut<F>) -> anyhow::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, self.params.max_depth);
|
||||||
let last_index = N_CELLS - 1;
|
let last_index = self.params.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, self.params.max_depth);
|
||||||
|
|
||||||
let split_point = BOT_DEPTH;
|
let split_point = self.params.bot_depth();
|
||||||
|
|
||||||
let slot_last_bits = block_last_bits.split_off(split_point);
|
let slot_last_bits = block_last_bits.split_off(split_point);
|
||||||
let slot_path_bits = block_path_bits.split_off(split_point);
|
let slot_path_bits = block_path_bits.split_off(split_point);
|
||||||
|
@ -170,8 +127,18 @@ 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>::reconstruct_root2(leaf_hash, block_path_bits.clone(), block_last_bits.clone(), block_path);
|
let block_res = MerkleProof::<F>::reconstruct_root2(
|
||||||
let reconstructed_root = MerkleProof::<F>::reconstruct_root2(block_res.unwrap(), slot_path_bits, slot_last_bits, slot_path);
|
leaf_hash,
|
||||||
|
block_path_bits.clone(),
|
||||||
|
block_last_bits.clone(),
|
||||||
|
block_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)
|
||||||
}
|
}
|
||||||
|
@ -187,50 +154,49 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------ Dataset Tree --------
|
// ------ Dataset Tree --------
|
||||||
///dataset tree containing all slot trees
|
/// Dataset tree containing all slot trees
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DatasetTree<
|
pub struct DatasetTree<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> {
|
> {
|
||||||
pub tree: MerkleTree<F>, // dataset tree
|
pub tree: MerkleTree<F>, // dataset tree
|
||||||
pub slot_trees: Vec<SlotTree<F, D>>, // vec of slot trees
|
pub slot_trees: Vec<SlotTree<F, D>>, // vec of slot trees
|
||||||
|
pub params: Params, // parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dataset Merkle proof struct, containing the dataset proof and N_SAMPLES proofs.
|
/// Dataset Merkle proof struct, containing the dataset proof and sampled proofs.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DatasetProof<F: RichField> {
|
pub struct DatasetProof<
|
||||||
pub slot_index: F,
|
|
||||||
pub entropy: HashOut<F>,
|
|
||||||
pub dataset_proof: MerkleProof<F>, // proof for dataset level tree
|
|
||||||
pub slot_proofs: Vec<MerkleProof<F>>, // proofs for sampled slot, contains N_SAMPLES proofs
|
|
||||||
pub cell_data: Vec<Vec<F>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<
|
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> Default for DatasetTree<F, D> {
|
> {
|
||||||
/// dataset tree with fake data, for testing only
|
pub slot_index: F,
|
||||||
fn default() -> Self {
|
pub entropy: HashOut<F>,
|
||||||
let mut slot_trees = vec![];
|
pub dataset_proof: MerkleProof<F>, // proof for dataset level tree
|
||||||
let n_slots = 1 << DATASET_DEPTH;
|
pub slot_proofs: Vec<MerkleProof<F>>, // proofs for sampled slot
|
||||||
for i in 0..n_slots {
|
pub cell_data: Vec<Cell<F,D>>,
|
||||||
slot_trees.push(SlotTree::<F, D>::default());
|
|
||||||
}
|
|
||||||
Self::new(slot_trees)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<
|
||||||
F: RichField + Extendable<D> + Poseidon2,
|
F: RichField + Extendable<D> + Poseidon2,
|
||||||
const D: usize,
|
const D: usize,
|
||||||
> DatasetTree<F, D> {
|
> DatasetTree<F, D> {
|
||||||
/// 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
|
pub fn new_default(params: &Params) -> Self {
|
||||||
pub fn new_for_testing() -> Self {
|
|
||||||
let mut slot_trees = vec![];
|
let mut slot_trees = vec![];
|
||||||
let n_slots = 1 << DATASET_DEPTH;
|
let n_slots = 1 << params.dataset_depth_test();
|
||||||
|
for _ in 0..n_slots {
|
||||||
|
slot_trees.push(SlotTree::<F, D>::new_default(params));
|
||||||
|
}
|
||||||
|
Self::new(slot_trees, params.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create data for only the specified slot index in params
|
||||||
|
pub fn new_for_testing(params: &Params) -> Self {
|
||||||
|
let mut slot_trees = vec![];
|
||||||
|
// let n_slots = 1 << params.dataset_depth();
|
||||||
|
let n_slots = params.n_slots;
|
||||||
// zero hash
|
// zero hash
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
elements: [F::ZERO; 4],
|
elements: [F::ZERO; 4],
|
||||||
|
@ -239,34 +205,34 @@ impl<
|
||||||
tree: MerkleTree::<F>::new(&[zero.clone()], zero.clone()).unwrap(),
|
tree: MerkleTree::<F>::new(&[zero.clone()], zero.clone()).unwrap(),
|
||||||
block_trees: vec![],
|
block_trees: vec![],
|
||||||
cell_data: vec![],
|
cell_data: vec![],
|
||||||
|
params: params.clone(),
|
||||||
};
|
};
|
||||||
for i in 0..n_slots {
|
for i in 0..n_slots {
|
||||||
if (i == TESTING_SLOT_INDEX) {
|
if i == params.testing_slot_index {
|
||||||
slot_trees.push(SlotTree::<F, D>::default());
|
slot_trees.push(SlotTree::<F, D>::new_default(params));
|
||||||
} else {
|
} else {
|
||||||
slot_trees.push(zero_slot.clone());
|
slot_trees.push(zero_slot.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// get the roots or slot trees
|
// get the roots of slot trees
|
||||||
let slot_roots = slot_trees.iter()
|
let slot_roots = slot_trees
|
||||||
.map(|t| {
|
.iter()
|
||||||
t.tree.root().unwrap()
|
.map(|t| t.tree.root().unwrap())
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let dataset_tree = MerkleTree::<F>::new(&slot_roots, zero).unwrap();
|
let dataset_tree = MerkleTree::<F>::new(&slot_roots, zero).unwrap();
|
||||||
Self {
|
Self {
|
||||||
tree: dataset_tree,
|
tree: dataset_tree,
|
||||||
slot_trees,
|
slot_trees,
|
||||||
|
params: params.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// same as default but with supplied slot trees
|
/// Same as default but with supplied slot trees
|
||||||
pub fn new(slot_trees: Vec<SlotTree<F, D>>) -> Self {
|
pub fn new(slot_trees: Vec<SlotTree<F, D>>, params: Params) -> Self {
|
||||||
// get the roots or slot trees
|
// get the roots of slot trees
|
||||||
let slot_roots = slot_trees.iter()
|
let slot_roots = slot_trees
|
||||||
.map(|t| {
|
.iter()
|
||||||
t.tree.root().unwrap()
|
.map(|t| t.tree.root().unwrap())
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
// zero hash
|
// zero hash
|
||||||
let zero = HashOut {
|
let zero = HashOut {
|
||||||
|
@ -276,20 +242,24 @@ impl<
|
||||||
Self {
|
Self {
|
||||||
tree: dataset_tree,
|
tree: dataset_tree,
|
||||||
slot_trees,
|
slot_trees,
|
||||||
|
params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates a dataset level proof for given slot index
|
/// Generates a dataset level proof for the given slot index
|
||||||
/// just a regular merkle tree proof
|
/// Just a regular Merkle tree proof
|
||||||
pub fn get_proof(&self, index: usize) -> MerkleProof<F> {
|
pub fn get_proof(&self, index: usize) -> MerkleProof<F> {
|
||||||
let dataset_proof = self.tree.get_proof(index).unwrap();
|
let dataset_proof = self.tree.get_proof(index).unwrap();
|
||||||
dataset_proof
|
dataset_proof
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates a proof for given slot index
|
/// Generates a proof for the given slot index
|
||||||
/// also takes entropy so it can use it sample the slot
|
/// Also takes entropy so it can use it to sample the slot
|
||||||
pub fn sample_slot(&self, index: usize, entropy: usize) -> DatasetProof<F> {
|
pub fn sample_slot(&self, index: usize, entropy: usize) -> DatasetProof<F,D> {
|
||||||
let dataset_proof = self.tree.get_proof(index).unwrap();
|
let mut dataset_proof = self.tree.get_proof(index).unwrap();
|
||||||
|
// println!("d proof len = {}", dataset_proof.path.len());
|
||||||
|
Self::pad_proof(&mut dataset_proof, self.params.dataset_depth());
|
||||||
|
// println!("d proof len = {}", dataset_proof.path.len());
|
||||||
let slot = &self.slot_trees[index];
|
let slot = &self.slot_trees[index];
|
||||||
let slot_root = slot.tree.root().unwrap();
|
let slot_root = slot.tree.root().unwrap();
|
||||||
let mut slot_proofs = vec![];
|
let mut slot_proofs = vec![];
|
||||||
|
@ -298,12 +268,24 @@ impl<
|
||||||
let mut entropy_as_digest = HashOut::<F>::ZERO;
|
let mut entropy_as_digest = HashOut::<F>::ZERO;
|
||||||
entropy_as_digest.elements[0] = entropy_field;
|
entropy_as_digest.elements[0] = entropy_field;
|
||||||
// get the index for cell from H(slot_root|counter|entropy)
|
// get the index for cell from H(slot_root|counter|entropy)
|
||||||
for i in 0..N_SAMPLES {
|
let mask_bits = usize_to_bits_le_padded(self.params.n_cells-1, self.params.max_depth+1);
|
||||||
let cell_index_bits = calculate_cell_index_bits(&entropy_as_digest.elements.to_vec(), slot_root, i+1, MAX_DEPTH);
|
for i in 0..self.params.n_samples {
|
||||||
|
let cell_index_bits = calculate_cell_index_bits(
|
||||||
|
&entropy_as_digest.elements.to_vec(),
|
||||||
|
slot_root,
|
||||||
|
i + 1,
|
||||||
|
self.params.max_depth,
|
||||||
|
mask_bits.clone()
|
||||||
|
);
|
||||||
let cell_index = bits_le_padded_to_usize(&cell_index_bits);
|
let cell_index = bits_le_padded_to_usize(&cell_index_bits);
|
||||||
let s_proof = slot.get_proof(cell_index);
|
let mut s_proof = slot.get_proof(cell_index);
|
||||||
|
Self::pad_proof(&mut s_proof, self.params.max_depth);
|
||||||
slot_proofs.push(s_proof);
|
slot_proofs.push(s_proof);
|
||||||
cell_data.push(slot.cell_data[cell_index].data.clone());
|
let data_i = slot.cell_data[cell_index].data.clone();
|
||||||
|
let cell_i = Cell::<F,D>{
|
||||||
|
data: data_i
|
||||||
|
};
|
||||||
|
cell_data.push(cell_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
DatasetProof {
|
DatasetProof {
|
||||||
|
@ -315,28 +297,39 @@ impl<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify the sampling - non-circuit version
|
pub fn pad_proof(merkle_proof: &mut MerkleProof<F>, max_depth: usize){
|
||||||
pub fn verify_sampling(&self, proof: DatasetProof<F>) -> bool {
|
for i in merkle_proof.path.len()..max_depth{
|
||||||
let slot = &self.slot_trees[proof.slot_index.to_canonical_u64() as usize];
|
merkle_proof.path.push(HashOut::<F>::ZERO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the sampling - non-circuit version
|
||||||
|
pub fn verify_sampling(&self, proof: DatasetProof<F,D>) -> bool {
|
||||||
|
let slot_index = proof.slot_index.to_canonical_u64() as usize;
|
||||||
|
let slot = &self.slot_trees[slot_index];
|
||||||
let slot_root = slot.tree.root().unwrap();
|
let slot_root = slot.tree.root().unwrap();
|
||||||
// check dataset level proof
|
// check dataset level proof
|
||||||
let d_res = proof.dataset_proof.verify(slot_root, self.tree.root().unwrap());
|
let d_res = proof.dataset_proof.verify(slot_root, self.tree.root().unwrap());
|
||||||
if (d_res.unwrap() == false) {
|
if d_res.unwrap() == false {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// sanity check
|
// sanity check
|
||||||
assert_eq!(N_SAMPLES, proof.slot_proofs.len());
|
assert_eq!(self.params.n_samples, proof.slot_proofs.len());
|
||||||
// get the index for cell from H(slot_root|counter|entropy)
|
// get the index for cell from H(slot_root|counter|entropy)
|
||||||
for i in 0..N_SAMPLES {
|
let mask_bits = usize_to_bits_le_padded(self.params.n_cells -1, self.params.max_depth);
|
||||||
// let entropy_field = F::from_canonical_u64(proof.entropy as u64);
|
for i in 0..self.params.n_samples {
|
||||||
// let mut entropy_as_digest = HashOut::<F>::ZERO;
|
let cell_index_bits = calculate_cell_index_bits(
|
||||||
// entropy_as_digest.elements[0] = entropy_field;
|
&proof.entropy.elements.to_vec(),
|
||||||
let cell_index_bits = calculate_cell_index_bits(&proof.entropy.elements.to_vec(), slot_root, i+1, MAX_DEPTH);
|
slot_root,
|
||||||
|
i + 1,
|
||||||
|
self.params.max_depth,
|
||||||
|
mask_bits.clone(),
|
||||||
|
);
|
||||||
let cell_index = bits_le_padded_to_usize(&cell_index_bits);
|
let cell_index = bits_le_padded_to_usize(&cell_index_bits);
|
||||||
//check the cell_index is the same as one in the proof
|
// check the cell_index is the same as one in the proof
|
||||||
assert_eq!(cell_index, proof.slot_proofs[i].index);
|
assert_eq!(cell_index, proof.slot_proofs[i].index);
|
||||||
let s_res = slot.verify_cell_proof(proof.slot_proofs[i].clone(), slot_root);
|
let s_res = slot.verify_cell_proof(proof.slot_proofs[i].clone(), slot_root);
|
||||||
if (s_res.unwrap() == false) {
|
if s_res.unwrap() == false {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,76 +345,82 @@ mod tests {
|
||||||
use plonky2::plonk::config::GenericConfig;
|
use plonky2::plonk::config::GenericConfig;
|
||||||
use plonky2::iop::witness::PartialWitness;
|
use plonky2::iop::witness::PartialWitness;
|
||||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
use crate::circuits::sample_cells::{CircuitParams, DatasetTreeCircuit, SampleCircuitInput};
|
use crate::circuits::params::CircuitParams;
|
||||||
use crate::proof_input::test_params::{D, C, F, H, N_SLOTS};
|
use crate::circuits::sample_cells::{MerklePath, SampleCircuit, SampleCircuitInput};
|
||||||
|
use crate::proof_input::test_params::{C, D, F};
|
||||||
|
|
||||||
// test sample cells (non-circuit)
|
// Test sample cells (non-circuit)
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sample_cells() {
|
fn test_sample_cells() {
|
||||||
let dataset_t = DatasetTree::<F, D>::new_for_testing();
|
let params = Params::default();
|
||||||
let slot_index = 2;
|
let dataset_t = DatasetTree::<F, D>::new_for_testing(¶ms);
|
||||||
let entropy = 2;
|
let slot_index = params.testing_slot_index;
|
||||||
let proof = dataset_t.sample_slot(slot_index,entropy);
|
let entropy = params.entropy; // Use the entropy from Params if desired
|
||||||
|
let proof = dataset_t.sample_slot(slot_index, entropy);
|
||||||
let res = dataset_t.verify_sampling(proof);
|
let res = dataset_t.verify_sampling(proof);
|
||||||
assert_eq!(res, true);
|
assert_eq!(res, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// test sample cells in-circuit for a selected slot
|
// Test sample cells in-circuit for a selected slot
|
||||||
#[test]
|
#[test]
|
||||||
fn test_sample_cells_circuit_from_selected_slot() -> anyhow::Result<()> {
|
fn test_sample_cells_circuit_from_selected_slot() -> anyhow::Result<()> {
|
||||||
|
let params = Params::default();
|
||||||
|
let dataset_t = DatasetTree::<F, D>::new_for_testing(¶ms);
|
||||||
|
|
||||||
let mut dataset_t = DatasetTree::<F, D>::new_for_testing();
|
let slot_index = params.testing_slot_index;
|
||||||
|
let entropy = params.entropy; // Use the entropy from Params if desired
|
||||||
|
|
||||||
let slot_index = TESTING_SLOT_INDEX;
|
// Sanity check
|
||||||
let entropy = 123;
|
let proof = dataset_t.sample_slot(slot_index, entropy);
|
||||||
|
|
||||||
// sanity check
|
|
||||||
let proof = dataset_t.sample_slot(slot_index,entropy);
|
|
||||||
let slot_root = dataset_t.slot_trees[slot_index].tree.root().unwrap();
|
let slot_root = dataset_t.slot_trees[slot_index].tree.root().unwrap();
|
||||||
let res = dataset_t.verify_sampling(proof.clone());
|
// let res = dataset_t.verify_sampling(proof.clone());
|
||||||
assert_eq!(res, true);
|
// assert_eq!(res, true);
|
||||||
|
|
||||||
// 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 circuit_params = CircuitParams{
|
let circuit_params = CircuitParams {
|
||||||
max_depth: MAX_DEPTH,
|
max_depth: params.max_depth,
|
||||||
max_log2_n_slots: DATASET_DEPTH,
|
max_log2_n_slots: params.dataset_depth(),
|
||||||
block_tree_depth: BOT_DEPTH,
|
block_tree_depth: params.bot_depth(),
|
||||||
n_field_elems_per_cell: N_FIELD_ELEMS_PER_CELL,
|
n_field_elems_per_cell: params.n_field_elems_per_cell(),
|
||||||
n_samples: N_SAMPLES,
|
n_samples: params.n_samples,
|
||||||
};
|
};
|
||||||
let circ = DatasetTreeCircuit::new(circuit_params);
|
let circ = SampleCircuit::new(circuit_params.clone());
|
||||||
let mut targets = circ.sample_slot_circuit(&mut builder);
|
let mut targets = circ.sample_slot_circuit(&mut builder);
|
||||||
|
|
||||||
// create a PartialWitness and assign
|
// Create a PartialWitness and assign
|
||||||
let mut pw = PartialWitness::new();
|
let mut pw = PartialWitness::new();
|
||||||
|
|
||||||
let mut slot_paths = vec![];
|
let mut slot_paths = vec![];
|
||||||
for i in 0..N_SAMPLES{
|
for i in 0..params.n_samples {
|
||||||
let path = proof.slot_proofs[i].path.clone();
|
let path = proof.slot_proofs[i].path.clone();
|
||||||
slot_paths.push(path);
|
let mp = MerklePath::<F,D>{
|
||||||
//TODO: need to be padded
|
path,
|
||||||
|
};
|
||||||
|
slot_paths.push(mp);
|
||||||
}
|
}
|
||||||
|
println!("circuit params = {:?}", circuit_params);
|
||||||
|
|
||||||
let witness = SampleCircuitInput::<F,D>{
|
let witness = SampleCircuitInput::<F, D> {
|
||||||
entropy: proof.entropy.elements.clone().to_vec(),
|
entropy: proof.entropy.elements.clone().to_vec(),
|
||||||
dataset_root: dataset_t.tree.root().unwrap(),
|
dataset_root: dataset_t.tree.root().unwrap(),
|
||||||
slot_index: proof.slot_index.clone(),
|
slot_index: proof.slot_index.clone(),
|
||||||
slot_root,
|
slot_root,
|
||||||
n_cells_per_slot: F::from_canonical_u64((2_u32.pow(MAX_DEPTH as u32)) as u64),
|
n_cells_per_slot: F::from_canonical_usize(params.n_cells),
|
||||||
n_slots_per_dataset: F::from_canonical_u64((2_u32.pow(DATASET_DEPTH as u32)) as u64),
|
n_slots_per_dataset: F::from_canonical_usize(params.n_slots),
|
||||||
slot_proof: proof.dataset_proof.path.clone(),
|
slot_proof: proof.dataset_proof.path.clone(),
|
||||||
cell_data: proof.cell_data.clone(),
|
cell_data: proof.cell_data.clone(),
|
||||||
merkle_paths: slot_paths,
|
merkle_paths: slot_paths,
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("dataset ={:?}",dataset_t.slot_trees[0].tree.layers);
|
println!("dataset = {:?}", witness.slot_proof.clone());
|
||||||
|
println!("n_slots_per_dataset = {:?}", witness.n_slots_per_dataset.clone());
|
||||||
|
|
||||||
circ.sample_slot_assign_witness(&mut pw, &mut targets,witness);
|
circ.sample_slot_assign_witness(&mut pw, &mut targets, witness);
|
||||||
|
|
||||||
// build the circuit
|
// Build the circuit
|
||||||
let data = builder.build::<C>();
|
let data = builder.build::<C>();
|
||||||
println!("circuit size = {:?}", data.common.degree_bits());
|
println!("circuit size = {:?}", data.common.degree_bits());
|
||||||
|
|
||||||
|
@ -430,7 +429,7 @@ mod tests {
|
||||||
let proof_with_pis = data.prove(pw)?;
|
let proof_with_pis = data.prove(pw)?;
|
||||||
println!("prove_time = {:?}", start_time.elapsed());
|
println!("prove_time = {:?}", start_time.elapsed());
|
||||||
|
|
||||||
// verify the proof
|
// Verify the proof
|
||||||
let verifier_data = data.verifier_data();
|
let verifier_data = data.verifier_data();
|
||||||
assert!(
|
assert!(
|
||||||
verifier_data.verify(proof_with_pis).is_ok(),
|
verifier_data.verify(proof_with_pis).is_ok(),
|
||||||
|
|
|
@ -0,0 +1,406 @@
|
||||||
|
// use std::fmt::Error;
|
||||||
|
use anyhow::{anyhow, Result, Error};
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_json::json;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, Write};
|
||||||
|
use crate::proof_input::gen_input::DatasetTree;
|
||||||
|
use plonky2::hash::hash_types::{HashOut, RichField};
|
||||||
|
use plonky2::plonk::config::{GenericConfig, Hasher};
|
||||||
|
use plonky2_field::extension::Extendable;
|
||||||
|
use plonky2_field::types::Field;
|
||||||
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
|
use crate::circuits::sample_cells::{Cell, MerklePath, SampleCircuitInput};
|
||||||
|
use crate::proof_input::test_params::Params;
|
||||||
|
|
||||||
|
// ... (Include necessary imports and your existing code)
|
||||||
|
|
||||||
|
impl<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
||||||
|
const D: usize,
|
||||||
|
> DatasetTree<F, D> {
|
||||||
|
/// Function to generate witness and export to JSON
|
||||||
|
pub fn export_witness_to_json(&self, params: &Params, filename: &str) -> anyhow::Result<()> {
|
||||||
|
// Sample the slot
|
||||||
|
let slot_index = params.testing_slot_index;
|
||||||
|
let entropy = params.entropy;
|
||||||
|
|
||||||
|
let proof = self.sample_slot(slot_index, entropy);
|
||||||
|
let slot_root = self.slot_trees[slot_index].tree.root().unwrap();
|
||||||
|
|
||||||
|
// Prepare the witness data
|
||||||
|
let mut slot_paths = vec![];
|
||||||
|
for i in 0..params.n_samples {
|
||||||
|
let path = proof.slot_proofs[i].path.clone();
|
||||||
|
let mp = MerklePath::<F,D>{
|
||||||
|
path,
|
||||||
|
};
|
||||||
|
slot_paths.push(mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the witness
|
||||||
|
let witness = SampleCircuitInput::<F, D> {
|
||||||
|
entropy: proof.entropy.elements.clone().to_vec(),
|
||||||
|
dataset_root: self.tree.root().unwrap(),
|
||||||
|
slot_index: proof.slot_index.clone(),
|
||||||
|
slot_root,
|
||||||
|
n_cells_per_slot: F::from_canonical_usize(params.n_cells_per_slot()),
|
||||||
|
n_slots_per_dataset: F::from_canonical_usize(params.n_slots_per_dataset()),
|
||||||
|
slot_proof: proof.dataset_proof.path.clone(),
|
||||||
|
cell_data: proof.cell_data.clone(),
|
||||||
|
merkle_paths: slot_paths,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert the witness to a serializable format
|
||||||
|
let serializable_witness = SerializableWitness::from_witness(&witness);
|
||||||
|
|
||||||
|
// Serialize to JSON
|
||||||
|
let json_data = serde_json::to_string_pretty(&serializable_witness)?;
|
||||||
|
|
||||||
|
// Write to file
|
||||||
|
let mut file = File::create(filename)?;
|
||||||
|
file.write_all(json_data.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializable versions of your data structures
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct SerializableWitness<
|
||||||
|
// F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
||||||
|
// const D: usize,
|
||||||
|
> {
|
||||||
|
dataSetRoot: Vec<String>,
|
||||||
|
entropy: Vec<String>,
|
||||||
|
nCellsPerSlot: usize,
|
||||||
|
nSlotsPerDataSet: usize,
|
||||||
|
slotIndex: u64,
|
||||||
|
slotRoot: Vec<String>,
|
||||||
|
slotProof: Vec<String>,
|
||||||
|
cellData: Vec<Vec<String>>,
|
||||||
|
merklePaths: Vec<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
// F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
||||||
|
// const D: usize,
|
||||||
|
> SerializableWitness{
|
||||||
|
pub fn from_witness<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2 + Serialize,
|
||||||
|
const D: usize,
|
||||||
|
>(witness: &SampleCircuitInput<F, D>) -> Self {
|
||||||
|
SerializableWitness {
|
||||||
|
dataSetRoot: witness
|
||||||
|
.dataset_root
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.to_canonical_u64().to_string())
|
||||||
|
.collect(),
|
||||||
|
entropy: witness
|
||||||
|
.entropy
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.to_canonical_u64().to_string())
|
||||||
|
.collect(),
|
||||||
|
nCellsPerSlot: witness.n_cells_per_slot.to_canonical_u64() as usize,
|
||||||
|
nSlotsPerDataSet: witness.n_slots_per_dataset.to_canonical_u64() as usize,
|
||||||
|
slotIndex: witness.slot_index.to_canonical_u64(),
|
||||||
|
slotRoot: witness
|
||||||
|
.slot_root
|
||||||
|
.elements
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.to_canonical_u64().to_string())
|
||||||
|
.collect(),
|
||||||
|
slotProof: witness
|
||||||
|
.slot_proof
|
||||||
|
.iter()
|
||||||
|
.flat_map(|hash| hash.elements.iter())
|
||||||
|
.map(|e| e.to_canonical_u64().to_string())
|
||||||
|
.collect(),
|
||||||
|
cellData: witness
|
||||||
|
.cell_data
|
||||||
|
.iter()
|
||||||
|
.map(|data_vec| {
|
||||||
|
data_vec.data
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.to_canonical_u64().to_string())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
merklePaths: witness
|
||||||
|
.merkle_paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| {
|
||||||
|
path.path.iter()
|
||||||
|
.flat_map(|hash| hash.elements.iter())
|
||||||
|
.map(|e| e.to_canonical_u64().to_string())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub struct SampleCircuitInput<
|
||||||
|
// F: RichField + Extendable<D> + Poseidon2,
|
||||||
|
// const D: usize,
|
||||||
|
// > {
|
||||||
|
// pub entropy: Vec<F>,
|
||||||
|
// pub dataset_root: HashOut<F>,
|
||||||
|
// pub slot_index: F,
|
||||||
|
// pub slot_root: HashOut<F>,
|
||||||
|
// pub n_cells_per_slot: F,
|
||||||
|
// pub n_slots_per_dataset: F,
|
||||||
|
// pub slot_proof: Vec<HashOut<F>>,
|
||||||
|
// pub cell_data: Vec<Vec<F>>,
|
||||||
|
// pub merkle_paths: Vec<Vec<HashOut<F>>>,
|
||||||
|
// }
|
||||||
|
|
||||||
|
impl<> SerializableWitness {
|
||||||
|
pub fn to_witness<
|
||||||
|
F: RichField + Extendable<D> + Poseidon2, const D: usize
|
||||||
|
>(&self) -> Result<SampleCircuitInput<F, D>> {
|
||||||
|
// Convert entropy
|
||||||
|
let entropy = self
|
||||||
|
.entropy
|
||||||
|
.iter()
|
||||||
|
.map(|s| -> Result<F, Error> {
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(F::from_canonical_u64(n))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<F>, Error>>()?;
|
||||||
|
|
||||||
|
// Convert dataset_root
|
||||||
|
let dataset_root_elements = self
|
||||||
|
.dataSetRoot
|
||||||
|
.iter()
|
||||||
|
.map(|s| -> Result<F, Error> {
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(F::from_canonical_u64(n))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<F>, Error>>()?;
|
||||||
|
let dataset_root = HashOut {
|
||||||
|
elements: dataset_root_elements
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| anyhow!("Invalid dataset_root length"))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// slot_index
|
||||||
|
let slot_index = F::from_canonical_u64(self.slotIndex);
|
||||||
|
|
||||||
|
// slot_root
|
||||||
|
let slot_root_elements = self
|
||||||
|
.slotRoot
|
||||||
|
.iter()
|
||||||
|
.map(|s| -> Result<F, Error> {
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(F::from_canonical_u64(n))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<F>, Error>>()?;
|
||||||
|
let slot_root = HashOut {
|
||||||
|
elements: slot_root_elements
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| anyhow!("Invalid slot_root length"))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// n_cells_per_slot
|
||||||
|
let n_cells_per_slot = F::from_canonical_usize(self.nCellsPerSlot);
|
||||||
|
|
||||||
|
// n_slots_per_dataset
|
||||||
|
let n_slots_per_dataset = F::from_canonical_usize(self.nSlotsPerDataSet);
|
||||||
|
|
||||||
|
// slot_proof
|
||||||
|
let slot_proof_elements = self
|
||||||
|
.slotProof
|
||||||
|
.iter()
|
||||||
|
.map(|s| -> Result<F, Error> {
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(F::from_canonical_u64(n))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<F>, Error>>()?;
|
||||||
|
if slot_proof_elements.len() % 4 != 0 {
|
||||||
|
return Err(anyhow!("Invalid slot_proof length"));
|
||||||
|
}
|
||||||
|
let slot_proof = slot_proof_elements
|
||||||
|
.chunks(4)
|
||||||
|
.map(|chunk| -> Result<HashOut<F>, Error> {
|
||||||
|
let elements: [F; 4] = chunk
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| anyhow!("Invalid chunk length"))?;
|
||||||
|
Ok(HashOut { elements })
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<HashOut<F>>, Error>>()?;
|
||||||
|
|
||||||
|
// cell_data
|
||||||
|
let cell_data = self
|
||||||
|
.cellData
|
||||||
|
.iter()
|
||||||
|
.map(|vec_of_strings| -> Result<Cell<F,D>, Error> {
|
||||||
|
let cell = vec_of_strings
|
||||||
|
.iter()
|
||||||
|
.map(|s| -> Result<F, Error> {
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(F::from_canonical_u64(n))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<F>, Error>>();
|
||||||
|
Ok(Cell::<F,D>{
|
||||||
|
data: cell.unwrap(),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<Cell<F,D>>, Error>>()?;
|
||||||
|
|
||||||
|
// merkle_paths
|
||||||
|
let merkle_paths = self
|
||||||
|
.merklePaths
|
||||||
|
.iter()
|
||||||
|
.map(|path_strings| -> Result<MerklePath<F,D>, Error> {
|
||||||
|
let path_elements = path_strings
|
||||||
|
.iter()
|
||||||
|
.map(|s| -> Result<F, Error> {
|
||||||
|
let n = s.parse::<u64>()?;
|
||||||
|
Ok(F::from_canonical_u64(n))
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<F>, Error>>()?;
|
||||||
|
|
||||||
|
if path_elements.len() % 4 != 0 {
|
||||||
|
return Err(anyhow!("Invalid merkle path length"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = path_elements
|
||||||
|
.chunks(4)
|
||||||
|
.map(|chunk| -> Result<HashOut<F>, Error> {
|
||||||
|
let elements: [F; 4] = chunk
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| anyhow!("Invalid chunk length"))?;
|
||||||
|
Ok(HashOut { elements })
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<HashOut<F>>, Error>>()?;
|
||||||
|
|
||||||
|
let mp = MerklePath::<F,D>{
|
||||||
|
path,
|
||||||
|
};
|
||||||
|
Ok(mp)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<MerklePath<F,D>>, Error>>()?;
|
||||||
|
|
||||||
|
Ok(SampleCircuitInput {
|
||||||
|
entropy,
|
||||||
|
dataset_root,
|
||||||
|
slot_index,
|
||||||
|
slot_root,
|
||||||
|
n_cells_per_slot,
|
||||||
|
n_slots_per_dataset,
|
||||||
|
slot_proof,
|
||||||
|
cell_data,
|
||||||
|
merkle_paths,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn import_witness_from_json<F: RichField + Extendable<D> + Poseidon2, const D: usize>(
|
||||||
|
filename: &str,
|
||||||
|
) -> Result<SampleCircuitInput<F, D>> {
|
||||||
|
let file = File::open(filename)?;
|
||||||
|
let reader = BufReader::new(file);
|
||||||
|
let serializable_witness: SerializableWitness = serde_json::from_reader(reader)?;
|
||||||
|
|
||||||
|
let witness = serializable_witness.to_witness()?;
|
||||||
|
Ok(witness)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::proof_input::test_params::{F,D};
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
// Test to generate the JSON file
|
||||||
|
#[test]
|
||||||
|
fn test_export_witness_to_json() -> anyhow::Result<()> {
|
||||||
|
// Create Params instance
|
||||||
|
let params = Params::default();
|
||||||
|
|
||||||
|
// Create the dataset tree
|
||||||
|
let dataset_t = DatasetTree::<F, D>::new_for_testing(¶ms);
|
||||||
|
|
||||||
|
// Export the witness to JSON
|
||||||
|
dataset_t.export_witness_to_json(¶ms, "input.json")?;
|
||||||
|
|
||||||
|
println!("Witness exported to input.json");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_import_witness_from_json() -> anyhow::Result<()> {
|
||||||
|
// First, ensure that the JSON file exists
|
||||||
|
// You can generate it using the export function if needed
|
||||||
|
|
||||||
|
// Import the witness from the JSON file
|
||||||
|
let witness: SampleCircuitInput<F, D> = import_witness_from_json("input.json")?;
|
||||||
|
|
||||||
|
// Perform some checks to verify that the data was imported correctly
|
||||||
|
assert_eq!(witness.entropy.len(), 4); // Example check
|
||||||
|
// Add more assertions as needed
|
||||||
|
|
||||||
|
println!("Witness imported successfully");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_export_import_witness() -> anyhow::Result<()> {
|
||||||
|
// Create Params instance
|
||||||
|
let params = Params::default();
|
||||||
|
|
||||||
|
// Create the dataset tree
|
||||||
|
let dataset_t = DatasetTree::<F, D>::new_for_testing(¶ms);
|
||||||
|
|
||||||
|
// Generate the witness data
|
||||||
|
let slot_index = params.testing_slot_index;
|
||||||
|
let entropy = params.entropy;
|
||||||
|
|
||||||
|
let proof = dataset_t.sample_slot(slot_index, entropy);
|
||||||
|
let slot_root = dataset_t.slot_trees[slot_index].tree.root().unwrap();
|
||||||
|
|
||||||
|
let mut slot_paths = vec![];
|
||||||
|
for i in 0..params.n_samples {
|
||||||
|
let path = proof.slot_proofs[i].path.clone();
|
||||||
|
let mp = MerklePath::<F,D>{
|
||||||
|
path,
|
||||||
|
};
|
||||||
|
slot_paths.push(mp);
|
||||||
|
}
|
||||||
|
|
||||||
|
let original_witness = SampleCircuitInput::<F, D> {
|
||||||
|
entropy: proof.entropy.elements.clone().to_vec(),
|
||||||
|
dataset_root: dataset_t.tree.root().unwrap(),
|
||||||
|
slot_index: proof.slot_index.clone(),
|
||||||
|
slot_root,
|
||||||
|
n_cells_per_slot: F::from_canonical_usize(params.n_cells_per_slot()),
|
||||||
|
n_slots_per_dataset: F::from_canonical_usize(params.n_slots_per_dataset()),
|
||||||
|
slot_proof: proof.dataset_proof.path.clone(),
|
||||||
|
cell_data: proof.cell_data.clone(),
|
||||||
|
merkle_paths: slot_paths,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Export the witness to JSON
|
||||||
|
dataset_t.export_witness_to_json(¶ms, "input.json")?;
|
||||||
|
println!("Witness exported to input.json");
|
||||||
|
|
||||||
|
// Import the witness from JSON
|
||||||
|
let imported_witness: SampleCircuitInput<F, D> = import_witness_from_json("input.json")?;
|
||||||
|
println!("Witness imported from input.json");
|
||||||
|
|
||||||
|
// Compare the original and imported witnesses
|
||||||
|
assert_eq!(original_witness, imported_witness, "Witnesses are not equal");
|
||||||
|
|
||||||
|
// Cleanup: Remove the generated JSON file
|
||||||
|
fs::remove_file("input.json")?;
|
||||||
|
|
||||||
|
println!("Test passed: Original and imported witnesses are equal.");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
pub mod gen_input;
|
pub mod gen_input;
|
||||||
pub mod test_params;
|
pub mod test_params;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
pub mod json;
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
use plonky2::hash::poseidon::PoseidonHash;
|
use plonky2::hash::poseidon::PoseidonHash;
|
||||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||||
|
use std::env;
|
||||||
|
use anyhow::{Result, Context};
|
||||||
|
|
||||||
// fake input params
|
// fake input params
|
||||||
|
|
||||||
|
@ -13,7 +15,7 @@ pub type H = PoseidonHash;
|
||||||
|
|
||||||
|
|
||||||
// hardcoded params for generating proof input
|
// hardcoded params for generating proof input
|
||||||
pub const MAX_DEPTH: usize = 8; // depth of big tree (slot tree depth, includes block tree depth)
|
pub const MAX_DEPTH: usize = 32; // depth of big tree (slot tree depth, includes block tree depth)
|
||||||
pub const MAX_SLOTS: usize = 256; // maximum number of slots
|
pub const MAX_SLOTS: usize = 256; // maximum number of slots
|
||||||
pub const CELL_SIZE: usize = 2048; // cell size in bytes
|
pub const CELL_SIZE: usize = 2048; // cell size in bytes
|
||||||
pub const BLOCK_SIZE: usize = 65536; // block size in bytes
|
pub const BLOCK_SIZE: usize = 65536; // block size in bytes
|
||||||
|
@ -22,11 +24,12 @@ pub const N_SAMPLES: usize = 5; // number of samples to prove
|
||||||
pub const ENTROPY: usize = 1234567; // external randomness
|
pub const ENTROPY: usize = 1234567; // external randomness
|
||||||
pub const SEED: usize = 12345; // seed for creating fake data TODO: not used now
|
pub const SEED: usize = 12345; // seed for creating fake data TODO: not used now
|
||||||
|
|
||||||
pub const N_SLOTS: usize = 8; // number of slots in the dataset
|
pub const N_SLOTS: usize = 16; // number of slots in the dataset
|
||||||
pub const TESTING_SLOT_INDEX: usize = 2; // the index of the slot to be sampled
|
pub const TESTING_SLOT_INDEX: usize = 2; // the index of the slot to be sampled
|
||||||
pub const N_CELLS: usize = 512; // number of cells in each slot
|
pub const N_CELLS: usize = 512; // number of cells in each slot
|
||||||
|
|
||||||
/// Params struct
|
/// Params struct
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub max_depth: usize,
|
pub max_depth: usize,
|
||||||
pub max_slots: usize,
|
pub max_slots: usize,
|
||||||
|
@ -97,7 +100,7 @@ impl Params {
|
||||||
|
|
||||||
// BOT_DEPTH
|
// BOT_DEPTH
|
||||||
pub fn bot_depth(&self) -> usize {
|
pub fn bot_depth(&self) -> usize {
|
||||||
(self.block_size / self.cell_size).ilog2() as usize
|
(self.block_size / self.cell_size).trailing_zeros() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
// N_CELLS_IN_BLOCKS
|
// N_CELLS_IN_BLOCKS
|
||||||
|
@ -110,10 +113,36 @@ impl Params {
|
||||||
1 << (self.max_depth - self.bot_depth())
|
1 << (self.max_depth - self.bot_depth())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Depth of test input
|
||||||
|
pub fn depth_test(&self) -> usize {
|
||||||
|
self.n_cells.trailing_zeros() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
// N_BLOCKS for the test input
|
||||||
|
pub fn n_blocks_test(&self) -> usize {
|
||||||
|
1 << (self.depth_test() - self.bot_depth())
|
||||||
|
}
|
||||||
|
|
||||||
// DATASET_DEPTH
|
// DATASET_DEPTH
|
||||||
pub fn dataset_depth(&self) -> usize {
|
pub fn dataset_depth(&self) -> usize {
|
||||||
self.max_slots.ilog2() as usize
|
self.max_slots.trailing_zeros() as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DATASET_DEPTH for test
|
||||||
|
pub fn dataset_depth_test(&self) -> usize {
|
||||||
|
self.n_slots.trailing_zeros() as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
// n_cells_per_slot (2^max_depth)
|
||||||
|
pub fn n_cells_per_slot(&self) -> usize {
|
||||||
|
1 << self.max_depth
|
||||||
|
}
|
||||||
|
|
||||||
|
// n_slots_per_dataset (2^dataset_depth)
|
||||||
|
pub fn n_slots_per_dataset(&self) -> usize {
|
||||||
|
1 << self.dataset_depth()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,4 +156,71 @@ pub const N_BLOCKS: usize = 1<<(MAX_DEPTH - BOT_DEPTH); // 2^(MAX_DEPTH - BOT_DE
|
||||||
|
|
||||||
pub const DATASET_DEPTH: usize = MAX_SLOTS.ilog2() as usize;
|
pub const DATASET_DEPTH: usize = MAX_SLOTS.ilog2() as usize;
|
||||||
|
|
||||||
// TODO: load params
|
// load params
|
||||||
|
|
||||||
|
impl Params {
|
||||||
|
pub fn from_env() -> Result<Self> {
|
||||||
|
let max_depth = env::var("MAXDEPTH")
|
||||||
|
.context("MAXDEPTH not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid MAXDEPTH")?;
|
||||||
|
|
||||||
|
let max_slots = env::var("MAXSLOTS")
|
||||||
|
.context("MAXSLOTS not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid MAXSLOTS")?;
|
||||||
|
|
||||||
|
let cell_size = env::var("CELLSIZE")
|
||||||
|
.context("CELLSIZE not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid CELLSIZE")?;
|
||||||
|
|
||||||
|
let block_size = env::var("BLOCKSIZE")
|
||||||
|
.context("BLOCKSIZE not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid BLOCKSIZE")?;
|
||||||
|
|
||||||
|
let n_samples = env::var("NSAMPLES")
|
||||||
|
.context("NSAMPLES not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid NSAMPLES")?;
|
||||||
|
|
||||||
|
let entropy = env::var("ENTROPY")
|
||||||
|
.context("ENTROPY not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid ENTROPY")?;
|
||||||
|
|
||||||
|
let seed = env::var("SEED")
|
||||||
|
.context("SEED not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid SEED")?;
|
||||||
|
|
||||||
|
let n_slots = env::var("NSLOTS")
|
||||||
|
.context("NSLOTS not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid NSLOTS")?;
|
||||||
|
|
||||||
|
let testing_slot_index = env::var("SLOTINDEX")
|
||||||
|
.context("SLOTINDEX not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid SLOTINDEX")?;
|
||||||
|
|
||||||
|
let n_cells = env::var("NCELLS")
|
||||||
|
.context("NCELLS not set")?
|
||||||
|
.parse::<usize>()
|
||||||
|
.context("Invalid NCELLS")?;
|
||||||
|
|
||||||
|
Ok(Params {
|
||||||
|
max_depth,
|
||||||
|
max_slots,
|
||||||
|
cell_size,
|
||||||
|
block_size,
|
||||||
|
n_samples,
|
||||||
|
entropy,
|
||||||
|
seed,
|
||||||
|
n_slots,
|
||||||
|
testing_slot_index,
|
||||||
|
n_cells,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,26 +2,19 @@ use anyhow::Result;
|
||||||
use plonky2::field::extension::Extendable;
|
use plonky2::field::extension::Extendable;
|
||||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
use plonky2::hash::hash_types::{HashOut, HashOutTarget, RichField, NUM_HASH_OUT_ELTS};
|
use plonky2::hash::hash_types::{HashOut, HashOutTarget, NUM_HASH_OUT_ELTS, RichField};
|
||||||
use plonky2::hash::hashing::PlonkyPermutation;
|
use plonky2::hash::hashing::PlonkyPermutation;
|
||||||
use plonky2::hash::poseidon::PoseidonHash;
|
use plonky2::hash::poseidon::PoseidonHash;
|
||||||
use plonky2::iop::target::{BoolTarget, Target};
|
|
||||||
use plonky2::iop::witness::{PartialWitness, Witness, WitnessWrite};
|
use plonky2::iop::witness::{PartialWitness, Witness, WitnessWrite};
|
||||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitData};
|
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, GenericHashOut, Hasher, PoseidonGoldilocksConfig};
|
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, GenericHashOut, Hasher, PoseidonGoldilocksConfig};
|
||||||
use plonky2::plonk::proof::{Proof, ProofWithPublicInputs};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::os::macos::raw::stat;
|
|
||||||
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use crate::circuits::keyed_compress::key_compress_circuit;
|
|
||||||
use crate::circuits::params::HF;
|
|
||||||
use crate::circuits::merkle_circuit::{MerkleProofTarget, MerkleTreeCircuit, MerkleTreeTargets};
|
use crate::circuits::merkle_circuit::{MerkleProofTarget, MerkleTreeCircuit, MerkleTreeTargets};
|
||||||
use crate::circuits::utils::{add_assign_hash_out_target, assign_bool_targets, assign_hash_out_targets, mul_hash_out_target, usize_to_bits_le_padded};
|
use crate::circuits::utils::{assign_bool_targets, assign_hash_out_targets, usize_to_bits_le_padded};
|
||||||
|
|
||||||
use crate::merkle_tree::merkle_safe::MerkleTree;
|
use crate::merkle_tree::merkle_safe::MerkleTree;
|
||||||
use crate::merkle_tree::merkle_safe::{KEY_NONE,KEY_BOTTOM_LAYER};
|
|
||||||
|
|
||||||
/// the input to the merkle tree circuit
|
/// the input to the merkle tree circuit
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -115,7 +108,6 @@ pub fn assign_witness<
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::time::Instant;
|
|
||||||
use plonky2::hash::hash_types::HashOut;
|
use plonky2::hash::hash_types::HashOut;
|
||||||
use plonky2::hash::poseidon::PoseidonHash;
|
use plonky2::hash::poseidon::PoseidonHash;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -124,11 +116,8 @@ mod tests {
|
||||||
use plonky2::iop::witness::PartialWitness;
|
use plonky2::iop::witness::PartialWitness;
|
||||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||||
use crate::circuits::merkle_circuit::{MerkleTreeCircuit, };
|
|
||||||
use crate::circuits::sample_cells::{CircuitParams, DatasetTreeCircuit, SampleCircuitInput};
|
|
||||||
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;
|
use crate::merkle_tree::merkle_safe::MerkleTree;
|
||||||
use crate::proof_input::test_params::{D, C, F, H, N_SLOTS, MAX_DEPTH};
|
|
||||||
|
|
||||||
// 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
|
||||||
// will be fixed later, but for that test check the prove_single_cell tests
|
// will be fixed later, but for that test check the prove_single_cell tests
|
||||||
|
|
Loading…
Reference in New Issue