1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
// Copyright(c) 2018 3NSoft Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::ge25519::*;
use super::sc25519::*;
use crate::hash::sha512::{ hash_sha512, Sha512 };
use crate::util::{ make_conf_error, make_signature_verification_error, Error,
	Resetable, verify::compare_v32 };

pub struct Keypair {
	
	/// Secret key of this pair.
	pub skey: [u8; SECRET_KEY_LENGTH],
	
	/// Public key of this pair.
	pub pkey: [u8; PUBLIC_KEY_LENGTH],

}

/// Signing algorithm name for JWK's (JSON Web Key) 
pub const JWK_ALG_NAME: &str = "NaCl-sign-Ed25519";

/// Seed length, from which keypair is created
pub const SEED_LENGTH: usize = 32;

/// Public key length for signing
pub const PUBLIC_KEY_LENGTH: usize = 32;

/// Secret key length for signing
pub const SECRET_KEY_LENGTH: usize = 64;

fn make_keypair() -> Keypair {
	Keypair {
		skey: [0; SECRET_KEY_LENGTH],
		pkey: [0; PUBLIC_KEY_LENGTH],
	}
}

/// Analog of crypto_sign_keypair in crypto_sign/ed25519/ref/keypair.c
pub fn generate_keypair(seed: &[u8]) -> Keypair {
	let mut az: [u8; 64] = [0; 64];
	let mut scsk = make_sc25519();
	let mut gepk = make_ge25519();

	hash_sha512(&mut az, &seed);
	az[0] &= 248;
	az[31] &= 127;
	az[31] |= 64;

	sc25519_from32bytes(&mut scsk, &az[0..32]);

	ge25519_scalarmult_base(&mut gepk, &scsk);

	let mut pair = make_keypair();
	ge25519_pack(&mut pair.pkey, &gepk);
	pair.skey[0..32].copy_from_slice(seed);
	pair.skey[32..].copy_from_slice(&pair.pkey);

	pair
}

/// Extracts public key from a given secret key
pub fn extract_pkey(sk: &[u8]) -> Result<Vec<u8>, Error> {
	if sk.len() != SECRET_KEY_LENGTH { return Err(make_conf_error(format!(
		"Length of given sk array is {} instead of {}",
		sk.len(), SECRET_KEY_LENGTH))); }
	let mut pk: Vec<u8> = vec![0; 32];
	pk[..].copy_from_slice(&sk[32..]);
	Ok(pk)
}

/// Analog of crypto_sign in crypto_sign/ed25519/ref/sign.c
pub fn sign(m: &[u8], sk: &[u8]) -> Result<Vec<u8>, Error> {
	if sk.len() != 64 { return Err(make_conf_error(format!(
		"Secret key array is {} bytes long instead of 64", sk.len()))); }
	if m.len() == 0 { return Err(make_conf_error(format!(
		"Message array m is empty"))); }

	let mut pk: [u8; 32] = [0; 32];
	pk.copy_from_slice(&sk[32..]);
	/* pk: 32-byte public key A */

	let mut az: [u8; 64] = [0; 64];
	hash_sha512(&mut az, &sk[0..32]);
	az[0] &= 248;
	az[31] &= 127;
	az[31] |= 64;
	/* az: 32-byte scalar a, 32-byte randomizer z */

	let mut sm: Vec<u8> = vec![0; m.len()+64];
	sm[64..].copy_from_slice(m);
	sm[32..64].copy_from_slice(&az[32..64]);
	/* sm: 32-byte uninit, 32-byte z, mlen-byte m */

	let mut nonce: [u8; 64] = [0; 64];
	hash_sha512(&mut nonce, &sm[32..]);
	/* nonce: 64-byte H(z,m) */

	let mut sck = make_sc25519();
	let mut ger = make_ge25519();
	sc25519_from64bytes(&mut sck, &nonce);
	ge25519_scalarmult_base(&mut ger, &sck);
	ge25519_pack(&mut sm[0..32], &ger);
	/* sm: 32-byte R, 32-byte z, mlen-byte m */

	sm[32..64].copy_from_slice(&pk);
	/* sm: 32-byte R, 32-byte A, mlen-byte m */

	let mut hram: [u8; 64] = [0; 64];
	hash_sha512(&mut hram, &sm);
	/* hram: 64-byte H(R,A,m) */

	let mut scs = make_sc25519();
	let mut scs_temp = make_sc25519();
	let mut scsk = make_sc25519();
	sc25519_from64bytes(&mut scs, &hram);
	sc25519_from32bytes(&mut scsk, &az[0..32]);
	sc25519_mul(&mut scs_temp, &scs, &scsk);
	sc25519_add(&mut scs, &scs_temp, &sck);
	/* scs: S = nonce + H(R,A,m)a */

	sc25519_to32bytes(&mut sm[32..64], &scs);
	/* sm: 32-byte R, 32-byte S, mlen-byte m */

	az.reset();
	scs_temp.v.reset();
	scsk.v.reset();
	nonce.reset();
	hram.reset();
	sck.v.reset();
	ger.x.v.reset();

	Ok(sm)
}

/// Signs message `m` with key `sk`, returning only signature bytes.
pub fn signature(m: &[u8], sk: &[u8]) -> Result<Vec<u8>, Error> {
	if sk.len() != 64 { return Err(make_conf_error(format!(
		"Secret key array is {} bytes long instead of 64", sk.len()))); }
	if m.len() == 0 { return Err(make_conf_error(format!(
		"Message array m is empty"))); }
	
	let mut pk: [u8; 32] = [0; 32];
	pk.copy_from_slice(&sk[32..]);
	/* pk: 32-byte public key A */

	let mut az: [u8; 64] = [0; 64];
	hash_sha512(&mut az, &sk[0..32]);
	az[0] &= 248;
	az[31] &= 127;
	az[31] |= 64;
	/* az: 32-byte scalar a, 32-byte randomizer z */

	let mut sig: Vec<u8> = vec![0; 64];
	sig[32..64].copy_from_slice(&az[32..]);
	/* sig: 32-byte uninit, 32-byte z */

	let mut hasher = Sha512::new();
	hasher.update(&sig[32..]);
	hasher.update(m);
	let nonce = hasher.digest();
	/* nonce: 64-byte H(z,m) */

	let mut sck = make_sc25519();
	let mut ger = make_ge25519();
	sc25519_from64bytes(&mut sck, &nonce);
	ge25519_scalarmult_base(&mut ger, &sck);
	ge25519_pack(&mut sig[0..32], &ger);
	/* sig: 32-byte R, 32-byte z */

	hasher.update(&sig[0..32]);
	hasher.update(&pk);
	hasher.update(m);
	let hram = hasher.digest();
	/* hram: 64-byte H(R,A,m) */

	let mut scs = make_sc25519();
	let mut scs_temp = make_sc25519();
	let mut scsk = make_sc25519();
	sc25519_from64bytes(&mut scs, &hram);
	sc25519_from32bytes(&mut scsk, &az[0..32]);
	sc25519_mul(&mut scs_temp, &scs, &scsk);
	sc25519_add(&mut scs, &scs_temp, &sck);
	/* scs: S = nonce + H(R,A,m)a */

	sc25519_to32bytes(&mut sig[32..64], &scs);
	/* sig: 32-byte R, 32-byte S */

	Ok(sig)
}

/// Analog of crypto_sign_open in crypto_sign/ed25519/ref/open.c
pub fn open(sm: &[u8], pk: &[u8]) -> Result<Vec<u8>, Error> {
	if pk.len() != 32 { return Err(make_conf_error(format!(
		"Public key array is {} bytes long instead of 32", pk.len()))); }

	let mut get1 = make_ge25519();
	if (sm.len() < 64)
	|| ((sm[63] & 224) != 0)
	|| !ge25519_unpackneg_vartime(&mut get1, pk) {
		return Err(make_signature_verification_error());
	}

	let mut rcopy: [u8; 32] = [0; 32];
	rcopy.copy_from_slice(&sm[0..32]);

	let mut scs = make_sc25519();
	sc25519_from32bytes(&mut scs, &sm[32..64]);

	let mut m: Vec<u8> = sm.to_vec();
	m[32..64].copy_from_slice(pk);
	let mut hram: [u8; 64] = [0; 64];
	hash_sha512(&mut hram, &m);

	let mut schram = make_sc25519();
	sc25519_from64bytes(&mut schram, &hram);

	let mut get2 = make_ge25519();
	ge25519_double_scalarmult_vartime(
		&mut get2, &get1, &schram, &ge25519_base, &scs);
	let mut rcheck: [u8; 32] = [0; 32];
	ge25519_pack(&mut rcheck, &get2);

	if compare_v32(&rcopy, &rcheck) {
		Ok(m[64..].to_vec())
	} else {
		Err(make_signature_verification_error())
	}
}

/// Verifies that signature `sig` was created on message `m` with key with
/// given public part `pk`.
pub fn verify(sig: &[u8], m: &[u8], pk: &[u8]) -> Result<bool, Error> {
	if pk.len() != 32 { return Err(make_conf_error(format!(
		"Public key array is {} bytes long instead of 32", pk.len()))); }

	let mut get1 = make_ge25519();
	if (sig.len() < 64)
	|| ((sig[63] & 224) != 0)
	|| !ge25519_unpackneg_vartime(&mut get1, pk) {
		return Ok(false);
	}

	let mut rcopy: [u8; 32] = [0; 32];
	rcopy.copy_from_slice(&sig[0..32]);

	let mut scs = make_sc25519();
	sc25519_from32bytes(&mut scs, &sig[32..64]);

	let mut hasher = Sha512::new();
	hasher.update(&sig[0..32]);
	hasher.update(pk);
	hasher.update(m);
	let hram = hasher.digest();

	let mut schram = make_sc25519();
	sc25519_from64bytes(&mut schram, &hram);

	let mut get2 = make_ge25519();
	ge25519_double_scalarmult_vartime(
		&mut get2, &get1, &schram, &ge25519_base, &scs);
	let mut rcheck: [u8; 32] = [0; 32];
	ge25519_pack(&mut rcheck, &get2);

	Ok(compare_v32(&rcopy, &rcheck))
}


#[cfg(test)]
mod tests {

	use super::{ generate_keypair, sign, open, signature, verify, SEED_LENGTH, PUBLIC_KEY_LENGTH };
	use crate::util::verify::compare;
	use crate::util::ops::incr;

	#[test]
	fn test1() {

		let key_seed: [u8; SEED_LENGTH] = [
			0xae, 0x38, 0x86, 0x7b, 0xd2, 0x65, 0xcb, 0x86, 0x57, 0x0e,
			0x90, 0x0e, 0x24, 0xa1, 0x75, 0x03, 0x2f, 0x74, 0xab, 0x4d,
			0xa1, 0xbd, 0xf5, 0xc9, 0x12, 0x3e, 0x4c, 0x98, 0x12, 0xaa,
			0x0c, 0x95 ];

		let expected_pkey: [u8; 32] = [
			0xd0, 0xa5, 0xe8, 0xca, 0xeb, 0xff, 0xb8, 0x2a, 0x5e, 0x6d,
			0x24, 0x4a, 0x94, 0x94, 0x3c, 0xd5, 0x34, 0x03, 0x68, 0x0d,
			0x93, 0x02, 0x82, 0xb2, 0xc0, 0x7b, 0x1f, 0xfd, 0xbd, 0x21,
			0x39, 0xd0 ];

		// Testing signing keys generation
		let pair = generate_keypair(&key_seed);
		assert!(compare(&pair.pkey, &expected_pkey));

		// Testing of message signing");
		let m = "testing\n".as_bytes();

		let expected_signed_m = [
			0x74, 0xff, 0xb4, 0x4b, 0xf0, 0x46, 0xf9, 0xe9, 0x86, 0x87,
			0xa4, 0x6b, 0x28, 0xc3, 0x38, 0x6e, 0x78, 0xb0, 0x62, 0x53,
			0x2f, 0xf6, 0x45, 0x39, 0x97, 0x24, 0x0b, 0xa0, 0xab, 0xee,
			0x5d, 0x7e, 0x44, 0xc8, 0x80, 0x2f, 0x86, 0xf5, 0x34, 0x21,
			0x32, 0x7f, 0xb4, 0x3f, 0xa6, 0xd8, 0x9c, 0x0a, 0xdf, 0x5b,
			0x91, 0x04, 0x9a, 0x67, 0xba, 0x3b, 0xf0, 0xdd, 0x7c, 0xd1,
			0x5d, 0xbd, 0x89, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,
			0x67, 0x0a ];

		let signed_m = sign(&m, &pair.skey).unwrap();
		assert!(compare(&signed_m, &expected_signed_m));

		let result = open(&signed_m, &pair.pkey).unwrap();
		assert!(compare(&result, &m));
		
		// Testing of separated-signature functionality
		let sig = signature(&m, &pair.skey).unwrap();
		assert!(compare(&sig, &expected_signed_m[0..64]));
		assert!(verify(&sig, &m, &pair.pkey).unwrap());
	}

	#[test]
	fn test2() {

		struct SeedAndPKey {
			seed: [u8; SEED_LENGTH],
			pkey: [u8; PUBLIC_KEY_LENGTH]
		}
		
		let seed_and_pkeys = [
			SeedAndPKey {
				seed: [ 0x13, 0xca, 0x75, 0xbe, 0x97, 0x13, 0x61, 0x62, 0xb4, 0x36,
					0x95, 0xfa, 0xd2, 0xa2, 0xb2, 0xcb, 0xb4, 0x35, 0xc9, 0xad,
					0x0a, 0x0f, 0xf5, 0xb6, 0x58, 0x7e, 0xd9, 0xd0, 0xcf, 0xfb,
					0x59, 0xec ],
				pkey: [ 0xed, 0xef, 0xc9, 0x54, 0x05, 0xce, 0x9f, 0x81, 0x7d, 0x2b,
					0xd8, 0xb9, 0x48, 0x0c, 0x3f, 0xfb, 0xa8, 0xd9, 0x6a, 0x6e,
					0x00, 0x87, 0x90, 0x6a, 0xe2, 0xe9, 0xa9, 0x2f, 0xf5, 0xa9,
					0xdc, 0xe7 ] },
			SeedAndPKey {
				seed: [ 0xee, 0xdd, 0xec, 0xfa, 0x96, 0x70, 0x23, 0x6b, 0xdd, 0x4b,
						0xba, 0x59, 0xae, 0x69, 0x65, 0x7a, 0x83, 0xb9, 0x74, 0x9a,
						0xd7, 0xd7, 0x68, 0x21, 0xe8, 0x64, 0x1a, 0x4b, 0xe3, 0x1a,
						0x5b, 0x74 ],
				pkey: [ 0x20, 0x95, 0x60, 0x39, 0xa6, 0x6f, 0x66, 0x63, 0xe0, 0x08,
						0xa3, 0xac, 0xd2, 0x96, 0x76, 0x5e, 0xea, 0x21, 0xe5, 0x6c,
						0x3d, 0x2f, 0xea, 0xb7, 0xc7, 0x4d, 0x0c, 0x9d, 0x2f, 0x6e,
						0xc5, 0xe4 ] },
			SeedAndPKey {
				seed: [ 0x9a, 0xae, 0xe7, 0xc6, 0xf9, 0xd7, 0xe4, 0x9c, 0x64, 0x05,
						0xa9, 0x81, 0xa6, 0xe3, 0xa6, 0x52, 0x5b, 0x62, 0x5f, 0xa1,
						0xae, 0x92, 0x5c, 0xec, 0x12, 0x2f, 0x2d, 0xe3, 0x3d, 0x4d,
						0x30, 0x3c ],
				pkey: [ 0xe3, 0x43, 0x33, 0xb1, 0x42, 0xc5, 0xc5, 0x86, 0x14, 0x86,
						0x46, 0x37, 0x0d, 0xfc, 0xf7, 0x21, 0x48, 0x50, 0x24, 0x6d,
						0x69, 0x7f, 0x6d, 0x32, 0x60, 0x47, 0xdf, 0xa7, 0x85, 0xd6,
						0xee, 0xd5 ] } ];

		let m = "<From https://doc.rust-lang.org/book/second-edition/ch04-03-slices.html>
We’ll discuss iterators in more detail in Chapter 13. For now, know that iter is a method that returns each element in a collection and that enumerate wraps the result of iter and returns each element as part of a tuple instead. The first element of the tuple returned from enumerate is the index, and the second element is a reference to the element. This is a bit more convenient than calculating the index ourselves.

Because the enumerate method returns a tuple, we can use patterns to destructure that tuple, just like everywhere else in Rust. So in the for loop, we specify a pattern that has i for the index in the tuple and &item for the single byte in the tuple. Because we get a reference to the element from .iter().enumerate(), we use & in the pattern.

Inside the for loop, we search for the byte that represents the space by using the byte literal syntax. If we find a space, we return the position. Otherwise, we return the length of the string by using s.len():

    if item == b' ' {
        return i;
    }
}
s.len()

We now have a way to find out the index of the end of the first word in the string, but there’s a problem. We’re returning a usize on its own, but it’s only a meaningful number in the context of the &String. In other words, because it’s a separate value from the String, there’s no guarantee that it will still be valid in the future. Consider the program in Listing 4-8 that uses the first_word function from Listing 4-7:
...".as_bytes();

		for sp in seed_and_pkeys.iter() {
			let pair = generate_keypair(&sp.seed);
			assert!(compare(&pair.pkey, &sp.pkey));
			let signed_m = sign(&m, &pair.skey).unwrap();
			let mut sig = signature(&m, &pair.skey).unwrap();
			assert!(compare(&sig, &signed_m[0..64]));
			let result = open(&signed_m, &pair.pkey).unwrap();
			assert!(compare(&result, &m));
			assert!(verify(&sig, &m, &pair.pkey).unwrap());
			incr!(sig[5], 1 as u8);
			assert!(!verify(&sig, &m, &pair.pkey).unwrap());
		}
		
	}

}