cypher/
ed25519.rs

1// Set of libraries for privacy-preserving networking apps
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2023 by
6//     Dr. Maxim Orlovsky <orlovsky@cyphernet.org>
7//
8// Copyright 2022-2023 Cyphernet DAO, Switzerland
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22//! Edwards25519 curve keys and EdDSA algorithm implementation for Ed25519 scheme.
23
24use std::cmp::Ordering;
25use std::ops::Deref;
26
27use crate::display::{Encoding, MultiDisplay};
28use crate::{EcPk, EcPkInvalid, EcSig, EcSigInvalid, EcSign, EcSk, EcSkInvalid, EcVerifyError};
29
30// ============================================================================
31// ec25519 keys
32
33impl MultiDisplay<Encoding> for ec25519::PublicKey {
34    type Display = String;
35    fn display_fmt(&self, f: &Encoding) -> Self::Display { f.encode(self.as_slice()) }
36}
37
38impl EcPk for ec25519::PublicKey {
39    const COMPRESSED_LEN: usize = 32;
40    const CURVE_NAME: &'static str = "Edwards25519";
41    type Compressed = [u8; 32];
42
43    fn base_point() -> Self {
44        ec25519::PublicKey::from_slice(
45            &[
46                0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
47                0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
48                0x66, 0x66, 0x66, 0x66,
49            ][..],
50        )
51        .expect("hardcoded basepoint value")
52    }
53
54    fn to_pk_compressed(&self) -> Self::Compressed { *self.deref() }
55
56    fn from_pk_compressed(pk: Self::Compressed) -> Result<Self, EcPkInvalid> {
57        Ok(ec25519::PublicKey::new(pk))
58    }
59
60    fn from_pk_compressed_slice(slice: &[u8]) -> Result<Self, EcPkInvalid> {
61        if slice.len() != Self::COMPRESSED_LEN {
62            return Err(EcPkInvalid {});
63        }
64        let mut buf = [0u8; 32];
65        buf.copy_from_slice(slice);
66        Self::from_pk_compressed(buf)
67    }
68}
69
70impl EcSk for ec25519::SecretKey {
71    type Pk = ec25519::PublicKey;
72
73    fn generate_keypair() -> (Self, Self::Pk)
74    where Self: Sized {
75        let pair = ec25519::KeyPair::generate();
76        (pair.sk, pair.pk)
77    }
78
79    fn to_pk(&self) -> Result<Self::Pk, EcSkInvalid> { Ok(self.public_key()) }
80}
81
82// ============================================================================
83// Key newtypes
84
85#[derive(Wrapper, Copy, Clone, PartialEq, Eq, Hash, Debug, From)]
86#[wrapper(Deref)]
87#[cfg_attr(
88    feature = "serde",
89    derive(Serialize, Deserialize),
90    serde(into = "String", try_from = "String")
91)]
92pub struct PublicKey(#[from] ec25519::PublicKey);
93
94impl PartialOrd for PublicKey {
95    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
96        self.0.as_ref().partial_cmp(other.0.as_ref())
97    }
98}
99
100impl Ord for PublicKey {
101    fn cmp(&self, other: &Self) -> Ordering { self.0.as_ref().cmp(other.0.as_ref()) }
102}
103
104impl EcPk for PublicKey {
105    const COMPRESSED_LEN: usize = 32;
106    const CURVE_NAME: &'static str = "Edwards25519";
107    type Compressed = [u8; 32];
108
109    fn base_point() -> Self { Self(ec25519::PublicKey::base_point()) }
110
111    fn to_pk_compressed(&self) -> Self::Compressed { self.0.to_pk_compressed() }
112
113    fn from_pk_compressed(pk: Self::Compressed) -> Result<Self, EcPkInvalid> {
114        ec25519::PublicKey::from_pk_compressed(pk).map(Self)
115    }
116
117    fn from_pk_compressed_slice(slice: &[u8]) -> Result<Self, EcPkInvalid> {
118        ec25519::PublicKey::from_pk_compressed_slice(slice).map(Self)
119    }
120}
121
122impl MultiDisplay<Encoding> for PublicKey {
123    type Display = String;
124    fn display_fmt(&self, f: &Encoding) -> Self::Display { self.0.display_fmt(f) }
125}
126
127#[derive(Wrapper, Clone, PartialEq, Eq, Hash, Debug, From)]
128#[wrapper(Deref)]
129pub struct PrivateKey(#[from] ec25519::SecretKey);
130
131impl PartialOrd for PrivateKey {
132    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
133}
134
135impl Ord for PrivateKey {
136    fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&other.0) }
137}
138
139impl EcSk for PrivateKey {
140    type Pk = PublicKey;
141
142    fn generate_keypair() -> (Self, Self::Pk)
143    where Self: Sized {
144        let (sk, pk) = ec25519::SecretKey::generate_keypair();
145        (sk.into(), pk.into())
146    }
147
148    fn to_pk(&self) -> Result<PublicKey, EcSkInvalid> { self.0.to_pk().map(PublicKey::from) }
149}
150
151// ============================================================================
152// EdDSA
153
154impl EcSign for ec25519::SecretKey {
155    type Sig = ec25519::Signature;
156
157    fn sign(&self, msg: impl AsRef<[u8]>) -> ec25519::Signature { self.sign(msg, None) }
158}
159
160impl MultiDisplay<Encoding> for ec25519::Signature {
161    type Display = String;
162    fn display_fmt(&self, f: &Encoding) -> Self::Display { f.encode(self.as_slice()) }
163}
164
165impl EcSig for ec25519::Signature {
166    const COMPRESSED_LEN: usize = 64;
167
168    type Pk = ec25519::PublicKey;
169    type Compressed = [u8; 64];
170
171    fn to_sig_compressed(&self) -> Self::Compressed { *self.deref() }
172
173    fn from_sig_compressed(sig: Self::Compressed) -> Result<Self, EcSigInvalid> {
174        Ok(Self::from_slice(&sig).expect("fixed length"))
175    }
176
177    fn from_sig_compressed_slice(slice: &[u8]) -> Result<Self, EcSigInvalid> {
178        Self::from_slice(slice).map_err(|_| EcSigInvalid {})
179    }
180
181    fn verify(&self, pk: &Self::Pk, msg: impl AsRef<[u8]>) -> Result<(), EcVerifyError> {
182        pk.verify(msg, self).map_err(EcVerifyError::from)
183    }
184}
185
186/// Cryptographic signature.
187#[derive(Wrapper, Copy, Clone, PartialEq, Eq, Hash, Debug)]
188#[wrapper(Deref)]
189pub struct Signature(ec25519::Signature);
190
191impl AsRef<[u8]> for Signature {
192    fn as_ref(&self) -> &[u8] { self.0.as_ref() }
193}
194
195impl From<ec25519::Signature> for Signature {
196    fn from(other: ec25519::Signature) -> Self { Self(other) }
197}
198
199impl MultiDisplay<Encoding> for Signature {
200    type Display = String;
201    fn display_fmt(&self, f: &Encoding) -> Self::Display { self.0.display_fmt(f) }
202}
203
204impl EcSig for Signature {
205    const COMPRESSED_LEN: usize = 64;
206    type Pk = PublicKey;
207    type Compressed = [u8; 64];
208
209    fn to_sig_compressed(&self) -> Self::Compressed { self.0.to_sig_compressed() }
210
211    fn from_sig_compressed(sig: Self::Compressed) -> Result<Self, EcSigInvalid> {
212        ec25519::Signature::from_sig_compressed(sig).map(Self)
213    }
214
215    fn from_sig_compressed_slice(slice: &[u8]) -> Result<Self, EcSigInvalid> {
216        ec25519::Signature::from_sig_compressed_slice(slice).map(Self)
217    }
218
219    fn verify(&self, pk: &Self::Pk, msg: impl AsRef<[u8]>) -> Result<(), EcVerifyError> {
220        self.0.verify(pk, msg)
221    }
222}
223
224impl EcSign for PrivateKey {
225    type Sig = Signature;
226
227    fn sign(&self, msg: impl AsRef<[u8]>) -> Signature { Signature(self.0.sign(msg, None)) }
228}
229
230// ============================================================================
231// Display and from string
232
233#[cfg(feature = "multibase")]
234mod human_readable {
235    use std::fmt::{self, Display, Formatter};
236    use std::str::FromStr;
237
238    use super::*;
239    use crate::EcSerError;
240
241    impl PublicKey {
242        /// Multicodec key type for Ed25519 keys.
243        pub const MULTICODEC_TYPE: [u8; 2] = [0xED, 0x1];
244
245        /// Encode public key in human-readable format.
246        ///
247        /// We use the format specified by the DID `key` method, which is described as:
248        ///
249        /// `did:key:MULTIBASE(base58-btc, MULTICODEC(public-key-type, raw-public-key-bytes))`
250        pub fn to_human_readable(&self) -> String {
251            let mut buf = [0; 2 + ec25519::PublicKey::BYTES];
252            buf[..2].copy_from_slice(&Self::MULTICODEC_TYPE);
253            buf[2..].copy_from_slice(self.0.deref());
254
255            multibase::encode(multibase::Base::Base58Btc, buf)
256        }
257    }
258
259    impl Display for PublicKey {
260        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
261            f.write_str(&self.to_human_readable())
262        }
263    }
264
265    impl FromStr for PublicKey {
266        type Err = EcSerError;
267
268        fn from_str(s: &str) -> Result<Self, Self::Err> {
269            let (_, bytes) = multibase::decode(s)?;
270
271            if let Some(bytes) = bytes.strip_prefix(&Self::MULTICODEC_TYPE) {
272                let key = ec25519::PublicKey::from_slice(bytes)?;
273
274                Ok(Self(key))
275            } else {
276                Err(EcSerError::DataEncoding(s!("unrecognized multicode type")))
277            }
278        }
279    }
280
281    impl From<PublicKey> for String {
282        fn from(other: PublicKey) -> Self { other.to_human_readable() }
283    }
284
285    impl TryFrom<String> for PublicKey {
286        type Error = EcSerError;
287
288        fn try_from(value: String) -> Result<Self, Self::Error> { Self::from_str(&value) }
289    }
290
291    impl Display for Signature {
292        fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
293            let base = multibase::Base::Base58Btc;
294            write!(f, "{}", multibase::encode(base, self.0))
295        }
296    }
297
298    impl FromStr for Signature {
299        type Err = EcSerError;
300
301        fn from_str(s: &str) -> Result<Self, Self::Err> {
302            let (_, bytes) = multibase::decode(s)?;
303            let sig = ec25519::Signature::from_slice(bytes.as_slice())?;
304
305            Ok(Self(sig))
306        }
307    }
308}
309
310#[cfg(feature = "pem")]
311mod pem_der {
312    use super::*;
313
314    impl PublicKey {
315        pub fn from_pem(pem: &str) -> Result<Self, ec25519::Error> {
316            ec25519::PublicKey::from_pem(pem).map(Self)
317        }
318
319        pub fn from_der(der: &[u8]) -> Result<Self, ec25519::Error> {
320            ec25519::PublicKey::from_der(der).map(Self::from)
321        }
322
323        pub fn to_pem(&self) -> String { self.0.to_pem() }
324    }
325
326    impl PrivateKey {
327        pub fn from_pem(pem: &str) -> Result<Self, ec25519::Error> {
328            ec25519::SecretKey::from_pem(pem).map(Self::from)
329        }
330
331        pub fn from_der(der: &[u8]) -> Result<Self, ec25519::Error> {
332            ec25519::SecretKey::from_der(der).map(Self::from)
333        }
334
335        pub fn to_pem(&self) -> String { self.0.to_pem() }
336    }
337}