crypto/
ed25519.rs

1use digest::Digest;
2use sha2::{Sha512};
3use curve25519::{GeP2, GeP3, ge_scalarmult_base, sc_reduce, sc_muladd, curve25519, Fe};
4use util::{fixed_time_eq};
5use std::ops::{Add, Sub, Mul};
6
7static L: [u8; 32] =
8      [ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
9        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
10        0x14, 0xde, 0xf9, 0xde, 0xa2, 0xf7, 0x9c, 0xd6,
11        0x58, 0x12, 0x63, 0x1a, 0x5c, 0xf5, 0xd3, 0xed ];
12
13pub fn keypair(seed: &[u8]) -> ([u8; 64], [u8; 32]) {
14    let mut secret: [u8; 64] = {
15        let mut hash_output: [u8; 64] = [0; 64];
16        let mut hasher = Sha512::new();
17        hasher.input(seed);
18        hasher.result(&mut hash_output);
19        hash_output[0] &= 248;
20        hash_output[31] &= 63;
21        hash_output[31] |= 64;
22        hash_output
23    };
24
25    let a = ge_scalarmult_base(&secret[0..32]);
26    let public_key = a.to_bytes();
27    for (dest, src) in (&mut secret[32..64]).iter_mut().zip(public_key.iter()) {
28        *dest = *src;
29    }
30    for (dest, src) in (&mut secret[0..32]).iter_mut().zip(seed.iter()) {
31        *dest = *src;
32    }
33    (secret, public_key)
34}
35
36pub fn signature(message: &[u8], secret_key: &[u8]) -> [u8; 64] {
37    let seed = &secret_key[0..32];
38    let public_key = &secret_key[32..64];
39    let az: [u8; 64] = {
40        let mut hash_output: [u8; 64] = [0; 64];
41        let mut hasher = Sha512::new();
42        hasher.input(seed);
43        hasher.result(&mut hash_output);
44        hash_output[0] &= 248;
45        hash_output[31] &= 63;
46        hash_output[31] |= 64;
47        hash_output
48    };
49
50    let nonce = {
51        let mut hash_output: [u8; 64] = [0; 64];
52        let mut hasher = Sha512::new();
53        hasher.input(&az[32..64]);
54        hasher.input(message);
55        hasher.result(&mut hash_output);
56        sc_reduce(&mut hash_output[0..64]);
57        hash_output
58    };
59
60    let mut signature: [u8; 64] = [0; 64];
61    let r: GeP3 = ge_scalarmult_base(&nonce[0..32]);
62    for (result_byte, source_byte) in (&mut signature[0..32]).iter_mut().zip(r.to_bytes().iter()) {
63        *result_byte = *source_byte;
64    }
65    for (result_byte, source_byte) in (&mut signature[32..64]).iter_mut().zip(public_key.iter()) {
66        *result_byte = *source_byte;
67    }
68
69    {
70        let mut hasher = Sha512::new();
71        hasher.input(signature.as_ref());
72        hasher.input(message);
73        let mut hram: [u8; 64] = [0; 64];
74        hasher.result(&mut hram);
75        sc_reduce(&mut hram);
76        sc_muladd(&mut signature[32..64], &hram[0..32], &az[0..32], &nonce[0..32]);
77    }
78
79    signature
80}
81
82fn check_s_lt_l(s: &[u8]) -> bool
83{
84    let mut c: u8 = 0;
85    let mut n: u8 = 1;
86
87    let mut i = 31;
88    loop {
89        c |= ((((s[i] as i32) - (L[i] as i32)) >> 8) as u8) & n;
90        n &= (((((s[i] ^ L[i]) as i32)) - 1) >> 8) as u8;
91        if i == 0 {
92            break;
93        } else {
94            i -= 1;
95        }
96    }
97
98    c == 0
99}
100
101pub fn verify(message: &[u8], public_key: &[u8], signature: &[u8]) -> bool {
102    if check_s_lt_l(&signature[32..64]) {
103        return false;
104    }
105
106    let a = match GeP3::from_bytes_negate_vartime(public_key) {
107        Some(g) => g,
108        None => { return false; }
109    };
110    let mut d = 0;
111    for pk_byte in public_key.iter() {
112        d |= *pk_byte;
113    }
114    if d == 0 {
115        return false;
116    }
117
118    let mut hasher = Sha512::new();
119    hasher.input(&signature[0..32]);
120    hasher.input(public_key);
121    hasher.input(message);
122    let mut hash: [u8; 64] = [0; 64];
123    hasher.result(&mut hash);
124    sc_reduce(&mut hash);
125
126    let r = GeP2::double_scalarmult_vartime(hash.as_ref(), a, &signature[32..64]);
127    let rcheck = r.to_bytes();
128
129    fixed_time_eq(rcheck.as_ref(), &signature[0..32])
130}
131
132pub fn exchange(public_key: &[u8], private_key: &[u8]) -> [u8; 32] {
133    let ed_y = Fe::from_bytes(&public_key);
134    // Produce public key in Montgomery form.
135    let mont_x = edwards_to_montgomery_x(ed_y);
136
137    // Produce private key from seed component (bytes 0 to 32)
138    // of the Ed25519 extended private key (64 bytes).
139    let mut hasher = Sha512::new();
140    hasher.input(&private_key[0..32]);
141    let mut hash: [u8; 64] = [0; 64];
142    hasher.result(&mut hash);
143    // Clamp the hash such that it is a valid private key
144    hash[0] &= 248;
145    hash[31] &= 127;
146    hash[31] |= 64;
147
148    let shared_mont_x : [u8; 32] = curve25519(&hash, &mont_x.to_bytes()); // priv., pub.
149
150    shared_mont_x
151}
152
153fn edwards_to_montgomery_x(ed_y: Fe) -> Fe {
154    let ed_z = Fe([1,0,0,0,0,0,0,0,0,0]);
155    let temp_x = ed_z.add(ed_y);
156    let temp_z = ed_z.sub(ed_y);
157    let temp_z_inv = temp_z.invert();
158
159    let mont_x = temp_x.mul(temp_z_inv);
160
161    mont_x
162}
163
164#[cfg(test)]
165mod tests {
166    use ed25519::{keypair, signature, verify, exchange};
167    use curve25519::{curve25519_base, curve25519};
168    use digest::Digest;
169    use sha2::{Sha512};
170
171    fn do_keypair_case(seed: [u8; 32], expected_secret: [u8; 64], expected_public: [u8; 32]) {
172        let (actual_secret, actual_public) = keypair(seed.as_ref());
173        assert_eq!(actual_secret.to_vec(), expected_secret.to_vec());
174        assert_eq!(actual_public.to_vec(), expected_public.to_vec());
175    }
176
177    #[test]
178    fn keypair_cases() {
179        do_keypair_case(
180            [0x26, 0x27, 0xf6, 0x85, 0x97, 0x15, 0xad, 0x1d, 0xd2, 0x94, 0xdd, 0xc4, 0x76, 0x19, 0x39, 0x31,
181             0xf1, 0xad, 0xb5, 0x58, 0xf0, 0x93, 0x97, 0x32, 0x19, 0x2b, 0xd1, 0xc0, 0xfd, 0x16, 0x8e, 0x4e],
182            [0x26, 0x27, 0xf6, 0x85, 0x97, 0x15, 0xad, 0x1d, 0xd2, 0x94, 0xdd, 0xc4, 0x76, 0x19, 0x39, 0x31,
183             0xf1, 0xad, 0xb5, 0x58, 0xf0, 0x93, 0x97, 0x32, 0x19, 0x2b, 0xd1, 0xc0, 0xfd, 0x16, 0x8e, 0x4e,
184             0x5d, 0x6d, 0x23, 0x6b, 0x52, 0xd1, 0x8e, 0x3a, 0xb6, 0xd6, 0x07, 0x2f, 0xb6, 0xe4, 0xc7, 0xd4,
185             0x6b, 0xd5, 0x9a, 0xd9, 0xcc, 0x19, 0x47, 0x26, 0x5f, 0x00, 0xb7, 0x20, 0xfa, 0x2c, 0x8f, 0x66],
186            [0x5d, 0x6d, 0x23, 0x6b, 0x52, 0xd1, 0x8e, 0x3a, 0xb6, 0xd6, 0x07, 0x2f, 0xb6, 0xe4, 0xc7, 0xd4,
187             0x6b, 0xd5, 0x9a, 0xd9, 0xcc, 0x19, 0x47, 0x26, 0x5f, 0x00, 0xb7, 0x20, 0xfa, 0x2c, 0x8f, 0x66]);
188        do_keypair_case(
189            [0x29, 0x23, 0xbe, 0x84, 0xe1, 0x6c, 0xd6, 0xae, 0x52, 0x90, 0x49, 0xf1, 0xf1, 0xbb, 0xe9, 0xeb,
190             0xb3, 0xa6, 0xdb, 0x3c, 0x87, 0x0c, 0x3e, 0x99, 0x24, 0x5e, 0x0d, 0x1c, 0x06, 0xb7, 0x47, 0xde],
191            [0x29, 0x23, 0xbe, 0x84, 0xe1, 0x6c, 0xd6, 0xae, 0x52, 0x90, 0x49, 0xf1, 0xf1, 0xbb, 0xe9, 0xeb,
192             0xb3, 0xa6, 0xdb, 0x3c, 0x87, 0x0c, 0x3e, 0x99, 0x24, 0x5e, 0x0d, 0x1c, 0x06, 0xb7, 0x47, 0xde,
193             0x5d, 0x83, 0x31, 0x26, 0x56, 0x0c, 0xb1, 0x9a, 0x14, 0x19, 0x37, 0x27, 0x78, 0x96, 0xf0, 0xfd,
194             0x43, 0x7b, 0xa6, 0x80, 0x1e, 0xb2, 0x10, 0xac, 0x4c, 0x39, 0xd9, 0x00, 0x72, 0xd7, 0x0d, 0xa8],
195            [0x5d, 0x83, 0x31, 0x26, 0x56, 0x0c, 0xb1, 0x9a, 0x14, 0x19, 0x37, 0x27, 0x78, 0x96, 0xf0, 0xfd,
196             0x43, 0x7b, 0xa6, 0x80, 0x1e, 0xb2, 0x10, 0xac, 0x4c, 0x39, 0xd9, 0x00, 0x72, 0xd7, 0x0d, 0xa8]);
197    }
198
199    #[test]
200    fn keypair_matches_mont() {
201        let seed = [0x26, 0x27, 0xf6, 0x85, 0x97, 0x15, 0xad, 0x1d, 0xd2, 0x94, 0xdd, 0xc4, 0x76, 0x19, 0x39, 0x31,
202                    0xf1, 0xad, 0xb5, 0x58, 0xf0, 0x93, 0x97, 0x32, 0x19, 0x2b, 0xd1, 0xc0, 0xfd, 0x16, 0x8e, 0x4e];
203        let (ed_private, ed_public) = keypair(seed.as_ref());
204
205        let mut hasher = Sha512::new();
206        hasher.input(&ed_private[0..32]);
207        let mut hash: [u8; 64] = [0; 64];
208        hasher.result(&mut hash);
209        hash[0] &= 248;
210        hash[31] &= 127;
211        hash[31] |= 64;
212
213        let cv_public = curve25519_base(&hash);
214
215        let edx_ss = exchange(&ed_public, &ed_private);
216        let cv_ss = curve25519(&hash, &cv_public);
217
218        assert_eq!(edx_ss.to_vec(), cv_ss.to_vec());
219    }
220
221    fn do_sign_verify_case(seed: [u8; 32], message: &[u8], expected_signature: [u8; 64]) {
222        let (secret_key, public_key) = keypair(seed.as_ref());
223        let mut actual_signature = signature(message, secret_key.as_ref());
224        assert_eq!(expected_signature.to_vec(), actual_signature.to_vec());
225        assert!(verify(message, public_key.as_ref(), actual_signature.as_ref()));
226
227        for &(index, flip) in [(0, 1), (31, 0x80), (20, 0xff)].iter() {
228            actual_signature[index] ^= flip;
229            assert!(!verify(message, public_key.as_ref(), actual_signature.as_ref()));
230            actual_signature[index] ^= flip;
231        }
232
233        let mut public_key_corrupt = public_key;
234        public_key_corrupt[0] ^= 1;
235        assert!(!verify(message, public_key_corrupt.as_ref(), actual_signature.as_ref()));
236    }
237
238    #[test]
239    fn sign_verify_cases() {
240        do_sign_verify_case(
241            [0x2d, 0x20, 0x86, 0x83, 0x2c, 0xc2, 0xfe, 0x3f, 0xd1, 0x8c, 0xb5, 0x1d, 0x6c, 0x5e, 0x99, 0xa5,
242             0x75, 0x9f, 0x02, 0x21, 0x1f, 0x85, 0xe5, 0xff, 0x2f, 0x90, 0x4a, 0x78, 0x0f, 0x58, 0x00, 0x6f],
243            [0x89, 0x8f, 0x9c, 0x4b, 0x2c, 0x6e, 0xe9, 0xe2, 0x28, 0x76, 0x1c, 0xa5, 0x08, 0x97, 0xb7, 0x1f,
244             0xfe, 0xca, 0x1c, 0x35, 0x28, 0x46, 0xf5, 0xfe, 0x13, 0xf7, 0xd3, 0xd5, 0x7e, 0x2c, 0x15, 0xac,
245             0x60, 0x90, 0x0c, 0xa3, 0x2c, 0x5b, 0x5d, 0xd9, 0x53, 0xc9, 0xa6, 0x81, 0x0a, 0xcc, 0x64, 0x39,
246             0x4f, 0xfd, 0x14, 0x98, 0x26, 0xd9, 0x98, 0x06, 0x29, 0x2a, 0xdd, 0xd1, 0x3f, 0xc3, 0xbb, 0x7d,
247             0xac, 0x70, 0x1c, 0x5b, 0x4a, 0x2d, 0x61, 0x5d, 0x15, 0x96, 0x01, 0x28, 0xed, 0x9f, 0x73, 0x6b,
248             0x98, 0x85, 0x4f, 0x6f, 0x07, 0x05, 0xb0, 0xf0, 0xda, 0xcb, 0xdc, 0x2c, 0x26, 0x2d, 0x27, 0x39,
249             0x75, 0x19, 0x14, 0x9b, 0x0e, 0x4c, 0xbe, 0x16, 0x77, 0xc5, 0x76, 0xc1, 0x39, 0x7a, 0xae, 0x5c,
250             0xe3, 0x49, 0x16, 0xe3, 0x51, 0x31, 0x04, 0x63, 0x2e, 0xc2, 0x19, 0x0d, 0xb8, 0xd2, 0x22, 0x89,
251             0xc3, 0x72, 0x3c, 0x8d, 0x01, 0x21, 0x3c, 0xad, 0x80, 0x3f, 0x4d, 0x75, 0x74, 0xc4, 0xdb, 0xb5,
252             0x37, 0x31, 0xb0, 0x1c, 0x8e, 0xc7, 0x5d, 0x08, 0x2e, 0xf7, 0xdc, 0x9d, 0x7f, 0x1b, 0x73, 0x15,
253             0x9f, 0x63, 0xdb, 0x56, 0xaa, 0x12, 0xa2, 0xca, 0x39, 0xea, 0xce, 0x6b, 0x28, 0xe4, 0xc3, 0x1d,
254             0x9d, 0x25, 0x67, 0x41, 0x45, 0x2e, 0x83, 0x87, 0xe1, 0x53, 0x6d, 0x03, 0x02, 0x6e, 0xe4, 0x84,
255             0x10, 0xd4, 0x3b, 0x21, 0x91, 0x88, 0xba, 0x14, 0xa8, 0xaf].as_ref(),
256            [0x91, 0x20, 0x91, 0x66, 0x1e, 0xed, 0x18, 0xa4, 0x03, 0x4b, 0xc7, 0xdb, 0x4b, 0xd6, 0x0f, 0xe2,
257             0xde, 0xeb, 0xf3, 0xff, 0x3b, 0x6b, 0x99, 0x8d, 0xae, 0x20, 0x94, 0xb6, 0x09, 0x86, 0x5c, 0x20,
258             0x19, 0xec, 0x67, 0x22, 0xbf, 0xdc, 0x87, 0xbd, 0xa5, 0x40, 0x91, 0x92, 0x2e, 0x11, 0xe3, 0x93,
259             0xf5, 0xfd, 0xce, 0xea, 0x3e, 0x09, 0x1f, 0x2e, 0xe6, 0xbc, 0x62, 0xdf, 0x94, 0x8e, 0x99, 0x09]
260        );
261        do_sign_verify_case(
262            [0x33, 0x19, 0x17, 0x82, 0xc1, 0x70, 0x4f, 0x60, 0xd0, 0x84, 0x8d, 0x75, 0x62, 0xa2, 0xfa, 0x19,
263             0xf9, 0x92, 0x4f, 0xea, 0x4e, 0x77, 0x33, 0xcd, 0x45, 0xf6, 0xc3, 0x2f, 0x21, 0x9a, 0x72, 0x91],
264            [0x77, 0x13, 0x43, 0x5a, 0x0e, 0x34, 0x6f, 0x67, 0x71, 0xae, 0x5a, 0xde, 0xa8, 0x7a, 0xe7, 0xa4,
265             0x52, 0xc6, 0x5d, 0x74, 0x8f, 0x48, 0x69, 0xd3, 0x1e, 0xd3, 0x67, 0x47, 0xc3, 0x28, 0xdd, 0xc4,
266             0xec, 0x0e, 0x48, 0x67, 0x93, 0xa5, 0x1c, 0x67, 0x66, 0xf7, 0x06, 0x48, 0x26, 0xd0, 0x74, 0x51,
267             0x4d, 0xd0, 0x57, 0x41, 0xf3, 0xbe, 0x27, 0x3e, 0xf2, 0x1f, 0x28, 0x0e, 0x49, 0x07, 0xed, 0x89,
268             0xbe, 0x30, 0x1a, 0x4e, 0xc8, 0x49, 0x6e, 0xb6, 0xab, 0x90, 0x00, 0x06, 0xe5, 0xa3, 0xc8, 0xe9,
269             0xc9, 0x93, 0x62, 0x1d, 0x6a, 0x3b, 0x0f, 0x6c, 0xba, 0xd0, 0xfd, 0xde, 0xf3, 0xb9, 0xc8, 0x2d].as_ref(),
270            [0x4b, 0x8d, 0x9b, 0x1e, 0xca, 0x54, 0x00, 0xea, 0xc6, 0xf5, 0xcc, 0x0c, 0x94, 0x39, 0x63, 0x00,
271             0x52, 0xf7, 0x34, 0xce, 0x45, 0x3e, 0x94, 0x26, 0xf3, 0x19, 0xdd, 0x96, 0x03, 0xb6, 0xae, 0xae,
272             0xb9, 0xd2, 0x3a, 0x5f, 0x93, 0xf0, 0x6a, 0x46, 0x00, 0x18, 0xf0, 0x69, 0xdf, 0x19, 0x44, 0x48,
273             0xf5, 0x60, 0x51, 0xab, 0x9e, 0x6b, 0xfa, 0xeb, 0x64, 0x10, 0x16, 0xf7, 0xa9, 0x0b, 0xe2, 0x0c]
274        );
275
276    }
277}