embedded_td/crypto/
sr25519.rs

1use curve25519_dalek_ng::{constants, scalar::Scalar};
2use rand_core::{CryptoRng, RngCore};
3use sha2::{digest::FixedOutput, Digest, Sha512};
4
5use super::define_as_ref_u8_array;
6
7#[derive(Debug, Clone)]
8pub struct SecretKey(pub [u8; 32]);
9define_as_ref_u8_array!(SecretKey);
10
11#[derive(Debug, Clone)]
12pub struct PublicKey(pub [u8; 32]);
13define_as_ref_u8_array!(PublicKey);
14
15impl SecretKey {
16    pub fn generate(rng: impl RngCore + CryptoRng) -> Self {
17        let mut rng = rng;
18
19        let mut sk = [0u8; 32];
20
21        rng.fill_bytes(&mut sk);
22
23        SecretKey(sk)
24    }
25
26    pub fn public_key(&self) -> PublicKey {
27        let mut h = Sha512::default();
28        h.update(self.0);
29        let r = h.finalize_fixed();
30
31        let mut key = [0u8; 32];
32        key.copy_from_slice(&r.as_slice()[0..32]);
33        key[0] &= 248;
34        key[31] &= 63;
35        key[31] |= 64;
36
37        divide_scalar_bytes_by_cofactor(&mut key);
38        let key = Scalar::from_bits(key);
39
40        let point = &key * &constants::RISTRETTO_BASEPOINT_TABLE;
41
42        let compressed = point.compress();
43
44        PublicKey(compressed.to_bytes())
45    }
46}
47
48fn divide_scalar_bytes_by_cofactor(scalar: &mut [u8; 32]) {
49    let mut low = 0u8;
50    for i in scalar.iter_mut().rev() {
51        let r = *i & 0b00000111; // save remainder
52        *i >>= 3; // divide by 8
53        *i += low;
54        low = r << 5;
55    }
56}