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 {
143143 p.t.cMov(a.t, c);
144144 }
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 {
147147 var t = Edwards25519.identityElement;
148148 comptime var i: u8 = 1;
149149 inline while (i < pc.len) : (i += 1) {
......@@ -176,7 +176,7 @@ pub const Edwards25519 = struct {
176176 // Based on real-world benchmarks, we only use this for multi-scalar multiplication.
177177 // NAF could be useful to half the size of precomputation tables, but we intentionally
178178 // 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 {
180180 std.debug.assert(vartime);
181181 const e = slide(s);
182182 var q = Edwards25519.identityElement;
......@@ -196,7 +196,7 @@ pub const Edwards25519 = struct {
196196 }
197197
198198 // 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 {
200200 var q = Edwards25519.identityElement;
201201 var pos: usize = 252;
202202 while (true) : (pos -= 4) {
......@@ -231,11 +231,6 @@ pub const Edwards25519 = struct {
231231 break :pc precompute(Edwards25519.basePoint, 15);
232232 };
233233
234 const basePointPc8 = pc: {
235 @setEvalBranchQuota(10000);
236 break :pc precompute(Edwards25519.basePoint, 8);
237 };
238
239234 /// Multiply an Edwards25519 point by a scalar without clamping it.
240235 /// Return error.WeakPublicKey if the base generates a small-order group,
241236 /// and error.IdentityElement if the result is the identity element.
......@@ -245,33 +240,35 @@ pub const Edwards25519 = struct {
245240 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
246241 break :pc xpc;
247242 };
248 return pcMul16(pc, s, false);
243 return pcMul16(&pc, s, false);
249244 }
250245
251246 /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
252247 /// This can be used for signature verification.
253248 pub fn mulPublic(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
254249 if (p.is_base) {
255 return pcMul16(basePointPc, s, true);
250 return pcMul16(&basePointPc, s, true);
256251 } else {
257252 const pc = precompute(p, 8);
258253 pc[4].rejectIdentity() catch return error.WeakPublicKey;
259 return pcMul(pc, s, true);
254 return pcMul(&pc, s, true);
260255 }
261256 }
262257
263258 /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME*
264259 /// This can be used for signature verification.
265260 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: {
267 const xpc = precompute(p1, 8);
268 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
269 break :pc xpc;
261 var pc1_array: [9]Edwards25519 = undefined;
262 const pc1 = if (p1.is_base) basePointPc[0..9] else pc: {
263 pc1_array = precompute(p1, 8);
264 pc1_array[4].rejectIdentity() catch return error.WeakPublicKey;
265 break :pc &pc1_array;
270266 };
271 const pc2 = if (p2.is_base) basePointPc8 else pc: {
272 const xpc = precompute(p2, 8);
273 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
274 break :pc xpc;
267 var pc2_array: [9]Edwards25519 = undefined;
268 const pc2 = if (p2.is_base) basePointPc[0..9] else pc: {
269 pc2_array = precompute(p2, 8);
270 pc2_array[4].rejectIdentity() catch return error.WeakPublicKey;
271 break :pc &pc2_array;
275272 };
276273 const e1 = slide(s1);
277274 const e2 = slide(s2);
......@@ -301,9 +298,13 @@ pub const Edwards25519 = struct {
301298 /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually
302299 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
303300 var pcs: [count][9]Edwards25519 = undefined;
301
302 var bpc: [9]Edwards25519 = undefined;
303 mem.copy(Edwards25519, bpc[0..], basePointPc[0..bpc.len]);
304
304305 for (ps) |p, i| {
305306 if (p.is_base) {
306 pcs[i] = basePointPc8;
307 pcs[i] = bpc;
307308 } else {
308309 pcs[i] = precompute(p, 8);
309310 pcs[i][4].rejectIdentity() catch return error.WeakPublicKey;
lib/std/crypto/pcurves/common.zig+8-6
......@@ -20,12 +20,13 @@ pub const FieldParams = struct {
2020/// A field element, internally stored in Montgomery domain.
2121pub fn Field(comptime params: FieldParams) type {
2222 const fiat = params.fiat;
23 const Limbs = fiat.Limbs;
23 const MontgomeryDomainFieldElement = fiat.MontgomeryDomainFieldElement;
24 const NonMontgomeryDomainFieldElement = fiat.NonMontgomeryDomainFieldElement;
2425
2526 return struct {
2627 const Fe = @This();
2728
28 limbs: Limbs,
29 limbs: MontgomeryDomainFieldElement,
2930
3031 /// Field size.
3132 pub const field_order = params.field_order;
......@@ -40,7 +41,7 @@ pub fn Field(comptime params: FieldParams) type {
4041 pub const encoded_length = params.encoded_length;
4142
4243 /// Zero.
43 pub const zero: Fe = Fe{ .limbs = mem.zeroes(Limbs) };
44 pub const zero: Fe = Fe{ .limbs = mem.zeroes(MontgomeryDomainFieldElement) };
4445
4546 /// One.
4647 pub const one = one: {
......@@ -73,16 +74,16 @@ pub fn Field(comptime params: FieldParams) type {
7374 pub fn fromBytes(s_: [encoded_length]u8, endian: builtin.Endian) NonCanonicalError!Fe {
7475 var s = if (endian == .Little) s_ else orderSwap(s_);
7576 try rejectNonCanonical(s, .Little);
76 var limbs_z: Limbs = undefined;
77 var limbs_z: NonMontgomeryDomainFieldElement = undefined;
7778 fiat.fromBytes(&limbs_z, s);
78 var limbs: Limbs = undefined;
79 var limbs: MontgomeryDomainFieldElement = undefined;
7980 fiat.toMontgomery(&limbs, limbs_z);
8081 return Fe{ .limbs = limbs };
8182 }
8283
8384 /// Pack a field element.
8485 pub fn toBytes(fe: Fe, endian: builtin.Endian) [encoded_length]u8 {
85 var limbs_z: Limbs = undefined;
86 var limbs_z: NonMontgomeryDomainFieldElement = undefined;
8687 fiat.fromMontgomery(&limbs_z, fe.limbs);
8788 var s: [encoded_length]u8 = undefined;
8889 fiat.toBytes(&s, limbs_z);
......@@ -198,6 +199,7 @@ pub fn Field(comptime params: FieldParams) type {
198199 // Field inversion from https://eprint.iacr.org/2021/549.pdf
199200 pub fn invert(a: Fe) Fe {
200201 const iterations = (49 * field_bits + 57) / 17;
202 const Limbs = @TypeOf(a.limbs);
201203 const Word = @TypeOf(a.limbs[0]);
202204 const XLimbs = [a.limbs.len + 1]Word;
203205
lib/std/crypto/pcurves/p256.zig+60-19
......@@ -286,6 +286,11 @@ pub const P256 = struct {
286286 return p.add(q.neg());
287287 }
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
289294 /// Return affine coordinates.
290295 pub fn affineCoordinates(p: P256) AffineCoordinates {
291296 const zinv = p.z.invert();
......@@ -312,7 +317,7 @@ pub const P256 = struct {
312317 p.z.cMov(a.z, c);
313318 }
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 {
316321 var t = P256.identityElement;
317322 comptime var i: u8 = 1;
318323 inline while (i < pc.len) : (i += 1) {
......@@ -341,7 +346,7 @@ pub const P256 = struct {
341346 return e;
342347 }
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 {
345350 std.debug.assert(vartime);
346351 const e = slide(s);
347352 var q = P256.identityElement;
......@@ -360,7 +365,7 @@ pub const P256 = struct {
360365 return q;
361366 }
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 {
364369 var q = P256.identityElement;
365370 var pos: usize = 252;
366371 while (true) : (pos -= 4) {
......@@ -395,33 +400,69 @@ pub const P256 = struct {
395400 break :pc precompute(P256.basePoint, 15);
396401 };
397402
398 const basePointPc8 = pc: {
399 @setEvalBranchQuota(50000);
400 break :pc precompute(P256.basePoint, 8);
401 };
402
403403 /// Multiply an elliptic curve point by a scalar.
404404 /// Return error.IdentityElement if the result is the identity element.
405405 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
406406 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
407 const pc = if (p.is_base) basePointPc else pc: {
408 try p.rejectIdentity();
409 const xpc = precompute(p, 15);
410 break :pc xpc;
411 };
412 return pcMul16(pc, s, false);
407 if (p.is_base) {
408 return pcMul16(&basePointPc, s, false);
409 }
410 try p.rejectIdentity();
411 const pc = precompute(p, 15);
412 return pcMul16(&pc, s, false);
413413 }
414414
415415 /// Multiply an elliptic curve point by a *PUBLIC* scalar *IN VARIABLE TIME*
416416 /// This can be used for signature verification.
417417 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
418418 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
419 const pc = if (p.is_base) basePointPc8 else pc: {
420 try p.rejectIdentity();
421 const xpc = precompute(p, 8);
422 break :pc xpc;
419 if (p.is_base) {
420 return pcMul16(&basePointPc, s, true);
421 }
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;
423437 };
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;
425466 }
426467};
427468
lib/std/crypto/pcurves/p256/p256_64.zig+40-51
......@@ -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_precomp
1// 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
22// curve description (via package name): p256
33// machine_wordsize = 64 (from "64")
44// 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 @@
1212// return values.
1313//
1414// Computed values:
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)
17// 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^256
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)
17// 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^256
1919
2020const std = @import("std");
2121const cast = std.meta.cast;
2222const 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
2632/// The function addcarryxU64 is an addition with carry.
33///
2734/// Postconditions:
2835/// out1 = (arg1 + arg2 + arg3) mod 2^64
2936/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
......@@ -45,6 +52,7 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
4552}
4653
4754/// The function subborrowxU64 is a subtraction with borrow.
55///
4856/// Postconditions:
4957/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
5058/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
......@@ -66,6 +74,7 @@ inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) v
6674}
6775
6876/// The function mulxU64 is a multiplication, returning the full double-width result.
77///
6978/// Postconditions:
7079/// out1 = (arg1 * arg2) mod 2^64
7180/// out2 = ⌊arg1 * arg2 / 2^64⌋
......@@ -85,6 +94,7 @@ inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void {
8594}
8695
8796/// The function cmovznzU64 is a single-word conditional move.
97///
8898/// Postconditions:
8999/// out1 = (if arg1 = 0 then arg2 else arg3)
90100///
......@@ -102,6 +112,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
102112}
103113
104114/// The function mul multiplies two field elements in the Montgomery domain.
115///
105116/// Preconditions:
106117/// 0 ≤ eval arg1 < m
107118/// 0 ≤ eval arg2 < m
......@@ -109,12 +120,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
109120/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
110121/// 0 ≤ eval out1 < m
111122///
112/// Input Bounds:
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 {
123pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
118124 @setRuntimeSafety(mode == .Debug);
119125
120126 const x1 = (arg1[1]);
......@@ -399,17 +405,14 @@ pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
399405}
400406
401407/// The function square squares a field element in the Montgomery domain.
408///
402409/// Preconditions:
403410/// 0 ≤ eval arg1 < m
404411/// Postconditions:
405412/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
406413/// 0 ≤ eval out1 < m
407414///
408/// Input Bounds:
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 {
415pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
413416 @setRuntimeSafety(mode == .Debug);
414417
415418 const x1 = (arg1[1]);
......@@ -694,6 +697,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
694697}
695698
696699/// The function add adds two field elements in the Montgomery domain.
700///
697701/// Preconditions:
698702/// 0 ≤ eval arg1 < m
699703/// 0 ≤ eval arg2 < m
......@@ -701,12 +705,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
701705/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
702706/// 0 ≤ eval out1 < m
703707///
704/// Input Bounds:
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 {
708pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
710709 @setRuntimeSafety(mode == .Debug);
711710
712711 var x1: u64 = undefined;
......@@ -751,6 +750,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
751750}
752751
753752/// The function sub subtracts two field elements in the Montgomery domain.
753///
754754/// Preconditions:
755755/// 0 ≤ eval arg1 < m
756756/// 0 ≤ eval arg2 < m
......@@ -758,12 +758,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
758758/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
759759/// 0 ≤ eval out1 < m
760760///
761/// Input Bounds:
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 {
761pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
767762 @setRuntimeSafety(mode == .Debug);
768763
769764 var x1: u64 = undefined;
......@@ -799,17 +794,14 @@ pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
799794}
800795
801796/// The function opp negates a field element in the Montgomery domain.
797///
802798/// Preconditions:
803799/// 0 ≤ eval arg1 < m
804800/// Postconditions:
805801/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
806802/// 0 ≤ eval out1 < m
807803///
808/// Input Bounds:
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 {
804pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
813805 @setRuntimeSafety(mode == .Debug);
814806
815807 var x1: u64 = undefined;
......@@ -845,17 +837,14 @@ pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
845837}
846838
847839/// The function fromMontgomery translates a field element out of the Montgomery domain.
840///
848841/// Preconditions:
849842/// 0 ≤ eval arg1 < m
850843/// Postconditions:
851844/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
852845/// 0 ≤ eval out1 < m
853846///
854/// Input Bounds:
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 {
847pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
859848 @setRuntimeSafety(mode == .Debug);
860849
861850 const x1 = (arg1[0]);
......@@ -1001,17 +990,14 @@ pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
1001990}
1002991
1003992/// The function toMontgomery translates a field element into the Montgomery domain.
993///
1004994/// Preconditions:
1005995/// 0 ≤ eval arg1 < m
1006996/// Postconditions:
1007997/// eval (from_montgomery out1) mod m = eval arg1 mod m
1008998/// 0 ≤ eval out1 < m
1009999///
1010/// Input Bounds:
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 {
1000pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void {
10151001 @setRuntimeSafety(mode == .Debug);
10161002
10171003 const x1 = (arg1[1]);
......@@ -1276,6 +1262,7 @@ pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
12761262}
12771263
12781264/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
1265///
12791266/// Preconditions:
12801267/// 0 ≤ eval arg1 < m
12811268/// Postconditions:
......@@ -1293,6 +1280,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void {
12931280}
12941281
12951282/// The function selectznz is a multi-limb conditional select.
1283///
12961284/// Postconditions:
12971285/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
12981286///
......@@ -1320,6 +1308,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
13201308}
13211309
13221310/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
1311///
13231312/// Preconditions:
13241313/// 0 ≤ eval arg1 < m
13251314/// Postconditions:
......@@ -1427,6 +1416,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
14271416}
14281417
14291418/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
1419///
14301420/// Preconditions:
14311421/// 0 ≤ bytes_eval arg1 < m
14321422/// Postconditions:
......@@ -1507,14 +1497,12 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
15071497}
15081498
15091499/// The function setOne returns the field element one in the Montgomery domain.
1500///
15101501/// Postconditions:
15111502/// eval (from_montgomery out1) mod m = 1 mod m
15121503/// 0 ≤ eval out1 < m
15131504///
1514/// Input Bounds:
1515/// Output Bounds:
1516/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1517pub fn setOne(out1: *[4]u64) void {
1505pub fn setOne(out1: *MontgomeryDomainFieldElement) void {
15181506 @setRuntimeSafety(mode == .Debug);
15191507
15201508 out1[0] = cast(u64, 0x1);
......@@ -1524,11 +1512,11 @@ pub fn setOne(out1: *[4]u64) void {
15241512}
15251513
15261514/// The function msat returns the saturated representation of the prime modulus.
1515///
15271516/// Postconditions:
15281517/// twos_complement_eval out1 = m
15291518/// 0 ≤ eval out1 < m
15301519///
1531/// Input Bounds:
15321520/// Output Bounds:
15331521/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
15341522pub fn msat(out1: *[5]u64) void {
......@@ -1542,6 +1530,7 @@ pub fn msat(out1: *[5]u64) void {
15421530}
15431531
15441532/// The function divstep computes a divstep.
1533///
15451534/// Preconditions:
15461535/// 0 ≤ eval arg4 < m
15471536/// 0 ≤ eval arg5 < m
......@@ -1795,11 +1784,11 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[
17951784}
17961785
17971786/// The function divstepPrecomp returns the precomputed value for Bernstein-Yang-inversion (in montgomery form).
1787///
17981788/// 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⌋)
18001790/// 0 ≤ eval out1 < m
18011791///
1802/// Input Bounds:
18031792/// Output Bounds:
18041793/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
18051794pub fn divstepPrecomp(out1: *[4]u64) void {
lib/std/crypto/pcurves/p256/p256_scalar_64.zig+56-67
......@@ -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 115792089210356248762697446949407573529996955224135760342422259061068512044369
1// 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
22// curve description (via package name): p256-scalar
33// 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
55// m = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 (from "115792089210356248762697446949407573529996955224135760342422259061068512044369")
66//
77// NOTE: In addition to the bounds specified above each function, all
......@@ -12,18 +12,25 @@
1212// return values.
1313//
1414// Computed values:
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)
17// 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^256
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)
17// 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^256
1919
2020const std = @import("std");
2121const cast = std.meta.cast;
2222const 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
2632/// The function addcarryxU64 is an addition with carry.
33///
2734/// Postconditions:
2835/// out1 = (arg1 + arg2 + arg3) mod 2^64
2936/// out2 = ⌊(arg1 + arg2 + arg3) / 2^64⌋
......@@ -45,6 +52,7 @@ inline fn addcarryxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) vo
4552}
4653
4754/// The function subborrowxU64 is a subtraction with borrow.
55///
4856/// Postconditions:
4957/// out1 = (-arg1 + arg2 + -arg3) mod 2^64
5058/// out2 = -⌊(-arg1 + arg2 + -arg3) / 2^64⌋
......@@ -66,6 +74,7 @@ inline fn subborrowxU64(out1: *u64, out2: *u1, arg1: u1, arg2: u64, arg3: u64) v
6674}
6775
6876/// The function mulxU64 is a multiplication, returning the full double-width result.
77///
6978/// Postconditions:
7079/// out1 = (arg1 * arg2) mod 2^64
7180/// out2 = ⌊arg1 * arg2 / 2^64⌋
......@@ -85,6 +94,7 @@ inline fn mulxU64(out1: *u64, out2: *u64, arg1: u64, arg2: u64) void {
8594}
8695
8796/// The function cmovznzU64 is a single-word conditional move.
97///
8898/// Postconditions:
8999/// out1 = (if arg1 = 0 then arg2 else arg3)
90100///
......@@ -102,6 +112,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
102112}
103113
104114/// The function mul multiplies two field elements in the Montgomery domain.
115///
105116/// Preconditions:
106117/// 0 ≤ eval arg1 < m
107118/// 0 ≤ eval arg2 < m
......@@ -109,12 +120,7 @@ inline fn cmovznzU64(out1: *u64, arg1: u1, arg2: u64, arg3: u64) void {
109120/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
110121/// 0 ≤ eval out1 < m
111122///
112/// Input Bounds:
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 {
123pub fn mul(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
118124 @setRuntimeSafety(mode == .Debug);
119125
120126 const x1 = (arg1[1]);
......@@ -447,17 +453,14 @@ pub fn mul(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
447453}
448454
449455/// The function square squares a field element in the Montgomery domain.
456///
450457/// Preconditions:
451458/// 0 ≤ eval arg1 < m
452459/// Postconditions:
453460/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
454461/// 0 ≤ eval out1 < m
455462///
456/// Input Bounds:
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 {
463pub fn square(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
461464 @setRuntimeSafety(mode == .Debug);
462465
463466 const x1 = (arg1[1]);
......@@ -790,6 +793,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
790793}
791794
792795/// The function add adds two field elements in the Montgomery domain.
796///
793797/// Preconditions:
794798/// 0 ≤ eval arg1 < m
795799/// 0 ≤ eval arg2 < m
......@@ -797,12 +801,7 @@ pub fn square(out1: *[4]u64, arg1: [4]u64) void {
797801/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
798802/// 0 ≤ eval out1 < m
799803///
800/// Input Bounds:
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 {
804pub fn add(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
806805 @setRuntimeSafety(mode == .Debug);
807806
808807 var x1: u64 = undefined;
......@@ -847,6 +846,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
847846}
848847
849848/// The function sub subtracts two field elements in the Montgomery domain.
849///
850850/// Preconditions:
851851/// 0 ≤ eval arg1 < m
852852/// 0 ≤ eval arg2 < m
......@@ -854,12 +854,7 @@ pub fn add(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
854854/// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
855855/// 0 ≤ eval out1 < m
856856///
857/// Input Bounds:
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 {
857pub fn sub(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement, arg2: MontgomeryDomainFieldElement) void {
863858 @setRuntimeSafety(mode == .Debug);
864859
865860 var x1: u64 = undefined;
......@@ -895,17 +890,14 @@ pub fn sub(out1: *[4]u64, arg1: [4]u64, arg2: [4]u64) void {
895890}
896891
897892/// The function opp negates a field element in the Montgomery domain.
893///
898894/// Preconditions:
899895/// 0 ≤ eval arg1 < m
900896/// Postconditions:
901897/// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
902898/// 0 ≤ eval out1 < m
903899///
904/// Input Bounds:
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 {
900pub fn opp(out1: *MontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
909901 @setRuntimeSafety(mode == .Debug);
910902
911903 var x1: u64 = undefined;
......@@ -941,17 +933,14 @@ pub fn opp(out1: *[4]u64, arg1: [4]u64) void {
941933}
942934
943935/// The function fromMontgomery translates a field element out of the Montgomery domain.
936///
944937/// Preconditions:
945938/// 0 ≤ eval arg1 < m
946939/// Postconditions:
947940/// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
948941/// 0 ≤ eval out1 < m
949942///
950/// Input Bounds:
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 {
943pub fn fromMontgomery(out1: *NonMontgomeryDomainFieldElement, arg1: MontgomeryDomainFieldElement) void {
955944 @setRuntimeSafety(mode == .Debug);
956945
957946 const x1 = (arg1[0]);
......@@ -1157,17 +1146,14 @@ pub fn fromMontgomery(out1: *[4]u64, arg1: [4]u64) void {
11571146}
11581147
11591148/// The function toMontgomery translates a field element into the Montgomery domain.
1149///
11601150/// Preconditions:
11611151/// 0 ≤ eval arg1 < m
11621152/// Postconditions:
11631153/// eval (from_montgomery out1) mod m = eval arg1 mod m
11641154/// 0 ≤ eval out1 < m
11651155///
1166/// Input Bounds:
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 {
1156pub fn toMontgomery(out1: *MontgomeryDomainFieldElement, arg1: NonMontgomeryDomainFieldElement) void {
11711157 @setRuntimeSafety(mode == .Debug);
11721158
11731159 const x1 = (arg1[1]);
......@@ -1480,6 +1466,7 @@ pub fn toMontgomery(out1: *[4]u64, arg1: [4]u64) void {
14801466}
14811467
14821468/// The function nonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
1469///
14831470/// Preconditions:
14841471/// 0 ≤ eval arg1 < m
14851472/// Postconditions:
......@@ -1497,6 +1484,7 @@ pub fn nonzero(out1: *u64, arg1: [4]u64) void {
14971484}
14981485
14991486/// The function selectznz is a multi-limb conditional select.
1487///
15001488/// Postconditions:
15011489/// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
15021490///
......@@ -1524,6 +1512,7 @@ pub fn selectznz(out1: *[4]u64, arg1: u1, arg2: [4]u64, arg3: [4]u64) void {
15241512}
15251513
15261514/// The function toBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
1515///
15271516/// Preconditions:
15281517/// 0 ≤ eval arg1 < m
15291518/// Postconditions:
......@@ -1631,6 +1620,7 @@ pub fn toBytes(out1: *[32]u8, arg1: [4]u64) void {
16311620}
16321621
16331622/// The function fromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
1623///
16341624/// Preconditions:
16351625/// 0 ≤ bytes_eval arg1 < m
16361626/// Postconditions:
......@@ -1711,14 +1701,12 @@ pub fn fromBytes(out1: *[4]u64, arg1: [32]u8) void {
17111701}
17121702
17131703/// The function setOne returns the field element one in the Montgomery domain.
1704///
17141705/// Postconditions:
17151706/// eval (from_montgomery out1) mod m = 1 mod m
17161707/// 0 ≤ eval out1 < m
17171708///
1718/// Input Bounds:
1719/// Output Bounds:
1720/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
1721pub fn setOne(out1: *[4]u64) void {
1709pub fn setOne(out1: *MontgomeryDomainFieldElement) void {
17221710 @setRuntimeSafety(mode == .Debug);
17231711
17241712 out1[0] = 0xc46353d039cdaaf;
......@@ -1728,11 +1716,11 @@ pub fn setOne(out1: *[4]u64) void {
17281716}
17291717
17301718/// The function msat returns the saturated representation of the prime modulus.
1719///
17311720/// Postconditions:
17321721/// twos_complement_eval out1 = m
17331722/// 0 ≤ eval out1 < m
17341723///
1735/// Input Bounds:
17361724/// Output Bounds:
17371725/// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
17381726pub fn msat(out1: *[5]u64) void {
......@@ -1745,24 +1733,8 @@ pub fn msat(out1: *[5]u64) void {
17451733 out1[4] = cast(u64, 0x0);
17461734}
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
17651736/// The function divstep computes a divstep.
1737///
17661738/// Preconditions:
17671739/// 0 ≤ eval arg4 < m
17681740/// 0 ≤ eval arg5 < m
......@@ -2014,3 +1986,20 @@ pub fn divstep(out1: *u64, out2: *[5]u64, out3: *[5]u64, out4: *[4]u64, out5: *[
20141986 out5[2] = x125;
20151987 out5[3] = x126;
20161988}
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" {
107107 const p = try P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one });
108108 try testing.expectError(error.IdentityElement, p.rejectIdentity());
109109}
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}