Integrate recursion into MainPod (#243)
* calculate MainPod id in a dynamic-friendly way The MainPod id is now calculated with front padding and a fixed size independent of max_public_statements so that introduction gadgets can be verified by a MainPod while paying only for the number of statements they use. This is because with front padding of none-statements we can precompute the poseidon state corresponding to absorbing all the padding statements and only pay constraints for the non-padding statements. The id is calculated as follows: `id = hash(serialize(reverse(statements || none-statements)))` * add time feature and disable timing by default * apply suggestions from @arnaucube * link issues in todos
This commit is contained in:
parent
d3fef8392e
commit
88a75986b8
23 changed files with 1405 additions and 729 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -22,4 +22,6 @@ jobs:
|
||||||
run: cargo build
|
run: cargo build
|
||||||
- name: Build metrics
|
- name: Build metrics
|
||||||
run: cargo build --features metrics
|
run: cargo build --features metrics
|
||||||
|
- name: Build time
|
||||||
|
run: cargo build --features time
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,3 +39,4 @@ jsonschema = "0.30.0"
|
||||||
default = ["backend_plonky2"]
|
default = ["backend_plonky2"]
|
||||||
backend_plonky2 = ["plonky2"]
|
backend_plonky2 = ["plonky2"]
|
||||||
metrics = []
|
metrics = []
|
||||||
|
time = []
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
//! This file exposes the middleware::basetypes to be used in the middleware when the
|
//! This file exposes the basetypes to be used in the middleware when the `backend_plonky2` feature
|
||||||
//! `backend_plonky2` feature is enabled.
|
//! is enabled.
|
||||||
//! See src/middleware/basetypes.rs for more details.
|
//! See src/middleware/basetypes.rs for more details.
|
||||||
|
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::extension::quadratic::QuadraticExtension,
|
field::{extension::quadratic::QuadraticExtension, goldilocks_field::GoldilocksField},
|
||||||
hash::poseidon::PoseidonHash,
|
hash::poseidon::PoseidonHash,
|
||||||
plonk::{config::GenericConfig, proof::Proof as Plonky2Proof},
|
plonk::{circuit_builder, circuit_data, config::GenericConfig, proof},
|
||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::middleware::F;
|
/// F is the native field we use everywhere. Currently it's Goldilocks from plonky2
|
||||||
|
pub type F = GoldilocksField;
|
||||||
|
|
||||||
/// D defines the extension degree of the field used in the Plonky2 proofs (quadratic extension).
|
/// D defines the extension degree of the field used in the Plonky2 proofs (quadratic extension).
|
||||||
pub const D: usize = 2;
|
pub const D: usize = 2;
|
||||||
|
|
@ -27,5 +28,11 @@ impl GenericConfig<D> for C {
|
||||||
type InnerHasher = PoseidonHash;
|
type InnerHasher = PoseidonHash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// proof system proof
|
pub type CircuitData = circuit_data::CircuitData<F, C, D>;
|
||||||
pub type Proof = Plonky2Proof<F, C, D>;
|
pub type CommonCircuitData = circuit_data::CommonCircuitData<F, D>;
|
||||||
|
pub type ProverOnlyCircuitData = circuit_data::ProverOnlyCircuitData<F, C, D>;
|
||||||
|
pub type VerifierOnlyCircuitData = circuit_data::VerifierOnlyCircuitData<C, D>;
|
||||||
|
pub type VerifierCircuitData = circuit_data::VerifierCircuitData<F, C, D>;
|
||||||
|
pub type CircuitBuilder = circuit_builder::CircuitBuilder<F, D>;
|
||||||
|
pub type Proof = proof::Proof<F, C, D>;
|
||||||
|
pub type ProofWithPublicInputs = proof::ProofWithPublicInputs<F, C, D>;
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,12 @@ use plonky2::{
|
||||||
target::{BoolTarget, Target},
|
target::{BoolTarget, Target},
|
||||||
witness::{PartialWitness, PartitionWitness, Witness, WitnessWrite},
|
witness::{PartialWitness, PartitionWitness, Witness, WitnessWrite},
|
||||||
},
|
},
|
||||||
plonk::{circuit_builder::CircuitBuilder, circuit_data::CommonCircuitData},
|
|
||||||
util::serialization::{Buffer, IoResult, Read, Write},
|
util::serialization::{Buffer, IoResult, Read, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::D,
|
basetypes::{CircuitBuilder, CommonCircuitData, D},
|
||||||
circuits::mainpod::CustomPredicateVerification,
|
circuits::mainpod::CustomPredicateVerification,
|
||||||
error::Result,
|
error::Result,
|
||||||
mainpod::{Operation, OperationArg, Statement},
|
mainpod::{Operation, OperationArg, Statement},
|
||||||
|
|
@ -47,13 +46,13 @@ pub struct ValueTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueTarget {
|
impl ValueTarget {
|
||||||
pub fn zero(builder: &mut CircuitBuilder<F, D>) -> Self {
|
pub fn zero(builder: &mut CircuitBuilder) -> Self {
|
||||||
Self {
|
Self {
|
||||||
elements: [builder.zero(); VALUE_SIZE],
|
elements: [builder.zero(); VALUE_SIZE],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn one(builder: &mut CircuitBuilder<F, D>) -> Self {
|
pub fn one(builder: &mut CircuitBuilder) -> Self {
|
||||||
Self {
|
Self {
|
||||||
elements: array::from_fn(|i| {
|
elements: array::from_fn(|i| {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
|
@ -99,25 +98,25 @@ impl StatementArgTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn none(builder: &mut CircuitBuilder<F, D>) -> Self {
|
pub fn none(builder: &mut CircuitBuilder) -> Self {
|
||||||
let empty = builder.constant_value(EMPTY_VALUE);
|
let empty = builder.constant_value(EMPTY_VALUE);
|
||||||
Self::new(empty, empty)
|
Self::new(empty, empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn literal(builder: &mut CircuitBuilder<F, D>, value: &ValueTarget) -> Self {
|
pub fn literal(builder: &mut CircuitBuilder, value: &ValueTarget) -> Self {
|
||||||
let empty = builder.constant_value(EMPTY_VALUE);
|
let empty = builder.constant_value(EMPTY_VALUE);
|
||||||
Self::new(*value, empty)
|
Self::new(*value, empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn anchored_key(
|
pub fn anchored_key(
|
||||||
_builder: &mut CircuitBuilder<F, D>,
|
_builder: &mut CircuitBuilder,
|
||||||
pod_id: &ValueTarget,
|
pod_id: &ValueTarget,
|
||||||
key: &ValueTarget,
|
key: &ValueTarget,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self::new(*pod_id, *key)
|
Self::new(*pod_id, *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wildcard_literal(builder: &mut CircuitBuilder<F, D>, value: &ValueTarget) -> Self {
|
pub fn wildcard_literal(builder: &mut CircuitBuilder, value: &ValueTarget) -> Self {
|
||||||
let empty = builder.constant_value(EMPTY_VALUE);
|
let empty = builder.constant_value(EMPTY_VALUE);
|
||||||
Self::new(*value, empty)
|
Self::new(*value, empty)
|
||||||
}
|
}
|
||||||
|
|
@ -137,17 +136,17 @@ pub struct StatementTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Build<T> {
|
pub trait Build<T> {
|
||||||
fn build(self, builder: &mut CircuitBuilder<F, D>, params: &Params) -> T;
|
fn build(self, builder: &mut CircuitBuilder, params: &Params) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Build<NativePredicateTarget> for NativePredicate {
|
impl Build<NativePredicateTarget> for NativePredicate {
|
||||||
fn build(self, builder: &mut CircuitBuilder<F, D>, params: &Params) -> NativePredicateTarget {
|
fn build(self, builder: &mut CircuitBuilder, params: &Params) -> NativePredicateTarget {
|
||||||
NativePredicateTarget::constant(builder, params, self)
|
NativePredicateTarget::constant(builder, params, self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Build<T> for T {
|
impl<T> Build<T> for T {
|
||||||
fn build(self, _builder: &mut CircuitBuilder<F, D>, _params: &Params) -> T {
|
fn build(self, _builder: &mut CircuitBuilder, _params: &Params) -> T {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +154,7 @@ impl<T> Build<T> for T {
|
||||||
impl StatementTarget {
|
impl StatementTarget {
|
||||||
/// Build a new native StatementTarget. Pads the arguments.
|
/// Build a new native StatementTarget. Pads the arguments.
|
||||||
pub fn new_native(
|
pub fn new_native(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
native_predicate: impl Build<NativePredicateTarget>,
|
native_predicate: impl Build<NativePredicateTarget>,
|
||||||
args: &[StatementArgTarget],
|
args: &[StatementArgTarget],
|
||||||
|
|
@ -194,7 +193,7 @@ impl StatementTarget {
|
||||||
|
|
||||||
pub fn has_native_type(
|
pub fn has_native_type(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
t: NativePredicate,
|
t: NativePredicate,
|
||||||
) -> BoolTarget {
|
) -> BoolTarget {
|
||||||
|
|
@ -210,7 +209,7 @@ pub struct OperationTypeTarget {
|
||||||
|
|
||||||
impl OperationTypeTarget {
|
impl OperationTypeTarget {
|
||||||
pub fn new_custom(
|
pub fn new_custom(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
batch_id: HashOutTarget,
|
batch_id: HashOutTarget,
|
||||||
index: Target,
|
index: Target,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -222,10 +221,7 @@ impl OperationTypeTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_custom(
|
pub fn as_custom(&self, builder: &mut CircuitBuilder) -> (BoolTarget, HashOutTarget, Target) {
|
||||||
&self,
|
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
|
||||||
) -> (BoolTarget, HashOutTarget, Target) {
|
|
||||||
// TODO: Use an enum for these prefixes
|
// TODO: Use an enum for these prefixes
|
||||||
let three = builder.constant(F::from_canonical_usize(3));
|
let three = builder.constant(F::from_canonical_usize(3));
|
||||||
let op_is_custom = builder.is_equal(self.elements[0], three);
|
let op_is_custom = builder.is_equal(self.elements[0], three);
|
||||||
|
|
@ -234,7 +230,7 @@ impl OperationTypeTarget {
|
||||||
(op_is_custom, batch_id, index)
|
(op_is_custom, batch_id, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_native(&self, builder: &mut CircuitBuilder<F, D>, t: NativeOperation) -> BoolTarget {
|
pub fn has_native(&self, builder: &mut CircuitBuilder, t: NativeOperation) -> BoolTarget {
|
||||||
// TODO: Use an enum for these prefixes
|
// TODO: Use an enum for these prefixes
|
||||||
let one = builder.one();
|
let one = builder.one();
|
||||||
let op_is_native = builder.is_equal(self.elements[0], one);
|
let op_is_native = builder.is_equal(self.elements[0], one);
|
||||||
|
|
@ -288,7 +284,7 @@ pub struct NativePredicateTarget(Target);
|
||||||
|
|
||||||
impl NativePredicateTarget {
|
impl NativePredicateTarget {
|
||||||
pub fn constant(
|
pub fn constant(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
native_predicate: NativePredicate,
|
native_predicate: NativePredicate,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -316,7 +312,7 @@ pub struct PredicateTarget {
|
||||||
|
|
||||||
impl PredicateTarget {
|
impl PredicateTarget {
|
||||||
pub fn new_native(
|
pub fn new_native(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
native_predicate: impl Build<NativePredicateTarget>,
|
native_predicate: impl Build<NativePredicateTarget>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -328,7 +324,7 @@ impl PredicateTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_batch_self(builder: &mut CircuitBuilder<F, D>, index: Target) -> Self {
|
pub fn new_batch_self(builder: &mut CircuitBuilder, index: Target) -> Self {
|
||||||
let prefix = builder.constant(F::from(PredicatePrefix::BatchSelf));
|
let prefix = builder.constant(F::from(PredicatePrefix::BatchSelf));
|
||||||
let zero = builder.zero();
|
let zero = builder.zero();
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -337,7 +333,7 @@ impl PredicateTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_custom(
|
pub fn new_custom(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
batch_id: HashOutTarget,
|
batch_id: HashOutTarget,
|
||||||
index: Target,
|
index: Target,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
|
@ -373,7 +369,7 @@ impl LiteralOrWildcardTarget {
|
||||||
/// cases: ((is_key, key), (is_wildcard, wildcard_index))
|
/// cases: ((is_key, key), (is_wildcard, wildcard_index))
|
||||||
pub fn cases(
|
pub fn cases(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
) -> ((BoolTarget, ValueTarget), (BoolTarget, Target)) {
|
) -> ((BoolTarget, ValueTarget), (BoolTarget, Target)) {
|
||||||
let zero = builder.zero();
|
let zero = builder.zero();
|
||||||
let is_zero_tail: Vec<_> = (1..4)
|
let is_zero_tail: Vec<_> = (1..4)
|
||||||
|
|
@ -397,12 +393,12 @@ pub struct StatementTmplArgTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatementTmplArgTarget {
|
impl StatementTmplArgTarget {
|
||||||
pub fn as_none(&self, builder: &mut CircuitBuilder<F, D>) -> BoolTarget {
|
pub fn as_none(&self, builder: &mut CircuitBuilder) -> BoolTarget {
|
||||||
let prefix = builder.constant(F::from(StatementTmplArgPrefix::None));
|
let prefix = builder.constant(F::from(StatementTmplArgPrefix::None));
|
||||||
builder.is_equal(self.elements[0], prefix)
|
builder.is_equal(self.elements[0], prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_literal(&self, builder: &mut CircuitBuilder<F, D>) -> (BoolTarget, ValueTarget) {
|
pub fn as_literal(&self, builder: &mut CircuitBuilder) -> (BoolTarget, ValueTarget) {
|
||||||
let prefix = builder.constant(F::from(StatementTmplArgPrefix::Literal));
|
let prefix = builder.constant(F::from(StatementTmplArgPrefix::Literal));
|
||||||
let case_ok = builder.is_equal(self.elements[0], prefix);
|
let case_ok = builder.is_equal(self.elements[0], prefix);
|
||||||
let value = ValueTarget::from_slice(&self.elements[1..5]);
|
let value = ValueTarget::from_slice(&self.elements[1..5]);
|
||||||
|
|
@ -411,7 +407,7 @@ impl StatementTmplArgTarget {
|
||||||
|
|
||||||
pub fn as_anchored_key(
|
pub fn as_anchored_key(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
) -> (BoolTarget, Target, LiteralOrWildcardTarget) {
|
) -> (BoolTarget, Target, LiteralOrWildcardTarget) {
|
||||||
let prefix = builder.constant(F::from(StatementTmplArgPrefix::AnchoredKey));
|
let prefix = builder.constant(F::from(StatementTmplArgPrefix::AnchoredKey));
|
||||||
let case_ok = builder.is_equal(self.elements[0], prefix);
|
let case_ok = builder.is_equal(self.elements[0], prefix);
|
||||||
|
|
@ -420,7 +416,7 @@ impl StatementTmplArgTarget {
|
||||||
(case_ok, id_wildcard_index, value_key_or_wildcard)
|
(case_ok, id_wildcard_index, value_key_or_wildcard)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_wildcard_literal(&self, builder: &mut CircuitBuilder<F, D>) -> (BoolTarget, Target) {
|
pub fn as_wildcard_literal(&self, builder: &mut CircuitBuilder) -> (BoolTarget, Target) {
|
||||||
let prefix = builder.constant(F::from(StatementTmplArgPrefix::WildcardLiteral));
|
let prefix = builder.constant(F::from(StatementTmplArgPrefix::WildcardLiteral));
|
||||||
let case_ok = builder.is_equal(self.elements[0], prefix);
|
let case_ok = builder.is_equal(self.elements[0], prefix);
|
||||||
let wildcard_index = self.elements[1];
|
let wildcard_index = self.elements[1];
|
||||||
|
|
@ -479,7 +475,7 @@ pub struct CustomPredicateBatchTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomPredicateBatchTarget {
|
impl CustomPredicateBatchTarget {
|
||||||
pub fn id(&self, builder: &mut CircuitBuilder<F, D>) -> HashOutTarget {
|
pub fn id(&self, builder: &mut CircuitBuilder) -> HashOutTarget {
|
||||||
let flattened = self.predicates.iter().flat_map(|cp| cp.flatten()).collect();
|
let flattened = self.predicates.iter().flat_map(|cp| cp.flatten()).collect();
|
||||||
builder.hash_n_to_hash_no_pad::<PoseidonHash>(flattened)
|
builder.hash_n_to_hash_no_pad::<PoseidonHash>(flattened)
|
||||||
}
|
}
|
||||||
|
|
@ -573,7 +569,7 @@ impl Flattenable for CustomPredicateEntryTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomPredicateEntryTarget {
|
impl CustomPredicateEntryTarget {
|
||||||
pub fn hash(&self, builder: &mut CircuitBuilder<F, D>) -> HashOutTarget {
|
pub fn hash(&self, builder: &mut CircuitBuilder) -> HashOutTarget {
|
||||||
builder.hash_n_to_hash_no_pad::<PoseidonHash>(self.flatten())
|
builder.hash_n_to_hash_no_pad::<PoseidonHash>(self.flatten())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -630,7 +626,7 @@ pub struct CustomPredicateVerifyQueryTarget {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomPredicateVerifyQueryTarget {
|
impl CustomPredicateVerifyQueryTarget {
|
||||||
pub fn hash(&self, builder: &mut CircuitBuilder<F, D>) -> HashOutTarget {
|
pub fn hash(&self, builder: &mut CircuitBuilder) -> HashOutTarget {
|
||||||
builder.hash_n_to_hash_no_pad::<PoseidonHash>(self.flatten())
|
builder.hash_n_to_hash_no_pad::<PoseidonHash>(self.flatten())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -930,7 +926,7 @@ pub trait CircuitBuilderPod<F: RichField + Extendable<D>, const D: usize> {
|
||||||
fn lt_mask(&mut self, len: usize, n: Target) -> Vec<BoolTarget>;
|
fn lt_mask(&mut self, len: usize, n: Target) -> Vec<BoolTarget>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CircuitBuilderPod<F, D> for CircuitBuilder<F, D> {
|
impl CircuitBuilderPod<F, D> for CircuitBuilder {
|
||||||
fn connect_slice(&mut self, xs: &[Target], ys: &[Target]) {
|
fn connect_slice(&mut self, xs: &[Target], ys: &[Target]) {
|
||||||
assert_eq!(xs.len(), ys.len());
|
assert_eq!(xs.len(), ys.len());
|
||||||
for (x, y) in xs.iter().zip(ys.iter()) {
|
for (x, y) in xs.iter().zip(ys.iter()) {
|
||||||
|
|
@ -1267,11 +1263,11 @@ impl CircuitBuilderPod<F, D> for CircuitBuilder<F, D> {
|
||||||
// then do `ts: &[HashCache<T>]`.
|
// then do `ts: &[HashCache<T>]`.
|
||||||
fn vec_ref<T: Flattenable>(&mut self, params: &Params, ts: &[T], i: Target) -> T {
|
fn vec_ref<T: Flattenable>(&mut self, params: &Params, ts: &[T], i: Target) -> T {
|
||||||
// TODO: Revisit this when we need more than 64 statements.
|
// TODO: Revisit this when we need more than 64 statements.
|
||||||
let vector_ref = |builder: &mut CircuitBuilder<F, D>, v: &[Target], i| {
|
let vector_ref = |builder: &mut CircuitBuilder, v: &[Target], i| {
|
||||||
assert!(v.len() <= 64);
|
assert!(v.len() <= 64);
|
||||||
builder.random_access(i, v.to_vec())
|
builder.random_access(i, v.to_vec())
|
||||||
};
|
};
|
||||||
let matrix_row_ref = |builder: &mut CircuitBuilder<F, D>, m: &[Vec<Target>], i| {
|
let matrix_row_ref = |builder: &mut CircuitBuilder, m: &[Vec<Target>], i| {
|
||||||
let num_rows = m.len();
|
let num_rows = m.len();
|
||||||
let num_columns = m
|
let num_columns = m
|
||||||
.first()
|
.first()
|
||||||
|
|
@ -1367,7 +1363,7 @@ pub struct LtMaskGenerator {
|
||||||
pub(crate) mask: Vec<Target>,
|
pub(crate) mask: Vec<Target>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D> for LtMaskGenerator {
|
impl SimpleGenerator<F, D> for LtMaskGenerator {
|
||||||
fn id(&self) -> String {
|
fn id(&self) -> String {
|
||||||
"LtMaskGenerator".to_string()
|
"LtMaskGenerator".to_string()
|
||||||
}
|
}
|
||||||
|
|
@ -1390,12 +1386,12 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F, D> for LtM
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize(&self, dst: &mut Vec<u8>, _common_data: &CommonCircuitData<F, D>) -> IoResult<()> {
|
fn serialize(&self, dst: &mut Vec<u8>, _common_data: &CommonCircuitData) -> IoResult<()> {
|
||||||
dst.write_target(self.n)?;
|
dst.write_target(self.n)?;
|
||||||
dst.write_target_vec(&self.mask)
|
dst.write_target_vec(&self.mask)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData<F, D>) -> IoResult<Self> {
|
fn deserialize(src: &mut Buffer, _common_data: &CommonCircuitData) -> IoResult<Self> {
|
||||||
let n = src.read_target()?;
|
let n = src.read_target()?;
|
||||||
let mask = src.read_target_vec()?;
|
let mask = src.read_target_vec()?;
|
||||||
Ok(Self { n, mask })
|
Ok(Self { n, mask })
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,14 @@ use plonky2::{
|
||||||
},
|
},
|
||||||
iop::{
|
iop::{
|
||||||
target::{BoolTarget, Target},
|
target::{BoolTarget, Target},
|
||||||
witness::PartialWitness,
|
witness::{PartialWitness, WitnessWrite},
|
||||||
},
|
},
|
||||||
plonk::{circuit_builder::CircuitBuilder, config::AlgebraicHasher},
|
plonk::config::AlgebraicHasher,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::D,
|
basetypes::CircuitBuilder,
|
||||||
circuits::{
|
circuits::{
|
||||||
common::{
|
common::{
|
||||||
CircuitBuilderPod, CustomPredicateBatchTarget, CustomPredicateEntryTarget,
|
CircuitBuilderPod, CustomPredicateBatchTarget, CustomPredicateEntryTarget,
|
||||||
|
|
@ -28,18 +28,21 @@ use crate::{
|
||||||
},
|
},
|
||||||
signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget},
|
signedpod::{SignedPodVerifyGadget, SignedPodVerifyTarget},
|
||||||
},
|
},
|
||||||
|
emptypod::EmptyPod,
|
||||||
error::Result,
|
error::Result,
|
||||||
mainpod::{self, pad_statement},
|
mainpod::{self, pad_statement},
|
||||||
primitives::merkletree::{
|
primitives::merkletree::{
|
||||||
MerkleClaimAndProof, MerkleClaimAndProofTarget, MerkleProofGadget,
|
MerkleClaimAndProof, MerkleClaimAndProofTarget, MerkleProofGadget,
|
||||||
},
|
},
|
||||||
|
recursion::{InnerCircuit, VerifiedProofTarget},
|
||||||
signedpod::SignedPod,
|
signedpod::SignedPod,
|
||||||
},
|
},
|
||||||
measure_gates_begin, measure_gates_end,
|
measure_gates_begin, measure_gates_end,
|
||||||
middleware::{
|
middleware::{
|
||||||
AnchoredKey, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, NativeOperation,
|
AnchoredKey, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Hash,
|
||||||
NativePredicate, Params, PodType, PredicatePrefix, Statement, StatementArg, ToFields,
|
NativeOperation, NativePredicate, Params, PodType, PredicatePrefix, Statement,
|
||||||
Value, WildcardValue, F, KEY_TYPE, SELF, VALUE_SIZE,
|
StatementArg, ToFields, Value, WildcardValue, EMPTY_VALUE, F, HASH_SIZE, KEY_TYPE, SELF,
|
||||||
|
VALUE_SIZE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -47,6 +50,13 @@ use crate::{
|
||||||
// MainPod verification
|
// MainPod verification
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/// Offset in public inputs where we store the pod id
|
||||||
|
pub const PI_OFFSET_ID: usize = 0;
|
||||||
|
/// Offset in public inputs where we store the verified data array root
|
||||||
|
pub const PI_OFFSET_VDSROOT: usize = 4;
|
||||||
|
|
||||||
|
pub const NUM_PUBLIC_INPUTS: usize = 8;
|
||||||
|
|
||||||
struct OperationVerifyGadget {
|
struct OperationVerifyGadget {
|
||||||
params: Params,
|
params: Params,
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +68,7 @@ impl OperationVerifyGadget {
|
||||||
/// argument.
|
/// argument.
|
||||||
fn first_n_args_as_values<const N: usize>(
|
fn first_n_args_as_values<const N: usize>(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
) -> (BoolTarget, [ValueTarget; N]) {
|
) -> (BoolTarget, [ValueTarget; N]) {
|
||||||
let arg_is_valueof = resolved_op_args[..N]
|
let arg_is_valueof = resolved_op_args[..N]
|
||||||
|
|
@ -80,7 +90,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval(
|
fn eval(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op: &OperationTarget,
|
op: &OperationTarget,
|
||||||
prev_statements: &[StatementTarget],
|
prev_statements: &[StatementTarget],
|
||||||
|
|
@ -212,7 +222,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_contains_from_entries(
|
fn eval_contains_from_entries(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_merkle_claim: MerkleClaimTarget,
|
resolved_merkle_claim: MerkleClaimTarget,
|
||||||
|
|
@ -260,7 +270,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_not_contains_from_entries(
|
fn eval_not_contains_from_entries(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_merkle_claim: MerkleClaimTarget,
|
resolved_merkle_claim: MerkleClaimTarget,
|
||||||
|
|
@ -306,7 +316,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_custom(
|
fn eval_custom(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_custom_pred_verification: HashOutTarget,
|
resolved_custom_pred_verification: HashOutTarget,
|
||||||
|
|
@ -331,7 +341,7 @@ impl OperationVerifyGadget {
|
||||||
/// NotEqualFromEntries.
|
/// NotEqualFromEntries.
|
||||||
fn eval_eq_neq_from_entries(
|
fn eval_eq_neq_from_entries(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -382,7 +392,7 @@ impl OperationVerifyGadget {
|
||||||
/// LtEqFromEntries.
|
/// LtEqFromEntries.
|
||||||
fn eval_lt_lteq_from_entries(
|
fn eval_lt_lteq_from_entries(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -451,7 +461,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_hash_of(
|
fn eval_hash_of(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -485,7 +495,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_sum_of(
|
fn eval_sum_of(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -524,7 +534,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_product_of(
|
fn eval_product_of(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -563,7 +573,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_max_of(
|
fn eval_max_of(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -609,7 +619,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_transitive_eq(
|
fn eval_transitive_eq(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -645,7 +655,7 @@ impl OperationVerifyGadget {
|
||||||
}
|
}
|
||||||
fn eval_none(
|
fn eval_none(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
) -> BoolTarget {
|
) -> BoolTarget {
|
||||||
|
|
@ -663,7 +673,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_new_entry(
|
fn eval_new_entry(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
prev_statements: &[StatementTarget],
|
prev_statements: &[StatementTarget],
|
||||||
|
|
@ -701,7 +711,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_lt_to_neq(
|
fn eval_lt_to_neq(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -730,7 +740,7 @@ impl OperationVerifyGadget {
|
||||||
|
|
||||||
fn eval_copy(
|
fn eval_copy(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st: &StatementTarget,
|
st: &StatementTarget,
|
||||||
op_type: &OperationTypeTarget,
|
op_type: &OperationTypeTarget,
|
||||||
resolved_op_args: &[StatementTarget],
|
resolved_op_args: &[StatementTarget],
|
||||||
|
|
@ -759,7 +769,7 @@ struct CustomOperationVerifyGadget {
|
||||||
impl CustomOperationVerifyGadget {
|
impl CustomOperationVerifyGadget {
|
||||||
fn statement_arg_from_template(
|
fn statement_arg_from_template(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st_tmpl_arg: &StatementTmplArgTarget,
|
st_tmpl_arg: &StatementTmplArgTarget,
|
||||||
args: &[ValueTarget],
|
args: &[ValueTarget],
|
||||||
) -> StatementArgTarget {
|
) -> StatementArgTarget {
|
||||||
|
|
@ -812,7 +822,7 @@ impl CustomOperationVerifyGadget {
|
||||||
|
|
||||||
fn statement_from_template(
|
fn statement_from_template(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st_tmpl: &StatementTmplTarget,
|
st_tmpl: &StatementTmplTarget,
|
||||||
args: &[ValueTarget],
|
args: &[ValueTarget],
|
||||||
) -> StatementTarget {
|
) -> StatementTarget {
|
||||||
|
|
@ -836,7 +846,7 @@ impl CustomOperationVerifyGadget {
|
||||||
/// - Build the expected operation type
|
/// - Build the expected operation type
|
||||||
fn eval(
|
fn eval(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
custom_predicate: &CustomPredicateEntryTarget,
|
custom_predicate: &CustomPredicateEntryTarget,
|
||||||
op_args: &[StatementTarget],
|
op_args: &[StatementTarget],
|
||||||
args: &[ValueTarget], // arguments to the custom predicate, public and private
|
args: &[ValueTarget], // arguments to the custom predicate, public and private
|
||||||
|
|
@ -901,10 +911,49 @@ impl CustomOperationVerifyGadget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CalculateIdGadget {
|
/// Replace references to SELF by `self_id` in a statement.
|
||||||
|
struct NormalizeStatementGadget {
|
||||||
params: Params,
|
params: Params,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl NormalizeStatementGadget {
|
||||||
|
fn eval(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder,
|
||||||
|
statement: &StatementTarget,
|
||||||
|
self_id: &ValueTarget,
|
||||||
|
) -> StatementTarget {
|
||||||
|
let zero_value = builder.constant_value(EMPTY_VALUE);
|
||||||
|
let self_value = builder.constant_value(SELF.0.into());
|
||||||
|
let args = statement
|
||||||
|
.args
|
||||||
|
.iter()
|
||||||
|
.map(|arg| {
|
||||||
|
let first = ValueTarget::from_slice(&arg.elements[..VALUE_SIZE]);
|
||||||
|
let second = ValueTarget::from_slice(&arg.elements[VALUE_SIZE..]);
|
||||||
|
let is_not_ak = builder.is_equal_flattenable(&zero_value, &second);
|
||||||
|
let is_ak = builder.not(is_not_ak);
|
||||||
|
let is_self = builder.is_equal_flattenable(&self_value, &first);
|
||||||
|
let normalize = builder.and(is_ak, is_self);
|
||||||
|
let first_normalized =
|
||||||
|
builder.select_flattenable(&self.params, normalize, self_id, &first);
|
||||||
|
StatementArgTarget::new(first_normalized, second)
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
StatementTarget {
|
||||||
|
predicate: statement.predicate.clone(),
|
||||||
|
args,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CalculateIdGadget {
|
||||||
|
/// `params.num_public_statements_id` is the total number of statements that will be hashed.
|
||||||
|
/// The id is calculated with front-padded none-statements and then the input statements
|
||||||
|
/// reversed. The part of the hash from the front-padded none-statements is precomputed.
|
||||||
|
pub params: Params,
|
||||||
|
}
|
||||||
|
|
||||||
impl CalculateIdGadget {
|
impl CalculateIdGadget {
|
||||||
/// Precompute the hash state by absorbing all full chunks from `inputs` and return the reminder
|
/// Precompute the hash state by absorbing all full chunks from `inputs` and return the reminder
|
||||||
/// elements that didn't fit into a chunk.
|
/// elements that didn't fit into a chunk.
|
||||||
|
|
@ -923,7 +972,7 @@ impl CalculateIdGadget {
|
||||||
|
|
||||||
/// Hash `inputs` starting from a circuit-constant `perm` state.
|
/// Hash `inputs` starting from a circuit-constant `perm` state.
|
||||||
fn hash_from_state<H: AlgebraicHasher<F>, P: PlonkyPermutation<F>>(
|
fn hash_from_state<H: AlgebraicHasher<F>, P: PlonkyPermutation<F>>(
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
perm: P,
|
perm: P,
|
||||||
inputs: &[Target],
|
inputs: &[Target],
|
||||||
) -> HashOutTarget {
|
) -> HashOutTarget {
|
||||||
|
|
@ -953,17 +1002,19 @@ impl CalculateIdGadget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(
|
pub fn eval(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
|
// These statements will be padded to reach `self.num_statements`
|
||||||
statements: &[StatementTarget],
|
statements: &[StatementTarget],
|
||||||
) -> HashOutTarget {
|
) -> HashOutTarget {
|
||||||
|
assert!(statements.len() <= self.params.num_public_statements_id);
|
||||||
let measure = measure_gates_begin!(builder, "CalculateId");
|
let measure = measure_gates_begin!(builder, "CalculateId");
|
||||||
let statements_rev_flattened = statements.iter().rev().flat_map(|s| s.flatten());
|
let statements_rev_flattened = statements.iter().rev().flat_map(|s| s.flatten());
|
||||||
let mut none_st = mainpod::Statement::from(Statement::None);
|
let mut none_st = mainpod::Statement::from(Statement::None);
|
||||||
pad_statement(&self.params, &mut none_st);
|
pad_statement(&self.params, &mut none_st);
|
||||||
let front_pad_elts = iter::repeat(&none_st)
|
let front_pad_elts = iter::repeat(&none_st)
|
||||||
.take(self.params.num_public_statements_id - self.params.max_public_statements)
|
.take(self.params.num_public_statements_id - statements.len())
|
||||||
.flat_map(|s| s.to_fields(&self.params))
|
.flat_map(|s| s.to_fields(&self.params))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let (perm, front_pad_elts_rem) =
|
let (perm, front_pad_elts_rem) =
|
||||||
|
|
@ -992,7 +1043,7 @@ impl MainPodVerifyGadget {
|
||||||
// index
|
// index
|
||||||
fn normalize_st_tmpl(
|
fn normalize_st_tmpl(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
st_tmpl: &StatementTmplTarget,
|
st_tmpl: &StatementTmplTarget,
|
||||||
id: HashOutTarget,
|
id: HashOutTarget,
|
||||||
) -> StatementTmplTarget {
|
) -> StatementTmplTarget {
|
||||||
|
|
@ -1012,7 +1063,7 @@ impl MainPodVerifyGadget {
|
||||||
/// calculate the id of each batch.
|
/// calculate the id of each batch.
|
||||||
fn build_custom_predicate_table(
|
fn build_custom_predicate_table(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
) -> Result<(Vec<HashOutTarget>, Vec<CustomPredicateBatchTarget>)> {
|
) -> Result<(Vec<HashOutTarget>, Vec<CustomPredicateBatchTarget>)> {
|
||||||
let measure = measure_gates_begin!(builder, "BuildCustomPredicateTable");
|
let measure = measure_gates_begin!(builder, "BuildCustomPredicateTable");
|
||||||
let params = &self.params;
|
let params = &self.params;
|
||||||
|
|
@ -1053,7 +1104,7 @@ impl MainPodVerifyGadget {
|
||||||
/// custom predicate against the operation and statement.
|
/// custom predicate against the operation and statement.
|
||||||
fn build_custom_predicate_verification_table(
|
fn build_custom_predicate_verification_table(
|
||||||
&self,
|
&self,
|
||||||
builder: &mut CircuitBuilder<F, D>,
|
builder: &mut CircuitBuilder,
|
||||||
custom_predicate_table: &[HashOutTarget],
|
custom_predicate_table: &[HashOutTarget],
|
||||||
) -> Result<(Vec<HashOutTarget>, Vec<CustomPredicateVerifyEntryTarget>)> {
|
) -> Result<(Vec<HashOutTarget>, Vec<CustomPredicateVerifyEntryTarget>)> {
|
||||||
let measure = measure_gates_begin!(builder, "BuildCustomPredicateVerificationTable");
|
let measure = measure_gates_begin!(builder, "BuildCustomPredicateVerificationTable");
|
||||||
|
|
@ -1105,7 +1156,13 @@ impl MainPodVerifyGadget {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<MainPodVerifyTarget> {
|
fn eval(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder,
|
||||||
|
verified_proofs: &[VerifiedProofTarget],
|
||||||
|
) -> Result<MainPodVerifyTarget> {
|
||||||
|
assert_eq!(self.params.max_input_recursive_pods, verified_proofs.len());
|
||||||
|
|
||||||
let measure = measure_gates_begin!(builder, "MainPodVerify");
|
let measure = measure_gates_begin!(builder, "MainPodVerify");
|
||||||
let params = &self.params;
|
let params = &self.params;
|
||||||
// 1. Verify all input signed pods
|
// 1. Verify all input signed pods
|
||||||
|
|
@ -1115,6 +1172,7 @@ impl MainPodVerifyGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
}
|
}
|
||||||
.eval(builder)?;
|
.eval(builder)?;
|
||||||
|
builder.assert_one(signed_pod.signature.enabled.target);
|
||||||
signed_pods.push(signed_pod);
|
signed_pods.push(signed_pod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1132,16 +1190,47 @@ impl MainPodVerifyGadget {
|
||||||
statements.len(),
|
statements.len(),
|
||||||
1 + self.params.max_input_signed_pods * self.params.max_signed_pod_values
|
1 + self.params.max_input_signed_pods * self.params.max_signed_pod_values
|
||||||
);
|
);
|
||||||
// TODO: Fill with input main pods
|
|
||||||
for _main_pod in 0..self.params.max_input_main_pods {
|
let id_gadget = CalculateIdGadget {
|
||||||
for _statement in 0..self.params.max_public_statements {
|
params: params.clone(),
|
||||||
statements.push(StatementTarget::new_native(
|
};
|
||||||
builder,
|
let mut input_pods_self_statements: Vec<Vec<StatementTarget>> = Vec::new();
|
||||||
&self.params,
|
let normalize_statement_gadget = NormalizeStatementGadget {
|
||||||
NativePredicate::None,
|
params: self.params.clone(),
|
||||||
&[],
|
};
|
||||||
))
|
for verified_proof in verified_proofs {
|
||||||
|
let expected_id = HashOutTarget::try_from(
|
||||||
|
&verified_proof.public_inputs[PI_OFFSET_ID..PI_OFFSET_ID + HASH_SIZE],
|
||||||
|
)
|
||||||
|
.expect("4 elements");
|
||||||
|
let id_value = ValueTarget {
|
||||||
|
elements: expected_id.elements,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut input_pod_self_statements = Vec::new();
|
||||||
|
for _ in 0..self.params.max_input_pods_public_statements {
|
||||||
|
let self_st = builder.add_virtual_statement(params);
|
||||||
|
let normalized_st = normalize_statement_gadget.eval(builder, &self_st, &id_value);
|
||||||
|
input_pod_self_statements.push(self_st);
|
||||||
|
statements.push(normalized_st);
|
||||||
}
|
}
|
||||||
|
let id = id_gadget.eval(builder, &input_pod_self_statements);
|
||||||
|
builder.connect_hashes(expected_id, id);
|
||||||
|
input_pods_self_statements.push(input_pod_self_statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
let vds_root = builder.add_virtual_hash();
|
||||||
|
// TODO: verify that all input pod proofs use verifier data from the public input VD array
|
||||||
|
// This requires merkle proofs
|
||||||
|
// https://github.com/0xPARC/pod2/issues/250
|
||||||
|
|
||||||
|
// Verify that VD array that input pod uses is the same we use now.
|
||||||
|
for verified_proof in verified_proofs {
|
||||||
|
let verified_proof_vds_root = HashOutTarget::try_from(
|
||||||
|
&verified_proof.public_inputs[PI_OFFSET_VDSROOT..PI_OFFSET_VDSROOT + HASH_SIZE],
|
||||||
|
)
|
||||||
|
.expect("4 elements");
|
||||||
|
builder.connect_hashes(vds_root, verified_proof_vds_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the input (private and public) statements and corresponding operations
|
// Add the input (private and public) statements and corresponding operations
|
||||||
|
|
@ -1220,8 +1309,10 @@ impl MainPodVerifyGadget {
|
||||||
measure_gates_end!(builder, measure);
|
measure_gates_end!(builder, measure);
|
||||||
Ok(MainPodVerifyTarget {
|
Ok(MainPodVerifyTarget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
|
vds_root,
|
||||||
id,
|
id,
|
||||||
signed_pods,
|
signed_pods,
|
||||||
|
input_pods_self_statements,
|
||||||
statements: input_statements.to_vec(),
|
statements: input_statements.to_vec(),
|
||||||
operations,
|
operations,
|
||||||
merkle_proofs,
|
merkle_proofs,
|
||||||
|
|
@ -1233,8 +1324,10 @@ impl MainPodVerifyGadget {
|
||||||
|
|
||||||
pub struct MainPodVerifyTarget {
|
pub struct MainPodVerifyTarget {
|
||||||
params: Params,
|
params: Params,
|
||||||
|
vds_root: HashOutTarget,
|
||||||
id: HashOutTarget,
|
id: HashOutTarget,
|
||||||
signed_pods: Vec<SignedPodVerifyTarget>,
|
signed_pods: Vec<SignedPodVerifyTarget>,
|
||||||
|
input_pods_self_statements: Vec<Vec<StatementTarget>>,
|
||||||
// The KEY_TYPE statement must be the first public one
|
// The KEY_TYPE statement must be the first public one
|
||||||
statements: Vec<StatementTarget>,
|
statements: Vec<StatementTarget>,
|
||||||
operations: Vec<OperationTarget>,
|
operations: Vec<OperationTarget>,
|
||||||
|
|
@ -1251,7 +1344,9 @@ pub struct CustomPredicateVerification {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MainPodVerifyInput {
|
pub struct MainPodVerifyInput {
|
||||||
|
pub vds_root: Hash,
|
||||||
pub signed_pods: Vec<SignedPod>,
|
pub signed_pods: Vec<SignedPod>,
|
||||||
|
pub recursive_pods_pub_self_statements: Vec<Vec<Statement>>,
|
||||||
pub statements: Vec<mainpod::Statement>,
|
pub statements: Vec<mainpod::Statement>,
|
||||||
pub operations: Vec<mainpod::Operation>,
|
pub operations: Vec<mainpod::Operation>,
|
||||||
pub merkle_proofs: Vec<MerkleClaimAndProof>,
|
pub merkle_proofs: Vec<MerkleClaimAndProof>,
|
||||||
|
|
@ -1259,18 +1354,44 @@ pub struct MainPodVerifyInput {
|
||||||
pub custom_predicate_verifications: Vec<CustomPredicateVerification>,
|
pub custom_predicate_verifications: Vec<CustomPredicateVerification>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_targets_input_pods_self_statements(
|
||||||
|
pw: &mut PartialWitness<F>,
|
||||||
|
params: &Params,
|
||||||
|
statements_target: &[StatementTarget],
|
||||||
|
statements: &[Statement],
|
||||||
|
) -> Result<()> {
|
||||||
|
assert_eq!(
|
||||||
|
statements_target.len(),
|
||||||
|
params.max_input_pods_public_statements
|
||||||
|
);
|
||||||
|
assert!(statements.len() <= params.num_public_statements_id);
|
||||||
|
|
||||||
|
for (i, statement) in statements.iter().enumerate() {
|
||||||
|
statements_target[i].set_targets(pw, params, &statement.clone().into())?;
|
||||||
|
}
|
||||||
|
// Padding
|
||||||
|
let mut none_st = mainpod::Statement::from(Statement::None);
|
||||||
|
pad_statement(params, &mut none_st);
|
||||||
|
for statement_target in statements_target.iter().skip(statements.len()) {
|
||||||
|
statement_target.set_targets(pw, params, &none_st)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
impl MainPodVerifyTarget {
|
impl MainPodVerifyTarget {
|
||||||
pub fn set_targets(
|
pub fn set_targets(
|
||||||
&self,
|
&self,
|
||||||
pw: &mut PartialWitness<F>,
|
pw: &mut PartialWitness<F>,
|
||||||
input: &MainPodVerifyInput,
|
input: &MainPodVerifyInput,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
pw.set_target_arr(&self.vds_root.elements, &input.vds_root.0)?;
|
||||||
|
|
||||||
assert!(input.signed_pods.len() <= self.params.max_input_signed_pods);
|
assert!(input.signed_pods.len() <= self.params.max_input_signed_pods);
|
||||||
for (i, signed_pod) in input.signed_pods.iter().enumerate() {
|
for (i, signed_pod) in input.signed_pods.iter().enumerate() {
|
||||||
self.signed_pods[i].set_targets(pw, signed_pod)?;
|
self.signed_pods[i].set_targets(pw, signed_pod)?;
|
||||||
}
|
}
|
||||||
// Padding
|
// Padding
|
||||||
if self.params.max_input_signed_pods > 0 {
|
if input.signed_pods.len() != self.params.max_input_signed_pods {
|
||||||
// TODO: Instead of using an input for padding, use a canonical minimal SignedPod,
|
// TODO: Instead of using an input for padding, use a canonical minimal SignedPod,
|
||||||
// without it a MainPod configured to support input signed pods must have at least one
|
// without it a MainPod configured to support input signed pods must have at least one
|
||||||
// input signed pod :(
|
// input signed pod :(
|
||||||
|
|
@ -1279,6 +1400,34 @@ impl MainPodVerifyTarget {
|
||||||
self.signed_pods[i].set_targets(pw, pad_pod)?;
|
self.signed_pods[i].set_targets(pw, pad_pod)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
input.recursive_pods_pub_self_statements.len() <= self.params.max_input_recursive_pods
|
||||||
|
);
|
||||||
|
for (i, pod_pub_statements) in input.recursive_pods_pub_self_statements.iter().enumerate() {
|
||||||
|
set_targets_input_pods_self_statements(
|
||||||
|
pw,
|
||||||
|
&self.params,
|
||||||
|
&self.input_pods_self_statements[i],
|
||||||
|
pod_pub_statements,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
// Padding
|
||||||
|
if input.recursive_pods_pub_self_statements.len() != self.params.max_input_recursive_pods {
|
||||||
|
let empty_pod = EmptyPod::new_boxed(&self.params, input.vds_root);
|
||||||
|
let empty_pod_statements = empty_pod.pub_statements();
|
||||||
|
for i in
|
||||||
|
input.recursive_pods_pub_self_statements.len()..self.params.max_input_recursive_pods
|
||||||
|
{
|
||||||
|
set_targets_input_pods_self_statements(
|
||||||
|
pw,
|
||||||
|
&self.params,
|
||||||
|
&self.input_pods_self_statements[i],
|
||||||
|
&empty_pod_statements,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert_eq!(input.statements.len(), self.params.max_statements);
|
assert_eq!(input.statements.len(), self.params.max_statements);
|
||||||
for (i, (st, op)) in zip_eq(&input.statements, &input.operations).enumerate() {
|
for (i, (st, op)) in zip_eq(&input.statements, &input.operations).enumerate() {
|
||||||
self.statements[i].set_targets(pw, &self.params, st)?;
|
self.statements[i].set_targets(pw, &self.params, st)?;
|
||||||
|
|
@ -1342,17 +1491,44 @@ pub struct MainPodVerifyCircuit {
|
||||||
pub params: Params,
|
pub params: Params,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this type and implement it's logic directly in `impl InnerCircuit for MainPodVerifyTarget`
|
||||||
impl MainPodVerifyCircuit {
|
impl MainPodVerifyCircuit {
|
||||||
pub fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<MainPodVerifyTarget> {
|
pub fn eval(
|
||||||
|
&self,
|
||||||
|
builder: &mut CircuitBuilder,
|
||||||
|
verified_proofs: &[VerifiedProofTarget],
|
||||||
|
) -> Result<MainPodVerifyTarget> {
|
||||||
let main_pod = MainPodVerifyGadget {
|
let main_pod = MainPodVerifyGadget {
|
||||||
params: self.params.clone(),
|
params: self.params.clone(),
|
||||||
}
|
}
|
||||||
.eval(builder)?;
|
.eval(builder, verified_proofs)?;
|
||||||
builder.register_public_inputs(&main_pod.id.elements);
|
builder.register_public_inputs(&main_pod.id.elements);
|
||||||
|
builder.register_public_inputs(&main_pod.vds_root.elements);
|
||||||
Ok(main_pod)
|
Ok(main_pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InnerCircuit for MainPodVerifyTarget {
|
||||||
|
type Input = MainPodVerifyInput;
|
||||||
|
type Params = Params;
|
||||||
|
|
||||||
|
fn build(
|
||||||
|
builder: &mut CircuitBuilder,
|
||||||
|
params: &Self::Params,
|
||||||
|
verified_proofs: &[VerifiedProofTarget],
|
||||||
|
) -> Result<Self> {
|
||||||
|
MainPodVerifyCircuit {
|
||||||
|
params: params.clone(),
|
||||||
|
}
|
||||||
|
.eval(builder, verified_proofs)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// assigns the values to the targets
|
||||||
|
fn set_targets(&self, pw: &mut PartialWitness<F>, input: &Self::Input) -> Result<()> {
|
||||||
|
self.set_targets(pw, input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{iter, ops::Not};
|
use std::{iter, ops::Not};
|
||||||
|
|
@ -1395,7 +1571,7 @@ mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::new(config);
|
||||||
|
|
||||||
let st_target = builder.add_virtual_statement(¶ms);
|
let st_target = builder.add_virtual_statement(¶ms);
|
||||||
let op_target = builder.add_virtual_operation(¶ms);
|
let op_target = builder.add_virtual_operation(¶ms);
|
||||||
|
|
@ -2268,7 +2444,7 @@ mod tests {
|
||||||
expected_st_arg: StatementArg,
|
expected_st_arg: StatementArg,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::new(config);
|
||||||
let gadget = CustomOperationVerifyGadget {
|
let gadget = CustomOperationVerifyGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
};
|
};
|
||||||
|
|
@ -2369,7 +2545,7 @@ mod tests {
|
||||||
expected_st: Statement,
|
expected_st: Statement,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::new(config);
|
||||||
let gadget = CustomOperationVerifyGadget {
|
let gadget = CustomOperationVerifyGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
};
|
};
|
||||||
|
|
@ -2433,7 +2609,7 @@ mod tests {
|
||||||
expected_st: Option<Statement>,
|
expected_st: Option<Statement>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::new(config);
|
||||||
let gadget = CustomOperationVerifyGadget {
|
let gadget = CustomOperationVerifyGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
};
|
};
|
||||||
|
|
@ -2775,7 +2951,7 @@ mod tests {
|
||||||
|
|
||||||
fn helper_calculate_id(params: &Params, statements: &[Statement]) -> Result<()> {
|
fn helper_calculate_id(params: &Params, statements: &[Statement]) -> Result<()> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let mut builder = CircuitBuilder::new(config);
|
||||||
let gadget = CalculateIdGadget {
|
let gadget = CalculateIdGadget {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ pub struct SignedPodVerifyTarget {
|
||||||
// the KEY_TYPE entry must be the first one
|
// the KEY_TYPE entry must be the first one
|
||||||
// the KEY_SIGNER entry must be the second one
|
// the KEY_SIGNER entry must be the second one
|
||||||
mt_proofs: Vec<MerkleProofExistenceTarget>,
|
mt_proofs: Vec<MerkleProofExistenceTarget>,
|
||||||
signature: SignatureVerifyTarget,
|
pub(crate) signature: SignatureVerifyTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignedPodVerifyTarget {
|
impl SignedPodVerifyTarget {
|
||||||
|
|
|
||||||
207
src/backends/plonky2/emptypod.rs
Normal file
207
src/backends/plonky2/emptypod.rs
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
use std::{collections::HashMap, sync::Mutex};
|
||||||
|
|
||||||
|
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use plonky2::{
|
||||||
|
hash::hash_types::HashOutTarget,
|
||||||
|
iop::witness::{PartialWitness, WitnessWrite},
|
||||||
|
plonk::{
|
||||||
|
circuit_builder::CircuitBuilder,
|
||||||
|
circuit_data::{self, CircuitConfig},
|
||||||
|
proof::ProofWithPublicInputs,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backends::plonky2::{
|
||||||
|
basetypes::{Proof, C, D},
|
||||||
|
circuits::{
|
||||||
|
common::{Flattenable, StatementTarget},
|
||||||
|
mainpod::{CalculateIdGadget, PI_OFFSET_ID},
|
||||||
|
},
|
||||||
|
error::{Error, Result},
|
||||||
|
mainpod::{self, calculate_id},
|
||||||
|
recursion::pad_circuit,
|
||||||
|
LazyLock, DEFAULT_PARAMS, STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
||||||
|
},
|
||||||
|
middleware::{
|
||||||
|
self, AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement,
|
||||||
|
ToFields, Value, VerifierOnlyCircuitData, EMPTY_HASH, F, HASH_SIZE, KEY_TYPE, SELF,
|
||||||
|
},
|
||||||
|
timed,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EmptyPodVerifyCircuit {
|
||||||
|
params: Params,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_statement() -> Statement {
|
||||||
|
Statement::ValueOf(
|
||||||
|
AnchoredKey::from((SELF, KEY_TYPE)),
|
||||||
|
Value::from(PodType::Empty),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmptyPodVerifyCircuit {
|
||||||
|
fn eval(&self, builder: &mut CircuitBuilder<F, D>) -> Result<EmptyPodVerifyTarget> {
|
||||||
|
let type_statement = StatementTarget::from_flattened(
|
||||||
|
&self.params,
|
||||||
|
&builder.constants(&type_statement().to_fields(&self.params)),
|
||||||
|
);
|
||||||
|
let id = CalculateIdGadget {
|
||||||
|
params: self.params.clone(),
|
||||||
|
}
|
||||||
|
.eval(builder, &[type_statement]);
|
||||||
|
let vds_root = builder.add_virtual_hash();
|
||||||
|
builder.register_public_inputs(&id.elements);
|
||||||
|
builder.register_public_inputs(&vds_root.elements);
|
||||||
|
Ok(EmptyPodVerifyTarget { vds_root })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EmptyPodVerifyTarget {
|
||||||
|
vds_root: HashOutTarget,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EmptyPodVerifyTarget {
|
||||||
|
pub fn set_targets(&self, pw: &mut PartialWitness<F>, vds_root: Hash) -> Result<()> {
|
||||||
|
Ok(pw.set_target_arr(&self.vds_root.elements, &vds_root.0)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct EmptyPod {
|
||||||
|
params: Params,
|
||||||
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
|
proof: Proof,
|
||||||
|
}
|
||||||
|
|
||||||
|
type CircuitData = circuit_data::CircuitData<F, C, D>;
|
||||||
|
|
||||||
|
static STANDARD_EMPTY_POD_DATA: LazyLock<(EmptyPodVerifyTarget, CircuitData)> =
|
||||||
|
LazyLock::new(|| build().expect("successful build"));
|
||||||
|
|
||||||
|
fn build() -> Result<(EmptyPodVerifyTarget, CircuitData)> {
|
||||||
|
let params = &*DEFAULT_PARAMS;
|
||||||
|
let config = CircuitConfig::standard_recursion_config();
|
||||||
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
||||||
|
let empty_pod_verify_target = EmptyPodVerifyCircuit {
|
||||||
|
params: params.clone(),
|
||||||
|
}
|
||||||
|
.eval(&mut builder)?;
|
||||||
|
let circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||||
|
pad_circuit(&mut builder, &circuit_data.common);
|
||||||
|
|
||||||
|
let data = timed!("EmptyPod build", builder.build::<C>());
|
||||||
|
assert_eq!(circuit_data.common, data.common);
|
||||||
|
Ok((empty_pod_verify_target, data))
|
||||||
|
}
|
||||||
|
|
||||||
|
static EMPTY_POD_CACHE: LazyLock<Mutex<HashMap<Hash, EmptyPod>>> =
|
||||||
|
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||||
|
|
||||||
|
impl EmptyPod {
|
||||||
|
pub fn _prove(params: &Params, vds_root: Hash) -> Result<EmptyPod> {
|
||||||
|
let (empty_pod_verify_target, data) = &*STANDARD_EMPTY_POD_DATA;
|
||||||
|
|
||||||
|
let mut pw = PartialWitness::<F>::new();
|
||||||
|
empty_pod_verify_target.set_targets(&mut pw, vds_root)?;
|
||||||
|
let proof = timed!("EmptyPod prove", data.prove(pw)?);
|
||||||
|
let id = &proof.public_inputs[PI_OFFSET_ID..PI_OFFSET_ID + HASH_SIZE];
|
||||||
|
let id = PodId(Hash([id[0], id[1], id[2], id[3]]));
|
||||||
|
Ok(EmptyPod {
|
||||||
|
params: params.clone(),
|
||||||
|
id,
|
||||||
|
vds_root,
|
||||||
|
proof: proof.proof,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn new_boxed(params: &Params, vds_root: Hash) -> Box<dyn RecursivePod> {
|
||||||
|
let default_params = &*DEFAULT_PARAMS;
|
||||||
|
assert_eq!(default_params.id_params(), params.id_params());
|
||||||
|
|
||||||
|
let empty_pod = EMPTY_POD_CACHE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.entry(vds_root)
|
||||||
|
.or_insert_with(|| Self::_prove(params, vds_root).expect("prove EmptyPod"))
|
||||||
|
.clone();
|
||||||
|
Box::new(empty_pod)
|
||||||
|
}
|
||||||
|
fn _verify(&self) -> Result<()> {
|
||||||
|
let statements = self
|
||||||
|
.pub_self_statements()
|
||||||
|
.into_iter()
|
||||||
|
.map(mainpod::Statement::from)
|
||||||
|
.collect_vec();
|
||||||
|
let id = PodId(calculate_id(&statements, &self.params));
|
||||||
|
if id != self.id {
|
||||||
|
return Err(Error::id_not_equal(self.id, id));
|
||||||
|
}
|
||||||
|
|
||||||
|
let public_inputs = id
|
||||||
|
.to_fields(&self.params)
|
||||||
|
.iter()
|
||||||
|
.chain(EMPTY_HASH.0.iter()) // slot for the unused vds root
|
||||||
|
.cloned()
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let (_, data) = &*STANDARD_EMPTY_POD_DATA;
|
||||||
|
data.verify(ProofWithPublicInputs {
|
||||||
|
proof: self.proof.clone(),
|
||||||
|
public_inputs,
|
||||||
|
})
|
||||||
|
.map_err(|e| Error::custom(format!("EmptyPod proof verification failure: {:?}", e)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pod for EmptyPod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
&self.params
|
||||||
|
}
|
||||||
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
|
Ok(self._verify()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id(&self) -> PodId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||||
|
vec![type_statement()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialized_proof(&self) -> String {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
use plonky2::util::serialization::Write;
|
||||||
|
buffer.write_proof(&self.proof).unwrap();
|
||||||
|
BASE64_STANDARD.encode(buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecursivePod for EmptyPod {
|
||||||
|
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||||
|
let (_, data) = &*STANDARD_EMPTY_POD_DATA;
|
||||||
|
data.verifier_only.clone()
|
||||||
|
}
|
||||||
|
fn proof(&self) -> Proof {
|
||||||
|
self.proof.clone()
|
||||||
|
}
|
||||||
|
fn vds_root(&self) -> Hash {
|
||||||
|
self.vds_root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_pod() {
|
||||||
|
let params = Params::default();
|
||||||
|
|
||||||
|
let empty_pod = EmptyPod::new_boxed(¶ms, EMPTY_HASH);
|
||||||
|
empty_pod.verify().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,31 +7,29 @@ use itertools::Itertools;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
hash::poseidon::PoseidonHash,
|
hash::poseidon::PoseidonHash,
|
||||||
iop::witness::PartialWitness,
|
plonk::{circuit_data::CommonCircuitData, config::Hasher},
|
||||||
plonk::{
|
|
||||||
circuit_builder::CircuitBuilder,
|
|
||||||
circuit_data::{CircuitConfig, CommonCircuitData},
|
|
||||||
config::Hasher,
|
|
||||||
proof::{Proof, ProofWithPublicInputs},
|
|
||||||
},
|
|
||||||
util::serialization::{Buffer, Read},
|
util::serialization::{Buffer, Read},
|
||||||
};
|
};
|
||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::{C, D},
|
basetypes::{Proof, ProofWithPublicInputs, VerifierOnlyCircuitData, D},
|
||||||
circuits::mainpod::{
|
circuits::mainpod::{
|
||||||
CustomPredicateVerification, MainPodVerifyCircuit, MainPodVerifyInput,
|
CustomPredicateVerification, MainPodVerifyInput, MainPodVerifyTarget, NUM_PUBLIC_INPUTS,
|
||||||
},
|
},
|
||||||
|
emptypod::EmptyPod,
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
|
mock::emptypod::MockEmptyPod,
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
|
recursion::{self, RecursiveCircuit, RecursiveParams},
|
||||||
signedpod::SignedPod,
|
signedpod::SignedPod,
|
||||||
|
STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, resolve_wildcard_values, AnchoredKey, CustomPredicateBatch, DynError, Hash,
|
self, resolve_wildcard_values, AnchoredKey, CustomPredicateBatch, DynError, Hash,
|
||||||
MainPodInputs, NativeOperation, NonePod, OperationType, Params, Pod, PodId, PodProver,
|
MainPodInputs, NativeOperation, NonePod, OperationType, Params, Pod, PodId, PodProver,
|
||||||
PodType, StatementArg, ToFields, F, KEY_TYPE, SELF,
|
PodType, RecursivePod, StatementArg, ToFields, F, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -42,11 +40,8 @@ use crate::{
|
||||||
/// with a precomputed constant corresponding to the front-padding part:
|
/// with a precomputed constant corresponding to the front-padding part:
|
||||||
/// `id = hash(serialize(reverse(statements || none-statements)))`
|
/// `id = hash(serialize(reverse(statements || none-statements)))`
|
||||||
pub(crate) fn calculate_id(statements: &[Statement], params: &Params) -> middleware::Hash {
|
pub(crate) fn calculate_id(statements: &[Statement], params: &Params) -> middleware::Hash {
|
||||||
assert_eq!(params.max_public_statements, statements.len());
|
assert!(statements.len() <= params.num_public_statements_id);
|
||||||
assert!(params.max_public_statements <= params.num_public_statements_id);
|
assert!(params.max_public_statements <= params.num_public_statements_id);
|
||||||
statements
|
|
||||||
.iter()
|
|
||||||
.for_each(|st| assert_eq!(params.max_statement_args, st.1.len()));
|
|
||||||
|
|
||||||
let mut none_st: Statement = middleware::Statement::None.into();
|
let mut none_st: Statement = middleware::Statement::None.into();
|
||||||
pad_statement(params, &mut none_st);
|
pad_statement(params, &mut none_st);
|
||||||
|
|
@ -250,7 +245,11 @@ fn pad_operation_args(params: &Params, args: &mut Vec<OperationArg>) {
|
||||||
|
|
||||||
/// Returns the statements from the given MainPodInputs, padding to the
|
/// Returns the statements from the given MainPodInputs, padding to the
|
||||||
/// respective max lengths defined at the given Params.
|
/// respective max lengths defined at the given Params.
|
||||||
pub(crate) fn layout_statements(params: &Params, inputs: &MainPodInputs) -> Vec<Statement> {
|
pub(crate) fn layout_statements(
|
||||||
|
params: &Params,
|
||||||
|
mock: bool,
|
||||||
|
inputs: &MainPodInputs,
|
||||||
|
) -> Result<Vec<Statement>> {
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
|
||||||
// Statement at index 0 is always None to be used for padding operation arguments in custom
|
// Statement at index 0 is always None to be used for padding operation arguments in custom
|
||||||
|
|
@ -258,6 +257,8 @@ pub(crate) fn layout_statements(params: &Params, inputs: &MainPodInputs) -> Vec<
|
||||||
statements.push(middleware::Statement::None.into());
|
statements.push(middleware::Statement::None.into());
|
||||||
|
|
||||||
// Input signed pods region
|
// Input signed pods region
|
||||||
|
// TODO: Replace this with a dumb signed pod
|
||||||
|
// https://github.com/0xPARC/pod2/issues/246
|
||||||
let none_sig_pod_box: Box<dyn Pod> = Box::new(NonePod {});
|
let none_sig_pod_box: Box<dyn Pod> = Box::new(NonePod {});
|
||||||
let none_sig_pod = none_sig_pod_box.as_ref();
|
let none_sig_pod = none_sig_pod_box.as_ref();
|
||||||
assert!(inputs.signed_pods.len() <= params.max_input_signed_pods);
|
assert!(inputs.signed_pods.len() <= params.max_input_signed_pods);
|
||||||
|
|
@ -277,14 +278,20 @@ pub(crate) fn layout_statements(params: &Params, inputs: &MainPodInputs) -> Vec<
|
||||||
}
|
}
|
||||||
|
|
||||||
// Input main pods region
|
// Input main pods region
|
||||||
let none_main_pod_box: Box<dyn Pod> = Box::new(NonePod {});
|
let empty_pod_box: Box<dyn RecursivePod> =
|
||||||
let none_main_pod = none_main_pod_box.as_ref();
|
if mock || inputs.recursive_pods.len() == params.max_input_recursive_pods {
|
||||||
assert!(inputs.main_pods.len() <= params.max_input_main_pods);
|
// We mocking or we don't need padding so we skip creating an EmptyPod
|
||||||
for i in 0..params.max_input_main_pods {
|
MockEmptyPod::new_boxed(params)
|
||||||
let pod = inputs.main_pods.get(i).copied().unwrap_or(none_main_pod);
|
} else {
|
||||||
|
EmptyPod::new_boxed(params, inputs.vds_root)
|
||||||
|
};
|
||||||
|
let empty_pod = empty_pod_box.as_ref();
|
||||||
|
assert!(inputs.recursive_pods.len() <= params.max_input_recursive_pods);
|
||||||
|
for i in 0..params.max_input_recursive_pods {
|
||||||
|
let pod = inputs.recursive_pods.get(i).copied().unwrap_or(empty_pod);
|
||||||
let sts = pod.pub_statements();
|
let sts = pod.pub_statements();
|
||||||
assert!(sts.len() <= params.max_public_statements);
|
assert!(sts.len() <= params.max_public_statements);
|
||||||
for j in 0..params.max_public_statements {
|
for j in 0..params.max_input_pods_public_statements {
|
||||||
let mut st = sts
|
let mut st = sts
|
||||||
.get(j)
|
.get(j)
|
||||||
.unwrap_or(&middleware::Statement::None)
|
.unwrap_or(&middleware::Statement::None)
|
||||||
|
|
@ -329,7 +336,7 @@ pub(crate) fn layout_statements(params: &Params, inputs: &MainPodInputs) -> Vec<
|
||||||
statements.push(st);
|
statements.push(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
statements
|
Ok(statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process_private_statements_operations(
|
pub(crate) fn process_private_statements_operations(
|
||||||
|
|
@ -399,15 +406,25 @@ pub(crate) fn process_public_statements_operations(
|
||||||
pub struct Prover {}
|
pub struct Prover {}
|
||||||
|
|
||||||
impl Prover {
|
impl Prover {
|
||||||
fn _prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<MainPod> {
|
fn _prove(&self, params: &Params, inputs: MainPodInputs) -> Result<MainPod> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let (main_pod_target, circuit_data) =
|
||||||
let main_pod = MainPodVerifyCircuit {
|
RecursiveCircuit::<MainPodVerifyTarget>::circuit_data_padded(
|
||||||
params: params.clone(),
|
params.max_input_recursive_pods,
|
||||||
}
|
&rec_circuit_data.common,
|
||||||
.eval(&mut builder)?;
|
params,
|
||||||
|
)?;
|
||||||
|
let rec_params = RecursiveParams {
|
||||||
|
arity: params.max_input_recursive_pods,
|
||||||
|
common_data: circuit_data.common.clone(),
|
||||||
|
verifier_data: circuit_data.verifier_data(),
|
||||||
|
};
|
||||||
|
let main_pod = RecursiveCircuit {
|
||||||
|
params: rec_params,
|
||||||
|
prover: circuit_data.prover_data(),
|
||||||
|
target: main_pod_target,
|
||||||
|
};
|
||||||
|
|
||||||
let mut pw = PartialWitness::<F>::new();
|
|
||||||
let signed_pods_input: Vec<SignedPod> = inputs
|
let signed_pods_input: Vec<SignedPod> = inputs
|
||||||
.signed_pods
|
.signed_pods
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -419,6 +436,33 @@ impl Prover {
|
||||||
})
|
})
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
|
// Pad input recursive pods with empty pods if necessary
|
||||||
|
let empty_pod = if inputs.recursive_pods.len() == params.max_input_recursive_pods {
|
||||||
|
// We don't need padding so we skip creating an EmptyPod
|
||||||
|
MockEmptyPod::new_boxed(params)
|
||||||
|
} else {
|
||||||
|
EmptyPod::new_boxed(params, inputs.vds_root)
|
||||||
|
};
|
||||||
|
let inputs = MainPodInputs {
|
||||||
|
recursive_pods: &inputs
|
||||||
|
.recursive_pods
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.chain(iter::repeat(&*empty_pod))
|
||||||
|
.take(params.max_input_recursive_pods)
|
||||||
|
.collect_vec(),
|
||||||
|
..inputs
|
||||||
|
};
|
||||||
|
|
||||||
|
let recursive_pods_pub_self_statements = inputs
|
||||||
|
.recursive_pods
|
||||||
|
.iter()
|
||||||
|
.map(|pod| {
|
||||||
|
assert_eq!(params.id_params(), pod.params().id_params());
|
||||||
|
pod.pub_self_statements()
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
||||||
let custom_predicate_batches = extract_custom_predicate_batches(params, inputs.operations)?;
|
let custom_predicate_batches = extract_custom_predicate_batches(params, inputs.operations)?;
|
||||||
let custom_predicate_verifications = extract_custom_predicate_verifications(
|
let custom_predicate_verifications = extract_custom_predicate_verifications(
|
||||||
|
|
@ -427,7 +471,7 @@ impl Prover {
|
||||||
&custom_predicate_batches,
|
&custom_predicate_batches,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let statements = layout_statements(params, &inputs);
|
let statements = layout_statements(params, false, &inputs)?;
|
||||||
let operations = process_private_statements_operations(
|
let operations = process_private_statements_operations(
|
||||||
params,
|
params,
|
||||||
&statements,
|
&statements,
|
||||||
|
|
@ -442,23 +486,38 @@ impl Prover {
|
||||||
// get the id out of the public statements
|
// get the id out of the public statements
|
||||||
let id: PodId = PodId(calculate_id(&public_statements, params));
|
let id: PodId = PodId(calculate_id(&public_statements, params));
|
||||||
|
|
||||||
|
let proofs = inputs
|
||||||
|
.recursive_pods
|
||||||
|
.iter()
|
||||||
|
.map(|pod| {
|
||||||
|
assert_eq!(inputs.vds_root, pod.vds_root());
|
||||||
|
ProofWithPublicInputs {
|
||||||
|
proof: pod.proof(),
|
||||||
|
public_inputs: [pod.id().0 .0, inputs.vds_root.0].concat(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
let verifier_datas = inputs
|
||||||
|
.recursive_pods
|
||||||
|
.iter()
|
||||||
|
.map(|pod| pod.verifier_data())
|
||||||
|
.collect_vec();
|
||||||
let input = MainPodVerifyInput {
|
let input = MainPodVerifyInput {
|
||||||
|
vds_root: inputs.vds_root,
|
||||||
signed_pods: signed_pods_input,
|
signed_pods: signed_pods_input,
|
||||||
|
recursive_pods_pub_self_statements,
|
||||||
statements: statements[statements.len() - params.max_statements..].to_vec(),
|
statements: statements[statements.len() - params.max_statements..].to_vec(),
|
||||||
operations,
|
operations,
|
||||||
merkle_proofs,
|
merkle_proofs,
|
||||||
custom_predicate_batches,
|
custom_predicate_batches,
|
||||||
custom_predicate_verifications,
|
custom_predicate_verifications,
|
||||||
};
|
};
|
||||||
main_pod.set_targets(&mut pw, &input)?;
|
let proof_with_pis = main_pod.prove(&input, proofs, verifier_datas)?;
|
||||||
|
|
||||||
// generate & verify proof
|
|
||||||
let data = builder.build::<C>();
|
|
||||||
let proof_with_pis = data.prove(pw)?;
|
|
||||||
|
|
||||||
Ok(MainPod {
|
Ok(MainPod {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
id,
|
id,
|
||||||
|
vds_root: inputs.vds_root,
|
||||||
public_statements,
|
public_statements,
|
||||||
proof: proof_with_pis.proof,
|
proof: proof_with_pis.proof,
|
||||||
})
|
})
|
||||||
|
|
@ -467,41 +526,21 @@ impl Prover {
|
||||||
|
|
||||||
impl PodProver for Prover {
|
impl PodProver for Prover {
|
||||||
fn prove(
|
fn prove(
|
||||||
&mut self,
|
&self,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
inputs: MainPodInputs,
|
inputs: MainPodInputs,
|
||||||
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
) -> Result<Box<dyn RecursivePod>, Box<DynError>> {
|
||||||
Ok(self._prove(params, inputs).map(Box::new)?)
|
Ok(self._prove(params, inputs).map(Box::new)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type MainPodProof = Proof<F, C, D>;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MainPod {
|
pub struct MainPod {
|
||||||
params: Params,
|
params: Params,
|
||||||
id: PodId,
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
public_statements: Vec<Statement>,
|
public_statements: Vec<Statement>,
|
||||||
proof: MainPodProof,
|
proof: Proof,
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert a Statement into middleware::Statement and replace references to SELF by `self_id`.
|
|
||||||
pub(crate) fn normalize_statement(statement: &Statement, self_id: PodId) -> middleware::Statement {
|
|
||||||
Statement(
|
|
||||||
statement.0.clone(),
|
|
||||||
statement
|
|
||||||
.1
|
|
||||||
.iter()
|
|
||||||
.map(|sa| match &sa {
|
|
||||||
StatementArg::Key(AnchoredKey { pod_id, key }) if *pod_id == SELF => {
|
|
||||||
StatementArg::Key(AnchoredKey::new(self_id, key.clone()))
|
|
||||||
}
|
|
||||||
_ => sa.clone(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.try_into()
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a helper function to get the CommonCircuitData necessary to decode
|
// This is a helper function to get the CommonCircuitData necessary to decode
|
||||||
|
|
@ -509,66 +548,76 @@ pub(crate) fn normalize_statement(statement: &Statement, self_id: PodId) -> midd
|
||||||
// as a constant or with static initialization, but in the meantime we can
|
// as a constant or with static initialization, but in the meantime we can
|
||||||
// generate it on-demand.
|
// generate it on-demand.
|
||||||
fn get_common_data(params: &Params) -> Result<CommonCircuitData<F, D>, Error> {
|
fn get_common_data(params: &Params) -> Result<CommonCircuitData<F, D>, Error> {
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
// TODO: Cache this somehow
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
// https://github.com/0xPARC/pod2/issues/247
|
||||||
let _main_pod = MainPodVerifyCircuit {
|
let rec_params = recursion::new_params::<MainPodVerifyTarget>(
|
||||||
params: params.clone(),
|
params.max_input_recursive_pods,
|
||||||
}
|
NUM_PUBLIC_INPUTS,
|
||||||
.eval(&mut builder)
|
params,
|
||||||
.map_err(|e| Error::custom(format!("Failed to evaluate MainPodVerifyCircuit: {}", e)))?;
|
)?;
|
||||||
|
Ok(rec_params.common_data().clone())
|
||||||
let data = builder.build::<C>();
|
|
||||||
Ok(data.common)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MainPod {
|
impl MainPod {
|
||||||
fn _verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 2. get the id out of the public statements
|
// 2. get the id out of the public statements
|
||||||
let id: PodId = PodId(calculate_id(&self.public_statements, &self.params));
|
let id = PodId(calculate_id(&self.public_statements, &self.params));
|
||||||
if id != self.id {
|
if id != self.id {
|
||||||
return Err(Error::id_not_equal(self.id, id));
|
return Err(Error::id_not_equal(self.id, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1, 3, 4, 5 verification via the zkSNARK proof
|
// 1, 3, 4, 5 verification via the zkSNARK proof
|
||||||
|
let rec_circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||||
// TODO: cache these artefacts
|
// TODO: cache these artefacts
|
||||||
let config = CircuitConfig::standard_recursion_config();
|
// https://github.com/0xPARC/pod2/issues/247
|
||||||
let mut builder = CircuitBuilder::<F, D>::new(config);
|
let (_, circuit_data) = RecursiveCircuit::<MainPodVerifyTarget>::circuit_data_padded(
|
||||||
let _main_pod = MainPodVerifyCircuit {
|
self.params.max_input_recursive_pods,
|
||||||
params: self.params.clone(),
|
&rec_circuit_data.common,
|
||||||
}
|
&self.params,
|
||||||
.eval(&mut builder)?;
|
)?;
|
||||||
|
let public_inputs = id
|
||||||
let data = builder.build::<C>();
|
.to_fields(&self.params)
|
||||||
data.verify(ProofWithPublicInputs {
|
.iter()
|
||||||
|
.chain(self.vds_root.0.iter())
|
||||||
|
.cloned()
|
||||||
|
.collect_vec();
|
||||||
|
circuit_data
|
||||||
|
.verify(ProofWithPublicInputs {
|
||||||
proof: self.proof.clone(),
|
proof: self.proof.clone(),
|
||||||
public_inputs: id.to_fields(&self.params),
|
public_inputs,
|
||||||
})
|
})
|
||||||
.map_err(|e| Error::custom(format!("MainPod proof verification failure: {:?}", e)))
|
.map_err(|e| Error::custom(format!("MainPod proof verification failure: {:?}", e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn proof(&self) -> MainPodProof {
|
pub fn proof(&self) -> Proof {
|
||||||
self.proof.clone()
|
self.proof.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vds_root(&self) -> Hash {
|
||||||
|
self.vds_root
|
||||||
|
}
|
||||||
|
|
||||||
pub fn params(&self) -> &Params {
|
pub fn params(&self) -> &Params {
|
||||||
&self.params
|
&self.params
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
proof: MainPodProof,
|
proof: Proof,
|
||||||
public_statements: Vec<Statement>,
|
public_statements: Vec<Statement>,
|
||||||
id: PodId,
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
params: Params,
|
params: Params,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
params,
|
params,
|
||||||
id,
|
id,
|
||||||
|
vds_root,
|
||||||
public_statements,
|
public_statements,
|
||||||
proof,
|
proof,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_proof(proof: &str, params: &Params) -> Result<MainPodProof, Error> {
|
pub fn decode_proof(proof: &str, params: &Params) -> Result<Proof, Error> {
|
||||||
let decoded = BASE64_STANDARD.decode(proof).map_err(|e| {
|
let decoded = BASE64_STANDARD.decode(proof).map_err(|e| {
|
||||||
Error::custom(format!(
|
Error::custom(format!(
|
||||||
"Failed to decode proof from base64: {}. Value: {}",
|
"Failed to decode proof from base64: {}. Value: {}",
|
||||||
|
|
@ -590,6 +639,9 @@ impl MainPod {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MainPod {
|
impl Pod for MainPod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
&self.params
|
||||||
|
}
|
||||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
Ok(self._verify()?)
|
Ok(self._verify()?)
|
||||||
}
|
}
|
||||||
|
|
@ -598,12 +650,11 @@ impl Pod for MainPod {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pub_statements(&self) -> Vec<middleware::Statement> {
|
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||||
// return the public statements, where when origin=SELF is replaced by origin=self.id()
|
|
||||||
self.public_statements
|
self.public_statements
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|statement| normalize_statement(&statement, self.id()))
|
.map(|st| st.try_into().expect("valid statement"))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,6 +666,19 @@ impl Pod for MainPod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RecursivePod for MainPod {
|
||||||
|
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||||
|
let data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||||
|
data.verifier_only.clone()
|
||||||
|
}
|
||||||
|
fn proof(&self) -> Proof {
|
||||||
|
self.proof.clone()
|
||||||
|
}
|
||||||
|
fn vds_root(&self) -> Hash {
|
||||||
|
self.vds_root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -642,7 +706,7 @@ pub mod tests {
|
||||||
let params = middleware::Params {
|
let params = middleware::Params {
|
||||||
// Currently the circuit uses random access that only supports vectors of length 64.
|
// Currently the circuit uses random access that only supports vectors of length 64.
|
||||||
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
||||||
max_input_main_pods: 0,
|
max_input_recursive_pods: 0,
|
||||||
max_custom_predicate_batches: 0,
|
max_custom_predicate_batches: 0,
|
||||||
max_custom_predicate_verifications: 0,
|
max_custom_predicate_verifications: 0,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -672,10 +736,11 @@ pub mod tests {
|
||||||
fn test_mini_0() {
|
fn test_mini_0() {
|
||||||
let params = middleware::Params {
|
let params = middleware::Params {
|
||||||
max_input_signed_pods: 1,
|
max_input_signed_pods: 1,
|
||||||
max_input_main_pods: 1,
|
max_input_recursive_pods: 1,
|
||||||
max_signed_pod_values: 6,
|
max_signed_pod_values: 6,
|
||||||
max_statements: 8,
|
max_statements: 8,
|
||||||
max_public_statements: 4,
|
max_public_statements: 4,
|
||||||
|
max_input_pods_public_statements: 10,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -715,7 +780,8 @@ pub mod tests {
|
||||||
fn test_mainpod_small_empty() {
|
fn test_mainpod_small_empty() {
|
||||||
let params = middleware::Params {
|
let params = middleware::Params {
|
||||||
max_input_signed_pods: 0,
|
max_input_signed_pods: 0,
|
||||||
max_input_main_pods: 0,
|
max_input_recursive_pods: 0,
|
||||||
|
max_input_pods_public_statements: 2,
|
||||||
max_statements: 5,
|
max_statements: 5,
|
||||||
max_signed_pod_values: 2,
|
max_signed_pod_values: 2,
|
||||||
max_public_statements: 2,
|
max_public_statements: 2,
|
||||||
|
|
@ -753,14 +819,11 @@ pub mod tests {
|
||||||
fn test_main_ethdos() -> frontend::Result<()> {
|
fn test_main_ethdos() -> frontend::Result<()> {
|
||||||
let params = Params {
|
let params = Params {
|
||||||
max_input_signed_pods: 2,
|
max_input_signed_pods: 2,
|
||||||
max_input_main_pods: 1,
|
max_input_recursive_pods: 1,
|
||||||
max_statements: 26,
|
max_statements: 26,
|
||||||
max_public_statements: 5,
|
max_public_statements: 5,
|
||||||
max_signed_pod_values: 8,
|
max_signed_pod_values: 8,
|
||||||
max_statement_args: 3,
|
max_operation_args: 5,
|
||||||
max_operation_args: 4,
|
|
||||||
max_custom_predicate_arity: 4,
|
|
||||||
max_custom_batch_size: 3,
|
|
||||||
max_custom_predicate_wildcards: 6,
|
max_custom_predicate_wildcards: 6,
|
||||||
max_custom_predicate_verifications: 8,
|
max_custom_predicate_verifications: 8,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
@ -805,7 +868,7 @@ pub mod tests {
|
||||||
fn test_main_mini_custom_1() -> frontend::Result<()> {
|
fn test_main_mini_custom_1() -> frontend::Result<()> {
|
||||||
let params = Params {
|
let params = Params {
|
||||||
max_input_signed_pods: 0,
|
max_input_signed_pods: 0,
|
||||||
max_input_main_pods: 0,
|
max_input_recursive_pods: 0,
|
||||||
max_statements: 9,
|
max_statements: 9,
|
||||||
max_public_statements: 4,
|
max_public_statements: 4,
|
||||||
max_statement_args: 3,
|
max_statement_args: 3,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::fmt;
|
use std::{fmt, iter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -28,9 +28,15 @@ impl Statement {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToFields for Statement {
|
impl ToFields for Statement {
|
||||||
fn to_fields(&self, _params: &Params) -> Vec<middleware::F> {
|
fn to_fields(&self, params: &Params) -> Vec<middleware::F> {
|
||||||
let mut fields = self.0.to_fields(_params);
|
let mut fields = self.0.to_fields(params);
|
||||||
fields.extend(self.1.iter().flat_map(|arg| arg.to_fields(_params)));
|
fields.extend(
|
||||||
|
self.1
|
||||||
|
.iter()
|
||||||
|
.chain(iter::repeat(&StatementArg::None))
|
||||||
|
.take(params.max_statement_args)
|
||||||
|
.flat_map(|arg| arg.to_fields(params)),
|
||||||
|
);
|
||||||
fields
|
fields
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
93
src/backends/plonky2/mock/emptypod.rs
Normal file
93
src/backends/plonky2/mock/emptypod.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
use itertools::Itertools;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backends::plonky2::{
|
||||||
|
basetypes::{Proof, VerifierOnlyCircuitData},
|
||||||
|
error::{Error, Result},
|
||||||
|
mainpod::{self, calculate_id},
|
||||||
|
},
|
||||||
|
middleware::{
|
||||||
|
AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement, Value,
|
||||||
|
KEY_TYPE, SELF,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MockEmptyPod {
|
||||||
|
params: Params,
|
||||||
|
id: PodId,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_statement() -> Statement {
|
||||||
|
Statement::ValueOf(
|
||||||
|
AnchoredKey::from((SELF, KEY_TYPE)),
|
||||||
|
Value::from(PodType::Empty),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MockEmptyPod {
|
||||||
|
pub fn new_boxed(params: &Params) -> Box<dyn RecursivePod> {
|
||||||
|
let statements = [mainpod::Statement::from(type_statement())];
|
||||||
|
let id = PodId(calculate_id(&statements, params));
|
||||||
|
Box::new(Self {
|
||||||
|
params: params.clone(),
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn _verify(&self) -> Result<()> {
|
||||||
|
let statements = self
|
||||||
|
.pub_self_statements()
|
||||||
|
.into_iter()
|
||||||
|
.map(mainpod::Statement::from)
|
||||||
|
.collect_vec();
|
||||||
|
let id = PodId(calculate_id(&statements, &self.params));
|
||||||
|
if id != self.id {
|
||||||
|
return Err(Error::id_not_equal(self.id, id));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pod for MockEmptyPod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
&self.params
|
||||||
|
}
|
||||||
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
|
Ok(self._verify()?)
|
||||||
|
}
|
||||||
|
fn id(&self) -> PodId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
|
vec![type_statement()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialized_proof(&self) -> String {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RecursivePod for MockEmptyPod {
|
||||||
|
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||||
|
panic!("MockEmptyPod can't be verified in a recursive MainPod circuit");
|
||||||
|
}
|
||||||
|
fn proof(&self) -> Proof {
|
||||||
|
panic!("MockEmptyPod can't be verified in a recursive MainPod circuit");
|
||||||
|
}
|
||||||
|
fn vds_root(&self) -> Hash {
|
||||||
|
panic!("MockEmptyPod can't be verified in a recursive MainPod circuit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mock_empty_pod() {
|
||||||
|
let params = Params::default();
|
||||||
|
|
||||||
|
let empty_pod = MockEmptyPod::new_boxed(¶ms);
|
||||||
|
empty_pod.verify().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,17 +9,18 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
|
basetypes::{Proof, VerifierOnlyCircuitData},
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
mainpod::{
|
mainpod::{
|
||||||
calculate_id, extract_merkle_proofs, layout_statements, normalize_statement,
|
calculate_id, extract_merkle_proofs, layout_statements,
|
||||||
process_private_statements_operations, process_public_statements_operations, Operation,
|
process_private_statements_operations, process_public_statements_operations, Operation,
|
||||||
Statement,
|
Statement,
|
||||||
},
|
},
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, hash_str, AnchoredKey, DynError, MainPodInputs, NativePredicate, Params, Pod, PodId,
|
self, hash_str, AnchoredKey, DynError, Hash, MainPodInputs, NativePredicate, Params, Pod,
|
||||||
PodProver, Predicate, StatementArg, KEY_TYPE, SELF,
|
PodId, PodProver, Predicate, RecursivePod, StatementArg, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -27,10 +28,10 @@ pub struct MockProver {}
|
||||||
|
|
||||||
impl PodProver for MockProver {
|
impl PodProver for MockProver {
|
||||||
fn prove(
|
fn prove(
|
||||||
&mut self,
|
&self,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
inputs: MainPodInputs,
|
inputs: MainPodInputs,
|
||||||
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
) -> Result<Box<dyn RecursivePod>, Box<DynError>> {
|
||||||
Ok(Box::new(MockMainPod::new(params, inputs)?))
|
Ok(Box::new(MockMainPod::new(params, inputs)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -73,7 +74,8 @@ impl fmt::Display for MockMainPod {
|
||||||
}
|
}
|
||||||
if (i >= offset_input_main_pods)
|
if (i >= offset_input_main_pods)
|
||||||
&& (i < offset_input_statements)
|
&& (i < offset_input_statements)
|
||||||
&& ((i - offset_input_main_pods) % self.params.max_public_statements == 0)
|
&& ((i - offset_input_main_pods) % self.params.max_input_pods_public_statements
|
||||||
|
== 0)
|
||||||
{
|
{
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
|
|
@ -137,7 +139,7 @@ impl MockMainPod {
|
||||||
}
|
}
|
||||||
fn offset_input_statements(&self) -> usize {
|
fn offset_input_statements(&self) -> usize {
|
||||||
self.offset_input_main_pods()
|
self.offset_input_main_pods()
|
||||||
+ self.params.max_input_main_pods * self.params.max_public_statements
|
+ self.params.max_input_recursive_pods * self.params.max_input_pods_public_statements
|
||||||
}
|
}
|
||||||
fn offset_public_statements(&self) -> usize {
|
fn offset_public_statements(&self) -> usize {
|
||||||
self.offset_input_statements() + self.params.max_priv_statements()
|
self.offset_input_statements() + self.params.max_priv_statements()
|
||||||
|
|
@ -146,7 +148,7 @@ impl MockMainPod {
|
||||||
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
||||||
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
||||||
// value=PodType::MockMainPod`
|
// value=PodType::MockMainPod`
|
||||||
let statements = layout_statements(params, &inputs);
|
let statements = layout_statements(params, true, &inputs)?;
|
||||||
// Extract Merkle proofs and pad.
|
// Extract Merkle proofs and pad.
|
||||||
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
||||||
|
|
||||||
|
|
@ -278,20 +280,20 @@ impl MockMainPod {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MockMainPod {
|
impl Pod for MockMainPod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
&self.params
|
||||||
|
}
|
||||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
Ok(self._verify()?)
|
Ok(self._verify()?)
|
||||||
}
|
}
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
fn pub_statements(&self) -> Vec<middleware::Statement> {
|
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||||
// return the public statements, where when origin=SELF is replaced by origin=self.id()
|
self.public_statements
|
||||||
// By convention we expect the KEY_TYPE to be the first statement
|
|
||||||
self.statements
|
|
||||||
.iter()
|
.iter()
|
||||||
.skip(self.offset_public_statements())
|
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|statement| normalize_statement(&statement, self.id()))
|
.map(|st| st.try_into().expect("valid statement"))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,6 +302,18 @@ impl Pod for MockMainPod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RecursivePod for MockMainPod {
|
||||||
|
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||||
|
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||||
|
}
|
||||||
|
fn proof(&self) -> Proof {
|
||||||
|
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||||
|
}
|
||||||
|
fn vds_root(&self) -> Hash {
|
||||||
|
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
|
pub mod emptypod;
|
||||||
pub mod mainpod;
|
pub mod mainpod;
|
||||||
pub mod signedpod;
|
pub mod signedpod;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{
|
middleware::{
|
||||||
containers::Dictionary, hash_str, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId,
|
containers::Dictionary, hash_str, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId,
|
||||||
PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -111,6 +111,9 @@ impl MockSignedPod {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MockSignedPod {
|
impl Pod for MockSignedPod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
panic!("MockSignedPod doesn't have params");
|
||||||
|
}
|
||||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
Ok(self._verify()?)
|
Ok(self._verify()?)
|
||||||
}
|
}
|
||||||
|
|
@ -119,8 +122,7 @@ impl Pod for MockSignedPod {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pub_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
let id = self.id();
|
|
||||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||||
let mut kvs = self.kvs.clone();
|
let mut kvs = self.kvs.clone();
|
||||||
let key_type = Key::from(KEY_TYPE);
|
let key_type = Key::from(KEY_TYPE);
|
||||||
|
|
@ -130,7 +132,7 @@ impl Pod for MockSignedPod {
|
||||||
[(key_type, value_type), (key_signer, value_signer)]
|
[(key_type, value_type), (key_signer, value_signer)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
||||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((id, k)), v))
|
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((SELF, k)), v))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod basetypes;
|
pub mod basetypes;
|
||||||
pub mod circuits;
|
pub mod circuits;
|
||||||
|
pub mod emptypod;
|
||||||
mod error;
|
mod error;
|
||||||
pub mod mainpod;
|
pub mod mainpod;
|
||||||
pub mod mock;
|
pub mod mock;
|
||||||
|
|
@ -7,4 +8,32 @@ pub mod primitives;
|
||||||
pub mod recursion;
|
pub mod recursion;
|
||||||
pub mod signedpod;
|
pub mod signedpod;
|
||||||
|
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backends::plonky2::{
|
||||||
|
basetypes::CircuitData,
|
||||||
|
circuits::mainpod::{MainPodVerifyTarget, NUM_PUBLIC_INPUTS},
|
||||||
|
recursion::RecursiveCircuit,
|
||||||
|
},
|
||||||
|
middleware::Params,
|
||||||
|
timed,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub static DEFAULT_PARAMS: LazyLock<Params> = LazyLock::new(Params::default);
|
||||||
|
|
||||||
|
pub static STANDARD_REC_MAIN_POD_CIRCUIT_DATA: LazyLock<CircuitData> = LazyLock::new(|| {
|
||||||
|
let params = &*DEFAULT_PARAMS;
|
||||||
|
timed!(
|
||||||
|
"recursive MainPod circuit_data",
|
||||||
|
RecursiveCircuit::<MainPodVerifyTarget>::target_and_circuit_data(
|
||||||
|
params.max_input_recursive_pods,
|
||||||
|
NUM_PUBLIC_INPUTS,
|
||||||
|
params
|
||||||
|
)
|
||||||
|
.expect("calculate circuit_data")
|
||||||
|
.1
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use plonky2::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::{Proof, C, D},
|
basetypes::{C, D},
|
||||||
circuits::common::{CircuitBuilderPod, ValueTarget},
|
circuits::common::{CircuitBuilderPod, ValueTarget},
|
||||||
error::Result,
|
error::Result,
|
||||||
primitives::signature::{
|
primitives::signature::{
|
||||||
|
|
@ -31,7 +31,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
measure_gates_begin, measure_gates_end,
|
measure_gates_begin, measure_gates_end,
|
||||||
middleware::{Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F, VALUE_SIZE},
|
middleware::{Hash, Proof, RawValue, EMPTY_HASH, EMPTY_VALUE, F, VALUE_SIZE},
|
||||||
};
|
};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,2 +1,5 @@
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
pub use circuit::{InnerCircuit, RecursiveCircuit, RecursiveParams};
|
pub use circuit::{
|
||||||
|
common_data_for_recursion, new_params, new_params_padded, pad_circuit, InnerCircuit,
|
||||||
|
RecursiveCircuit, RecursiveParams, VerifiedProofTarget,
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{
|
middleware::{
|
||||||
containers::Dictionary, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId, PodSigner,
|
containers::Dictionary, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId, PodSigner,
|
||||||
PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -120,6 +120,9 @@ impl SignedPod {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for SignedPod {
|
impl Pod for SignedPod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
panic!("SignedPod doesn't have params");
|
||||||
|
}
|
||||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
Ok(self._verify().map_err(Box::new)?)
|
Ok(self._verify().map_err(Box::new)?)
|
||||||
}
|
}
|
||||||
|
|
@ -128,8 +131,7 @@ impl Pod for SignedPod {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pub_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
let id = self.id();
|
|
||||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||||
let mut kvs: HashMap<Key, Value> = self.dict.kvs().clone();
|
let mut kvs: HashMap<Key, Value> = self.dict.kvs().clone();
|
||||||
let key_type = Key::from(KEY_TYPE);
|
let key_type = Key::from(KEY_TYPE);
|
||||||
|
|
@ -139,7 +141,7 @@ impl Pod for SignedPod {
|
||||||
[(key_type, value_type), (key_signer, value_signer)]
|
[(key_type, value_type), (key_signer, value_signer)]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
||||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((id, k)), v))
|
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((SELF, k)), v))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ use serialization::{SerializedMainPod, SerializedSignedPod};
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
self, check_st_tmpl, hash_str, hash_values, AnchoredKey, Hash, Key, MainPodInputs,
|
self, check_st_tmpl, hash_str, hash_values, AnchoredKey, Hash, Key, MainPodInputs,
|
||||||
NativeOperation, NativePredicate, OperationAux, OperationType, Params, PodId, PodProver,
|
NativeOperation, NativePredicate, OperationAux, OperationType, Params, PodId, PodProver,
|
||||||
PodSigner, Predicate, Statement, StatementArg, Value, WildcardValue, KEY_TYPE, SELF,
|
PodSigner, Predicate, Statement, StatementArg, Value, WildcardValue, EMPTY_HASH, KEY_TYPE,
|
||||||
|
SELF,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod custom;
|
mod custom;
|
||||||
|
|
@ -553,7 +554,7 @@ impl MainPodBuilder {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.pod.as_ref())
|
.map(|p| p.pod.as_ref())
|
||||||
.collect_vec(),
|
.collect_vec(),
|
||||||
main_pods: &self
|
recursive_pods: &self
|
||||||
.input_main_pods
|
.input_main_pods
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.pod.as_ref())
|
.map(|p| p.pod.as_ref())
|
||||||
|
|
@ -561,6 +562,7 @@ impl MainPodBuilder {
|
||||||
statements: &statements,
|
statements: &statements,
|
||||||
operations: &operations,
|
operations: &operations,
|
||||||
public_statements: &public_statements,
|
public_statements: &public_statements,
|
||||||
|
vds_root: EMPTY_HASH, // TODO https://github.com/0xPARC/pod2/issues/249
|
||||||
};
|
};
|
||||||
let pod = prover.prove(&self.params, inputs)?;
|
let pod = prover.prove(&self.params, inputs)?;
|
||||||
|
|
||||||
|
|
@ -618,7 +620,7 @@ impl MainPodBuilder {
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(try_from = "SerializedMainPod", into = "SerializedMainPod")]
|
#[serde(try_from = "SerializedMainPod", into = "SerializedMainPod")]
|
||||||
pub struct MainPod {
|
pub struct MainPod {
|
||||||
pub pod: Box<dyn middleware::Pod>,
|
pub pod: Box<dyn middleware::RecursivePod>,
|
||||||
pub public_statements: Vec<Statement>,
|
pub public_statements: Vec<Statement>,
|
||||||
pub params: Params,
|
pub params: Params,
|
||||||
}
|
}
|
||||||
|
|
@ -898,7 +900,7 @@ pub mod tests {
|
||||||
fn test_ethdos() -> Result<()> {
|
fn test_ethdos() -> Result<()> {
|
||||||
let params = Params {
|
let params = Params {
|
||||||
max_input_signed_pods: 3,
|
max_input_signed_pods: 3,
|
||||||
max_input_main_pods: 3,
|
max_input_recursive_pods: 3,
|
||||||
max_statements: 31,
|
max_statements: 31,
|
||||||
max_signed_pod_values: 8,
|
max_signed_pod_values: 8,
|
||||||
max_public_statements: 10,
|
max_public_statements: 10,
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
frontend::{MainPod, SignedPod},
|
frontend::{MainPod, SignedPod},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, containers::Dictionary, serialization::ordered_map, AnchoredKey, Key, Params, PodId,
|
self, containers::Dictionary, serialization::ordered_map, AnchoredKey, Hash, Key, Params,
|
||||||
Statement, StatementArg, Value, SELF,
|
PodId, Statement, StatementArg, Value, EMPTY_HASH, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -45,6 +45,7 @@ pub enum MainPodType {
|
||||||
#[schemars(rename = "MainPod")]
|
#[schemars(rename = "MainPod")]
|
||||||
pub struct SerializedMainPod {
|
pub struct SerializedMainPod {
|
||||||
id: PodId,
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
public_statements: Vec<Statement>,
|
public_statements: Vec<Statement>,
|
||||||
proof: String,
|
proof: String,
|
||||||
params: Params,
|
params: Params,
|
||||||
|
|
@ -99,23 +100,23 @@ impl From<SerializedSignedPod> for SignedPod {
|
||||||
|
|
||||||
impl From<MainPod> for SerializedMainPod {
|
impl From<MainPod> for SerializedMainPod {
|
||||||
fn from(pod: MainPod) -> Self {
|
fn from(pod: MainPod) -> Self {
|
||||||
SerializedMainPod {
|
let (pod_type, vds_root) =
|
||||||
id: pod.id(),
|
if let Some(pod) = (&*pod.pod as &dyn Any).downcast_ref::<Plonky2MainPod>() {
|
||||||
proof: pod.pod.serialized_proof(),
|
(MainPodType::Main, pod.vds_root())
|
||||||
params: pod.params.clone(),
|
|
||||||
pod_type: if (&*pod.pod as &dyn Any)
|
|
||||||
.downcast_ref::<Plonky2MainPod>()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
MainPodType::Main
|
|
||||||
} else if (&*pod.pod as &dyn Any)
|
} else if (&*pod.pod as &dyn Any)
|
||||||
.downcast_ref::<MockMainPod>()
|
.downcast_ref::<MockMainPod>()
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
MainPodType::MockMain
|
(MainPodType::MockMain, EMPTY_HASH)
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
},
|
};
|
||||||
|
SerializedMainPod {
|
||||||
|
id: pod.id(),
|
||||||
|
vds_root,
|
||||||
|
proof: pod.pod.serialized_proof(),
|
||||||
|
params: pod.params.clone(),
|
||||||
|
pod_type,
|
||||||
public_statements: pod.public_statements.clone(),
|
public_statements: pod.public_statements.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,6 +143,7 @@ impl TryFrom<SerializedMainPod> for MainPod {
|
||||||
serialized.id,
|
serialized.id,
|
||||||
),
|
),
|
||||||
serialized.id,
|
serialized.id,
|
||||||
|
serialized.vds_root,
|
||||||
serialized.params.clone(),
|
serialized.params.clone(),
|
||||||
)),
|
)),
|
||||||
public_statements: serialized.public_statements,
|
public_statements: serialized.public_statements,
|
||||||
|
|
@ -369,7 +371,7 @@ mod tests {
|
||||||
let params = middleware::Params {
|
let params = middleware::Params {
|
||||||
// Currently the circuit uses random access that only supports vectors of length 64.
|
// Currently the circuit uses random access that only supports vectors of length 64.
|
||||||
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
||||||
max_input_main_pods: 1,
|
max_input_recursive_pods: 1,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -420,7 +422,7 @@ mod tests {
|
||||||
fn build_ethdos_pod() -> Result<MainPod> {
|
fn build_ethdos_pod() -> Result<MainPod> {
|
||||||
let params = Params {
|
let params = Params {
|
||||||
max_input_signed_pods: 3,
|
max_input_signed_pods: 3,
|
||||||
max_input_main_pods: 3,
|
max_input_recursive_pods: 3,
|
||||||
max_statements: 31,
|
max_statements: 31,
|
||||||
max_signed_pod_values: 8,
|
max_signed_pod_values: 8,
|
||||||
max_public_statements: 10,
|
max_public_statements: 10,
|
||||||
|
|
|
||||||
28
src/lib.rs
28
src/lib.rs
|
|
@ -1,5 +1,6 @@
|
||||||
#![allow(clippy::get_first)]
|
#![allow(clippy::get_first)]
|
||||||
#![feature(trait_upcasting)]
|
#![feature(trait_upcasting)]
|
||||||
|
#![feature(mapped_lock_guards)]
|
||||||
|
|
||||||
pub mod backends;
|
pub mod backends;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
|
@ -8,3 +9,30 @@ pub mod middleware;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod examples;
|
pub mod examples;
|
||||||
|
|
||||||
|
#[cfg(feature = "time")]
|
||||||
|
pub mod time_macros {
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! timed {
|
||||||
|
($ctx:expr, $exp:expr) => {{
|
||||||
|
let start = std::time::Instant::now();
|
||||||
|
let res = $exp;
|
||||||
|
println!(
|
||||||
|
"timed \"{}\": {:?}",
|
||||||
|
$ctx,
|
||||||
|
std::time::Instant::now() - start
|
||||||
|
);
|
||||||
|
res
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "time"))]
|
||||||
|
pub mod time_macros {
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! timed {
|
||||||
|
($ctx:expr, $exp:expr) => {{
|
||||||
|
$exp
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,30 @@
|
||||||
// TODO: Update this doc
|
//! This file exposes the imported backend dependent basetypes as middleware types, taking them
|
||||||
//! This file exposes the backend dependent basetypes as middleware types,
|
//! from the feature-enabled backend.
|
||||||
//! taking them from the feature-enabled backend.
|
|
||||||
//!
|
//!
|
||||||
//! This is done in order to avoid inconsistencies where a type or parameter is
|
//! This is done in order to avoid inconsistencies where a type or parameter is defined in the
|
||||||
//! defined in the middleware to have certain carachteristic and later in the
|
//! middleware to have certain carachteristic and later in the backend it gets used differently.
|
||||||
//! backend it gets used differently. The idea is that those types and
|
//! The idea is that those types and parameters (eg. lengths) have a single source of truth in the
|
||||||
//! parameters (eg. lengths) have a single source of truth in the code; and in
|
//! code; and in the case of the "base types" this is determined by the backend being used under
|
||||||
//! the case of the "base types" this is determined by the backend being used
|
//! the hood, not by a choice of the middleware parameters.
|
||||||
//! under the hood, not by a choice of the middleware parameters.
|
|
||||||
//!
|
//!
|
||||||
//! The idea with this approach, is that the frontend & middleware should not
|
//! The idea with this approach, is that the frontend & middleware should not need to import the
|
||||||
//! need to import the proving library used by the backend (eg. plonky2,
|
//! proving library used by the backend (eg. plonky2, plonky3, etc).
|
||||||
//! plonky3, etc).
|
|
||||||
//!
|
//!
|
||||||
//! For example, the `Hash` and `Value` types are types belonging at the
|
//! For example, the `Hash` and `Value` types are types belonging at the middleware, and is the
|
||||||
//! middleware, and is the middleware who reasons about them, but depending on
|
//! middleware who reasons about them, but depending on the backend being used, the `Hash` and
|
||||||
//! the backend being used, the `Hash` and `Value` types will have different
|
//! `Value` types will have different sizes. So it's the backend being used who actually defines
|
||||||
//! sizes. So it's the backend being used who actually defines their nature
|
//! their nature under the hood. For example with a plonky2 backend, these types will have a length
|
||||||
//! under the hood. For example with a plonky2 backend, these types will have a
|
//! of 4 field elements, whereas with a plonky3 backend they will have a length of 8 field
|
||||||
//! length of 4 field elements, whereas with a plonky3 backend they will have a
|
//! eleements.
|
||||||
//! length of 8 field eleements.
|
|
||||||
//!
|
//!
|
||||||
//! Note that his approach does not introduce new traits or abstract code,
|
//! Note that his approach does not introduce new traits or abstract code, just makes use of rust
|
||||||
//! just makes use of rust features to define 'base types' that are being used
|
//! features to define 'base types' that are being used in the middleware.
|
||||||
//! in the middleware.
|
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
//! NOTE (TMP): current implementation still uses plonky2 in the middleware for
|
//! NOTE (TMP): current implementation still uses plonky2 in the middleware for u64/i64 to F
|
||||||
//! u64/i64 to F conversion. Eventually we will do those conversions through the
|
//! conversion. Eventually we will do those conversions through the approach described in this
|
||||||
//! approach described in this file, removing the imports of plonky2 in the
|
//! file, removing the imports of plonky2 in the middleware.
|
||||||
//! middleware.
|
|
||||||
//! TODO: Update this doc
|
|
||||||
|
|
||||||
/// Value, Hash and F are imported based on 'features'. For example by default
|
|
||||||
/// we use the 'plonky2' feature, but it could be used a 'plonky3' feature, so
|
|
||||||
/// then the Value, Hash and F types would come from the plonky3 backend.
|
|
||||||
// #[cfg(feature = "backend_plonky2")]
|
|
||||||
// pub use crate::backends::plonky2::basetypes::{
|
|
||||||
// hash_fields, hash_str, hash_value, Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F, HASH_SIZE,
|
|
||||||
// SELF_ID_HASH, VALUE_SIZE,
|
|
||||||
// };
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{Ord, Ordering},
|
cmp::{Ord, Ordering},
|
||||||
fmt,
|
fmt,
|
||||||
|
|
@ -47,10 +32,7 @@ use std::{
|
||||||
|
|
||||||
use hex::{FromHex, FromHexError};
|
use hex::{FromHex, FromHexError};
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
field::{
|
field::types::{Field, PrimeField64},
|
||||||
goldilocks_field::GoldilocksField,
|
|
||||||
types::{Field, PrimeField64},
|
|
||||||
},
|
|
||||||
hash::poseidon::PoseidonHash,
|
hash::poseidon::PoseidonHash,
|
||||||
plonk::config::Hasher,
|
plonk::config::Hasher,
|
||||||
};
|
};
|
||||||
|
|
@ -58,11 +40,14 @@ use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::serialization::*;
|
use super::serialization::*;
|
||||||
|
// Plonky2 specific types.
|
||||||
|
// Value, Hash, F and other types are imported based on 'features'. For example by default we use
|
||||||
|
// theg'plonky2' feature, but it could be used a 'plonky3' feature, so then the Value, Hash and F
|
||||||
|
// types would come from the plonky3 backend.
|
||||||
|
#[cfg(feature = "backend_plonky2")]
|
||||||
|
pub use crate::backends::plonky2::basetypes::*;
|
||||||
use crate::middleware::{Params, ToFields, Value};
|
use crate::middleware::{Params, ToFields, Value};
|
||||||
|
|
||||||
/// F is the native field we use everywhere. Currently it's Goldilocks from plonky2
|
|
||||||
pub type F = GoldilocksField;
|
|
||||||
|
|
||||||
pub const HASH_SIZE: usize = 4;
|
pub const HASH_SIZE: usize = 4;
|
||||||
pub const VALUE_SIZE: usize = 4;
|
pub const VALUE_SIZE: usize = 4;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -558,8 +558,10 @@ pub enum PodType {
|
||||||
None = 0,
|
None = 0,
|
||||||
MockSigned = 1,
|
MockSigned = 1,
|
||||||
MockMain = 2,
|
MockMain = 2,
|
||||||
Signed = 3,
|
MockEmpty = 3,
|
||||||
Main = 4,
|
Signed = 4,
|
||||||
|
Main = 5,
|
||||||
|
Empty = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PodType {
|
impl fmt::Display for PodType {
|
||||||
|
|
@ -568,45 +570,56 @@ impl fmt::Display for PodType {
|
||||||
PodType::None => write!(f, "None"),
|
PodType::None => write!(f, "None"),
|
||||||
PodType::MockSigned => write!(f, "MockSigned"),
|
PodType::MockSigned => write!(f, "MockSigned"),
|
||||||
PodType::MockMain => write!(f, "MockMain"),
|
PodType::MockMain => write!(f, "MockMain"),
|
||||||
|
PodType::MockEmpty => write!(f, "MockEmpty"),
|
||||||
PodType::Signed => write!(f, "Signed"),
|
PodType::Signed => write!(f, "Signed"),
|
||||||
PodType::Main => write!(f, "Main"),
|
PodType::Main => write!(f, "Main"),
|
||||||
|
PodType::Empty => write!(f, "Empty"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Hash)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub max_input_signed_pods: usize,
|
pub max_input_signed_pods: usize,
|
||||||
pub max_input_main_pods: usize,
|
pub max_input_recursive_pods: usize,
|
||||||
|
pub max_input_pods_public_statements: usize,
|
||||||
pub max_statements: usize,
|
pub max_statements: usize,
|
||||||
pub max_signed_pod_values: usize,
|
pub max_signed_pod_values: usize,
|
||||||
pub max_public_statements: usize,
|
pub max_public_statements: usize,
|
||||||
// Number of public statements to hash to calculate the id. Must be equal or greater than
|
|
||||||
// `max_public_statements`.
|
|
||||||
pub num_public_statements_id: usize,
|
|
||||||
pub max_statement_args: usize,
|
|
||||||
pub max_operation_args: usize,
|
pub max_operation_args: usize,
|
||||||
// max number of custom predicates batches that a MainPod can use
|
// max number of custom predicates batches that a MainPod can use
|
||||||
pub max_custom_predicate_batches: usize,
|
pub max_custom_predicate_batches: usize,
|
||||||
// max number of operations using custom predicates that can be verified in the MainPod
|
// max number of operations using custom predicates that can be verified in the MainPod
|
||||||
pub max_custom_predicate_verifications: usize,
|
pub max_custom_predicate_verifications: usize,
|
||||||
// max number of statements that can be ANDed or ORed together
|
|
||||||
// in a custom predicate
|
|
||||||
pub max_custom_predicate_arity: usize,
|
|
||||||
pub max_custom_predicate_wildcards: usize,
|
pub max_custom_predicate_wildcards: usize,
|
||||||
pub max_custom_batch_size: usize,
|
|
||||||
// maximum number of merkle proofs
|
// maximum number of merkle proofs
|
||||||
pub max_merkle_proofs: usize,
|
pub max_merkle_proofs: usize,
|
||||||
// maximum depth for merkle tree gadget
|
// maximum depth for merkle tree gadget
|
||||||
pub max_depth_mt_gadget: usize,
|
pub max_depth_mt_gadget: usize,
|
||||||
|
//
|
||||||
|
// The following parameters define how a pod id is calculated. They need to be the same among
|
||||||
|
// different circuits to be compatible in their verification.
|
||||||
|
//
|
||||||
|
// Number of public statements to hash to calculate the id. Must be equal or greater than
|
||||||
|
// `max_public_statements`.
|
||||||
|
pub num_public_statements_id: usize,
|
||||||
|
pub max_statement_args: usize,
|
||||||
|
//
|
||||||
|
// The following parameters define how a custom predicate batch id is calculated.
|
||||||
|
//
|
||||||
|
// max number of statements that can be ANDed or ORed together
|
||||||
|
// in a custom predicate
|
||||||
|
pub max_custom_predicate_arity: usize,
|
||||||
|
pub max_custom_batch_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Params {
|
impl Default for Params {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
max_input_signed_pods: 3,
|
max_input_signed_pods: 3,
|
||||||
max_input_main_pods: 3,
|
max_input_recursive_pods: 2,
|
||||||
|
max_input_pods_public_statements: 10,
|
||||||
max_statements: 20,
|
max_statements: 20,
|
||||||
max_signed_pod_values: 8,
|
max_signed_pod_values: 8,
|
||||||
max_public_statements: 10,
|
max_public_statements: 10,
|
||||||
|
|
@ -661,6 +674,16 @@ impl Params {
|
||||||
self.max_custom_batch_size * self.custom_predicate_size()
|
self.max_custom_batch_size * self.custom_predicate_size()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parameters that define how the id is calculated
|
||||||
|
pub fn id_params(&self) -> Vec<usize> {
|
||||||
|
vec![
|
||||||
|
self.num_public_statements_id,
|
||||||
|
self.max_statement_args,
|
||||||
|
self.max_custom_predicate_arity,
|
||||||
|
self.max_custom_batch_size,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print_serialized_sizes(&self) {
|
pub fn print_serialized_sizes(&self) {
|
||||||
println!("Parameter sizes:");
|
println!("Parameter sizes:");
|
||||||
println!(
|
println!(
|
||||||
|
|
@ -678,12 +701,39 @@ impl Params {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replace references to SELF by `self_id` in anchored keys of the statement.
|
||||||
|
pub fn normalize_statement(statement: &Statement, self_id: PodId) -> Statement {
|
||||||
|
let predicate = statement.predicate();
|
||||||
|
let args = statement
|
||||||
|
.args()
|
||||||
|
.iter()
|
||||||
|
.map(|sa| match &sa {
|
||||||
|
StatementArg::Key(AnchoredKey { pod_id, key }) if *pod_id == SELF => {
|
||||||
|
StatementArg::Key(AnchoredKey::new(self_id, key.clone()))
|
||||||
|
}
|
||||||
|
_ => sa.clone(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Statement::from_args(predicate, args).expect("statement was valid before normalization")
|
||||||
|
}
|
||||||
|
|
||||||
pub type DynError = dyn std::error::Error + Send + Sync;
|
pub type DynError = dyn std::error::Error + Send + Sync;
|
||||||
|
|
||||||
pub trait Pod: fmt::Debug + DynClone + Any {
|
pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
|
fn params(&self) -> &Params;
|
||||||
fn verify(&self) -> Result<(), Box<DynError>>;
|
fn verify(&self) -> Result<(), Box<DynError>>;
|
||||||
fn id(&self) -> PodId;
|
fn id(&self) -> PodId;
|
||||||
fn pub_statements(&self) -> Vec<Statement>;
|
/// Statements as internally generated, where self-referencing arguments use SELF in the
|
||||||
|
/// anchored key. The serialization of these statements is used to calculate the id.
|
||||||
|
fn pub_self_statements(&self) -> Vec<Statement>;
|
||||||
|
/// Normalized statements, where self-referencing arguments use the pod id instead of SELF in
|
||||||
|
/// the anchored key.
|
||||||
|
fn pub_statements(&self) -> Vec<Statement> {
|
||||||
|
self.pub_self_statements()
|
||||||
|
.into_iter()
|
||||||
|
.map(|statement| normalize_statement(&statement, self.id()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
/// Extract key-values from ValueOf public statements
|
/// Extract key-values from ValueOf public statements
|
||||||
fn kvs(&self) -> HashMap<AnchoredKey, Value> {
|
fn kvs(&self) -> HashMap<AnchoredKey, Value> {
|
||||||
self.pub_statements()
|
self.pub_statements()
|
||||||
|
|
@ -708,9 +758,21 @@ pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
fn serialized_proof(&self) -> String;
|
fn serialized_proof(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Clone for Box<dyn SignedPod>
|
// impl Clone for Box<dyn Pod>
|
||||||
dyn_clone::clone_trait_object!(Pod);
|
dyn_clone::clone_trait_object!(Pod);
|
||||||
|
|
||||||
|
/// Trait for pods that are generated with a plonky2 circuit and that can be verified by a
|
||||||
|
/// recursive MainPod circuit. A Pod implementing this trait does not necesarilly come from
|
||||||
|
/// recursion: for example an introduction Pod in general is not recursive.
|
||||||
|
pub trait RecursivePod: Pod {
|
||||||
|
fn verifier_data(&self) -> VerifierOnlyCircuitData;
|
||||||
|
fn proof(&self) -> Proof;
|
||||||
|
fn vds_root(&self) -> Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl Clone for Box<dyn RecursivePod>
|
||||||
|
dyn_clone::clone_trait_object!(RecursivePod);
|
||||||
|
|
||||||
pub trait PodSigner {
|
pub trait PodSigner {
|
||||||
fn sign(
|
fn sign(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -719,19 +781,24 @@ pub trait PodSigner {
|
||||||
) -> Result<Box<dyn Pod>, Box<DynError>>;
|
) -> Result<Box<dyn Pod>, Box<DynError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Delete once we have a fully working EmptyPod and a dumb SignedPod
|
||||||
|
// https://github.com/0xPARC/pod2/issues/246
|
||||||
/// This is a filler type that fulfills the Pod trait and always verifies. It's empty. This
|
/// This is a filler type that fulfills the Pod trait and always verifies. It's empty. This
|
||||||
/// can be used to simulate padding in a circuit.
|
/// can be used to simulate padding in a circuit.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NonePod {}
|
pub struct NonePod {}
|
||||||
|
|
||||||
impl Pod for NonePod {
|
impl Pod for NonePod {
|
||||||
|
fn params(&self) -> &Params {
|
||||||
|
panic!("NonePod doesn't have params");
|
||||||
|
}
|
||||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
PodId(EMPTY_HASH)
|
PodId(EMPTY_HASH)
|
||||||
}
|
}
|
||||||
fn pub_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialized_proof(&self) -> String {
|
||||||
|
|
@ -742,20 +809,21 @@ impl Pod for NonePod {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct MainPodInputs<'a> {
|
pub struct MainPodInputs<'a> {
|
||||||
pub signed_pods: &'a [&'a dyn Pod],
|
pub signed_pods: &'a [&'a dyn Pod],
|
||||||
pub main_pods: &'a [&'a dyn Pod],
|
pub recursive_pods: &'a [&'a dyn RecursivePod],
|
||||||
pub statements: &'a [Statement],
|
pub statements: &'a [Statement],
|
||||||
pub operations: &'a [Operation],
|
pub operations: &'a [Operation],
|
||||||
/// Statements that need to be made public (they can come from input pods or input
|
/// Statements that need to be made public (they can come from input pods or input
|
||||||
/// statements)
|
/// statements)
|
||||||
pub public_statements: &'a [Statement],
|
pub public_statements: &'a [Statement],
|
||||||
|
pub vds_root: Hash, // TODO: Figure out if we use Hash or a Map here https://github.com/0xPARC/pod2/issues/249
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PodProver {
|
pub trait PodProver {
|
||||||
fn prove(
|
fn prove(
|
||||||
&mut self,
|
&self,
|
||||||
params: &Params,
|
params: &Params,
|
||||||
inputs: MainPodInputs,
|
inputs: MainPodInputs,
|
||||||
) -> Result<Box<dyn Pod>, Box<DynError>>;
|
) -> Result<Box<dyn RecursivePod>, Box<DynError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToFields {
|
pub trait ToFields {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue