eth_utils/
ecdsa_keys.rs

1use bip0039::{Count, Language, Mnemonic};
2use bip32::{DerivationPath, XPrv};
3use core::{
4    cmp::Ordering,
5    hash::{Hash, Hasher},
6};
7use hashing::keccak_256;
8use libsecp256k1::{PublicKey, SecretKey};
9use primitive_types::{H160, H256};
10use rand::{rngs::OsRng, RngCore};
11use ruc::eg;
12use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
13use sha3::{Digest, Keccak256};
14use std::{fmt, str::FromStr};
15
16/// A secret seed (which is bytewise essentially equivalent to a SecretKey).
17///
18/// We need it as a different type because `Seed` is expected to be AsRef<[u8]>.
19type Seed = [u8; 32];
20
21/// The ECDSA compressed public key.
22#[derive(Clone, Copy)]
23pub struct Public(pub [u8; 33]);
24
25impl PartialOrd for Public {
26    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
27        Some(self.cmp(other))
28    }
29}
30
31impl Ord for Public {
32    fn cmp(&self, other: &Self) -> Ordering {
33        self.as_ref().cmp(other.as_ref())
34    }
35}
36
37impl PartialEq for Public {
38    fn eq(&self, other: &Self) -> bool {
39        self.as_ref() == other.as_ref()
40    }
41}
42
43impl Eq for Public {}
44
45impl Default for Public {
46    fn default() -> Self {
47        Public([0u8; 33])
48    }
49}
50
51impl std::fmt::Debug for Public {
52    fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
53        write!(
54            f,
55            "{}",
56            base64::encode_config(self.as_ref(), base64::URL_SAFE)
57        )
58    }
59}
60
61impl Serialize for Public {
62    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
63    where
64        S: Serializer,
65    {
66        serializer.serialize_str(&base64::encode_config(self.as_ref(), base64::URL_SAFE))
67    }
68}
69
70impl<'de> Deserialize<'de> for Public {
71    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
72    where
73        D: Deserializer<'de>,
74    {
75        let pk = base64::decode_config(&String::deserialize(deserializer)?, base64::URL_SAFE)
76            .map_err(|e| de::Error::custom(format!("{:?}", e)))?;
77        Public::try_from(pk.as_slice()).map_err(|e| de::Error::custom(format!("{:?}", e)))
78    }
79}
80
81impl Public {
82    /// A new instance from the given 33-byte `data`.
83    ///
84    /// NOTE: No checking goes on to ensure this is a real public key. Only use it if
85    /// you are certain that the array actually is a pubkey. GIGO!
86    pub fn from_raw(data: [u8; 33]) -> Self {
87        Self(data)
88    }
89
90    /// A new instance from the given slice that should be 33 bytes long.
91    ///
92    /// NOTE: No checking goes on to ensure this is a real public key. Only use it if
93    /// you are certain that the array actually is a pubkey. GIGO!
94    pub fn from_slice(data: &[u8]) -> Self {
95        let mut r = [0u8; 33];
96        r.copy_from_slice(data);
97        Self(r)
98    }
99
100    /// Create a new instance from the given full public key.
101    ///
102    /// This will convert the full public key into the compressed format.
103    pub fn from_full(full: &[u8]) -> ruc::Result<Self> {
104        libsecp256k1::PublicKey::parse_slice(full, None)
105            .map(|k| k.serialize_compressed())
106            .map(Self)
107            .map_err(|_| eg!("invalid public key"))
108    }
109}
110
111impl AsRef<[u8]> for Public {
112    fn as_ref(&self) -> &[u8] {
113        &self.0[..]
114    }
115}
116
117impl AsMut<[u8]> for Public {
118    fn as_mut(&mut self) -> &mut [u8] {
119        &mut self.0[..]
120    }
121}
122
123impl TryFrom<&[u8]> for Public {
124    type Error = ();
125    fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
126        if data.len() == 33 {
127            let mut r = [0u8; 33];
128            r.copy_from_slice(data);
129            Ok(Self(r))
130        } else {
131            Err(())
132        }
133    }
134}
135
136impl From<SecpPair> for Public {
137    fn from(x: SecpPair) -> Self {
138        x.public()
139    }
140}
141
142/// A signature (a 512-bit value, plus 8 bits for recovery ID).
143#[derive(Clone, Copy)]
144pub struct Signature(pub [u8; 65]);
145
146impl TryFrom<&[u8]> for Signature {
147    type Error = ();
148
149    fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
150        if data.len() == 65 {
151            let mut inner = [0u8; 65];
152            inner.copy_from_slice(data);
153            Ok(Signature(inner))
154        } else {
155            Err(())
156        }
157    }
158}
159
160impl Serialize for Signature {
161    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
162    where
163        S: Serializer,
164    {
165        serializer.serialize_str(&hex::encode(self))
166    }
167}
168
169impl<'de> Deserialize<'de> for Signature {
170    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
171    where
172        D: Deserializer<'de>,
173    {
174        let signature_hex = hex::decode(&String::deserialize(deserializer)?)
175            .map_err(|e| de::Error::custom(format!("{:?}", e)))?;
176        Signature::try_from(signature_hex.as_ref())
177            .map_err(|e| de::Error::custom(format!("{:?}", e)))
178    }
179}
180
181impl Default for Signature {
182    fn default() -> Self {
183        Signature([0u8; 65])
184    }
185}
186
187impl PartialEq for Signature {
188    fn eq(&self, b: &Self) -> bool {
189        self.0[..] == b.0[..]
190    }
191}
192
193impl Eq for Signature {}
194
195impl std::fmt::Debug for Signature {
196    fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
197        write!(f, "{}", hex::encode(self))
198    }
199}
200
201impl From<Signature> for [u8; 65] {
202    fn from(v: Signature) -> [u8; 65] {
203        v.0
204    }
205}
206
207impl AsRef<[u8; 65]> for Signature {
208    fn as_ref(&self) -> &[u8; 65] {
209        &self.0
210    }
211}
212
213impl AsRef<[u8]> for Signature {
214    fn as_ref(&self) -> &[u8] {
215        &self.0[..]
216    }
217}
218
219impl AsMut<[u8]> for Signature {
220    fn as_mut(&mut self) -> &mut [u8] {
221        &mut self.0[..]
222    }
223}
224
225impl Hash for Signature {
226    fn hash<H: Hasher>(&self, state: &mut H) {
227        Hash::hash(&self.0[..], state);
228    }
229}
230
231impl Signature {
232    /// A new instance from the given 65-byte `data`.
233    ///
234    /// NOTE: No checking goes on to ensure this is a real signature. Only use it if
235    /// you are certain that the array actually is a signature. GIGO!
236    pub fn from_raw(data: [u8; 65]) -> Signature {
237        Signature(data)
238    }
239
240    /// A new instance from the given slice that should be 65 bytes long.
241    ///
242    /// NOTE: No checking goes on to ensure this is a real signature. Only use it if
243    /// you are certain that the array actually is a signature. GIGO!
244    pub fn from_slice(data: &[u8]) -> Self {
245        let mut r = [0u8; 65];
246        r.copy_from_slice(data);
247        Signature(r)
248    }
249
250    /// Recover the public key from this signature and a message.
251    pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
252        let message = libsecp256k1::Message::parse(&keccak_256(message.as_ref()));
253        let sig: (_, _) = self.try_into().ok()?;
254        libsecp256k1::recover(&message, &sig.0, &sig.1)
255            .ok()
256            .map(|recovered| Public(recovered.serialize_compressed()))
257    }
258}
259
260impl From<(libsecp256k1::Signature, libsecp256k1::RecoveryId)> for Signature {
261    fn from(x: (libsecp256k1::Signature, libsecp256k1::RecoveryId)) -> Signature {
262        let mut r = Self::default();
263        r.0[0..64].copy_from_slice(&x.0.serialize()[..]);
264        r.0[64] = x.1.serialize();
265        r
266    }
267}
268
269impl<'a> TryFrom<&'a Signature> for (libsecp256k1::Signature, libsecp256k1::RecoveryId) {
270    type Error = ();
271    fn try_from(
272        x: &'a Signature,
273    ) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), Self::Error> {
274        Ok((
275            libsecp256k1::Signature::parse_standard_slice(&x.0[0..64])
276                .expect("hardcoded to 64 bytes; qed"),
277            libsecp256k1::RecoveryId::parse(x.0[64]).map_err(|_| ())?,
278        ))
279    }
280}
281
282/// A secp256k1 key pair.
283#[derive(Debug, Clone, Copy, Eq, PartialEq)]
284pub struct SecpPair {
285    public: PublicKey,
286    secret: SecretKey,
287}
288
289impl SecpPair {
290    /// Get the seed for this key.
291    pub fn seed(&self) -> Seed {
292        self.secret.serialize()
293    }
294
295    pub fn generate() -> (Self, Seed) {
296        let mut seed = Seed::default();
297        OsRng.fill_bytes(seed.as_mut());
298        (Self::from_seed(&seed), seed)
299    }
300
301    /// Generate new secure (random) key pair and provide the recovery phrase.
302    ///
303    /// You can recover the same key later with `from_phrase`.
304    pub fn generate_with_phrase(password: Option<&str>) -> (SecpPair, String, Seed) {
305        let mnemonic = Mnemonic::generate_in(Language::English, Count::Words12);
306        let phrase = mnemonic.phrase();
307        let (pair, seed) = Self::from_phrase(phrase, password)
308            .expect("All phrases generated by Mnemonic are valid; qed");
309        (pair, phrase.to_owned(), seed)
310    }
311
312    /// Generate key pair from given recovery phrase and password.
313    pub fn from_phrase(phrase: &str, password: Option<&str>) -> ruc::Result<(SecpPair, Seed)> {
314        let mnemonic = Mnemonic::from_phrase_in(Language::English, phrase)
315            .map_err(|_| eg!("InvalidPhrase"))?;
316        let bs = mnemonic.to_seed(password.unwrap_or(""));
317        let ext = XPrv::derive_from_path(
318            &bs,
319            &DerivationPath::from_str("m/44'/60'/0'/0/0")
320                .map_err(|_| eg!("InvalidDerivationPath"))?,
321        )
322        .map_err(|_| eg!("Failed to ExtendedPrivateKey"))?;
323        let mut seed = Seed::default();
324        seed.copy_from_slice(&bs[0..32]);
325        Self::from_seed_slice(&ext.to_bytes()).map(|x| (x, seed))
326    }
327
328    /// Make a new key pair from secret seed material.
329    ///
330    /// You should never need to use this; generate(), generate_with_phrase
331    pub fn from_seed(seed: &Seed) -> SecpPair {
332        Self::from_seed_slice(&seed[..]).expect("seed has valid length; qed")
333    }
334
335    /// Make a new key pair from secret seed material. The slice must be 32 bytes long or it
336    /// will return `None`.
337    ///
338    /// You should never need to use this; generate(), generate_with_phrase
339    pub fn from_seed_slice(seed_slice: &[u8]) -> ruc::Result<SecpPair> {
340        let secret = SecretKey::parse_slice(seed_slice).map_err(|_| eg!("InvalidSeedLength"))?;
341        let public = PublicKey::from_secret_key(&secret);
342        Ok(SecpPair { public, secret })
343    }
344
345    /// Get the public key.
346    pub fn public(&self) -> Public {
347        Public(self.public.serialize_compressed())
348    }
349
350    /// Ethereum address format.
351    pub fn address(&self) -> H160 {
352        let mut res = [0u8; 64];
353        res.copy_from_slice(&self.public.serialize()[1..65]);
354        H160::from(H256::from_slice(Keccak256::digest(&res).as_slice()))
355    }
356
357    /// Sign a message.
358    pub fn sign(&self, message: &[u8]) -> Signature {
359        let message = libsecp256k1::Message::parse(&keccak_256(message));
360        libsecp256k1::sign(&message, &self.secret).into()
361    }
362
363    /// Sign a pre-hashed message
364    pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature {
365        let message = libsecp256k1::Message::parse(message);
366        libsecp256k1::sign(&message, &self.secret).into()
367    }
368
369    /// Verify a signature on a message. Returns true if the signature is good.
370    pub fn verify<M: AsRef<[u8]>>(sig: &Signature, message: M, pubkey: &Public) -> bool {
371        let message = libsecp256k1::Message::parse(&keccak_256(message.as_ref()));
372        let sig: (_, _) = match sig.try_into() {
373            Ok(x) => x,
374            _ => return false,
375        };
376        match libsecp256k1::recover(&message, &sig.0, &sig.1) {
377            Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..],
378            _ => false,
379        }
380    }
381
382    /// Return a vec filled with raw data.
383    pub fn to_raw_vec(self) -> Vec<u8> {
384        self.seed().to_vec()
385    }
386}
387
388mod hashing {
389    use tiny_keccak::{Hasher, Keccak};
390
391    /// Do a keccak 256-bit hash and return result.
392    pub fn keccak_256(data: &[u8]) -> [u8; 32] {
393        let mut keccak = Keccak::v256();
394        keccak.update(data);
395        let mut output = [0u8; 32];
396        keccak.finalize(&mut output);
397        output
398    }
399}
400
401#[cfg(test)]
402mod test {
403    use super::*;
404    use hex_literal::hex;
405
406    #[test]
407    fn test_vector_should_work() {
408        let pair = SecpPair::from_seed(&hex!(
409            "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"
410        ));
411        let public = pair.public();
412        assert_eq!(
413            public,
414            Public::from_full(
415                &hex!("8db55b05db86c0b1786ca49f095d76344c9e6056b2f02701a7e7f3c20aabfd913ebbe148dd17c56551a52952371071a6c604b3f3abe8f2c8fa742158ea6dd7d4")[..],
416            ).unwrap(),
417        );
418        let message = b"";
419        let signature = hex!(
420            "4e1fd58a98bbce5fe948c4e5fec7662d253130a300156c037429dca66f9f6a0728e8b5e8bc55f4bcf445af4b75928a876d54949aaee93a62e3eb1cf12aefb60800"
421        );
422        let signature = Signature::from_raw(signature);
423        assert_eq!(pair.sign(&message[..]), signature);
424        assert!(SecpPair::verify(&signature, &message[..], &public));
425    }
426
427    #[test]
428    fn generated_pair_should_work() {
429        let (pair, _) = SecpPair::generate();
430        let public = pair.public();
431        let message = b"Something important";
432        let signature = pair.sign(&message[..]);
433        assert!(SecpPair::verify(&signature, &message[..], &public));
434        assert!(!SecpPair::verify(&signature, b"Something else", &public));
435    }
436
437    #[test]
438    fn seeded_pair_should_work() {
439        let pair = SecpPair::from_seed(b"12345678901234567890123456789012");
440        let public = pair.public();
441        assert_eq!(
442            public,
443            Public::from_full(
444                &hex!("5676109c54b9a16d271abeb4954316a40a32bcce023ac14c8e26e958aa68fba995840f3de562156558efbfdac3f16af0065e5f66795f4dd8262a228ef8c6d813")[..],
445            ).unwrap(),
446        );
447        let message = hex!(
448            "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee00000000000000000200d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a4500000000000000"
449        );
450        let signature = pair.sign(&message[..]);
451        println!("Correct signature: {:?}", signature);
452        assert!(SecpPair::verify(&signature, &message[..], &public));
453        assert!(!SecpPair::verify(&signature, "Other message", &public));
454    }
455
456    #[test]
457    fn generate_with_phrase_recovery_possible() {
458        let (pair1, phrase, _) = SecpPair::generate_with_phrase(None);
459        let (pair2, _) = SecpPair::from_phrase(&phrase, None).unwrap();
460
461        assert_eq!(pair1.public(), pair2.public());
462    }
463
464    #[test]
465    fn generate_with_password_phrase_recovery_possible() {
466        let (pair1, phrase, _) = SecpPair::generate_with_phrase(Some("password"));
467        let (pair2, _) = SecpPair::from_phrase(&phrase, Some("password")).unwrap();
468
469        assert_eq!(pair1.public(), pair2.public());
470    }
471
472    #[test]
473    fn password_does_something() {
474        let (pair1, phrase, _) = SecpPair::generate_with_phrase(Some("password"));
475        let (pair2, _) = SecpPair::from_phrase(&phrase, None).unwrap();
476
477        assert_ne!(pair1.public(), pair2.public());
478    }
479
480    #[test]
481    fn public_serialization_works() {
482        let pair = SecpPair::from_seed(b"12345678901234567890123456789012");
483        let pk = Public::from(pair);
484        let serialized_public = serde_json::to_string(&pk).unwrap();
485        let public = serde_json::from_str::<Public>(&serialized_public).unwrap();
486        assert!(public.eq(&pk));
487    }
488
489    #[test]
490    fn signature_serialization_works() {
491        let pair = SecpPair::from_seed(b"12345678901234567890123456789012");
492        let message = b"Something important";
493        let signature = pair.sign(&message[..]);
494        let serialized_signature = serde_json::to_string(&signature).unwrap();
495        // Signature is 65 bytes, so 130 chars + 2 quote chars
496        assert_eq!(serialized_signature.len(), 132);
497        let signature = serde_json::from_str(&serialized_signature).unwrap();
498        assert!(SecpPair::verify(&signature, &message[..], &pair.public()));
499    }
500
501    #[test]
502    fn signature_serialization_doesnt_panic() {
503        fn deserialize_signature(text: &str) -> Result<Signature, serde_json::error::Error> {
504            serde_json::from_str(text)
505        }
506        assert!(deserialize_signature("Not valid json.").is_err());
507        assert!(deserialize_signature("\"Not an actual signature.\"").is_err());
508        // Poorly-sized
509        assert!(deserialize_signature("\"abc123\"").is_err());
510    }
511
512    #[test]
513    fn sign_prehashed_works() {
514        let (pair, _, _) = SecpPair::generate_with_phrase(Some("password"));
515
516        // `msg` shouldn't be mangled
517        let msg = [0u8; 32];
518        let sig1 = pair.sign_prehashed(&msg);
519        let sig2: Signature =
520            libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into();
521
522        assert_eq!(sig1, sig2);
523
524        // signature is actually different
525        let sig2 = pair.sign(&msg);
526
527        assert_ne!(sig1, sig2);
528
529        // using pre-hashed `msg` works
530        let msg = keccak_256(b"this should be hashed");
531        let sig1 = pair.sign_prehashed(&msg);
532        let sig2: Signature =
533            libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into();
534
535        assert_eq!(sig1, sig2);
536    }
537}