Skip to main content

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