| ... | @@ -14,13 +14,13 @@ pub const X25519 = struct { | ... | @@ -14,13 +14,13 @@ pub const X25519 = struct { |
| 14 | pub const secret_length = 32; | 14 | pub const secret_length = 32; |
| 15 | pub const minimum_key_length = 32; | 15 | pub const minimum_key_length = 32; |
| 16 | | 16 | |
| 17 | fn trim_scalar(s: []u8) void { | 17 | fn trimScalar(s: []u8) void { |
| 18 | s[0] &= 248; | 18 | s[0] &= 248; |
| 19 | s[31] &= 127; | 19 | s[31] &= 127; |
| 20 | s[31] |= 64; | 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 | return (s[i >> 3] >> @intCast(u3, i & 7)) & 1; | 24 | return (s[i >> 3] >> @intCast(u3, i & 7)) & 1; |
| 25 | } | 25 | } |
| 26 | | 26 | |
| ... | @@ -30,7 +30,6 @@ pub const X25519 = struct { | ... | @@ -30,7 +30,6 @@ pub const X25519 = struct { |
| 30 | std.debug.assert(public_key.len >= minimum_key_length); | 30 | std.debug.assert(public_key.len >= minimum_key_length); |
| 31 | | 31 | |
| 32 | var storage: [7]Fe = undefined; | 32 | var storage: [7]Fe = undefined; |
| 33 | | | |
| 34 | var x1 = &storage[0]; | 33 | var x1 = &storage[0]; |
| 35 | var x2 = &storage[1]; | 34 | var x2 = &storage[1]; |
| 36 | var z2 = &storage[2]; | 35 | var z2 = &storage[2]; |
| ... | @@ -40,74 +39,74 @@ pub const X25519 = struct { | ... | @@ -40,74 +39,74 @@ pub const X25519 = struct { |
| 40 | var t1 = &storage[6]; | 39 | var t1 = &storage[6]; |
| 41 | | 40 | |
| 42 | // computes the scalar product | 41 | // computes the scalar product |
| 43 | fe_frombytes(x1, public_key); | 42 | Fe.fromBytes(x1, public_key); |
| 44 | | 43 | |
| 45 | // restrict the possible scalar values | 44 | // restrict the possible scalar values |
| 46 | var e: [32]u8 = undefined; | 45 | var e: [32]u8 = undefined; |
| 47 | for (e[0..]) |_, i| { | 46 | for (e[0..]) |_, i| { |
| 48 | e[i] = private_key[i]; | 47 | e[i] = private_key[i]; |
| 49 | } | 48 | } |
| 50 | trim_scalar(e[0..]); | 49 | trimScalar(e[0..]); |
| 51 | | 50 | |
| 52 | // computes the actual scalar product (the result is in x2 and z2) | 51 | // computes the actual scalar product (the result is in x2 and z2) |
| 53 | | 52 | |
| 54 | // Montgomery ladder | 53 | // Montgomery ladder |
| 55 | // In projective coordinates, to avoid divisons: x = X / Z | 54 | // In projective coordinates, to avoid divisons: x = X / Z |
| 56 | // We don't care about the y coordinate, it's only 1 bit of information | 55 | // We don't care about the y coordinate, it's only 1 bit of information |
| 57 | fe_1(x2); | 56 | Fe.init1(x2); |
| 58 | fe_0(z2); // "zero" point | 57 | Fe.init0(z2); // "zero" point |
| 59 | fe_copy(x3, x1); | 58 | Fe.copy(x3, x1); |
| 60 | fe_1(z3); | 59 | Fe.init1(z3); |
| 61 | | 60 | |
| 62 | var swap: i32 = 0; | 61 | var swap: i32 = 0; |
| 63 | var pos: isize = 254; | 62 | var pos: isize = 254; |
| 64 | while (pos >= 0) : (pos -= 1) { | 63 | while (pos >= 0) : (pos -= 1) { |
| 65 | // constant time conditional swap before ladder step | 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 | swap ^= b; // xor trick avoids swapping at the end of the loop | 66 | swap ^= b; // xor trick avoids swapping at the end of the loop |
| 68 | fe_cswap(x2, x3, swap); | 67 | Fe.cswap(x2, x3, swap); |
| 69 | fe_cswap(z2, z3, swap); | 68 | Fe.cswap(z2, z3, swap); |
| 70 | swap = b; // anticipates one last swap after the loop | 69 | swap = b; // anticipates one last swap after the loop |
| 71 | | 70 | |
| 72 | // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3) | 71 | // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3) |
| 73 | // with differential addition | 72 | // with differential addition |
| 74 | fe_sub(t0, x3, z3); | 73 | Fe.sub(t0, x3, z3); |
| 75 | fe_sub(t1, x2, z2); | 74 | Fe.sub(t1, x2, z2); |
| 76 | fe_add(x2, x2, z2); | 75 | Fe.add(x2, x2, z2); |
| 77 | fe_add(z2, x3, z3); | 76 | Fe.add(z2, x3, z3); |
| 78 | fe_mul(z3, t0, x2); | 77 | Fe.mul(z3, t0, x2); |
| 79 | fe_mul(z2, z2, t1); | 78 | Fe.mul(z2, z2, t1); |
| 80 | fe_sq(t0, t1); | 79 | Fe.sq(t0, t1); |
| 81 | fe_sq(t1, x2); | 80 | Fe.sq(t1, x2); |
| 82 | fe_add(x3, z3, z2); | 81 | Fe.add(x3, z3, z2); |
| 83 | fe_sub(z2, z3, z2); | 82 | Fe.sub(z2, z3, z2); |
| 84 | fe_mul(x2, t1, t0); | 83 | Fe.mul(x2, t1, t0); |
| 85 | fe_sub(t1, t1, t0); | 84 | Fe.sub(t1, t1, t0); |
| 86 | fe_sq(z2, z2); | 85 | Fe.sq(z2, z2); |
| 87 | fe_mul121666(z3, t1); | 86 | Fe.mulSmall(z3, t1, 121666); |
| 88 | fe_sq(x3, x3); | 87 | Fe.sq(x3, x3); |
| 89 | fe_add(t0, t0, z3); | 88 | Fe.add(t0, t0, z3); |
| 90 | fe_mul(z3, x1, z2); | 89 | Fe.mul(z3, x1, z2); |
| 91 | fe_mul(z2, t1, t0); | 90 | Fe.mul(z2, t1, t0); |
| 92 | } | 91 | } |
| 93 | | 92 | |
| 94 | // last swap is necessary to compensate for the xor trick | 93 | // last swap is necessary to compensate for the xor trick |
| 95 | // Note: after this swap, P3 == P2 + P1. | 94 | // Note: after this swap, P3 == P2 + P1. |
| 96 | fe_cswap(x2, x3, swap); | 95 | Fe.cswap(x2, x3, swap); |
| 97 | fe_cswap(z2, z3, swap); | 96 | Fe.cswap(z2, z3, swap); |
| 98 | | 97 | |
| 99 | // normalises the coordinates: x == X / Z | 98 | // normalises the coordinates: x == X / Z |
| 100 | fe_invert(z2, z2); | 99 | Fe.invert(z2, z2); |
| 101 | fe_mul(x2, x2, z2); | 100 | Fe.mul(x2, x2, z2); |
| 102 | fe_tobytes(out, x2); | 101 | Fe.toBytes(out, x2); |
| 103 | | 102 | |
| 104 | x1.secure_zero(); | 103 | x1.secureZero(); |
| 105 | x2.secure_zero(); | 104 | x2.secureZero(); |
| 106 | x3.secure_zero(); | 105 | x3.secureZero(); |
| 107 | t0.secure_zero(); | 106 | t0.secureZero(); |
| 108 | t1.secure_zero(); | 107 | t1.secureZero(); |
| 109 | z2.secure_zero(); | 108 | z2.secureZero(); |
| 110 | z3.secure_zero(); | 109 | z3.secureZero(); |
| 111 | std.mem.secureZero(u8, e[0..]); | 110 | std.mem.secureZero(u8, e[0..]); |
| 112 | | 111 | |
| 113 | // Returns false if the output is all zero | 112 | // Returns false if the output is all zero |
| ... | @@ -140,448 +139,439 @@ fn zerocmp(comptime T: type, a: []const T) bool { | ... | @@ -140,448 +139,439 @@ fn zerocmp(comptime T: type, a: []const T) bool { |
| 140 | const Fe = struct { | 139 | const Fe = struct { |
| 141 | b: [10]i32, | 140 | b: [10]i32, |
| 142 | | 141 | |
| 143 | fn secure_zero(self: *Fe) void { | 142 | fn secureZero(self: *Fe) void { |
| 144 | std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Fe)]); | 143 | std.mem.secureZero(u8, @ptrCast([*]u8, self)[0..@sizeOf(Fe)]); |
| 145 | } | 144 | } |
| 146 | }; | | |
| 147 | | 145 | |
| 148 | fn fe_0(h: *Fe) void { | 146 | fn init0(h: *Fe) void { |
| 149 | for (h.b) |*e| { | 147 | for (h.b) |*e| { |
| 150 | e.* = 0; | 148 | e.* = 0; |
| | 149 | } |
| 151 | } | 150 | } |
| 152 | } | | |
| 153 | | 151 | |
| 154 | fn fe_1(h: *Fe) void { | 152 | fn init1(h: *Fe) void { |
| 155 | for (h.b[1..]) |*e| { | 153 | for (h.b[1..]) |*e| { |
| 156 | e.* = 0; | 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 { | 159 | fn copy(h: *Fe, f: *const Fe) void { |
| 162 | for (h.b) |_, i| { | 160 | for (h.b) |_, i| { |
| 163 | h.b[i] = f.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 { | 165 | fn neg(h: *Fe, f: *const Fe) void { |
| 168 | for (h.b) |_, i| { | 166 | for (h.b) |_, i| { |
| 169 | h.b[i] = -f.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 { | 171 | fn add(h: *Fe, f: *const Fe, g: *const Fe) void { |
| 174 | for (h.b) |_, i| { | 172 | for (h.b) |_, i| { |
| 175 | h.b[i] = f.b[i] + g.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 { | 177 | fn sub(h: *Fe, f: *const Fe, g: *const Fe) void { |
| 180 | for (h.b) |_, i| { | 178 | for (h.b) |_, i| { |
| 181 | h.b[i] = f.b[i] - g.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 { | 183 | fn cswap(f: *Fe, g: *Fe, b: i32) void { |
| 186 | for (f.b) |_, i| { | 184 | for (f.b) |_, i| { |
| 187 | const x = (f.b[i] ^ g.b[i]) & -b; | 185 | const x = (f.b[i] ^ g.b[i]) & -b; |
| 188 | f.b[i] ^= x; | 186 | f.b[i] ^= x; |
| 189 | g.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 { | 191 | fn ccopy(f: *Fe, g: *const Fe, b: i32) void { |
| 194 | for (f.b) |_, i| { | 192 | for (f.b) |_, i| { |
| 195 | const x = (f.b[i] ^ g.b[i]) & -b; | 193 | const x = (f.b[i] ^ g.b[i]) & -b; |
| 196 | f.b[i] ^= x; | 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..]; | 198 | inline fn carryRound(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int, comptime mult: comptime_int) void { |
| 212 | var st = t[0..]; | 199 | const j = (i + 1) % 10; |
| 213 | | 200 | |
| 214 | carryround(sc, st, 9, 24, 19); | 201 | c[i] = (t[i] + (i64(1) << shift)) >> (shift + 1); |
| 215 | carryround(sc, st, 1, 24, 1); | 202 | t[j] += c[i] * mult; |
| 216 | carryround(sc, st, 3, 24, 1); | 203 | t[i] -= c[i] * (i64(1) << (shift + 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]); | | |
| 227 | } | 204 | } |
| 228 | } | | |
| 229 | | 205 | |
| 230 | fn feCarry2(h: *Fe, t: []i64) void { | 206 | fn carry1(h: *Fe, t: []i64) void { |
| 231 | var c: [10]i64 = undefined; | 207 | var c: [10]i64 = undefined; |
| 232 | | 208 | |
| 233 | var sc = c[0..]; | 209 | var sc = c[0..]; |
| 234 | var st = t[0..]; | 210 | var st = t[0..]; |
| 235 | | 211 | |
| 236 | carryround(sc, st, 0, 25, 1); | 212 | carryRound(sc, st, 9, 24, 19); |
| 237 | carryround(sc, st, 4, 25, 1); | 213 | carryRound(sc, st, 1, 24, 1); |
| 238 | carryround(sc, st, 1, 24, 1); | 214 | carryRound(sc, st, 3, 24, 1); |
| 239 | carryround(sc, st, 5, 24, 1); | 215 | carryRound(sc, st, 5, 24, 1); |
| 240 | carryround(sc, st, 2, 25, 1); | 216 | carryRound(sc, st, 7, 24, 1); |
| 241 | carryround(sc, st, 6, 25, 1); | 217 | carryRound(sc, st, 0, 25, 1); |
| 242 | carryround(sc, st, 3, 24, 1); | 218 | carryRound(sc, st, 2, 25, 1); |
| 243 | carryround(sc, st, 7, 24, 1); | 219 | carryRound(sc, st, 4, 25, 1); |
| 244 | carryround(sc, st, 4, 25, 1); | 220 | carryRound(sc, st, 6, 25, 1); |
| 245 | carryround(sc, st, 8, 25, 1); | 221 | carryRound(sc, st, 8, 25, 1); |
| 246 | carryround(sc, st, 9, 24, 19); | 222 | |
| 247 | carryround(sc, st, 0, 25, 1); | 223 | for (h.b) |_, i| { |
| 248 | | 224 | h.b[i] = @intCast(i32, t[i]); |
| 249 | for (h.b) |_, i| { | 225 | } |
| 250 | h.b[i] = @intCast(i32, t[i]); | | |
| 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 { | 228 | fn carry2(h: *Fe, t: []i64) void { |
| 260 | std.debug.assert(s.len >= 32); | 229 | var c: [10]i64 = undefined; |
| 261 | | 230 | |
| 262 | var t: [10]i64 = undefined; | 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); | 252 | fn fromBytes(h: *Fe, s: []const u8) void { |
| 265 | t[1] = load24_le(s[4..7]) << 6; | 253 | std.debug.assert(s.len >= 32); |
| 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; | | |
| 274 | | 254 | |
| 275 | feCarry1(h, t[0..]); | 255 | var t: [10]i64 = undefined; |
| 276 | } | | |
| 277 | | 256 | |
| 278 | fn fe_mul_small(h: *Fe, f: *const Fe, comptime g: comptime_int) void { | 257 | t[0] = readInt(s[0..4], u32, Endian.Little); |
| 279 | var t: [10]i64 = undefined; | 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| { | 268 | carry1(h, t[0..]); |
| 282 | t[i] = i64(f.b[i]) * g; | | |
| 283 | } | 269 | } |
| 284 | | 270 | |
| 285 | feCarry1(h, t[0..]); | 271 | fn mulSmall(h: *Fe, f: *const Fe, comptime g: comptime_int) void { |
| 286 | } | 272 | var t: [10]i64 = undefined; |
| 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 | } | | |
| 331 | | 273 | |
| 332 | // we could use fe_mul() for this, but this is significantly faster | 274 | for (t[0..]) |_, i| { |
| 333 | fn fe_sq(h: *Fe, fz: *const Fe) void { | 275 | t[i] = i64(f.b[i]) * g; |
| 334 | const f0 = fz.b[0]; | 276 | } |
| 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 | } | | |
| 374 | | 277 | |
| 375 | fn fe_sq2(h: *Fe, f: *const Fe) void { | 278 | carry1(h, t[0..]); |
| 376 | fe_sq(h, f); | 279 | } |
| 377 | fe_mul_small(h, h, 2); | | |
| 378 | } | | |
| 379 | | 280 | |
| 380 | // This could be simplified, but it would be slower | 281 | fn mul(h: *Fe, f1: *const Fe, g1: *const Fe) void { |
| 381 | fn fe_invert(out: *Fe, z: *const Fe) void { | 282 | const f = f1.b; |
| 382 | var i: usize = undefined; | 283 | const g = g1.b; |
| 383 | | 284 | |
| 384 | var t: [4]Fe = undefined; | 285 | var F: [10]i32 = undefined; |
| 385 | var t0 = &t[0]; | 286 | var G: [10]i32 = undefined; |
| 386 | var t1 = &t[1]; | 287 | |
| 387 | var t2 = &t[2]; | 288 | F[1] = f[1] * 2; |
| 388 | var t3 = &t[3]; | 289 | F[3] = f[3] * 2; |
| 389 | | 290 | F[5] = f[5] * 2; |
| 390 | fe_sq(t0, z); | 291 | F[7] = f[7] * 2; |
| 391 | fe_sq(t1, t0); | 292 | F[9] = f[9] * 2; |
| 392 | fe_sq(t1, t1); | 293 | |
| 393 | fe_mul(t1, z, t1); | 294 | G[1] = g[1] * 19; |
| 394 | fe_mul(t0, t0, t1); | 295 | G[2] = g[2] * 19; |
| 395 | | 296 | G[3] = g[3] * 19; |
| 396 | fe_sq(t2, t0); | 297 | G[4] = g[4] * 19; |
| 397 | fe_mul(t1, t1, t2); | 298 | G[5] = g[5] * 19; |
| 398 | | 299 | G[6] = g[6] * 19; |
| 399 | fe_sq(t2, t1); | 300 | G[7] = g[7] * 19; |
| 400 | i = 1; | 301 | G[8] = g[8] * 19; |
| 401 | while (i < 5) : (i += 1) fe_sq(t2, t2); | 302 | G[9] = g[9] * 19; |
| 402 | fe_mul(t1, t2, t1); | 303 | |
| 403 | | 304 | // t's become h |
| 404 | fe_sq(t2, t1); | 305 | var t: [10]i64 = undefined; |
| 405 | i = 1; | 306 | |
| 406 | while (i < 10) : (i += 1) fe_sq(t2, t2); | 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]); |
| 407 | fe_mul(t2, t2, t1); | 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]); |
| 408 | | 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]); |
| 409 | fe_sq(t3, t2); | 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]); |
| 410 | i = 1; | 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]); |
| 411 | while (i < 20) : (i += 1) fe_sq(t3, t3); | 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]); |
| 412 | fe_mul(t2, t3, t2); | 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]); |
| 413 | | 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]); |
| 414 | fe_sq(t2, t2); | 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]); |
| 415 | i = 1; | 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]); |
| 416 | while (i < 10) : (i += 1) fe_sq(t2, t2); | 317 | |
| 417 | fe_mul(t1, t2, t1); | 318 | carry2(h, t[0..]); |
| 418 | | 319 | } |
| 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 | } | | |
| 444 | | 320 | |
| 445 | // This could be simplified, but it would be slower | 321 | // we could use Fe.mul() for this, but this is significantly faster |
| 446 | fn fe_pow22523(out: *Fe, z: *const Fe) void { | 322 | fn sq(h: *Fe, fz: *const Fe) void { |
| 447 | var i: usize = undefined; | 323 | const f0 = fz.b[0]; |
| 448 | | 324 | const f1 = fz.b[1]; |
| 449 | var t: [3]Fe = undefined; | 325 | const f2 = fz.b[2]; |
| 450 | var t0 = &t[0]; | 326 | const f3 = fz.b[3]; |
| 451 | var t1 = &t[1]; | 327 | const f4 = fz.b[4]; |
| 452 | var t2 = &t[2]; | 328 | const f5 = fz.b[5]; |
| 453 | | 329 | const f6 = fz.b[6]; |
| 454 | fe_sq(t0, z); | 330 | const f7 = fz.b[7]; |
| 455 | fe_sq(t1, t0); | 331 | const f8 = fz.b[8]; |
| 456 | fe_sq(t1, t1); | 332 | const f9 = fz.b[9]; |
| 457 | fe_mul(t1, z, t1); | 333 | |
| 458 | fe_mul(t0, t0, t1); | 334 | const f0_2 = f0 * 2; |
| 459 | | 335 | const f1_2 = f1 * 2; |
| 460 | fe_sq(t0, t0); | 336 | const f2_2 = f2 * 2; |
| 461 | fe_mul(t0, t1, t0); | 337 | const f3_2 = f3 * 2; |
| 462 | | 338 | const f4_2 = f4 * 2; |
| 463 | fe_sq(t1, t0); | 339 | const f5_2 = f5 * 2; |
| 464 | i = 1; | 340 | const f6_2 = f6 * 2; |
| 465 | while (i < 5) : (i += 1) fe_sq(t1, t1); | 341 | const f7_2 = f7 * 2; |
| 466 | fe_mul(t0, t1, t0); | 342 | const f5_38 = f5 * 38; |
| 467 | | 343 | const f6_19 = f6 * 19; |
| 468 | fe_sq(t1, t0); | 344 | const f7_38 = f7 * 38; |
| 469 | i = 1; | 345 | const f8_19 = f8 * 19; |
| 470 | while (i < 10) : (i += 1) fe_sq(t1, t1); | 346 | const f9_38 = f9 * 38; |
| 471 | fe_mul(t1, t1, t0); | 347 | |
| 472 | | 348 | var t: [10]i64 = undefined; |
| 473 | fe_sq(t2, t1); | 349 | |
| 474 | i = 1; | 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); |
| 475 | while (i < 20) : (i += 1) fe_sq(t2, t2); | 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); |
| 476 | fe_mul(t1, t2, t1); | 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); |
| 477 | | 353 | t[3] = f0_2 * i64(f3) + f1_2 * i64(f2) + f4 * i64(f9_38) + f5_2 * i64(f8_19) + f6 * i64(f7_38); |
| 478 | fe_sq(t1, t1); | 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); |
| 479 | i = 1; | 355 | t[5] = f0_2 * i64(f5) + f1_2 * i64(f4) + f2_2 * i64(f3) + f6 * i64(f9_38) + f7_2 * i64(f8_19); |
| 480 | while (i < 10) : (i += 1) fe_sq(t1, t1); | 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); |
| 481 | fe_mul(t0, t1, t0); | 357 | t[7] = f0_2 * i64(f7) + f1_2 * i64(f6) + f2_2 * i64(f5) + f3_2 * i64(f4) + f8 * i64(f9_38); |
| 482 | | 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); |
| 483 | fe_sq(t1, t0); | 359 | t[9] = f0_2 * i64(f9) + f1_2 * i64(f8) + f2_2 * i64(f7) + f3_2 * i64(f6) + f4 * i64(f5_2); |
| 484 | i = 1; | 360 | |
| 485 | while (i < 50) : (i += 1) fe_sq(t1, t1); | 361 | carry2(h, t[0..]); |
| 486 | fe_mul(t1, t1, t0); | 362 | } |
| 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 | } | | |
| 507 | | 363 | |
| 508 | inline fn tobytesround(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int) void { | 364 | fn sq2(h: *Fe, f: *const Fe) void { |
| 509 | c[i] = t[i] >> shift; | 365 | Fe.sq(h, f); |
| 510 | if (i + 1 < 10) { | 366 | Fe.mul_small(h, h, 2); |
| 511 | t[i + 1] += c[i]; | | |
| 512 | } | 367 | } |
| 513 | t[i] -= c[i] * (i32(1) << shift); | | |
| 514 | } | | |
| 515 | | 368 | |
| 516 | fn fe_tobytes(s: []u8, h: *const Fe) void { | 369 | // This could be simplified, but it would be slower |
| 517 | std.debug.assert(s.len >= 32); | 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; | 434 | // This could be simplified, but it would be slower |
| 520 | for (h.b[0..]) |_, i| { | 435 | fn pow22523(out: *Fe, z: *const Fe) void { |
| 521 | t[i] = h.b[i]; | 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; | 497 | inline fn toBytesRound(c: []i64, t: []i64, comptime i: comptime_int, comptime shift: comptime_int) void { |
| 525 | { | 498 | c[i] = t[i] >> shift; |
| 526 | var i: usize = 0; | 499 | if (i + 1 < 10) { |
| 527 | while (i < 5) : (i += 1) { | 500 | t[i + 1] += c[i]; |
| 528 | q += t[2 * i]; | | |
| 529 | q >>= 26; | | |
| 530 | q += t[2 * i + 1]; | | |
| 531 | q >>= 25; | | |
| 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..]; | 505 | fn toBytes(s: []u8, h: *const Fe) void { |
| 539 | var sc = c[0..]; | 506 | std.debug.assert(s.len >= 32); |
| 540 | | 507 | |
| 541 | tobytesround(sc, st, 0, 26); | 508 | var t: [10]i64 = undefined; |
| 542 | tobytesround(sc, st, 1, 25); | 509 | for (h.b[0..]) |_, i| { |
| 543 | tobytesround(sc, st, 2, 26); | 510 | t[i] = h.b[i]; |
| 544 | tobytesround(sc, st, 3, 25); | 511 | } |
| 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); | | |
| 551 | | 512 | |
| 552 | var ut: [10]u32 = undefined; | 513 | var q = (19 * t[9] + ((i32(1) << 24))) >> 25; |
| 553 | for (ut[0..]) |_, i| { | 514 | { |
| 554 | ut[i] = @bitCast(u32, @intCast(i32, t[i])); | 515 | var i: usize = 0; |
| 555 | } | 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); | 546 | writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little); |
| 558 | writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little); | 547 | writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little); |
| 559 | writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little); | 548 | writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little); |
| 560 | writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little); | 549 | writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little); |
| 561 | writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little); | 550 | writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little); |
| 562 | writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little); | 551 | writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little); |
| 563 | writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little); | 552 | writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little); |
| 564 | writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little); | 553 | writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little); |
| 565 | | 554 | |
| 566 | std.mem.secureZero(i64, t[0..]); | 555 | std.mem.secureZero(i64, t[0..]); |
| 567 | } | 556 | } |
| 568 | | 557 | |
| 569 | // Parity check. Returns 0 if even, 1 if odd | 558 | // Parity check. Returns 0 if even, 1 if odd |
| 570 | fn fe_isnegative(f: *const Fe) bool { | 559 | fn isNegative(f: *const Fe) bool { |
| 571 | var s: [32]u8 = undefined; | 560 | var s: [32]u8 = undefined; |
| 572 | fe_tobytes(s[0..], f); | 561 | Fe.toBytes(s[0..], f); |
| 573 | const isneg = s[0] & 1; | 562 | const isneg = s[0] & 1; |
| 574 | s.secure_zero(); | 563 | s.secureZero(); |
| 575 | return isneg; | 564 | return isneg; |
| 576 | } | 565 | } |
| 577 | | 566 | |
| 578 | fn fe_isnonzero(f: *const Fe) bool { | 567 | fn isNonZero(f: *const Fe) bool { |
| 579 | var s: [32]u8 = undefined; | 568 | var s: [32]u8 = undefined; |
| 580 | fe_tobytes(s[0..], f); | 569 | Fe.toBytes(s[0..], f); |
| 581 | const isnonzero = zerocmp(u8, s[0..]); | 570 | const isnonzero = zerocmp(u8, s[0..]); |
| 582 | s.secure_zero(); | 571 | s.secureZero(); |
| 583 | return isneg; | 572 | return isneg; |
| 584 | } | 573 | } |
| | 574 | }; |
| 585 | | 575 | |
| 586 | test "x25519 rfc7748 vector1" { | 576 | test "x25519 rfc7748 vector1" { |
| 587 | 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"; | 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"; |