From 816767c6315eef3255bbfdc735ae28854d688ceb Mon Sep 17 00:00:00 2001 From: Steven Gu Date: Wed, 26 Apr 2023 15:13:42 +0800 Subject: [PATCH] Add Challenge API. --- src/challenges.rs | 52 +++++++++++++++++++++++++++ src/gadgets/mpt_update.rs | 8 +++-- src/lib.rs | 65 +++++++++++++++++++-------------- src/mpt_table.rs | 76 +++++++++++++++++++++------------------ src/operation.rs | 24 +++++++------ 5 files changed, 149 insertions(+), 76 deletions(-) create mode 100644 src/challenges.rs diff --git a/src/challenges.rs b/src/challenges.rs new file mode 100644 index 00000000..d568afb9 --- /dev/null +++ b/src/challenges.rs @@ -0,0 +1,52 @@ +use halo2_proofs::{ + arithmetic::FieldExt, + circuit::{Layouter, Value}, + plonk::{Challenge, ConstraintSystem, Expression, FirstPhase, VirtualCells}, +}; + +#[derive(Clone, Copy, Debug)] +pub struct Challenges { + mpt_word: T, +} + +impl Challenges { + pub fn construct(meta: &mut ConstraintSystem) -> Self { + Self { + mpt_word: meta.challenge_usable_after(FirstPhase), + } + } + + /// Return `Expression` of challenges from `ConstraintSystem`. + pub fn exprs(&self, meta: &mut ConstraintSystem) -> Challenges> { + let [mpt_word] = query_expression(meta, |meta| { + [self.mpt_word].map(|challenge| meta.query_challenge(challenge)) + }); + + Challenges { mpt_word } + } + + /// Return `Value` of challenges from `Layouter`. + pub fn values(&self, layouter: &impl Layouter) -> Challenges> { + Challenges { + mpt_word: layouter.get_challenge(self.mpt_word), + } + } +} + +impl Challenges { + pub fn mpt_word(&self) -> T { + self.mpt_word.clone() + } +} + +fn query_expression( + meta: &mut ConstraintSystem, + mut f: impl FnMut(&mut VirtualCells) -> T, +) -> T { + let mut expr = None; + meta.create_gate("Query expression", |meta| { + expr = Some(f(meta)); + Some(Expression::Constant(F::from(0))) + }); + expr.unwrap() +} diff --git a/src/gadgets/mpt_update.rs b/src/gadgets/mpt_update.rs index ff0aafbe..bc72c39c 100644 --- a/src/gadgets/mpt_update.rs +++ b/src/gadgets/mpt_update.rs @@ -5,6 +5,7 @@ use super::{ poseidon::PoseidonLookup, }; use crate::{ + challenges::Challenges, constraint_builder::{AdviceColumn, ConstraintBuilder, Query, SelectorColumn}, serde::SMTTrace, types::Proof, @@ -13,7 +14,7 @@ use crate::{ use ethers_core::k256::elliptic_curve::PrimeField; use ethers_core::types::Address; use halo2_proofs::{ - arithmetic::FieldExt, circuit::Region, halo2curves::bn256::Fr, plonk::ConstraintSystem, + arithmetic::FieldExt, circuit::{Region, Value}, halo2curves::bn256::Fr, plonk::{ConstraintSystem, Expression}, }; use strum::IntoEnumIterator; use strum_macros::EnumIter; @@ -104,6 +105,7 @@ impl MptUpdateConfig { fn configure( cs: &mut ConstraintSystem, cb: &mut ConstraintBuilder, + challenges: &Challenges>, poseidon: &impl PoseidonLookup, key_bit: &impl KeyBitLookup, rlc: &impl RlcLookup, @@ -178,8 +180,8 @@ impl MptUpdateConfig { config } - fn assign(&self, region: &mut Region<'_, Fr>, updates: &[SMTTrace]) { - let randomness = Fr::from(123123u64); // TODOOOOOOO + fn assign(&self, region: &mut Region<'_, Fr>, updates: &[SMTTrace], challenges: &Challenges>) { + let randomness = challenges.mpt_word(); let mut offset = 0; for update in updates { diff --git a/src/lib.rs b/src/lib.rs index d44bd219..f9fd2ae5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub use crate::serde::{Hash, Row, RowDeError}; +mod challenges; mod constraint_builder; mod eth; mod gadgets; @@ -25,7 +26,9 @@ mod util; pub mod operation; pub mod serde; +use challenges::Challenges; use eth::StorageGadget; +use halo2_proofs::circuit::Value; use hash_circuit::hash::PoseidonHashTable; /// re-export required namespace from depened poseidon hash circuit pub use hash_circuit::{hash, poseidon}; @@ -155,7 +158,7 @@ impl SimpleTrie { } impl Circuit for SimpleTrie { - type Config = SimpleTrieConfig; + type Config = (SimpleTrieConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -186,20 +189,24 @@ impl Circuit for SimpleTrie { layer.get_free_cols(), Some(layer.get_root_indexs()), ); + let challenges = Challenges::construct(meta); let cst = meta.fixed_column(); meta.enable_constant(cst); - SimpleTrieConfig { - layer, - padding, - mpt, - } + ( + SimpleTrieConfig { + layer, + padding, + mpt, + }, + challenges, + ) } fn synthesize( &self, - config: Self::Config, + (config, _challenges): Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { layouter.assign_region( @@ -414,10 +421,10 @@ impl EthTrieConfig { meta: &mut ConstraintSystem, mpt_tbl: [Column; 7], hash_tbl: [Column; 5], - randomness: Expression, + challenges: Challenges>, ) -> Self { let mut lite_cfg = Self::configure_base(meta, hash_tbl); - let mpt_tbl = MPTTable::configure(meta, mpt_tbl, randomness); + let mpt_tbl = MPTTable::configure(meta, mpt_tbl, challenges.mpt_word()); let layer = &lite_cfg.layer; let layer_exported = layer.exported_cols(0); let gadget_ind = layer.get_gadget_index(); @@ -444,14 +451,14 @@ impl EthTrieConfig { pub fn load_mpt_table<'d, Fp: Hashable>( &self, layouter: &mut impl Layouter, - randomness: Option, + challenge: Option>, ops: impl IntoIterator>, tbl_tips: impl IntoIterator, rows: usize, ) -> Result<(), Error> { let mpt_entries = tbl_tips.into_iter().zip(ops).map(|(proof_type, op)| { - if let Some(rand) = randomness { - MPTEntry::from_op(proof_type, op, rand) + if let Some(challenge) = challenge { + MPTEntry::from_op(proof_type, op, challenge) } else { MPTEntry::from_op_no_base(proof_type, op) } @@ -841,7 +848,7 @@ impl CommitmentIndexs { /// get commitment for lite circuit (no mpt) pub fn new() -> Self { let mut cs: ConstraintSystem = Default::default(); - let config = EthTrieCircuit::<_, true>::configure(&mut cs); + let config = EthTrieCircuit::<_, true>::configure(&mut cs).0; let trie_circuit_indexs = config.hash_tbl.commitment_index(); @@ -856,7 +863,7 @@ impl CommitmentIndexs { /// get commitment for full circuit pub fn new_full_circuit() -> Self { let mut cs: ConstraintSystem = Default::default(); - let config = EthTrieCircuit::<_, false>::configure(&mut cs); + let config = EthTrieCircuit::<_, false>::configure(&mut cs).0; let trie_circuit_indexs = config.hash_tbl.commitment_index(); let mpt_table_start = config @@ -877,10 +884,8 @@ impl CommitmentIndexs { } } -const TEMP_RANDOMNESS: u64 = 1; - impl Circuit for EthTrieCircuit { - type Config = EthTrieConfig; + type Config = (EthTrieConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -892,19 +897,24 @@ impl Circuit for EthTrieCircuit { } fn configure(meta: &mut ConstraintSystem) -> Self::Config { - if LITE { - EthTrieConfig::configure_lite(meta) - } else { - let base = [0; 7].map(|_| meta.advice_column()); - let hash_tbl = [0; 5].map(|_| meta.advice_column()); - let randomness = Expression::Constant(Fp::from(get_rand_base())); - EthTrieConfig::configure_sub(meta, base, hash_tbl, randomness) - } + let challenges = Challenges::construct(meta); + + ( + if LITE { + EthTrieConfig::configure_lite(meta) + } else { + let base = [0; 7].map(|_| meta.advice_column()); + let hash_tbl = [0; 5].map(|_| meta.advice_column()); + let challenges = challenges.exprs(meta); + EthTrieConfig::configure_sub(meta, base, hash_tbl, challenges) + }, + challenges, + ) } fn synthesize( &self, - config: Self::Config, + (config, challenges): Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { config.dev_load_hash_table( @@ -916,9 +926,10 @@ impl Circuit for EthTrieCircuit { if LITE { Ok(()) } else { + let mpt_word = challenges.values(&layouter).mpt_word(); config.load_mpt_table( &mut layouter, - Some(Fp::from(get_rand_base())), + Some(mpt_word), self.ops.as_slice(), self.mpt_table.iter().copied(), self.calcs, diff --git a/src/mpt_table.rs b/src/mpt_table.rs index d548996d..a0e6ad8f 100644 --- a/src/mpt_table.rs +++ b/src/mpt_table.rs @@ -253,7 +253,7 @@ pub enum MPTProofType { #[derive(Clone, Debug)] pub(crate) struct MPTEntry { proof_type: MPTProofType, - base: [Option; 7], + base: [Option>; 7], storage_key: KeyValue, new_value: KeyValue, old_value: KeyValue, @@ -262,7 +262,7 @@ pub(crate) struct MPTEntry { impl MPTEntry { // detect proof type from op data itself, just mocking, // not always correct - pub fn mock_from_op(op: &AccountOp, randomness: F) -> Self { + pub fn mock_from_op(op: &AccountOp, randomness: Value) -> Self { if op.state_trie.is_some() { return if op.store_after.is_none() && op.store_before.is_none() { Self::from_op(MPTProofType::StorageDoesNotExist, op, randomness) @@ -312,9 +312,9 @@ impl MPTEntry { Self { proof_type, base: [ - Some(op.address), + Some(Value::known(op.address)), None, - Some(F::from(proof_type as u64)), + Some(Value::known(F::from(proof_type as u64))), None, None, None, @@ -326,45 +326,53 @@ impl MPTEntry { } } - pub fn from_op(proof_type: MPTProofType, op: &AccountOp, randomness: F) -> Self { + pub fn from_op(proof_type: MPTProofType, op: &AccountOp, randomness: Value) -> Self { let mut ret = Self::from_op_no_base(proof_type, op); - let (old_value_f, new_value_f) = match proof_type { + let (old_value, new_value) = match proof_type { MPTProofType::NonceChanged => ( - op.account_before - .as_ref() - .map(|acc| acc.nonce) - .unwrap_or_default(), - op.account_after - .as_ref() - .map(|acc| acc.nonce) - .unwrap_or_default(), + Value::known( + op.account_before + .as_ref() + .map(|acc| acc.nonce) + .unwrap_or_default(), + ), + Value::known( + op.account_after + .as_ref() + .map(|acc| acc.nonce) + .unwrap_or_default(), + ), ), MPTProofType::BalanceChanged => ( - op.account_before - .as_ref() - .map(|acc| acc.balance) - .unwrap_or_default(), - op.account_after - .as_ref() - .map(|acc| acc.balance) - .unwrap_or_default(), + Value::known( + op.account_before + .as_ref() + .map(|acc| acc.balance) + .unwrap_or_default(), + ), + Value::known( + op.account_after + .as_ref() + .map(|acc| acc.balance) + .unwrap_or_default(), + ), ), MPTProofType::StorageChanged | MPTProofType::CodeHashExists => ( ret.old_value.u8_rlc(randomness), ret.new_value.u8_rlc(randomness), ), - _ => (F::zero(), F::zero()), + _ => (Value::known(F::zero()), Value::known(F::zero())), }; ret.base = [ ret.base[0], Some(ret.storage_key.u8_rlc(randomness)), ret.base[2], - Some(op.account_root()), - Some(op.account_root_before()), - Some(new_value_f), - Some(old_value_f), + Some(Value::known(op.account_root())), + Some(Value::known(op.account_root_before())), + Some(new_value), + Some(old_value), ]; ret @@ -382,12 +390,12 @@ impl MPTEntry { ret.base = [ ret.base[0], - store_key, + store_key.map(Value::known), ret.base[1], - Some(op.account_root()), - Some(op.account_root_before()), - Some(new_value_f), - Some(old_value_f), + Some(Value::known(op.account_root())), + Some(Value::known(op.account_root_before())), + Some(Value::known(new_value_f)), + Some(Value::known(old_value_f)), ]; ret @@ -535,9 +543,7 @@ impl MPTTable { )?; } - let base_entries = entry - .base - .map(|entry| entry.map(Value::known).unwrap_or_else(Value::unknown)); + let base_entries = entry.base.map(|entry| entry.unwrap_or_else(Value::unknown)); for (val, col) in base_entries.into_iter().zip([ config.address, diff --git a/src/operation.rs b/src/operation.rs index fe85703c..26ef969a 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -2,7 +2,7 @@ use super::{eth, serde, HashType}; use crate::hash::Hashable; -use halo2_proofs::arithmetic::FieldExt; +use halo2_proofs::{arithmetic::FieldExt, circuit::Value}; use num_bigint::BigUint; use std::cmp::Ordering; use std::convert::TryFrom; @@ -507,23 +507,25 @@ impl KeyValue { self.data.2 } /// obtain the linear combination of two field - pub fn lc(&self, randomness: Fp) -> Fp { - self.data.0 + self.data.1 * randomness + pub fn lc(&self, randomness: Value) -> Value { + randomness.map(|rand| self.data.0 + self.data.1 * rand) } /// obtain the linear combination of the value, in byte represent, which /// is common used in zkevm circuit /// the u256 is represented by le bytes and combined with randomness 1, o, o^2 ... o^31 on each /// and we calculate it from be represent - pub fn u8_rlc(&self, randomness: Fp) -> Fp { + pub fn u8_rlc(&self, randomness: Value) -> Value { let u128_hi = self.data.0.get_lower_128(); let u128_lo = self.data.1.get_lower_128(); - u128_hi - .to_be_bytes() - .into_iter() - .chain(u128_lo.to_be_bytes()) - .map(|bt| Fp::from(bt as u64)) - .reduce(|acc, f| acc * randomness + f) - .expect("not empty") + randomness.map(|rand| { + u128_hi + .to_be_bytes() + .into_iter() + .chain(u128_lo.to_be_bytes()) + .map(|bt| Fp::from(bt as u64)) + .reduce(|acc, f| acc * rand + f) + .expect("not empty") + }) } /// obtain the first limb pub fn limb_0(&self) -> Fp {