From 1c424f70e380f31747bfcd3011b4b93d0b6d2f7a Mon Sep 17 00:00:00 2001 From: Insun35 Date: Wed, 14 Aug 2024 15:44:45 +0900 Subject: [PATCH] feat: implement circuit for no results in chunck --- .../src/results_tree/extraction/mod.rs | 1 + .../extraction/no_results_in_chunk.rs | 191 ++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 verifiable-db/src/results_tree/extraction/no_results_in_chunk.rs diff --git a/verifiable-db/src/results_tree/extraction/mod.rs b/verifiable-db/src/results_tree/extraction/mod.rs index cc5429add..d4e5e8e6c 100644 --- a/verifiable-db/src/results_tree/extraction/mod.rs +++ b/verifiable-db/src/results_tree/extraction/mod.rs @@ -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; diff --git a/verifiable-db/src/results_tree/extraction/no_results_in_chunk.rs b/verifiable-db/src/results_tree/extraction/no_results_in_chunk.rs new file mode 100644 index 000000000..027e822bf --- /dev/null +++ b/verifiable-db/src/results_tree/extraction/no_results_in_chunk.rs @@ -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, + /// 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, 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 for NoResultsInChunkWires { + type CircuitBuilderParams = (); + type Inputs = NoResultsInChunkCircuit; + + const NUM_PUBLIC_INPUTS: usize = PublicInputs::::total_len(); + + fn circuit_logic( + builder: &mut CBuilder, + _verified_proofs: [&ProofWithPublicInputsTarget; NUM_VERIFIED_PROOFS], + _builder_parameters: Self::CircuitBuilderParams, + ) -> Self { + Self::Inputs::build(builder) + } + + fn assign_input(&self, inputs: Self::Inputs, pw: &mut PartialWitness) -> 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 for NoResultsInChunkCircuit { + type Wires = NoResultsInChunkWires; + + fn build(b: &mut CBuilder) -> Self::Wires { + NoResultsInChunkCircuit::build(b) + } + + fn prove(&self, pw: &mut PartialWitness, 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::(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); + } +}