1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use eth_types::{GethExecStep, ToWord, Word};

use crate::{
    circuit_input_builder::{Call, CircuitInputStateRef, ExecState, ExecStep},
    operation::CallContextField,
    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),
        PrecompileCalls::Identity => (
            None,
            Some(PrecompileAuxData::Base {
                input_bytes: input_bytes.to_vec(),
                output_bytes: output_bytes.to_vec(),
                return_bytes: return_bytes.to_vec(),
            }),
        ),
        _ => {
            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)
}

fn common_call_ctx_reads(
    state: &mut CircuitInputStateRef,
    exec_step: &mut ExecStep,
    call: &Call,
) -> Result<(), Error> {
    for (field, value) in [
        (
            CallContextField::IsSuccess,
            Word::from(call.is_success as u64),
        ),
        (
            CallContextField::CalleeAddress,
            call.code_address().unwrap().to_word(),
        ),
        (CallContextField::CallerId, call.caller_id.into()),
        (
            CallContextField::CallDataOffset,
            call.call_data_offset.into(),
        ),
        (
            CallContextField::CallDataLength,
            call.call_data_length.into(),
        ),
        (
            CallContextField::ReturnDataOffset,
            call.return_data_offset.into(),
        ),
        (
            CallContextField::ReturnDataLength,
            call.return_data_length.into(),
        ),
    ] {
        state.call_context_read(exec_step, call.call_id, field, value)?;
    }

    Ok(())
}