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 cryptogrophy.
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/// bls-public-key = %x60 96OCTECT
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, Hash, PartialEq, Eq, PartialOrd, Ord)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
24#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
25pub struct Bls12381PublicKey(
26    #[cfg_attr(
27        feature = "serde",
28        serde(
29            with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array96, ::serde_with::Bytes>>"
30        )
31    )]
32    #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::Base64"))]
33    [u8; Self::LENGTH],
34);
35
36impl Bls12381PublicKey {
37    /// The length of an bls12381 public key in bytes.
38    pub const LENGTH: usize = 96;
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 generate<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    /// Return the underlying byte array of an Bls12381PublicKey.
56    pub const fn into_inner(self) -> [u8; Self::LENGTH] {
57        self.0
58    }
59
60    pub const fn inner(&self) -> &[u8; Self::LENGTH] {
61        &self.0
62    }
63
64    pub const fn as_bytes(&self) -> &[u8] {
65        &self.0
66    }
67
68    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, std::array::TryFromSliceError> {
69        <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self)
70    }
71}
72
73impl std::str::FromStr for Bls12381PublicKey {
74    type Err = base64ct::Error;
75
76    fn from_str(s: &str) -> Result<Self, Self::Err> {
77        super::Base64FromStr96::from_str(s).map(|a| Self(a.0))
78    }
79}
80
81impl AsRef<[u8]> for Bls12381PublicKey {
82    fn as_ref(&self) -> &[u8] {
83        &self.0
84    }
85}
86
87impl AsRef<[u8; Self::LENGTH]> for Bls12381PublicKey {
88    fn as_ref(&self) -> &[u8; Self::LENGTH] {
89        &self.0
90    }
91}
92
93impl From<Bls12381PublicKey> for [u8; Bls12381PublicKey::LENGTH] {
94    fn from(public_key: Bls12381PublicKey) -> Self {
95        public_key.into_inner()
96    }
97}
98
99impl From<[u8; Self::LENGTH]> for Bls12381PublicKey {
100    fn from(public_key: [u8; Self::LENGTH]) -> Self {
101        Self::new(public_key)
102    }
103}
104
105impl std::fmt::Display for Bls12381PublicKey {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        std::fmt::Display::fmt(&super::Base64Display96(&self.0), f)
108    }
109}
110
111impl std::fmt::Debug for Bls12381PublicKey {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        f.debug_tuple("Bls12381PublicKey")
114            .field(&format_args!("\"{self}\""))
115            .finish()
116    }
117}
118
119/// A bls12381 min-sig signature.
120///
121/// # BCS
122///
123/// The BCS serialized form for this type is defined by the following ABNF:
124///
125/// ```text
126/// bls-signature = 48OCTECT
127/// ```
128#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
130#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
131#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
132pub struct Bls12381Signature(
133    #[cfg_attr(
134        feature = "serde",
135        serde(
136            with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array48, [::serde_with::Same; 48]>>"
137        )
138    )]
139    #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::Base64"))]
140    [u8; Self::LENGTH],
141);
142
143impl Bls12381Signature {
144    /// The length of an bls12381 signature key in bytes.
145    pub const LENGTH: usize = 48;
146
147    pub const fn new(bytes: [u8; Self::LENGTH]) -> Self {
148        Self(bytes)
149    }
150
151    #[cfg(feature = "rand")]
152    #[cfg_attr(doc_cfg, doc(cfg(feature = "rand")))]
153    pub fn generate<R>(mut rng: R) -> Self
154    where
155        R: rand_core::RngCore + rand_core::CryptoRng,
156    {
157        let mut buf: [u8; Self::LENGTH] = [0; Self::LENGTH];
158        rng.fill_bytes(&mut buf);
159        Self::new(buf)
160    }
161
162    /// Return the underlying byte array of an Bls12381Signature.
163    pub const fn into_inner(self) -> [u8; Self::LENGTH] {
164        self.0
165    }
166
167    pub const fn inner(&self) -> &[u8; Self::LENGTH] {
168        &self.0
169    }
170
171    pub const fn as_bytes(&self) -> &[u8] {
172        &self.0
173    }
174
175    pub fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, std::array::TryFromSliceError> {
176        <[u8; Self::LENGTH]>::try_from(bytes.as_ref()).map(Self)
177    }
178}
179
180impl std::str::FromStr for Bls12381Signature {
181    type Err = base64ct::Error;
182
183    fn from_str(s: &str) -> Result<Self, Self::Err> {
184        super::Base64FromStr48::from_str(s).map(|a| Self::new(a.0))
185    }
186}
187
188impl AsRef<[u8]> for Bls12381Signature {
189    fn as_ref(&self) -> &[u8] {
190        &self.0
191    }
192}
193
194impl AsRef<[u8; Self::LENGTH]> for Bls12381Signature {
195    fn as_ref(&self) -> &[u8; Self::LENGTH] {
196        &self.0
197    }
198}
199
200impl From<Bls12381Signature> for [u8; Bls12381Signature::LENGTH] {
201    fn from(signature: Bls12381Signature) -> Self {
202        signature.into_inner()
203    }
204}
205
206impl From<[u8; Self::LENGTH]> for Bls12381Signature {
207    fn from(signature: [u8; Self::LENGTH]) -> Self {
208        Self::new(signature)
209    }
210}
211
212impl std::fmt::Display for Bls12381Signature {
213    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
214        std::fmt::Display::fmt(&super::Base64Display48(&self.0), f)
215    }
216}
217
218impl std::fmt::Debug for Bls12381Signature {
219    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220        f.debug_tuple("Bls12381Signature")
221            .field(&format_args!("\"{self}\""))
222            .finish()
223    }
224}