reth_primitives_traits/
crypto.rs1use 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
15#[cfg(feature = "secp256k1")]
17pub mod secp256k1 {
18 pub use super::impl_secp256k1::*;
19}
20
21#[cfg(not(feature = "secp256k1"))]
23pub mod secp256k1 {
24 pub use super::impl_k256::*;
25}
26
27#[cfg(feature = "secp256k1")]
28#[allow(unused)]
29mod impl_secp256k1 {
30 use super::*;
31 pub(crate) use ::secp256k1::Error;
32 use ::secp256k1::{
33 ecdsa::{RecoverableSignature, RecoveryId},
34 Message, PublicKey, SecretKey, SECP256K1,
35 };
36 use alloy_primitives::{keccak256, Address, B256, U256};
37
38 pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result<Address, Error> {
45 let sig =
46 RecoverableSignature::from_compact(&sig[0..64], RecoveryId::from_i32(sig[64] as i32)?)?;
47
48 let public = SECP256K1.recover_ecdsa(&Message::from_digest(*msg), &sig)?;
49 Ok(public_key_to_address(public))
50 }
51
52 pub fn sign_message(secret: B256, message: B256) -> Result<Signature, Error> {
55 let sec = SecretKey::from_slice(secret.as_ref())?;
56 let s = SECP256K1.sign_ecdsa_recoverable(&Message::from_digest(message.0), &sec);
57 let (rec_id, data) = s.serialize_compact();
58
59 let signature = Signature::new(
60 U256::try_from_be_slice(&data[..32]).expect("The slice has at most 32 bytes"),
61 U256::try_from_be_slice(&data[32..64]).expect("The slice has at most 32 bytes"),
62 rec_id.to_i32() != 0,
63 );
64 Ok(signature)
65 }
66
67 pub fn public_key_to_address(public: PublicKey) -> Address {
70 let hash = keccak256(&public.serialize_uncompressed()[1..]);
73 Address::from_slice(&hash[12..])
74 }
75}
76
77#[cfg_attr(feature = "secp256k1", allow(unused, unreachable_pub))]
78mod impl_k256 {
79 use super::*;
80 use alloy_primitives::{keccak256, Address, B256};
81 pub(crate) use k256::ecdsa::Error;
82 use k256::ecdsa::{RecoveryId, SigningKey, VerifyingKey};
83
84 pub fn recover_signer_unchecked(sig: &[u8; 65], msg: &[u8; 32]) -> Result<Address, Error> {
91 let mut signature = k256::ecdsa::Signature::from_slice(&sig[0..64])?;
92 let mut recid = sig[64];
93
94 if let Some(sig_normalized) = signature.normalize_s() {
96 signature = sig_normalized;
97 recid ^= 1;
98 }
99 let recid = RecoveryId::from_byte(recid).expect("recovery ID is valid");
100
101 let recovered_key = VerifyingKey::recover_from_prehash(&msg[..], &signature, recid)?;
103 Ok(public_key_to_address(recovered_key))
104 }
105
106 pub fn sign_message(secret: B256, message: B256) -> Result<Signature, Error> {
109 let sec = SigningKey::from_slice(secret.as_ref())?;
110 sec.sign_prehash_recoverable(&message.0).map(Into::into)
111 }
112
113 pub fn public_key_to_address(public: VerifyingKey) -> Address {
116 let hash = keccak256(&public.to_encoded_point(false).as_bytes()[1..]);
117 Address::from_slice(&hash[12..])
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use alloy_primitives::{keccak256, B256};
124
125 #[cfg(feature = "secp256k1")]
126 #[test]
127 fn sanity_ecrecover_call_secp256k1() {
128 use super::impl_secp256k1::*;
129
130 let (secret, public) = secp256k1::generate_keypair(&mut rand::thread_rng());
131 let signer = public_key_to_address(public);
132
133 let message = b"hello world";
134 let hash = keccak256(message);
135 let signature =
136 sign_message(B256::from_slice(&secret.secret_bytes()[..]), hash).expect("sign message");
137
138 let mut sig: [u8; 65] = [0; 65];
139 sig[0..32].copy_from_slice(&signature.r().to_be_bytes::<32>());
140 sig[32..64].copy_from_slice(&signature.s().to_be_bytes::<32>());
141 sig[64] = signature.v() as u8;
142
143 assert_eq!(recover_signer_unchecked(&sig, &hash), Ok(signer));
144 }
145
146 #[cfg(not(feature = "secp256k1"))]
147 #[test]
148 fn sanity_ecrecover_call_k256() {
149 use super::impl_k256::*;
150
151 let secret = k256::ecdsa::SigningKey::random(&mut rand::thread_rng());
152 let public = *secret.verifying_key();
153 let signer = public_key_to_address(public);
154
155 let message = b"hello world";
156 let hash = keccak256(message);
157 let signature =
158 sign_message(B256::from_slice(&secret.to_bytes()[..]), hash).expect("sign message");
159
160 let mut sig: [u8; 65] = [0; 65];
161 sig[0..32].copy_from_slice(&signature.r.to_be_bytes::<32>());
162 sig[32..64].copy_from_slice(&signature.s.to_be_bytes::<32>());
163 sig[64] = signature.odd_y_parity as u8;
164
165 assert_eq!(recover_signer_unchecked(&sig, &hash).ok(), Some(signer));
166 }
167
168 #[test]
169 fn sanity_secp256k1_k256_compat() {
170 use super::{impl_k256, impl_secp256k1};
171
172 let (secp256k1_secret, secp256k1_public) =
173 secp256k1::generate_keypair(&mut rand::thread_rng());
174 let k256_secret = k256::ecdsa::SigningKey::from_slice(&secp256k1_secret.secret_bytes())
175 .expect("k256 secret");
176 let k256_public = *k256_secret.verifying_key();
177
178 let secp256k1_signer = impl_secp256k1::public_key_to_address(secp256k1_public);
179 let k256_signer = impl_k256::public_key_to_address(k256_public);
180 assert_eq!(secp256k1_signer, k256_signer);
181
182 let message = b"hello world";
183 let hash = keccak256(message);
184
185 let secp256k1_signature = impl_secp256k1::sign_message(
186 B256::from_slice(&secp256k1_secret.secret_bytes()[..]),
187 hash,
188 )
189 .expect("secp256k1 sign");
190 let k256_signature =
191 impl_k256::sign_message(B256::from_slice(&k256_secret.to_bytes()[..]), hash)
192 .expect("k256 sign");
193 assert_eq!(secp256k1_signature, k256_signature);
194
195 let mut sig: [u8; 65] = [0; 65];
196
197 sig[0..32].copy_from_slice(&secp256k1_signature.r().to_be_bytes::<32>());
198 sig[32..64].copy_from_slice(&secp256k1_signature.s().to_be_bytes::<32>());
199 sig[64] = secp256k1_signature.v() as u8;
200 let secp256k1_recovered =
201 impl_secp256k1::recover_signer_unchecked(&sig, &hash).expect("secp256k1 recover");
202 assert_eq!(secp256k1_recovered, secp256k1_signer);
203
204 sig[0..32].copy_from_slice(&k256_signature.r().to_be_bytes::<32>());
205 sig[32..64].copy_from_slice(&k256_signature.s().to_be_bytes::<32>());
206 sig[64] = k256_signature.v() as u8;
207 let k256_recovered =
208 impl_k256::recover_signer_unchecked(&sig, &hash).expect("k256 recover");
209 assert_eq!(k256_recovered, k256_signer);
210
211 assert_eq!(secp256k1_recovered, k256_recovered);
212 }
213}