authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2021-05-26 21:20:23+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-27 16:35:10-04:00
log7674a8b43d42434a2ed424ca0778bb348e1e3d70
tree24eeca98b8cd5d8dcbc476690a7f030420311f37
parentd8d92dafe8763ac18d964bb1a6e88de0b13da152

p256: update to the last fiat-crypto code & share PC tables

fiat-crypto now generates proper types, so take advantage of that. Add mixed subtraction and double base multiplication. We will eventually leverage mixed addition/subtraction for fixed base multiplication. The reason we don't right now is that precomputing the tables at comptime would take forever. We don't use combs for the same reason. Stage2 + less function calls in the fiat-crypto generated code will eventually address that. Also make the edwards25519 code consistent with these changes. No functional changes.

6 files changed, 195 insertions(+), 163 deletions(-)

lib/std/crypto/25519/edwards25519.zig+21-20
...@@ -143,7 +143,7 @@ pub const Edwards25519 = struct {...@@ -143,7 +143,7 @@ pub const Edwards25519 = struct {
143 p.t.cMov(a.t, c);143 p.t.cMov(a.t, c);
144 }144 }
145145
146 inline fn pcSelect(comptime n: usize, pc: [n]Edwards25519, b: u8) Edwards25519 {146 inline fn pcSelect(comptime n: usize, pc: *const [n]Edwards25519, b: u8) Edwards25519 {
147 var t = Edwards25519.identityElement;147 var t = Edwards25519.identityElement;
148 comptime var i: u8 = 1;148 comptime var i: u8 = 1;
149 inline while (i < pc.len) : (i += 1) {149 inline while (i < pc.len) : (i += 1) {
...@@ -176,7 +176,7 @@ pub const Edwards25519 = struct {...@@ -176,7 +176,7 @@ pub const Edwards25519 = struct {
176 // Based on real-world benchmarks, we only use this for multi-scalar multiplication.176 // Based on real-world benchmarks, we only use this for multi-scalar multiplication.
177 // NAF could be useful to half the size of precomputation tables, but we intentionally177 // NAF could be useful to half the size of precomputation tables, but we intentionally
178 // avoid these to keep the standard library lightweight.178 // avoid these to keep the standard library lightweight.
179 fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {179 fn pcMul(pc: *const [9]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {
180 std.debug.assert(vartime);180 std.debug.assert(vartime);
181 const e = slide(s);181 const e = slide(s);
182 var q = Edwards25519.identityElement;182 var q = Edwards25519.identityElement;
...@@ -196,7 +196,7 @@ pub const Edwards25519 = struct {...@@ -196,7 +196,7 @@ pub const Edwards25519 = struct {
196 }196 }
197197
198 // Scalar multiplication with a 4-bit window and the first 15 multiples.198 // Scalar multiplication with a 4-bit window and the first 15 multiples.
199 fn pcMul16(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {199 fn pcMul16(pc: *const [16]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {
200 var q = Edwards25519.identityElement;200 var q = Edwards25519.identityElement;
201 var pos: usize = 252;201 var pos: usize = 252;
202 while (true) : (pos -= 4) {202 while (true) : (pos -= 4) {
...@@ -231,11 +231,6 @@ pub const Edwards25519 = struct {...@@ -231,11 +231,6 @@ pub const Edwards25519 = struct {
231 break :pc precompute(Edwards25519.basePoint, 15);231 break :pc precompute(Edwards25519.basePoint, 15);
232 };232 };
233233
234 const basePointPc8 = pc: {
235 @setEvalBranchQuota(10000);
236 break :pc precompute(Edwards25519.basePoint, 8);
237 };
238
239 /// Multiply an Edwards25519 point by a scalar without clamping it.234 /// Multiply an Edwards25519 point by a scalar without clamping it.
240 /// Return error.WeakPublicKey if the base generates a small-order group,235 /// Return error.WeakPublicKey if the base generates a small-order group,
241 /// and error.IdentityElement if the result is the identity element.236 /// and error.IdentityElement if the result is the identity element.
...@@ -245,33 +240,35 @@ pub const Edwards25519 = struct {...@@ -245,33 +240,35 @@ pub const Edwards25519 = struct {
245 xpc[4].rejectIdentity() catch return error.WeakPublicKey;240 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
246 break :pc xpc;241 break :pc xpc;
247 };242 };
248 return pcMul16(pc, s, false);243 return pcMul16(&pc, s, false);
249 }244 }
250245
251 /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*246 /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
252 /// This can be used for signature verification.247 /// This can be used for signature verification.
253 pub fn mulPublic(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {248 pub fn mulPublic(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
254 if (p.is_base) {249 if (p.is_base) {
255 return pcMul16(basePointPc, s, true);250 return pcMul16(&basePointPc, s, true);
256 } else {251 } else {
257 const pc = precompute(p, 8);252 const pc = precompute(p, 8);
258 pc[4].rejectIdentity() catch return error.WeakPublicKey;253 pc[4].rejectIdentity() catch return error.WeakPublicKey;
259 return pcMul(pc, s, true);254 return pcMul(&pc, s, true);
260 }255 }
261 }256 }
262257
263 /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME*258 /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME*
264 /// This can be used for signature verification.259 /// This can be used for signature verification.
265 pub fn mulDoubleBasePublic(p1: Edwards25519, s1: [32]u8, p2: Edwards25519, s2: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {260 pub fn mulDoubleBasePublic(p1: Edwards25519, s1: [32]u8, p2: Edwards25519, s2: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
266 const pc1 = if (p1.is_base) basePointPc8 else pc: {261 var pc1_array: [9]Edwards25519 = undefined;
267 const xpc = precompute(p1, 8);262 const pc1 = if (p1.is_base) basePointPc[0..9] else pc: {
268 xpc[4].rejectIdentity() catch return error.WeakPublicKey;263 pc1_array = precompute(p1, 8);
269 break :pc xpc;264 pc1_array[4].rejectIdentity() catch return error.WeakPublicKey;
265 break :pc &pc1_array;
270 };266 };
271 const pc2 = if (p2.is_base) basePointPc8 else pc: {267 var pc2_array: [9]Edwards25519 = undefined;
272 const xpc = precompute(p2, 8);268 const pc2 = if (p2.is_base) basePointPc[0..9] else pc: {
273 xpc[4].rejectIdentity() catch return error.WeakPublicKey;269 pc2_array = precompute(p2, 8);
274 break :pc xpc;270 pc2_array[4].rejectIdentity() catch return error.WeakPublicKey;
271 break :pc &pc2_array;
275 };272 };
276 const e1 = slide(s1);273 const e1 = slide(s1);
277 const e2 = slide(s2);274 const e2 = slide(s2);
...@@ -301,9 +298,13 @@ pub const Edwards25519 = struct {...@@ -301,9 +298,13 @@ pub const Edwards25519 = struct {
301 /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually298 /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually
302 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {299 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
303 var pcs: [count][9]Edwards25519 = undefined;300 var pcs: [count][9]Edwards25519 = undefined;
301
302 var bpc: [9]Edwards25519 = undefined;
303 mem.copy(Edwards25519, bpc[0..], basePointPc[0..bpc.len]);
304
304 for (ps) |p, i| {305 for (ps) |p, i| {
305 if (p.is_base) {306 if (p.is_base) {
306 pcs[i] = basePointPc8;307 pcs[i] = bpc;
307 } else {308 } else {
308 pcs[i] = precompute(p, 8);309 pcs[i] = precompute(p, 8);
309 pcs[i][4].rejectIdentity() catch return error.WeakPublicKey;310 pcs[i][4].rejectIdentity() catch return error.WeakPublicKey;
lib/std/crypto/pcurves/common.zig+8-6
...@@ -20,12 +20,13 @@ pub const FieldParams = struct {...@@ -20,12 +20,13 @@ pub const FieldParams = struct {
20/// A field element, internally stored in Montgomery domain.20/// A field element, internally stored in Montgomery domain.
21pub fn Field(comptime params: FieldParams) type {21pub fn Field(comptime params: FieldParams) type {
22 const fiat = params.fiat;22 const fiat = params.fiat;
23 const Limbs = fiat.Limbs;23 const MontgomeryDomainFieldElement = fiat.MontgomeryDomainFieldElement;
24 const NonMontgomeryDomainFieldElement = fiat.NonMontgomeryDomainFieldElement;
2425
25 return struct {26 return struct {
26 const Fe = @This();27 const Fe = @This();
2728
28 limbs: Limbs,29 limbs: MontgomeryDomainFieldElement,
2930
30 /// Field size.31 /// Field size.
31 pub const field_order = params.field_order;32 pub const field_order = params.field_order;
...@@ -40,7 +41,7 @@ pub fn Field(comptime params: FieldParams) type {...@@ -40,7 +41,7 @@ pub fn Field(comptime params: FieldParams) type {
40 pub const encoded_length = params.encoded_length;41 pub const encoded_length = params.encoded_length;
4142
42 /// Zero.43 /// Zero.
43 pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) };44 pub const zero: Fe = Fe{ .limbs = mem.zeroes(MontgomeryDomainFieldElement) };
4445
45 /// One.46 /// One.
46 pub const one = one: {47 pub const one = one: {
...@@ -73,16 +74,16 @@ pub fn Field(comptime params: FieldParams) type {...@@ -73,16 +74,16 @@ pub fn Field(comptime params: FieldParams) type {
73 pub fn fromBytes(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!Fe {74 pub fn fromBytes(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!Fe {
74 var s = if (endian == .Little) s_ else orderSwap(s_);75 var s = if (endian == .Little) s_ else orderSwap(s_);
75 try rejectNonCanonical(s, .Little);76 try rejectNonCanonical(s, .Little);
76 var limbs_z: Limbs = undefined;77 var limbs_z: NonMontgomeryDomainFieldElement = undefined;
77 fiat.fromBytes(&limbs_z, s);78 fiat.fromBytes(&limbs_z, s);
78 var limbs: Limbs = undefined;79 var limbs: MontgomeryDomainFieldElement = undefined;
79 fiat.toMontgomery(&limbs, limbs_z);80 fiat.toMontgomery(&limbs, limbs_z);
80 return Fe{ .limbs = limbs };81 return Fe{ .limbs = limbs };
81 }82 }
8283
83 /// Pack a field element.84 /// Pack a field element.
84 pub fn toBytes(fe: Fe, endian: builtin.Endian) [encoded_length]u8 {85 pub fn toBytes(fe: Fe, endian: builtin.Endian) [encoded_length]u8 {
85 var limbs_z: Limbs = undefined;86 var limbs_z: NonMontgomeryDomainFieldElement = undefined;
86 fiat.fromMontgomery(&limbs_z, fe.limbs);87 fiat.fromMontgomery(&limbs_z, fe.limbs);
87 var s: [encoded_length]u8 = undefined;88 var s: [encoded_length]u8 = undefined;
88 fiat.toBytes(&s, limbs_z);89 fiat.toBytes(&s, limbs_z);
...@@ -198,6 +199,7 @@ pub fn Field(comptime params: FieldParams) type {...@@ -198,6 +199,7 @@ pub fn Field(comptime params: FieldParams) type {
198 // Field inversion from https://eprint.iacr.org/2021/549.pdf199 // Field inversion from https://eprint.iacr.org/2021/549.pdf
199 pub fn invert(a: Fe) Fe {200 pub fn invert(a: Fe) Fe {
200 const iterations = (49 * field_bits + 57) / 17;201 const iterations = (49 * field_bits + 57) / 17;
202 const Limbs = @TypeOf(a.limbs);
201 const Word = @TypeOf(a.limbs[0]);203 const Word = @TypeOf(a.limbs[0]);
202 const XLimbs = [a.limbs.len + 1]Word;204 const XLimbs = [a.limbs.len + 1]Word;
203205
lib/std/crypto/pcurves/p256.zig+60-19
...@@ -286,6 +286,11 @@ pub const P256 = struct {...@@ -286,6 +286,11 @@ pub const P256 = struct {
286 return p.add(q.neg());286 return p.add(q.neg());
287 }287 }
288288
289 /// Subtract P256 points, the second being specified using affine coordinates.
290 pub fn subMixed(p: P256, q: AffineCoordinates) P256 {
291 return p.addMixed(q.neg());
292 }
293
289 /// Return affine coordinates.294 /// Return affine coordinates.
290 pub fn affineCoordinates(p: P256) AffineCoordinates {295 pub fn affineCoordinates(p: P256) AffineCoordinates {
291 const zinv = p.z.invert();296 const zinv = p.z.invert();
...@@ -312,7 +317,7 @@ pub const P256 = struct {...@@ -312,7 +317,7 @@ pub const P256 = struct {
312 p.z.cMov(a.z, c);317 p.z.cMov(a.z, c);
313 }318 }
314319
315 fn pcSelect(comptime n: usize, pc: [n]P256, b: u8) P256 {320 fn pcSelect(comptime n: usize, pc: *const [n]P256, b: u8) P256 {
316 var t = P256.identityElement;321 var t = P256.identityElement;
317 comptime var i: u8 = 1;322 comptime var i: u8 = 1;
318 inline while (i < pc.len) : (i += 1) {323 inline while (i < pc.len) : (i += 1) {
...@@ -341,7 +346,7 @@ pub const P256 = struct {...@@ -341,7 +346,7 @@ pub const P256 = struct {
341 return e;346 return e;
342 }347 }
343348
344 fn pcMul(pc: [9]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {349 fn pcMul(pc: *const [9]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {
345 std.debug.assert(vartime);350 std.debug.assert(vartime);
346 const e = slide(s);351 const e = slide(s);
347 var q = P256.identityElement;352 var q = P256.identityElement;
...@@ -360,7 +365,7 @@ pub const P256 = struct {...@@ -360,7 +365,7 @@ pub const P256 = struct {
360 return q;365 return q;
361 }366 }
362367
363 fn pcMul16(pc: [16]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {368 fn pcMul16(pc: *const [16]P256, s: [32]u8, comptime vartime: bool) IdentityElementError!P256 {
364 var q = P256.identityElement;369 var q = P256.identityElement;
365 var pos: usize = 252;370 var pos: usize = 252;
366 while (true) : (pos -= 4) {371 while (true) : (pos -= 4) {
...@@ -395,33 +400,69 @@ pub const P256 = struct {...@@ -395,33 +400,69 @@ pub const P256 = struct {
395 break :pc precompute(P256.basePoint, 15);400 break :pc precompute(P256.basePoint, 15);
396 };401 };
397402
398 const basePointPc8 = pc: {
399 @setEvalBranchQuota(50000);
400 break :pc precompute(P256.basePoint, 8);
401 };
402
403 /// Multiply an elliptic curve point by a scalar.403 /// Multiply an elliptic curve point by a scalar.
404 /// Return error.IdentityElement if the result is the identity element.404 /// Return error.IdentityElement if the result is the identity element.
405 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {405 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
406 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);406 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
407 const pc = if (p.is_base) basePointPc else pc: {407 if (p.is_base) {
408 try p.rejectIdentity();408 return pcMul16(&basePointPc, s, false);
409 const xpc = precompute(p, 15);409 }
410 break :pc xpc;410 try p.rejectIdentity();
411 };411 const pc = precompute(p, 15);
412 return pcMul16(pc, s, false);412 return pcMul16(&pc, s, false);
413 }413 }
414414
415 /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME*415 /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME*
416 /// This can be used for signature verification.416 /// This can be used for signature verification.
417 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {417 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
418 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);418 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
419 const pc = if (p.is_base) basePointPc8 else pc: {419 if (p.is_base) {
420 try p.rejectIdentity();420 return pcMul16(&basePointPc, s, true);
421 const xpc = precompute(p, 8);421 }
422 break :pc xpc;422 try p.rejectIdentity();
423 const pc = precompute(p, 8);
424 return pcMul(&pc, s, true);
425 }
426
427 /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME*
428 /// This can be used for signature verification.
429 pub fn mulDoubleBasePublic(p1: P256, s1_: [32]u8, p2: P256, s2_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
430 const s1 = if (endian == .Little) s1_ else Fe.orderSwap(s1_);
431 const s2 = if (endian == .Little) s2_ else Fe.orderSwap(s2_);
432 try p1.rejectIdentity();
433 var pc1_array: [9]P256 = undefined;
434 const pc1 = if (p1.is_base) basePointPc[0..9] else pc: {
435 pc1_array = precompute(p1, 8);
436 break :pc &pc1_array;
423 };437 };
424 return pcMul(pc, s, true);438 try p2.rejectIdentity();
439 var pc2_array: [9]P256 = undefined;
440 const pc2 = if (p2.is_base) basePointPc[0..9] else pc: {
441 pc2_array = precompute(p2, 8);
442 break :pc &pc2_array;
443 };
444 const e1 = slide(s1);
445 const e2 = slide(s2);
446 var q = P256.identityElement;
447 var pos: usize = 2 * 32 - 1;
448 while (true) : (pos -= 1) {
449 const slot1 = e1[pos];
450 if (slot1 > 0) {
451 q = q.add(pc1[@intCast(usize, slot1)]);
452 } else if (slot1 < 0) {
453 q = q.sub(pc1[@intCast(usize, -slot1)]);
454 }
455 const slot2 = e2[pos];
456 if (slot2 > 0) {
457 q = q.add(pc2[@intCast(usize, slot2)]);
458 } else if (slot2 < 0) {
459 q = q.sub(pc2[@intCast(usize, -slot2)]);
460 }
461 if (pos == 0) break;
462 q = q.dbl().dbl().dbl().dbl();
463 }
464 try q.rejectIdentity();
465 return q;
425 }466 }
426};467};
427468
lib/std/crypto/pcurves/p256/p256_64.zig+40-51
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --no-prefix-fiat --package-name p256 '' 64 '2^256 - 2^224 + 2^192 + 2^96 - 1' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp1// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case UpperCamelCase --no-prefix-fiat --package-name p256 '' 64 '2^256 - 2^224 + 2^192 + 2^96 - 1' mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp
2// curve description (via package name): p2562// curve description (via package name): p256
3// machine_wordsize = 64 (from "64")3// machine_wordsize = 64 (from "64")
4// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp4// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp
...@@ -12,18 +12,25 @@...@@ -12,18 +12,25 @@
12// return values.12// return values.
13//13//
14// Computed values:14// Computed values:
15// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)15// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
16// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)16// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
17// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in17// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
18// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^25618// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
1919
20const std = @import("std");20const std = @import("std");
21const cast = std.meta.cast;21const cast = std.meta.cast;
22const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels22const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels
2323
24pub const Limbs = [4]u64;24// The type MontgomeryDomainFieldElement is a field element in the Montgomery domain.
25// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
26pub const MontgomeryDomainFieldElement = [4]u64;
27
28// The type NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
29// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
30pub const NonMontgomeryDomainFieldElement = [4]u64;
2531
26/// The function addcarryxU64 is an addition with carry.32/// The function addcarryxU64 is an addition with carry.
33///
27/// Postconditions:34/// Postconditions:
28/// out1 = (arg1 + arg2 + arg3) mod 2^6435/// out1 = (arg1 + arg2 + arg3) mod 2^64
29/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋36/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
...@@ -45,6 +52,7 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo...@@ -45,6 +52,7 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
45}52}
4653
47/// The function subborrowxU64 is a subtraction with borrow.54/// The function subborrowxU64 is a subtraction with borrow.
55///
48/// Postconditions:56/// Postconditions:
49/// out1 = (-arg1 + arg2 + -arg3) mod 2^6457/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
50/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋58/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
...@@ -66,6 +74,7 @@ inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) v...@@ -66,6 +74,7 @@ inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) v
66}74}
6775
68/// The function mulxU64 is a multiplication, returning the full double-width result.76/// The function mulxU64 is a multiplication, returning the full double-width result.
77///
69/// Postconditions:78/// Postconditions:
70/// out1 = (arg1 * arg2) mod 2^6479/// out1 = (arg1 * arg2) mod 2^64
71/// out2 = ⌊arg1 * arg2 / 2^64⌋80/// out2 = ⌊arg1 * arg2 / 2^64⌋
...@@ -85,6 +94,7 @@ inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void {...@@ -85,6 +94,7 @@ inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void {
85}94}
8695
87/// The function cmovznzU64 is a single-word conditional move.96/// The function cmovznzU64 is a single-word conditional move.
97///
88/// Postconditions:98/// Postconditions:
89/// out1 = (if arg1 = 0 then arg2 else arg3)99/// out1 = (if arg1 = 0 then arg2 else arg3)
90///100///
...@@ -102,6 +112,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {...@@ -102,6 +112,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
102}112}
103113
104/// The function mul multiplies two field elements in the Montgomery domain.114/// The function mul multiplies two field elements in the Montgomery domain.
115///
105/// Preconditions:116/// Preconditions:
106/// 0 ≤ eval arg1 < m117/// 0 ≤ eval arg1 < m
107/// 0 ≤ eval arg2 < m118/// 0 ≤ eval arg2 < m
...@@ -109,12 +120,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {...@@ -109,12 +120,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
109/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m120/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
110/// 0 ≤ eval out1 < m121/// 0 ≤ eval out1 < m
111///122///
112/// Input Bounds:123pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
113/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
114/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
115/// Output Bounds:
116/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
117pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
118 @setRuntimeSafety(mode == .Debug);124 @setRuntimeSafety(mode == .Debug);
119125
120 const x1 = (arg1[1]);126 const x1 = (arg1[1]);
...@@ -399,17 +405,14 @@ pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -399,17 +405,14 @@ pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
399}405}
400406
401/// The function square squares a field element in the Montgomery domain.407/// The function square squares a field element in the Montgomery domain.
408///
402/// Preconditions:409/// Preconditions:
403/// 0 ≤ eval arg1 < m410/// 0 ≤ eval arg1 < m
404/// Postconditions:411/// Postconditions:
405/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m412/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
406/// 0 ≤ eval out1 < m413/// 0 ≤ eval out1 < m
407///414///
408/// Input Bounds:415pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
409/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
410/// Output Bounds:
411/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
412pub fn square(out1: *[4]u64, arg1: [4]u64) void {
413 @setRuntimeSafety(mode == .Debug);416 @setRuntimeSafety(mode == .Debug);
414417
415 const x1 = (arg1[1]);418 const x1 = (arg1[1]);
...@@ -694,6 +697,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {...@@ -694,6 +697,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
694}697}
695698
696/// The function add adds two field elements in the Montgomery domain.699/// The function add adds two field elements in the Montgomery domain.
700///
697/// Preconditions:701/// Preconditions:
698/// 0 ≤ eval arg1 < m702/// 0 ≤ eval arg1 < m
699/// 0 ≤ eval arg2 < m703/// 0 ≤ eval arg2 < m
...@@ -701,12 +705,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {...@@ -701,12 +705,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
701/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m705/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
702/// 0 ≤ eval out1 < m706/// 0 ≤ eval out1 < m
703///707///
704/// Input Bounds:708pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
705/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
706/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
707/// Output Bounds:
708/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
709pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
710 @setRuntimeSafety(mode == .Debug);709 @setRuntimeSafety(mode == .Debug);
711710
712 var x1: u64 = undefined;711 var x1: u64 = undefined;
...@@ -751,6 +750,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -751,6 +750,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
751}750}
752751
753/// The function sub subtracts two field elements in the Montgomery domain.752/// The function sub subtracts two field elements in the Montgomery domain.
753///
754/// Preconditions:754/// Preconditions:
755/// 0 ≤ eval arg1 < m755/// 0 ≤ eval arg1 < m
756/// 0 ≤ eval arg2 < m756/// 0 ≤ eval arg2 < m
...@@ -758,12 +758,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -758,12 +758,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
758/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m758/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
759/// 0 ≤ eval out1 < m759/// 0 ≤ eval out1 < m
760///760///
761/// Input Bounds:761pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
762/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
763/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
764/// Output Bounds:
765/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
766pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
767 @setRuntimeSafety(mode == .Debug);762 @setRuntimeSafety(mode == .Debug);
768763
769 var x1: u64 = undefined;764 var x1: u64 = undefined;
...@@ -799,17 +794,14 @@ pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -799,17 +794,14 @@ pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
799}794}
800795
801/// The function opp negates a field element in the Montgomery domain.796/// The function opp negates a field element in the Montgomery domain.
797///
802/// Preconditions:798/// Preconditions:
803/// 0 ≤ eval arg1 < m799/// 0 ≤ eval arg1 < m
804/// Postconditions:800/// Postconditions:
805/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m801/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
806/// 0 ≤ eval out1 < m802/// 0 ≤ eval out1 < m
807///803///
808/// Input Bounds:804pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
809/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
810/// Output Bounds:
811/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
812pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
813 @setRuntimeSafety(mode == .Debug);805 @setRuntimeSafety(mode == .Debug);
814806
815 var x1: u64 = undefined;807 var x1: u64 = undefined;
...@@ -845,17 +837,14 @@ pub fn opp(out1: *[4]u64, arg1: [4]u64) void {...@@ -845,17 +837,14 @@ pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
845}837}
846838
847/// The function fromMontgomery translates a field element out of the Montgomery domain.839/// The function fromMontgomery translates a field element out of the Montgomery domain.
840///
848/// Preconditions:841/// Preconditions:
849/// 0 ≤ eval arg1 < m842/// 0 ≤ eval arg1 < m
850/// Postconditions:843/// Postconditions:
851/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m844/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
852/// 0 ≤ eval out1 < m845/// 0 ≤ eval out1 < m
853///846///
854/// Input Bounds:847pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
855/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
856/// Output Bounds:
857/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
858pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
859 @setRuntimeSafety(mode == .Debug);848 @setRuntimeSafety(mode == .Debug);
860849
861 const x1 = (arg1[0]);850 const x1 = (arg1[0]);
...@@ -1001,17 +990,14 @@ pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {...@@ -1001,17 +990,14 @@ pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1001}990}
1002991
1003/// The function toMontgomery translates a field element into the Montgomery domain.992/// The function toMontgomery translates a field element into the Montgomery domain.
993///
1004/// Preconditions:994/// Preconditions:
1005/// 0 ≤ eval arg1 < m995/// 0 ≤ eval arg1 < m
1006/// Postconditions:996/// Postconditions:
1007/// eval (from_montgomery out1) mod m = eval arg1 mod m997/// eval (from_montgomery out1) mod m = eval arg1 mod m
1008/// 0 ≤ eval out1 < m998/// 0 ≤ eval out1 < m
1009///999///
1010/// Input Bounds:1000pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void {
1011/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1012/// Output Bounds:
1013/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1014pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1015 @setRuntimeSafety(mode == .Debug);1001 @setRuntimeSafety(mode == .Debug);
10161002
1017 const x1 = (arg1[1]);1003 const x1 = (arg1[1]);
...@@ -1276,6 +1262,7 @@ pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {...@@ -1276,6 +1262,7 @@ pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1276}1262}
12771263
1278/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.1264/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
1265///
1279/// Preconditions:1266/// Preconditions:
1280/// 0 ≤ eval arg1 < m1267/// 0 ≤ eval arg1 < m
1281/// Postconditions:1268/// Postconditions:
...@@ -1293,6 +1280,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void {...@@ -1293,6 +1280,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void {
1293}1280}
12941281
1295/// The function selectznz is a multi-limb conditional select.1282/// The function selectznz is a multi-limb conditional select.
1283///
1296/// Postconditions:1284/// Postconditions:
1297/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)1285/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
1298///1286///
...@@ -1320,6 +1308,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {...@@ -1320,6 +1308,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
1320}1308}
13211309
1322/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.1310/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
1311///
1323/// Preconditions:1312/// Preconditions:
1324/// 0 ≤ eval arg1 < m1313/// 0 ≤ eval arg1 < m
1325/// Postconditions:1314/// Postconditions:
...@@ -1427,6 +1416,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {...@@ -1427,6 +1416,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
1427}1416}
14281417
1429/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.1418/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
1419///
1430/// Preconditions:1420/// Preconditions:
1431/// 0 ≤ bytes_eval arg1 < m1421/// 0 ≤ bytes_eval arg1 < m
1432/// Postconditions:1422/// Postconditions:
...@@ -1507,14 +1497,12 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {...@@ -1507,14 +1497,12 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
1507}1497}
15081498
1509/// The function setOne returns the field element one in the Montgomery domain.1499/// The function setOne returns the field element one in the Montgomery domain.
1500///
1510/// Postconditions:1501/// Postconditions:
1511/// eval (from_montgomery out1) mod m = 1 mod m1502/// eval (from_montgomery out1) mod m = 1 mod m
1512/// 0 ≤ eval out1 < m1503/// 0 ≤ eval out1 < m
1513///1504///
1514/// Input Bounds:1505pub fn setOne(out1: *MontgomeryDomainFieldElement) void {
1515/// Output Bounds:
1516/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1517pub fn setOne(out1: *[4]u64) void {
1518 @setRuntimeSafety(mode == .Debug);1506 @setRuntimeSafety(mode == .Debug);
15191507
1520 out1[0] = cast(u64, 0x1);1508 out1[0] = cast(u64, 0x1);
...@@ -1524,11 +1512,11 @@ pub fn setOne(out1: *[4]u64) void {...@@ -1524,11 +1512,11 @@ pub fn setOne(out1: *[4]u64) void {
1524}1512}
15251513
1526/// The function msat returns the saturated representation of the prime modulus.1514/// The function msat returns the saturated representation of the prime modulus.
1515///
1527/// Postconditions:1516/// Postconditions:
1528/// twos_complement_eval out1 = m1517/// twos_complement_eval out1 = m
1529/// 0 ≤ eval out1 < m1518/// 0 ≤ eval out1 < m
1530///1519///
1531/// Input Bounds:
1532/// Output Bounds:1520/// Output Bounds:
1533/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]1521/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1534pub fn msat(out1: *[5]u64) void {1522pub fn msat(out1: *[5]u64) void {
...@@ -1542,6 +1530,7 @@ pub fn msat(out1: *[5]u64) void {...@@ -1542,6 +1530,7 @@ pub fn msat(out1: *[5]u64) void {
1542}1530}
15431531
1544/// The function divstep computes a divstep.1532/// The function divstep computes a divstep.
1533///
1545/// Preconditions:1534/// Preconditions:
1546/// 0 ≤ eval arg4 < m1535/// 0 ≤ eval arg4 < m
1547/// 0 ≤ eval arg5 < m1536/// 0 ≤ eval arg5 < m
...@@ -1795,11 +1784,11 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[...@@ -1795,11 +1784,11 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[
1795}1784}
17961785
1797/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).1786/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
1787///
1798/// Postconditions:1788/// Postconditions:
1799/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if (log2 m) + 1 < 46 then ⌊(49 * ((log2 m) + 1) + 80) / 17⌋ else ⌊(49 * ((log2 m) + 1) + 57) / 17⌋)1789/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if ⌊log2 m⌋ + 1 < 46 then ⌊(49 * (⌊log2 m⌋ + 1) + 80) / 17⌋ else ⌊(49 * (⌊log2 m⌋ + 1) + 57) / 17⌋)
1800/// 0 ≤ eval out1 < m1790/// 0 ≤ eval out1 < m
1801///1791///
1802/// Input Bounds:
1803/// Output Bounds:1792/// Output Bounds:
1804/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]1793/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1805pub fn divstepPrecomp(out1: *[4]u64) void {1794pub fn divstepPrecomp(out1: *[4]u64) void {
lib/std/crypto/pcurves/p256/p256_scalar_64.zig+56-67
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1// Autogenerated: './src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --no-prefix-fiat --package-name p256-scalar '' 64 1157920892103562487626974469494075735299969552241357603424222590610685120443691// Autogenerated: 'src/ExtractionOCaml/word_by_word_montgomery' --lang Zig --internal-static --public-function-case camelCase --private-function-case camelCase --public-type-case UpperCamelCase --private-type-case UpperCamelCase --no-prefix-fiat --package-name p256-scalar '' 64 115792089210356248762697446949407573529996955224135760342422259061068512044369 mul square add sub opp from_montgomery to_montgomery nonzero selectznz to_bytes from_bytes one msat divstep divstep_precomp
2// curve description (via package name): p256-scalar2// curve description (via package name): p256-scalar
3// machine_wordsize = 64 (from "64")3// machine_wordsize = 64 (from "64")
4// requested operations: (all)4// requested operations: mul, square, add, sub, opp, from_montgomery, to_montgomery, nonzero, selectznz, to_bytes, from_bytes, one, msat, divstep, divstep_precomp
5// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "115792089210356248762697446949407573529996955224135760342422259061068512044369")5// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "115792089210356248762697446949407573529996955224135760342422259061068512044369")
6//6//
7// NOTE: In addition to the bounds specified above each function, all7// NOTE: In addition to the bounds specified above each function, all
...@@ -12,18 +12,25 @@...@@ -12,18 +12,25 @@
12// return values.12// return values.
13//13//
14// Computed values:14// Computed values:
15// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)15// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
16// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)16// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
17// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in17// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
18// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^25618// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
1919
20const std = @import("std");20const std = @import("std");
21const cast = std.meta.cast;21const cast = std.meta.cast;
22const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels22const mode = std.builtin.mode; // Checked arithmetic is disabled in non-debug modes to avoid side channels
2323
24pub const Limbs = [4]u64;24// The type MontgomeryDomainFieldElement is a field element in the Montgomery domain.
25// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
26pub const MontgomeryDomainFieldElement = [4]u64;
27
28// The type NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
29// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
30pub const NonMontgomeryDomainFieldElement = [4]u64;
2531
26/// The function addcarryxU64 is an addition with carry.32/// The function addcarryxU64 is an addition with carry.
33///
27/// Postconditions:34/// Postconditions:
28/// out1 = (arg1 + arg2 + arg3) mod 2^6435/// out1 = (arg1 + arg2 + arg3) mod 2^64
29/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋36/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
...@@ -45,6 +52,7 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo...@@ -45,6 +52,7 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
45}52}
4653
47/// The function subborrowxU64 is a subtraction with borrow.54/// The function subborrowxU64 is a subtraction with borrow.
55///
48/// Postconditions:56/// Postconditions:
49/// out1 = (-arg1 + arg2 + -arg3) mod 2^6457/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
50/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋58/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
...@@ -66,6 +74,7 @@ inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) v...@@ -66,6 +74,7 @@ inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) v
66}74}
6775
68/// The function mulxU64 is a multiplication, returning the full double-width result.76/// The function mulxU64 is a multiplication, returning the full double-width result.
77///
69/// Postconditions:78/// Postconditions:
70/// out1 = (arg1 * arg2) mod 2^6479/// out1 = (arg1 * arg2) mod 2^64
71/// out2 = ⌊arg1 * arg2 / 2^64⌋80/// out2 = ⌊arg1 * arg2 / 2^64⌋
...@@ -85,6 +94,7 @@ inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void {...@@ -85,6 +94,7 @@ inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void {
85}94}
8695
87/// The function cmovznzU64 is a single-word conditional move.96/// The function cmovznzU64 is a single-word conditional move.
97///
88/// Postconditions:98/// Postconditions:
89/// out1 = (if arg1 = 0 then arg2 else arg3)99/// out1 = (if arg1 = 0 then arg2 else arg3)
90///100///
...@@ -102,6 +112,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {...@@ -102,6 +112,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
102}112}
103113
104/// The function mul multiplies two field elements in the Montgomery domain.114/// The function mul multiplies two field elements in the Montgomery domain.
115///
105/// Preconditions:116/// Preconditions:
106/// 0 ≤ eval arg1 < m117/// 0 ≤ eval arg1 < m
107/// 0 ≤ eval arg2 < m118/// 0 ≤ eval arg2 < m
...@@ -109,12 +120,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {...@@ -109,12 +120,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
109/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m120/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
110/// 0 ≤ eval out1 < m121/// 0 ≤ eval out1 < m
111///122///
112/// Input Bounds:123pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
113/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
114/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
115/// Output Bounds:
116/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
117pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
118 @setRuntimeSafety(mode == .Debug);124 @setRuntimeSafety(mode == .Debug);
119125
120 const x1 = (arg1[1]);126 const x1 = (arg1[1]);
...@@ -447,17 +453,14 @@ pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -447,17 +453,14 @@ pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
447}453}
448454
449/// The function square squares a field element in the Montgomery domain.455/// The function square squares a field element in the Montgomery domain.
456///
450/// Preconditions:457/// Preconditions:
451/// 0 ≤ eval arg1 < m458/// 0 ≤ eval arg1 < m
452/// Postconditions:459/// Postconditions:
453/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m460/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
454/// 0 ≤ eval out1 < m461/// 0 ≤ eval out1 < m
455///462///
456/// Input Bounds:463pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
457/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
458/// Output Bounds:
459/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
460pub fn square(out1: *[4]u64, arg1: [4]u64) void {
461 @setRuntimeSafety(mode == .Debug);464 @setRuntimeSafety(mode == .Debug);
462465
463 const x1 = (arg1[1]);466 const x1 = (arg1[1]);
...@@ -790,6 +793,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {...@@ -790,6 +793,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
790}793}
791794
792/// The function add adds two field elements in the Montgomery domain.795/// The function add adds two field elements in the Montgomery domain.
796///
793/// Preconditions:797/// Preconditions:
794/// 0 ≤ eval arg1 < m798/// 0 ≤ eval arg1 < m
795/// 0 ≤ eval arg2 < m799/// 0 ≤ eval arg2 < m
...@@ -797,12 +801,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {...@@ -797,12 +801,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
797/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m801/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
798/// 0 ≤ eval out1 < m802/// 0 ≤ eval out1 < m
799///803///
800/// Input Bounds:804pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
801/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
802/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
803/// Output Bounds:
804/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
805pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
806 @setRuntimeSafety(mode == .Debug);805 @setRuntimeSafety(mode == .Debug);
807806
808 var x1: u64 = undefined;807 var x1: u64 = undefined;
...@@ -847,6 +846,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -847,6 +846,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
847}846}
848847
849/// The function sub subtracts two field elements in the Montgomery domain.848/// The function sub subtracts two field elements in the Montgomery domain.
849///
850/// Preconditions:850/// Preconditions:
851/// 0 ≤ eval arg1 < m851/// 0 ≤ eval arg1 < m
852/// 0 ≤ eval arg2 < m852/// 0 ≤ eval arg2 < m
...@@ -854,12 +854,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -854,12 +854,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
854/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m854/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
855/// 0 ≤ eval out1 < m855/// 0 ≤ eval out1 < m
856///856///
857/// Input Bounds:857pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
858/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
859/// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
860/// Output Bounds:
861/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
862pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
863 @setRuntimeSafety(mode == .Debug);858 @setRuntimeSafety(mode == .Debug);
864859
865 var x1: u64 = undefined;860 var x1: u64 = undefined;
...@@ -895,17 +890,14 @@ pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {...@@ -895,17 +890,14 @@ pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
895}890}
896891
897/// The function opp negates a field element in the Montgomery domain.892/// The function opp negates a field element in the Montgomery domain.
893///
898/// Preconditions:894/// Preconditions:
899/// 0 ≤ eval arg1 < m895/// 0 ≤ eval arg1 < m
900/// Postconditions:896/// Postconditions:
901/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m897/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
902/// 0 ≤ eval out1 < m898/// 0 ≤ eval out1 < m
903///899///
904/// Input Bounds:900pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
905/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
906/// Output Bounds:
907/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
908pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
909 @setRuntimeSafety(mode == .Debug);901 @setRuntimeSafety(mode == .Debug);
910902
911 var x1: u64 = undefined;903 var x1: u64 = undefined;
...@@ -941,17 +933,14 @@ pub fn opp(out1: *[4]u64, arg1: [4]u64) void {...@@ -941,17 +933,14 @@ pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
941}933}
942934
943/// The function fromMontgomery translates a field element out of the Montgomery domain.935/// The function fromMontgomery translates a field element out of the Montgomery domain.
936///
944/// Preconditions:937/// Preconditions:
945/// 0 ≤ eval arg1 < m938/// 0 ≤ eval arg1 < m
946/// Postconditions:939/// Postconditions:
947/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m940/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
948/// 0 ≤ eval out1 < m941/// 0 ≤ eval out1 < m
949///942///
950/// Input Bounds:943pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
951/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
952/// Output Bounds:
953/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
954pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
955 @setRuntimeSafety(mode == .Debug);944 @setRuntimeSafety(mode == .Debug);
956945
957 const x1 = (arg1[0]);946 const x1 = (arg1[0]);
...@@ -1157,17 +1146,14 @@ pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {...@@ -1157,17 +1146,14 @@ pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1157}1146}
11581147
1159/// The function toMontgomery translates a field element into the Montgomery domain.1148/// The function toMontgomery translates a field element into the Montgomery domain.
1149///
1160/// Preconditions:1150/// Preconditions:
1161/// 0 ≤ eval arg1 < m1151/// 0 ≤ eval arg1 < m
1162/// Postconditions:1152/// Postconditions:
1163/// eval (from_montgomery out1) mod m = eval arg1 mod m1153/// eval (from_montgomery out1) mod m = eval arg1 mod m
1164/// 0 ≤ eval out1 < m1154/// 0 ≤ eval out1 < m
1165///1155///
1166/// Input Bounds:1156pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void {
1167/// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1168/// Output Bounds:
1169/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1170pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1171 @setRuntimeSafety(mode == .Debug);1157 @setRuntimeSafety(mode == .Debug);
11721158
1173 const x1 = (arg1[1]);1159 const x1 = (arg1[1]);
...@@ -1480,6 +1466,7 @@ pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {...@@ -1480,6 +1466,7 @@ pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1480}1466}
14811467
1482/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.1468/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
1469///
1483/// Preconditions:1470/// Preconditions:
1484/// 0 ≤ eval arg1 < m1471/// 0 ≤ eval arg1 < m
1485/// Postconditions:1472/// Postconditions:
...@@ -1497,6 +1484,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void {...@@ -1497,6 +1484,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void {
1497}1484}
14981485
1499/// The function selectznz is a multi-limb conditional select.1486/// The function selectznz is a multi-limb conditional select.
1487///
1500/// Postconditions:1488/// Postconditions:
1501/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)1489/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
1502///1490///
...@@ -1524,6 +1512,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {...@@ -1524,6 +1512,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
1524}1512}
15251513
1526/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.1514/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
1515///
1527/// Preconditions:1516/// Preconditions:
1528/// 0 ≤ eval arg1 < m1517/// 0 ≤ eval arg1 < m
1529/// Postconditions:1518/// Postconditions:
...@@ -1631,6 +1620,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {...@@ -1631,6 +1620,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
1631}1620}
16321621
1633/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.1622/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
1623///
1634/// Preconditions:1624/// Preconditions:
1635/// 0 ≤ bytes_eval arg1 < m1625/// 0 ≤ bytes_eval arg1 < m
1636/// Postconditions:1626/// Postconditions:
...@@ -1711,14 +1701,12 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {...@@ -1711,14 +1701,12 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
1711}1701}
17121702
1713/// The function setOne returns the field element one in the Montgomery domain.1703/// The function setOne returns the field element one in the Montgomery domain.
1704///
1714/// Postconditions:1705/// Postconditions:
1715/// eval (from_montgomery out1) mod m = 1 mod m1706/// eval (from_montgomery out1) mod m = 1 mod m
1716/// 0 ≤ eval out1 < m1707/// 0 ≤ eval out1 < m
1717///1708///
1718/// Input Bounds:1709pub fn setOne(out1: *MontgomeryDomainFieldElement) void {
1719/// Output Bounds:
1720/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1721pub fn setOne(out1: *[4]u64) void {
1722 @setRuntimeSafety(mode == .Debug);1710 @setRuntimeSafety(mode == .Debug);
17231711
1724 out1[0] = 0xc46353d039cdaaf;1712 out1[0] = 0xc46353d039cdaaf;
...@@ -1728,11 +1716,11 @@ pub fn setOne(out1: *[4]u64) void {...@@ -1728,11 +1716,11 @@ pub fn setOne(out1: *[4]u64) void {
1728}1716}
17291717
1730/// The function msat returns the saturated representation of the prime modulus.1718/// The function msat returns the saturated representation of the prime modulus.
1719///
1731/// Postconditions:1720/// Postconditions:
1732/// twos_complement_eval out1 = m1721/// twos_complement_eval out1 = m
1733/// 0 ≤ eval out1 < m1722/// 0 ≤ eval out1 < m
1734///1723///
1735/// Input Bounds:
1736/// Output Bounds:1724/// Output Bounds:
1737/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]1725/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1738pub fn msat(out1: *[5]u64) void {1726pub fn msat(out1: *[5]u64) void {
...@@ -1745,24 +1733,8 @@ pub fn msat(out1: *[5]u64) void {...@@ -1745,24 +1733,8 @@ pub fn msat(out1: *[5]u64) void {
1745 out1[4] = cast(u64, 0x0);1733 out1[4] = cast(u64, 0x0);
1746}1734}
17471735
1748/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
1749/// Postconditions:
1750/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if (log2 m) + 1 < 46 then ⌊(49 * ((log2 m) + 1) + 80) / 17⌋ else ⌊(49 * ((log2 m) + 1) + 57) / 17⌋)
1751/// 0 ≤ eval out1 < m
1752///
1753/// Input Bounds:
1754/// Output Bounds:
1755/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1756pub fn divstepPrecomp(out1: *[4]u64) void {
1757 @setRuntimeSafety(mode == .Debug);
1758
1759 out1[0] = 0xd739262fb7fcfbb5;
1760 out1[1] = 0x8ac6f75d20074414;
1761 out1[2] = 0xc67428bfb5e3c256;
1762 out1[3] = 0x444962f2eda7aedf;
1763}
1764
1765/// The function divstep computes a divstep.1736/// The function divstep computes a divstep.
1737///
1766/// Preconditions:1738/// Preconditions:
1767/// 0 ≤ eval arg4 < m1739/// 0 ≤ eval arg4 < m
1768/// 0 ≤ eval arg5 < m1740/// 0 ≤ eval arg5 < m
...@@ -2014,3 +1986,20 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[...@@ -2014,3 +1986,20 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[
2014 out5[2] = x125;1986 out5[2] = x125;
2015 out5[3] = x126;1987 out5[3] = x126;
2016}1988}
1989
1990/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
1991///
1992/// Postconditions:
1993/// eval (from_montgomery out1) = ⌊(m - 1) / 2⌋^(if ⌊log2 m⌋ + 1 < 46 then ⌊(49 * (⌊log2 m⌋ + 1) + 80) / 17⌋ else ⌊(49 * (⌊log2 m⌋ + 1) + 57) / 17⌋)
1994/// 0 ≤ eval out1 < m
1995///
1996/// Output Bounds:
1997/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1998pub fn divstepPrecomp(out1: *[4]u64) void {
1999 @setRuntimeSafety(mode == .Debug);
2000
2001 out1[0] = 0xd739262fb7fcfbb5;
2002 out1[1] = 0x8ac6f75d20074414;
2003 out1[2] = 0xc67428bfb5e3c256;
2004 out1[3] = 0x444962f2eda7aedf;
2005}
lib/std/crypto/pcurves/tests.zig+10
...@@ -107,3 +107,13 @@ test "p256 neutral element decoding" {...@@ -107,3 +107,13 @@ test "p256 neutral element decoding" {
107 const p = try P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one });107 const p = try P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one });
108 try testing.expectError(error.IdentityElement, p.rejectIdentity());108 try testing.expectError(error.IdentityElement, p.rejectIdentity());
109}109}
110
111test "p256 double base multiplication" {
112 const p1 = P256.basePoint;
113 const p2 = P256.basePoint.dbl();
114 const s1 = [_]u8{0x01} ** 32;
115 const s2 = [_]u8{0x02} ** 32;
116 const pr1 = try P256.mulDoubleBasePublic(p1, s1, p2, s2, .Little);
117 const pr2 = (try p1.mul(s1, .Little)).add(try p2.mul(s2, .Little));
118 try testing.expect(pr1.equivalent(pr2));
119}