This repository has been archived by the owner on Nov 25, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
feat: integrate secp256r1 precompile #6
Merged
Merged
Changes from 4 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c4a2e49
feat: integrate secp256r1 precompile
fgimenez 5f2b30f
update precompile address
fgimenez 9621117
fix and enable test
fgimenez 203084d
add more tests
fgimenez b5ef65a
prevent copying bytes
fgimenez 8615a7a
use pad utils from revm_precompile
fgimenez 2ba34e6
Update crates/precompile/src/secp256r1.rs
fgimenez b99172f
simplify result return
fgimenez 37f4fd3
return verification failure on input len < 160
fgimenez 4b31c8a
add input format doc
fgimenez File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[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 | ||
|
||
[dev-dependencies] | ||
rstest.workspace = true | ||
|
||
[lints] | ||
workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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], | ||
]) | ||
} | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
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(11), /* 0x0b according to https://eips.ethereum.org/EIPS/eip-7212#specification */ | ||
fgimenez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Precompile::Standard(p256_verify as StandardPrecompileFn), | ||
); | ||
|
||
fn p256_verify(i: &Bytes, target_gas: u64) -> PrecompileResult { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. excellent
fgimenez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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)]); | ||
fgimenez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// 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(); | ||
fgimenez marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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())) | ||
DaniPopes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod test { | ||
use super::p256_verify; | ||
use revm_primitives::{hex::FromHex, Bytes, PrecompileError}; | ||
use rstest::rstest; | ||
|
||
#[rstest] | ||
// test vectors from https://github.com/daimo-eth/p256-verifier/tree/master/test-vectors | ||
#[case::ok_1("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", true)] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. interesting that this generates multiple tests, I usually just do this with an array / loop There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, there are other niceties from |
||
#[case::ok_2("3fec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", true)] | ||
#[case::ok_3("e775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", true)] | ||
#[case::ok_4("b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", true)] | ||
#[case::ok_5("858b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf31b7c691f5ce665f8aae0bda895c23595c834fecc2390a5bcc203b04afcacbb4280713287a2d0c37e23f7513fab898f2c1fefa00ec09a924c335d9b629f1d4fb71901c3e59611afbfea354d101324e894c788d1c01f00b3c251b2", true)] | ||
#[case::fail_1("3cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", false)] | ||
#[case::fail_2("afec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", false)] | ||
#[case::fail_3("f775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", false)] | ||
#[case::fail_4("c5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", false)] | ||
#[case::fail_5("958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf31b7c691f5ce665f8aae0bda895c23595c834fecc2390a5bcc203b04afcacbb4280713287a2d0c37e23f7513fab898f2c1fefa00ec09a924c335d9b629f1d4fb71901c3e59611afbfea354d101324e894c788d1c01f00b3c251b2", false)] | ||
fn test_sig_verify(#[case] input: &str, #[case] expect_success: bool) { | ||
let input = Bytes::from_hex(input).unwrap(); | ||
let target_gas = 3_500u64; | ||
let (gas_used, res) = p256_verify(&input, target_gas).unwrap(); | ||
assert_eq!(gas_used, 3_450u64); | ||
let expected_result_str = if expect_success { | ||
"0000000000000000000000000000000000000000000000000000000000000001" | ||
} else { | ||
"0000000000000000000000000000000000000000000000000000000000000000" | ||
}; | ||
let expected_result = Bytes::from_hex(expected_result_str).unwrap(); | ||
assert_eq!(res, expected_result.to_vec()); | ||
} | ||
|
||
#[rstest] | ||
fn test_not_enough_gas_fails() { | ||
let input = Bytes::from_hex("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e").unwrap(); | ||
let target_gas = 2_500u64; | ||
let result = p256_verify(&input, target_gas); | ||
|
||
assert!(result.is_err()); | ||
assert_eq!(result.err(), Some(PrecompileError::OutOfGas)); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
think alloy should support this? @DaniPopes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
found it in revm, but it's not public there https://github.com/bluealloy/revm/blob/main/crates/precompile/src/lib.rs#L263 would be indeed very helpful to be able to import it from somewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will make it pub