1use crate::transaction::signature::Signature;
4use alloy_primitives::U256;
5
6pub const SECP256K1N_HALF: U256 = U256::from_be_bytes([
11 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
12 0x5D, 0x57, 0x6E, 0x73, 0x57, 0xA4, 0x50, 0x1D, 0xDF, 0xE9, 0x2F, 0x46, 0x68, 0x1B, 0x20, 0xA0,
13]);
14
15pub mod secp256k1 {
17 use super::*;
18 use revm_primitives::{Address, B256};
19
20 #[cfg(not(feature = "secp256k1"))]
21 use super::impl_k256 as imp;
22 #[cfg(feature = "secp256k1")]
23 use super::impl_secp256k1 as imp;
24
25 use crate::transaction::signed::RecoveryError;
26 pub use imp::{public_key_to_address, sign_message};
27
28 pub fn recover_signer_unchecked(
35 signature: &Signature,
36 hash: B256,
37 ) -> Result<Address, RecoveryError> {
38 let mut sig: [u8; 65] = [0; 65];
39
40 sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
41 sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
42 sig[64] = signature.v() as u8;
43
44 imp::recover_signer_unchecked(&sig, &hash.0).map_err(|_| RecoveryError)
47 }
48
49 pub fn recover_signer(signature: &Signature, hash: B256) -> Result<Address, RecoveryError> {
55 if signature.s() > SECP256K1N_HALF {
56 return Err(RecoveryError)
57 }
58 recover_signer_unchecked(signature, hash)
59 }
60}
61
62#[cfg(any(test, feature = "secp256k1"))]
63mod impl_secp256k1 {
64 use super::*;
65 pub(crate) use ::secp256k1::Error;
66 use ::secp256k1::{
67 ecdsa::{RecoverableSignature, RecoveryId},
68 Message, PublicKey, SecretKey, SECP256K1,
69 };
70 use alloy_primitives::{keccak256, Address, B256, U256};
71
72 pub(crate) fn recover_signer_unchecked(
79 sig: &[u8; 65],
80 msg: &[u8; 32],
81 ) -> Result<Address, Error> {
82 let sig =
83 RecoverableSignature::from_compact(&sig[0..64], RecoveryId::try_from(sig[64] as i32)?)?;
84
85 let public = SECP256K1.recover_ecdsa(&Message::from_digest(*msg), &sig)?;
86 Ok(public_key_to_address(public))
87 }
88
89 pub fn sign_message(secret: B256, message: B256) -> Result<Signature, Error> {
92 let sec = SecretKey::from_slice(secret.as_ref())?;
93 let s = SECP256K1.sign_ecdsa_recoverable(&Message::from_digest(message.0), &sec);
94 let (rec_id, data) = s.serialize_compact();
95
96 let signature = Signature::new(
97 U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
98 U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
99 i32::from(rec_id) != 0,
100 );
101 Ok(signature)
102 }
103
104 pub fn public_key_to_address(public: PublicKey) -> Address {
107 let hash = keccak256(&public.serialize_uncompressed()[1..]);
110 Address::from_slice(&hash[12..])
111 }
112}
113
114#[cfg_attr(feature = "secp256k1", allow(unused, unreachable_pub))]
115mod impl_k256 {
116 use super::*;
117 use alloy_primitives::{keccak256, Address, B256};
118 pub(crate) use k256::ecdsa::Error;
119 use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
120
121 pub(crate) fn recover_signer_unchecked(
128 sig: &[u8; 65],
129 msg: &[u8; 32],
130 ) -> Result<Address, Error> {
131 let mut signature = k256::ecdsa::Signature::from_slice(&sig[0..64])?;
132 let mut recid = sig[64];
133
134 if let Some(sig_normalized) = signature.normalize_s() {
136 signature = sig_normalized;
137 recid ^= 1;
138 }
139 let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
140
141 let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &signature, recid)?;
143 Ok(public_key_to_address(recovered_key))
144 }
145
146 pub fn sign_message(secret: B256, message: B256) -> Result<Signature, Error> {
149 let sec = SigningKey::from_slice(secret.as_ref())?;
150 sec.sign_prehash_recoverable(&message.0).map(Into::into)
151 }
152
153 pub fn public_key_to_address(public: VerifyingKey) -> Address {
156 let hash = keccak256(&public.to_encoded_point(false).as_bytes()[1..]);
157 Address::from_slice(&hash[12..])
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use alloy_primitives::{keccak256, B256};
164
165 #[cfg(feature = "secp256k1")]
166 #[test]
167 fn sanity_ecrecover_call_secp256k1() {
168 use super::impl_secp256k1::*;
169
170 let (secret, public) = secp256k1::generate_keypair(&mut rand_08::thread_rng());
171 let signer = public_key_to_address(public);
172
173 let message = b"hello world";
174 let hash = keccak256(message);
175 let signature =
176 sign_message(B256::from_slice(&secret.secret_bytes()[..]), hash).expect("sign message");
177
178 let mut sig: [u8; 65] = [0; 65];
179 sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
180 sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
181 sig[64] = signature.v() as u8;
182
183 assert_eq!(recover_signer_unchecked(&sig, &hash), Ok(signer));
184 }
185
186 #[cfg(not(feature = "secp256k1"))]
187 #[test]
188 fn sanity_ecrecover_call_k256() {
189 use super::impl_k256::*;
190
191 let secret = k256::ecdsa::SigningKey::random(&mut rand::thread_rng());
192 let public = *secret.verifying_key();
193 let signer = public_key_to_address(public);
194
195 let message = b"hello world";
196 let hash = keccak256(message);
197 let signature =
198 sign_message(B256::from_slice(&secret.to_bytes()[..]), hash).expect("sign message");
199
200 let mut sig: [u8; 65] = [0; 65];
201 sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
202 sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
203 sig[64] = signature.v() as u8;
204
205 assert_eq!(recover_signer_unchecked(&sig, &hash).ok(), Some(signer));
206 }
207
208 #[test]
209 fn sanity_secp256k1_k256_compat() {
210 use super::{impl_k256, impl_secp256k1};
211
212 let (secp256k1_secret, secp256k1_public) =
213 secp256k1::generate_keypair(&mut rand_08::thread_rng());
214 let k256_secret = k256::ecdsa::SigningKey::from_slice(&secp256k1_secret.secret_bytes())
215 .expect("k256 secret");
216 let k256_public = *k256_secret.verifying_key();
217
218 let secp256k1_signer = impl_secp256k1::public_key_to_address(secp256k1_public);
219 let k256_signer = impl_k256::public_key_to_address(k256_public);
220 assert_eq!(secp256k1_signer, k256_signer);
221
222 let message = b"hello world";
223 let hash = keccak256(message);
224
225 let secp256k1_signature = impl_secp256k1::sign_message(
226 B256::from_slice(&secp256k1_secret.secret_bytes()[..]),
227 hash,
228 )
229 .expect("secp256k1 sign");
230 let k256_signature =
231 impl_k256::sign_message(B256::from_slice(&k256_secret.to_bytes()[..]), hash)
232 .expect("k256 sign");
233 assert_eq!(secp256k1_signature, k256_signature);
234
235 let mut sig: [u8; 65] = [0; 65];
236
237 sig[0..32].copy_from_slice(&secp256k1_signature.r().to_be_bytes::<32>());
238 sig[32..64].copy_from_slice(&secp256k1_signature.s().to_be_bytes::<32>());
239 sig[64] = secp256k1_signature.v() as u8;
240 let secp256k1_recovered =
241 impl_secp256k1::recover_signer_unchecked(&sig, &hash).expect("secp256k1 recover");
242 assert_eq!(secp256k1_recovered, secp256k1_signer);
243
244 sig[0..32].copy_from_slice(&k256_signature.r().to_be_bytes::<32>());
245 sig[32..64].copy_from_slice(&k256_signature.s().to_be_bytes::<32>());
246 sig[64] = k256_signature.v() as u8;
247 let k256_recovered =
248 impl_k256::recover_signer_unchecked(&sig, &hash).expect("k256 recover");
249 assert_eq!(k256_recovered, k256_signer);
250
251 assert_eq!(secp256k1_recovered, k256_recovered);
252 }
253}