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

Commit

Permalink
feat: integrate secp256r1 precompile
Browse files Browse the repository at this point in the history
  • Loading branch information
fgimenez committed Mar 6, 2024
1 parent 8439dbb commit c4a2e49
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 13 deletions.
42 changes: 42 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["bin/alphanet/", "crates/node"]
members = ["bin/alphanet/", "crates/node", "crates/precompile"]
default-members = ["bin/alphanet/"]
resolver = "2"

Expand Down Expand Up @@ -43,6 +43,7 @@ incremental = false
[workspace.dependencies]
# alphanet
alphanet-node = { path = "crates/node" }
alphanet-precompile = { path = "crates/precompile" }

# tokio
tokio = { version = "1.21", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions crates/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ keywords.workspace = true
categories.workspace = true

[dependencies]
alphanet-precompile.workspace = true
reth.workspace = true
reth-node-api.workspace = true
reth-node-optimism.workspace = true
Expand Down
16 changes: 4 additions & 12 deletions crates/node/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use alphanet_precompile::secp256r1::P256VERIFY;
use reth::{
primitives::{
address,
revm::{config::revm_spec, env::fill_op_tx_env},
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, Env, PrecompileResult, TxEnv},
revm_primitives::{AnalysisKind, CfgEnvWithHandlerCfg, TxEnv},
Address, Bytes, ChainSpec, Head, Header, Transaction, U256,
},
revm::{
handler::register::EvmHandler,
precompile::{Precompile, PrecompileSpecId, Precompiles},
precompile::{PrecompileSpecId, Precompiles},
Database, Evm, EvmBuilder,
},
};
Expand Down Expand Up @@ -36,18 +36,10 @@ impl AlphaNetEvmConfig {
// install the precompiles
handler.pre_execution.load_precompiles = Arc::new(move || {
let mut precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec_id)).clone();
precompiles.inner.insert(
address!("0000000000000000000000000000000000000999"),
Precompile::Env(Self::alphanet_precompile),
);
precompiles.inner.insert(P256VERIFY.0, P256VERIFY.1);
precompiles
});
}

/// A custom precompile that does nothing
fn alphanet_precompile(_data: &Bytes, _gas: u64, _env: &Env) -> PrecompileResult {
Ok((0, Bytes::new()))
}
}

impl ConfigureEvm for AlphaNetEvmConfig {
Expand Down
18 changes: 18 additions & 0 deletions crates/precompile/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[package]
name = "alphanet-precompile"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
keywords.workspace = true
categories.workspace = true

[dependencies]
p256 = { version = "0.13.2", features = ["ecdsa"] }
reth.workspace = true
revm-primitives.workspace = true

[lints]
workspace = true
19 changes: 19 additions & 0 deletions crates/precompile/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! # alphanet-precompile
//!
//! Implementations of EVM precompiled contracts for AlphaNet.
/// EIP-7212 secp256r1 precompile.
pub mod secp256r1;

/// Const function for making an address by concatenating the bytes from two given numbers.
///
/// Note that 32 + 128 = 160 = 20 bytes (the length of an address). This function is used
/// as a convenience for specifying the addresses of the various precompiles.
use revm_primitives::Address;
#[inline]
const fn u64_to_address(x: u64) -> Address {
let x = x.to_be_bytes();
Address::new([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
])
}
63 changes: 63 additions & 0 deletions crates/precompile/src/secp256r1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use reth::revm::precompile::{Precompile, PrecompileWithAddress};
use revm_primitives::{Bytes, PrecompileError, PrecompileResult, StandardPrecompileFn};

/// EIP-7212 secp256r1 precompile.
pub const P256VERIFY: PrecompileWithAddress = PrecompileWithAddress(
crate::u64_to_address(10),
Precompile::Standard(p256_verify as StandardPrecompileFn),
);

fn p256_verify(i: &Bytes, target_gas: u64) -> PrecompileResult {
use core::cmp::min;
use p256::ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey};

const P256VERIFY_BASE: u64 = 3_450;

if P256VERIFY_BASE > target_gas {
return Err(PrecompileError::OutOfGas);
}
let mut input = [0u8; 160];
input[..min(i.len(), 160)].copy_from_slice(&i[..min(i.len(), 160)]);

// msg signed (msg is already the hash of the original message)
let msg: [u8; 32] = input[..32].try_into().unwrap();
// r, s: signature
let sig: [u8; 64] = input[32..96].try_into().unwrap();
// x, y: public key
let pk: [u8; 64] = input[96..160].try_into().unwrap();
// append 0x04 to the public key: uncompressed form
let mut uncompressed_pk = [0u8; 65];
uncompressed_pk[0] = 0x04;
uncompressed_pk[1..].copy_from_slice(&pk);

let signature: Signature = Signature::from_slice(&sig).unwrap();
let public_key: VerifyingKey = VerifyingKey::from_sec1_bytes(&uncompressed_pk).unwrap();

let mut result = [0u8; 32];

// verify
if public_key.verify_prehash(&msg, &signature).is_ok() {
result[31] = 0x01;
Ok((P256VERIFY_BASE, result.into()))
} else {
Ok((P256VERIFY_BASE, result.into()))
}
}

#[cfg(test)]
mod test {
use super::p256_verify;
use revm_primitives::Bytes;

#[test]
#[ignore]
fn proper_sig_verify() {
let input = Bytes::from("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e");
let target_gas = 3_500u64;
let (gas_used, res) = p256_verify(&input, target_gas).unwrap();
assert_eq!(gas_used, 3_450u64);
let mut expected_res = [0u8; 32];
expected_res[31] = 1;
assert_eq!(res, expected_res.to_vec());
}
}

0 comments on commit c4a2e49

Please sign in to comment.