Skip to content

Commit 9130e7e

Browse files
authored
feat: revm precompile crypto skeleton (#1076)
depends on #1069 (requires rust 1.88)
1 parent d096f28 commit 9130e7e

File tree

12 files changed

+1439
-51
lines changed

12 files changed

+1439
-51
lines changed

Cargo.lock

Lines changed: 1082 additions & 49 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ serde_json = "1.0"
5656
strum = "0.26"
5757
strum_macros = "0.26"
5858
substrate-bn = { version = "0.6.0" }
59-
thiserror = "1" # do we need this?
59+
thiserror = "2"
6060
thread_local = "1.1"
6161
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
6262
tracing = { version = "0.1", features = [

clippy.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ allowed-duplicate-crates = [
77
"regex-automata",
88
"regex-syntax",
99
"syn",
10+
"thiserror",
11+
"thiserror-impl",
1012
"windows-sys",
1113
"tracing-subscriber",
1214
"wasi",

guest_libs/crypto/Cargo.toml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
categories = ["cryptography", "zk", "blockchain", "ceno"]
3+
description = "Ceno zkVM Crypto Guest Library"
4+
edition = "2021"
5+
keywords = ["cryptography", "zk", "blockchain", "ceno"]
6+
license = "MIT OR Apache-2.0"
7+
name = "ceno_crypto"
8+
readme = "README.md"
9+
repository = "https://github.com/scroll-tech/ceno"
10+
version = "0.1.0"
11+
12+
[dependencies]
13+
ceno_rt = { path = "../../ceno_rt" }
14+
thiserror.workspace = true
15+
16+
[dev-dependencies]
17+
alloy-consensus = { version = "1.0", features = ["crypto-backend"] }
18+
alloy-primitives = "1.4"
19+
revm-precompile = "27"

guest_libs/crypto/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Ceno Crypto Providers
2+
3+
**WORKING IN PROGRESS**
4+
5+
TODOs:
6+
- [ ] secp256k1
7+
- [ ] bn254
8+
- [ ] sha256
9+
- [ ] secp256r1
10+
11+
## Usage
12+
13+
Enable the `crypto-backend` feature of `alloy-consensus` in your `Cargo.toml`:
14+
15+
```toml
16+
[dependencies]
17+
alloy-consensus = { version = "1.0", features = ["crypto-backend"] }
18+
```
19+
20+
In your guest program:
21+
22+
```rust
23+
use ceno_crypto::ceno_crypto;
24+
25+
// By default, it generates a struct named `CenoCrypto`,
26+
// using `revm_precompile` crate as revm_precompile,
27+
// `alloy_consensus` crate as alloy_consensus, and `alloy_primitives::Address` as Address type,
28+
// and implements the `Crypto` trait of revm_precompile and `CryptoProvider` of alloy_consensus.
29+
ceno_crypto!();
30+
31+
// You can change the name of generated struct
32+
// ceno_crypto!(name = MyCryptoProvider);
33+
34+
// or using different revm_precompile crate (default is revm_precompile)
35+
// ceno_crypto!(revm_precompile = revm::precompile);
36+
37+
// or using different alloy_consensus crate (default is alloy_consensus)
38+
// ceno_crypto!(alloy_consensus = alloy::consensus);
39+
40+
// or using different `Address` type (default is alloy_primitives::Address)
41+
// ceno_crypto!(address_type = alloy::primitives::Address);
42+
43+
// or mix above options in arbitrary order
44+
45+
fn main() {
46+
CenoCrypto::install();
47+
48+
// or use fallible version
49+
// CenoCrypto::try_install().ok();
50+
51+
// Your other code here
52+
}
53+
```

guest_libs/crypto/src/bn254.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use crate::CenoCryptoError;
2+
3+
/// BN254 elliptic curve addition.
4+
pub fn bn254_g1_add(_p1: &[u8], _p2: &[u8]) -> Result<[u8; 64], CenoCryptoError> {
5+
unimplemented!()
6+
}
7+
8+
/// BN254 elliptic curve scalar multiplication.
9+
pub fn bn254_g1_mul(_point: &[u8], _scalar: &[u8]) -> Result<[u8; 64], CenoCryptoError> {
10+
unimplemented!()
11+
}
12+
13+
/// BN254 pairing check.
14+
pub fn bn254_pairing_check(_pairs: &[(&[u8], &[u8])]) -> Result<bool, CenoCryptoError> {
15+
unimplemented!()
16+
}

guest_libs/crypto/src/lib.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#![deny(missing_docs)]
2+
//! Ceno zkVM guest implementations for the revm precompile crypto interface.
3+
//!
4+
//! This crate is revm version ir-relevant, unless the signature of the precompiles change.
5+
6+
/// BN254 elliptic curve
7+
pub mod bn254;
8+
/// secp256k1
9+
pub mod secp256k1;
10+
/// secp256r1
11+
pub mod secp256r1;
12+
/// SHA-256 implementation.
13+
pub mod sha256;
14+
15+
mod macros;
16+
17+
/// Error returned when trying to install the crypto provider more than once.
18+
#[derive(Debug, thiserror::Error)]
19+
#[error("Crypto provider has already been installed")]
20+
pub struct CenoCryptoInstallError;
21+
22+
/// Errors that can occur during cryptographic operations.
23+
#[derive(Debug, thiserror::Error)]
24+
#[non_exhaustive]
25+
pub enum CenoCryptoError {
26+
/// Bn254 errors
27+
#[error("Bn254 field point is not a member of the field")]
28+
Bn254FieldPointNotAMember,
29+
/// Bn254 affine g failed to create
30+
#[error("Bn254 affine G failed to create")]
31+
Bn254AffineGFailedToCreate,
32+
/// Bn254 pair length
33+
#[error("Bn254 pair length error")]
34+
Bn254PairLength,
35+
/// Sepk256k1 ecrecover error
36+
#[error("Secp256k1 ecrecover error")]
37+
Secp256k1EcRecover,
38+
}
39+
40+
#[cfg(test)]
41+
mod test {
42+
use super::*;
43+
44+
#[test]
45+
fn test_install() {
46+
{
47+
ceno_crypto!(name = MyCustomName);
48+
}
49+
{
50+
use revm_precompile as another_crate;
51+
ceno_crypto!(revm_precompile = another_crate);
52+
}
53+
{
54+
use alloy_consensus as another_crate;
55+
ceno_crypto!(alloy_consensus = another_crate);
56+
}
57+
{
58+
use alloy_primitives::Address as AnotherAddress;
59+
ceno_crypto!(address_type = AnotherAddress);
60+
}
61+
{
62+
use alloy_primitives::Address as AnotherAddress;
63+
ceno_crypto!(address_type = AnotherAddress);
64+
}
65+
{
66+
use alloy_consensus as another_crate;
67+
use alloy_primitives::Address as AnotherAddress;
68+
ceno_crypto!(
69+
address_type = AnotherAddress,
70+
alloy_consensus = another_crate
71+
);
72+
}
73+
{
74+
use alloy_consensus as another_crate;
75+
use alloy_primitives::Address as AnotherAddress;
76+
ceno_crypto!(
77+
alloy_consensus = another_crate,
78+
address_type = AnotherAddress
79+
);
80+
}
81+
82+
ceno_crypto!();
83+
CenoCrypto::install();
84+
}
85+
}

guest_libs/crypto/src/macros.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/// Declare a crypto operations provider using the Ceno zkVM guest implementations.
2+
#[macro_export]
3+
macro_rules! ceno_crypto {
4+
( $( $key:ident = $val:tt ),* $(,)? ) => {
5+
// default values
6+
ceno_crypto!(@parse {
7+
revm_precompile: ::revm_precompile,
8+
alloy_consensus: ::alloy_consensus,
9+
address_type: ::alloy_primitives::Address,
10+
name: CenoCrypto
11+
} $( $key = $val, )* );
12+
};
13+
14+
// parse optional args
15+
(@parse { revm_precompile: $r:path, alloy_consensus: $ac:path, address_type: $addr:path, name: $n:tt }
16+
revm_precompile = $nr:path $(, $($rest:tt)*)?
17+
) => {
18+
ceno_crypto!(@parse { revm_precompile: $nr, alloy_consensus: $ac, address_type: $addr, name: $n } $($($rest)*)? );
19+
};
20+
21+
(@parse { revm_precompile: $r:path, alloy_consensus: $ac:path, address_type: $addr:path, name: $n:tt }
22+
alloy_consensus = $nac:path $(, $($rest:tt)*)?
23+
) => {
24+
ceno_crypto!(@parse { revm_precompile: $r, alloy_consensus: $nac, address_type: $addr, name: $n } $($($rest)*)? );
25+
};
26+
27+
(@parse { revm_precompile: $r:path, alloy_consensus: $ac:path, address_type: $addr:path, name: $n:tt }
28+
address_type = $na:path $(, $($rest:tt)*)?
29+
) => {
30+
ceno_crypto!(@parse { revm_precompile: $r, alloy_consensus: $ac, address_type: $na, name: $n } $($($rest)*)? );
31+
};
32+
33+
(@parse { revm_precompile: $r:path, alloy_consensus: $ac:path, address_type: $addr:path, name: $n:tt }
34+
name = $nn:ident $(, $($rest:tt)*)?
35+
) => {
36+
ceno_crypto!(@parse { revm_precompile: $r, alloy_consensus: $ac, address_type: $addr, name: $nn } $($($rest)*)? );
37+
};
38+
39+
// unknown key
40+
(@parse { $($state:tt)* } $bad:ident = $($rest:tt)*) => {
41+
compile_error!(concat!("unknown option: ", stringify!($bad)));
42+
};
43+
44+
45+
// finish parsing
46+
(@parse { revm_precompile: $r:path, alloy_consensus: $ac:path, address_type: $addr:path, name: $n:ident } $(,)?) => {
47+
use $ac as __ac;
48+
use $r as __rp;
49+
50+
/// Ceno zkVM crypto operations provider
51+
#[derive(Debug)]
52+
#[allow(dead_code)]
53+
pub struct $n;
54+
55+
impl $n {
56+
/// Install this as the global crypto provider.
57+
///
58+
/// # Panics
59+
///
60+
/// Panics if a crypto provider has already been installed.
61+
#[allow(dead_code)]
62+
pub fn install() {
63+
Self::try_install().unwrap();
64+
}
65+
66+
/// Install this as the global crypto provider.
67+
#[allow(dead_code)]
68+
pub fn try_install() -> Result<(), $crate::CenoCryptoInstallError> {
69+
let revm_install = __rp::install_crypto(Self);
70+
let alloy_install =
71+
__ac::crypto::install_default_provider(::std::sync::Arc::new(Self)).is_ok();
72+
if !(revm_install && alloy_install) {
73+
Err($crate::CenoCryptoInstallError)
74+
} else {
75+
Ok(())
76+
}
77+
}
78+
}
79+
80+
#[allow(dead_code)]
81+
fn __map_err(e: $crate::CenoCryptoError) -> __rp::PrecompileError {
82+
match e {
83+
$crate::CenoCryptoError::Bn254FieldPointNotAMember => {
84+
__rp::PrecompileError::Bn254FieldPointNotAMember
85+
}
86+
$crate::CenoCryptoError::Bn254AffineGFailedToCreate => {
87+
__rp::PrecompileError::Bn254AffineGFailedToCreate
88+
}
89+
$crate::CenoCryptoError::Bn254PairLength => __rp::PrecompileError::Bn254PairLength,
90+
_ => __rp::PrecompileError::Other(e.to_string()),
91+
}
92+
}
93+
94+
impl __rp::Crypto for $n {
95+
#[inline]
96+
fn sha256(&self, input: &[u8]) -> [u8; 32] {
97+
$crate::sha256::sha256(input)
98+
}
99+
#[inline]
100+
fn bn254_g1_add(
101+
&self,
102+
p1: &[u8],
103+
p2: &[u8],
104+
) -> Result<[u8; 64], __rp::PrecompileError> {
105+
$crate::bn254::bn254_g1_add(p1, p2).map_err(__map_err)
106+
}
107+
#[inline]
108+
fn bn254_g1_mul(
109+
&self,
110+
point: &[u8],
111+
scalar: &[u8],
112+
) -> Result<[u8; 64], __rp::PrecompileError> {
113+
$crate::bn254::bn254_g1_mul(point, scalar).map_err(__map_err)
114+
}
115+
#[inline]
116+
fn bn254_pairing_check(
117+
&self,
118+
pairs: &[(&[u8], &[u8])],
119+
) -> Result<bool, __rp::PrecompileError> {
120+
$crate::bn254::bn254_pairing_check(pairs).map_err(__map_err)
121+
}
122+
#[inline]
123+
fn secp256k1_ecrecover(
124+
&self,
125+
sig: &[u8; 64],
126+
recid: u8,
127+
msg: &[u8; 32],
128+
) -> Result<[u8; 32], __rp::PrecompileError> {
129+
$crate::secp256k1::secp256k1_ecrecover(sig, recid, msg).map_err(__map_err)
130+
}
131+
#[inline]
132+
fn secp256r1_verify_signature(
133+
&self,
134+
msg: &[u8; 32],
135+
sig: &[u8; 64],
136+
pk: &[u8; 64],
137+
) -> bool {
138+
$crate::secp256r1::secp256r1_verify_signature(msg, sig, pk)
139+
}
140+
}
141+
142+
impl __ac::crypto::backend::CryptoProvider for $n {
143+
#[inline]
144+
fn recover_signer_unchecked(
145+
&self,
146+
sig: &[u8; 65],
147+
msg: &[u8; 32],
148+
) -> Result<$addr, __ac::crypto::RecoveryError> {
149+
use $addr as Address;
150+
$crate::secp256k1::secp256k1_ecrecover(
151+
(&sig[..64]).try_into().unwrap(),
152+
sig[64],
153+
msg,
154+
)
155+
.map(|res| Address::from_slice(&res[12..]))
156+
.map_err(__ac::crypto::RecoveryError::from_source)
157+
}
158+
}
159+
};
160+
}

guest_libs/crypto/src/secp256k1.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
use crate::CenoCryptoError;
2+
3+
/// secp256k1 ECDSA signature recovery.
4+
#[inline]
5+
pub fn secp256k1_ecrecover(
6+
_sig: &[u8; 64],
7+
_recid: u8,
8+
_msg: &[u8; 32],
9+
) -> Result<[u8; 32], CenoCryptoError> {
10+
unimplemented!()
11+
}

guest_libs/crypto/src/secp256r1.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// secp256r1 (P-256) signature verification.
2+
#[inline]
3+
pub fn secp256r1_verify_signature(_msg: &[u8; 32], _sig: &[u8; 64], _pk: &[u8; 64]) -> bool {
4+
unimplemented!()
5+
}

0 commit comments

Comments
 (0)