nacl/boxes/
scalarmult.rs

1// Copyright(c) 2018, 2021 3NSoft Inc.
2//
3// This program is free software: you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11// GNU Lesser General Public License for more details.
12//
13// You should have received a copy of the GNU Lesser General Public License
14// along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16//! This module provides curve25519 math functions, analogous to thus from
17//! crypto_scalarmult/curve25519/ref/smult.c and
18//! crypto_scalarmult/curve25519/ref/base.c
19
20use crate::util::ops::{ subw, incr };
21
22fn add(out: &mut [u32], a: &[u32], b: &[u32]) {
23	let mut u: u32 = 0;
24	for j in 0..31 { u += a[j] + b[j]; out[j] = u & 255; u >>= 8; }
25	u += a[31] + b[31]; out[31] = u;
26}
27
28fn sub(out: &mut [u32], a: &[u32], b: &[u32]) {
29	let mut u: u32 = 218;
30	for j in 0..31 {
31		u += a[j] + 65280 - b[j];
32		out[j] = u & 255;
33		u >>= 8;
34	}
35	incr!( u, subw!( a[31], b[31] ));
36	out[31] = u;
37}
38
39fn squeeze(a: &mut [u32]) {
40	let mut u: u32 = 0;
41	for j in 0..31 { u += a[j]; a[j] = u & 255; u >>= 8; }
42	u += a[31]; a[31] = u & 127;
43	u = 19 * (u >> 7);
44	for j in 0..31 { u += a[j]; a[j] = u & 255; u >>= 8; }
45	u += a[31]; a[31] = u;
46}
47
48static MINUSP: [u32; 32] = [
49	19, 0, 0, 0, 0, 0, 0, 0,
50	 0, 0, 0, 0, 0, 0, 0, 0,
51	 0, 0, 0, 0, 0, 0, 0, 0,
52	 0, 0, 0, 0, 0, 0, 0, 128 ];
53
54fn freeze(a: &mut [u32]) {
55	let mut aorig: [u32; 32] = [0; 32];
56	for j in 0..32 { aorig[j] = a[j]; }
57	add(a, &aorig, &MINUSP);
58	let negative = -(((a[31] >> 7) & 1) as i32) as u32;
59	for j in 0..32 { a[j] ^= negative & (aorig[j] ^ a[j]); }
60}
61
62fn mult(out: &mut [u32], a: &[u32], b: &[u32]) {
63	for i in 0..32 {
64		let mut u: u32 = 0;
65		for j in 0..i+1 { u += a[j] * b[i - j]; }
66		for j in i+1..32 { u += 38 * a[j] * b[i + 32 - j] };
67		out[i] = u;
68	}
69	squeeze(out);
70}
71
72fn mult121665(out: &mut [u32], a: &[u32]) {
73	let mut u:u32 = 0;
74	for j in 0..31 { u += 121665 * a[j]; out[j] = u & 255; u >>= 8; }
75	u += 121665 * a[31]; out[31] = u & 127;
76	u = 19 * (u >> 7);
77	for j in 0..31 { u += out[j]; out[j] = u & 255; u >>= 8; }
78	u += out[31]; out[31] = u;
79}
80
81fn square(out: &mut [u32], a: &[u32]) {
82	for i in 0..32 {
83		let mut u: u32 = 0;
84		let mut j: usize = 0;
85		while j < (i - j) { u += a[j] * a[i - j]; j += 1; }
86		j = i + 1;
87		while j < (i + 32 - j) { u += 38 * a[j] * a[i + 32 - j]; j += 1; }
88		u *= 2;
89		if (i & 1) == 0 {
90			u += a[i / 2] * a[i / 2];
91			u += 38 * a[i / 2 + 16] * a[i / 2 + 16];
92		}
93		out[i] = u;
94	}
95	squeeze(out);
96}
97
98fn select(p: &mut [u32], q: &mut [u32], r: &[u32], s: &[u32], b: u32) {
99	let bminus1 = subw!( b, 1 as u32 );
100	for j in 0..64 {
101		let t = bminus1 & (r[j] ^ s[j]);
102		p[j] = s[j] ^ t;
103		q[j] = r[j] ^ t;
104	}
105}
106
107fn mainloop(work1: &mut [u32], work2: &mut [u32], e: &[u32]) {
108	let mut xzm1: [u32; 64] = [0; 64];
109	let mut xzm: [u32; 64] = [0; 64];
110	let mut xzmb: [u32; 64] = [0; 64];
111	let mut xzm1b: [u32; 64] = [0; 64];
112	let mut xznb: [u32; 64] = [0; 64];
113	let mut xzn1b: [u32; 64] = [0; 64];
114	let mut a0: [u32; 64] = [0; 64];
115	let mut a1: [u32; 64] = [0; 64];
116	let mut b0: [u32; 64] = [0; 64];
117	let mut b1: [u32; 64] = [0; 64];
118	let mut c1: [u32; 64] = [0; 64];
119	let mut r: [u32; 32] = [0; 32];
120	let mut s: [u32; 32] = [0; 32];
121	let mut t: [u32; 32] = [0; 32];
122	let mut u: [u32; 32] = [0; 32];
123
124	xzm1[0..32].copy_from_slice(work1);
125	xzm1[32] = 1;
126
127	xzm[0] = 1;
128	for j in 1..64 { xzm[j] = 0; }
129
130	let mut pos: usize = 254;
131	loop {
132		let mut b = e[pos / 8] >> (pos & 7);
133		b &= 1;
134		select(&mut xzmb, &mut xzm1b, &xzm, &xzm1, b);
135		add(&mut a0[0..32], &xzmb[0..32], &xzmb[32..]);
136		sub(&mut a0[32..], &xzmb[0..32], &xzmb[32..]);
137		add(&mut a1[0..32], &xzm1b[0..32], &xzm1b[32..]);
138		sub(&mut a1[32..], &xzm1b[0..32], &xzm1b[32..]);
139		square(&mut b0[0..32], &a0[0..32]);
140		square(&mut b0[32..], &a0[32..]);
141		mult(&mut b1[0..32], &a1[0..32], &a0[32..]);
142		mult(&mut b1[32..], &a1[32..], &a0[0..32]);
143		add(&mut c1[0..32], &b1[0..32], &b1[32..]);
144		sub(&mut c1[32..], &b1[0..32], &b1[32..]);
145		square(&mut r[0..32], &c1[32..]);
146		sub(&mut s[0..32], &b0[0..32], &b0[32..]);
147		mult121665(&mut t[0..32], &s[0..32]);
148		add(&mut u[0..32], &t[0..32], &b0[0..32]);
149		mult(&mut xznb[0..32], &b0[0..32], &b0[32..]);
150		mult(&mut xznb[32..], &s[0..32], &u[0..32]);
151		square(&mut xzn1b[0..32], &c1[0..32]);
152		mult(&mut xzn1b[32..], &r[0..32], &work1);
153		select(&mut xzm, &mut xzm1, &xznb, &xzn1b, b);
154		if pos == 0 { break; }
155		pos -= 1;
156	}
157
158	work1.copy_from_slice(&xzm[0..32]);
159	work2.copy_from_slice(&xzm[32..64]);
160}
161
162fn recip(out: &mut [u32], z: &[u32]) {
163	let mut z2: [u32; 32] = [0; 32];
164	let mut z9: [u32; 32] = [0; 32];
165	let mut z11: [u32; 32] = [0; 32];
166	let mut z2_5_0: [u32; 32] = [0; 32];
167	let mut z2_10_0: [u32; 32] = [0; 32];
168	let mut z2_20_0: [u32; 32] = [0; 32];
169	let mut z2_50_0: [u32; 32] = [0; 32];
170	let mut z2_100_0: [u32; 32] = [0; 32];
171	let mut t0: [u32; 32] = [0; 32];
172	let mut t1: [u32; 32] = [0; 32];
173
174	/* 2 */ square(&mut z2, &z);
175	/* 4 */ square(&mut t1, &z2);
176	/* 8 */ square(&mut t0, &t1);
177	/* 9 */ mult(&mut z9, &t0, &z);
178	/* 11 */ mult(&mut z11, &z9, &z2);
179	/* 22 */ square(&mut t0, &z11);
180	/* 2^5 - 2^0 = 31 */ mult(&mut z2_5_0, &t0, &z9);
181
182	/* 2^6 - 2^1 */ square(&mut t0, &z2_5_0);
183	/* 2^7 - 2^2 */ square(&mut t1, &t0);
184	/* 2^8 - 2^3 */ square(&mut t0, &t1);
185	/* 2^9 - 2^4 */ square(&mut t1, &t0);
186	/* 2^10 - 2^5 */ square(&mut t0, &t1);
187	/* 2^10 - 2^0 */ mult(&mut z2_10_0, &t0, &z2_5_0);
188
189	/* 2^11 - 2^1 */ square(&mut t0, &z2_10_0);
190	/* 2^12 - 2^2 */ square(&mut t1, &t0);
191	/* 2^20 - 2^10 */ for _ in 1..5 { square(&mut t0, &t1); square(&mut t1, &t0); }
192	/* 2^20 - 2^0 */ mult(&mut z2_20_0, &t1, &z2_10_0);
193
194	/* 2^21 - 2^1 */ square(&mut t0, &z2_20_0);
195	/* 2^22 - 2^2 */ square(&mut t1, &t0);
196	/* 2^40 - 2^20 */ for _ in 1..10 { square(&mut t0, &t1); square(&mut t1, &t0); }
197	/* 2^40 - 2^0 */ mult(&mut t0, &t1, &z2_20_0);
198
199	/* 2^41 - 2^1 */ square(&mut t1, &t0);
200	/* 2^42 - 2^2 */ square(&mut t0, &t1);
201	/* 2^50 - 2^10 */ for _ in 1..5 { square(&mut t1, &t0); square(&mut t0, &t1); }
202	/* 2^50 - 2^0 */ mult(&mut z2_50_0, &t0, &z2_10_0);
203
204	/* 2^51 - 2^1 */ square(&mut t0, &z2_50_0);
205	/* 2^52 - 2^2 */ square(&mut t1, &t0);
206	/* 2^100 - 2^50 */ for _ in 1..25 { square(&mut t0, &t1); square(&mut t1, &t0); }
207	/* 2^100 - 2^0 */ mult(&mut z2_100_0, &t1, &z2_50_0);
208
209	/* 2^101 - 2^1 */ square(&mut t1, &z2_100_0);
210	/* 2^102 - 2^2 */ square(&mut t0, &t1);
211	/* 2^200 - 2^100 */ for _ in 1..50 { square(&mut t1, &t0); square(&mut t0, &t1); }
212	/* 2^200 - 2^0 */ mult(&mut t1, &t0, &z2_100_0);
213
214	/* 2^201 - 2^1 */ square(&mut t0, &t1);
215	/* 2^202 - 2^2 */ square(&mut t1, &t0);
216	/* 2^250 - 2^50 */ for _ in 1..25 { square(&mut t0, &t1); square(&mut t1, &t0); }
217	/* 2^250 - 2^0 */ mult(&mut t0, &t1, &z2_50_0);
218
219	/* 2^251 - 2^1 */ square(&mut t1, &t0);
220	/* 2^252 - 2^2 */ square(&mut t0, &t1);
221	/* 2^253 - 2^3 */ square(&mut t1, &t0);
222	/* 2^254 - 2^4 */ square(&mut t0, &t1);
223	/* 2^255 - 2^5 */ square(&mut t1, &t0);
224	/* 2^255 - 21 */ mult(out, &t1, &z11);
225}
226
227pub fn curve25519(q: &mut [u8], n: &[u8], p: &[u8]) {
228	let mut work1: [u32; 32]= [0; 32];
229	let mut work2: [u32; 32]= [0; 32];
230	let mut work3: [u32; 32]= [0; 32];
231	let mut e: [u32; 32]= [0; 32];
232	for i in 0..32 { e[i] = n[i] as u32; }
233	e[0] &= 248;
234	e[31] &= 127;
235	e[31] |= 64;
236	for i in 0..32 { work1[i] = p[i] as u32; }
237	mainloop(&mut work1, &mut work2, &e);
238	let mut t_work2: [u32; 32]= [0; 32];
239	t_work2.copy_from_slice(&work2);
240	recip(&mut work2, &t_work2);
241	mult(&mut work3, &work1, &work2);
242	freeze(&mut work3);
243	for i in 0..32 { q[i] = work3[i] as u8; }
244}
245
246const BASE: [u8; 32] = [
247	9, 0, 0, 0, 0, 0, 0, 0,
248	0, 0, 0, 0, 0, 0, 0, 0,
249	0, 0, 0, 0, 0, 0, 0, 0,
250	0, 0, 0, 0, 0, 0, 0, 0 ];
251
252pub fn curve25519_base(q: &mut [u8], n: &[u8]) {
253  return curve25519(q, n, &BASE);
254}
255
256
257#[cfg(test)]
258mod tests {
259
260	use super::{ curve25519_base, curve25519 };
261	use crate::util::verify::compare;
262
263	/// Test analogs of tests/scalarmult.c, tests/scalarmult2.c,
264	/// tests/scalarmult5.c, and tests/scalarmult6.c
265	/// 
266	#[test]
267	fn scalarmults() {
268
269		let alicesk: [u8; 32] = [
270			0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d,
271			0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45,
272			0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a,
273			0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a ];
274		let mut alicepk: [u8; 32] = [0; 32];
275
276		let bobsk: [u8; 32] = [
277			0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b,
278			0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6,
279			0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd,
280			0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb ];
281		let mut bobpk: [u8; 32] = [0; 32];
282
283		// Testing of 'curve25519_base', analog to tests/scalarmult.c
284		curve25519_base(&mut alicepk, &alicesk);
285		// taken from tests/scalarmult.out
286		assert!(compare(&alicepk, &[
287			0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54,
288			0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a,
289			0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4,
290			0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a ]));
291
292		// Testing of 'curve25519_base', analog to tests/scalarmult2.c
293		curve25519_base(&mut bobpk, &bobsk);
294		// taken from tests/scalarmult2.out
295		assert!(compare(&bobpk, &[
296			0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4,
297			0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37,
298			0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d,
299			0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f ]));
300
301		// Testing of 'curve25519', analog to tests/scalarmult5.c
302		let mut k: [u8; 32] = [0; 32];
303		curve25519(&mut k, &alicesk, &bobpk);
304		// taken from tests/scalarmult5.out
305		assert!(compare(&k, &[
306			0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1,
307			0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25,
308			0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33,
309			0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42 ]));
310
311		// Testing of 'curve25519', analog to tests/scalarmult6.c
312		let mut k2: [u8; 32] = [0; 32];
313		curve25519(&mut k2, &bobsk, &alicepk);
314		assert!(compare(&k2, &k));
315		
316	}
317
318}