| ... | ... | @@ -14,13 +14,13 @@ pub const X25519 = struct { |
| 14 | 14 | pub const secret_length = 32; |
| 15 | 15 | pub const minimum_key_length = 32; |
| 16 | 16 | |
| 17 | | fn trim_scalar(s: []u8) void { |
| 17 | fn trimScalar(s: []u8) void { |
| 18 | 18 | s[0] &= 248; |
| 19 | 19 | s[31] &= 127; |
| 20 | 20 | s[31] |= 64; |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | | fn scalar_bit(s: []const u8, i: usize) i32 { |
| 23 | fn scalarBit(s: []const u8, i: usize) i32 { |
| 24 | 24 | return (s[i >> 3] >> @intCast(u3, i & 7)) & 1; |
| 25 | 25 | } |
| 26 | 26 | |
| ... | ... | @@ -30,7 +30,6 @@ pub const X25519 = struct { |
| 30 | 30 | std.debug.assert(public_key.len >= minimum_key_length); |
| 31 | 31 | |
| 32 | 32 | var storage: [7]Fe = undefined; |
| 33 | | |
| 34 | 33 | var x1 = &storage[0]; |
| 35 | 34 | var x2 = &storage[1]; |
| 36 | 35 | var z2 = &storage[2]; |
| ... | ... | @@ -40,74 +39,74 @@ pub const X25519 = struct { |
| 40 | 39 | var t1 = &storage[6]; |
| 41 | 40 | |
| 42 | 41 | // computes the scalar product |
| 43 | | fe_frombytes(x1, public_key); |
| 42 | Fe.fromBytes(x1, public_key); |
| 44 | 43 | |
| 45 | 44 | // restrict the possible scalar values |
| 46 | 45 | var e: [32]u8 = undefined; |
| 47 | 46 | for (e[0..]) |_, i| { |
| 48 | 47 | e[i] = private_key[i]; |
| 49 | 48 | } |
| 50 | | trim_scalar(e[0..]); |
| 49 | trimScalar(e[0..]); |
| 51 | 50 | |
| 52 | 51 | // computes the actual scalar product (the result is in x2 and z2) |
| 53 | 52 | |
| 54 | 53 | // Montgomery ladder |
| 55 | 54 | // In projective coordinates, to avoid divisons: x = X / Z |
| 56 | 55 | // 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); |
| 61 | 60 | |
| 62 | 61 | var swap: i32 = 0; |
| 63 | 62 | var pos: isize = 254; |
| 64 | 63 | while (pos >= 0) : (pos -= 1) { |
| 65 | 64 | // constant time conditional swap before ladder step |
| 66 | | const b = scalar_bit(e, @intCast(usize, pos)); |
| 65 | const b = scalarBit(e, @intCast(usize, pos)); |
| 67 | 66 | 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); |
| 70 | 69 | swap = b; // anticipates one last swap after the loop |
| 71 | 70 | |
| 72 | 71 | // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3) |
| 73 | 72 | // 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); |
| 92 | 91 | } |
| 93 | 92 | |
| 94 | 93 | // last swap is necessary to compensate for the xor trick |
| 95 | 94 | // 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); |
| 98 | 97 | |
| 99 | 98 | // 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(); |
| 111 | 110 | std.mem.secureZero(u8, e[0..]); |
| 112 | 111 | |
| 113 | 112 | // Returns false if the output is all zero |
| ... | ... | @@ -140,448 +139,439 @@ fn zerocmp(comptime T: type, a: []const T) bool { |
| 140 | 139 | const Fe = struct { |
| 141 | 140 | b: [10]i32, |
| 142 | 141 | |
| 143 | | fn secure_zero(self: *Fe) void { |
| 142 | fn secureZero(self: *Fe) void { |
| 144 | 143 | std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Fe)]); |
| 145 | 144 | } |
| 146 | | }; |
| 147 | 145 | |
| 148 | | fn 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 | } |
| 151 | 150 | } |
| 152 | | } |
| 153 | 151 | |
| 154 | | fn 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; |
| 157 | 157 | } |
| 158 | | h.b[0] = 1; |
| 159 | | } |
| 160 | 158 | |
| 161 | | fn 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 | } |
| 164 | 163 | } |
| 165 | | } |
| 166 | 164 | |
| 167 | | fn 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 | } |
| 170 | 169 | } |
| 171 | | } |
| 172 | 170 | |
| 173 | | fn 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 | } |
| 176 | 175 | } |
| 177 | | } |
| 178 | 176 | |
| 179 | | fn 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 | } |
| 182 | 181 | } |
| 183 | | } |
| 184 | 182 | |
| 185 | | fn 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 | } |
| 190 | 189 | } |
| 191 | | } |
| 192 | 190 | |
| 193 | | fn 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 | } |
| 197 | 196 | } |
| 198 | | } |
| 199 | | |
| 200 | | inline 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 | | |
| 208 | | fn feCarry1(h: *Fe, t: []i64) void { |
| 209 | | var c: [10]i64 = undefined; |
| 210 | 197 | |
| 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; |
| 213 | 200 | |
| 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)); |
| 227 | 204 | } |
| 228 | | } |
| 229 | 205 | |
| 230 | | fn 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 | } |
| 251 | 226 | } |
| 252 | | } |
| 253 | | |
| 254 | | // TODO: Use readInt(u24) but double check alignment since currently it produces different values. |
| 255 | | fn load24_le(s: []const u8) u32 { |
| 256 | | return s[0] | (u32(s[1]) << 8) | (u32(s[2]) << 16); |
| 257 | | } |
| 258 | 227 | |
| 259 | | fn 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 | } |
| 263 | 251 | |
| 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); |
| 274 | 254 | |
| 275 | | feCarry1(h, t[0..]); |
| 276 | | } |
| 255 | var t: [10]i64 = undefined; |
| 277 | 256 | |
| 278 | | fn 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; |
| 280 | 267 | |
| 281 | | for (t[0..]) |_, i| { |
| 282 | | t[i] = i64(f.b[i]) * g; |
| 268 | carry1(h, t[0..]); |
| 283 | 269 | } |
| 284 | 270 | |
| 285 | | feCarry1(h, t[0..]); |
| 286 | | } |
| 287 | | |
| 288 | | fn fe_mul121666(h: *Fe, f: *const Fe) void { |
| 289 | | fe_mul_small(h, f, 121666); |
| 290 | | } |
| 291 | | |
| 292 | | fn 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; |
| 331 | 273 | |
| 332 | | // we could use fe_mul() for this, but this is significantly faster |
| 333 | | fn 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 | } |
| 374 | 277 | |
| 375 | | fn 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 | } |
| 379 | 280 | |
| 380 | | // This could be simplified, but it would be slower |
| 381 | | fn 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 | } |
| 444 | 320 | |
| 445 | | // This could be simplified, but it would be slower |
| 446 | | fn 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 | } |
| 507 | 363 | |
| 508 | | inline 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); |
| 512 | 367 | } |
| 513 | | t[i] -= c[i] * (i32(1) << shift); |
| 514 | | } |
| 515 | 368 | |
| 516 | | fn 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 | } |
| 518 | 433 | |
| 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(); |
| 522 | 495 | } |
| 523 | 496 | |
| 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]; |
| 532 | 501 | } |
| 502 | t[i] -= c[i] * (i32(1) << shift); |
| 533 | 503 | } |
| 534 | | t[0] += 19 * q; |
| 535 | | |
| 536 | | var c: [10]i64 = undefined; |
| 537 | 504 | |
| 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); |
| 540 | 507 | |
| 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 | } |
| 551 | 512 | |
| 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 | } |
| 556 | 545 | |
| 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); |
| 565 | 554 | |
| 566 | | std.mem.secureZero(i64, t[0..]); |
| 567 | | } |
| 555 | std.mem.secureZero(i64, t[0..]); |
| 556 | } |
| 568 | 557 | |
| 569 | | // Parity check. Returns 0 if even, 1 if odd |
| 570 | | fn 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 | } |
| 577 | 566 | |
| 578 | | fn 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 | }; |
| 585 | 575 | |
| 586 | 576 | test "x25519 rfc7748 vector1" { |
| 587 | 577 | 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"; |