| ... | ... | @@ -144,98 +144,147 @@ pub const Edwards25519 = struct { |
| 144 | 144 | p.t.cMov(a.t, c); |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | | inline fn pcSelect(pc: [16]Edwards25519, b: u8) Edwards25519 { |
| 147 | inline fn pcSelect(comptime n: usize, pc: [n]Edwards25519, b: u8) Edwards25519 { |
| 148 | 148 | var t = Edwards25519.identityElement; |
| 149 | | comptime var i: u8 = 0; |
| 150 | | inline while (i < 16) : (i += 1) { |
| 149 | comptime var i: u8 = 1; |
| 150 | inline while (i < pc.len) : (i += 1) { |
| 151 | 151 | t.cMov(pc[i], ((@as(usize, b ^ i) -% 1) >> 8) & 1); |
| 152 | 152 | } |
| 153 | 153 | return t; |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | | fn pcMul(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) !Edwards25519 { |
| 156 | fn nonAdjacentForm(s: [32]u8) [2 * 32]i8 { |
| 157 | var e: [2 * 32]i8 = undefined; |
| 158 | for (s) |x, i| { |
| 159 | e[i * 2 + 0] = @as(i8, @truncate(u4, x)); |
| 160 | e[i * 2 + 1] = @as(i8, @truncate(u4, x >> 4)); |
| 161 | } |
| 162 | // Now, e[0..63] is between 0 and 15, e[63] is between 0 and 7 |
| 163 | var carry: i8 = 0; |
| 164 | for (e[0..63]) |*x| { |
| 165 | x.* += carry; |
| 166 | carry = (x.* + 8) >> 4; |
| 167 | x.* -= carry * 16; |
| 168 | } |
| 169 | e[63] += carry; |
| 170 | // Now, e[*] is between -8 and 8, including e[63] |
| 171 | return e; |
| 172 | } |
| 173 | |
| 174 | // Scalar multiplication with a 4-bit window and the first 8 multiples. |
| 175 | // This requires the scalar to be converted to non-adjacent form. |
| 176 | // Based on real-world benchmarks, we only use this for multi-scalar multiplication. |
| 177 | // NAF could be useful to half the size of precomputation tables, but we intentionally |
| 178 | // avoid these to keep the standard library lightweight. |
| 179 | fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) !Edwards25519 { |
| 180 | std.debug.assert(vartime); |
| 181 | const e = nonAdjacentForm(s); |
| 182 | var q = Edwards25519.identityElement; |
| 183 | var pos: usize = 2 * 32 - 1; |
| 184 | while (true) : (pos -= 1) { |
| 185 | const slot = e[pos]; |
| 186 | if (slot > 0) { |
| 187 | q = q.add(pc[@intCast(usize, slot)]); |
| 188 | } else if (slot < 0) { |
| 189 | q = q.sub(pc[@intCast(usize, -slot)]); |
| 190 | } |
| 191 | if (pos == 0) break; |
| 192 | q = q.dbl().dbl().dbl().dbl(); |
| 193 | } |
| 194 | try q.rejectIdentity(); |
| 195 | return q; |
| 196 | } |
| 197 | |
| 198 | // Scalar multiplication with a 4-bit window and the first 15 multiples. |
| 199 | fn pcMul16(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) !Edwards25519 { |
| 157 | 200 | var q = Edwards25519.identityElement; |
| 158 | 201 | var pos: usize = 252; |
| 159 | 202 | while (true) : (pos -= 4) { |
| 160 | | q = q.dbl().dbl().dbl().dbl(); |
| 161 | | const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf; |
| 203 | const slot = @truncate(u4, (s[pos >> 3] >> @truncate(u3, pos))); |
| 162 | 204 | if (vartime) { |
| 163 | | if (bit != 0) { |
| 164 | | q = q.add(pc[bit]); |
| 205 | if (slot != 0) { |
| 206 | q = q.add(pc[slot]); |
| 165 | 207 | } |
| 166 | 208 | } else { |
| 167 | | q = q.add(pcSelect(pc, bit)); |
| 209 | q = q.add(pcSelect(16, pc, slot)); |
| 168 | 210 | } |
| 169 | 211 | if (pos == 0) break; |
| 212 | q = q.dbl().dbl().dbl().dbl(); |
| 170 | 213 | } |
| 171 | 214 | try q.rejectIdentity(); |
| 172 | 215 | return q; |
| 173 | 216 | } |
| 174 | 217 | |
| 175 | | fn precompute(p: Edwards25519) [16]Edwards25519 { |
| 176 | | var pc: [16]Edwards25519 = undefined; |
| 218 | fn precompute(p: Edwards25519, comptime count: usize) [1 + count]Edwards25519 { |
| 219 | var pc: [1 + count]Edwards25519 = undefined; |
| 177 | 220 | pc[0] = Edwards25519.identityElement; |
| 178 | 221 | pc[1] = p; |
| 179 | 222 | var i: usize = 2; |
| 180 | | while (i < 16) : (i += 1) { |
| 223 | while (i <= count) : (i += 1) { |
| 181 | 224 | pc[i] = pc[i - 1].add(p); |
| 182 | 225 | } |
| 183 | 226 | return pc; |
| 184 | 227 | } |
| 185 | 228 | |
| 229 | const basePointPc = comptime pc: { |
| 230 | @setEvalBranchQuota(10000); |
| 231 | break :pc precompute(Edwards25519.basePoint, 15); |
| 232 | }; |
| 233 | |
| 186 | 234 | /// Multiply an Edwards25519 point by a scalar without clamping it. |
| 187 | 235 | /// Return error.WeakPublicKey if the resulting point is |
| 188 | 236 | /// the identity element. |
| 189 | 237 | pub fn mul(p: Edwards25519, s: [32]u8) !Edwards25519 { |
| 190 | | var pc: [16]Edwards25519 = undefined; |
| 191 | | if (p.is_base) { |
| 192 | | @setEvalBranchQuota(10000); |
| 193 | | pc = comptime precompute(Edwards25519.basePoint); |
| 194 | | } else { |
| 195 | | pc = precompute(p); |
| 196 | | pc[4].rejectIdentity() catch |_| return error.WeakPublicKey; |
| 197 | | } |
| 198 | | return pcMul(pc, s, false); |
| 238 | const pc = if (p.is_base) basePointPc else pc: { |
| 239 | const xpc = precompute(p, 15); |
| 240 | xpc[4].rejectIdentity() catch |_| return error.WeakPublicKey; |
| 241 | break :pc xpc; |
| 242 | }; |
| 243 | return pcMul16(pc, s, false); |
| 199 | 244 | } |
| 200 | 245 | |
| 201 | 246 | /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME* |
| 202 | 247 | /// This can be used for signature verification. |
| 203 | 248 | pub fn mulPublic(p: Edwards25519, s: [32]u8) !Edwards25519 { |
| 204 | | var pc: [16]Edwards25519 = undefined; |
| 205 | 249 | if (p.is_base) { |
| 206 | | @setEvalBranchQuota(10000); |
| 207 | | pc = comptime precompute(Edwards25519.basePoint); |
| 250 | return pcMul16(basePointPc, s, true); |
| 208 | 251 | } else { |
| 209 | | pc = precompute(p); |
| 252 | const pc = precompute(p, 8); |
| 210 | 253 | pc[4].rejectIdentity() catch |_| return error.WeakPublicKey; |
| 254 | return pcMul(pc, s, true); |
| 211 | 255 | } |
| 212 | | return pcMul(pc, s, true); |
| 213 | 256 | } |
| 214 | 257 | |
| 215 | 258 | /// Multiscalar multiplication *IN VARIABLE TIME* for public data |
| 216 | 259 | /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually |
| 217 | 260 | pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) !Edwards25519 { |
| 218 | | var pcs: [count][16]Edwards25519 = undefined; |
| 261 | var pcs: [count][9]Edwards25519 = undefined; |
| 219 | 262 | for (ps) |p, i| { |
| 220 | 263 | if (p.is_base) { |
| 221 | 264 | @setEvalBranchQuota(10000); |
| 222 | | pcs[i] = comptime precompute(Edwards25519.basePoint); |
| 265 | pcs[i] = comptime precompute(Edwards25519.basePoint, 8); |
| 223 | 266 | } else { |
| 224 | | pcs[i] = precompute(p); |
| 267 | pcs[i] = precompute(p, 8); |
| 225 | 268 | pcs[i][4].rejectIdentity() catch |_| return error.WeakPublicKey; |
| 226 | 269 | } |
| 227 | 270 | } |
| 271 | var es: [count][2 * 32]i8 = undefined; |
| 272 | for (ss) |s, i| { |
| 273 | es[i] = nonAdjacentForm(s); |
| 274 | } |
| 228 | 275 | var q = Edwards25519.identityElement; |
| 229 | | var pos: usize = 252; |
| 230 | | while (true) : (pos -= 4) { |
| 231 | | q = q.dbl().dbl().dbl().dbl(); |
| 232 | | for (ss) |s, i| { |
| 233 | | const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf; |
| 234 | | if (bit != 0) { |
| 235 | | q = q.add(pcs[i][bit]); |
| 276 | var pos: usize = 2 * 32 - 1; |
| 277 | while (true) : (pos -= 1) { |
| 278 | for (es) |e, i| { |
| 279 | const slot = e[pos]; |
| 280 | if (slot > 0) { |
| 281 | q = q.add(pcs[i][@intCast(usize, slot)]); |
| 282 | } else if (slot < 0) { |
| 283 | q = q.sub(pcs[i][@intCast(usize, -slot)]); |
| 236 | 284 | } |
| 237 | 285 | } |
| 238 | 286 | if (pos == 0) break; |
| 287 | q = q.dbl().dbl().dbl().dbl(); |
| 239 | 288 | } |
| 240 | 289 | try q.rejectIdentity(); |
| 241 | 290 | return q; |