Skip to main content

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