Skip to content
This repository was archived by the owner on Jul 5, 2024. It is now read-only.

Commit e19d163

Browse files
KimiWu123roynalnarutolispc
authored
feat/#1665 Precompile ECRECOVER (#1720)
closed #1665 This PR was ported from - scroll-tech#529 - scroll-tech#930 which manly includes, 1. the main logic in ecrecover gadget (`ecrecover.rs`) 2. signature verifcation circuiit (`sig_circuit.rs`). What I did is to change rlc to word lo/hi. 3. a new table, `sig_table.rs` 4. ecc circuit (`ecc_circuit.rs`). It's not be used in `ecRecover`, but it was implemented in Scroll's PR. If I removed ecc_circuit, it would be inconvienent for people porting `ecAdd`, `ecMul` or `ecPairing`. That's why I keep it here. 5. dependencies update, using `halo2lib` (includes `halo2-base` and `halo2-ecc`) --------- Co-authored-by: Rohit Narurkar <[email protected]> Co-authored-by: Zhang Zhuo <[email protected]>
1 parent db0d403 commit e19d163

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+5143
-59
lines changed

.github/workflows/main-tests.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ jobs:
7979
uses: actions-rs/cargo@v1
8080
with:
8181
command: test
82-
args: --verbose --release --all --all-features --exclude integration-tests --exclude circuit-benchmarks
82+
args: --verbose --release --all --all-features --exclude integration-tests --exclude circuit-benchmarks -- --test-threads 24
8383
- name: Run testool internal tests
8484
uses: actions-rs/cargo@v1
8585
with:

Cargo.lock

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

Cargo.toml

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ members = [
1717
[patch.crates-io]
1818
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v0.3.0" }
1919

20+
[patch."https://github.com/scroll-tech/halo2.git"]
21+
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v0.3.0" }
22+
23+
[patch."https://github.com/privacy-scaling-explorations/halo2curves.git"]
24+
halo2curves = { version = "0.1.0", features = ["derive_serde"] }
25+
2026
# Definition of benchmarks profile to use.
2127
[profile.bench]
2228
opt-level = 3

bus-mapping/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.gi
1616
itertools = "0.10"
1717
lazy_static = "1.4"
1818
log = "0.4.14"
19+
num = "0.4"
20+
rand = { version = "0.8", optional = true }
1921
serde = {version = "1.0.130", features = ["derive"] }
2022
serde_json = "1.0.66"
2123
strum = "0.24"

bus-mapping/src/circuit_input_builder.rs

+8
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use eth_types::{
3131
use ethers_providers::JsonRpcClient;
3232
pub use execution::{
3333
CopyDataType, CopyEvent, CopyStep, ExecState, ExecStep, ExpEvent, ExpStep, NumberOrHash,
34+
PrecompileEvent, PrecompileEvents, N_BYTES_PER_PAIR, N_PAIRING_PER_OP,
3435
};
3536
pub use input_state_ref::CircuitInputStateRef;
3637
use itertools::Itertools;
@@ -112,6 +113,11 @@ pub struct FixedCParams {
112113
/// calculated, so the same circuit will not be able to prove different
113114
/// witnesses.
114115
pub max_keccak_rows: usize,
116+
/// This number indicate what 100% usage means, for example if we can support up to 2
117+
/// ecPairing inside circuit, and max_vertical_circuit_rows is set to 1_000_000,
118+
/// then if there is 1 ecPairing in the input, we will return 500_000 as the "row usage"
119+
/// for the ec circuit.
120+
pub max_vertical_circuit_rows: usize,
115121
}
116122

117123
/// Unset Circuits Parameters
@@ -153,6 +159,7 @@ impl Default for FixedCParams {
153159
max_bytecode: 512,
154160
max_evm_rows: 0,
155161
max_keccak_rows: 0,
162+
max_vertical_circuit_rows: 0,
156163
}
157164
}
158165
}
@@ -497,6 +504,7 @@ impl CircuitInputBuilder<DynamicCParams> {
497504
max_bytecode,
498505
max_evm_rows,
499506
max_keccak_rows,
507+
max_vertical_circuit_rows: 0,
500508
}
501509
};
502510
let mut cib = CircuitInputBuilder::<FixedCParams> {

bus-mapping/src/circuit_input_builder/block.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Block-related utility module
22
33
use super::{
4-
execution::ExecState, transaction::Transaction, CopyEvent, ExecStep, ExpEvent, Withdrawal,
4+
execution::ExecState, transaction::Transaction, CopyEvent, ExecStep, ExpEvent, PrecompileEvent,
5+
PrecompileEvents, Withdrawal,
56
};
67
use crate::{
78
operation::{OperationContainer, RWCounter},
@@ -87,6 +88,8 @@ pub struct Block {
8788
pub sha3_inputs: Vec<Vec<u8>>,
8889
/// Exponentiation events in the block.
8990
pub exp_events: Vec<ExpEvent>,
91+
/// IO to/from the precompiled contract calls.
92+
pub precompile_events: PrecompileEvents,
9093
/// Original block from geth
9194
pub eth_block: eth_types::Block<eth_types::Transaction>,
9295
}
@@ -145,6 +148,7 @@ impl Block {
145148
copy_events: Vec::new(),
146149
exp_events: Vec::new(),
147150
sha3_inputs: Vec::new(),
151+
precompile_events: PrecompileEvents { events: Vec::new() },
148152
eth_block: eth_block.clone(),
149153
})
150154
}
@@ -191,4 +195,9 @@ impl Block {
191195
pub fn add_exp_event(&mut self, event: ExpEvent) {
192196
self.exp_events.push(event);
193197
}
198+
199+
/// Push a precompile event to the block.
200+
pub fn add_precompile_event(&mut self, event: PrecompileEvent) {
201+
self.precompile_events.events.push(event);
202+
}
194203
}

bus-mapping/src/circuit_input_builder/execution.rs

+46-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use crate::{
55
error::{ExecError, OogError},
66
exec_trace::OperationRef,
77
operation::RWCounter,
8-
precompile::PrecompileCalls,
8+
precompile::{PrecompileAuxData, PrecompileCalls},
99
};
10-
use eth_types::{evm_types::OpcodeId, GethExecStep, Word, H256};
10+
use eth_types::{evm_types::OpcodeId, sign_types::SignData, GethExecStep, Word, H256};
1111
use gadgets::impl_expr;
1212
use halo2_proofs::plonk::Expression;
1313
use strum_macros::EnumIter;
@@ -49,6 +49,8 @@ pub struct ExecStep {
4949
pub copy_rw_counter_delta: u64,
5050
/// Error generated by this step
5151
pub error: Option<ExecError>,
52+
/// Optional auxiliary data that is attached to precompile call internal states.
53+
pub aux_data: Option<PrecompileAuxData>,
5254
}
5355

5456
impl ExecStep {
@@ -77,6 +79,7 @@ impl ExecStep {
7779
bus_mapping_instance: Vec::new(),
7880
copy_rw_counter_delta: 0,
7981
error: None,
82+
aux_data: None,
8083
}
8184
}
8285

@@ -364,3 +367,44 @@ impl Default for ExpEvent {
364367
}
365368
}
366369
}
370+
371+
/// I/Os from all precompiled contract calls in a block.
372+
#[derive(Clone, Debug, Default)]
373+
pub struct PrecompileEvents {
374+
/// All events.
375+
pub events: Vec<PrecompileEvent>,
376+
}
377+
378+
impl PrecompileEvents {
379+
/// Get all ecrecover events.
380+
pub fn get_ecrecover_events(&self) -> Vec<SignData> {
381+
self.events
382+
.iter()
383+
.map(|e| {
384+
let PrecompileEvent::Ecrecover(sign_data) = e;
385+
sign_data
386+
})
387+
.cloned()
388+
.collect()
389+
}
390+
}
391+
392+
/// I/O from a precompiled contract call.
393+
#[derive(Clone, Debug)]
394+
pub enum PrecompileEvent {
395+
/// Represents the I/O from Ecrecover call.
396+
Ecrecover(SignData),
397+
}
398+
399+
impl Default for PrecompileEvent {
400+
fn default() -> Self {
401+
Self::Ecrecover(SignData::default())
402+
}
403+
}
404+
405+
/// The number of pairing inputs per pairing operation. If the inputs provided to the precompile
406+
/// call are < 4, we append (G1::infinity, G2::generator) until we have the required no. of inputs.
407+
pub const N_PAIRING_PER_OP: usize = 4;
408+
409+
/// The number of bytes taken to represent a pair (G1, G2).
410+
pub const N_BYTES_PER_PAIR: usize = 192;

bus-mapping/src/circuit_input_builder/input_state_ref.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use super::{
44
get_call_memory_offset_length, get_create_init_code, Block, BlockContext, Call, CallContext,
5-
CallKind, CodeSource, CopyEvent, ExecState, ExecStep, ExpEvent, Transaction,
5+
CallKind, CodeSource, CopyEvent, ExecState, ExecStep, ExpEvent, PrecompileEvent, Transaction,
66
TransactionContext,
77
};
88
use crate::{
@@ -1404,6 +1404,11 @@ impl<'a> CircuitInputStateRef<'a> {
14041404
self.block.add_exp_event(event)
14051405
}
14061406

1407+
/// Push an event representing auxiliary data for a precompile call to the state.
1408+
pub fn push_precompile_event(&mut self, event: PrecompileEvent) {
1409+
self.block.add_precompile_event(event)
1410+
}
1411+
14071412
pub(crate) fn get_step_err(
14081413
&self,
14091414
step: &GethExecStep,
@@ -1614,7 +1619,6 @@ impl<'a> CircuitInputStateRef<'a> {
16141619
PrecompileCalls::Sha256
16151620
| PrecompileCalls::Ripemd160
16161621
| PrecompileCalls::Blake2F
1617-
| PrecompileCalls::ECRecover
16181622
| PrecompileCalls::Bn128Add
16191623
| PrecompileCalls::Bn128Mul
16201624
| PrecompileCalls::Bn128Pairing

bus-mapping/src/circuit_input_builder/transaction.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -182,14 +182,24 @@ pub struct Transaction {
182182
/// The transaction id
183183
pub id: u64,
184184
/// The raw transaction fields
185-
tx: geth_types::Transaction,
185+
pub tx: geth_types::Transaction,
186186
/// Calls made in the transaction
187187
pub(crate) calls: Vec<Call>,
188188
/// Execution steps
189189
steps: Vec<ExecStep>,
190190
}
191191

192192
impl Transaction {
193+
/// Create a dummy Transaction with zero values
194+
pub fn dummy() -> Self {
195+
Self {
196+
id: 0,
197+
calls: Vec::new(),
198+
steps: Vec::new(),
199+
tx: geth_types::Transaction::dummy(),
200+
}
201+
}
202+
193203
/// Create a new Self.
194204
pub fn new(
195205
id: u64,

bus-mapping/src/evm/opcodes/callop.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
362362

363363
// insert a copy event (input) for this step and generate memory op
364364
let rw_counter_start = state.block_ctx.rwc;
365-
if call.call_data_length > 0 {
365+
let input_bytes = if call.call_data_length > 0 {
366366
let n_input_bytes = if let Some(input_len) = precompile_call.input_len() {
367367
min(input_len, call.call_data_length as usize)
368368
} else {
@@ -390,11 +390,14 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
390390
bytes: input_bytes.iter().map(|s| (*s, false)).collect(),
391391
},
392392
);
393-
}
393+
Some(input_bytes)
394+
} else {
395+
None
396+
};
394397

395398
// write the result in the callee's memory
396399
let rw_counter_start = state.block_ctx.rwc;
397-
if call.is_success && !result.is_empty() {
400+
let output_bytes = if call.is_success && !result.is_empty() {
398401
let (output_bytes, _prev_bytes) = state
399402
.gen_copy_steps_for_precompile_callee_memory(&mut exec_step, &result)?;
400403

@@ -413,11 +416,14 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
413416
bytes: output_bytes.iter().map(|s| (*s, false)).collect(),
414417
},
415418
);
416-
}
419+
Some(output_bytes)
420+
} else {
421+
None
422+
};
417423

418424
// insert another copy event (output) for this step.
419425
let rw_counter_start = state.block_ctx.rwc;
420-
if call.is_success && length > 0 {
426+
let return_bytes = if call.is_success && length > 0 {
421427
let return_bytes = state.gen_copy_steps_for_precompile_returndata(
422428
&mut exec_step,
423429
call.return_data_offset,
@@ -439,7 +445,10 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
439445
bytes: return_bytes.iter().map(|s| (*s, false)).collect(),
440446
},
441447
);
442-
}
448+
Some(return_bytes)
449+
} else {
450+
None
451+
};
443452

444453
if has_oog_err {
445454
let mut oog_step = ErrorOOGPrecompile::gen_associated_ops(
@@ -462,6 +471,9 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
462471
geth_steps[1].clone(),
463472
call.clone(),
464473
precompile_call,
474+
&input_bytes.unwrap_or_default(),
475+
&output_bytes.unwrap_or_default(),
476+
&return_bytes.unwrap_or_default(),
465477
)?;
466478

467479
// Set gas left and gas cost for precompile step.

0 commit comments

Comments
 (0)