Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.6 #88

Closed
wants to merge 16 commits into from
2,964 changes: 2,964 additions & 0 deletions Cargo.lock.current

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ethers-core = "0.17.0"
ethers-core = "2.0.7"
itertools = "0.10.5"
hash-circuit = { package = "poseidon-circuit", git = "https://github.com/scroll-tech/poseidon-circuit.git", branch = "scroll-dev-0723"}
hash-circuit = { package = "poseidon-circuit", git = "https://github.com/scroll-tech/poseidon-circuit.git", branch = "scroll-dev-0901"}
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_09_10" }
rand = "0.8"
lazy_static = "1.4.0"
Expand All @@ -24,6 +24,8 @@ log = "0.4"

[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
halo2_proofs = { git = "https://github.com/scroll-tech/halo2.git", branch = "develop" }
[patch.crates-io]
ethers-core = { git = "https://github.com/scroll-tech/ethers-rs.git", branch = "v2.0.7" }

[features]
# printout the layout of circuits for demo and some unittests
Expand Down
3 changes: 1 addition & 2 deletions src/constraint_builder/query.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use super::BinaryQuery;
use ethers_core::k256::elliptic_curve::PrimeField;
use halo2_proofs::{
arithmetic::{Field, FieldExt},
halo2curves::bn256::Fr,
halo2curves::{bn256::Fr, group::ff::PrimeField},
plonk::{Advice, Challenge, Column, Expression, Fixed, VirtualCells},
poly::Rotation,
};
Expand Down
12 changes: 10 additions & 2 deletions src/gadgets/byte_representation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,17 @@ impl ByteRepresentationConfig {
pub fn assign<F: FieldExt>(
&self,
region: &mut Region<'_, F>,
u32s: &[u32],
u64s: &[u64],
u128s: &[u128],
frs: &[Fr],
randomness: Value<F>,
) {
self.is_first.enable(region, 0);
let byte_representations = u64s
let byte_representations = u32s
.iter()
.map(u64_to_big_endian)
.map(u32_to_big_endian)
.chain(u64s.iter().map(u64_to_big_endian))
.chain(u128s.iter().map(u128_to_big_endian))
.chain(frs.iter().map(fr_to_big_endian));

Expand Down Expand Up @@ -133,6 +135,9 @@ impl ByteRepresentationConfig {
}
}

fn u32_to_big_endian(x: &u32) -> Vec<u8> {
x.to_be_bytes().to_vec()
}
fn u64_to_big_endian(x: &u64) -> Vec<u8> {
x.to_be_bytes().to_vec()
}
Expand Down Expand Up @@ -173,6 +178,7 @@ mod test {

#[derive(Clone, Default, Debug)]
struct TestCircuit {
u32s: Vec<u32>,
u64s: Vec<u64>,
u128s: Vec<u128>,
frs: Vec<Fr>,
Expand Down Expand Up @@ -219,6 +225,7 @@ mod test {
byte_bit.assign(&mut region);
byte_representation.assign(
&mut region,
&self.u32s,
&self.u64s,
&self.u128s,
&self.frs,
Expand All @@ -233,6 +240,7 @@ mod test {
#[test]
fn test_byte_representation() {
let circuit = TestCircuit {
u32s: vec![0, 1, u32::MAX],
u64s: vec![u64::MAX],
u128s: vec![0, 1, u128::MAX],
frs: vec![Fr::from(2342)],
Expand Down
30 changes: 17 additions & 13 deletions src/gadgets/canonical_representation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ use super::super::constraint_builder::{
AdviceColumn, BinaryColumn, ConstraintBuilder, FixedColumn, Query, SecondPhaseAdviceColumn,
SelectorColumn,
};
use super::{
byte_bit::RangeCheck256Lookup, byte_representation::RlcLookup, is_zero::IsZeroGadget,
rlc_randomness::RlcRandomness,
};
use super::{byte_bit::RangeCheck256Lookup, is_zero::IsZeroGadget, rlc_randomness::RlcRandomness};
use ethers_core::types::U256;
use halo2_proofs::{
arithmetic::{Field, FieldExt},
Expand All @@ -20,6 +17,11 @@ pub trait CanonicalRepresentationLookup {
fn lookup<F: FieldExt>(&self) -> [Query<F>; 3];
}

// Lookup to prove that Rlc(x: Fr) = y
pub trait FrRlcLookup {
fn lookup<F: FieldExt>(&self) -> [Query<F>; 2];
}

#[derive(Clone)]
pub struct CanonicalRepresentationConfig {
// Lookup columns
Expand All @@ -30,9 +32,9 @@ pub struct CanonicalRepresentationConfig {

// Witness columns
index_is_zero: SelectorColumn, // (0..32).repeat().map(|i| i == 0)
// index_is_31: SelectorColumn, // (0..32).repeat().map(|i| i == 31)
modulus_byte: FixedColumn, // (0..32).repeat().map(|i| Fr::MODULUS.to_be_bytes()[i])
difference: AdviceColumn, // modulus_byte - byte
index_is_31: SelectorColumn, // (0..32).repeat().map(|i| i == 31)
modulus_byte: FixedColumn, // (0..32).repeat().map(|i| Fr::MODULUS.to_be_bytes()[i])
difference: AdviceColumn, // modulus_byte - byte
difference_is_zero: IsZeroGadget,
differences_are_zero_so_far: BinaryColumn, // difference[0] ... difference[index - 1] are all 0.
}
Expand All @@ -44,7 +46,7 @@ impl CanonicalRepresentationConfig {
range_check: &impl RangeCheck256Lookup,
randomness: &RlcRandomness,
) -> Self {
let ([index_is_zero], [index, modulus_byte], [value, byte, difference]) =
let ([index_is_zero, index_is_31], [index, modulus_byte], [value, byte, difference]) =
cb.build_columns(cs);
let [rlc] = cb.second_phase_advice_columns(cs);

Expand Down Expand Up @@ -120,6 +122,7 @@ impl CanonicalRepresentationConfig {
byte,
rlc,
index_is_zero,
index_is_31,
modulus_byte,
difference,
difference_is_zero,
Expand Down Expand Up @@ -153,6 +156,8 @@ impl CanonicalRepresentationConfig {
.assign(region, offset, u64::try_from(index).unwrap());
if index.is_zero() {
self.index_is_zero.enable(region, offset);
} else if index == 31 {
self.index_is_31.enable(region, offset);
}

let difference = Fr::from(u64::from(*modulus_byte)) - Fr::from(u64::from(*byte));
Expand Down Expand Up @@ -187,12 +192,11 @@ impl CanonicalRepresentationLookup for CanonicalRepresentationConfig {
}
}

impl RlcLookup for CanonicalRepresentationConfig {
fn lookup<F: FieldExt>(&self) -> [Query<F>; 3] {
impl FrRlcLookup for CanonicalRepresentationConfig {
fn lookup<F: FieldExt>(&self) -> [Query<F>; 2] {
[
self.value.current(),
self.rlc.current(),
self.index.current(),
self.value.current() * self.index_is_31.current(),
self.rlc.current() * self.index_is_31.current(),
]
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/gadgets/is_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ impl IsZeroGadget {
);
cb.assert_zero(
"inverse_or_zero is 0 or inverse_or_zero is inverse of value",
inverse_or_zero.current() * (Query::one() - value.current() * inverse_or_zero.current()),
inverse_or_zero.current()
* (Query::one() - value.current() * inverse_or_zero.current()),
);
Self {
value,
Expand Down
67 changes: 42 additions & 25 deletions src/gadgets/mpt_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use word_rlc::{assign as assign_word_rlc, configure as configure_word_rlc};

use super::{
byte_representation::{BytesLookup, RlcLookup},
canonical_representation::FrRlcLookup,
is_zero::IsZeroGadget,
key_bit::KeyBitLookup,
one_hot::OneHot,
Expand All @@ -26,11 +27,11 @@ use crate::{
util::{account_key, domain_hash, lagrange_polynomial, rlc, u256_hi_lo, u256_to_big_endian},
MPTProofType,
};
use ethers_core::{k256::elliptic_curve::PrimeField, types::Address};
use ethers_core::types::Address;
use halo2_proofs::{
arithmetic::{Field, FieldExt},
circuit::{Region, Value},
halo2curves::bn256::Fr,
halo2curves::{bn256::Fr, group::ff::PrimeField},
plonk::ConstraintSystem,
};
use itertools::izip;
Expand Down Expand Up @@ -83,7 +84,10 @@ impl<F: FieldExt> MptUpdateLookup<F> for MptUpdateConfig {
let proof_type = self.proof_type.current() * is_start();
let old_value = self.old_value.current() * is_start();
let new_value = self.new_value.current() * is_start();
let address = self.intermediate_values[0].current() * is_start();
let [address_high, address_low, ..] = self.intermediate_values;
let address = (address_high.current() * Query::Constant(F::from_u128(1 << 32))
+ address_low.current())
* is_start();
let storage_key_rlc = self.storage_key_rlc.current() * is_start();
[
is_start().into(),
Expand All @@ -107,7 +111,7 @@ impl MptUpdateConfig {
rlc: &impl RlcLookup,
bytes: &impl BytesLookup,
rlc_randomness: &RlcRandomness,
fr_rlc: &impl RlcLookup,
fr_rlc: &impl FrRlcLookup,
) -> Self {
let proof_type: OneHot<MPTProofType> = OneHot::configure(cs, cb);
let [storage_key_rlc, old_value, new_value] = cb.second_phase_advice_columns(cs);
Expand All @@ -131,30 +135,36 @@ impl MptUpdateConfig {
path_type.current_matches(&[PathType::Start]).into(),
);
cb.condition(is_start.clone().and(cb.every_row_selector()), |cb| {
let [address, address_high, ..] = intermediate_values;
let [address_high, address_low, ..] = intermediate_values;
let [old_hash_rlc, new_hash_rlc, ..] = second_phase_intermediate_values;
let address_low: Query<F> = (address.current() - address_high.current() * (1 << 32))
* (1 << 32)
* (1 << 32)
* (1 << 32);
cb.poseidon_lookup(
"account mpt key = h(address_high, address_low)",
"account mpt key = h(address_high, address_low << 96)",
[
address_high.current(),
address_low,
address_low.current() * Query::Constant(F::from_u128(1 << 96)),
Query::from(u64::from(HashDomain::Pair)),
key.current(),
],
poseidon,
);
cb.add_lookup(
"address_high is 16 bytes",
[address_high.current(), Query::from(15)],
bytes.lookup(),
);
cb.add_lookup(
"address_low is 4 bytes",
[address_low.current(), Query::from(3)],
bytes.lookup(),
);
cb.add_lookup(
"rlc_old_root = rlc(old_root)",
[old_hash.current(), old_hash_rlc.current(), Query::from(31)],
[old_hash.current(), old_hash_rlc.current()],
fr_rlc.lookup(),
);
cb.add_lookup(
"rlc_new_root = rlc(new_root)",
[new_hash.current(), new_hash_rlc.current(), Query::from(31)],
[new_hash.current(), new_hash_rlc.current()],
fr_rlc.lookup(),
);
});
Expand Down Expand Up @@ -388,12 +398,16 @@ impl MptUpdateConfig {
self.other_key.assign(region, offset, other_key);
self.domain.assign(region, offset, HashDomain::Pair);

self.intermediate_values[0].assign(region, offset, address_to_fr(proof.claim.address));
self.intermediate_values[1].assign(
self.intermediate_values[0].assign(
region,
offset,
Fr::from_u128(address_high(proof.claim.address)),
);
self.intermediate_values[1].assign(
region,
offset,
u64::from(address_low(proof.claim.address)),
);

let rlc_fr = |x: Fr| {
let mut bytes = x.to_bytes();
Expand Down Expand Up @@ -435,7 +449,7 @@ impl MptUpdateConfig {
})
.unwrap_or(PathType::Common);
let (final_old_hash, final_new_hash) = match proof.address_hash_traces.first() {
None => unimplemented!("single account mpt not handled"),
None => (proof.old.hash(), proof.new.hash()),
Some((_, _, old_hash, new_hash, _, _, _)) => (*old_hash, *new_hash),
};

Expand Down Expand Up @@ -1283,7 +1297,7 @@ fn configure_nonce<F: FieldExt>(
);
for variant in SegmentType::iter() {
let conditional_constraints = |cb: &mut ConstraintBuilder<F>| match variant {
SegmentType::AccountTrie => {
SegmentType::Start | SegmentType::AccountTrie => {
cb.condition(
config.segment_type.next_matches(&[SegmentType::Start]),
|cb| {
Expand Down Expand Up @@ -1415,7 +1429,7 @@ fn configure_code_size<F: FieldExt>(
);
for variant in SegmentType::iter() {
let conditional_constraints = |cb: &mut ConstraintBuilder<F>| match variant {
SegmentType::AccountTrie => {
SegmentType::Start | SegmentType::AccountTrie => {
cb.condition(
config.segment_type.next_matches(&[SegmentType::Start]),
|cb| {
Expand Down Expand Up @@ -1499,7 +1513,7 @@ fn configure_balance<F: FieldExt>(
) {
for variant in SegmentType::iter() {
let conditional_constraints = |cb: &mut ConstraintBuilder<F>| match variant {
SegmentType::AccountTrie => {
SegmentType::Start | SegmentType::AccountTrie => {
cb.condition(
config.segment_type.next_matches(&[SegmentType::Start]),
|cb| {
Expand Down Expand Up @@ -1685,7 +1699,7 @@ fn configure_keccak_code_hash<F: FieldExt>(
);
for variant in SegmentType::iter() {
let conditional_constraints = |cb: &mut ConstraintBuilder<F>| match variant {
SegmentType::AccountTrie => {
SegmentType::Start | SegmentType::AccountTrie => {
cb.condition(
config.segment_type.next_matches(&[SegmentType::Start]),
|cb| {
Expand Down Expand Up @@ -2008,9 +2022,9 @@ fn address_high(a: Address) -> u128 {
u128::from_be_bytes(high_bytes)
}

fn address_low(a: Address) -> u128 {
fn address_low(a: Address) -> u32 {
let low_bytes: [u8; 4] = a.0[16..].try_into().unwrap();
u128::from(u32::from_be_bytes(low_bytes)) << 96
u32::from_be_bytes(low_bytes)
}

// ... the return traces: ([inp;2], domain, hash)
Expand All @@ -2037,7 +2051,7 @@ pub fn hash_traces(proofs: &[Proof]) -> Vec<([Fr; 2], Fr, Fr)> {
hash_traces.push((
[
Fr::from_u128(address_high(proof.claim.address)),
Fr::from_u128(address_low(proof.claim.address)),
Fr::from_u128(u128::from(address_low(proof.claim.address)) << 96),
],
HashDomain::Pair.into(),
key,
Expand Down Expand Up @@ -2108,12 +2122,15 @@ pub fn key_bit_lookups(proofs: &[Proof]) -> Vec<(Fr, usize, bool)> {
}

/// ...
pub fn byte_representations(proofs: &[Proof]) -> (Vec<u64>, Vec<u128>, Vec<Fr>) {
pub fn byte_representations(proofs: &[Proof]) -> (Vec<u32>, Vec<u64>, Vec<u128>, Vec<Fr>) {
let mut u32s = vec![];
let mut u64s = vec![];
let mut u128s = vec![0];
let mut frs = vec![];

for proof in proofs {
u128s.push(address_high(proof.claim.address));
u32s.push(address_low(proof.claim.address));
match MPTProofType::from(proof.claim) {
MPTProofType::NonceChanged | MPTProofType::CodeSizeExists => {
u128s.push(address_high(proof.claim.address));
Expand Down Expand Up @@ -2182,7 +2199,7 @@ pub fn byte_representations(proofs: &[Proof]) -> (Vec<u64>, Vec<u128>, Vec<Fr>)
_ => {}
}
}
(u64s, u128s, frs)
(u32s, u64s, u128s, frs)
}

/// ..
Expand Down
2 changes: 2 additions & 0 deletions src/gadgets/mpt_update/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub fn transitions(proof: MPTProofType) -> HashMap<SegmentType, Vec<SegmentType>
(
SegmentType::Start,
vec![
SegmentType::Start, // empty account proof in an empty mpt
SegmentType::AccountTrie, // mpt has > 1 account
SegmentType::AccountLeaf0, // mpt has <= 1 account
],
Expand Down Expand Up @@ -106,6 +107,7 @@ pub fn transitions(proof: MPTProofType) -> HashMap<SegmentType, Vec<SegmentType>
(
SegmentType::Start,
vec![
SegmentType::Start, // empty account proof in an empty mpt
SegmentType::AccountTrie, // mpt has > 1 account
SegmentType::AccountLeaf0, // mpt has 1 account
],
Expand Down
Loading