iota_sdk_types/crypto/
secp256k1.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5//! Implementation of secp256k1 public-key cryptogrophy.
6
7use crate::crypto::{PublicKeyExt, SignatureScheme};
8
9/// A secp256k1 public key.
10///
11/// # BCS
12///
13/// The BCS serialized form for this type is defined by the following ABNF:
14///
15/// ```text
16/// secp256k1-public-key = 33OCTECT
17/// ```
18#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
21#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
22pub struct Secp256k1PublicKey(
23    #[cfg_attr(
24        feature = "serde",
25        serde(
26            with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array33, [::serde_with::Same; 33]>>"
27        )
28    )]
29    #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::Base64"))]
30    [u8; Self::LENGTH],
31);
32
33impl Secp256k1PublicKey {
34    /// The length of an secp256k1 public key in bytes.
35    pub const LENGTH: usize = 33;
36
37    pub const fn new(bytes: [u8; Self::LENGTH]) -> Self {
38        Self(bytes)
39    }
40
41    #[cfg(feature = "rand")]
42    #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
43    pub fn generate<R>(mut rng: R) -> Self
44    where
45        R: rand_core::RngCore + rand_core::CryptoRng,
46    {
47        let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
48        rng.fill_bytes(&mut buf);
49        Self::new(buf)
50    }
51
52    /// Return the underlying byte array of an Secp256k1PublicKey.
53    pub const fn into_inner(self) -> [u8; Self::LENGTH] {
54        self.0
55    }
56
57    pub const fn inner(&self) -> &[u8; Self::LENGTH] {
58        &self.0
59    }
60}
61
62impl PublicKeyExt for Secp256k1PublicKey {
63    type FromBytesErr = std::array::TryFromSliceError;
64
65    /// Returns the public key as bytes.
66    fn as_bytes(&self) -> &[u8] {
67        &self.0
68    }
69
70    /// Tries to create a Secp256k1PublicKey from bytes.
71    fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, Self::FromBytesErr> {
72        <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self)
73    }
74
75    /// Returns the signature scheme for this public key.
76    fn scheme(&self) -> SignatureScheme {
77        SignatureScheme::Secp256k1
78    }
79}
80
81impl std::str::FromStr for Secp256k1PublicKey {
82    type Err = base64ct::Error;
83
84    fn from_str(s: &str) -> Result<Self, Self::Err> {
85        super::Base64FromStr33::from_str(s).map(|a| Self::new(a.0))
86    }
87}
88
89impl AsRef<[u8]> for Secp256k1PublicKey {
90    fn as_ref(&self) -> &[u8] {
91        &self.0
92    }
93}
94
95impl AsRef<[u8; Self::LENGTH]> for Secp256k1PublicKey {
96    fn as_ref(&self) -> &[u8; Self::LENGTH] {
97        &self.0
98    }
99}
100
101impl From<Secp256k1PublicKey> for [u8; Secp256k1PublicKey::LENGTH] {
102    fn from(public_key: Secp256k1PublicKey) -> Self {
103        public_key.into_inner()
104    }
105}
106
107impl From<[u8; Self::LENGTH]> for Secp256k1PublicKey {
108    fn from(public_key: [u8; Self::LENGTH]) -> Self {
109        Self::new(public_key)
110    }
111}
112
113impl std::fmt::Display for Secp256k1PublicKey {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        std::fmt::Display::fmt(&super::Base64Display33(&self.0), f)
116    }
117}
118
119impl std::fmt::Debug for Secp256k1PublicKey {
120    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121        f.debug_tuple("Secp256k1PublicKey")
122            .field(&format_args!("\"{self}\""))
123            .finish()
124    }
125}
126
127/// A secp256k1 signature.
128///
129/// # BCS
130///
131/// The BCS serialized form for this type is defined by the following ABNF:
132///
133/// ```text
134/// secp256k1-signature = 64OCTECT
135/// ```
136#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
137#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
138#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
139#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
140pub struct Secp256k1Signature(
141    #[cfg_attr(
142        feature = "serde",
143        serde(
144            with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array64, [::serde_with::Same; 64]>>"
145        )
146    )]
147    #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::Base64"))]
148    [u8; Self::LENGTH],
149);
150
151impl Secp256k1Signature {
152    /// The length of an secp256k1 signature key in bytes.
153    pub const LENGTH: usize = 64;
154
155    pub const fn new(bytes: [u8; Self::LENGTH]) -> Self {
156        Self(bytes)
157    }
158
159    #[cfg(feature = "rand")]
160    #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
161    pub fn generate<R>(mut rng: R) -> Self
162    where
163        R: rand_core::RngCore + rand_core::CryptoRng,
164    {
165        let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
166        rng.fill_bytes(&mut buf);
167        Self::new(buf)
168    }
169
170    /// Return the underlying byte array of an Secp256k1Signature.
171    pub const fn into_inner(self) -> [u8; Self::LENGTH] {
172        self.0
173    }
174
175    pub const fn inner(&self) -> &[u8; Self::LENGTH] {
176        &self.0
177    }
178
179    pub const fn as_bytes(&self) -> &[u8] {
180        &self.0
181    }
182
183    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, std::array::TryFromSliceError> {
184        <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self)
185    }
186}
187
188impl std::str::FromStr for Secp256k1Signature {
189    type Err = base64ct::Error;
190
191    fn from_str(s: &str) -> Result<Self, Self::Err> {
192        super::Base64FromStr64::from_str(s).map(|a| Self::new(a.0))
193    }
194}
195
196impl AsRef<[u8]> for Secp256k1Signature {
197    fn as_ref(&self) -> &[u8] {
198        &self.0
199    }
200}
201
202impl AsRef<[u8; Self::LENGTH]> for Secp256k1Signature {
203    fn as_ref(&self) -> &[u8; Self::LENGTH] {
204        &self.0
205    }
206}
207
208impl From<Secp256k1Signature> for [u8; Secp256k1Signature::LENGTH] {
209    fn from(signature: Secp256k1Signature) -> Self {
210        signature.into_inner()
211    }
212}
213
214impl From<[u8; Self::LENGTH]> for Secp256k1Signature {
215    fn from(signature: [u8; Self::LENGTH]) -> Self {
216        Self::new(signature)
217    }
218}
219
220impl std::fmt::Display for Secp256k1Signature {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        std::fmt::Display::fmt(&super::Base64Display64(&self.0), f)
223    }
224}
225
226impl std::fmt::Debug for Secp256k1Signature {
227    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
228        f.debug_tuple("Secp256k1Signature")
229            .field(&format_args!("\"{self}\""))
230            .finish()
231    }
232}