| ... | @@ -208,6 +208,35 @@ pub const Edwards25519 = struct { | ... | @@ -208,6 +208,35 @@ pub const Edwards25519 = struct { |
| 208 | return pcMul(pc, s, true); | 208 | return pcMul(pc, s, true); |
| 209 | } | 209 | } |
| 210 | | 210 | |
| | 211 | /// Multiscalar multiplication *IN VARIABLE TIME* for public data |
| | 212 | /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually |
| | 213 | pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) !Edwards25519 { |
| | 214 | var pcs: [count][16]Edwards25519 = undefined; |
| | 215 | for (ps) |p, i| { |
| | 216 | if (p.is_base) { |
| | 217 | @setEvalBranchQuota(10000); |
| | 218 | pcs[i] = comptime precompute(Edwards25519.basePoint); |
| | 219 | } else { |
| | 220 | pcs[i] = precompute(p); |
| | 221 | pcs[i][4].rejectIdentity() catch |_| return error.WeakPublicKey; |
| | 222 | } |
| | 223 | } |
| | 224 | var q = Edwards25519.identityElement; |
| | 225 | var pos: usize = 252; |
| | 226 | while (true) : (pos -= 4) { |
| | 227 | q = q.dbl().dbl().dbl().dbl(); |
| | 228 | for (ss) |s, i| { |
| | 229 | const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf; |
| | 230 | if (bit != 0) { |
| | 231 | q = q.add(pcs[i][bit]); |
| | 232 | } |
| | 233 | } |
| | 234 | if (pos == 0) break; |
| | 235 | } |
| | 236 | try q.rejectIdentity(); |
| | 237 | return q; |
| | 238 | } |
| | 239 | |
| 211 | /// Multiply an Edwards25519 point by a scalar after "clamping" it. | 240 | /// Multiply an Edwards25519 point by a scalar after "clamping" it. |
| 212 | /// Clamping forces the scalar to be a multiple of the cofactor in | 241 | /// Clamping forces the scalar to be a multiple of the cofactor in |
| 213 | /// order to prevent small subgroups attacks. | 242 | /// order to prevent small subgroups attacks. |