-
Notifications
You must be signed in to change notification settings - Fork 841
MPT initial #560
MPT initial #560
Changes from all commits
29627dd
67c214e
75c5bc4
8c5aa63
9a69643
dd9f408
3d9f3a1
0a47f08
cd10057
d69ebf9
cd2cdc1
92fb3b4
b6ad5ee
8091156
2cd8d15
12e29cb
9c0c058
bc0cb33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,8 @@ members = [ | |
| "eth-types", | ||
| "external-tracer", | ||
| "mock", | ||
| "prover" | ||
| "prover", | ||
| "mpt" | ||
| ] | ||
|
|
||
| [patch.crates-io] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| [package] | ||
| name = "mpt" | ||
| version = "0.1.0" | ||
| edition = "2018" | ||
|
|
||
| [dependencies] | ||
| halo2_proofs = { version = "0.1.0-beta.1" } | ||
| itertools = "0.10.1" | ||
| num-bigint = "0.4.2" | ||
| num-traits = "0.2.14" | ||
| plotters = { version = "0.3.0", optional = true } | ||
| eth-types = { path = "../eth-types" } | ||
| lazy_static = "1.4" | ||
| keccak256 = { path = "../keccak256"} | ||
| serde = { version = "1.0", features = ["derive"] } | ||
| serde_json = "1.0" | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| use halo2_proofs::{ | ||
| plonk::{Advice, Column, ConstraintSystem, Expression, Fixed}, | ||
| poly::Rotation, | ||
| }; | ||
| use eth_types::Field; | ||
| use std::marker::PhantomData; | ||
|
|
||
| use crate::{ | ||
| helpers::get_is_extension_node, | ||
| param::{KECCAK_INPUT_WIDTH, KECCAK_OUTPUT_WIDTH, IS_BRANCH_S_PLACEHOLDER_POS, IS_BRANCH_C_PLACEHOLDER_POS, RLP_NUM}, mpt::MainCols, | ||
| }; | ||
|
|
||
| #[derive(Clone, Debug)] | ||
| pub(crate) struct BranchHashInParentConfig<F> { | ||
| _marker: PhantomData<F>, | ||
| } | ||
|
|
||
| impl<F: Field> BranchHashInParentConfig<F> { | ||
| pub fn configure( | ||
| meta: &mut ConstraintSystem<F>, | ||
| inter_root: Column<Advice>, | ||
| not_first_level: Column<Advice>, | ||
| q_not_first: Column<Fixed>, | ||
| is_account_leaf_in_added_branch: Column<Advice>, | ||
| is_last_branch_child: Column<Advice>, | ||
| s_main: MainCols, | ||
| mod_node_hash_rlc: Column<Advice>, | ||
| acc: Column<Advice>, | ||
| acc_mult: Column<Advice>, | ||
| keccak_table: [Column<Fixed>; KECCAK_INPUT_WIDTH + KECCAK_OUTPUT_WIDTH], | ||
| is_s: bool, | ||
| ) -> Self { | ||
| let config = BranchHashInParentConfig { _marker: PhantomData, }; | ||
| let one = Expression::Constant(F::from(1_u64)); | ||
|
|
||
| meta.lookup_any( | ||
| "account first level branch hash - compared to root", | ||
| |meta| { | ||
| let mut constraints = vec![]; | ||
| let q_not_first = meta.query_fixed(q_not_first, Rotation::cur()); | ||
| let not_first_level = meta.query_advice(not_first_level, Rotation::cur()); | ||
|
|
||
| let is_last_branch_child = meta.query_advice(is_last_branch_child, Rotation::cur()); | ||
|
|
||
| // TODO: acc currently doesn't have branch ValueNode info (which 128 if nil) | ||
| let acc = meta.query_advice(acc, Rotation::cur()); | ||
| let c128 = Expression::Constant(F::from(128)); | ||
| let mult = meta.query_advice(acc_mult, Rotation::cur()); | ||
| let branch_acc = acc + c128 * mult; | ||
|
|
||
| let root = meta.query_advice(inter_root, Rotation::cur()); | ||
|
|
||
| constraints.push(( | ||
| q_not_first.clone() | ||
| * is_last_branch_child.clone() | ||
| * (one.clone() - not_first_level.clone()) | ||
| * branch_acc, // TODO: replace with acc once ValueNode is added | ||
| meta.query_fixed(keccak_table[0], Rotation::cur()), | ||
| )); | ||
| let keccak_table_i = meta.query_fixed(keccak_table[1], Rotation::cur()); | ||
| constraints.push(( | ||
| q_not_first * is_last_branch_child * (one.clone() - not_first_level) * root, | ||
| keccak_table_i, | ||
| )); | ||
|
|
||
| constraints | ||
| }, | ||
| ); | ||
|
|
||
| // Check whether hash of a branch is in parent branch. | ||
| // Check if (accumulated_s(c)_rlc, hash1, hash2, hash3, hash4) is in keccak | ||
| // table, where hash1, hash2, hash3, hash4 are stored in the previous | ||
| // branch and accumulated_s(c)_rlc presents the branch RLC. | ||
| meta.lookup_any("branch_hash_in_parent", |meta| { | ||
| let not_first_level = meta.query_advice(not_first_level, Rotation::cur()); | ||
|
|
||
| // -17 because we are in the last branch child (-16 takes us to branch init) | ||
| let is_account_leaf_in_added_branch_prev = | ||
| meta.query_advice(is_account_leaf_in_added_branch, Rotation(-17)); | ||
|
|
||
| // We need to do the lookup only if we are in the last branch child. | ||
| let is_last_branch_child = meta.query_advice(is_last_branch_child, Rotation::cur()); | ||
|
|
||
| // When placeholder branch, we don't check its hash in a parent. | ||
| let mut is_branch_placeholder = meta.query_advice(s_main.bytes[IS_BRANCH_S_PLACEHOLDER_POS - RLP_NUM], Rotation(-16)); | ||
| if !is_s { | ||
| is_branch_placeholder = meta.query_advice(s_main.bytes[IS_BRANCH_C_PLACEHOLDER_POS - RLP_NUM], Rotation(-16)); | ||
| } | ||
|
|
||
| let is_extension_node = get_is_extension_node(meta, s_main.bytes, -16); | ||
|
|
||
| // TODO: acc currently doesn't have branch ValueNode info (which 128 if nil) | ||
| let acc = meta.query_advice(acc, Rotation::cur()); | ||
| let c128 = Expression::Constant(F::from(128)); | ||
| let mult = meta.query_advice(acc_mult, Rotation::cur()); | ||
| let branch_acc = acc + c128 * mult; | ||
|
|
||
| let mut constraints = vec![( | ||
| not_first_level.clone() | ||
| * is_last_branch_child.clone() | ||
| * (one.clone() - is_account_leaf_in_added_branch_prev.clone()) // we don't check this in the first storage level | ||
| * (one.clone() - is_branch_placeholder.clone()) | ||
| * (one.clone() - is_extension_node.clone()) | ||
| * branch_acc, // TODO: replace with acc once ValueNode is added | ||
| meta.query_fixed(keccak_table[0], Rotation::cur()), | ||
| )]; | ||
| // Any rotation that lands into branch can be used instead of -19. | ||
| let mod_node_hash_rlc_cur = meta.query_advice(mod_node_hash_rlc, Rotation(-19)); | ||
| let keccak_table_i = meta.query_fixed(keccak_table[1], Rotation::cur()); | ||
| constraints.push(( | ||
| not_first_level | ||
| * is_last_branch_child | ||
| * (one.clone() | ||
| - is_account_leaf_in_added_branch_prev) // we don't check this in the first storage level | ||
| * (one.clone() - is_branch_placeholder) | ||
| * (one.clone() - is_extension_node) | ||
| * mod_node_hash_rlc_cur, | ||
| keccak_table_i, | ||
| )); | ||
|
|
||
| constraints | ||
| }); | ||
|
|
||
| config | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| use halo2_proofs::{ | ||
| plonk::{Advice, Column, ConstraintSystem, Expression, VirtualCells}, | ||
| poly::Rotation, | ||
| }; | ||
| use eth_types::Field; | ||
| use std::marker::PhantomData; | ||
|
|
||
| use crate::{param::{HASH_WIDTH, R_TABLE_LEN}, mpt::MainCols}; | ||
|
|
||
| #[derive(Clone, Debug)] | ||
| pub(crate) struct BranchRLCConfig<F> { | ||
| _marker: PhantomData<F>, | ||
| } | ||
|
|
||
| // BranchRLCChip verifies the random linear combination for the branch which is | ||
| // then used to check the hash of a branch. | ||
| impl<F: Field> BranchRLCConfig<F> { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it suffices to have Config. Or do you think it's better to have Chips? |
||
| pub fn configure( | ||
| meta: &mut ConstraintSystem<F>, | ||
| q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression<F>, | ||
| main: MainCols, | ||
| branch_acc: Column<Advice>, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is called |
||
| branch_mult: Column<Advice>, | ||
| r_table: Vec<Expression<F>>, | ||
| ) -> BranchRLCConfig<F> { | ||
| let config = BranchRLCConfig { _marker: PhantomData, }; | ||
|
|
||
| meta.create_gate("branch acc", |meta| { | ||
| let q_enable = q_enable(meta); | ||
|
|
||
| let mut constraints = vec![]; | ||
| let rlp2 = meta.query_advice(main.rlp2, Rotation::cur()); | ||
| let branch_acc_prev = meta.query_advice(branch_acc, Rotation::prev()); | ||
| let branch_acc_cur = meta.query_advice(branch_acc, Rotation::cur()); | ||
| let branch_mult_prev = meta.query_advice(branch_mult, Rotation::prev()); | ||
| let branch_mult_cur = meta.query_advice(branch_mult, Rotation::cur()); | ||
|
|
||
| let c128 = Expression::Constant(F::from(128_u64)); | ||
| let c160 = Expression::Constant(F::from(160_u64)); | ||
|
|
||
| // empty: | ||
| // branch_acc_curr = branch_acc_prev + 128 * branch_mult_prev | ||
| constraints.push(( | ||
| "branch acc empty", | ||
| q_enable.clone() | ||
| * (c160.clone() - rlp2.clone()) | ||
| * (branch_acc_cur.clone() | ||
| - branch_acc_prev.clone() | ||
| - c128 * branch_mult_prev.clone()), | ||
| )); | ||
| constraints.push(( | ||
| "branch acc mult empty", | ||
| q_enable.clone() | ||
| * (c160.clone() - rlp2.clone()) | ||
| * (branch_mult_cur.clone() - branch_mult_prev.clone() * r_table[0].clone()), | ||
| )); | ||
|
|
||
| // non-empty | ||
| let mut expr = c160 * branch_mult_prev.clone(); | ||
| for (ind, col) in main.bytes.iter().enumerate() { | ||
| let s = meta.query_advice(*col, Rotation::cur()); | ||
| expr = expr + s * branch_mult_prev.clone() * r_table[ind].clone(); | ||
| } | ||
| constraints.push(( | ||
| "branch acc non-empty", | ||
| q_enable.clone() * rlp2.clone() * (branch_acc_cur - branch_acc_prev - expr), | ||
| )); | ||
| constraints.push(( | ||
| "branch acc mult non-empty", | ||
| q_enable | ||
| * rlp2 | ||
| * (branch_mult_cur | ||
| - branch_mult_prev * r_table[R_TABLE_LEN - 1].clone() * r_table[0].clone()), | ||
| )); | ||
|
|
||
| constraints | ||
| }); | ||
|
|
||
| config | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that
branch_rlc_initworks forSandC, butbranch_rlconly works for one (SorC). Why this? I think that is going to be more clear to have a uniquebranch_rlc( that are instantiated twice, one for S and other for C) that also includes init branch row.