use eth_types::{
sign_types::{biguint_to_32bytes_le, recover_pk, SignData, SECP256K1_Q},
ToBigEndian, ToLittleEndian,
};
use halo2_proofs::halo2curves::{
group::{ff::PrimeField, prime::PrimeCurveAffine},
secp256k1::{Fq, Secp256k1Affine},
};
use num::{BigUint, Integer};
use crate::{
circuit_input_builder::PrecompileEvent,
precompile::{EcrecoverAuxData, PrecompileAuxData},
};
pub(crate) fn opt_data(
input_bytes: &[u8],
output_bytes: &[u8],
return_bytes: &[u8],
) -> (Option<PrecompileEvent>, Option<PrecompileAuxData>) {
let aux_data = EcrecoverAuxData::new(input_bytes, output_bytes, return_bytes);
let opt_sig_r: Option<Fq> = Fq::from_bytes(&aux_data.sig_r.to_le_bytes()).into();
let opt_sig_s: Option<Fq> = Fq::from_bytes(&aux_data.sig_s.to_le_bytes()).into();
if opt_sig_r.zip(opt_sig_s).is_none() {
return (None, Some(PrecompileAuxData::Ecrecover(aux_data)));
}
if let Some(sig_v) = aux_data.recovery_id() {
let recovered_pk = recover_pk(
sig_v,
&aux_data.sig_r,
&aux_data.sig_s,
&aux_data.msg_hash.to_be_bytes(),
)
.unwrap_or(Secp256k1Affine::identity());
let sign_data = SignData {
signature: (
Fq::from_bytes(&aux_data.sig_r.to_le_bytes()).unwrap(),
Fq::from_bytes(&aux_data.sig_s.to_le_bytes()).unwrap(),
sig_v,
),
pk: recovered_pk,
msg: aux_data.input_bytes.clone().into(),
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);
let msg_hash_le = biguint_to_32bytes_le(msg_hash);
Fq::from_repr(msg_hash_le).unwrap()
},
};
(
Some(PrecompileEvent::Ecrecover(sign_data)),
Some(PrecompileAuxData::Ecrecover(aux_data)),
)
} else {
(None, Some(PrecompileAuxData::Ecrecover(aux_data)))
}
}