authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-09-04 20:16:12+12:00
committergravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-09-04 20:16:12+12:00
log8b50d10a846005f221bf910b3d8928915c126c4c
treefc327f0f6888defe8e02bc02ec160ac889f9d6a6
parent763845f95c33140859aa0297c9495d5f08f9afea

std/crypto: Clean up poly1305/x25519


4 files changed, 448 insertions(+), 463 deletions(-)

std/crypto/index.zig+4-4
......@@ -32,13 +32,13 @@ pub const Poly1305 = @import("poly1305.zig").Poly1305;
3232pub const X25519 = @import("x25519.zig").X25519;
3333
3434test "crypto" {
35 _ = @import("blake2.zig");
36 _ = @import("chacha20.zig");
37 _ = @import("hmac.zig");
3538 _ = @import("md5.zig");
39 _ = @import("poly1305.zig");
3640 _ = @import("sha1.zig");
3741 _ = @import("sha2.zig");
3842 _ = @import("sha3.zig");
39 _ = @import("blake2.zig");
40 _ = @import("hmac.zig");
41 _ = @import("chacha20.zig");
42 _ = @import("poly1305.zig");
4343 _ = @import("x25519.zig");
4444}
std/crypto/poly1305.zig+18-18
......@@ -26,7 +26,7 @@ pub const Poly1305 = struct {
2626 // How many bytes are there in the chunk.
2727 c_idx: usize,
2828
29 fn secure_zero(self: *Poly1305) void {
29 fn secureZero(self: *Self) void {
3030 std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Poly1305)]);
3131 }
3232
......@@ -53,7 +53,7 @@ pub const Poly1305 = struct {
5353 }
5454 // add 2^130 to every input block
5555 ctx.c[4] = 1;
56 poly_clear_c(&ctx);
56 polyClearC(&ctx);
5757
5858 // load r and pad (r has some of its bits cleared)
5959 {
......@@ -85,7 +85,7 @@ pub const Poly1305 = struct {
8585 // ctx->r <= 0ffffffc_0ffffffc_0ffffffc_0fffffff
8686 // Postcondition:
8787 // ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
88 fn poly_block(ctx: *Poly1305) void {
88 fn polyBlock(ctx: *Self) void {
8989 // s = h + c, without carry propagation
9090 const s0 = u64(ctx.h[0]) + ctx.c[0]; // s0 <= 1_fffffffe
9191 const s1 = u64(ctx.h[1]) + ctx.c[1]; // s1 <= 1_fffffffe
......@@ -127,7 +127,7 @@ pub const Poly1305 = struct {
127127 }
128128
129129 // (re-)initializes the input counter and input buffer
130 fn poly_clear_c(ctx: *Poly1305) void {
130 fn polyClearC(ctx: *Self) void {
131131 ctx.c[0] = 0;
132132 ctx.c[1] = 0;
133133 ctx.c[2] = 0;
......@@ -135,32 +135,32 @@ pub const Poly1305 = struct {
135135 ctx.c_idx = 0;
136136 }
137137
138 fn poly_take_input(ctx: *Poly1305, input: u8) void {
138 fn polyTakeInput(ctx: *Self, input: u8) void {
139139 const word = ctx.c_idx >> 2;
140140 const byte = ctx.c_idx & 3;
141141 ctx.c[word] |= std.math.shl(u32, input, byte * 8);
142142 ctx.c_idx += 1;
143143 }
144144
145 fn poly_update(ctx: *Poly1305, msg: []const u8) void {
145 fn polyUpdate(ctx: *Self, msg: []const u8) void {
146146 for (msg) |b| {
147 poly_take_input(ctx, b);
147 polyTakeInput(ctx, b);
148148 if (ctx.c_idx == 16) {
149 poly_block(ctx);
150 poly_clear_c(ctx);
149 polyBlock(ctx);
150 polyClearC(ctx);
151151 }
152152 }
153153 }
154154
155 inline fn alignto(x: usize, block_size: usize) usize {
155 fn alignTo(x: usize, block_size: usize) usize {
156156 return ((~x) +% 1) & (block_size - 1);
157157 }
158158
159159 // Feed data into the MAC context.
160160 pub fn update(ctx: *Self, msg: []const u8) void {
161161 // Align ourselves with block boundaries
162 const alignm = std.math.min(alignto(ctx.c_idx, 16), msg.len);
163 poly_update(ctx, msg[0..alignm]);
162 const alignm = std.math.min(alignTo(ctx.c_idx, 16), msg.len);
163 polyUpdate(ctx, msg[0..alignm]);
164164
165165 var nmsg = msg[alignm..];
166166
......@@ -172,15 +172,15 @@ pub const Poly1305 = struct {
172172 ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little);
173173 ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little);
174174 ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little);
175 poly_block(ctx);
175 polyBlock(ctx);
176176 nmsg = nmsg[16..];
177177 }
178178 if (nb_blocks > 0) {
179 poly_clear_c(ctx);
179 polyClearC(ctx);
180180 }
181181
182182 // remaining bytes
183 poly_update(ctx, nmsg[0..]);
183 polyUpdate(ctx, nmsg[0..]);
184184 }
185185
186186 // Finalize the MAC and output into buffer provided by caller.
......@@ -190,9 +190,9 @@ pub const Poly1305 = struct {
190190 // move the final 1 according to remaining input length
191191 // (We may add less than 2^130 to the last input block)
192192 ctx.c[4] = 0;
193 poly_take_input(ctx, 1);
193 polyTakeInput(ctx, 1);
194194 // one last hash update
195 poly_block(ctx);
195 polyBlock(ctx);
196196 }
197197
198198 // check if we should subtract 2^130-5 by performing the
......@@ -215,7 +215,7 @@ pub const Poly1305 = struct {
215215 writeInt(out[8..], @truncate(u32, uu2), Endian.Little);
216216 writeInt(out[12..], @truncate(u32, uu3), Endian.Little);
217217
218 ctx.secure_zero();
218 ctx.secureZero();
219219 }
220220};
221221
std/crypto/throughput_test.zig-5
......@@ -168,11 +168,6 @@ pub fn main() !void {
168168 }
169169
170170 inline for (hashes) |H| {
171 // TODO: Inverted early continue case here segfaults compiler. Create reduced test case.
172 //
173 // if (filter != null and std.mem.indexOf(u8, H.name, filter.?) == null) {
174 // continue;
175 // }
176171 if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
177172 const throughput = try benchmarkHash(H.ty, mode(32 * MiB));
178173 try printPad(stdout, H.name);
std/crypto/x25519.zig+426-436
......@@ -14,13 +14,13 @@ pub const X25519 = struct {
1414 pub const secret_length = 32;
1515 pub const minimum_key_length = 32;
1616
17 fn trim_scalar(s: []u8) void {
17 fn trimScalar(s: []u8) void {
1818 s[0] &= 248;
1919 s[31] &= 127;
2020 s[31] |= 64;
2121 }
2222
23 fn scalar_bit(s: []const u8, i: usize) i32 {
23 fn scalarBit(s: []const u8, i: usize) i32 {
2424 return (s[i >> 3] >> @intCast(u3, i & 7)) & 1;
2525 }
2626
......@@ -30,7 +30,6 @@ pub const X25519 = struct {
3030 std.debug.assert(public_key.len >= minimum_key_length);
3131
3232 var storage: [7]Fe = undefined;
33
3433 var x1 = &storage[0];
3534 var x2 = &storage[1];
3635 var z2 = &storage[2];
......@@ -40,74 +39,74 @@ pub const X25519 = struct {
4039 var t1 = &storage[6];
4140
4241 // computes the scalar product
43 fe_frombytes(x1, public_key);
42 Fe.fromBytes(x1, public_key);
4443
4544 // restrict the possible scalar values
4645 var e: [32]u8 = undefined;
4746 for (e[0..]) |_, i| {
4847 e[i] = private_key[i];
4948 }
50 trim_scalar(e[0..]);
49 trimScalar(e[0..]);
5150
5251 // computes the actual scalar product (the result is in x2 and z2)
5352
5453 // Montgomery ladder
5554 // In projective coordinates, to avoid divisons: x = X / Z
5655 // We don't care about the y coordinate, it's only 1 bit of information
57 fe_1(x2);
58 fe_0(z2); // "zero" point
59 fe_copy(x3, x1);
60 fe_1(z3);
56 Fe.init1(x2);
57 Fe.init0(z2); // "zero" point
58 Fe.copy(x3, x1);
59 Fe.init1(z3);
6160
6261 var swap: i32 = 0;
6362 var pos: isize = 254;
6463 while (pos >= 0) : (pos -= 1) {
6564 // constant time conditional swap before ladder step
66 const b = scalar_bit(e, @intCast(usize, pos));
65 const b = scalarBit(e, @intCast(usize, pos));
6766 swap ^= b; // xor trick avoids swapping at the end of the loop
68 fe_cswap(x2, x3, swap);
69 fe_cswap(z2, z3, swap);
67 Fe.cswap(x2, x3, swap);
68 Fe.cswap(z2, z3, swap);
7069 swap = b; // anticipates one last swap after the loop
7170
7271 // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3)
7372 // with differential addition
74 fe_sub(t0, x3, z3);
75 fe_sub(t1, x2, z2);
76 fe_add(x2, x2, z2);
77 fe_add(z2, x3, z3);
78 fe_mul(z3, t0, x2);
79 fe_mul(z2, z2, t1);
80 fe_sq(t0, t1);
81 fe_sq(t1, x2);
82 fe_add(x3, z3, z2);
83 fe_sub(z2, z3, z2);
84 fe_mul(x2, t1, t0);
85 fe_sub(t1, t1, t0);
86 fe_sq(z2, z2);
87 fe_mul121666(z3, t1);
88 fe_sq(x3, x3);
89 fe_add(t0, t0, z3);
90 fe_mul(z3, x1, z2);
91 fe_mul(z2, t1, t0);
73 Fe.sub(t0, x3, z3);
74 Fe.sub(t1, x2, z2);
75 Fe.add(x2, x2, z2);
76 Fe.add(z2, x3, z3);
77 Fe.mul(z3, t0, x2);
78 Fe.mul(z2, z2, t1);
79 Fe.sq(t0, t1);
80 Fe.sq(t1, x2);
81 Fe.add(x3, z3, z2);
82 Fe.sub(z2, z3, z2);
83 Fe.mul(x2, t1, t0);
84 Fe.sub(t1, t1, t0);
85 Fe.sq(z2, z2);
86 Fe.mulSmall(z3, t1, 121666);
87 Fe.sq(x3, x3);
88 Fe.add(t0, t0, z3);
89 Fe.mul(z3, x1, z2);
90 Fe.mul(z2, t1, t0);
9291 }
9392
9493 // last swap is necessary to compensate for the xor trick
9594 // Note: after this swap, P3 == P2 + P1.
96 fe_cswap(x2, x3, swap);
97 fe_cswap(z2, z3, swap);
95 Fe.cswap(x2, x3, swap);
96 Fe.cswap(z2, z3, swap);
9897
9998 // normalises the coordinates: x == X / Z
100 fe_invert(z2, z2);
101 fe_mul(x2, x2, z2);
102 fe_tobytes(out, x2);
103
104 x1.secure_zero();
105 x2.secure_zero();
106 x3.secure_zero();
107 t0.secure_zero();
108 t1.secure_zero();
109 z2.secure_zero();
110 z3.secure_zero();
99 Fe.invert(z2, z2);
100 Fe.mul(x2, x2, z2);
101 Fe.toBytes(out, x2);
102
103 x1.secureZero();
104 x2.secureZero();
105 x3.secureZero();
106 t0.secureZero();
107 t1.secureZero();
108 z2.secureZero();
109 z3.secureZero();
111110 std.mem.secureZero(u8, e[0..]);
112111
113112 // Returns false if the output is all zero
......@@ -140,448 +139,439 @@ fn zerocmp(comptime T: type, a: []const T) bool {
140139const Fe = struct {
141140 b: [10]i32,
142141
143 fn secure_zero(self: *Fe) void {
142 fn secureZero(self: *Fe) void {
144143 std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Fe)]);
145144 }
146};
147145
148fn fe_0(h: *Fe) void {
149 for (h.b) |*e| {
150 e.* = 0;
146 fn init0(h: *Fe) void {
147 for (h.b) |*e| {
148 e.* = 0;
149 }
151150 }
152}
153151
154fn fe_1(h: *Fe) void {
155 for (h.b[1..]) |*e| {
156 e.* = 0;
152 fn init1(h: *Fe) void {
153 for (h.b[1..]) |*e| {
154 e.* = 0;
155 }
156 h.b[0] = 1;
157157 }
158 h.b[0] = 1;
159}
160158
161fn fe_copy(h: *Fe, f: *const Fe) void {
162 for (h.b) |_, i| {
163 h.b[i] = f.b[i];
159 fn copy(h: *Fe, f: *const Fe) void {
160 for (h.b) |_, i| {
161 h.b[i] = f.b[i];
162 }
164163 }
165}
166164
167fn fe_neg(h: *Fe, f: *const Fe) void {
168 for (h.b) |_, i| {
169 h.b[i] = -f.b[i];
165 fn neg(h: *Fe, f: *const Fe) void {
166 for (h.b) |_, i| {
167 h.b[i] = -f.b[i];
168 }
170169 }
171}
172170
173fn fe_add(h: *Fe, f: *const Fe, g: *const Fe) void {
174 for (h.b) |_, i| {
175 h.b[i] = f.b[i] + g.b[i];
171 fn add(h: *Fe, f: *const Fe, g: *const Fe) void {
172 for (h.b) |_, i| {
173 h.b[i] = f.b[i] + g.b[i];
174 }
176175 }
177}
178176
179fn fe_sub(h: *Fe, f: *const Fe, g: *const Fe) void {
180 for (h.b) |_, i| {
181 h.b[i] = f.b[i] - g.b[i];
177 fn sub(h: *Fe, f: *const Fe, g: *const Fe) void {
178 for (h.b) |_, i| {
179 h.b[i] = f.b[i] - g.b[i];
180 }
182181 }
183}
184182
185fn fe_cswap(f: *Fe, g: *Fe, b: i32) void {
186 for (f.b) |_, i| {
187 const x = (f.b[i] ^ g.b[i]) & -b;
188 f.b[i] ^= x;
189 g.b[i] ^= x;
183 fn cswap(f: *Fe, g: *Fe, b: i32) void {
184 for (f.b) |_, i| {
185 const x = (f.b[i] ^ g.b[i]) & -b;
186 f.b[i] ^= x;
187 g.b[i] ^= x;
188 }
190189 }
191}
192190
193fn fe_ccopy(f: *Fe, g: *const Fe, b: i32) void {
194 for (f.b) |_, i| {
195 const x = (f.b[i] ^ g.b[i]) & -b;
196 f.b[i] ^= x;
191 fn ccopy(f: *Fe, g: *const Fe, b: i32) void {
192 for (f.b) |_, i| {
193 const x = (f.b[i] ^ g.b[i]) & -b;
194 f.b[i] ^= x;
195 }
197196 }
198}
199
200inline fn carryround(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int, comptime mult: comptime_int) void {
201 const j = (i + 1) % 10;
202
203 c[i] = (t[i] + (i64(1) << shift)) >> (shift + 1);
204 t[j] += c[i] * mult;
205 t[i] -= c[i] * (i64(1) << (shift + 1));
206}
207
208fn feCarry1(h: *Fe, t: []i64) void {
209 var c: [10]i64 = undefined;
210197
211 var sc = c[0..];
212 var st = t[0..];
198 inline fn carryRound(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int, comptime mult: comptime_int) void {
199 const j = (i + 1) % 10;
213200
214 carryround(sc, st, 9, 24, 19);
215 carryround(sc, st, 1, 24, 1);
216 carryround(sc, st, 3, 24, 1);
217 carryround(sc, st, 5, 24, 1);
218 carryround(sc, st, 7, 24, 1);
219 carryround(sc, st, 0, 25, 1);
220 carryround(sc, st, 2, 25, 1);
221 carryround(sc, st, 4, 25, 1);
222 carryround(sc, st, 6, 25, 1);
223 carryround(sc, st, 8, 25, 1);
224
225 for (h.b) |_, i| {
226 h.b[i] = @intCast(i32, t[i]);
201 c[i] = (t[i] + (i64(1) << shift)) >> (shift + 1);
202 t[j] += c[i] * mult;
203 t[i] -= c[i] * (i64(1) << (shift + 1));
227204 }
228}
229205
230fn feCarry2(h: *Fe, t: []i64) void {
231 var c: [10]i64 = undefined;
232
233 var sc = c[0..];
234 var st = t[0..];
235
236 carryround(sc, st, 0, 25, 1);
237 carryround(sc, st, 4, 25, 1);
238 carryround(sc, st, 1, 24, 1);
239 carryround(sc, st, 5, 24, 1);
240 carryround(sc, st, 2, 25, 1);
241 carryround(sc, st, 6, 25, 1);
242 carryround(sc, st, 3, 24, 1);
243 carryround(sc, st, 7, 24, 1);
244 carryround(sc, st, 4, 25, 1);
245 carryround(sc, st, 8, 25, 1);
246 carryround(sc, st, 9, 24, 19);
247 carryround(sc, st, 0, 25, 1);
248
249 for (h.b) |_, i| {
250 h.b[i] = @intCast(i32, t[i]);
206 fn carry1(h: *Fe, t: []i64) void {
207 var c: [10]i64 = undefined;
208
209 var sc = c[0..];
210 var st = t[0..];
211
212 carryRound(sc, st, 9, 24, 19);
213 carryRound(sc, st, 1, 24, 1);
214 carryRound(sc, st, 3, 24, 1);
215 carryRound(sc, st, 5, 24, 1);
216 carryRound(sc, st, 7, 24, 1);
217 carryRound(sc, st, 0, 25, 1);
218 carryRound(sc, st, 2, 25, 1);
219 carryRound(sc, st, 4, 25, 1);
220 carryRound(sc, st, 6, 25, 1);
221 carryRound(sc, st, 8, 25, 1);
222
223 for (h.b) |_, i| {
224 h.b[i] = @intCast(i32, t[i]);
225 }
251226 }
252}
253
254// TODO: Use readInt(u24) but double check alignment since currently it produces different values.
255fn load24_le(s: []const u8) u32 {
256 return s[0] | (u32(s[1]) << 8) | (u32(s[2]) << 16);
257}
258227
259fn fe_frombytes(h: *Fe, s: []const u8) void {
260 std.debug.assert(s.len >= 32);
261
262 var t: [10]i64 = undefined;
228 fn carry2(h: *Fe, t: []i64) void {
229 var c: [10]i64 = undefined;
230
231 var sc = c[0..];
232 var st = t[0..];
233
234 carryRound(sc, st, 0, 25, 1);
235 carryRound(sc, st, 4, 25, 1);
236 carryRound(sc, st, 1, 24, 1);
237 carryRound(sc, st, 5, 24, 1);
238 carryRound(sc, st, 2, 25, 1);
239 carryRound(sc, st, 6, 25, 1);
240 carryRound(sc, st, 3, 24, 1);
241 carryRound(sc, st, 7, 24, 1);
242 carryRound(sc, st, 4, 25, 1);
243 carryRound(sc, st, 8, 25, 1);
244 carryRound(sc, st, 9, 24, 19);
245 carryRound(sc, st, 0, 25, 1);
246
247 for (h.b) |_, i| {
248 h.b[i] = @intCast(i32, t[i]);
249 }
250 }
263251
264 t[0] = readInt(s[0..4], u32, Endian.Little);
265 t[1] = load24_le(s[4..7]) << 6;
266 t[2] = load24_le(s[7..10]) << 5;
267 t[3] = load24_le(s[10..13]) << 3;
268 t[4] = load24_le(s[13..16]) << 2;
269 t[5] = readInt(s[16..20], u32, Endian.Little);
270 t[6] = load24_le(s[20..23]) << 7;
271 t[7] = load24_le(s[23..26]) << 5;
272 t[8] = load24_le(s[26..29]) << 4;
273 t[9] = (load24_le(s[29..32]) & 0x7fffff) << 2;
252 fn fromBytes(h: *Fe, s: []const u8) void {
253 std.debug.assert(s.len >= 32);
274254
275 feCarry1(h, t[0..]);
276}
255 var t: [10]i64 = undefined;
277256
278fn fe_mul_small(h: *Fe, f: *const Fe, comptime g: comptime_int) void {
279 var t: [10]i64 = undefined;
257 t[0] = readInt(s[0..4], u32, Endian.Little);
258 t[1] = readInt(s[4..7], u32, Endian.Little) << 6;
259 t[2] = readInt(s[7..10], u32, Endian.Little) << 5;
260 t[3] = readInt(s[10..13], u32, Endian.Little) << 3;
261 t[4] = readInt(s[13..16], u32, Endian.Little) << 2;
262 t[5] = readInt(s[16..20], u32, Endian.Little);
263 t[6] = readInt(s[20..23], u32, Endian.Little) << 7;
264 t[7] = readInt(s[23..26], u32, Endian.Little) << 5;
265 t[8] = readInt(s[26..29], u32, Endian.Little) << 4;
266 t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2;
280267
281 for (t[0..]) |_, i| {
282 t[i] = i64(f.b[i]) * g;
268 carry1(h, t[0..]);
283269 }
284270
285 feCarry1(h, t[0..]);
286}
287
288fn fe_mul121666(h: *Fe, f: *const Fe) void {
289 fe_mul_small(h, f, 121666);
290}
291
292fn fe_mul(h: *Fe, f1: *const Fe, g1: *const Fe) void {
293 const f = f1.b;
294 const g = g1.b;
295
296 var F: [10]i32 = undefined;
297 var G: [10]i32 = undefined;
298
299 F[1] = f[1] * 2;
300 F[3] = f[3] * 2;
301 F[5] = f[5] * 2;
302 F[7] = f[7] * 2;
303 F[9] = f[9] * 2;
304
305 G[1] = g[1] * 19;
306 G[2] = g[2] * 19;
307 G[3] = g[3] * 19;
308 G[4] = g[4] * 19;
309 G[5] = g[5] * 19;
310 G[6] = g[6] * 19;
311 G[7] = g[7] * 19;
312 G[8] = g[8] * 19;
313 G[9] = g[9] * 19;
314
315 // t's become h
316 var t: [10]i64 = undefined;
317
318 t[0] = f[0] * i64(g[0]) + F[1] * i64(G[9]) + f[2] * i64(G[8]) + F[3] * i64(G[7]) + f[4] * i64(G[6]) + F[5] * i64(G[5]) + f[6] * i64(G[4]) + F[7] * i64(G[3]) + f[8] * i64(G[2]) + F[9] * i64(G[1]);
319 t[1] = f[0] * i64(g[1]) + f[1] * i64(g[0]) + f[2] * i64(G[9]) + f[3] * i64(G[8]) + f[4] * i64(G[7]) + f[5] * i64(G[6]) + f[6] * i64(G[5]) + f[7] * i64(G[4]) + f[8] * i64(G[3]) + f[9] * i64(G[2]);
320 t[2] = f[0] * i64(g[2]) + F[1] * i64(g[1]) + f[2] * i64(g[0]) + F[3] * i64(G[9]) + f[4] * i64(G[8]) + F[5] * i64(G[7]) + f[6] * i64(G[6]) + F[7] * i64(G[5]) + f[8] * i64(G[4]) + F[9] * i64(G[3]);
321 t[3] = f[0] * i64(g[3]) + f[1] * i64(g[2]) + f[2] * i64(g[1]) + f[3] * i64(g[0]) + f[4] * i64(G[9]) + f[5] * i64(G[8]) + f[6] * i64(G[7]) + f[7] * i64(G[6]) + f[8] * i64(G[5]) + f[9] * i64(G[4]);
322 t[4] = f[0] * i64(g[4]) + F[1] * i64(g[3]) + f[2] * i64(g[2]) + F[3] * i64(g[1]) + f[4] * i64(g[0]) + F[5] * i64(G[9]) + f[6] * i64(G[8]) + F[7] * i64(G[7]) + f[8] * i64(G[6]) + F[9] * i64(G[5]);
323 t[5] = f[0] * i64(g[5]) + f[1] * i64(g[4]) + f[2] * i64(g[3]) + f[3] * i64(g[2]) + f[4] * i64(g[1]) + f[5] * i64(g[0]) + f[6] * i64(G[9]) + f[7] * i64(G[8]) + f[8] * i64(G[7]) + f[9] * i64(G[6]);
324 t[6] = f[0] * i64(g[6]) + F[1] * i64(g[5]) + f[2] * i64(g[4]) + F[3] * i64(g[3]) + f[4] * i64(g[2]) + F[5] * i64(g[1]) + f[6] * i64(g[0]) + F[7] * i64(G[9]) + f[8] * i64(G[8]) + F[9] * i64(G[7]);
325 t[7] = f[0] * i64(g[7]) + f[1] * i64(g[6]) + f[2] * i64(g[5]) + f[3] * i64(g[4]) + f[4] * i64(g[3]) + f[5] * i64(g[2]) + f[6] * i64(g[1]) + f[7] * i64(g[0]) + f[8] * i64(G[9]) + f[9] * i64(G[8]);
326 t[8] = f[0] * i64(g[8]) + F[1] * i64(g[7]) + f[2] * i64(g[6]) + F[3] * i64(g[5]) + f[4] * i64(g[4]) + F[5] * i64(g[3]) + f[6] * i64(g[2]) + F[7] * i64(g[1]) + f[8] * i64(g[0]) + F[9] * i64(G[9]);
327 t[9] = f[0] * i64(g[9]) + f[1] * i64(g[8]) + f[2] * i64(g[7]) + f[3] * i64(g[6]) + f[4] * i64(g[5]) + f[5] * i64(g[4]) + f[6] * i64(g[3]) + f[7] * i64(g[2]) + f[8] * i64(g[1]) + f[9] * i64(g[0]);
328
329 feCarry2(h, t[0..]);
330}
271 fn mulSmall(h: *Fe, f: *const Fe, comptime g: comptime_int) void {
272 var t: [10]i64 = undefined;
331273
332// we could use fe_mul() for this, but this is significantly faster
333fn fe_sq(h: *Fe, fz: *const Fe) void {
334 const f0 = fz.b[0];
335 const f1 = fz.b[1];
336 const f2 = fz.b[2];
337 const f3 = fz.b[3];
338 const f4 = fz.b[4];
339 const f5 = fz.b[5];
340 const f6 = fz.b[6];
341 const f7 = fz.b[7];
342 const f8 = fz.b[8];
343 const f9 = fz.b[9];
344
345 const f0_2 = f0 * 2;
346 const f1_2 = f1 * 2;
347 const f2_2 = f2 * 2;
348 const f3_2 = f3 * 2;
349 const f4_2 = f4 * 2;
350 const f5_2 = f5 * 2;
351 const f6_2 = f6 * 2;
352 const f7_2 = f7 * 2;
353 const f5_38 = f5 * 38;
354 const f6_19 = f6 * 19;
355 const f7_38 = f7 * 38;
356 const f8_19 = f8 * 19;
357 const f9_38 = f9 * 38;
358
359 var t: [10]i64 = undefined;
360
361 t[0] = f0 * i64(f0) + f1_2 * i64(f9_38) + f2_2 * i64(f8_19) + f3_2 * i64(f7_38) + f4_2 * i64(f6_19) + f5 * i64(f5_38);
362 t[1] = f0_2 * i64(f1) + f2 * i64(f9_38) + f3_2 * i64(f8_19) + f4 * i64(f7_38) + f5_2 * i64(f6_19);
363 t[2] = f0_2 * i64(f2) + f1_2 * i64(f1) + f3_2 * i64(f9_38) + f4_2 * i64(f8_19) + f5_2 * i64(f7_38) + f6 * i64(f6_19);
364 t[3] = f0_2 * i64(f3) + f1_2 * i64(f2) + f4 * i64(f9_38) + f5_2 * i64(f8_19) + f6 * i64(f7_38);
365 t[4] = f0_2 * i64(f4) + f1_2 * i64(f3_2) + f2 * i64(f2) + f5_2 * i64(f9_38) + f6_2 * i64(f8_19) + f7 * i64(f7_38);
366 t[5] = f0_2 * i64(f5) + f1_2 * i64(f4) + f2_2 * i64(f3) + f6 * i64(f9_38) + f7_2 * i64(f8_19);
367 t[6] = f0_2 * i64(f6) + f1_2 * i64(f5_2) + f2_2 * i64(f4) + f3_2 * i64(f3) + f7_2 * i64(f9_38) + f8 * i64(f8_19);
368 t[7] = f0_2 * i64(f7) + f1_2 * i64(f6) + f2_2 * i64(f5) + f3_2 * i64(f4) + f8 * i64(f9_38);
369 t[8] = f0_2 * i64(f8) + f1_2 * i64(f7_2) + f2_2 * i64(f6) + f3_2 * i64(f5_2) + f4 * i64(f4) + f9 * i64(f9_38);
370 t[9] = f0_2 * i64(f9) + f1_2 * i64(f8) + f2_2 * i64(f7) + f3_2 * i64(f6) + f4 * i64(f5_2);
371
372 feCarry2(h, t[0..]);
373}
274 for (t[0..]) |_, i| {
275 t[i] = i64(f.b[i]) * g;
276 }
374277
375fn fe_sq2(h: *Fe, f: *const Fe) void {
376 fe_sq(h, f);
377 fe_mul_small(h, h, 2);
378}
278 carry1(h, t[0..]);
279 }
379280
380// This could be simplified, but it would be slower
381fn fe_invert(out: *Fe, z: *const Fe) void {
382 var i: usize = undefined;
383
384 var t: [4]Fe = undefined;
385 var t0 = &t[0];
386 var t1 = &t[1];
387 var t2 = &t[2];
388 var t3 = &t[3];
389
390 fe_sq(t0, z);
391 fe_sq(t1, t0);
392 fe_sq(t1, t1);
393 fe_mul(t1, z, t1);
394 fe_mul(t0, t0, t1);
395
396 fe_sq(t2, t0);
397 fe_mul(t1, t1, t2);
398
399 fe_sq(t2, t1);
400 i = 1;
401 while (i < 5) : (i += 1) fe_sq(t2, t2);
402 fe_mul(t1, t2, t1);
403
404 fe_sq(t2, t1);
405 i = 1;
406 while (i < 10) : (i += 1) fe_sq(t2, t2);
407 fe_mul(t2, t2, t1);
408
409 fe_sq(t3, t2);
410 i = 1;
411 while (i < 20) : (i += 1) fe_sq(t3, t3);
412 fe_mul(t2, t3, t2);
413
414 fe_sq(t2, t2);
415 i = 1;
416 while (i < 10) : (i += 1) fe_sq(t2, t2);
417 fe_mul(t1, t2, t1);
418
419 fe_sq(t2, t1);
420 i = 1;
421 while (i < 50) : (i += 1) fe_sq(t2, t2);
422 fe_mul(t2, t2, t1);
423
424 fe_sq(t3, t2);
425 i = 1;
426 while (i < 100) : (i += 1) fe_sq(t3, t3);
427 fe_mul(t2, t3, t2);
428
429 fe_sq(t2, t2);
430 i = 1;
431 while (i < 50) : (i += 1) fe_sq(t2, t2);
432 fe_mul(t1, t2, t1);
433
434 fe_sq(t1, t1);
435 i = 1;
436 while (i < 5) : (i += 1) fe_sq(t1, t1);
437 fe_mul(out, t1, t0);
438
439 t0.secure_zero();
440 t1.secure_zero();
441 t2.secure_zero();
442 t3.secure_zero();
443}
281 fn mul(h: *Fe, f1: *const Fe, g1: *const Fe) void {
282 const f = f1.b;
283 const g = g1.b;
284
285 var F: [10]i32 = undefined;
286 var G: [10]i32 = undefined;
287
288 F[1] = f[1] * 2;
289 F[3] = f[3] * 2;
290 F[5] = f[5] * 2;
291 F[7] = f[7] * 2;
292 F[9] = f[9] * 2;
293
294 G[1] = g[1] * 19;
295 G[2] = g[2] * 19;
296 G[3] = g[3] * 19;
297 G[4] = g[4] * 19;
298 G[5] = g[5] * 19;
299 G[6] = g[6] * 19;
300 G[7] = g[7] * 19;
301 G[8] = g[8] * 19;
302 G[9] = g[9] * 19;
303
304 // t's become h
305 var t: [10]i64 = undefined;
306
307 t[0] = f[0] * i64(g[0]) + F[1] * i64(G[9]) + f[2] * i64(G[8]) + F[3] * i64(G[7]) + f[4] * i64(G[6]) + F[5] * i64(G[5]) + f[6] * i64(G[4]) + F[7] * i64(G[3]) + f[8] * i64(G[2]) + F[9] * i64(G[1]);
308 t[1] = f[0] * i64(g[1]) + f[1] * i64(g[0]) + f[2] * i64(G[9]) + f[3] * i64(G[8]) + f[4] * i64(G[7]) + f[5] * i64(G[6]) + f[6] * i64(G[5]) + f[7] * i64(G[4]) + f[8] * i64(G[3]) + f[9] * i64(G[2]);
309 t[2] = f[0] * i64(g[2]) + F[1] * i64(g[1]) + f[2] * i64(g[0]) + F[3] * i64(G[9]) + f[4] * i64(G[8]) + F[5] * i64(G[7]) + f[6] * i64(G[6]) + F[7] * i64(G[5]) + f[8] * i64(G[4]) + F[9] * i64(G[3]);
310 t[3] = f[0] * i64(g[3]) + f[1] * i64(g[2]) + f[2] * i64(g[1]) + f[3] * i64(g[0]) + f[4] * i64(G[9]) + f[5] * i64(G[8]) + f[6] * i64(G[7]) + f[7] * i64(G[6]) + f[8] * i64(G[5]) + f[9] * i64(G[4]);
311 t[4] = f[0] * i64(g[4]) + F[1] * i64(g[3]) + f[2] * i64(g[2]) + F[3] * i64(g[1]) + f[4] * i64(g[0]) + F[5] * i64(G[9]) + f[6] * i64(G[8]) + F[7] * i64(G[7]) + f[8] * i64(G[6]) + F[9] * i64(G[5]);
312 t[5] = f[0] * i64(g[5]) + f[1] * i64(g[4]) + f[2] * i64(g[3]) + f[3] * i64(g[2]) + f[4] * i64(g[1]) + f[5] * i64(g[0]) + f[6] * i64(G[9]) + f[7] * i64(G[8]) + f[8] * i64(G[7]) + f[9] * i64(G[6]);
313 t[6] = f[0] * i64(g[6]) + F[1] * i64(g[5]) + f[2] * i64(g[4]) + F[3] * i64(g[3]) + f[4] * i64(g[2]) + F[5] * i64(g[1]) + f[6] * i64(g[0]) + F[7] * i64(G[9]) + f[8] * i64(G[8]) + F[9] * i64(G[7]);
314 t[7] = f[0] * i64(g[7]) + f[1] * i64(g[6]) + f[2] * i64(g[5]) + f[3] * i64(g[4]) + f[4] * i64(g[3]) + f[5] * i64(g[2]) + f[6] * i64(g[1]) + f[7] * i64(g[0]) + f[8] * i64(G[9]) + f[9] * i64(G[8]);
315 t[8] = f[0] * i64(g[8]) + F[1] * i64(g[7]) + f[2] * i64(g[6]) + F[3] * i64(g[5]) + f[4] * i64(g[4]) + F[5] * i64(g[3]) + f[6] * i64(g[2]) + F[7] * i64(g[1]) + f[8] * i64(g[0]) + F[9] * i64(G[9]);
316 t[9] = f[0] * i64(g[9]) + f[1] * i64(g[8]) + f[2] * i64(g[7]) + f[3] * i64(g[6]) + f[4] * i64(g[5]) + f[5] * i64(g[4]) + f[6] * i64(g[3]) + f[7] * i64(g[2]) + f[8] * i64(g[1]) + f[9] * i64(g[0]);
317
318 carry2(h, t[0..]);
319 }
444320
445// This could be simplified, but it would be slower
446fn fe_pow22523(out: *Fe, z: *const Fe) void {
447 var i: usize = undefined;
448
449 var t: [3]Fe = undefined;
450 var t0 = &t[0];
451 var t1 = &t[1];
452 var t2 = &t[2];
453
454 fe_sq(t0, z);
455 fe_sq(t1, t0);
456 fe_sq(t1, t1);
457 fe_mul(t1, z, t1);
458 fe_mul(t0, t0, t1);
459
460 fe_sq(t0, t0);
461 fe_mul(t0, t1, t0);
462
463 fe_sq(t1, t0);
464 i = 1;
465 while (i < 5) : (i += 1) fe_sq(t1, t1);
466 fe_mul(t0, t1, t0);
467
468 fe_sq(t1, t0);
469 i = 1;
470 while (i < 10) : (i += 1) fe_sq(t1, t1);
471 fe_mul(t1, t1, t0);
472
473 fe_sq(t2, t1);
474 i = 1;
475 while (i < 20) : (i += 1) fe_sq(t2, t2);
476 fe_mul(t1, t2, t1);
477
478 fe_sq(t1, t1);
479 i = 1;
480 while (i < 10) : (i += 1) fe_sq(t1, t1);
481 fe_mul(t0, t1, t0);
482
483 fe_sq(t1, t0);
484 i = 1;
485 while (i < 50) : (i += 1) fe_sq(t1, t1);
486 fe_mul(t1, t1, t0);
487
488 fe_sq(t2, t1);
489 i = 1;
490 while (i < 100) : (i += 1) fe_sq(t2, t2);
491 fe_mul(t1, t2, t1);
492
493 fe_sq(t1, t1);
494 i = 1;
495 while (i < 50) : (i += 1) fe_sq(t1, t1);
496 fe_mul(t0, t1, t0);
497
498 fe_sq(t0, t0);
499 i = 1;
500 while (i < 2) : (i += 1) fe_sq(t0, t0);
501 fe_mul(out, t0, z);
502
503 t0.secure_zero();
504 t1.secure_zero();
505 t2.secure_zero();
506}
321 // we could use Fe.mul() for this, but this is significantly faster
322 fn sq(h: *Fe, fz: *const Fe) void {
323 const f0 = fz.b[0];
324 const f1 = fz.b[1];
325 const f2 = fz.b[2];
326 const f3 = fz.b[3];
327 const f4 = fz.b[4];
328 const f5 = fz.b[5];
329 const f6 = fz.b[6];
330 const f7 = fz.b[7];
331 const f8 = fz.b[8];
332 const f9 = fz.b[9];
333
334 const f0_2 = f0 * 2;
335 const f1_2 = f1 * 2;
336 const f2_2 = f2 * 2;
337 const f3_2 = f3 * 2;
338 const f4_2 = f4 * 2;
339 const f5_2 = f5 * 2;
340 const f6_2 = f6 * 2;
341 const f7_2 = f7 * 2;
342 const f5_38 = f5 * 38;
343 const f6_19 = f6 * 19;
344 const f7_38 = f7 * 38;
345 const f8_19 = f8 * 19;
346 const f9_38 = f9 * 38;
347
348 var t: [10]i64 = undefined;
349
350 t[0] = f0 * i64(f0) + f1_2 * i64(f9_38) + f2_2 * i64(f8_19) + f3_2 * i64(f7_38) + f4_2 * i64(f6_19) + f5 * i64(f5_38);
351 t[1] = f0_2 * i64(f1) + f2 * i64(f9_38) + f3_2 * i64(f8_19) + f4 * i64(f7_38) + f5_2 * i64(f6_19);
352 t[2] = f0_2 * i64(f2) + f1_2 * i64(f1) + f3_2 * i64(f9_38) + f4_2 * i64(f8_19) + f5_2 * i64(f7_38) + f6 * i64(f6_19);
353 t[3] = f0_2 * i64(f3) + f1_2 * i64(f2) + f4 * i64(f9_38) + f5_2 * i64(f8_19) + f6 * i64(f7_38);
354 t[4] = f0_2 * i64(f4) + f1_2 * i64(f3_2) + f2 * i64(f2) + f5_2 * i64(f9_38) + f6_2 * i64(f8_19) + f7 * i64(f7_38);
355 t[5] = f0_2 * i64(f5) + f1_2 * i64(f4) + f2_2 * i64(f3) + f6 * i64(f9_38) + f7_2 * i64(f8_19);
356 t[6] = f0_2 * i64(f6) + f1_2 * i64(f5_2) + f2_2 * i64(f4) + f3_2 * i64(f3) + f7_2 * i64(f9_38) + f8 * i64(f8_19);
357 t[7] = f0_2 * i64(f7) + f1_2 * i64(f6) + f2_2 * i64(f5) + f3_2 * i64(f4) + f8 * i64(f9_38);
358 t[8] = f0_2 * i64(f8) + f1_2 * i64(f7_2) + f2_2 * i64(f6) + f3_2 * i64(f5_2) + f4 * i64(f4) + f9 * i64(f9_38);
359 t[9] = f0_2 * i64(f9) + f1_2 * i64(f8) + f2_2 * i64(f7) + f3_2 * i64(f6) + f4 * i64(f5_2);
360
361 carry2(h, t[0..]);
362 }
507363
508inline fn tobytesround(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int) void {
509 c[i] = t[i] >> shift;
510 if (i + 1 < 10) {
511 t[i + 1] += c[i];
364 fn sq2(h: *Fe, f: *const Fe) void {
365 Fe.sq(h, f);
366 Fe.mul_small(h, h, 2);
512367 }
513 t[i] -= c[i] * (i32(1) << shift);
514}
515368
516fn fe_tobytes(s: []u8, h: *const Fe) void {
517 std.debug.assert(s.len >= 32);
369 // This could be simplified, but it would be slower
370 fn invert(out: *Fe, z: *const Fe) void {
371 var i: usize = undefined;
372
373 var t: [4]Fe = undefined;
374 var t0 = &t[0];
375 var t1 = &t[1];
376 var t2 = &t[2];
377 var t3 = &t[3];
378
379 Fe.sq(t0, z);
380 Fe.sq(t1, t0);
381 Fe.sq(t1, t1);
382 Fe.mul(t1, z, t1);
383 Fe.mul(t0, t0, t1);
384
385 Fe.sq(t2, t0);
386 Fe.mul(t1, t1, t2);
387
388 Fe.sq(t2, t1);
389 i = 1;
390 while (i < 5) : (i += 1) Fe.sq(t2, t2);
391 Fe.mul(t1, t2, t1);
392
393 Fe.sq(t2, t1);
394 i = 1;
395 while (i < 10) : (i += 1) Fe.sq(t2, t2);
396 Fe.mul(t2, t2, t1);
397
398 Fe.sq(t3, t2);
399 i = 1;
400 while (i < 20) : (i += 1) Fe.sq(t3, t3);
401 Fe.mul(t2, t3, t2);
402
403 Fe.sq(t2, t2);
404 i = 1;
405 while (i < 10) : (i += 1) Fe.sq(t2, t2);
406 Fe.mul(t1, t2, t1);
407
408 Fe.sq(t2, t1);
409 i = 1;
410 while (i < 50) : (i += 1) Fe.sq(t2, t2);
411 Fe.mul(t2, t2, t1);
412
413 Fe.sq(t3, t2);
414 i = 1;
415 while (i < 100) : (i += 1) Fe.sq(t3, t3);
416 Fe.mul(t2, t3, t2);
417
418 Fe.sq(t2, t2);
419 i = 1;
420 while (i < 50) : (i += 1) Fe.sq(t2, t2);
421 Fe.mul(t1, t2, t1);
422
423 Fe.sq(t1, t1);
424 i = 1;
425 while (i < 5) : (i += 1) Fe.sq(t1, t1);
426 Fe.mul(out, t1, t0);
427
428 t0.secureZero();
429 t1.secureZero();
430 t2.secureZero();
431 t3.secureZero();
432 }
518433
519 var t: [10]i64 = undefined;
520 for (h.b[0..]) |_, i| {
521 t[i] = h.b[i];
434 // This could be simplified, but it would be slower
435 fn pow22523(out: *Fe, z: *const Fe) void {
436 var i: usize = undefined;
437
438 var t: [3]Fe = undefined;
439 var t0 = &t[0];
440 var t1 = &t[1];
441 var t2 = &t[2];
442
443 Fe.sq(t0, z);
444 Fe.sq(t1, t0);
445 Fe.sq(t1, t1);
446 Fe.mul(t1, z, t1);
447 Fe.mul(t0, t0, t1);
448
449 Fe.sq(t0, t0);
450 Fe.mul(t0, t1, t0);
451
452 Fe.sq(t1, t0);
453 i = 1;
454 while (i < 5) : (i += 1) Fe.sq(t1, t1);
455 Fe.mul(t0, t1, t0);
456
457 Fe.sq(t1, t0);
458 i = 1;
459 while (i < 10) : (i += 1) Fe.sq(t1, t1);
460 Fe.mul(t1, t1, t0);
461
462 Fe.sq(t2, t1);
463 i = 1;
464 while (i < 20) : (i += 1) Fe.sq(t2, t2);
465 Fe.mul(t1, t2, t1);
466
467 Fe.sq(t1, t1);
468 i = 1;
469 while (i < 10) : (i += 1) Fe.sq(t1, t1);
470 Fe.mul(t0, t1, t0);
471
472 Fe.sq(t1, t0);
473 i = 1;
474 while (i < 50) : (i += 1) Fe.sq(t1, t1);
475 Fe.mul(t1, t1, t0);
476
477 Fe.sq(t2, t1);
478 i = 1;
479 while (i < 100) : (i += 1) Fe.sq(t2, t2);
480 Fe.mul(t1, t2, t1);
481
482 Fe.sq(t1, t1);
483 i = 1;
484 while (i < 50) : (i += 1) Fe.sq(t1, t1);
485 Fe.mul(t0, t1, t0);
486
487 Fe.sq(t0, t0);
488 i = 1;
489 while (i < 2) : (i += 1) Fe.sq(t0, t0);
490 Fe.mul(out, t0, z);
491
492 t0.secureZero();
493 t1.secureZero();
494 t2.secureZero();
522495 }
523496
524 var q = (19 * t[9] + ((i32(1) << 24))) >> 25;
525 {
526 var i: usize = 0;
527 while (i < 5) : (i += 1) {
528 q += t[2 * i];
529 q >>= 26;
530 q += t[2 * i + 1];
531 q >>= 25;
497 inline fn toBytesRound(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int) void {
498 c[i] = t[i] >> shift;
499 if (i + 1 < 10) {
500 t[i + 1] += c[i];
532501 }
502 t[i] -= c[i] * (i32(1) << shift);
533503 }
534 t[0] += 19 * q;
535
536 var c: [10]i64 = undefined;
537504
538 var st = t[0..];
539 var sc = c[0..];
505 fn toBytes(s: []u8, h: *const Fe) void {
506 std.debug.assert(s.len >= 32);
540507
541 tobytesround(sc, st, 0, 26);
542 tobytesround(sc, st, 1, 25);
543 tobytesround(sc, st, 2, 26);
544 tobytesround(sc, st, 3, 25);
545 tobytesround(sc, st, 4, 26);
546 tobytesround(sc, st, 5, 25);
547 tobytesround(sc, st, 6, 26);
548 tobytesround(sc, st, 7, 25);
549 tobytesround(sc, st, 8, 26);
550 tobytesround(sc, st, 9, 25);
508 var t: [10]i64 = undefined;
509 for (h.b[0..]) |_, i| {
510 t[i] = h.b[i];
511 }
551512
552 var ut: [10]u32 = undefined;
553 for (ut[0..]) |_, i| {
554 ut[i] = @bitCast(u32, @intCast(i32, t[i]));
555 }
513 var q = (19 * t[9] + ((i32(1) << 24))) >> 25;
514 {
515 var i: usize = 0;
516 while (i < 5) : (i += 1) {
517 q += t[2 * i];
518 q >>= 26;
519 q += t[2 * i + 1];
520 q >>= 25;
521 }
522 }
523 t[0] += 19 * q;
524
525 var c: [10]i64 = undefined;
526
527 var st = t[0..];
528 var sc = c[0..];
529
530 toBytesRound(sc, st, 0, 26);
531 toBytesRound(sc, st, 1, 25);
532 toBytesRound(sc, st, 2, 26);
533 toBytesRound(sc, st, 3, 25);
534 toBytesRound(sc, st, 4, 26);
535 toBytesRound(sc, st, 5, 25);
536 toBytesRound(sc, st, 6, 26);
537 toBytesRound(sc, st, 7, 25);
538 toBytesRound(sc, st, 8, 26);
539 toBytesRound(sc, st, 9, 25);
540
541 var ut: [10]u32 = undefined;
542 for (ut[0..]) |_, i| {
543 ut[i] = @bitCast(u32, @intCast(i32, t[i]));
544 }
556545
557 writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little);
558 writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little);
559 writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little);
560 writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little);
561 writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little);
562 writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little);
563 writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little);
564 writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little);
546 writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little);
547 writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little);
548 writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little);
549 writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little);
550 writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little);
551 writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little);
552 writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little);
553 writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little);
565554
566 std.mem.secureZero(i64, t[0..]);
567}
555 std.mem.secureZero(i64, t[0..]);
556 }
568557
569// Parity check. Returns 0 if even, 1 if odd
570fn fe_isnegative(f: *const Fe) bool {
571 var s: [32]u8 = undefined;
572 fe_tobytes(s[0..], f);
573 const isneg = s[0] & 1;
574 s.secure_zero();
575 return isneg;
576}
558 // Parity check. Returns 0 if even, 1 if odd
559 fn isNegative(f: *const Fe) bool {
560 var s: [32]u8 = undefined;
561 Fe.toBytes(s[0..], f);
562 const isneg = s[0] & 1;
563 s.secureZero();
564 return isneg;
565 }
577566
578fn fe_isnonzero(f: *const Fe) bool {
579 var s: [32]u8 = undefined;
580 fe_tobytes(s[0..], f);
581 const isnonzero = zerocmp(u8, s[0..]);
582 s.secure_zero();
583 return isneg;
584}
567 fn isNonZero(f: *const Fe) bool {
568 var s: [32]u8 = undefined;
569 Fe.toBytes(s[0..], f);
570 const isnonzero = zerocmp(u8, s[0..]);
571 s.secureZero();
572 return isneg;
573 }
574};
585575
586576test "x25519 rfc7748 vector1" {
587577 const secret_key = "\xa5\x46\xe3\x6b\xf0\x52\x7c\x9d\x3b\x16\x15\x4b\x82\x46\x5e\xdd\x62\x14\x4c\x0a\xc1\xfc\x5a\x18\x50\x6a\x22\x44\xba\x44\x9a\xc4";