Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

Commit fcf0381

Browse files
lispcroynalnarutozhenfeizhangkunxian-xia
authored
refactor sig verify subcircuit (#538)
* xx * fix: skip first 12 bytes for eth address * chore: fmt * feat: add sig table to evm circuit * impl SubCircuit trait for TxCircuitTester * fill r s v in test_util sig * lint * lint * clean code * chore: refactoring witness assignment * [fix] soundness bug in ctr int (#543) * [fix] soundness bug in ctr int * [fix] clippy * move assign function to make git diff easier * Feat: assert v is odd (#546) * [fix] soundness bug in ctr int * [fix] clippy * [feat] implement v_is_odd check * [fix] extract v from affine coord * [chore] cargo clippy; fmt --------- Co-authored-by: Zhang Zhuo <[email protected]> * address some comments * fix instance col * fix v permutation * sync up changes with halo2-lib; remove lifetimers (#554) * [fix] sync up api changes with halo2-lib: removing lifetimes * [minor] update cargo lock * [chore] clippy; update cargo lock * Update sig_circuit.rs --------- Co-authored-by: Zhang Zhuo <[email protected]> * lint * add lookup to sig table in tx circuit * add lookup to sig table in tx_circuit * remove get_num_rows_required * Update tx_circuit.rs * fix sig circuit assignment * fix: sign_data of padding tx * fmt --------- Co-authored-by: Rohit Narurkar <[email protected]> Co-authored-by: zhenfei <[email protected]> Co-authored-by: kunxian xia <[email protected]>
1 parent 7c2942f commit fcf0381

File tree

27 files changed

+1860
-1091
lines changed

27 files changed

+1860
-1091
lines changed

Cargo.lock

+433-410
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bus-mapping/src/circuit_input_builder/block.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
operation::{OperationContainer, RWCounter},
88
Error,
99
};
10-
use eth_types::{Address, Hash, ToWord, Word};
10+
use eth_types::{sign_types::SignData, Address, Hash, ToWord, Word};
1111
use std::collections::{BTreeMap, HashMap};
1212

1313
/// Context of a [`Block`] which can mutate in a [`Transaction`].
@@ -153,6 +153,8 @@ pub struct Block {
153153
pub code: HashMap<Hash, Vec<u8>>,
154154
/// Inputs to the SHA3 opcode
155155
pub sha3_inputs: Vec<Vec<u8>>,
156+
/// IO to/from the precompile Ecrecover calls.
157+
pub ecrecover_events: Vec<SignData>,
156158
/// Block-wise steps
157159
pub block_steps: BlockSteps,
158160
/// Exponentiation events in the block.
@@ -246,4 +248,8 @@ impl Block {
246248
pub fn add_exp_event(&mut self, event: ExpEvent) {
247249
self.exp_events.push(event);
248250
}
251+
/// Push an ecrecover event to the block.
252+
pub fn add_ecrecover_event(&mut self, event: SignData) {
253+
self.ecrecover_events.push(event);
254+
}
249255
}

circuit-benchmarks/src/tx_circuit.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ mod tests {
2424
use rand::SeedableRng;
2525
use rand_chacha::ChaCha20Rng;
2626
use std::env::var;
27-
use zkevm_circuits::{tx_circuit::TxCircuit, util::SubCircuit, witness::block_convert};
27+
use zkevm_circuits::{
28+
tx_circuit::TestTxCircuit as TxCircuit, util::SubCircuit, witness::block_convert,
29+
};
2830

2931
use bus_mapping::rpc::GethClient;
3032
use ethers::providers::Http;

eth-types/src/geth_types.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ impl Transaction {
333333
.try_into()
334334
.expect("hash length isn't 32 bytes");
335335
let v = self.tx_type.get_recovery_id(self.v);
336-
let pk = recover_pk(v, &self.r, &self.s, &msg_hash)?;
336+
let pk = recover_pk(v as u8, &self.r, &self.s, &msg_hash)?;
337337
// msg_hash = msg_hash % q
338338
let msg_hash = BigUint::from_bytes_be(msg_hash.as_slice());
339339
let msg_hash = msg_hash.mod_floor(&*SECP256K1_Q);
@@ -343,7 +343,7 @@ impl Transaction {
343343
libsecp256k1::Error::InvalidMessage,
344344
)?;
345345
Ok(SignData {
346-
signature: (sig_r, sig_s),
346+
signature: (sig_r, sig_s, v as u8),
347347
pk,
348348
msg,
349349
msg_hash,

eth-types/src/sign_types.rs

+34-17
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//! secp256k1 signature types and helper functions.
22
3-
use crate::{ToBigEndian, Word};
4-
use ethers_core::types::Bytes;
3+
use crate::{ToBigEndian, ToWord, Word};
4+
use ethers_core::{
5+
types::{Address, Bytes},
6+
utils::keccak256,
7+
};
58
use halo2_proofs::{
69
arithmetic::{CurveAffine, FieldExt},
710
halo2curves::{
@@ -23,32 +26,33 @@ pub fn sign(
2326
randomness: secp256k1::Fq,
2427
sk: secp256k1::Fq,
2528
msg_hash: secp256k1::Fq,
26-
) -> (secp256k1::Fq, secp256k1::Fq) {
29+
) -> (secp256k1::Fq, secp256k1::Fq, u8) {
2730
let randomness_inv =
2831
Option::<secp256k1::Fq>::from(randomness.invert()).expect("cannot invert randomness");
2932
let generator = Secp256k1Affine::generator();
3033
let sig_point = generator * randomness;
34+
let sig_v: bool = sig_point.to_affine().y.is_odd().into();
35+
3136
let x = *Option::<Coordinates<_>>::from(sig_point.to_affine().coordinates())
3237
.expect("point is the identity")
3338
.x();
3439

35-
let x_repr = &mut vec![0u8; 32];
36-
x_repr.copy_from_slice(x.to_bytes().as_slice());
37-
3840
let mut x_bytes = [0u8; 64];
39-
x_bytes[..32].copy_from_slice(&x_repr[..]);
41+
x_bytes[..32].copy_from_slice(&x.to_bytes());
4042

4143
let sig_r = secp256k1::Fq::from_bytes_wide(&x_bytes); // get x cordinate (E::Base) on E::Scalar
44+
4245
let sig_s = randomness_inv * (msg_hash + sig_r * sk);
43-
(sig_r, sig_s)
46+
(sig_r, sig_s, u8::from(sig_v))
4447
}
4548

4649
/// Signature data required by the SignVerify Chip as input to verify a
4750
/// signature.
4851
#[derive(Clone, Debug)]
4952
pub struct SignData {
50-
/// Secp256k1 signature point
51-
pub signature: (secp256k1::Fq, secp256k1::Fq),
53+
/// Secp256k1 signature point (r, s, v)
54+
/// v must be 0 or 1
55+
pub signature: (secp256k1::Fq, secp256k1::Fq, u8),
5256
/// Secp256k1 public key
5357
pub pk: Secp256k1Affine,
5458
/// Message being hashed before signing.
@@ -57,7 +61,20 @@ pub struct SignData {
5761
pub msg_hash: secp256k1::Fq,
5862
}
5963

64+
impl SignData {
65+
/// Recover address of the signature
66+
pub fn get_addr(&self) -> Word {
67+
let pk_le = pk_bytes_le(&self.pk);
68+
let pk_be = pk_bytes_swap_endianness(&pk_le);
69+
let pk_hash = keccak256(pk_be);
70+
let mut addr_bytes = [0u8; 20];
71+
addr_bytes.copy_from_slice(&pk_hash[12..]);
72+
Address::from(addr_bytes).to_word()
73+
}
74+
}
75+
6076
lazy_static! {
77+
// FIXME: use Transaction::dummy().sign_data() instead when we merged the develop branch
6178
static ref SIGN_DATA_DEFAULT: SignData = {
6279
let generator = Secp256k1Affine::generator();
6380
let sk = secp256k1::Fq::one();
@@ -80,10 +97,10 @@ lazy_static! {
8097
.expect("hash length isn't 32 bytes");
8198
let msg_hash = secp256k1::Fq::from_bytes(&msg_hash).unwrap();
8299
let randomness = secp256k1::Fq::one();
83-
let (sig_r, sig_s) = sign(randomness, sk, msg_hash);
100+
let (sig_r, sig_s, v) = sign(randomness, sk, msg_hash);
84101

85102
SignData {
86-
signature: (sig_r, sig_s),
103+
signature: (sig_r, sig_s, v),
87104
pk,
88105
msg: msg.into(),
89106
msg_hash,
@@ -92,12 +109,12 @@ lazy_static! {
92109
}
93110

94111
impl Default for SignData {
112+
// Hardcoded valid signature corresponding to a hardcoded private key and
113+
// message hash generated from "nothing up my sleeve" values to make the
114+
// ECDSA chip pass the constraints, to be use for padding signature
115+
// verifications (where the constraints pass, but we don't care about the
116+
// message hash and public key).
95117
fn default() -> Self {
96-
// Hardcoded valid signature corresponding to a hardcoded private key and
97-
// message hash generated from "nothing up my sleeve" values to make the
98-
// ECDSA chip pass the constraints, to be use for padding signature
99-
// verifications (where the constraints pass, but we don't care about the
100-
// message hash and public key).
101118
SIGN_DATA_DEFAULT.clone()
102119
}
103120
}

integration-tests/tests/mainnet.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use zkevm_circuits::{
1515
rlp_circuit_fsm::RlpCircuit,
1616
state_circuit::StateCircuit,
1717
super_circuit::SuperCircuit,
18-
tx_circuit::TxCircuit,
18+
tx_circuit::TestTxCircuit as TxCircuit,
1919
util::{Challenges, SubCircuit},
2020
witness,
2121
witness::Transaction,

mock/src/transaction.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use ethers_core::{
1212
use ethers_signers::{LocalWallet, Signer};
1313
use lazy_static::lazy_static;
1414
use rand::SeedableRng;
15-
use rand_chacha::ChaCha20Rng;
15+
use rand_chacha::{rand_core::OsRng, ChaCha20Rng};
1616

1717
lazy_static! {
1818
/// Collection of correctly hashed and signed Transactions which can be used to test circuits or opcodes that have to check integrity of the Tx itself.
@@ -171,7 +171,8 @@ impl Default for MockTransaction {
171171
block_hash: Hash::zero(),
172172
block_number: U64::zero(),
173173
transaction_index: U64::zero(),
174-
from: AddrOrWallet::Addr(MOCK_ACCOUNTS[0]),
174+
//from: AddrOrWallet::Addr(MOCK_ACCOUNTS[0]),
175+
from: AddrOrWallet::random(&mut OsRng),
175176
to: None,
176177
value: Word::zero(),
177178
gas_price: *MOCK_GASPRICE,

zkevm-circuits/Cargo.toml

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,17 @@ keccak256 = { path = "../keccak256"}
2929
log = "0.4"
3030
env_logger = "0.9"
3131

32-
halo2-base = { git = "https://github.com/scroll-tech/halo2-lib", branch = "halo2-ecc-snark-verifier-0323", default-features=false, features=["halo2-pse","display"] }
33-
halo2-ecc = { git = "https://github.com/scroll-tech/halo2-lib", branch = "halo2-ecc-snark-verifier-0323", default-features=false, features=["halo2-pse","display"] }
32+
halo2-base = { git = "https://github.com/scroll-tech/halo2-lib", branch = "develop", default-features=false, features=["halo2-pse","display"] }
33+
halo2-ecc = { git = "https://github.com/scroll-tech/halo2-lib", branch = "develop", default-features=false, features=["halo2-pse","display"] }
3434

3535
maingate = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02" }
3636

3737
libsecp256k1 = "0.7"
3838
num-bigint = { version = "0.4" }
3939
subtle = "2.4"
4040
rand_chacha = "0.3"
41-
snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", branch = "halo2-ecc-snark-verifier-0323" }
42-
snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", branch = "halo2-ecc-snark-verifier-0323", default-features=false, features = ["loader_halo2", "loader_evm", "halo2-pse"] }
41+
snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" }
42+
snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop", default-features=false, features = ["loader_halo2", "loader_evm", "halo2-pse"] }
4343
hex = "0.4.3"
4444
rayon = "1.5"
4545
once_cell = "1.17.0"

zkevm-circuits/src/evm_circuit.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ pub use crate::witness;
2121
use crate::{
2222
evm_circuit::param::{MAX_STEP_HEIGHT, STEP_STATE_HEIGHT},
2323
table::{
24-
BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, RwTable, TxTable,
24+
BlockTable, BytecodeTable, CopyTable, ExpTable, KeccakTable, LookupTable, RwTable,
25+
SigTable, TxTable,
2526
},
2627
util::{SubCircuit, SubCircuitConfig},
2728
};
@@ -47,6 +48,7 @@ pub struct EvmCircuitConfig<F> {
4748
copy_table: CopyTable,
4849
keccak_table: KeccakTable,
4950
exp_table: ExpTable,
51+
sig_table: SigTable,
5052
}
5153

5254
/// Circuit configuration arguments
@@ -67,6 +69,8 @@ pub struct EvmCircuitConfigArgs<F: Field> {
6769
pub keccak_table: KeccakTable,
6870
/// ExpTable
6971
pub exp_table: ExpTable,
72+
/// SigTable
73+
pub sig_table: SigTable,
7074
}
7175

7276
/// Circuit exported cells after synthesis, used for subcircuit
@@ -92,6 +96,7 @@ impl<F: Field> SubCircuitConfig<F> for EvmCircuitConfig<F> {
9296
copy_table,
9397
keccak_table,
9498
exp_table,
99+
sig_table,
95100
}: Self::ConfigArgs,
96101
) -> Self {
97102
let fixed_table = [(); 4].map(|_| meta.fixed_column());
@@ -108,6 +113,7 @@ impl<F: Field> SubCircuitConfig<F> for EvmCircuitConfig<F> {
108113
&copy_table,
109114
&keccak_table,
110115
&exp_table,
116+
&sig_table,
111117
));
112118

113119
meta.annotate_lookup_any_column(byte_table[0], || "byte_range");
@@ -121,6 +127,7 @@ impl<F: Field> SubCircuitConfig<F> for EvmCircuitConfig<F> {
121127
copy_table.annotate_columns(meta);
122128
keccak_table.annotate_columns(meta);
123129
exp_table.annotate_columns(meta);
130+
sig_table.annotate_columns(meta);
124131

125132
Self {
126133
fixed_table,
@@ -133,6 +140,7 @@ impl<F: Field> SubCircuitConfig<F> for EvmCircuitConfig<F> {
133140
copy_table,
134141
keccak_table,
135142
exp_table,
143+
sig_table,
136144
}
137145
}
138146
}
@@ -409,6 +417,7 @@ impl<F: Field> Circuit<F> for EvmCircuit<F> {
409417
let copy_table = CopyTable::construct(meta, q_copy_table);
410418
let keccak_table = KeccakTable::construct(meta);
411419
let exp_table = ExpTable::construct(meta);
420+
let sig_table = SigTable::construct(meta);
412421
(
413422
EvmCircuitConfig::new(
414423
meta,
@@ -421,6 +430,7 @@ impl<F: Field> Circuit<F> for EvmCircuit<F> {
421430
copy_table,
422431
keccak_table,
423432
exp_table,
433+
sig_table,
424434
},
425435
),
426436
challenges,
@@ -465,6 +475,9 @@ impl<F: Field> Circuit<F> for EvmCircuit<F> {
465475
.keccak_table
466476
.dev_load(&mut layouter, &block.sha3_inputs, &challenges)?;
467477
config.exp_table.dev_load(&mut layouter, block)?;
478+
config
479+
.sig_table
480+
.dev_load(&mut layouter, block, &challenges)?;
468481

469482
self.synthesize_sub(&config, &challenges, &mut layouter)
470483
}
@@ -646,7 +659,9 @@ mod evm_circuit_stats {
646659
keccak_table,
647660
LOOKUP_CONFIG[6].1,
648661
exp_table,
649-
LOOKUP_CONFIG[7].1
662+
LOOKUP_CONFIG[7].1,
663+
sig_table,
664+
LOOKUP_CONFIG[8].1
650665
);
651666
}
652667

zkevm-circuits/src/evm_circuit/execution.rs

+4
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ impl<F: Field> ExecutionConfig<F> {
377377
copy_table: &dyn LookupTable<F>,
378378
keccak_table: &dyn LookupTable<F>,
379379
exp_table: &dyn LookupTable<F>,
380+
sig_table: &dyn LookupTable<F>,
380381
) -> Self {
381382
let mut instrument = Instrument::default();
382383
let q_usable = meta.complex_selector();
@@ -650,6 +651,7 @@ impl<F: Field> ExecutionConfig<F> {
650651
copy_table,
651652
keccak_table,
652653
exp_table,
654+
sig_table,
653655
&challenges,
654656
&cell_manager,
655657
);
@@ -905,6 +907,7 @@ impl<F: Field> ExecutionConfig<F> {
905907
copy_table: &dyn LookupTable<F>,
906908
keccak_table: &dyn LookupTable<F>,
907909
exp_table: &dyn LookupTable<F>,
910+
sig_table: &dyn LookupTable<F>,
908911
challenges: &Challenges<Expression<F>>,
909912
cell_manager: &CellManager<F>,
910913
) {
@@ -921,6 +924,7 @@ impl<F: Field> ExecutionConfig<F> {
921924
Table::Copy => copy_table,
922925
Table::Keccak => keccak_table,
923926
Table::Exp => exp_table,
927+
Table::Sig => sig_table,
924928
}
925929
.table_exprs(meta);
926930
vec![(

zkevm-circuits/src/evm_circuit/param.rs

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ pub(crate) const LOOKUP_CONFIG: &[(Table, usize)] = &[
4949
(Table::Copy, COPY_TABLE_LOOKUPS),
5050
(Table::Keccak, KECCAK_TABLE_LOOKUPS),
5151
(Table::Exp, EXP_TABLE_LOOKUPS),
52+
(Table::Sig, SIG_TABLE_LOOKUPS),
5253
];
5354

5455
/// Fixed Table lookups done in EVMCircuit
@@ -75,6 +76,9 @@ pub const KECCAK_TABLE_LOOKUPS: usize = 1;
7576
/// Exp Table lookups done in EVMCircuit
7677
pub const EXP_TABLE_LOOKUPS: usize = 1;
7778

79+
/// Sig Table lookups done in EVMCircuit
80+
pub const SIG_TABLE_LOOKUPS: usize = 1;
81+
7882
/// Maximum number of bytes that an integer can fit in field without wrapping
7983
/// around.
8084
pub(crate) const MAX_N_BYTES_INTEGER: usize = 31;

0 commit comments

Comments
 (0)