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 let mont_x = edwards_to_montgomery_x(ed_y);
136
137 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 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()); 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}