Skip to main content

minisign/crypto/
ed25519.rs

1use super::curve25519::{ge_scalarmult_base, is_identity, sc_muladd, sc_reduce, GeP2, GeP3};
2use super::sha512;
3
4static L: [u8; 32] = [
5    0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde,
6    0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7    0x00, 0x10,
8];
9
10fn check_s_lt_l(s: &[u8]) -> bool {
11    let mut c: u8 = 0;
12    let mut n: u8 = 1;
13    let mut i: usize = 32;
14
15    loop {
16        i -= 1;
17        c |= ((((s[i] as i32) - (L[i] as i32)) >> 8) as u8) & n;
18        n &= ((((s[i] ^ L[i]) as i32) - 1) >> 8) as u8;
19        if i == 0 {
20            break;
21        }
22    }
23
24    c != 0
25}
26
27pub fn verify(message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
28    if !check_s_lt_l(&signature[32..64]) || is_identity(public_key) {
29        return false;
30    }
31    let a = match GeP3::from_bytes_negate_vartime(public_key) {
32        Some(g) => g,
33        None => {
34            return false;
35        }
36    };
37    if public_key.iter().fold(0, |acc, x| acc | x) == 0 {
38        return false;
39    }
40
41    let mut hasher = sha512::Hash::new();
42    hasher.update(&signature[0..32]);
43    hasher.update(public_key);
44    hasher.update(message);
45    let mut hash = hasher.finalize();
46    sc_reduce(&mut hash);
47
48    let r = GeP2::double_scalarmult_vartime(hash.as_ref(), a, &signature[32..64]);
49    r.to_bytes()
50        .as_ref()
51        .iter()
52        .zip(signature.iter())
53        .fold(0, |acc, (x, y)| acc | (x ^ y))
54        == 0
55}
56
57pub fn keypair(seed: &[u8]) -> ([u8; 64], [u8; 32]) {
58    let mut secret: [u8; 64] = {
59        let mut hash_output = sha512::Hash::hash(seed);
60        hash_output[0] &= 248;
61        hash_output[31] &= 63;
62        hash_output[31] |= 64;
63        hash_output
64    };
65    let a = ge_scalarmult_base(&secret[0..32]);
66    let public_key = a.to_bytes();
67    for (dest, src) in secret[32..64].iter_mut().zip(public_key.iter()) {
68        *dest = *src;
69    }
70    for (dest, src) in secret[0..32].iter_mut().zip(seed.iter()) {
71        *dest = *src;
72    }
73    (secret, public_key)
74}
75
76pub fn signature(message: &[u8], secret_key: &[u8], z: Option<&[u8]>) -> [u8; 64] {
77    let seed = &secret_key[0..32];
78    let public_key = &secret_key[32..64];
79    let az: [u8; 64] = {
80        let mut hash_output = sha512::Hash::hash(seed);
81        hash_output[0] &= 248;
82        hash_output[31] &= 63;
83        hash_output[31] |= 64;
84        hash_output
85    };
86    let nonce = {
87        let mut hasher = sha512::Hash::new();
88        if let Some(z) = z {
89            hasher.update(z);
90            hasher.update(&az[..]);
91        } else {
92            hasher.update(&az[32..64]);
93        }
94        hasher.update(message);
95        let mut hash_output = hasher.finalize();
96        sc_reduce(&mut hash_output[0..64]);
97        hash_output
98    };
99    let mut signature: [u8; 64] = [0; 64];
100    let r: GeP3 = ge_scalarmult_base(&nonce[0..32]);
101    for (result_byte, source_byte) in signature[0..32].iter_mut().zip(r.to_bytes().iter()) {
102        *result_byte = *source_byte;
103    }
104    for (result_byte, source_byte) in signature[32..64].iter_mut().zip(public_key.iter()) {
105        *result_byte = *source_byte;
106    }
107    {
108        let mut hasher = sha512::Hash::new();
109        hasher.update(signature.as_ref());
110        hasher.update(message);
111        let mut hram = hasher.finalize();
112        sc_reduce(&mut hram);
113        sc_muladd(
114            &mut signature[32..64],
115            &hram[0..32],
116            &az[0..32],
117            &nonce[0..32],
118        );
119    }
120    signature
121}