Skip to content

Commit

Permalink
[WIP] feat: implement record circuit
Browse files Browse the repository at this point in the history
  • Loading branch information
Insun35 committed Aug 7, 2024
1 parent 25d5e4c commit f34c61f
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 0 deletions.
3 changes: 3 additions & 0 deletions verifiable-db/src/results_tree/extraction/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pub(crate) mod public_inputs;
pub(crate) mod record;

use public_inputs::PublicInputs;
180 changes: 180 additions & 0 deletions verifiable-db/src/results_tree/extraction/record.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use crate::results_tree::extraction::PublicInputs;
use alloy::primitives::U256;
use mp2_common::{
group_hashing::CircuitBuilderGroupHashing,
poseidon::{empty_poseidon_hash, H},
public_inputs::PublicInputCommon,
serialization::{deserialize, deserialize_long_array, serialize, serialize_long_array},
types::CBuilder,
u256::{CircuitBuilderU256, UInt256Target, WitnessWriteU256},
utils::{SelectHashBuilder, ToTargets},
D, F,
};
use plonky2::{
hash::hash_types::{HashOut, HashOutTarget},
iop::{
target::{BoolTarget, Target},
witness::{PartialWitness, WitnessWrite},
},
plonk::proof::ProofWithPublicInputsTarget,
};
use recursion_framework::circuit_builder::CircuitLogicWires;
use serde::{Deserialize, Serialize};
use std::iter;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RecordWires<const MAX_NUM_RESULTS: usize> {
#[serde(
serialize_with = "serialize_long_array",
deserialize_with = "deserialize_long_array"
)]
indexed_items: [UInt256Target; MAX_NUM_RESULTS],
#[serde(
serialize_with = "serialize_long_array",
deserialize_with = "deserialize_long_array"
)]
index_ids: [Target; MAX_NUM_RESULTS],
#[serde(serialize_with = "serialize", deserialize_with = "deserialize")]
tree_hash: HashOutTarget,
counter: UInt256Target,
#[serde(serialize_with = "serialize", deserialize_with = "deserialize")]
is_stored_in_leaf: BoolTarget,
offset_range_min: UInt256Target,
offset_range_max: UInt256Target,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RecordCircuit<const MAX_NUM_RESULTS: usize> {
// TODO(Insun35): add comments
#[serde(
serialize_with = "serialize_long_array",
deserialize_with = "deserialize_long_array"
)]
pub(crate) indexed_items: [U256; MAX_NUM_RESULTS],
#[serde(
serialize_with = "serialize_long_array",
deserialize_with = "deserialize_long_array"
)]
pub(crate) index_ids: [F; MAX_NUM_RESULTS],
pub(crate) tree_hash: HashOut<F>,
pub(crate) counter: U256,
pub(crate) is_stored_in_leaf: bool,
/// Minimum offset range bound
pub(crate) offset_range_min: U256,
/// Maximum offset range bound
pub(crate) offset_range_max: U256,
}

impl<const MAX_NUM_RESULTS: usize> RecordCircuit<MAX_NUM_RESULTS> {
pub fn build(b: &mut CBuilder) -> RecordWires<MAX_NUM_RESULTS> {
let ffalse = b._false();
let empty_hash = b.constant_hash(*empty_poseidon_hash());

let indexed_items: [UInt256Target; MAX_NUM_RESULTS] = b.add_virtual_u256_arr_unsafe();
let index_ids: [Target; MAX_NUM_RESULTS] = b.add_virtual_target_arr();
let mut tree_hash = b.add_virtual_hash();
let counter = b.add_virtual_u256_unsafe();
let is_stored_in_leaf = b.add_virtual_bool_target_safe();
let offset_range_min = b.add_virtual_u256_unsafe();
let offset_range_max = b.add_virtual_u256_unsafe();

// H(H("")||H("")||indexed_items[1]||indexed_items[1]||index_ids[1]||indexed_items[1]||tree_hash)
let tree_hash_inputs = empty_hash
.elements
.iter()
.cloned()
.chain(empty_hash.elements)
.chain(indexed_items[1].to_targets())
.chain(indexed_items[1].to_targets())
.chain(iter::once(index_ids[1]))
.chain(indexed_items[1].to_targets())
.chain(tree_hash.elements)
.collect();
let new_tree_hash = b.hash_n_to_hash_no_pad::<H>(tree_hash_inputs);
tree_hash = b.select_hash(is_stored_in_leaf, &new_tree_hash, &tree_hash);

// D(index_ids[0]||indexed_items[0]||index_ids[1]||indexed_items[1]||tree_hash)
let accumulator_inputs: Vec<_> = iter::once(index_ids[0])
.chain(indexed_items[0].to_targets())
.chain(iter::once(index_ids[1]))
.chain(indexed_items[1].to_targets())
.chain(tree_hash.to_targets())
.collect();
let accumulator = b.map_to_curve_point(&accumulator_inputs);

// Ensure the counter associated to the current record is in the range
// specified by the query
// offset_range_min <= counter <= offset_range_max
// -> NOT((counter < offset_range_min) OR (counter > offset_range_max)
let is_less_than = b.is_less_than_u256(&counter, &offset_range_min);
let is_greater_than = b.is_greater_than_u256(&counter, &offset_range_max);
let is_out_of_range = b.or(is_less_than, is_greater_than);
b.connect(is_out_of_range.target, ffalse.target);

// Register the public inputs.
PublicInputs::<_, MAX_NUM_RESULTS>::new(
&tree_hash.to_targets(),
&indexed_items[1].to_targets(),
&indexed_items[1].to_targets(),
&indexed_items[0].to_targets(),
&index_ids,
&counter.to_targets(),
&counter.to_targets(),
&offset_range_min.to_targets(),
&offset_range_max.to_targets(),
&accumulator.to_targets(),
)
.register(b);

RecordWires {
indexed_items,
index_ids,
tree_hash,
counter,
is_stored_in_leaf,
offset_range_min,
offset_range_max,
}
}

fn assign(&self, pw: &mut PartialWitness<F>, wires: &RecordWires<MAX_NUM_RESULTS>) {
wires
.indexed_items
.iter()
.zip(self.indexed_items)
.for_each(|(t, v)| pw.set_u256_target(t, v));
pw.set_target_arr(&wires.index_ids, &self.index_ids);
pw.set_hash_target(wires.tree_hash, self.tree_hash);
pw.set_u256_target(&wires.counter, self.counter);
pw.set_bool_target(wires.is_stored_in_leaf, self.is_stored_in_leaf);
pw.set_u256_target(&wires.offset_range_min, self.offset_range_min);
pw.set_u256_target(&wires.offset_range_max, self.offset_range_max);
}
}

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

impl<const MAX_NUM_RESULTS: usize> CircuitLogicWires<F, D, NUM_VERIFIED_PROOFS>
for RecordWires<MAX_NUM_RESULTS>
{
type CircuitBuilderParams = ();
type Inputs = RecordCircuit<MAX_NUM_RESULTS>;

const NUM_PUBLIC_INPUTS: usize = PublicInputs::<F, MAX_NUM_RESULTS>::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(())
}
}

// TODO(Insun35): Add test

0 comments on commit f34c61f

Please sign in to comment.