Skip to main content

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