| ... | ... | @@ -33,7 +33,7 @@ pub fn calcToStringLimbsBufferLen(a_len: usize, base: u8) usize { |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | pub fn calcDivLimbsBufferLen(a_len: usize, b_len: usize) usize { |
| 36 | | return calcMulLimbsBufferLen(a_len, b_len, 2) * 4; |
| 36 | return a_len + b_len + 4; |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | pub fn calcMulLimbsBufferLen(a_len: usize, b_len: usize, aliases: usize) usize { |
| ... | ... | @@ -760,8 +760,8 @@ pub const Mutable = struct { |
| 760 | 760 | /// q may alias with a or b. |
| 761 | 761 | /// |
| 762 | 762 | /// Asserts there is enough memory to store q and r. |
| 763 | | /// The upper bound for r limb count is a.limbs.len. |
| 764 | | /// The upper bound for q limb count is given by `a.limbs.len + b.limbs.len + 1`. |
| 763 | /// The upper bound for r limb count is b.limbs.len. |
| 764 | /// The upper bound for q limb count is given by `a.limbs.len + b.limbs.len`. |
| 765 | 765 | /// |
| 766 | 766 | /// If `allocator` is provided, it will be used for temporary storage to improve |
| 767 | 767 | /// multiplication performance. `error.OutOfMemory` is handled with a fallback algorithm. |
| ... | ... | @@ -773,19 +773,17 @@ pub const Mutable = struct { |
| 773 | 773 | a: Const, |
| 774 | 774 | b: Const, |
| 775 | 775 | limbs_buffer: []Limb, |
| 776 | | allocator: ?*Allocator, |
| 777 | 776 | ) void { |
| 778 | | div(q, r, a, b, limbs_buffer, allocator); |
| 777 | div(q, r, a, b, limbs_buffer); |
| 779 | 778 | |
| 780 | 779 | // Trunc -> Floor. |
| 781 | 780 | if (a.positive and b.positive) return; |
| 782 | 781 | |
| 783 | 782 | if ((!q.positive or q.eqZero()) and !r.eqZero()) { |
| 784 | | const one: Const = .{ .limbs = &[_]Limb{1}, .positive = true }; |
| 785 | | q.sub(q.toConst(), one); |
| 783 | q.addScalar(q.toConst(), -1); |
| 786 | 784 | } |
| 787 | 785 | |
| 788 | | r.mulNoAlias(q.toConst(), b, allocator); |
| 786 | r.mulNoAlias(q.toConst(), b, null); |
| 789 | 787 | r.sub(a, r.toConst()); |
| 790 | 788 | } |
| 791 | 789 | |
| ... | ... | @@ -809,9 +807,8 @@ pub const Mutable = struct { |
| 809 | 807 | a: Const, |
| 810 | 808 | b: Const, |
| 811 | 809 | limbs_buffer: []Limb, |
| 812 | | allocator: ?*Allocator, |
| 813 | 810 | ) void { |
| 814 | | div(q, r, a, b, limbs_buffer, allocator); |
| 811 | div(q, r, a, b, limbs_buffer); |
| 815 | 812 | r.positive = a.positive; |
| 816 | 813 | } |
| 817 | 814 | |
| ... | ... | @@ -1177,7 +1174,7 @@ pub const Mutable = struct { |
| 1177 | 1174 | } |
| 1178 | 1175 | |
| 1179 | 1176 | /// Truncates by default. |
| 1180 | | fn div(quo: *Mutable, rem: *Mutable, a: Const, b: Const, limbs_buffer: []Limb, allocator: ?*Allocator) void { |
| 1177 | fn div(quo: *Mutable, rem: *Mutable, a: Const, b: Const, limbs_buffer: []Limb) void { |
| 1181 | 1178 | assert(!b.eqZero()); // division by zero |
| 1182 | 1179 | assert(quo != rem); // illegal aliasing |
| 1183 | 1180 | |
| ... | ... | @@ -1220,11 +1217,9 @@ pub const Mutable = struct { |
| 1220 | 1217 | rem.positive = true; |
| 1221 | 1218 | } else { |
| 1222 | 1219 | // x and y are modified during division |
| 1223 | | const sep_len = calcMulLimbsBufferLen(a.limbs.len, b.limbs.len, 2); |
| 1224 | | const x_limbs = limbs_buffer[0 * sep_len ..][0..sep_len]; |
| 1225 | | const y_limbs = limbs_buffer[1 * sep_len ..][0..sep_len]; |
| 1226 | | const t_limbs = limbs_buffer[2 * sep_len ..][0..sep_len]; |
| 1227 | | const mul_limbs_buf = limbs_buffer[3 * sep_len ..][0..sep_len]; |
| 1220 | const sep_len = a.limbs.len + 2; |
| 1221 | const x_limbs = limbs_buffer[0 .. sep_len]; |
| 1222 | const y_limbs = limbs_buffer[sep_len..]; |
| 1228 | 1223 | |
| 1229 | 1224 | var x: Mutable = .{ |
| 1230 | 1225 | .limbs = x_limbs, |
| ... | ... | @@ -1238,119 +1233,159 @@ pub const Mutable = struct { |
| 1238 | 1233 | }; |
| 1239 | 1234 | |
| 1240 | 1235 | // Shrink x, y such that the trailing zero limbs shared between are removed. |
| 1241 | | mem.copy(Limb, x.limbs, a.limbs[ab_zero_limb_count..a.limbs.len]); |
| 1242 | | mem.copy(Limb, y.limbs, b.limbs[ab_zero_limb_count..b.limbs.len]); |
| 1236 | mem.copy(Limb, x.limbs, a.limbs[ab_zero_limb_count..]); |
| 1237 | mem.copy(Limb, y.limbs, b.limbs[ab_zero_limb_count..]); |
| 1243 | 1238 | |
| 1244 | | divN(quo, rem, &x, &y, t_limbs, mul_limbs_buf, allocator); |
| 1239 | divmod(quo, rem, &x, &y); |
| 1245 | 1240 | quo.positive = (a.positive == b.positive); |
| 1246 | 1241 | } |
| 1247 | 1242 | |
| 1248 | 1243 | if (ab_zero_limb_count != 0) { |
| 1249 | | rem.shiftLeft(rem.toConst(), ab_zero_limb_count * limb_bits); |
| 1244 | // Manually shift here since we know its limb aligned. |
| 1245 | mem.copyBackwards(Limb, rem.limbs[ab_zero_limb_count..], rem.limbs[0..rem.len]); |
| 1246 | mem.set(Limb, rem.limbs[0..ab_zero_limb_count], 0); |
| 1247 | rem.len += ab_zero_limb_count; |
| 1250 | 1248 | } |
| 1251 | 1249 | } |
| 1252 | 1250 | |
| 1253 | 1251 | /// Handbook of Applied Cryptography, 14.20 |
| 1254 | 1252 | /// |
| 1255 | 1253 | /// x = qy + r where 0 <= r < y |
| 1256 | | fn divN( |
| 1254 | fn divmod( |
| 1257 | 1255 | q: *Mutable, |
| 1258 | 1256 | r: *Mutable, |
| 1259 | 1257 | x: *Mutable, |
| 1260 | 1258 | y: *Mutable, |
| 1261 | | tmp_limbs: []Limb, |
| 1262 | | mul_limb_buf: []Limb, |
| 1263 | | allocator: ?*Allocator, |
| 1264 | 1259 | ) void { |
| 1265 | | assert(y.len >= 2); |
| 1266 | | assert(x.len >= y.len); |
| 1267 | | assert(q.limbs.len >= x.len + y.len - 1); |
| 1268 | | |
| 1269 | | // See 3.2 |
| 1270 | | var backup_tmp_limbs: [3]Limb = undefined; |
| 1271 | | const t_limbs = if (tmp_limbs.len < 3) &backup_tmp_limbs else tmp_limbs; |
| 1272 | | |
| 1273 | | var tmp: Mutable = .{ |
| 1274 | | .limbs = t_limbs, |
| 1275 | | .len = 1, |
| 1276 | | .positive = true, |
| 1277 | | }; |
| 1278 | | tmp.limbs[0] = 0; |
| 1260 | // 0. |
| 1261 | // Normalize so that y[t] > b/2 |
| 1262 | const lz = @clz(Limb, y.limbs[y.len - 1]); |
| 1263 | const norm_shift = if (lz == 0 and y.toConst().isOdd()) |
| 1264 | limb_bits // Force an extra limb so that y is even. |
| 1265 | else |
| 1266 | lz; |
| 1279 | 1267 | |
| 1280 | | // Normalize so y > limb_bits / 2 (i.e. leading bit is set) and even |
| 1281 | | var norm_shift = @clz(Limb, y.limbs[y.len - 1]); |
| 1282 | | if (norm_shift == 0 and y.toConst().isOdd()) { |
| 1283 | | norm_shift = limb_bits; |
| 1284 | | } |
| 1285 | 1268 | x.shiftLeft(x.toConst(), norm_shift); |
| 1286 | 1269 | y.shiftLeft(y.toConst(), norm_shift); |
| 1287 | 1270 | |
| 1288 | 1271 | const n = x.len - 1; |
| 1289 | 1272 | const t = y.len - 1; |
| 1273 | const shift = n - t; |
| 1290 | 1274 | |
| 1291 | 1275 | // 1. |
| 1292 | | q.len = n - t + 1; |
| 1276 | // for 0 <= j <= n - t, set q[j] to 0 |
| 1277 | q.len = shift + 1; |
| 1293 | 1278 | q.positive = true; |
| 1294 | 1279 | mem.set(Limb, q.limbs[0..q.len], 0); |
| 1295 | 1280 | |
| 1296 | 1281 | // 2. |
| 1297 | | tmp.shiftLeft(y.toConst(), limb_bits * (n - t)); |
| 1298 | | while (x.toConst().order(tmp.toConst()) != .lt) { |
| 1299 | | q.limbs[n - t] += 1; |
| 1300 | | x.sub(x.toConst(), tmp.toConst()); |
| 1282 | // while x >= y * b^(n - t): |
| 1283 | // x -= y * b^(n - t) |
| 1284 | // q[n - t] += 1 |
| 1285 | // Note, this algorithm is performed only once if y[t] > radix/2 and y is even, which we |
| 1286 | // enforced in step 0. This means we can replace the while with an if. |
| 1287 | // Note, multiplication by b^(n - t) comes down to shifting to the right by n - t limbs. |
| 1288 | // We can also replace x >= y * b^(n - t) by x/b^(n - t) >= y, and use shifts for that. |
| 1289 | { |
| 1290 | // x >= y * b^(n - t) can be replaced by x/b^(n - t) >= y. |
| 1291 | |
| 1292 | // 'divide' x by b^(n - t) |
| 1293 | var tmp = Mutable{ |
| 1294 | .limbs = x.limbs[shift..], |
| 1295 | .len = x.len - shift, |
| 1296 | .positive = true, |
| 1297 | }; |
| 1298 | |
| 1299 | if (tmp.toConst().order(y.toConst()) != .lt) { |
| 1300 | // Perform x -= y * b^(n - t) |
| 1301 | // Note, we can subtract y from x[n - t..] and get the result without shifting. |
| 1302 | // We can also re-use tmp which already contains the relevant part of x. Note that |
| 1303 | // this also edits x. |
| 1304 | // Due to the check above, this cannot underflow. |
| 1305 | tmp.sub(tmp.toConst(), y.toConst()); |
| 1306 | |
| 1307 | // tmp.sub normalized tmp, but we need to normalize x now. |
| 1308 | x.limbs.len = tmp.limbs.len + shift; |
| 1309 | |
| 1310 | q.limbs[shift] += 1; |
| 1311 | } |
| 1301 | 1312 | } |
| 1302 | 1313 | |
| 1303 | 1314 | // 3. |
| 1315 | // for i from n down to t + 1, do |
| 1304 | 1316 | var i = n; |
| 1305 | | while (i > t) : (i -= 1) { |
| 1306 | | // 3.1 |
| 1317 | while (i >= t + 1) : (i -= 1) { |
| 1318 | const k = i - t - 1; |
| 1319 | // 3.1. |
| 1320 | // if x_i == y_t: |
| 1321 | // q[i - t - 1] = b - 1 |
| 1322 | // else: |
| 1323 | // q[i - t - 1] = (x[i] * b + x[i - 1]) / y[t] |
| 1307 | 1324 | if (x.limbs[i] == y.limbs[t]) { |
| 1308 | | q.limbs[i - t - 1] = maxInt(Limb); |
| 1325 | q.limbs[k] = maxInt(Limb); |
| 1309 | 1326 | } else { |
| 1310 | | const num = (@as(DoubleLimb, x.limbs[i]) << limb_bits) | @as(DoubleLimb, x.limbs[i - 1]); |
| 1311 | | const z = @intCast(Limb, num / @as(DoubleLimb, y.limbs[t])); |
| 1312 | | q.limbs[i - t - 1] = if (z > maxInt(Limb)) maxInt(Limb) else @as(Limb, z); |
| 1327 | const q0 = (@as(DoubleLimb, x.limbs[i]) << limb_bits) | @as(DoubleLimb, x.limbs[i - 1]); |
| 1328 | const n0 = @as(DoubleLimb, y.limbs[t]); |
| 1329 | q.limbs[k] = @intCast(Limb, q0 / n0); |
| 1313 | 1330 | } |
| 1314 | 1331 | |
| 1315 | 1332 | // 3.2 |
| 1316 | | tmp.limbs[0] = if (i >= 2) x.limbs[i - 2] else 0; |
| 1317 | | tmp.limbs[1] = if (i >= 1) x.limbs[i - 1] else 0; |
| 1318 | | tmp.limbs[2] = x.limbs[i]; |
| 1319 | | tmp.normalize(3); |
| 1333 | // while q[i - t - 1] * (y[t] * b + y[t - 1] > x[i] * b * b + x[i - 1] + x[i - 2]: |
| 1334 | // q[i - t - 1] -= 1 |
| 1335 | // Note, if y[t] > b / 2 this part is repeated no more than twice. |
| 1336 | |
| 1337 | // Extract from y. |
| 1338 | const y0 = if (t > 0) y.limbs[t - 1] else 0; |
| 1339 | const y1 = y.limbs[t]; |
| 1340 | |
| 1341 | // Extract from x. |
| 1342 | // Note, big endian. |
| 1343 | const tmp0 = [_]Limb{ |
| 1344 | x.limbs[i], |
| 1345 | if (i >= 1) x.limbs[i - 1] else 0, |
| 1346 | if (i >= 2) x.limbs[i - 2] else 0, |
| 1347 | }; |
| 1320 | 1348 | |
| 1321 | 1349 | while (true) { |
| 1322 | | // 2x1 limb multiplication unrolled against single-limb q[i-t-1] |
| 1323 | | var carry: Limb = 0; |
| 1324 | | r.limbs[0] = addMulLimbWithCarry(0, if (t >= 1) y.limbs[t - 1] else 0, q.limbs[i - t - 1], &carry); |
| 1325 | | r.limbs[1] = addMulLimbWithCarry(0, y.limbs[t], q.limbs[i - t - 1], &carry); |
| 1326 | | r.limbs[2] = carry; |
| 1327 | | r.normalize(3); |
| 1328 | | |
| 1329 | | if (r.toConst().orderAbs(tmp.toConst()) != .gt) { |
| 1350 | // Ad-hoc 2x1 multiplication with q[i - t - 1]. |
| 1351 | // Note, big endian. |
| 1352 | var tmp1 = [_]Limb{0, undefined, undefined}; |
| 1353 | tmp1[2] = addMulLimbWithCarry(0, y0, q.limbs[k], &tmp1[0]); |
| 1354 | tmp1[1] = addMulLimbWithCarry(0, y1, q.limbs[k], &tmp1[0]); |
| 1355 | |
| 1356 | // Big-endian compare |
| 1357 | if (mem.order(Limb, &tmp1, &tmp0) != .gt) |
| 1330 | 1358 | break; |
| 1331 | | } |
| 1332 | 1359 | |
| 1333 | | q.limbs[i - t - 1] -= 1; |
| 1360 | q.limbs[k] -= 1; |
| 1334 | 1361 | } |
| 1335 | 1362 | |
| 1336 | | // 3.3 |
| 1337 | | tmp.set(q.limbs[i - t - 1]); |
| 1338 | | tmp.mul(tmp.toConst(), y.toConst(), mul_limb_buf, allocator); |
| 1339 | | tmp.shiftLeft(tmp.toConst(), limb_bits * (i - t - 1)); |
| 1340 | | x.sub(x.toConst(), tmp.toConst()); |
| 1341 | | |
| 1342 | | if (!x.positive) { |
| 1343 | | tmp.shiftLeft(y.toConst(), limb_bits * (i - t - 1)); |
| 1344 | | x.add(x.toConst(), tmp.toConst()); |
| 1345 | | q.limbs[i - t - 1] -= 1; |
| 1363 | // 3.3. |
| 1364 | // x -= q[i - t - 1] * y * b^(i - t - 1) |
| 1365 | // Note, we multiply by a single limb here. |
| 1366 | // The shift doesn't need to be performed if we add the result of the first multiplication |
| 1367 | // to x[i - t - 1]. |
| 1368 | // mem.set(Limb, x.limbs, 0); |
| 1369 | const underflow = llmulLimb(.sub, x.limbs[k .. x.len], y.limbs[0 .. y.len], q.limbs[k]); |
| 1370 | |
| 1371 | // 3.4. |
| 1372 | // if x < 0: |
| 1373 | // x += y * b^(i - t - 1) |
| 1374 | // q[i - t - 1] -= 1 |
| 1375 | // Note, we check for x < 0 using the underflow flag from the previous operation. |
| 1376 | if (underflow) { |
| 1377 | // While we didn't properly set the signedness of x, this operation should 'flow' it back to positive. |
| 1378 | llaccum(.add, x.limbs[k .. x.len], y.limbs[0 .. y.len]); |
| 1379 | q.limbs[k] -= 1; |
| 1346 | 1380 | } |
| 1381 | |
| 1382 | x.normalize(x.len); |
| 1347 | 1383 | } |
| 1348 | 1384 | |
| 1349 | | // Denormalize |
| 1350 | 1385 | q.normalize(q.len); |
| 1351 | 1386 | |
| 1387 | // De-normalize r. |
| 1352 | 1388 | r.shiftRight(x.toConst(), norm_shift); |
| 1353 | | r.normalize(r.len); |
| 1354 | 1389 | } |
| 1355 | 1390 | |
| 1356 | 1391 | /// Truncate an integer to a number of bits, following 2s-complement semantics. |
| ... | ... | @@ -1808,7 +1843,7 @@ pub const Const = struct { |
| 1808 | 1843 | while (q.len >= 2) { |
| 1809 | 1844 | // Passing an allocator here would not be helpful since this division is destroying |
| 1810 | 1845 | // information, not creating it. [TODO citation needed] |
| 1811 | | q.divTrunc(&r, q.toConst(), b, rest_of_the_limbs_buf, null); |
| 1846 | q.divTrunc(&r, q.toConst(), b, rest_of_the_limbs_buf); |
| 1812 | 1847 | |
| 1813 | 1848 | var r_word = r.limbs[0]; |
| 1814 | 1849 | var i: usize = 0; |
| ... | ... | @@ -2435,16 +2470,14 @@ pub const Managed = struct { |
| 2435 | 2470 | /// a / b are floored (rounded towards 0). |
| 2436 | 2471 | /// |
| 2437 | 2472 | /// Returns an error if memory could not be allocated. |
| 2438 | | /// |
| 2439 | | /// q's allocator is used for temporary storage to speed up the multiplication. |
| 2440 | 2473 | pub fn divFloor(q: *Managed, r: *Managed, a: Const, b: Const) !void { |
| 2441 | | try q.ensureCapacity(a.limbs.len + b.limbs.len + 1); |
| 2442 | | try r.ensureCapacity(a.limbs.len); |
| 2474 | try q.ensureCapacity(a.limbs.len + b.limbs.len); |
| 2475 | try r.ensureCapacity(b.limbs.len); |
| 2443 | 2476 | var mq = q.toMutable(); |
| 2444 | 2477 | var mr = r.toMutable(); |
| 2445 | 2478 | const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.limbs.len, b.limbs.len)); |
| 2446 | 2479 | defer q.allocator.free(limbs_buffer); |
| 2447 | | mq.divFloor(&mr, a, b, limbs_buffer, q.allocator); |
| 2480 | mq.divFloor(&mr, a, b, limbs_buffer); |
| 2448 | 2481 | q.setMetadata(mq.positive, mq.len); |
| 2449 | 2482 | r.setMetadata(mr.positive, mr.len); |
| 2450 | 2483 | } |
| ... | ... | @@ -2454,16 +2487,14 @@ pub const Managed = struct { |
| 2454 | 2487 | /// a / b are truncated (rounded towards -inf). |
| 2455 | 2488 | /// |
| 2456 | 2489 | /// Returns an error if memory could not be allocated. |
| 2457 | | /// |
| 2458 | | /// q's allocator is used for temporary storage to speed up the multiplication. |
| 2459 | 2490 | pub fn divTrunc(q: *Managed, r: *Managed, a: Const, b: Const) !void { |
| 2460 | | try q.ensureCapacity(a.limbs.len + b.limbs.len + 1); |
| 2461 | | try r.ensureCapacity(a.limbs.len); |
| 2491 | try q.ensureCapacity(a.limbs.len + b.limbs.len); |
| 2492 | try r.ensureCapacity(b.limbs.len); |
| 2462 | 2493 | var mq = q.toMutable(); |
| 2463 | 2494 | var mr = r.toMutable(); |
| 2464 | 2495 | const limbs_buffer = try q.allocator.alloc(Limb, calcDivLimbsBufferLen(a.limbs.len, b.limbs.len)); |
| 2465 | 2496 | defer q.allocator.free(limbs_buffer); |
| 2466 | | mq.divTrunc(&mr, a, b, limbs_buffer, q.allocator); |
| 2497 | mq.divTrunc(&mr, a, b, limbs_buffer); |
| 2467 | 2498 | q.setMetadata(mq.positive, mq.len); |
| 2468 | 2499 | r.setMetadata(mr.positive, mr.len); |
| 2469 | 2500 | } |
| ... | ... | @@ -2893,20 +2924,22 @@ fn llmulaccLong(comptime op: AccOp, r: []Limb, a: []const Limb, b: []const Limb) |
| 2893 | 2924 | |
| 2894 | 2925 | var i: usize = 0; |
| 2895 | 2926 | while (i < b.len) : (i += 1) { |
| 2896 | | llmulLimb(op, r[i..], a, b[i]); |
| 2927 | _ = llmulLimb(op, r[i..], a, b[i]); |
| 2897 | 2928 | } |
| 2898 | 2929 | } |
| 2899 | 2930 | |
| 2900 | 2931 | /// r = r (op) y * xi |
| 2901 | 2932 | /// The result is computed modulo `r.len`. |
| 2902 | | fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) void { |
| 2933 | /// Returns whether the operation overflowed. |
| 2934 | fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) bool { |
| 2903 | 2935 | @setRuntimeSafety(debug_safety); |
| 2904 | 2936 | if (xi == 0) { |
| 2905 | | return; |
| 2937 | return false; |
| 2906 | 2938 | } |
| 2907 | 2939 | |
| 2908 | | var a_lo = acc[0..y.len]; |
| 2909 | | var a_hi = acc[y.len..]; |
| 2940 | const split = std.math.min(y.len, acc.len); |
| 2941 | var a_lo = acc[0..split]; |
| 2942 | var a_hi = acc[split..]; |
| 2910 | 2943 | |
| 2911 | 2944 | switch (op) { |
| 2912 | 2945 | .add => { |
| ... | ... | @@ -2920,6 +2953,8 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) void { |
| 2920 | 2953 | while ((carry != 0) and (j < a_hi.len)) : (j += 1) { |
| 2921 | 2954 | carry = @boolToInt(@addWithOverflow(Limb, a_hi[j], carry, &a_hi[j])); |
| 2922 | 2955 | } |
| 2956 | |
| 2957 | return carry != 0; |
| 2923 | 2958 | }, |
| 2924 | 2959 | .sub => { |
| 2925 | 2960 | var borrow: Limb = 0; |
| ... | ... | @@ -2932,6 +2967,8 @@ fn llmulLimb(comptime op: AccOp, acc: []Limb, y: []const Limb, xi: Limb) void { |
| 2932 | 2967 | while ((borrow != 0) and (j < a_hi.len)) : (j += 1) { |
| 2933 | 2968 | borrow = @boolToInt(@subWithOverflow(Limb, a_hi[j], borrow, &a_hi[j])); |
| 2934 | 2969 | } |
| 2970 | |
| 2971 | return borrow != 0; |
| 2935 | 2972 | }, |
| 2936 | 2973 | } |
| 2937 | 2974 | } |
| ... | ... | @@ -3424,7 +3461,8 @@ fn llsquareBasecase(r: []Limb, x: []const Limb) void { |
| 3424 | 3461 | |
| 3425 | 3462 | for (x_norm) |v, i| { |
| 3426 | 3463 | // Accumulate all the x[i]*x[j] (with x!=j) products |
| 3427 | | llmulLimb(.add, r[2 * i + 1 ..], x_norm[i + 1 ..], v); |
| 3464 | const overflow = llmulLimb(.add, r[2 * i + 1 ..], x_norm[i + 1 ..], v); |
| 3465 | assert(!overflow); |
| 3428 | 3466 | } |
| 3429 | 3467 | |
| 3430 | 3468 | // Each product appears twice, multiply by 2 |
| ... | ... | @@ -3432,7 +3470,8 @@ fn llsquareBasecase(r: []Limb, x: []const Limb) void { |
| 3432 | 3470 | |
| 3433 | 3471 | for (x_norm) |v, i| { |
| 3434 | 3472 | // Compute and add the squares |
| 3435 | | llmulLimb(.add, r[2 * i ..], x[i .. i + 1], v); |
| 3473 | const overflow = llmulLimb(.add, r[2 * i ..], x[i .. i + 1], v); |
| 3474 | assert(!overflow); |
| 3436 | 3475 | } |
| 3437 | 3476 | } |
| 3438 | 3477 | |