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

Commit

Permalink
feat: compiling error free
Browse files Browse the repository at this point in the history
  • Loading branch information
KimiWu123 committed Dec 28, 2023
1 parent 7bcd5de commit 99d2b1c
Show file tree
Hide file tree
Showing 19 changed files with 391 additions and 414 deletions.
2 changes: 1 addition & 1 deletion bus-mapping/src/circuit_input_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use eth_types::{
use ethers_providers::JsonRpcClient;
pub use execution::{
CopyDataType, CopyEvent, CopyStep, ExecState, ExecStep, ExpEvent, ExpStep, NumberOrHash,
N_BYTES_PER_PAIR, N_PAIRING_PER_OP,
PrecompileEvent, PrecompileEvents, N_BYTES_PER_PAIR, N_PAIRING_PER_OP,
};
pub use input_state_ref::CircuitInputStateRef;
use itertools::Itertools;
Expand Down
11 changes: 10 additions & 1 deletion bus-mapping/src/circuit_input_builder/block.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Block-related utility module

use super::{
execution::ExecState, transaction::Transaction, CopyEvent, ExecStep, ExpEvent, Withdrawal,
execution::ExecState, transaction::Transaction, CopyEvent, ExecStep, ExpEvent, PrecompileEvent,
PrecompileEvents, Withdrawal,
};
use crate::{
operation::{OperationContainer, RWCounter},
Expand Down Expand Up @@ -87,6 +88,8 @@ pub struct Block {
pub sha3_inputs: Vec<Vec<u8>>,
/// Exponentiation events in the block.
pub exp_events: Vec<ExpEvent>,
/// IO to/from the precompiled contract calls.
pub precompile_events: PrecompileEvents,
/// Original block from geth
pub eth_block: eth_types::Block<eth_types::Transaction>,
}
Expand Down Expand Up @@ -145,6 +148,7 @@ impl Block {
copy_events: Vec::new(),
exp_events: Vec::new(),
sha3_inputs: Vec::new(),
precompile_events: PrecompileEvents { events: Vec::new() },
eth_block: eth_block.clone(),
})
}
Expand Down Expand Up @@ -191,4 +195,9 @@ impl Block {
pub fn add_exp_event(&mut self, event: ExpEvent) {
self.exp_events.push(event);
}

/// Push a precompile event to the block.
pub fn add_precompile_event(&mut self, event: PrecompileEvent) {
self.precompile_events.events.push(event);
}
}
39 changes: 38 additions & 1 deletion bus-mapping/src/circuit_input_builder/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
operation::RWCounter,
precompile::{PrecompileAuxData, PrecompileCalls},
};
use eth_types::{evm_types::OpcodeId, GethExecStep, Word, H256};
use eth_types::{evm_types::OpcodeId, sign_types::SignData, GethExecStep, Word, H256};
use gadgets::impl_expr;
use halo2_proofs::plonk::Expression;
use strum_macros::EnumIter;
Expand Down Expand Up @@ -368,6 +368,43 @@ impl Default for ExpEvent {
}
}

/// I/Os from all precompiled contract calls in a block.
#[derive(Clone, Debug, Default)]
pub struct PrecompileEvents {
/// All events.
pub events: Vec<PrecompileEvent>,
}

impl PrecompileEvents {
/// Get all ecrecover events.
pub fn get_ecrecover_events(&self) -> Vec<SignData> {
self.events
.iter()
.filter_map(|e| {
if let PrecompileEvent::Ecrecover(sign_data) = e {
Some(sign_data)
} else {
None
}
})
.cloned()
.collect()
}
}

/// I/O from a precompiled contract call.
#[derive(Clone, Debug)]
pub enum PrecompileEvent {
/// Represents the I/O from Ecrecover call.
Ecrecover(SignData),
}

impl Default for PrecompileEvent {
fn default() -> Self {
Self::Ecrecover(SignData::default())
}
}

/// The number of pairing inputs per pairing operation. If the inputs provided to the precompile
/// call are < 4, we append (G1::infinity, G2::generator) until we have the required no. of inputs.
pub const N_PAIRING_PER_OP: usize = 4;
Expand Down
7 changes: 6 additions & 1 deletion bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use super::{
get_call_memory_offset_length, get_create_init_code, Block, BlockContext, Call, CallContext,
CallKind, CodeSource, CopyEvent, ExecState, ExecStep, ExpEvent, Transaction,
CallKind, CodeSource, CopyEvent, ExecState, ExecStep, ExpEvent, PrecompileEvent, Transaction,
TransactionContext,
};
use crate::{
Expand Down Expand Up @@ -1404,6 +1404,11 @@ impl<'a> CircuitInputStateRef<'a> {
self.block.add_exp_event(event)
}

/// Push an event representing auxiliary data for a precompile call to the state.
pub fn push_precompile_event(&mut self, event: PrecompileEvent) {
self.block.add_precompile_event(event)
}

pub(crate) fn get_step_err(
&self,
step: &GethExecStep,
Expand Down
12 changes: 11 additions & 1 deletion bus-mapping/src/circuit_input_builder/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,24 @@ pub struct Transaction {
/// The transaction id
pub id: u64,
/// The raw transaction fields
tx: geth_types::Transaction,
pub tx: geth_types::Transaction,
/// Calls made in the transaction
pub(crate) calls: Vec<Call>,
/// Execution steps
steps: Vec<ExecStep>,
}

impl Transaction {
/// Create a dummy Transaction with zero values
pub fn dummy() -> Self {
Self {
id: 0,
calls: Vec::new(),
steps: Vec::new(),
tx: geth_types::Transaction::dummy(),
}
}

/// Create a new Self.
pub fn new(
id: u64,
Expand Down
24 changes: 18 additions & 6 deletions bus-mapping/src/evm/opcodes/callop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {

// insert a copy event (input) for this step and generate memory op
let rw_counter_start = state.block_ctx.rwc;
if call.call_data_length > 0 {
let input_bytes = if call.call_data_length > 0 {
let n_input_bytes = if let Some(input_len) = precompile_call.input_len() {
min(input_len, call.call_data_length as usize)
} else {
Expand Down Expand Up @@ -390,11 +390,14 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
bytes: input_bytes.iter().map(|s| (*s, false)).collect(),
},
);
}
Some(input_bytes)
} else {
None
};

// write the result in the callee's memory
let rw_counter_start = state.block_ctx.rwc;
if call.is_success && !result.is_empty() {
let output_bytes = if call.is_success && !result.is_empty() {
let (output_bytes, _prev_bytes) = state
.gen_copy_steps_for_precompile_callee_memory(&mut exec_step, &result)?;

Expand All @@ -413,11 +416,14 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
bytes: output_bytes.iter().map(|s| (*s, false)).collect(),
},
);
}
Some(output_bytes)
} else {
None
};

// insert another copy event (output) for this step.
let rw_counter_start = state.block_ctx.rwc;
if call.is_success && length > 0 {
let return_bytes = if call.is_success && length > 0 {
let return_bytes = state.gen_copy_steps_for_precompile_returndata(
&mut exec_step,
call.return_data_offset,
Expand All @@ -439,7 +445,10 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
bytes: return_bytes.iter().map(|s| (*s, false)).collect(),
},
);
}
Some(return_bytes)
} else {
None
};

if has_oog_err {
let mut oog_step = ErrorOOGPrecompile::gen_associated_ops(
Expand All @@ -462,6 +471,9 @@ impl<const N_ARGS: usize> Opcode for CallOpcode<N_ARGS> {
geth_steps[1].clone(),
call.clone(),
precompile_call,
&input_bytes.unwrap_or_default(),
&output_bytes.unwrap_or_default(),
&return_bytes.unwrap_or_default(),
)?;

// Set gas left and gas cost for precompile step.
Expand Down
22 changes: 7 additions & 15 deletions bus-mapping/src/evm/opcodes/precompiles/ecrecover.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use eth_types::{
sign_types::{biguint_to_32bytes_le, recover_pk, SignData, SECP256K1_Q},
Bytes, ToBigEndian, ToLittleEndian,
ToBigEndian, ToLittleEndian,
};
use ethers_core::k256::elliptic_curve::PrimeField;
use halo2_proofs::halo2curves::{
group::prime::PrimeCurveAffine,
group::{ff::PrimeField, prime::PrimeCurveAffine},
secp256k1::{Fq, Secp256k1Affine},
};
use num::{BigUint, Integer};
Expand All @@ -15,18 +14,11 @@ use crate::{
};

pub(crate) fn opt_data(
input_bytes: Option<Vec<u8>>,
output_bytes: Option<Vec<u8>>,
input_bytes: &[u8],
output_bytes: &[u8],
return_bytes: &[u8],
) -> (Option<PrecompileEvent>, Option<PrecompileAuxData>) {
let input_bytes = input_bytes.map_or(vec![0u8; 128], |mut bytes| {
bytes.resize(128, 0u8);
bytes
});
let output_bytes = output_bytes.map_or(vec![0u8; 32], |mut bytes| {
bytes.resize(32, 0u8);
bytes
});
let aux_data = EcrecoverAuxData::new(input_bytes, output_bytes);
let aux_data = EcrecoverAuxData::new(input_bytes, output_bytes, return_bytes);

// We skip the validation through sig circuit if r or s was not in canonical form.
let opt_sig_r: Option<Fq> = Fq::from_bytes(&aux_data.sig_r.to_le_bytes()).into();
Expand All @@ -50,7 +42,7 @@ pub(crate) fn opt_data(
sig_v,
),
pk: recovered_pk,
msg: Bytes::default(),
// msg: Bytes::default(),
msg_hash: {
let msg_hash = BigUint::from_bytes_be(&aux_data.msg_hash.to_be_bytes());
let msg_hash = msg_hash.mod_floor(&*SECP256K1_Q);
Expand Down
30 changes: 29 additions & 1 deletion bus-mapping/src/evm/opcodes/precompiles/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,50 @@ use eth_types::{GethExecStep, ToWord, Word};
use crate::{
circuit_input_builder::{Call, CircuitInputStateRef, ExecState, ExecStep},
operation::CallContextField,
precompile::PrecompileCalls,
precompile::{PrecompileAuxData, PrecompileCalls},
Error,
};

mod ecrecover;

use ecrecover::opt_data as opt_data_ecrecover;

pub fn gen_associated_ops(
state: &mut CircuitInputStateRef,
geth_step: GethExecStep,
call: Call,
precompile: PrecompileCalls,
input_bytes: &[u8],
output_bytes: &[u8],
return_bytes: &[u8],
) -> Result<ExecStep, Error> {
assert_eq!(call.code_address(), Some(precompile.into()));
let mut exec_step = state.new_step(&geth_step)?;
exec_step.exec_state = ExecState::Precompile(precompile);

common_call_ctx_reads(state, &mut exec_step, &call)?;

let (opt_event, aux_data) = match precompile {
PrecompileCalls::Ecrecover => opt_data_ecrecover(input_bytes, output_bytes, return_bytes),
_ => {
log::warn!("precompile {:?} unsupported in circuits", precompile);
(
None,
Some(PrecompileAuxData::Base {
input_bytes: input_bytes.to_vec(),
output_bytes: output_bytes.to_vec(),
return_bytes: return_bytes.to_vec(),
}),
)
}
};
log::trace!("precompile event {opt_event:?}, aux data {aux_data:?}");

if let Some(event) = opt_event {
state.push_precompile_event(event);
}
exec_step.aux_data = aux_data;

Ok(exec_step)
}

Expand Down
38 changes: 29 additions & 9 deletions bus-mapping/src/precompile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,24 +221,35 @@ pub struct EcrecoverAuxData {
pub sig_s: Word,
/// Address that was recovered.
pub recovered_addr: Address,
/// Input bytes to the ecrecover call.
pub input_bytes: Vec<u8>,
/// Output bytes from the ecrecover call.
pub output_bytes: Vec<u8>,
/// Bytes returned to the caller from the ecrecover call.
pub return_bytes: Vec<u8>,
}

impl EcrecoverAuxData {
/// Create a new instance of ecrecover auxiliary data.
pub fn new(input: Vec<u8>, output: Vec<u8>) -> Self {
assert_eq!(input.len(), 128);
assert_eq!(output.len(), 32);
pub fn new(input: &[u8], output: &[u8], return_bytes: &[u8]) -> Self {
let mut resized_input = input.to_vec();
resized_input.resize(128, 0u8);
let mut resized_output = output.to_vec();
resized_output.resize(32, 0u8);

// assert that recovered address is 20 bytes.
assert!(output[0x00..0x0c].iter().all(|&b| b == 0));
let recovered_addr = Address::from_slice(&output[0x0c..0x20]);
assert!(resized_output[0x00..0x0c].iter().all(|&b| b == 0));
let recovered_addr = Address::from_slice(&resized_output[0x0c..0x20]);

Self {
msg_hash: Word::from_big_endian(&input[0x00..0x20]),
sig_v: Word::from_big_endian(&input[0x20..0x40]),
sig_r: Word::from_big_endian(&input[0x40..0x60]),
sig_s: Word::from_big_endian(&input[0x60..0x80]),
msg_hash: Word::from_big_endian(&resized_input[0x00..0x20]),
sig_v: Word::from_big_endian(&resized_input[0x20..0x40]),
sig_r: Word::from_big_endian(&resized_input[0x40..0x60]),
sig_s: Word::from_big_endian(&resized_input[0x60..0x80]),
recovered_addr,
input_bytes: input.to_vec(),
output_bytes: output.to_vec(),
return_bytes: return_bytes.to_vec(),
}
}

Expand All @@ -257,6 +268,15 @@ impl EcrecoverAuxData {
/// Auxiliary data attached to an internal state for precompile verification.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PrecompileAuxData {
/// Base precompile (used for Identity, SHA256, RIPEMD-160 and BLAKE2F).
Base {
/// input bytes to the identity call.
input_bytes: Vec<u8>,
/// output bytes from the identity call.
output_bytes: Vec<u8>,
/// bytes returned back to the caller from the identity call.
return_bytes: Vec<u8>,
},
/// Ecrecover.
Ecrecover(EcrecoverAuxData),
}
Expand Down
Loading

0 comments on commit 99d2b1c

Please sign in to comment.