Skip to content

Commit

Permalink
feat: implement circuit for no results in chunck
Browse files Browse the repository at this point in the history
  • Loading branch information
Insun35 committed Aug 14, 2024
1 parent 5b1f8de commit 1c424f7
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 0 deletions.
1 change: 1 addition & 0 deletions verifiable-db/src/results_tree/extraction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use public_inputs::PublicInputs;
pub(crate) mod child_included_single_path_node;
pub(crate) mod full_node;
pub(crate) mod no_child_included_single_path_node;
pub(crate) mod no_results_in_chunk;
pub(crate) mod partial_node;
pub(crate) mod public_inputs;
pub(crate) mod record;
Expand Down
191 changes: 191 additions & 0 deletions verifiable-db/src/results_tree/extraction/no_results_in_chunk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
use crate::results_tree::extraction::PublicInputs;
use alloy::primitives::U256;
use mp2_common::{
public_inputs::PublicInputCommon,
serialization::{deserialize, serialize},
types::CBuilder,
u256::CircuitBuilderU256,
utils::{greater_than, ToTargets},
D, F,
};
use plonky2::{
hash::hash_types::{HashOut, HashOutTarget},
iop::{
target::Target,
witness::{PartialWitness, WitnessWrite},
},
plonk::proof::ProofWithPublicInputsTarget,
};
use plonky2_ecgfp5::gadgets::curve::CircuitBuilderEcGFp5;
use recursion_framework::circuit_builder::CircuitLogicWires;
use serde::{Deserialize, Serialize};
use std::iter;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NoResultsInChunkWires {
num_records: Target,
#[serde(serialize_with = "serialize", deserialize_with = "deserialize")]
results_tree_hash: HashOutTarget,
offset_range_min: Target,
offset_range_max: Target,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NoResultsInChunkCircuit {
/// Number of records in the results tree
pub(crate) num_records: F,
/// Hash of the results tree
pub(crate) results_tree_hash: HashOut<F>,
/// Minimum offset range bound
pub(crate) offset_range_min: F,
/// Maximum offset range bound
pub(crate) offset_range_max: F,
}

impl NoResultsInChunkCircuit {
pub fn build(b: &mut CBuilder) -> NoResultsInChunkWires {
let zero_u256 = b.zero_u256();
let curve_zero = b.curve_zero();
let one = b.one();
let ttrue = b._true();

let num_records = b.add_virtual_target();
let results_tree_hash = b.add_virtual_hash();
let [offset_range_min, offset_range_max] = b.add_virtual_target_arr();

// Ensure that the query is asking to retrieve results with an offset
// being greater than the overall number of results
let is_greater = greater_than(b, offset_range_min, num_records, 32);
b.connect(is_greater.target, ttrue.target);

// Register the public inputs.
PublicInputs::new(
&results_tree_hash.to_targets(),
&zero_u256.to_targets(),
&zero_u256.to_targets(),
&zero_u256.to_targets(),
&[one; 2],
&[one],
&[num_records],
&[offset_range_min],
&[offset_range_max],
&curve_zero.to_targets(),
)
.register(b);

NoResultsInChunkWires {
num_records,
results_tree_hash,
offset_range_min,
offset_range_max,
}
}

fn assign(&self, pw: &mut PartialWitness<F>, wires: &NoResultsInChunkWires) {
pw.set_target(wires.num_records, self.num_records);
pw.set_hash_target(wires.results_tree_hash, self.results_tree_hash);
pw.set_target(wires.offset_range_min, self.offset_range_min);
pw.set_target(wires.offset_range_max, self.offset_range_max);
}
}

/// Verified proof number = 0
pub(crate) const NUM_VERIFIED_PROOFS: usize = 0;

impl CircuitLogicWires<F, D, NUM_VERIFIED_PROOFS> for NoResultsInChunkWires {
type CircuitBuilderParams = ();
type Inputs = NoResultsInChunkCircuit;

const NUM_PUBLIC_INPUTS: usize = PublicInputs::<F>::total_len();

fn circuit_logic(
builder: &mut CBuilder,
_verified_proofs: [&ProofWithPublicInputsTarget<D>; NUM_VERIFIED_PROOFS],
_builder_parameters: Self::CircuitBuilderParams,
) -> Self {
Self::Inputs::build(builder)
}

fn assign_input(&self, inputs: Self::Inputs, pw: &mut PartialWitness<F>) -> anyhow::Result<()> {
inputs.assign(pw, self);
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;
use mp2_common::C;
use mp2_test::{
circuit::{run_circuit, UserCircuit},
utils::gen_random_field_hash,
};
use plonky2::field::types::Field;
use plonky2_ecgfp5::curve::curve::WeierstrassPoint;
use rand::{thread_rng, Rng};

impl UserCircuit<F, D> for NoResultsInChunkCircuit {
type Wires = NoResultsInChunkWires;

fn build(b: &mut CBuilder) -> Self::Wires {
NoResultsInChunkCircuit::build(b)
}

fn prove(&self, pw: &mut PartialWitness<F>, wires: &Self::Wires) {
self.assign(pw, wires);
}
}

#[test]
fn test_no_results_in_chunk_circuit() {
// Construct the witness.
let mut rng = thread_rng();
let num_records = F::from_canonical_u32(rng.gen());
let results_tree_hash = gen_random_field_hash();
let offset_range_min = num_records + F::ONE;
let offset_range_max = offset_range_min + F::from_canonical_u32(rng.gen());

// Construct the circuit.
let test_circuit = NoResultsInChunkCircuit {
num_records,
results_tree_hash,
offset_range_min,
offset_range_max,
};

// Proof for the test circuit.
let proof = run_circuit::<F, D, C, _>(test_circuit);
let pi = PublicInputs::from_slice(&proof.public_inputs);

// Check the public inputs.
// Tree hash
assert_eq!(pi.tree_hash(), results_tree_hash);

// Min value
assert_eq!(pi.min_value(), U256::ZERO);

// Max value
assert_eq!(pi.max_value(), U256::ZERO);

// Primary index value
assert_eq!(pi.primary_index_value(), U256::ZERO);

// Index ids
assert_eq!(pi.index_ids(), [F::ONE; 2]);

// Min counter
assert_eq!(pi.min_counter(), F::ONE);

// Max counter
assert_eq!(pi.max_counter(), num_records);

// Offset range min
assert_eq!(pi.offset_range_min(), offset_range_min);

// Offset range max
assert_eq!(pi.offset_range_max(), offset_range_max);

// Accumulator
assert_eq!(pi.accumulator(), WeierstrassPoint::NEUTRAL);
}
}

0 comments on commit 1c424f7

Please sign in to comment.