linera_base/crypto/secp256k1/
mod.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2// Copyright (c) Zefchain Labs, Inc.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Defines secp256k1 signature primitives used by the Linera protocol.
6
7pub mod evm;
8
9use std::{
10    borrow::Cow,
11    fmt,
12    hash::{Hash, Hasher},
13    str::FromStr,
14};
15
16use allocative::{Allocative, Visitor};
17use k256::{
18    ecdsa::{Signature, SigningKey, VerifyingKey},
19    elliptic_curve::sec1::FromEncodedPoint,
20    EncodedPoint,
21};
22use linera_witty::{
23    GuestPointer, HList, InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory,
24    WitLoad, WitStore, WitType,
25};
26use serde::{Deserialize, Serialize};
27
28use super::{BcsHashable, BcsSignable, CryptoError, CryptoHash, HasTypeName};
29use crate::doc_scalar;
30
31/// Name of the secp256k1 scheme.
32const SECP256K1_SCHEME_LABEL: &str = "secp256k1";
33
34/// Length of secp256k1 compressed public key.
35const SECP256K1_PUBLIC_KEY_SIZE: usize = 33;
36
37/// Length of secp256k1 signature.
38const SECP256K1_SIGNATURE_SIZE: usize = 64;
39
40/// A secp256k1 secret key.
41#[derive(Eq, PartialEq)]
42pub struct Secp256k1SecretKey(pub SigningKey);
43
44/// A secp256k1 public key.
45#[derive(Eq, PartialEq, Ord, PartialOrd, Copy, Clone)]
46pub struct Secp256k1PublicKey(pub VerifyingKey);
47
48impl Allocative for Secp256k1PublicKey {
49    fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
50        visitor.visit_simple_sized::<Self>();
51    }
52}
53
54impl Hash for Secp256k1PublicKey {
55    fn hash<H: Hasher>(&self, state: &mut H) {
56        self.0.to_encoded_point(true).as_bytes().hash(state);
57    }
58}
59
60/// Secp256k1 public/secret key pair.
61#[derive(Debug, PartialEq, Eq)]
62pub struct Secp256k1KeyPair {
63    /// Secret key.
64    pub secret_key: Secp256k1SecretKey,
65    /// Public key.
66    pub public_key: Secp256k1PublicKey,
67}
68
69/// A secp256k1 signature.
70#[derive(Eq, PartialEq, Copy, Clone)]
71pub struct Secp256k1Signature(pub Signature);
72
73impl Allocative for Secp256k1Signature {
74    fn visit<'a, 'b: 'a>(&self, visitor: &'a mut Visitor<'b>) {
75        visitor.visit_simple_sized::<Self>();
76    }
77}
78
79impl Secp256k1PublicKey {
80    /// A fake public key used for testing.
81    #[cfg(all(with_testing, not(target_arch = "wasm32")))]
82    pub fn test_key(seed: u8) -> Self {
83        use rand::SeedableRng;
84        let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
85        let sk = k256::SecretKey::random(&mut rng);
86        Self(sk.public_key().into())
87    }
88
89    /// Returns the bytes of the public key in compressed representation.
90    pub fn as_bytes(&self) -> [u8; SECP256K1_PUBLIC_KEY_SIZE] {
91        // UNWRAP: We already have valid key so conversion should not fail.
92        self.0.to_encoded_point(true).as_bytes().try_into().unwrap()
93    }
94
95    /// Decodes the bytes into the public key.
96    /// Expects the bytes to be of compressed representation.
97    ///
98    /// Panics if the encoding can't be done in a constant time.
99    pub fn from_bytes(bytes: &[u8]) -> Result<Self, CryptoError> {
100        let encoded_point =
101            EncodedPoint::from_bytes(bytes).map_err(|_| CryptoError::IncorrectPublicKeySize {
102                scheme: SECP256K1_SCHEME_LABEL,
103                len: bytes.len(),
104                expected: SECP256K1_PUBLIC_KEY_SIZE,
105            })?;
106
107        match k256::PublicKey::from_encoded_point(&encoded_point).into_option() {
108            Some(public_key) => Ok(Self(public_key.into())),
109            None => {
110                let error = CryptoError::Secp256k1PointAtInfinity(hex::encode(bytes));
111                Err(error)
112            }
113        }
114    }
115}
116
117impl fmt::Debug for Secp256k1SecretKey {
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        write!(f, "<redacted for Secp256k1 secret key>")
120    }
121}
122
123impl Serialize for Secp256k1SecretKey {
124    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
125    where
126        S: serde::ser::Serializer,
127    {
128        // This is only used for JSON configuration.
129        assert!(serializer.is_human_readable());
130        serializer.serialize_str(&hex::encode(self.0.to_bytes()))
131    }
132}
133
134impl<'de> Deserialize<'de> for Secp256k1SecretKey {
135    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
136    where
137        D: serde::de::Deserializer<'de>,
138    {
139        // This is only used for JSON configuration.
140        assert!(deserializer.is_human_readable());
141        let str = String::deserialize(deserializer)?;
142        let bytes = hex::decode(&str).map_err(serde::de::Error::custom)?;
143        let sk = k256::ecdsa::SigningKey::from_slice(&bytes).map_err(serde::de::Error::custom)?;
144        Ok(Secp256k1SecretKey(sk))
145    }
146}
147
148impl Serialize for Secp256k1PublicKey {
149    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
150    where
151        S: serde::ser::Serializer,
152    {
153        if serializer.is_human_readable() {
154            serializer.serialize_str(&hex::encode(self.as_bytes()))
155        } else {
156            let compact_pk = serde_utils::CompressedPublicKey(self.as_bytes());
157            serializer.serialize_newtype_struct("Secp256k1PublicKey", &compact_pk)
158        }
159    }
160}
161
162impl<'de> Deserialize<'de> for Secp256k1PublicKey {
163    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
164    where
165        D: serde::de::Deserializer<'de>,
166    {
167        if deserializer.is_human_readable() {
168            let s = String::deserialize(deserializer)?;
169            let value = hex::decode(s).map_err(serde::de::Error::custom)?;
170            Ok(Secp256k1PublicKey::from_bytes(&value).map_err(serde::de::Error::custom)?)
171        } else {
172            #[derive(Deserialize)]
173            #[serde(rename = "Secp256k1PublicKey")]
174            struct PublicKey(serde_utils::CompressedPublicKey);
175            let compact = PublicKey::deserialize(deserializer)?;
176            Ok(Secp256k1PublicKey::from_bytes(&compact.0 .0).map_err(serde::de::Error::custom)?)
177        }
178    }
179}
180
181impl FromStr for Secp256k1PublicKey {
182    type Err = CryptoError;
183
184    fn from_str(s: &str) -> Result<Self, Self::Err> {
185        hex::decode(s)?.as_slice().try_into()
186    }
187}
188
189impl TryFrom<&[u8]> for Secp256k1PublicKey {
190    type Error = CryptoError;
191
192    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
193        Self::from_bytes(value)
194    }
195}
196
197impl fmt::Display for Secp256k1PublicKey {
198    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199        let str = hex::encode(self.as_bytes());
200        write!(f, "{}", str)
201    }
202}
203
204impl fmt::Debug for Secp256k1PublicKey {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
207    }
208}
209
210impl BcsHashable<'_> for Secp256k1PublicKey {}
211
212impl WitType for Secp256k1PublicKey {
213    const SIZE: u32 = <(u64, u64, u64, u64, u8) as WitType>::SIZE;
214    type Layout = <(u64, u64, u64, u64, u8) as WitType>::Layout;
215    type Dependencies = HList![];
216
217    fn wit_type_name() -> Cow<'static, str> {
218        "secp256k1-public-key".into()
219    }
220
221    fn wit_type_declaration() -> Cow<'static, str> {
222        concat!(
223            "    record secp256k1-public-key {\n",
224            "        part1: u64,\n",
225            "        part2: u64,\n",
226            "        part3: u64,\n",
227            "        part4: u64,\n",
228            "        part5: u8\n",
229            "    }\n",
230        )
231        .into()
232    }
233}
234
235impl WitLoad for Secp256k1PublicKey {
236    fn load<Instance>(
237        memory: &Memory<'_, Instance>,
238        location: GuestPointer,
239    ) -> Result<Self, RuntimeError>
240    where
241        Instance: InstanceWithMemory,
242        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
243    {
244        let (part1, part2, part3, part4, part5) = WitLoad::load(memory, location)?;
245        Ok(Self::from((part1, part2, part3, part4, part5)))
246    }
247
248    fn lift_from<Instance>(
249        flat_layout: <Self::Layout as Layout>::Flat,
250        memory: &Memory<'_, Instance>,
251    ) -> Result<Self, RuntimeError>
252    where
253        Instance: InstanceWithMemory,
254        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
255    {
256        let (part1, part2, part3, part4, part5) = WitLoad::lift_from(flat_layout, memory)?;
257        Ok(Self::from((part1, part2, part3, part4, part5)))
258    }
259}
260
261impl WitStore for Secp256k1PublicKey {
262    fn store<Instance>(
263        &self,
264        memory: &mut Memory<'_, Instance>,
265        location: GuestPointer,
266    ) -> Result<(), RuntimeError>
267    where
268        Instance: InstanceWithMemory,
269        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
270    {
271        let (part1, part2, part3, part4, part5) = (*self).into();
272        (part1, part2, part3, part4, part5).store(memory, location)
273    }
274
275    fn lower<Instance>(
276        &self,
277        memory: &mut Memory<'_, Instance>,
278    ) -> Result<<Self::Layout as Layout>::Flat, RuntimeError>
279    where
280        Instance: InstanceWithMemory,
281        <Instance::Runtime as Runtime>::Memory: RuntimeMemory<Instance>,
282    {
283        let (part1, part2, part3, part4, part5) = (*self).into();
284        (part1, part2, part3, part4, part5).lower(memory)
285    }
286}
287
288impl From<(u64, u64, u64, u64, u8)> for Secp256k1PublicKey {
289    fn from((part1, part2, part3, part4, part5): (u64, u64, u64, u64, u8)) -> Self {
290        let mut bytes = [0u8; SECP256K1_PUBLIC_KEY_SIZE];
291        bytes[0..8].copy_from_slice(&part1.to_be_bytes());
292        bytes[8..16].copy_from_slice(&part2.to_be_bytes());
293        bytes[16..24].copy_from_slice(&part3.to_be_bytes());
294        bytes[24..32].copy_from_slice(&part4.to_be_bytes());
295        bytes[32] = part5;
296        Self::from_bytes(&bytes).unwrap()
297    }
298}
299
300impl From<Secp256k1PublicKey> for (u64, u64, u64, u64, u8) {
301    fn from(key: Secp256k1PublicKey) -> Self {
302        let bytes = key.as_bytes();
303        let part1 = u64::from_be_bytes(bytes[0..8].try_into().unwrap());
304        let part2 = u64::from_be_bytes(bytes[8..16].try_into().unwrap());
305        let part3 = u64::from_be_bytes(bytes[16..24].try_into().unwrap());
306        let part4 = u64::from_be_bytes(bytes[24..32].try_into().unwrap());
307        let part5 = bytes[32];
308        (part1, part2, part3, part4, part5)
309    }
310}
311
312impl Secp256k1KeyPair {
313    /// Generates a new key pair.
314    #[cfg(all(with_getrandom, with_testing))]
315    pub fn generate() -> Self {
316        let mut rng = rand::rngs::OsRng;
317        Self::generate_from(&mut rng)
318    }
319
320    /// Generates a new key pair from the given RNG. Use with care.
321    #[cfg(with_getrandom)]
322    pub fn generate_from<R: super::CryptoRng>(rng: &mut R) -> Self {
323        let secret_key = Secp256k1SecretKey(SigningKey::random(rng));
324        let public_key = secret_key.public();
325        Secp256k1KeyPair {
326            secret_key,
327            public_key,
328        }
329    }
330}
331
332impl Secp256k1SecretKey {
333    /// Returns a public key for the given secret key.
334    pub fn public(&self) -> Secp256k1PublicKey {
335        Secp256k1PublicKey(*self.0.verifying_key())
336    }
337
338    /// Copies the key pair, **including the secret key**.
339    ///
340    /// The `Clone` and `Copy` traits are deliberately not implemented for `Secp256k1SecretKey` to prevent
341    /// accidental copies of secret keys.
342    pub fn copy(&self) -> Self {
343        Self(self.0.clone())
344    }
345
346    /// Generates a new key pair.
347    #[cfg(all(with_getrandom, with_testing))]
348    pub fn generate() -> Self {
349        let mut rng = rand::rngs::OsRng;
350        Self::generate_from(&mut rng)
351    }
352
353    /// Generates a new key pair from the given RNG. Use with care.
354    #[cfg(with_getrandom)]
355    pub fn generate_from<R: super::CryptoRng>(rng: &mut R) -> Self {
356        Secp256k1SecretKey(SigningKey::random(rng))
357    }
358}
359
360impl Secp256k1Signature {
361    /// Computes a secp256k1 signature for `value` using the given `secret`.
362    /// It first serializes the `T` type and then creates the `CryptoHash` from the serialized bytes.
363    pub fn new<'de, T>(value: &T, secret: &Secp256k1SecretKey) -> Self
364    where
365        T: BcsSignable<'de>,
366    {
367        Self::sign_prehash(secret, CryptoHash::new(value))
368    }
369
370    /// Computes a signature from a prehash.
371    pub fn sign_prehash(secret: &Secp256k1SecretKey, prehash: CryptoHash) -> Self {
372        use k256::ecdsa::signature::hazmat::PrehashSigner;
373
374        let (signature, _rid) = secret
375            .0
376            .sign_prehash(&prehash.as_bytes().0)
377            .expect("Failed to sign prehashed data"); // NOTE: This is a critical error we don't control.
378        Secp256k1Signature(signature)
379    }
380
381    /// Checks a signature.
382    pub fn check<'de, T>(&self, value: &T, author: Secp256k1PublicKey) -> Result<(), CryptoError>
383    where
384        T: BcsSignable<'de> + fmt::Debug,
385    {
386        let prehash = CryptoHash::new(value).as_bytes().0;
387        self.verify_inner::<T>(prehash, author)
388    }
389
390    /// Verifies a batch of signatures.
391    ///
392    /// Returns an error on first failed signature.
393    pub fn verify_batch<'a, 'de, T, I>(value: &'a T, votes: I) -> Result<(), CryptoError>
394    where
395        T: BcsSignable<'de> + fmt::Debug,
396        I: IntoIterator<Item = &'a (Secp256k1PublicKey, Secp256k1Signature)>,
397    {
398        let prehash = CryptoHash::new(value).as_bytes().0;
399        for (author, signature) in votes {
400            signature.verify_inner::<T>(prehash, *author)?;
401        }
402        Ok(())
403    }
404
405    /// Returns the byte representation of the signature.
406    pub fn as_bytes(&self) -> [u8; SECP256K1_SIGNATURE_SIZE] {
407        self.0.to_bytes().into()
408    }
409
410    fn verify_inner<'de, T>(
411        &self,
412        prehash: [u8; 32],
413        author: Secp256k1PublicKey,
414    ) -> Result<(), CryptoError>
415    where
416        T: BcsSignable<'de> + fmt::Debug,
417    {
418        use k256::ecdsa::signature::hazmat::PrehashVerifier;
419
420        author
421            .0
422            .verify_prehash(&prehash, &self.0)
423            .map_err(|error| CryptoError::InvalidSignature {
424                error: error.to_string(),
425                type_name: T::type_name().to_string(),
426            })
427    }
428
429    /// Creates a signature from the bytes.
430    /// Expects the signature to be serialized in raw-bytes form.
431    pub fn from_slice<A: AsRef<[u8]>>(bytes: A) -> Result<Self, CryptoError> {
432        let sig = k256::ecdsa::Signature::from_slice(bytes.as_ref())
433            .map_err(CryptoError::Secp256k1Error)?;
434        Ok(Secp256k1Signature(sig))
435    }
436}
437
438impl Serialize for Secp256k1Signature {
439    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
440    where
441        S: serde::ser::Serializer,
442    {
443        if serializer.is_human_readable() {
444            serializer.serialize_str(&hex::encode(self.as_bytes()))
445        } else {
446            let compact = serde_utils::CompactSignature(self.as_bytes());
447            serializer.serialize_newtype_struct("Secp256k1Signature", &compact)
448        }
449    }
450}
451
452impl<'de> Deserialize<'de> for Secp256k1Signature {
453    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
454    where
455        D: serde::de::Deserializer<'de>,
456    {
457        if deserializer.is_human_readable() {
458            let s = String::deserialize(deserializer)?;
459            let value = hex::decode(s).map_err(serde::de::Error::custom)?;
460            Self::from_slice(&value).map_err(serde::de::Error::custom)
461        } else {
462            #[derive(Deserialize)]
463            #[serde(rename = "Secp256k1Signature")]
464            struct Signature(serde_utils::CompactSignature);
465
466            let value = Signature::deserialize(deserializer)?;
467            Self::from_slice(value.0 .0.as_ref()).map_err(serde::de::Error::custom)
468        }
469    }
470}
471
472impl fmt::Display for Secp256k1Signature {
473    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474        let s = hex::encode(self.as_bytes());
475        write!(f, "{}", s)
476    }
477}
478
479impl fmt::Debug for Secp256k1Signature {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        write!(f, "{}..", hex::encode(&self.as_bytes()[0..9]))
482    }
483}
484
485doc_scalar!(Secp256k1Signature, "A secp256k1 signature value");
486doc_scalar!(Secp256k1PublicKey, "A secp256k1 public key value");
487
488mod serde_utils {
489    use serde::{Deserialize, Serialize};
490    use serde_with::serde_as;
491
492    use super::{SECP256K1_PUBLIC_KEY_SIZE, SECP256K1_SIGNATURE_SIZE};
493
494    /// Wrapper around compact signature serialization
495    /// so that we can implement custom serializer for it that uses fixed length.
496    // Serde treats arrays larger than 32 as variable length arrays, and adds the length as a prefix.
497    // Since we want a fixed size representation, we wrap it in this helper struct and use serde_as.
498    #[serde_as]
499    #[derive(Serialize, Deserialize)]
500    #[serde(transparent)]
501    pub struct CompactSignature(#[serde_as(as = "[_; 64]")] pub [u8; SECP256K1_SIGNATURE_SIZE]);
502
503    #[serde_as]
504    #[derive(Serialize, Deserialize)]
505    #[serde(transparent)]
506    pub struct CompressedPublicKey(#[serde_as(as = "[_; 33]")] pub [u8; SECP256K1_PUBLIC_KEY_SIZE]);
507}
508
509#[cfg(with_testing)]
510mod tests {
511    #[test]
512    fn test_signatures() {
513        use serde::{Deserialize, Serialize};
514
515        use crate::crypto::{
516            secp256k1::{Secp256k1KeyPair, Secp256k1Signature},
517            BcsSignable, TestString,
518        };
519
520        #[derive(Debug, Serialize, Deserialize)]
521        struct Foo(String);
522
523        impl BcsSignable<'_> for Foo {}
524
525        let keypair1 = Secp256k1KeyPair::generate();
526        let keypair2 = Secp256k1KeyPair::generate();
527
528        let ts = TestString("hello".into());
529        let tsx = TestString("hellox".into());
530        let foo = Foo("hello".into());
531
532        let s = Secp256k1Signature::new(&ts, &keypair1.secret_key);
533        assert!(s.check(&ts, keypair1.public_key).is_ok());
534        assert!(s.check(&ts, keypair2.public_key).is_err());
535        assert!(s.check(&tsx, keypair1.public_key).is_err());
536        assert!(s.check(&foo, keypair1.public_key).is_err());
537    }
538
539    #[test]
540    fn test_public_key_serialization() {
541        use crate::crypto::secp256k1::Secp256k1PublicKey;
542        let key_in = Secp256k1PublicKey::test_key(0);
543        let s = serde_json::to_string(&key_in).unwrap();
544        let key_out: Secp256k1PublicKey = serde_json::from_str(&s).unwrap();
545        assert_eq!(key_out, key_in);
546
547        let s = bcs::to_bytes(&key_in).unwrap();
548        let key_out: Secp256k1PublicKey = bcs::from_bytes(&s).unwrap();
549        assert_eq!(key_out, key_in);
550    }
551
552    #[test]
553    fn test_secret_key_serialization() {
554        use crate::crypto::secp256k1::{Secp256k1KeyPair, Secp256k1SecretKey};
555        let key_in = Secp256k1KeyPair::generate().secret_key;
556        let s = serde_json::to_string(&key_in).unwrap();
557        let key_out: Secp256k1SecretKey = serde_json::from_str(&s).unwrap();
558        assert_eq!(key_out, key_in);
559    }
560
561    #[test]
562    fn test_signature_serialization() {
563        use crate::crypto::{
564            secp256k1::{Secp256k1KeyPair, Secp256k1Signature},
565            TestString,
566        };
567        let keypair = Secp256k1KeyPair::generate();
568        let sig = Secp256k1Signature::new(&TestString("hello".into()), &keypair.secret_key);
569        let s = serde_json::to_string(&sig).unwrap();
570        let sig2: Secp256k1Signature = serde_json::from_str(&s).unwrap();
571        assert_eq!(sig, sig2);
572
573        let s = bcs::to_bytes(&sig).unwrap();
574        let sig2: Secp256k1Signature = bcs::from_bytes(&s).unwrap();
575        assert_eq!(sig, sig2);
576    }
577
578    #[test]
579    fn public_key_from_str() {
580        use std::str::FromStr;
581
582        use crate::crypto::secp256k1::Secp256k1PublicKey;
583        let key = Secp256k1PublicKey::test_key(0);
584        let s = key.to_string();
585        let key2 = Secp256k1PublicKey::from_str(s.as_str()).unwrap();
586        assert_eq!(key, key2);
587    }
588
589    #[test]
590    fn bytes_repr_compact_public_key() {
591        use crate::crypto::secp256k1::{Secp256k1PublicKey, SECP256K1_PUBLIC_KEY_SIZE};
592        let key_in: Secp256k1PublicKey = Secp256k1PublicKey::test_key(0);
593        let bytes = key_in.as_bytes();
594        assert!(
595            bytes.len() == SECP256K1_PUBLIC_KEY_SIZE,
596            "::to_bytes() should return compressed representation"
597        );
598        let key_out = Secp256k1PublicKey::from_bytes(&bytes).unwrap();
599        assert_eq!(key_in, key_out);
600    }
601
602    #[test]
603    fn human_readable_ser() {
604        use crate::crypto::{
605            secp256k1::{Secp256k1KeyPair, Secp256k1Signature},
606            TestString,
607        };
608        let key_pair = Secp256k1KeyPair::generate();
609        let sig = Secp256k1Signature::new(&TestString("hello".into()), &key_pair.secret_key);
610        let s = serde_json::to_string(&sig).unwrap();
611        let sig2: Secp256k1Signature = serde_json::from_str(&s).unwrap();
612        assert_eq!(sig, sig2);
613    }
614}