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"))]
63#[allow(unused, unreachable_pub)]
64mod impl_secp256k1 {
65 use super::*;
66 pub(crate) use ::secp256k1::Error;
67 use ::secp256k1::{
68 ecdsa::{RecoverableSignature, RecoveryId},
69 Message, PublicKey, SecretKey, SECP256K1,
70 };
71 use alloy_primitives::{keccak256, Address, B256, U256};
72
73 pub(crate) fn recover_signer_unchecked(
80 sig: &[u8; 65],
81 msg: &[u8; 32],
82 ) -> Result<Address, Error> {
83 let sig =
84 RecoverableSignature::from_compact(&sig[0..64], RecoveryId::try_from(sig[64] as i32)?)?;
85
86 let public = SECP256K1.recover_ecdsa(&Message::from_digest(*msg), &sig)?;
87 Ok(public_key_to_address(public))
88 }
89
90 pub fn sign_message(secret: B256, message: B256) -> Result<Signature, Error> {
93 let sec = SecretKey::from_slice(secret.as_ref())?;
94 let s = SECP256K1.sign_ecdsa_recoverable(&Message::from_digest(message.0), &sec);
95 let (rec_id, data) = s.serialize_compact();
96
97 let signature = Signature::new(
98 U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
99 U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
100 i32::from(rec_id) != 0,
101 );
102 Ok(signature)
103 }
104
105 pub fn public_key_to_address(public: PublicKey) -> Address {
108 let hash = keccak256(&public.serialize_uncompressed()[1..]);
111 Address::from_slice(&hash[12..])
112 }
113}
114
115#[cfg_attr(feature = "secp256k1", allow(unused, unreachable_pub))]
116mod impl_k256 {
117 use super::*;
118 use alloy_primitives::{keccak256, Address, B256};
119 pub(crate) use k256::ecdsa::Error;
120 use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
121
122 pub(crate) fn recover_signer_unchecked(
129 sig: &[u8; 65],
130 msg: &[u8; 32],
131 ) -> Result<Address, Error> {
132 let mut signature = k256::ecdsa::Signature::from_slice(&sig[0..64])?;
133 let mut recid = sig[64];
134
135 if let Some(sig_normalized) = signature.normalize_s() {
137 signature = sig_normalized;
138 recid ^= 1;
139 }
140 let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
141
142 let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &signature, recid)?;
144 Ok(public_key_to_address(recovered_key))
145 }
146
147 pub fn sign_message(secret: B256, message: B256) -> Result<Signature, Error> {
150 let sec = SigningKey::from_slice(secret.as_ref())?;
151 sec.sign_prehash_recoverable(&message.0).map(Into::into)
152 }
153
154 pub fn public_key_to_address(public: VerifyingKey) -> Address {
157 let hash = keccak256(&public.to_encoded_point(false).as_bytes()[1..]);
158 Address::from_slice(&hash[12..])
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use alloy_primitives::{keccak256, B256};
165
166 #[cfg(feature = "secp256k1")]
167 #[test]
168 fn sanity_ecrecover_call_secp256k1() {
169 use super::impl_secp256k1::*;
170
171 let (secret, public) = secp256k1::generate_keypair(&mut rand::thread_rng());
172 let signer = public_key_to_address(public);
173
174 let message = b"hello world";
175 let hash = keccak256(message);
176 let signature =
177 sign_message(B256::from_slice(&secret.secret_bytes()[..]), hash).expect("sign message");
178
179 let mut sig: [u8; 65] = [0; 65];
180 sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
181 sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
182 sig[64] = signature.v() as u8;
183
184 assert_eq!(recover_signer_unchecked(&sig, &hash), Ok(signer));
185 }
186
187 #[cfg(not(feature = "secp256k1"))]
188 #[test]
189 fn sanity_ecrecover_call_k256() {
190 use super::impl_k256::*;
191
192 let secret = k256::ecdsa::SigningKey::random(&mut rand::thread_rng());
193 let public = *secret.verifying_key();
194 let signer = public_key_to_address(public);
195
196 let message = b"hello world";
197 let hash = keccak256(message);
198 let signature =
199 sign_message(B256::from_slice(&secret.to_bytes()[..]), hash).expect("sign message");
200
201 let mut sig: [u8; 65] = [0; 65];
202 sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
203 sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
204 sig[64] = signature.v() as u8;
205
206 assert_eq!(recover_signer_unchecked(&sig, &hash).ok(), Some(signer));
207 }
208
209 #[test]
210 fn sanity_secp256k1_k256_compat() {
211 use super::{impl_k256, impl_secp256k1};
212
213 let (secp256k1_secret, secp256k1_public) =
214 secp256k1::generate_keypair(&mut rand::thread_rng());
215 let k256_secret = k256::ecdsa::SigningKey::from_slice(&secp256k1_secret.secret_bytes())
216 .expect("k256 secret");
217 let k256_public = *k256_secret.verifying_key();
218
219 let secp256k1_signer = impl_secp256k1::public_key_to_address(secp256k1_public);
220 let k256_signer = impl_k256::public_key_to_address(k256_public);
221 assert_eq!(secp256k1_signer, k256_signer);
222
223 let message = b"hello world";
224 let hash = keccak256(message);
225
226 let secp256k1_signature = impl_secp256k1::sign_message(
227 B256::from_slice(&secp256k1_secret.secret_bytes()[..]),
228 hash,
229 )
230 .expect("secp256k1 sign");
231 let k256_signature =
232 impl_k256::sign_message(B256::from_slice(&k256_secret.to_bytes()[..]), hash)
233 .expect("k256 sign");
234 assert_eq!(secp256k1_signature, k256_signature);
235
236 let mut sig: [u8; 65] = [0; 65];
237
238 sig[0..32].copy_from_slice(&secp256k1_signature.r().to_be_bytes::<32>());
239 sig[32..64].copy_from_slice(&secp256k1_signature.s().to_be_bytes::<32>());
240 sig[64] = secp256k1_signature.v() as u8;
241 let secp256k1_recovered =
242 impl_secp256k1::recover_signer_unchecked(&sig, &hash).expect("secp256k1 recover");
243 assert_eq!(secp256k1_recovered, secp256k1_signer);
244
245 sig[0..32].copy_from_slice(&k256_signature.r().to_be_bytes::<32>());
246 sig[32..64].copy_from_slice(&k256_signature.s().to_be_bytes::<32>());
247 sig[64] = k256_signature.v() as u8;
248 let k256_recovered =
249 impl_k256::recover_signer_unchecked(&sig, &hash).expect("k256 recover");
250 assert_eq!(k256_recovered, k256_signer);
251
252 assert_eq!(secp256k1_recovered, k256_recovered);
253 }
254}