iota_sdk_types/crypto/
mod.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5mod bls12381;
6mod ed25519;
7mod intent;
8mod multisig;
9mod passkey;
10mod secp256k1;
11mod secp256r1;
12mod signature;
13mod zklogin;
14
15pub use bls12381::{Bls12381PublicKey, Bls12381Signature};
16pub use ed25519::{Ed25519PublicKey, Ed25519Signature};
17pub use intent::{Intent, IntentAppId, IntentScope, IntentVersion};
18pub use multisig::{
19    MultisigAggregatedSignature, MultisigCommittee, MultisigMember, MultisigMemberPublicKey,
20    MultisigMemberSignature,
21};
22pub use passkey::{PasskeyAuthenticator, PasskeyPublicKey};
23pub use secp256k1::{Secp256k1PublicKey, Secp256k1Signature};
24pub use secp256r1::{Secp256r1PublicKey, Secp256r1Signature};
25pub use signature::{InvalidSignatureScheme, SignatureScheme, SimpleSignature, UserSignature};
26pub use zklogin::{
27    Bn254FieldElement, CircomG1, CircomG2, InvalidZkLoginAuthenticatorError, Jwk, JwkId,
28    ZkLoginAuthenticator, ZkLoginClaim, ZkLoginInputs, ZkLoginProof, ZkLoginPublicIdentifier,
29};
30
31#[cfg(feature = "serde")]
32#[derive(Debug)]
33pub struct SignatureFromBytesError(String);
34
35#[cfg(feature = "serde")]
36impl SignatureFromBytesError {
37    fn new(msg: impl core::fmt::Display) -> Self {
38        Self(msg.to_string())
39    }
40}
41
42#[cfg(feature = "serde")]
43impl core::fmt::Display for SignatureFromBytesError {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        write!(f, "error deserializing bytes: {}", self.0)
46    }
47}
48
49#[cfg(feature = "serde")]
50impl std::error::Error for SignatureFromBytesError {}
51
52// Implement various base64 fixed-size array helpers
53//
54
55/// Utility for calculating base64 encoding lengths.
56///
57/// In the Base64 encoding each character is used to represent 6 bits (log2(64)
58/// = 6). This means that 4 characters are used to represent 4*6 = 24 bits = 3
59/// bytes. So you need 4*(`n`/3) characters in order to represent `n` bytes, and
60/// this needs to be rounded up to a multiple of 4. The number of unused padding
61/// characters resulting from the rounding will be 0, 1, 2, or 3.
62const fn base64_encoded_length(len: usize) -> usize {
63    ((4 * len / 3) + 3) & !3
64}
65
66macro_rules! impl_base64_helper {
67    ($base:ident, $display:ident, $fromstr:ident, $test_module:ident, $array_length:literal) => {
68        #[allow(unused)]
69        struct $base;
70
71        impl $base {
72            const LENGTH: usize = $array_length;
73            #[allow(unused)]
74            const ENCODED_LENGTH: usize = base64_encoded_length(Self::LENGTH);
75        }
76
77        #[allow(unused)]
78        struct $display<'a>(&'a [u8; $base::LENGTH]);
79
80        impl<'a> std::fmt::Display for $display<'a> {
81            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82                let mut buf = [0; $base::ENCODED_LENGTH];
83                let encoded =
84                    <base64ct::Base64 as base64ct::Encoding>::encode(self.0, &mut buf).unwrap();
85                f.write_str(encoded)
86            }
87        }
88
89        #[allow(unused)]
90        #[derive(Debug, PartialEq)]
91        #[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
92        struct $fromstr([u8; $base::LENGTH]);
93
94        impl std::str::FromStr for $fromstr {
95            type Err = base64ct::Error;
96
97            fn from_str(s: &str) -> Result<Self, Self::Err> {
98                let mut buf = [0; $base::LENGTH];
99                let decoded = <base64ct::Base64 as base64ct::Encoding>::decode(s, &mut buf)?;
100                assert_eq!(decoded.len(), $base::LENGTH);
101                Ok(Self(buf))
102            }
103        }
104
105        #[cfg(feature = "serde")]
106        #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
107        impl serde_with::SerializeAs<[u8; Self::LENGTH]> for $base {
108            fn serialize_as<S>(
109                source: &[u8; Self::LENGTH],
110                serializer: S,
111            ) -> Result<S::Ok, S::Error>
112            where
113                S: serde::Serializer,
114            {
115                let display = $display(source);
116                serde_with::DisplayFromStr::serialize_as(&display, serializer)
117            }
118        }
119
120        #[cfg(feature = "serde")]
121        #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
122        impl<'de> serde_with::DeserializeAs<'de, [u8; Self::LENGTH]> for $base {
123            fn deserialize_as<D>(deserializer: D) -> Result<[u8; Self::LENGTH], D::Error>
124            where
125                D: serde::Deserializer<'de>,
126            {
127                let array: $fromstr = serde_with::DisplayFromStr::deserialize_as(deserializer)?;
128                Ok(array.0)
129            }
130        }
131
132        #[cfg(test)]
133        mod $test_module {
134            use test_strategy::proptest;
135
136            use super::{$display, $fromstr};
137
138            #[proptest]
139            fn roundtrip_display_fromstr(array: $fromstr) {
140                let s = $display(&array.0).to_string();
141                let a = s.parse::<$fromstr>().unwrap();
142                assert_eq!(array, a);
143            }
144        }
145    };
146}
147
148impl_base64_helper!(Base64Array32, Base64Display32, Base64FromStr32, test32, 32);
149impl_base64_helper!(Base64Array33, Base64Display33, Base64FromStr33, test33, 33);
150impl_base64_helper!(Base64Array34, Base64Display34, Base64FromStr34, test34, 34);
151impl_base64_helper!(Base64Array48, Base64Display48, Base64FromStr48, test48, 48);
152impl_base64_helper!(Base64Array64, Base64Display64, Base64FromStr64, test64, 64);
153impl_base64_helper!(Base64Array96, Base64Display96, Base64FromStr96, test96, 96);
154
155pub trait PublicKeyExt: Sized {
156    type FromBytesErr;
157
158    /// Returns the public key as bytes.
159    fn as_bytes(&self) -> &[u8];
160
161    /// Tries to create a PublicKey from bytes.
162    fn from_bytes<T: AsRef<[u8]>>(bytes: T) -> Result<Self, Self::FromBytesErr>;
163
164    /// Returns the signature scheme for this public key.
165    fn scheme(&self) -> SignatureScheme;
166
167    /// Returns the bytes with signature scheme flag prepended
168    fn to_flagged_bytes(&self) -> Vec<u8> {
169        let key_bytes = self.as_bytes();
170        let mut bytes = Vec::with_capacity(1 + key_bytes.len());
171        bytes.push(self.scheme().to_u8());
172        bytes.extend_from_slice(key_bytes);
173        bytes
174    }
175}