tiny_ec/
lib.rs

1//! Pure Rust implementation of the secp256k1 curve and fast ECDSA
2//! signatures. The secp256k1 curve is used extensively in Bitcoin and
3//! Ethereum-alike cryptocurrencies.
4
5#![deny(
6    unused_import_braces,
7    unused_imports,
8    unused_comparisons,
9    unused_must_use,
10    unused_variables,
11    non_shorthand_field_patterns,
12    unreachable_code,
13    unused_parens
14)]
15#![cfg_attr(not(feature = "std"), no_std)]
16
17use curve::Field;
18pub use tiny_ec_core::*;
19
20use arrayref::{array_mut_ref, array_ref};
21use core::convert::TryFrom;
22
23use crate::curve::{Affine, ECMultContext, ECMultGenContext, Jacobian, Scalar};
24#[cfg(feature = "std")]
25#[cfg(all(feature = "static-context"))]
26/// A static ECMult context.
27// Correct `pre_g` values are fed into `ECMultContext::new_from_raw`, generated by build script.
28pub static ECMULT_CONTEXT: ECMultContext =
29    unsafe { ECMultContext::new_from_raw(include!(concat!(env!("OUT_DIR"), "/const.rs"))) };
30
31#[cfg(all(feature = "static-context"))]
32/// A static ECMultGen context.
33// Correct `prec` values are fed into `ECMultGenContext::new_from_raw`, generated by build script.
34pub static ECMULT_GEN_CONTEXT: ECMultGenContext =
35    unsafe { ECMultGenContext::new_from_raw(include!(concat!(env!("OUT_DIR"), "/const_gen.rs"))) };
36
37#[derive(Debug, Clone, Copy, Eq, PartialEq)]
38/// Public key on a secp256k1 curve.
39pub struct PublicKey(Affine);
40
41#[derive(Debug, Clone, Copy, Eq, PartialEq)]
42/// Secret key (256-bit) on a secp256k1 curve.
43pub struct SecretKey(Scalar);
44
45#[derive(Debug, Clone, Copy, Eq, PartialEq)]
46/// An ECDSA signature.
47pub struct Signature {
48    pub r: Scalar,
49    pub s: Scalar,
50}
51
52#[derive(Debug, Clone, Copy, Eq, PartialEq)]
53/// Tag used for public key recovery from signatures.
54pub struct RecoveryId(u8);
55
56#[derive(Debug, Clone, Copy, Eq, PartialEq)]
57/// Hashed message input to an ECDSA signature.
58pub struct Message(pub Scalar);
59
60/// Format for public key parsing.
61pub enum PublicKeyFormat {
62    /// Compressed public key, 33 bytes.
63    Compressed,
64    /// Full length public key, 65 bytes.
65    Full,
66    /// Raw public key, 64 bytes.
67    Raw,
68}
69
70impl PublicKey {
71    pub fn from_secret_key_with_context(
72        seckey: &SecretKey,
73        context: &ECMultGenContext,
74    ) -> PublicKey {
75        let mut pj = Jacobian::default();
76        context.ecmult_gen(&mut pj, &seckey.0);
77        let mut p = Affine::default();
78        p.set_gej(&pj);
79        PublicKey(p)
80    }
81
82    #[cfg(any(feature = "static-context"))]
83    pub fn from_secret_key(seckey: &SecretKey) -> PublicKey {
84        Self::from_secret_key_with_context(seckey, &ECMULT_GEN_CONTEXT)
85    }
86
87    pub fn parse_slice(p: &[u8], format: Option<PublicKeyFormat>) -> Result<PublicKey, Error> {
88        let format = match (p.len(), format) {
89            (util::FULL_PUBLIC_KEY_SIZE, None)
90            | (util::FULL_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Full)) => PublicKeyFormat::Full,
91            (util::COMPRESSED_PUBLIC_KEY_SIZE, None)
92            | (util::COMPRESSED_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Compressed)) => {
93                PublicKeyFormat::Compressed
94            }
95            (util::RAW_PUBLIC_KEY_SIZE, None)
96            | (util::RAW_PUBLIC_KEY_SIZE, Some(PublicKeyFormat::Raw)) => PublicKeyFormat::Raw,
97            _ => return Err(Error::InvalidInputLength),
98        };
99
100        match format {
101            PublicKeyFormat::Full => {
102                let mut a = [0; util::FULL_PUBLIC_KEY_SIZE];
103                a.copy_from_slice(p);
104                Self::parse(&a)
105            }
106            PublicKeyFormat::Raw => {
107                use util::TAG_PUBKEY_FULL;
108
109                let mut a = [0; util::FULL_PUBLIC_KEY_SIZE];
110                a[0] = TAG_PUBKEY_FULL;
111                a[1..].copy_from_slice(p);
112                Self::parse(&a)
113            }
114            PublicKeyFormat::Compressed => {
115                let mut a = [0; util::COMPRESSED_PUBLIC_KEY_SIZE];
116                a.copy_from_slice(p);
117                Self::parse_compressed(&a)
118            }
119        }
120    }
121
122    pub fn parse(p: &[u8; util::FULL_PUBLIC_KEY_SIZE]) -> Result<PublicKey, Error> {
123        use util::{TAG_PUBKEY_FULL, TAG_PUBKEY_HYBRID_EVEN, TAG_PUBKEY_HYBRID_ODD};
124
125        if !(p[0] == TAG_PUBKEY_FULL
126            || p[0] == TAG_PUBKEY_HYBRID_EVEN
127            || p[0] == TAG_PUBKEY_HYBRID_ODD)
128        {
129            return Err(Error::InvalidPublicKey);
130        }
131        let mut x = Field::default();
132        let mut y = Field::default();
133        if !x.set_b32(array_ref!(p, 1, 32)) {
134            return Err(Error::InvalidPublicKey);
135        }
136        if !y.set_b32(array_ref!(p, 33, 32)) {
137            return Err(Error::InvalidPublicKey);
138        }
139        let mut elem = Affine::default();
140        elem.set_xy(&x, &y);
141        if (p[0] == TAG_PUBKEY_HYBRID_EVEN || p[0] == TAG_PUBKEY_HYBRID_ODD)
142            && (y.is_odd() != (p[0] == TAG_PUBKEY_HYBRID_ODD))
143        {
144            return Err(Error::InvalidPublicKey);
145        }
146        if elem.is_infinity() {
147            return Err(Error::InvalidPublicKey);
148        }
149        if elem.is_valid_var() {
150            Ok(PublicKey(elem))
151        } else {
152            Err(Error::InvalidPublicKey)
153        }
154    }
155
156    pub fn parse_compressed(
157        p: &[u8; util::COMPRESSED_PUBLIC_KEY_SIZE],
158    ) -> Result<PublicKey, Error> {
159        use util::{TAG_PUBKEY_EVEN, TAG_PUBKEY_ODD};
160
161        if !(p[0] == TAG_PUBKEY_EVEN || p[0] == TAG_PUBKEY_ODD) {
162            return Err(Error::InvalidPublicKey);
163        }
164        let mut x = Field::default();
165        if !x.set_b32(array_ref!(p, 1, 32)) {
166            return Err(Error::InvalidPublicKey);
167        }
168        let mut elem = Affine::default();
169        elem.set_xo_var(&x, p[0] == TAG_PUBKEY_ODD);
170        if elem.is_infinity() {
171            return Err(Error::InvalidPublicKey);
172        }
173        if elem.is_valid_var() {
174            Ok(PublicKey(elem))
175        } else {
176            Err(Error::InvalidPublicKey)
177        }
178    }
179
180    pub fn serialize(&self) -> [u8; util::FULL_PUBLIC_KEY_SIZE] {
181        use util::TAG_PUBKEY_FULL;
182
183        debug_assert!(!self.0.is_infinity());
184
185        let mut ret = [0u8; 65];
186        let mut elem = self.0;
187
188        elem.x.normalize_var();
189        elem.y.normalize_var();
190        elem.x.fill_b32(array_mut_ref!(ret, 1, 32));
191        elem.y.fill_b32(array_mut_ref!(ret, 33, 32));
192        ret[0] = TAG_PUBKEY_FULL;
193
194        ret
195    }
196
197    pub fn serialize_compressed(&self) -> [u8; util::COMPRESSED_PUBLIC_KEY_SIZE] {
198        use util::{TAG_PUBKEY_EVEN, TAG_PUBKEY_ODD};
199
200        debug_assert!(!self.0.is_infinity());
201
202        let mut ret = [0u8; 33];
203        let mut elem = self.0;
204
205        elem.x.normalize_var();
206        elem.y.normalize_var();
207        elem.x.fill_b32(array_mut_ref!(ret, 1, 32));
208        ret[0] = if elem.y.is_odd() {
209            TAG_PUBKEY_ODD
210        } else {
211            TAG_PUBKEY_EVEN
212        };
213
214        ret
215    }
216}
217
218impl Into<Affine> for PublicKey {
219    fn into(self) -> Affine {
220        self.0
221    }
222}
223
224impl TryFrom<Affine> for PublicKey {
225    type Error = Error;
226
227    fn try_from(value: Affine) -> Result<Self, Self::Error> {
228        if value.is_infinity() || !value.is_valid_var() {
229            Err(Error::InvalidAffine)
230        } else {
231            Ok(PublicKey(value))
232        }
233    }
234}
235
236impl SecretKey {
237    pub fn parse(p: &[u8; util::SECRET_KEY_SIZE]) -> Result<SecretKey, Error> {
238        let mut elem = Scalar::default();
239        if !bool::from(elem.set_b32(p)) {
240            Self::try_from(elem)
241        } else {
242            Err(Error::InvalidSecretKey)
243        }
244    }
245
246    pub fn parse_slice(p: &[u8]) -> Result<SecretKey, Error> {
247        if p.len() != util::SECRET_KEY_SIZE {
248            return Err(Error::InvalidInputLength);
249        }
250
251        let mut a = [0; 32];
252        a.copy_from_slice(p);
253        Self::parse(&a)
254    }
255
256    pub fn serialize(&self) -> [u8; util::SECRET_KEY_SIZE] {
257        self.0.b32()
258    }
259
260    pub fn tweak_add_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> {
261        let v = self.0 + tweak.0;
262        if v.is_zero() {
263            return Err(Error::TweakOutOfRange);
264        }
265        self.0 = v;
266        Ok(())
267    }
268
269    pub fn tweak_mul_assign(&mut self, tweak: &SecretKey) -> Result<(), Error> {
270        if tweak.0.is_zero() {
271            return Err(Error::TweakOutOfRange);
272        }
273
274        self.0 *= &tweak.0;
275        Ok(())
276    }
277
278    pub fn inv(&self) -> Self {
279        SecretKey(self.0.inv())
280    }
281
282    pub fn clear(&mut self) {
283        self.0.clear();
284    }
285
286    pub fn is_zero(&self) -> bool {
287        self.0.is_zero()
288    }
289}
290
291impl Default for SecretKey {
292    fn default() -> SecretKey {
293        let mut elem = Scalar::default();
294        let overflowed = bool::from(elem.set_b32(&[
295            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297            0x00, 0x00, 0x00, 0x01,
298        ]));
299        debug_assert!(!overflowed);
300        debug_assert!(!elem.is_zero());
301        SecretKey(elem)
302    }
303}
304
305impl Into<Scalar> for SecretKey {
306    fn into(self) -> Scalar {
307        self.0
308    }
309}
310
311impl TryFrom<Scalar> for SecretKey {
312    type Error = Error;
313
314    fn try_from(scalar: Scalar) -> Result<Self, Error> {
315        if scalar.is_zero() {
316            Err(Error::InvalidSecretKey)
317        } else {
318            Ok(Self(scalar))
319        }
320    }
321}
322
323impl core::fmt::LowerHex for SecretKey {
324    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
325        let scalar = self.0;
326
327        write!(f, "{:x}", scalar)
328    }
329}
330
331#[cfg(test)]
332mod tests {
333    use crate::SecretKey;
334    use hex_literal::hex;
335
336    #[test]
337    fn secret_key_inverse_is_sane() {
338        let sk = SecretKey::parse(&[1; 32]).unwrap();
339        let inv = sk.inv();
340        let invinv = inv.inv();
341        assert_eq!(sk, invinv);
342        // Check that the inverse of `[1; 32]` is same as rust-secp256k1
343        assert_eq!(
344            inv,
345            SecretKey::parse(&hex!(
346                "1536f1d756d1abf83aaf173bc5ee3fc487c93010f18624d80bd6d4038fadd59e"
347            ))
348            .unwrap()
349        )
350    }
351
352    #[test]
353    fn secret_key_clear_is_correct() {
354        let mut sk = SecretKey::parse(&[1; 32]).unwrap();
355        sk.clear();
356        assert_eq!(sk.is_zero(), true);
357    }
358}