Skip to main content

ed25519_compact/
x25519.rs

1use core::ops::{Deref, DerefMut};
2
3use super::common::*;
4use super::error::Error;
5use super::field25519::*;
6
7const POINT_BYTES: usize = 32;
8
9/// Non-uniform output of a scalar multiplication.
10/// This represents a point on the curve, and should not be used directly as a
11/// cipher key.
12#[derive(Clone, Debug, Eq, PartialEq, Hash)]
13pub struct DHOutput([u8; DHOutput::BYTES]);
14
15impl DHOutput {
16    pub const BYTES: usize = 32;
17}
18
19impl Deref for DHOutput {
20    type Target = [u8; DHOutput::BYTES];
21
22    /// Returns the output of the scalar multiplication as bytes.
23    /// The output is not uniform, and should be hashed before use.
24    fn deref(&self) -> &Self::Target {
25        &self.0
26    }
27}
28
29impl DerefMut for DHOutput {
30    /// Returns the output of the scalar multiplication as bytes.
31    /// The output is not uniform, and should be hashed before use.
32    fn deref_mut(&mut self) -> &mut Self::Target {
33        &mut self.0
34    }
35}
36
37impl From<DHOutput> for PublicKey {
38    fn from(dh: DHOutput) -> Self {
39        PublicKey(dh.0)
40    }
41}
42
43impl From<DHOutput> for SecretKey {
44    fn from(dh: DHOutput) -> Self {
45        SecretKey(dh.0)
46    }
47}
48
49impl Drop for DHOutput {
50    fn drop(&mut self) {
51        Mem::wipe(&mut self.0)
52    }
53}
54
55/// A public key.
56#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
57pub struct PublicKey([u8; POINT_BYTES]);
58
59impl PublicKey {
60    /// Number of raw bytes in a public key.
61    pub const BYTES: usize = POINT_BYTES;
62
63    /// Creates a public key from raw bytes.
64    pub fn new(pk: [u8; PublicKey::BYTES]) -> Self {
65        PublicKey(pk)
66    }
67
68    /// Creates a public key from a slice.
69    pub fn from_slice(pk: &[u8]) -> Result<Self, Error> {
70        let mut pk_ = [0u8; PublicKey::BYTES];
71        if pk.len() != pk_.len() {
72            return Err(Error::InvalidPublicKey);
73        }
74        Fe::reject_noncanonical(pk)?;
75        pk_.copy_from_slice(pk);
76        Ok(PublicKey::new(pk_))
77    }
78
79    /// Multiply a point by the cofactor, returning an error if the element is
80    /// in a small-order group.
81    pub fn clear_cofactor(&self) -> Result<[u8; PublicKey::BYTES], Error> {
82        let cofactor = [
83            8u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
84            0, 0, 0, 0,
85        ];
86        self.ladder(&cofactor, 4)
87    }
88
89    /// Multiply the point represented by the public key by the scalar after
90    /// clamping it
91    pub fn dh(&self, sk: &SecretKey) -> Result<DHOutput, Error> {
92        let sk = sk.clamped();
93        Ok(DHOutput(self.ladder(&sk.0, 255)?))
94    }
95
96    /// Multiply the point represented by the public key by the scalar WITHOUT
97    /// CLAMPING
98    pub fn unclamped_mul(&self, sk: &SecretKey) -> Result<DHOutput, Error> {
99        self.clear_cofactor()?;
100        Ok(DHOutput(self.ladder(&sk.0, 256)?))
101    }
102
103    #[cfg_attr(feature = "opt_size", inline(never))]
104    #[cfg_attr(not(feature = "opt_size"), inline(always))]
105    fn ladder(&self, s: &[u8], bits: usize) -> Result<[u8; POINT_BYTES], Error> {
106        let x1 = Fe::from_bytes(&self.0);
107        let mut x2 = FE_ONE;
108        let mut z2 = FE_ZERO;
109        let mut x3 = x1;
110        let mut z3 = FE_ONE;
111        let mut swap: u8 = 0;
112        let mut pos = bits - 1;
113        loop {
114            let bit = (s[pos >> 3] >> (pos & 7)) & 1;
115            swap ^= bit;
116            Fe::cswap2(&mut x2, &mut x3, &mut z2, &mut z3, swap);
117            swap = bit;
118            let a = x2 + z2;
119            let b = x2 - z2;
120            let aa = a.square();
121            let bb = b.square();
122            x2 = aa * bb;
123            let e = aa - bb;
124            let da = (x3 - z3) * a;
125            let cb = (x3 + z3) * b;
126            x3 = (da + cb).square();
127            z3 = x1 * ((da - cb).square());
128            z2 = e * (bb + (e.mul32(121666)));
129            if pos == 0 {
130                break;
131            }
132            pos -= 1;
133        }
134        Fe::cswap2(&mut x2, &mut x3, &mut z2, &mut z3, swap);
135        z2 = z2.invert();
136        x2 = x2 * z2;
137        if x2.is_zero() {
138            return Err(Error::WeakPublicKey);
139        }
140        Ok(x2.to_bytes())
141    }
142
143    /// The Curve25519 base point
144    #[inline]
145    pub fn base_point() -> PublicKey {
146        let mut pk = [0u8; POINT_BYTES];
147        pk[0] = 9;
148        PublicKey(pk)
149    }
150}
151
152impl Deref for PublicKey {
153    type Target = [u8; PublicKey::BYTES];
154
155    /// Returns a public key as bytes.
156    fn deref(&self) -> &Self::Target {
157        &self.0
158    }
159}
160
161impl DerefMut for PublicKey {
162    /// Returns a public key as mutable bytes.
163    fn deref_mut(&mut self) -> &mut Self::Target {
164        &mut self.0
165    }
166}
167
168/// A secret key.
169#[derive(Clone, Debug, Eq, PartialEq, Hash)]
170pub struct SecretKey([u8; SecretKey::BYTES]);
171
172impl SecretKey {
173    /// Number of bytes in a secret key.
174    pub const BYTES: usize = 32;
175
176    /// Creates a secret key from raw bytes.
177    pub fn new(sk: [u8; SecretKey::BYTES]) -> Self {
178        SecretKey(sk)
179    }
180
181    /// Creates a secret key from a slice.
182    pub fn from_slice(sk: &[u8]) -> Result<Self, Error> {
183        let mut sk_ = [0u8; SecretKey::BYTES];
184        if sk.len() != sk_.len() {
185            return Err(Error::InvalidSecretKey);
186        }
187        sk_.copy_from_slice(sk);
188        Ok(SecretKey::new(sk_))
189    }
190
191    /// Perform the X25519 clamping magic
192    pub fn clamped(&self) -> SecretKey {
193        let mut clamped = self.clone();
194        clamped[0] &= 248;
195        clamped[31] &= 63;
196        clamped[31] |= 64;
197        clamped
198    }
199
200    /// Recover the public key
201    pub fn recover_public_key(&self) -> Result<PublicKey, Error> {
202        let sk = self.clamped();
203        Ok(PublicKey(PublicKey::base_point().ladder(&sk.0, 255)?))
204    }
205
206    /// Returns `Ok(())` if the given public key is the public counterpart of
207    /// this secret key.
208    /// Returns `Err(Error::InvalidPublicKey)` otherwise.
209    pub fn validate_public_key(&self, pk: &PublicKey) -> Result<(), Error> {
210        let recovered_pk = self.recover_public_key()?;
211        if recovered_pk != *pk {
212            return Err(Error::InvalidPublicKey);
213        }
214        Ok(())
215    }
216}
217
218impl Drop for SecretKey {
219    fn drop(&mut self) {
220        Mem::wipe(&mut self.0)
221    }
222}
223
224impl Deref for SecretKey {
225    type Target = [u8; SecretKey::BYTES];
226
227    /// Returns a secret key as bytes.
228    fn deref(&self) -> &Self::Target {
229        &self.0
230    }
231}
232
233impl DerefMut for SecretKey {
234    /// Returns a secret key as mutable bytes.
235    fn deref_mut(&mut self) -> &mut Self::Target {
236        &mut self.0
237    }
238}
239
240/// A key pair.
241#[derive(Clone, Debug, Eq, PartialEq, Hash)]
242pub struct KeyPair {
243    /// Public key part of the key pair.
244    pub pk: PublicKey,
245    /// Secret key part of the key pair.
246    pub sk: SecretKey,
247}
248
249impl KeyPair {
250    /// Generates a new key pair.
251    #[cfg(feature = "random")]
252    pub fn generate() -> KeyPair {
253        let mut sk = [0u8; SecretKey::BYTES];
254        getrandom::fill(&mut sk).expect("getrandom");
255        if Fe::from_bytes(&sk).is_zero() {
256            panic!("All-zero secret key");
257        }
258        let sk = SecretKey(sk);
259        let pk = sk
260            .recover_public_key()
261            .expect("generated public key is weak");
262        KeyPair { pk, sk }
263    }
264
265    /// Check that the public key is valid for the secret key.
266    pub fn validate(&self) -> Result<(), Error> {
267        self.sk.validate_public_key(&self.pk)
268    }
269}
270
271#[cfg(not(feature = "disable-signatures"))]
272mod from_ed25519 {
273    use super::super::{
274        edwards25519, sha512, KeyPair as EdKeyPair, PublicKey as EdPublicKey,
275        SecretKey as EdSecretKey,
276    };
277    use super::*;
278
279    impl SecretKey {
280        /// Convert an Ed25519 secret key to a X25519 secret key.
281        pub fn from_ed25519(edsk: &EdSecretKey) -> Result<SecretKey, Error> {
282            let seed = edsk.seed();
283            let az: [u8; 64] = {
284                let mut hash_output = sha512::Hash::hash(*seed);
285                hash_output[0] &= 248;
286                hash_output[31] &= 63;
287                hash_output[31] |= 64;
288                hash_output
289            };
290            SecretKey::from_slice(&az[..32])
291        }
292    }
293
294    impl PublicKey {
295        /// Convert an Ed25519 public key to a X25519 public key.
296        pub fn from_ed25519(edpk: &EdPublicKey) -> Result<PublicKey, Error> {
297            let pk = PublicKey::from_slice(
298                &edwards25519::ge_to_x25519_vartime(edpk).ok_or(Error::InvalidPublicKey)?,
299            )?;
300            pk.clear_cofactor()?;
301            Ok(pk)
302        }
303    }
304
305    impl KeyPair {
306        /// Convert an Ed25519 key pair to a X25519 key pair.
307        pub fn from_ed25519(edkp: &EdKeyPair) -> Result<KeyPair, Error> {
308            let pk = PublicKey::from_ed25519(&edkp.pk)?;
309            let sk = SecretKey::from_ed25519(&edkp.sk)?;
310            Ok(KeyPair { pk, sk })
311        }
312    }
313}
314
315#[cfg(not(feature = "disable-signatures"))]
316#[allow(unused)]
317pub use from_ed25519::*;
318
319#[test]
320fn test_x25519() {
321    let sk_1 = SecretKey::from_slice(&[
322        1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
323        0, 0,
324    ])
325    .unwrap();
326    let output = PublicKey::base_point().unclamped_mul(&sk_1).unwrap();
327    assert_eq!(PublicKey::from(output), PublicKey::base_point());
328    let kp_a = KeyPair::generate();
329    let kp_b = KeyPair::generate();
330    let output_a = kp_b.pk.dh(&kp_a.sk).unwrap();
331    let output_b = kp_a.pk.dh(&kp_b.sk).unwrap();
332    assert_eq!(output_a, output_b);
333}
334
335#[test]
336fn test_x25519_rfc7748() {
337    use core::convert::TryInto;
338    use ct_codecs::{Decoder, Hex};
339
340    fn decode32(hex: &str) -> [u8; 32] {
341        Hex::decode_to_vec(hex, None).unwrap().try_into().unwrap()
342    }
343
344    let alice_sk = SecretKey::new(decode32(
345        "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
346    ));
347    let alice_pk = alice_sk.recover_public_key().unwrap();
348    assert_eq!(
349        &alice_pk[..],
350        &decode32("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a")
351    );
352
353    let bob_sk = SecretKey::new(decode32(
354        "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb",
355    ));
356    let bob_pk = PublicKey::from_slice(&decode32(
357        "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
358    ))
359    .unwrap();
360    assert_eq!(bob_sk.recover_public_key().unwrap(), bob_pk);
361
362    let shared_a = bob_pk.dh(&alice_sk).unwrap();
363    let shared_b = alice_pk.dh(&bob_sk).unwrap();
364    let expected = decode32("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
365    assert_eq!(&shared_a[..], &expected);
366    assert_eq!(shared_a, shared_b);
367}
368
369#[cfg(not(feature = "disable-signatures"))]
370#[test]
371fn test_x25519_map() {
372    use super::KeyPair as EdKeyPair;
373    let edkp_a = EdKeyPair::generate();
374    let edkp_b = EdKeyPair::generate();
375    let kp_a = KeyPair::from_ed25519(&edkp_a).unwrap();
376    let kp_b = KeyPair::from_ed25519(&edkp_b).unwrap();
377    let output_a = kp_b.pk.dh(&kp_a.sk).unwrap();
378    let output_b = kp_a.pk.dh(&kp_b.sk).unwrap();
379    assert_eq!(output_a, output_b);
380}
381
382#[test]
383#[cfg(all(not(feature = "disable-signatures"), feature = "random"))]
384fn test_x25519_invalid_keypair() {
385    let kp1 = KeyPair::generate();
386    let kp2 = KeyPair::generate();
387
388    assert_eq!(
389        kp1.sk.validate_public_key(&kp2.pk).unwrap_err(),
390        Error::InvalidPublicKey
391    );
392    assert_eq!(
393        kp2.sk.validate_public_key(&kp1.pk).unwrap_err(),
394        Error::InvalidPublicKey
395    );
396    assert!(kp1.sk.validate_public_key(&kp1.pk).is_ok());
397    assert!(kp2.sk.validate_public_key(&kp2.pk).is_ok());
398    assert!(kp1.validate().is_ok());
399}