authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-19 13:30:11+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-22 09:58:26+02:00
logff658abe790890c3f4e6f7fee34e52da4755a93c
tree2867c3ed4894fd8b778c28f666f8a29660fc17ca
parent8e79b3cf23b344e2f40e125581f2090dbe756c33

std/crypto/25519: use Barrett reduction for scalars (mod l)


2 files changed, 681 insertions(+), 124 deletions(-)

lib/std/crypto/25519/ed25519.zig+2-2
......@@ -144,7 +144,7 @@ pub const Ed25519 = struct {
144144 a_batch[i] = a;
145145 }
146146
147 var hram_batch: [count]Curve.scalar.Scalar = undefined;
147 var hram_batch: [count]Curve.scalar.CompressedScalar = undefined;
148148 for (signature_batch) |signature, i| {
149149 var h = Sha512.init(.{});
150150 h.update(&r_batch[i]);
......@@ -155,7 +155,7 @@ pub const Ed25519 = struct {
155155 hram_batch[i] = Curve.scalar.reduce64(hram64);
156156 }
157157
158 var z_batch: [count]Curve.scalar.Scalar = undefined;
158 var z_batch: [count]Curve.scalar.CompressedScalar = undefined;
159159 for (z_batch) |*z| {
160160 try std.crypto.randomBytes(z[0..16]);
161161 mem.set(u8, z[16..], 0);
lib/std/crypto/25519/scalar.zig+679-122
......@@ -6,129 +6,17 @@
66const std = @import("std");
77const mem = std.mem;
88
9/// A 32-byte representation of a scalar in 0 .. 2^252 + 27742317777372353535851937790883648493
10pub const Scalar = [32]u8;
11
129/// 2^252 + 27742317777372353535851937790883648493
1310pub const field_size = [32]u8{
1411 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, // 2^252+27742317777372353535851937790883648493
1512};
1613
14/// A compressed scalar
15pub const CompressedScalar = [32]u8;
16
1717/// Zero
1818pub const zero = [_]u8{0} ** 32;
1919
20/// Double-word scalar representation
21const ScalarExpanded = struct {
22 limbs: [64]i64 = [_]i64{0} ** 64,
23
24 fn fromBytes(s: [32]u8) ScalarExpanded {
25 var limbs: [64]i64 = undefined;
26 for (s) |x, idx| {
27 limbs[idx] = @as(i64, x);
28 }
29 mem.set(i64, limbs[32..], 0);
30 return .{ .limbs = limbs };
31 }
32
33 fn fromBytes64(s: [64]u8) ScalarExpanded {
34 var limbs: [64]i64 = undefined;
35 for (s) |x, idx| {
36 limbs[idx] = @as(i64, x);
37 }
38 return .{ .limbs = limbs };
39 }
40
41 fn reduce(e: *ScalarExpanded) void {
42 const limbs = &e.limbs;
43 var carry: i64 = undefined;
44 var i: usize = 63;
45 while (i >= 32) : (i -= 1) {
46 carry = 0;
47 const k = i - 12;
48 const xi = limbs[i];
49 var j = i - 32;
50 while (j < k) : (j += 1) {
51 const xj = limbs[j] + carry - 16 * xi * @as(i64, field_size[j - (i - 32)]);
52 carry = (xj + 128) >> 8;
53 limbs[j] = xj - carry * 256;
54 }
55 limbs[k] += carry;
56 limbs[i] = 0;
57 }
58 carry = 0;
59 comptime var j: usize = 0;
60 inline while (j < 32) : (j += 1) {
61 const xi = limbs[j] + carry - (limbs[31] >> 4) * @as(i64, field_size[j]);
62 carry = xi >> 8;
63 limbs[j] = xi & 255;
64 }
65 j = 0;
66 inline while (j < 32) : (j += 1) {
67 limbs[j] -= carry * @as(i64, field_size[j]);
68 }
69 j = 0;
70 inline while (j < 32) : (j += 1) {
71 limbs[j + 1] += limbs[j] >> 8;
72 }
73 j = 0;
74 inline while (j < 32) : (j += 1) {
75 limbs[j] &= 0xff;
76 }
77 limbs[32] = 0;
78 }
79
80 fn toBytes(e: *ScalarExpanded) [32]u8 {
81 e.reduce();
82 var r: [32]u8 = undefined;
83 var i: usize = 0;
84 while (i < 32) : (i += 1) {
85 r[i] = @intCast(u8, e.limbs[i]);
86 }
87 return r;
88 }
89
90 fn add(a: ScalarExpanded, b: ScalarExpanded) ScalarExpanded {
91 var r = ScalarExpanded{};
92 comptime var i = 0;
93 inline while (i < 64) : (i += 1) {
94 r.limbs[i] = a.limbs[i] + b.limbs[i];
95 }
96 return r;
97 }
98
99 fn mul(a: ScalarExpanded, b: ScalarExpanded) ScalarExpanded {
100 var r = ScalarExpanded{};
101 var i: usize = 0;
102 while (i < 32) : (i += 1) {
103 const ai = a.limbs[i];
104 comptime var j = 0;
105 inline while (j < 32) : (j += 1) {
106 r.limbs[i + j] += ai * b.limbs[j];
107 }
108 }
109 r.reduce();
110 return r;
111 }
112
113 fn sq(a: ScalarExpanded) ScalarExpanded {
114 return a.mul(a);
115 }
116
117 fn mulAdd(a: ScalarExpanded, b: ScalarExpanded, c: ScalarExpanded) ScalarExpanded {
118 var r: ScalarExpanded = .{ .limbs = c.limbs };
119 var i: usize = 0;
120 while (i < 32) : (i += 1) {
121 const ai = a.limbs[i];
122 comptime var j = 0;
123 inline while (j < 32) : (j += 1) {
124 r.limbs[i + j] += ai * b.limbs[j];
125 }
126 }
127 r.reduce();
128 return r;
129 }
130};
131
13220/// Reject a scalar whose encoding is not canonical.
13321pub fn rejectNonCanonical(s: [32]u8) !void {
13422 var c: u8 = 0;
......@@ -148,12 +36,12 @@ pub fn rejectNonCanonical(s: [32]u8) !void {
14836
14937/// Reduce a scalar to the field size.
15038pub fn reduce(s: [32]u8) [32]u8 {
151 return ScalarExpanded.fromBytes(s).toBytes();
39 return Scalar.fromBytes(s).toBytes();
15240}
15341
15442/// Reduce a 64-bytes scalar to the field size.
15543pub fn reduce64(s: [64]u8) [32]u8 {
156 return ScalarExpanded.fromBytes64(s).toBytes();
44 return ScalarDouble.fromBytes64(s).toBytes();
15745}
15846
15947/// Perform the X25519 "clamping" operation.
......@@ -165,17 +53,17 @@ pub inline fn clamp(s: *[32]u8) void {
16553
16654/// Return a*b (mod L)
16755pub fn mul(a: [32]u8, b: [32]u8) [32]u8 {
168 return ScalarExpanded.fromBytes(a).mul(ScalarExpanded.fromBytes(b)).toBytes();
56 return Scalar.fromBytes(a).mul(Scalar.fromBytes(b)).toBytes();
16957}
17058
17159/// Return a*b+c (mod L)
17260pub fn mulAdd(a: [32]u8, b: [32]u8, c: [32]u8) [32]u8 {
173 return ScalarExpanded.fromBytes(a).mulAdd(ScalarExpanded.fromBytes(b), ScalarExpanded.fromBytes(c)).toBytes();
61 return Scalar.fromBytes(a).mul(Scalar.fromBytes(b)).add(Scalar.fromBytes(c)).toBytes();
17462}
17563
17664/// Return a*8 (mod L)
17765pub fn mul8(s: [32]u8) [32]u8 {
178 var x = ScalarExpanded.fromBytes(s);
66 var x = Scalar.fromBytes(s);
17967 x = x.add(x);
18068 x = x.add(x);
18169 x = x.add(x);
......@@ -184,7 +72,7 @@ pub fn mul8(s: [32]u8) [32]u8 {
18472
18573/// Return a+b (mod L)
18674pub fn add(a: [32]u8, b: [32]u8) [32]u8 {
187 return ScalarExpanded.fromBytes(a).add(ScalarExpanded.fromBytes(b)).toBytes();
75 return Scalar.fromBytes(a).add(Scalar.fromBytes(b)).toBytes();
18876}
18977
19078/// Return -s (mod L)
......@@ -208,9 +96,678 @@ pub fn sub(a: [32]u8, b: [32]u8) [32]u8 {
20896 return add(a, neg(b));
20997}
21098
99/// A scalar in unpacked reprentation
100pub const Scalar = struct {
101 const Limbs = [5]u64;
102 limbs: Limbs = undefined,
103
104 /// Unpack a 32-byte representation of a scalar
105 pub fn fromBytes(bytes: [32]u8) Scalar {
106 return ScalarDouble.fromBytes32(bytes).reduce(5);
107 }
108
109 /// Pack a scalar into bytes
110 pub fn toBytes(expanded: *const Scalar) [32]u8 {
111 var bytes: [32]u8 = undefined;
112 var i: usize = 0;
113 while (i < 4) : (i += 1) {
114 mem.writeIntLittle(u64, bytes[i * 7 ..][0..8], expanded.limbs[i]);
115 }
116 mem.writeIntLittle(u32, bytes[i * 7 ..][0..4], @intCast(u32, expanded.limbs[i]));
117 return bytes;
118 }
119
120 /// Return x+y (mod l)
121 pub fn add(x: Scalar, y: Scalar) Scalar {
122 const carry0 = (x.limbs[0] + y.limbs[0]) >> 56;
123 const t0 = (x.limbs[0] + y.limbs[0]) & 0xffffffffffffff;
124 const t00 = t0;
125 const c0 = carry0;
126 const carry1 = (x.limbs[1] + y.limbs[1] + c0) >> 56;
127 const t1 = (x.limbs[1] + y.limbs[1] + c0) & 0xffffffffffffff;
128 const t10 = t1;
129 const c1 = carry1;
130 const carry2 = (x.limbs[2] + y.limbs[2] + c1) >> 56;
131 const t2 = (x.limbs[2] + y.limbs[2] + c1) & 0xffffffffffffff;
132 const t20 = t2;
133 const c2 = carry2;
134 const carry = (x.limbs[3] + y.limbs[3] + c2) >> 56;
135 const t3 = (x.limbs[3] + y.limbs[3] + c2) & 0xffffffffffffff;
136 const t30 = t3;
137 const c3 = carry;
138 const t4 = x.limbs[4] + y.limbs[4] + c3;
139
140 const y01: u64 = 5175514460705773;
141 const y11: u64 = 70332060721272408;
142 const y21: u64 = 5342;
143 const y31: u64 = 0;
144 const y41: u64 = 268435456;
145
146 const b5 = (t00 -% y01) >> 63;
147 const t5 = ((b5 << 56) + t00) -% y01;
148 const b0 = b5;
149 const t01 = t5;
150 const b6 = (t10 -% (y11 + b0)) >> 63;
151 const t6 = ((b6 << 56) + t10) -% (y11 + b0);
152 const b1 = b6;
153 const t11 = t6;
154 const b7 = (t20 -% (y21 + b1)) >> 63;
155 const t7 = ((b7 << 56) + t20) -% (y21 + b1);
156 const b2 = b7;
157 const t21 = t7;
158 const b8 = (t30 -% (y31 + b2)) >> 63;
159 const t8 = ((b8 << 56) + t30) -% (y31 + b2);
160 const b3 = b8;
161 const t31 = t8;
162 const b = (t4 -% (y41 + b3)) >> 63;
163 const t = ((b << 56) + t4) -% (y41 + b3);
164 const b4 = b;
165 const t41 = t;
166
167 const mask = (b4 -% 1);
168 const z00 = t00 ^ (mask & (t00 ^ t01));
169 const z10 = t10 ^ (mask & (t10 ^ t11));
170 const z20 = t20 ^ (mask & (t20 ^ t21));
171 const z30 = t30 ^ (mask & (t30 ^ t31));
172 const z40 = t4 ^ (mask & (t4 ^ t41));
173
174 return Scalar{ .limbs = .{ z00, z10, z20, z30, z40 } };
175 }
176
177 /// Return x*r (mod l)
178 pub fn mul(x: Scalar, y: Scalar) Scalar {
179 const xy000 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[0]);
180 const xy010 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[1]);
181 const xy020 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[2]);
182 const xy030 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[3]);
183 const xy040 = @as(u128, x.limbs[0]) * @as(u128, y.limbs[4]);
184 const xy100 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[0]);
185 const xy110 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[1]);
186 const xy120 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[2]);
187 const xy130 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[3]);
188 const xy140 = @as(u128, x.limbs[1]) * @as(u128, y.limbs[4]);
189 const xy200 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[0]);
190 const xy210 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[1]);
191 const xy220 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[2]);
192 const xy230 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[3]);
193 const xy240 = @as(u128, x.limbs[2]) * @as(u128, y.limbs[4]);
194 const xy300 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[0]);
195 const xy310 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[1]);
196 const xy320 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[2]);
197 const xy330 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[3]);
198 const xy340 = @as(u128, x.limbs[3]) * @as(u128, y.limbs[4]);
199 const xy400 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[0]);
200 const xy410 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[1]);
201 const xy420 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[2]);
202 const xy430 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[3]);
203 const xy440 = @as(u128, x.limbs[4]) * @as(u128, y.limbs[4]);
204 const z00 = xy000;
205 const z10 = xy010 + xy100;
206 const z20 = xy020 + xy110 + xy200;
207 const z30 = xy030 + xy120 + xy210 + xy300;
208 const z40 = xy040 + xy130 + xy220 + xy310 + xy400;
209 const z50 = xy140 + xy230 + xy320 + xy410;
210 const z60 = xy240 + xy330 + xy420;
211 const z70 = xy340 + xy430;
212 const z80 = xy440;
213
214 const carry0 = z00 >> 56;
215 const t10 = @truncate(u64, z00) & 0xffffffffffffff;
216 const c00 = carry0;
217 const t00 = t10;
218 const carry1 = (z10 + c00) >> 56;
219 const t11 = @truncate(u64, (z10 + c00)) & 0xffffffffffffff;
220 const c10 = carry1;
221 const t12 = t11;
222 const carry2 = (z20 + c10) >> 56;
223 const t13 = @truncate(u64, (z20 + c10)) & 0xffffffffffffff;
224 const c20 = carry2;
225 const t20 = t13;
226 const carry3 = (z30 + c20) >> 56;
227 const t14 = @truncate(u64, (z30 + c20)) & 0xffffffffffffff;
228 const c30 = carry3;
229 const t30 = t14;
230 const carry4 = (z40 + c30) >> 56;
231 const t15 = @truncate(u64, (z40 + c30)) & 0xffffffffffffff;
232 const c40 = carry4;
233 const t40 = t15;
234 const carry5 = (z50 + c40) >> 56;
235 const t16 = @truncate(u64, (z50 + c40)) & 0xffffffffffffff;
236 const c50 = carry5;
237 const t50 = t16;
238 const carry6 = (z60 + c50) >> 56;
239 const t17 = @truncate(u64, (z60 + c50)) & 0xffffffffffffff;
240 const c60 = carry6;
241 const t60 = t17;
242 const carry7 = (z70 + c60) >> 56;
243 const t18 = @truncate(u64, (z70 + c60)) & 0xffffffffffffff;
244 const c70 = carry7;
245 const t70 = t18;
246 const carry8 = (z80 + c70) >> 56;
247 const t19 = @truncate(u64, (z80 + c70)) & 0xffffffffffffff;
248 const c80 = carry8;
249 const t80 = t19;
250 const t90 = (@truncate(u64, c80));
251 const r0 = t00;
252 const r1 = t12;
253 const r2 = t20;
254 const r3 = t30;
255 const r4 = t40;
256 const r5 = t50;
257 const r6 = t60;
258 const r7 = t70;
259 const r8 = t80;
260 const r9 = t90;
261
262 const m0: u64 = 5175514460705773;
263 const m1: u64 = 70332060721272408;
264 const m2: u64 = 5342;
265 const m3: u64 = 0;
266 const m4: u64 = 268435456;
267 const mu0: u64 = 44162584779952923;
268 const mu1: u64 = 9390964836247533;
269 const mu2: u64 = 72057594036560134;
270 const mu3: u64 = 72057594037927935;
271 const mu4: u64 = 68719476735;
272
273 const y_ = (r5 & 0xffffff) << 32;
274 const x_ = r4 >> 24;
275 const z01 = (x_ | y_);
276 const y_0 = (r6 & 0xffffff) << 32;
277 const x_0 = r5 >> 24;
278 const z11 = (x_0 | y_0);
279 const y_1 = (r7 & 0xffffff) << 32;
280 const x_1 = r6 >> 24;
281 const z21 = (x_1 | y_1);
282 const y_2 = (r8 & 0xffffff) << 32;
283 const x_2 = r7 >> 24;
284 const z31 = (x_2 | y_2);
285 const y_3 = (r9 & 0xffffff) << 32;
286 const x_3 = r8 >> 24;
287 const z41 = (x_3 | y_3);
288 const q0 = z01;
289 const q1 = z11;
290 const q2 = z21;
291 const q3 = z31;
292 const q4 = z41;
293 const xy001 = @as(u128, q0) * @as(u128, mu0);
294 const xy011 = @as(u128, q0) * @as(u128, mu1);
295 const xy021 = @as(u128, q0) * @as(u128, mu2);
296 const xy031 = @as(u128, q0) * @as(u128, mu3);
297 const xy041 = @as(u128, q0) * @as(u128, mu4);
298 const xy101 = @as(u128, q1) * @as(u128, mu0);
299 const xy111 = @as(u128, q1) * @as(u128, mu1);
300 const xy121 = @as(u128, q1) * @as(u128, mu2);
301 const xy131 = @as(u128, q1) * @as(u128, mu3);
302 const xy14 = @as(u128, q1) * @as(u128, mu4);
303 const xy201 = @as(u128, q2) * @as(u128, mu0);
304 const xy211 = @as(u128, q2) * @as(u128, mu1);
305 const xy221 = @as(u128, q2) * @as(u128, mu2);
306 const xy23 = @as(u128, q2) * @as(u128, mu3);
307 const xy24 = @as(u128, q2) * @as(u128, mu4);
308 const xy301 = @as(u128, q3) * @as(u128, mu0);
309 const xy311 = @as(u128, q3) * @as(u128, mu1);
310 const xy32 = @as(u128, q3) * @as(u128, mu2);
311 const xy33 = @as(u128, q3) * @as(u128, mu3);
312 const xy34 = @as(u128, q3) * @as(u128, mu4);
313 const xy401 = @as(u128, q4) * @as(u128, mu0);
314 const xy41 = @as(u128, q4) * @as(u128, mu1);
315 const xy42 = @as(u128, q4) * @as(u128, mu2);
316 const xy43 = @as(u128, q4) * @as(u128, mu3);
317 const xy44 = @as(u128, q4) * @as(u128, mu4);
318 const z02 = xy001;
319 const z12 = xy011 + xy101;
320 const z22 = xy021 + xy111 + xy201;
321 const z32 = xy031 + xy121 + xy211 + xy301;
322 const z42 = xy041 + xy131 + xy221 + xy311 + xy401;
323 const z5 = xy14 + xy23 + xy32 + xy41;
324 const z6 = xy24 + xy33 + xy42;
325 const z7 = xy34 + xy43;
326 const z8 = xy44;
327
328 const carry9 = z02 >> 56;
329 const c01 = carry9;
330 const carry10 = (z12 + c01) >> 56;
331 const t21 = @truncate(u64, z12 + c01) & 0xffffffffffffff;
332 const c11 = carry10;
333 const carry11 = (z22 + c11) >> 56;
334 const t22 = @truncate(u64, z22 + c11) & 0xffffffffffffff;
335 const c21 = carry11;
336 const carry12 = (z32 + c21) >> 56;
337 const t23 = @truncate(u64, z32 + c21) & 0xffffffffffffff;
338 const c31 = carry12;
339 const carry13 = (z42 + c31) >> 56;
340 const t24 = @truncate(u64, z42 + c31) & 0xffffffffffffff;
341 const c41 = carry13;
342 const t41 = t24;
343 const carry14 = (z5 + c41) >> 56;
344 const t25 = @truncate(u64, z5 + c41) & 0xffffffffffffff;
345 const c5 = carry14;
346 const t5 = t25;
347 const carry15 = (z6 + c5) >> 56;
348 const t26 = @truncate(u64, z6 + c5) & 0xffffffffffffff;
349 const c6 = carry15;
350 const t6 = t26;
351 const carry16 = (z7 + c6) >> 56;
352 const t27 = @truncate(u64, z7 + c6) & 0xffffffffffffff;
353 const c7 = carry16;
354 const t7 = t27;
355 const carry17 = (z8 + c7) >> 56;
356 const t28 = @truncate(u64, z8 + c7) & 0xffffffffffffff;
357 const c8 = carry17;
358 const t8 = t28;
359 const t9 = @truncate(u64, c8);
360
361 const qmu4_ = t41;
362 const qmu5_ = t5;
363 const qmu6_ = t6;
364 const qmu7_ = t7;
365 const qmu8_ = t8;
366 const qmu9_ = t9;
367 const y_4 = (qmu5_ & 0xffffffffff) << 16;
368 const x_4 = qmu4_ >> 40;
369 const z03 = (x_4 | y_4);
370 const y_5 = (qmu6_ & 0xffffffffff) << 16;
371 const x_5 = qmu5_ >> 40;
372 const z13 = (x_5 | y_5);
373 const y_6 = (qmu7_ & 0xffffffffff) << 16;
374 const x_6 = qmu6_ >> 40;
375 const z23 = (x_6 | y_6);
376 const y_7 = (qmu8_ & 0xffffffffff) << 16;
377 const x_7 = qmu7_ >> 40;
378 const z33 = (x_7 | y_7);
379 const y_8 = (qmu9_ & 0xffffffffff) << 16;
380 const x_8 = qmu8_ >> 40;
381 const z43 = (x_8 | y_8);
382 const qdiv0 = z03;
383 const qdiv1 = z13;
384 const qdiv2 = z23;
385 const qdiv3 = z33;
386 const qdiv4 = z43;
387 const r01 = r0;
388 const r11 = r1;
389 const r21 = r2;
390 const r31 = r3;
391 const r41 = (r4 & 0xffffffffff);
392
393 const xy00 = @as(u128, qdiv0) * @as(u128, m0);
394 const xy01 = @as(u128, qdiv0) * @as(u128, m1);
395 const xy02 = @as(u128, qdiv0) * @as(u128, m2);
396 const xy03 = @as(u128, qdiv0) * @as(u128, m3);
397 const xy04 = @as(u128, qdiv0) * @as(u128, m4);
398 const xy10 = @as(u128, qdiv1) * @as(u128, m0);
399 const xy11 = @as(u128, qdiv1) * @as(u128, m1);
400 const xy12 = @as(u128, qdiv1) * @as(u128, m2);
401 const xy13 = @as(u128, qdiv1) * @as(u128, m3);
402 const xy20 = @as(u128, qdiv2) * @as(u128, m0);
403 const xy21 = @as(u128, qdiv2) * @as(u128, m1);
404 const xy22 = @as(u128, qdiv2) * @as(u128, m2);
405 const xy30 = @as(u128, qdiv3) * @as(u128, m0);
406 const xy31 = @as(u128, qdiv3) * @as(u128, m1);
407 const xy40 = @as(u128, qdiv4) * @as(u128, m0);
408 const carry18 = xy00 >> 56;
409 const t29 = @truncate(u64, xy00) & 0xffffffffffffff;
410 const c0 = carry18;
411 const t01 = t29;
412 const carry19 = (xy01 + xy10 + c0) >> 56;
413 const t31 = @truncate(u64, xy01 + xy10 + c0) & 0xffffffffffffff;
414 const c12 = carry19;
415 const t110 = t31;
416 const carry20 = (xy02 + xy11 + xy20 + c12) >> 56;
417 const t32 = @truncate(u64, xy02 + xy11 + xy20 + c12) & 0xffffffffffffff;
418 const c22 = carry20;
419 const t210 = t32;
420 const carry = (xy03 + xy12 + xy21 + xy30 + c22) >> 56;
421 const t33 = @truncate(u64, xy03 + xy12 + xy21 + xy30 + c22) & 0xffffffffffffff;
422 const c32 = carry;
423 const t34 = t33;
424 const t42 = @truncate(u64, xy04 + xy13 + xy22 + xy31 + xy40 + c32) & 0xffffffffff;
425
426 const qmul0 = t01;
427 const qmul1 = t110;
428 const qmul2 = t210;
429 const qmul3 = t34;
430 const qmul4 = t42;
431 const b5 = (r01 -% qmul0) >> 63;
432 const t35 = ((b5 << 56) + r01) -% qmul0;
433 const c1 = b5;
434 const t02 = t35;
435 const b6 = (r11 -% (qmul1 + c1)) >> 63;
436 const t36 = ((b6 << 56) + r11) -% (qmul1 + c1);
437 const c2 = b6;
438 const t111 = t36;
439 const b7 = (r21 -% (qmul2 + c2)) >> 63;
440 const t37 = ((b7 << 56) + r21) -% (qmul2 + c2);
441 const c3 = b7;
442 const t211 = t37;
443 const b8 = (r31 -% (qmul3 + c3)) >> 63;
444 const t38 = ((b8 << 56) + r31) -% (qmul3 + c3);
445 const c4 = b8;
446 const t39 = t38;
447 const b9 = (r41 -% (qmul4 + c4)) >> 63;
448 const t43 = ((b9 << 40) + r41) -% (qmul4 + c4);
449 const t44 = t43;
450 const s0 = t02;
451 const s1 = t111;
452 const s2 = t211;
453 const s3 = t39;
454 const s4 = t44;
455
456 const y01: u64 = 5175514460705773;
457 const y11: u64 = 70332060721272408;
458 const y21: u64 = 5342;
459 const y31: u64 = 0;
460 const y41: u64 = 268435456;
461
462 const b10 = (s0 -% y01) >> 63;
463 const t45 = ((b10 << 56) + s0) -% y01;
464 const b0 = b10;
465 const t0 = t45;
466 const b11 = (s1 -% (y11 + b0)) >> 63;
467 const t46 = ((b11 << 56) + s1) -% (y11 + b0);
468 const b1 = b11;
469 const t1 = t46;
470 const b12 = (s2 -% (y21 + b1)) >> 63;
471 const t47 = ((b12 << 56) + s2) -% (y21 + b1);
472 const b2 = b12;
473 const t2 = t47;
474 const b13 = (s3 -% (y31 + b2)) >> 63;
475 const t48 = ((b13 << 56) + s3) -% (y31 + b2);
476 const b3 = b13;
477 const t3 = t48;
478 const b = (s4 -% (y41 + b3)) >> 63;
479 const t = ((b << 56) + s4) -% (y41 + b3);
480 const b4 = b;
481 const t4 = t;
482 const mask = (b4 -% @intCast(u64, ((1))));
483 const z04 = s0 ^ (mask & (s0 ^ t0));
484 const z14 = s1 ^ (mask & (s1 ^ t1));
485 const z24 = s2 ^ (mask & (s2 ^ t2));
486 const z34 = s3 ^ (mask & (s3 ^ t3));
487 const z44 = s4 ^ (mask & (s4 ^ t4));
488
489 return Scalar{ .limbs = .{ z04, z14, z24, z34, z44 } };
490 }
491};
492
493const ScalarDouble = struct {
494 const Limbs = [10]u64;
495 limbs: Limbs = undefined,
496
497 fn fromBytes64(bytes: [64]u8) ScalarDouble {
498 var limbs: Limbs = undefined;
499 var i: usize = 0;
500 while (i < 9) : (i += 1) {
501 limbs[i] = mem.readIntLittle(u64, bytes[i * 7 ..][0..8]) & 0xffffffffffffff;
502 }
503 limbs[i] = @as(u64, bytes[i * 7]);
504 return ScalarDouble{ .limbs = limbs };
505 }
506
507 fn fromBytes32(bytes: [32]u8) ScalarDouble {
508 var limbs: Limbs = undefined;
509 var i: usize = 0;
510 while (i < 4) : (i += 1) {
511 limbs[i] = mem.readIntLittle(u64, bytes[i * 7 ..][0..8]) & 0xffffffffffffff;
512 }
513 limbs[i] = @as(u64, mem.readIntLittle(u32, bytes[i * 7 ..][0..4]));
514 mem.set(u64, limbs[5..], 0);
515 return ScalarDouble{ .limbs = limbs };
516 }
517
518 fn toBytes(expanded_double: *ScalarDouble) [32]u8 {
519 return expanded_double.reduce(10).toBytes();
520 }
521
522 /// Barrett reduction
523 fn reduce(expanded: *ScalarDouble, comptime limbs_count: usize) Scalar {
524 const t = expanded.limbs;
525 const t0 = if (limbs_count <= 0) 0 else t[0];
526 const t1 = if (limbs_count <= 1) 0 else t[1];
527 const t2 = if (limbs_count <= 2) 0 else t[2];
528 const t3 = if (limbs_count <= 3) 0 else t[3];
529 const t4 = if (limbs_count <= 4) 0 else t[4];
530 const t5 = if (limbs_count <= 5) 0 else t[5];
531 const t6 = if (limbs_count <= 6) 0 else t[6];
532 const t7 = if (limbs_count <= 7) 0 else t[7];
533 const t8 = if (limbs_count <= 8) 0 else t[8];
534 const t9 = if (limbs_count <= 9) 0 else t[9];
535
536 const m0: u64 = 5175514460705773;
537 const m1: u64 = 70332060721272408;
538 const m2: u64 = 5342;
539 const m3: u64 = 0;
540 const m4: u64 = 268435456;
541 const mu0: u64 = 44162584779952923;
542 const mu1: u64 = 9390964836247533;
543 const mu2: u64 = 72057594036560134;
544 const mu3: u64 = 0xffffffffffffff;
545 const mu4: u64 = 68719476735;
546
547 const y_ = (t5 & 0xffffff) << 32;
548 const x_ = t4 >> 24;
549 const z00 = x_ | y_;
550 const y_0 = (t6 & 0xffffff) << 32;
551 const x_0 = t5 >> 24;
552 const z10 = x_0 | y_0;
553 const y_1 = (t7 & 0xffffff) << 32;
554 const x_1 = t6 >> 24;
555 const z20 = x_1 | y_1;
556 const y_2 = (t8 & 0xffffff) << 32;
557 const x_2 = t7 >> 24;
558 const z30 = x_2 | y_2;
559 const y_3 = (t9 & 0xffffff) << 32;
560 const x_3 = t8 >> 24;
561 const z40 = x_3 | y_3;
562 const q0 = z00;
563 const q1 = z10;
564 const q2 = z20;
565 const q3 = z30;
566 const q4 = z40;
567
568 const xy000 = @as(u128, q0) * @as(u128, mu0);
569 const xy010 = @as(u128, q0) * @as(u128, mu1);
570 const xy020 = @as(u128, q0) * @as(u128, mu2);
571 const xy030 = @as(u128, q0) * @as(u128, mu3);
572 const xy040 = @as(u128, q0) * @as(u128, mu4);
573 const xy100 = @as(u128, q1) * @as(u128, mu0);
574 const xy110 = @as(u128, q1) * @as(u128, mu1);
575 const xy120 = @as(u128, q1) * @as(u128, mu2);
576 const xy130 = @as(u128, q1) * @as(u128, mu3);
577 const xy14 = @as(u128, q1) * @as(u128, mu4);
578 const xy200 = @as(u128, q2) * @as(u128, mu0);
579 const xy210 = @as(u128, q2) * @as(u128, mu1);
580 const xy220 = @as(u128, q2) * @as(u128, mu2);
581 const xy23 = @as(u128, q2) * @as(u128, mu3);
582 const xy24 = @as(u128, q2) * @as(u128, mu4);
583 const xy300 = @as(u128, q3) * @as(u128, mu0);
584 const xy310 = @as(u128, q3) * @as(u128, mu1);
585 const xy32 = @as(u128, q3) * @as(u128, mu2);
586 const xy33 = @as(u128, q3) * @as(u128, mu3);
587 const xy34 = @as(u128, q3) * @as(u128, mu4);
588 const xy400 = @as(u128, q4) * @as(u128, mu0);
589 const xy41 = @as(u128, q4) * @as(u128, mu1);
590 const xy42 = @as(u128, q4) * @as(u128, mu2);
591 const xy43 = @as(u128, q4) * @as(u128, mu3);
592 const xy44 = @as(u128, q4) * @as(u128, mu4);
593 const z01 = xy000;
594 const z11 = xy010 + xy100;
595 const z21 = xy020 + xy110 + xy200;
596 const z31 = xy030 + xy120 + xy210 + xy300;
597 const z41 = xy040 + xy130 + xy220 + xy310 + xy400;
598 const z5 = xy14 + xy23 + xy32 + xy41;
599 const z6 = xy24 + xy33 + xy42;
600 const z7 = xy34 + xy43;
601 const z8 = xy44;
602
603 const carry0 = z01 >> 56;
604 const c00 = carry0;
605 const carry1 = (z11 + c00) >> 56;
606 const t100 = @as(u64, @truncate(u64, z11 + c00)) & 0xffffffffffffff;
607 const c10 = carry1;
608 const carry2 = (z21 + c10) >> 56;
609 const t101 = @as(u64, @truncate(u64, z21 + c10)) & 0xffffffffffffff;
610 const c20 = carry2;
611 const carry3 = (z31 + c20) >> 56;
612 const t102 = @as(u64, @truncate(u64, z31 + c20)) & 0xffffffffffffff;
613 const c30 = carry3;
614 const carry4 = (z41 + c30) >> 56;
615 const t103 = @as(u64, @truncate(u64, z41 + c30)) & 0xffffffffffffff;
616 const c40 = carry4;
617 const t410 = t103;
618 const carry5 = (z5 + c40) >> 56;
619 const t104 = @as(u64, @truncate(u64, z5 + c40)) & 0xffffffffffffff;
620 const c5 = carry5;
621 const t51 = t104;
622 const carry6 = (z6 + c5) >> 56;
623 const t105 = @as(u64, @truncate(u64, z6 + c5)) & 0xffffffffffffff;
624 const c6 = carry6;
625 const t61 = t105;
626 const carry7 = (z7 + c6) >> 56;
627 const t106 = @as(u64, @truncate(u64, z7 + c6)) & 0xffffffffffffff;
628 const c7 = carry7;
629 const t71 = t106;
630 const carry8 = (z8 + c7) >> 56;
631 const t107 = @as(u64, @truncate(u64, z8 + c7)) & 0xffffffffffffff;
632 const c8 = carry8;
633 const t81 = t107;
634 const t91 = @as(u64, @truncate(u64, c8));
635
636 const qmu4_ = t410;
637 const qmu5_ = t51;
638 const qmu6_ = t61;
639 const qmu7_ = t71;
640 const qmu8_ = t81;
641 const qmu9_ = t91;
642 const y_4 = (qmu5_ & 0xffffffffff) << 16;
643 const x_4 = qmu4_ >> 40;
644 const z02 = x_4 | y_4;
645 const y_5 = (qmu6_ & 0xffffffffff) << 16;
646 const x_5 = qmu5_ >> 40;
647 const z12 = x_5 | y_5;
648 const y_6 = (qmu7_ & 0xffffffffff) << 16;
649 const x_6 = qmu6_ >> 40;
650 const z22 = x_6 | y_6;
651 const y_7 = (qmu8_ & 0xffffffffff) << 16;
652 const x_7 = qmu7_ >> 40;
653 const z32 = x_7 | y_7;
654 const y_8 = (qmu9_ & 0xffffffffff) << 16;
655 const x_8 = qmu8_ >> 40;
656 const z42 = x_8 | y_8;
657 const qdiv0 = z02;
658 const qdiv1 = z12;
659 const qdiv2 = z22;
660 const qdiv3 = z32;
661 const qdiv4 = z42;
662 const r0 = t0;
663 const r1 = t1;
664 const r2 = t2;
665 const r3 = t3;
666 const r4 = t4 & 0xffffffffff;
667
668 const xy00 = @as(u128, qdiv0) * @as(u128, m0);
669 const xy01 = @as(u128, qdiv0) * @as(u128, m1);
670 const xy02 = @as(u128, qdiv0) * @as(u128, m2);
671 const xy03 = @as(u128, qdiv0) * @as(u128, m3);
672 const xy04 = @as(u128, qdiv0) * @as(u128, m4);
673 const xy10 = @as(u128, qdiv1) * @as(u128, m0);
674 const xy11 = @as(u128, qdiv1) * @as(u128, m1);
675 const xy12 = @as(u128, qdiv1) * @as(u128, m2);
676 const xy13 = @as(u128, qdiv1) * @as(u128, m3);
677 const xy20 = @as(u128, qdiv2) * @as(u128, m0);
678 const xy21 = @as(u128, qdiv2) * @as(u128, m1);
679 const xy22 = @as(u128, qdiv2) * @as(u128, m2);
680 const xy30 = @as(u128, qdiv3) * @as(u128, m0);
681 const xy31 = @as(u128, qdiv3) * @as(u128, m1);
682 const xy40 = @as(u128, qdiv4) * @as(u128, m0);
683 const carry9 = xy00 >> 56;
684 const t108 = @truncate(u64, xy00) & 0xffffffffffffff;
685 const c0 = carry9;
686 const t010 = t108;
687 const carry10 = (xy01 + xy10 + c0) >> 56;
688 const t109 = @truncate(u64, xy01 + xy10 + c0) & 0xffffffffffffff;
689 const c11 = carry10;
690 const t110 = t109;
691 const carry11 = (xy02 + xy11 + xy20 + c11) >> 56;
692 const t1010 = @truncate(u64, xy02 + xy11 + xy20 + c11) & 0xffffffffffffff;
693 const c21 = carry11;
694 const t210 = t1010;
695 const carry = (xy03 + xy12 + xy21 + xy30 + c21) >> 56;
696 const t1011 = @truncate(u64, xy03 + xy12 + xy21 + xy30 + c21) & 0xffffffffffffff;
697 const c31 = carry;
698 const t310 = t1011;
699 const t411 = @truncate(u64, xy04 + xy13 + xy22 + xy31 + xy40 + c31) & 0xffffffffff;
700
701 const qmul0 = t010;
702 const qmul1 = t110;
703 const qmul2 = t210;
704 const qmul3 = t310;
705 const qmul4 = t411;
706 const b5 = (r0 -% qmul0) >> 63;
707 const t1012 = ((b5 << 56) + r0) -% qmul0;
708 const c1 = b5;
709 const t011 = t1012;
710 const b6 = (r1 -% (qmul1 + c1)) >> 63;
711 const t1013 = ((b6 << 56) + r1) -% (qmul1 + c1);
712 const c2 = b6;
713 const t111 = t1013;
714 const b7 = (r2 -% (qmul2 + c2)) >> 63;
715 const t1014 = ((b7 << 56) + r2) -% (qmul2 + c2);
716 const c3 = b7;
717 const t211 = t1014;
718 const b8 = (r3 -% (qmul3 + c3)) >> 63;
719 const t1015 = ((b8 << 56) + r3) -% (qmul3 + c3);
720 const c4 = b8;
721 const t311 = t1015;
722 const b9 = (r4 -% (qmul4 + c4)) >> 63;
723 const t1016 = ((b9 << 40) + r4) -% (qmul4 + c4);
724 const t412 = t1016;
725 const s0 = t011;
726 const s1 = t111;
727 const s2 = t211;
728 const s3 = t311;
729 const s4 = t412;
730
731 const y0: u64 = 5175514460705773;
732 const y1: u64 = 70332060721272408;
733 const y2: u64 = 5342;
734 const y3: u64 = 0;
735 const y4: u64 = 268435456;
736
737 const b10 = (s0 -% y0) >> 63;
738 const t1017 = ((b10 << 56) + s0) -% y0;
739 const b0 = b10;
740 const t01 = t1017;
741 const b11 = (s1 -% (y1 + b0)) >> 63;
742 const t1018 = ((b11 << 56) + s1) -% (y1 + b0);
743 const b1 = b11;
744 const t11 = t1018;
745 const b12 = (s2 -% (y2 + b1)) >> 63;
746 const t1019 = ((b12 << 56) + s2) -% (y2 + b1);
747 const b2 = b12;
748 const t21 = t1019;
749 const b13 = (s3 -% (y3 + b2)) >> 63;
750 const t1020 = ((b13 << 56) + s3) -% (y3 + b2);
751 const b3 = b13;
752 const t31 = t1020;
753 const b = (s4 -% (y4 + b3)) >> 63;
754 const t10 = ((b << 56) + s4) -% (y4 + b3);
755 const b4 = b;
756 const t41 = t10;
757 const mask = b4 -% @as(u64, @as(u64, 1));
758 const z03 = s0 ^ (mask & (s0 ^ t01));
759 const z13 = s1 ^ (mask & (s1 ^ t11));
760 const z23 = s2 ^ (mask & (s2 ^ t21));
761 const z33 = s3 ^ (mask & (s3 ^ t31));
762 const z43 = s4 ^ (mask & (s4 ^ t41));
763
764 return Scalar{ .limbs = .{ z03, z13, z23, z33, z43 } };
765 }
766};
767
211768test "scalar25519" {
212769 const bytes: [32]u8 = .{ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 255 };
213 var x = ScalarExpanded.fromBytes(bytes);
770 var x = Scalar.fromBytes(bytes);
214771 var y = x.toBytes();
215772 try rejectNonCanonical(y);
216773 var buf: [128]u8 = undefined;