crypto/signatures/
ed25519.rs

1// Copyright 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use core::{
5    cmp::Ordering,
6    convert::TryFrom,
7    hash::{Hash, Hasher},
8};
9
10use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
11
12#[deprecated = "Use associated const SecretKey::LENGTH"]
13pub const SECRET_KEY_LENGTH: usize = 32;
14#[deprecated = "Use associated const PublicKey::LENGTH"]
15pub const PUBLIC_KEY_LENGTH: usize = 32;
16#[deprecated = "Use associated const Signature::LENGTH"]
17pub const SIGNATURE_LENGTH: usize = 64;
18
19#[derive(Zeroize, ZeroizeOnDrop, Clone)]
20pub struct SecretKey(ed25519_zebra::SigningKey);
21
22impl SecretKey {
23    pub const LENGTH: usize = 32;
24
25    #[cfg(feature = "random")]
26    #[cfg_attr(docsrs, doc(cfg(feature = "random")))]
27    pub fn generate() -> crate::Result<Self> {
28        let mut bs = [0u8; SecretKey::LENGTH];
29        crate::utils::rand::fill(&mut bs)?;
30        let sk = Self::from_bytes(&bs);
31        bs.zeroize();
32        Ok(sk)
33    }
34
35    #[cfg(feature = "rand")]
36    pub fn generate_with<R: rand::CryptoRng + rand::RngCore>(rng: &mut R) -> Self {
37        let mut bs = [0_u8; SecretKey::LENGTH];
38        rng.fill_bytes(&mut bs);
39        let sk = Self::from_bytes(&bs);
40        bs.zeroize();
41        sk
42    }
43
44    pub fn public_key(&self) -> PublicKey {
45        PublicKey(ed25519_zebra::VerificationKey::from(&self.0))
46    }
47
48    pub fn to_bytes(&self) -> Zeroizing<[u8; SecretKey::LENGTH]> {
49        Zeroizing::new(self.0.into())
50    }
51
52    pub fn as_slice(&self) -> &[u8] {
53        self.0.as_ref()
54    }
55
56    pub fn from_bytes(bytes: &[u8; SecretKey::LENGTH]) -> Self {
57        Self((*bytes).into())
58    }
59
60    pub fn sign(&self, msg: &[u8]) -> Signature {
61        Signature(self.0.sign(msg))
62    }
63}
64
65#[derive(Copy, Clone, Debug)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67pub struct PublicKey(ed25519_zebra::VerificationKey);
68
69impl PublicKey {
70    pub const LENGTH: usize = 32;
71
72    pub fn verify(&self, sig: &Signature, msg: &[u8]) -> bool {
73        self.0.verify(&sig.0, msg).is_ok()
74    }
75
76    pub fn as_slice(&self) -> &[u8] {
77        self.0.as_ref()
78    }
79
80    pub fn to_bytes(self) -> [u8; PublicKey::LENGTH] {
81        self.0.into()
82    }
83
84    pub fn try_from_bytes(bytes: [u8; PublicKey::LENGTH]) -> crate::Result<Self> {
85        ed25519_zebra::VerificationKey::try_from(bytes)
86            .map(Self)
87            .map_err(|_| crate::Error::ConvertError {
88                from: "compressed bytes",
89                to: "Ed25519 public key",
90            })
91    }
92}
93
94impl AsRef<[u8]> for PublicKey {
95    fn as_ref(&self) -> &[u8] {
96        self.0.as_ref()
97    }
98}
99
100impl TryFrom<[u8; PublicKey::LENGTH]> for PublicKey {
101    type Error = crate::Error;
102    fn try_from(bytes: [u8; PublicKey::LENGTH]) -> crate::Result<Self> {
103        Self::try_from_bytes(bytes)
104    }
105}
106
107impl From<PublicKey> for [u8; PublicKey::LENGTH] {
108    fn from(pk: PublicKey) -> Self {
109        pk.to_bytes()
110    }
111}
112
113impl PartialEq for PublicKey {
114    fn eq(&self, other: &Self) -> bool {
115        self.as_slice() == other.as_slice()
116    }
117}
118
119impl Eq for PublicKey {}
120
121impl PartialOrd for PublicKey {
122    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
123        Some(self.cmp(other))
124    }
125}
126
127impl Ord for PublicKey {
128    fn cmp(&self, other: &Self) -> Ordering {
129        self.as_slice().cmp(other.as_slice())
130    }
131}
132
133impl Hash for PublicKey {
134    fn hash<H: Hasher>(&self, state: &mut H) {
135        (self.as_slice()).hash(state);
136    }
137}
138
139#[derive(Copy, Clone, Debug)]
140#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
141pub struct PublicKeyBytes(ed25519_zebra::VerificationKeyBytes);
142
143impl PublicKeyBytes {
144    pub const LENGTH: usize = PublicKey::LENGTH;
145
146    pub fn verify(&self, sig: &Signature, msg: &[u8]) -> crate::Result<bool> {
147        Ok(self.into_public_key()?.verify(sig, msg))
148    }
149
150    pub fn into_public_key(self) -> crate::Result<PublicKey> {
151        self.0
152            .try_into()
153            .map_err(|_| crate::Error::ConvertError {
154                from: "Ed25519 public key bytes",
155                to: "Ed25519 public key",
156            })
157            .map(PublicKey)
158    }
159
160    pub fn as_slice(&self) -> &[u8] {
161        self.0.as_ref()
162    }
163
164    pub fn to_bytes(self) -> [u8; PublicKey::LENGTH] {
165        self.0.into()
166    }
167
168    pub fn from_bytes(bytes: [u8; PublicKey::LENGTH]) -> Self {
169        Self(ed25519_zebra::VerificationKeyBytes::from(bytes))
170    }
171}
172
173impl TryFrom<PublicKeyBytes> for PublicKey {
174    type Error = crate::Error;
175
176    fn try_from(value: PublicKeyBytes) -> Result<Self, Self::Error> {
177        value.into_public_key()
178    }
179}
180
181impl AsRef<[u8]> for PublicKeyBytes {
182    fn as_ref(&self) -> &[u8] {
183        self.0.as_ref()
184    }
185}
186
187impl From<[u8; PublicKey::LENGTH]> for PublicKeyBytes {
188    fn from(bytes: [u8; PublicKey::LENGTH]) -> Self {
189        Self::from_bytes(bytes)
190    }
191}
192
193impl From<PublicKeyBytes> for [u8; PublicKey::LENGTH] {
194    fn from(pk: PublicKeyBytes) -> Self {
195        pk.to_bytes()
196    }
197}
198
199impl PartialEq for PublicKeyBytes {
200    fn eq(&self, other: &Self) -> bool {
201        self.as_slice() == other.as_slice()
202    }
203}
204
205impl Eq for PublicKeyBytes {}
206
207impl PartialOrd for PublicKeyBytes {
208    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
209        Some(self.cmp(other))
210    }
211}
212
213impl Ord for PublicKeyBytes {
214    fn cmp(&self, other: &Self) -> Ordering {
215        self.as_slice().cmp(other.as_slice())
216    }
217}
218
219impl Hash for PublicKeyBytes {
220    fn hash<H: Hasher>(&self, state: &mut H) {
221        (self.as_slice()).hash(state);
222    }
223}
224
225#[derive(Copy, Clone, Debug, Eq, PartialEq)]
226#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
227pub struct Signature(ed25519_zebra::Signature);
228
229impl Signature {
230    pub const LENGTH: usize = 64;
231
232    pub fn to_bytes(&self) -> [u8; Signature::LENGTH] {
233        self.0.into()
234    }
235
236    pub fn from_bytes(bs: [u8; Signature::LENGTH]) -> Self {
237        Self(ed25519_zebra::Signature::from(bs))
238    }
239}
240
241impl PartialOrd for Signature {
242    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
243        Some(self.cmp(other))
244    }
245}
246
247impl Ord for Signature {
248    fn cmp(&self, other: &Self) -> Ordering {
249        let r_cmp = self.0.r_bytes().cmp(other.0.r_bytes());
250        let s_cmp = self.0.s_bytes().cmp(other.0.s_bytes());
251        r_cmp.then(s_cmp)
252    }
253}
254
255impl Hash for Signature {
256    fn hash<H: Hasher>(&self, state: &mut H) {
257        <[u8; 64]>::from(self.0).hash(state);
258    }
259}