@btc-vision/btc-runtime 1.10.2 → 1.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/runtime/contracts/OP20.ts +19 -8
- package/runtime/contracts/OP721.ts +19 -8
- package/runtime/env/BlockchainEnvironment.ts +90 -65
- package/runtime/env/global.ts +24 -14
- package/runtime/generic/AddressMap.ts +113 -24
- package/runtime/generic/Map.ts +78 -22
- package/runtime/generic/MapUint8Array.ts +115 -27
- package/runtime/storage/StoredAddress.ts +2 -2
- package/runtime/storage/arrays/StoredPackedArray.ts +117 -60
- package/runtime/types/SafeMath.ts +240 -337
|
@@ -19,7 +19,15 @@ export class SafeMath {
|
|
|
19
19
|
* Constant representing zero in u256 format.
|
|
20
20
|
* Useful for comparisons and initializations.
|
|
21
21
|
*/
|
|
22
|
-
public static ZERO: u256 = u256.
|
|
22
|
+
public static readonly ZERO: u256 = u256.Zero;
|
|
23
|
+
|
|
24
|
+
// GAS OPTIMIZATION: Static constants to avoid allocation in hot loops
|
|
25
|
+
public static readonly ONE: u256 = u256.One;
|
|
26
|
+
private static readonly CONST_2: u256 = u256.fromU32(2);
|
|
27
|
+
private static readonly CONST_3: u256 = u256.fromU32(3);
|
|
28
|
+
private static readonly CONST_10: u256 = u256.fromU32(10);
|
|
29
|
+
private static readonly LN2_SCALED: u64 = 693147; // ln(2)*1e6
|
|
30
|
+
private static readonly SCALE_1E6: u64 = 1_000_000;
|
|
23
31
|
|
|
24
32
|
// ==================== Addition Operations ====================
|
|
25
33
|
|
|
@@ -42,7 +50,7 @@ export class SafeMath {
|
|
|
42
50
|
* - Gas efficient for small values
|
|
43
51
|
*/
|
|
44
52
|
public static add(a: u256, b: u256): u256 {
|
|
45
|
-
const c
|
|
53
|
+
const c = u256.add(a, b);
|
|
46
54
|
if (c < a) {
|
|
47
55
|
throw new Revert('SafeMath: addition overflow');
|
|
48
56
|
}
|
|
@@ -62,7 +70,7 @@ export class SafeMath {
|
|
|
62
70
|
* - More gas efficient than u256 for values that fit in 128 bits
|
|
63
71
|
*/
|
|
64
72
|
public static add128(a: u128, b: u128): u128 {
|
|
65
|
-
const c
|
|
73
|
+
const c = u128.add(a, b);
|
|
66
74
|
if (c < a) {
|
|
67
75
|
throw new Revert('SafeMath: addition overflow');
|
|
68
76
|
}
|
|
@@ -82,7 +90,7 @@ export class SafeMath {
|
|
|
82
90
|
* - Most gas efficient for small values
|
|
83
91
|
*/
|
|
84
92
|
public static add64(a: u64, b: u64): u64 {
|
|
85
|
-
const c
|
|
93
|
+
const c = a + b;
|
|
86
94
|
if (c < a) {
|
|
87
95
|
throw new Revert('SafeMath: addition overflow');
|
|
88
96
|
}
|
|
@@ -106,7 +114,7 @@ export class SafeMath {
|
|
|
106
114
|
* ```
|
|
107
115
|
*
|
|
108
116
|
* @warning Unsigned integers cannot represent negative values. Always ensure a >= b
|
|
109
|
-
*
|
|
117
|
+
* before calling, or handle the potential revert in your contract logic.
|
|
110
118
|
*
|
|
111
119
|
* @remarks
|
|
112
120
|
* - Result is always non-negative
|
|
@@ -165,7 +173,7 @@ export class SafeMath {
|
|
|
165
173
|
* ```
|
|
166
174
|
*
|
|
167
175
|
* @security The overflow check performs division after multiplication, which is safe
|
|
168
|
-
*
|
|
176
|
+
* because if overflow occurred, the division result won't equal the original operand.
|
|
169
177
|
*
|
|
170
178
|
* @remarks
|
|
171
179
|
* - Returns 0 if either operand is 0
|
|
@@ -176,7 +184,8 @@ export class SafeMath {
|
|
|
176
184
|
if (a.isZero() || b.isZero()) return u256.Zero;
|
|
177
185
|
|
|
178
186
|
const c = u256.mul(a, b);
|
|
179
|
-
|
|
187
|
+
// Use native div, it's faster than manual loop and handles edge cases correctly
|
|
188
|
+
const d = u256.div(c, a);
|
|
180
189
|
|
|
181
190
|
if (u256.ne(d, b)) throw new Revert('SafeMath: multiplication overflow');
|
|
182
191
|
|
|
@@ -195,7 +204,7 @@ export class SafeMath {
|
|
|
195
204
|
if (a.isZero() || b.isZero()) return u128.Zero;
|
|
196
205
|
|
|
197
206
|
const c = u128.mul(a, b);
|
|
198
|
-
const d =
|
|
207
|
+
const d = u128.div(c, a);
|
|
199
208
|
|
|
200
209
|
if (u128.ne(d, b)) throw new Revert('SafeMath: multiplication overflow');
|
|
201
210
|
|
|
@@ -240,10 +249,10 @@ export class SafeMath {
|
|
|
240
249
|
* ```
|
|
241
250
|
*
|
|
242
251
|
* @warning Integer division always rounds down. For 10/3, the result is 3, not 3.333...
|
|
243
|
-
*
|
|
252
|
+
* The remainder (1 in this case) is lost. Use `mod` to get the remainder.
|
|
244
253
|
*
|
|
245
254
|
* @security Division by zero is always checked and will revert the transaction,
|
|
246
|
-
*
|
|
255
|
+
* preventing undefined behavior or exploits.
|
|
247
256
|
*
|
|
248
257
|
* @remarks
|
|
249
258
|
* - Always rounds down (floor division)
|
|
@@ -257,33 +266,12 @@ export class SafeMath {
|
|
|
257
266
|
}
|
|
258
267
|
|
|
259
268
|
if (a.isZero()) {
|
|
260
|
-
return
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
if (u256.lt(a, b)) {
|
|
264
|
-
return new u256(); // Return 0 if a < b
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (u256.eq(a, b)) {
|
|
268
|
-
return new u256(1); // Return 1 if a == b
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
let n = a.clone();
|
|
272
|
-
let d = b.clone();
|
|
273
|
-
let result = new u256();
|
|
274
|
-
|
|
275
|
-
const shift = u256.clz(d) - u256.clz(n);
|
|
276
|
-
d = SafeMath.shl(d, shift); // align d with n by shifting left
|
|
277
|
-
|
|
278
|
-
for (let i = shift; i >= 0; i--) {
|
|
279
|
-
if (u256.ge(n, d)) {
|
|
280
|
-
n = u256.sub(n, d);
|
|
281
|
-
result = u256.or(result, SafeMath.shl(u256.One, i));
|
|
282
|
-
}
|
|
283
|
-
d = u256.shr(d, 1); // restore d to original by shifting right
|
|
269
|
+
return u256.Zero;
|
|
284
270
|
}
|
|
285
271
|
|
|
286
|
-
|
|
272
|
+
// GAS OPTIMIZATION: Use native as-bignum division instead of manual shift loop
|
|
273
|
+
// The native implementation is likely optimized in AssemblyScript/WASM
|
|
274
|
+
return u256.div(a, b);
|
|
287
275
|
}
|
|
288
276
|
|
|
289
277
|
/**
|
|
@@ -295,7 +283,7 @@ export class SafeMath {
|
|
|
295
283
|
* @throws {Revert} When b is zero
|
|
296
284
|
*
|
|
297
285
|
* @warning Integer division truncates decimals. Consider scaling your values
|
|
298
|
-
*
|
|
286
|
+
* before division if you need to preserve precision.
|
|
299
287
|
*/
|
|
300
288
|
public static div128(a: u128, b: u128): u128 {
|
|
301
289
|
if (b.isZero()) {
|
|
@@ -303,33 +291,10 @@ export class SafeMath {
|
|
|
303
291
|
}
|
|
304
292
|
|
|
305
293
|
if (a.isZero()) {
|
|
306
|
-
return
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (u128.lt(a, b)) {
|
|
310
|
-
return new u128(); // Return 0 if a < b
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (u128.eq(a, b)) {
|
|
314
|
-
return new u128(1); // Return 1 if a == b
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
let n = a.clone();
|
|
318
|
-
let d = b.clone();
|
|
319
|
-
let result = new u128();
|
|
320
|
-
|
|
321
|
-
const shift = u128.clz(d) - u128.clz(n);
|
|
322
|
-
d = SafeMath.shl128(d, shift);
|
|
323
|
-
|
|
324
|
-
for (let i = shift; i >= 0; i--) {
|
|
325
|
-
if (u128.ge(n, d)) {
|
|
326
|
-
n = u128.sub(n, d);
|
|
327
|
-
result = u128.or(result, SafeMath.shl128(u128.One, i));
|
|
328
|
-
}
|
|
329
|
-
d = u128.shr(d, 1);
|
|
294
|
+
return u128.Zero;
|
|
330
295
|
}
|
|
331
296
|
|
|
332
|
-
return
|
|
297
|
+
return u128.div(a, b);
|
|
333
298
|
}
|
|
334
299
|
|
|
335
300
|
/**
|
|
@@ -376,8 +341,8 @@ export class SafeMath {
|
|
|
376
341
|
* ```
|
|
377
342
|
*
|
|
378
343
|
* @security The modulo operation is commonly used in access control patterns
|
|
379
|
-
*
|
|
380
|
-
*
|
|
344
|
+
* (e.g., round-robin selection). Ensure the modulus is never zero
|
|
345
|
+
* and be aware that patterns in modulo operations can be predictable.
|
|
381
346
|
*
|
|
382
347
|
* @remarks
|
|
383
348
|
* - Result is always in range [0, b-1]
|
|
@@ -385,13 +350,11 @@ export class SafeMath {
|
|
|
385
350
|
* - a = (a/b)*b + (a%b)
|
|
386
351
|
*/
|
|
387
352
|
public static mod(a: u256, b: u256): u256 {
|
|
388
|
-
if (
|
|
353
|
+
if (b.isZero()) {
|
|
389
354
|
throw new Revert('SafeMath: modulo by zero');
|
|
390
355
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const product = SafeMath.mul(divResult, b);
|
|
394
|
-
return SafeMath.sub(a, product);
|
|
356
|
+
// Use optimized arithmetic: a - (a/b)*b
|
|
357
|
+
return u256.sub(a, u256.mul(u256.div(a, b), b));
|
|
395
358
|
}
|
|
396
359
|
|
|
397
360
|
/**
|
|
@@ -410,14 +373,14 @@ export class SafeMath {
|
|
|
410
373
|
* ```
|
|
411
374
|
*
|
|
412
375
|
* @warning This function automatically reduces inputs modulo m before multiplication.
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
376
|
+
* This means mulmod(2m, x, m) returns 0, not because 2m*x is computed,
|
|
377
|
+
* but because 2m is reduced to 0 first. This is mathematically correct
|
|
378
|
+
* for modular arithmetic but may surprise developers expecting raw multiplication.
|
|
416
379
|
*
|
|
417
380
|
* @security Critical for cryptographic operations. The automatic modular reduction
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
381
|
+
* of inputs ensures all operations occur within the field Z/mZ, preventing
|
|
382
|
+
* overflow attacks. Used extensively in ECC scalar multiplication and
|
|
383
|
+
* RSA operations.
|
|
421
384
|
*
|
|
422
385
|
* @remarks
|
|
423
386
|
* - Critical for cryptographic operations (RSA, ECC)
|
|
@@ -428,18 +391,20 @@ export class SafeMath {
|
|
|
428
391
|
* - Inputs are automatically reduced: a = a % m, b = b % m
|
|
429
392
|
*/
|
|
430
393
|
public static mulmod(a: u256, b: u256, modulus: u256): u256 {
|
|
431
|
-
if (
|
|
394
|
+
if (modulus.isZero()) throw new Revert('SafeMath: modulo by zero');
|
|
432
395
|
|
|
433
396
|
// Keep invariants: 0 <= a,b < modulus
|
|
434
|
-
a = SafeMath.mod(a, modulus);
|
|
435
|
-
b = SafeMath.mod(b, modulus);
|
|
397
|
+
if (u256.ge(a, modulus)) a = SafeMath.mod(a, modulus);
|
|
398
|
+
if (u256.ge(b, modulus)) b = SafeMath.mod(b, modulus);
|
|
399
|
+
|
|
436
400
|
if (a.isZero() || b.isZero()) return u256.Zero;
|
|
437
401
|
|
|
438
402
|
let res = u256.Zero;
|
|
439
403
|
|
|
440
|
-
// LSB-first ladder
|
|
404
|
+
// Optimized LSB-first ladder
|
|
441
405
|
while (!b.isZero()) {
|
|
442
|
-
if (
|
|
406
|
+
// if (b & 1) using raw access for speed
|
|
407
|
+
if ((b.lo1 & 1) != 0) {
|
|
443
408
|
res = SafeMath.addModNoCarry(res, a, modulus);
|
|
444
409
|
}
|
|
445
410
|
b = u256.shr(b, 1);
|
|
@@ -458,9 +423,9 @@ export class SafeMath {
|
|
|
458
423
|
* @param p - The modulus (must be > 1)
|
|
459
424
|
* @returns x such that (k * x) % p = 1
|
|
460
425
|
* @throws {Revert} When:
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
426
|
+
* - p is 0 or 1 (invalid modulus)
|
|
427
|
+
* - k is 0 (zero has no inverse)
|
|
428
|
+
* - gcd(k, p) ≠ 1 (no inverse exists when k and p are not coprime)
|
|
464
429
|
*
|
|
465
430
|
* @example
|
|
466
431
|
* ```typescript
|
|
@@ -470,13 +435,13 @@ export class SafeMath {
|
|
|
470
435
|
* ```
|
|
471
436
|
*
|
|
472
437
|
* @warning Only works when gcd(k, p) = 1. For prime p, all non-zero k < p have inverses.
|
|
473
|
-
*
|
|
438
|
+
* For composite moduli, check coprimality before calling.
|
|
474
439
|
*
|
|
475
440
|
* @security Essential for cryptographic protocols. Used in:
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
441
|
+
* - RSA private key generation (d = e^(-1) mod φ(n))
|
|
442
|
+
* - ECDSA signature generation (s = k^(-1)(h + rd) mod n)
|
|
443
|
+
* - Point division in elliptic curves
|
|
444
|
+
* Incorrect inverse computation breaks these protocols entirely.
|
|
480
445
|
*
|
|
481
446
|
* @remarks
|
|
482
447
|
* - Essential for RSA key generation and ECC operations
|
|
@@ -486,75 +451,62 @@ export class SafeMath {
|
|
|
486
451
|
* - Common in cryptographic signatures and key exchanges
|
|
487
452
|
*/
|
|
488
453
|
public static modInverse(k: u256, p: u256): u256 {
|
|
489
|
-
|
|
490
|
-
if (p.isZero() || u256.eq(p, u256.One)) {
|
|
454
|
+
if (p.isZero() || u256.eq(p, SafeMath.ONE)) {
|
|
491
455
|
throw new Revert('SafeMath: modulus must be > 1');
|
|
492
456
|
}
|
|
493
|
-
|
|
494
457
|
if (k.isZero()) {
|
|
495
458
|
throw new Revert('SafeMath: no inverse for zero');
|
|
496
459
|
}
|
|
497
460
|
|
|
498
|
-
|
|
499
|
-
let
|
|
500
|
-
let
|
|
501
|
-
let
|
|
502
|
-
let
|
|
503
|
-
let
|
|
461
|
+
// Extended Euclidean Algo
|
|
462
|
+
let s = u256.Zero;
|
|
463
|
+
let old_s = u256.One;
|
|
464
|
+
let s_negative = false;
|
|
465
|
+
let old_s_negative = false;
|
|
466
|
+
let r = p.clone();
|
|
467
|
+
let old_r = k.clone();
|
|
504
468
|
|
|
505
469
|
while (!r.isZero()) {
|
|
506
|
-
const quotient =
|
|
470
|
+
const quotient = u256.div(old_r, r);
|
|
507
471
|
|
|
508
472
|
// Update r
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
// Update s
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
s = SafeMath.sub(product, old_s);
|
|
524
|
-
s_negative = true;
|
|
525
|
-
}
|
|
526
|
-
} else if (old_s_negative && s_negative) {
|
|
527
|
-
if (u256.ge(product, old_s)) {
|
|
528
|
-
s = SafeMath.sub(product, old_s);
|
|
529
|
-
s_negative = false;
|
|
473
|
+
const next_r = u256.sub(old_r, u256.mul(quotient, r));
|
|
474
|
+
old_r = r;
|
|
475
|
+
r = next_r;
|
|
476
|
+
|
|
477
|
+
// Update s
|
|
478
|
+
const prod = u256.mul(quotient, s);
|
|
479
|
+
let next_s: u256;
|
|
480
|
+
let next_s_negative: boolean;
|
|
481
|
+
|
|
482
|
+
// Logic optimized to avoid excessive object allocation
|
|
483
|
+
if (old_s_negative == s_negative) {
|
|
484
|
+
if (u256.ge(old_s, prod)) {
|
|
485
|
+
next_s = u256.sub(old_s, prod);
|
|
486
|
+
next_s_negative = old_s_negative;
|
|
530
487
|
} else {
|
|
531
|
-
|
|
532
|
-
|
|
488
|
+
next_s = u256.sub(prod, old_s);
|
|
489
|
+
next_s_negative = !old_s_negative;
|
|
533
490
|
}
|
|
534
|
-
} else if (!old_s_negative && s_negative) {
|
|
535
|
-
s = SafeMath.add(old_s, product);
|
|
536
|
-
s_negative = false;
|
|
537
491
|
} else {
|
|
538
|
-
|
|
539
|
-
|
|
492
|
+
next_s = u256.add(old_s, prod);
|
|
493
|
+
next_s_negative = old_s_negative;
|
|
540
494
|
}
|
|
541
495
|
|
|
542
|
-
old_s =
|
|
543
|
-
old_s_negative =
|
|
496
|
+
old_s = s;
|
|
497
|
+
old_s_negative = s_negative;
|
|
498
|
+
s = next_s;
|
|
499
|
+
s_negative = next_s_negative;
|
|
544
500
|
}
|
|
545
501
|
|
|
546
|
-
|
|
547
|
-
if (!u256.eq(old_r, u256.One)) {
|
|
502
|
+
if (!u256.eq(old_r, SafeMath.ONE)) {
|
|
548
503
|
throw new Revert('SafeMath: no modular inverse exists');
|
|
549
504
|
}
|
|
550
505
|
|
|
551
|
-
// Handle negative values
|
|
552
506
|
if (old_s_negative) {
|
|
553
|
-
const
|
|
554
|
-
if (
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
return SafeMath.sub(p, mod_result);
|
|
507
|
+
const mod_res = SafeMath.mod(old_s, p);
|
|
508
|
+
if (mod_res.isZero()) return u256.Zero;
|
|
509
|
+
return u256.sub(p, mod_res);
|
|
558
510
|
}
|
|
559
511
|
|
|
560
512
|
return SafeMath.mod(old_s, p);
|
|
@@ -576,16 +528,16 @@ export class SafeMath {
|
|
|
576
528
|
* ```
|
|
577
529
|
*
|
|
578
530
|
* @warning CRITICAL: Unlike ALL other SafeMath operations, bit shifts do NOT throw on overflow!
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
531
|
+
* Bits shifted beyond the type width are SILENTLY LOST. This is intentional
|
|
532
|
+
* behavior that matches CPU bit shift semantics, but differs philosophically
|
|
533
|
+
* from other SafeMath operations which fail safely on overflow.
|
|
582
534
|
*
|
|
583
535
|
* @security If you need overflow detection for bit shifts, implement it manually:
|
|
584
536
|
* ```typescript
|
|
585
537
|
* const shifted = SafeMath.shl(value, n);
|
|
586
538
|
* const restored = SafeMath.shr(shifted, n);
|
|
587
539
|
* if (!u256.eq(restored, value)) {
|
|
588
|
-
*
|
|
540
|
+
* throw new Revert('Shift overflow detected');
|
|
589
541
|
* }
|
|
590
542
|
* ```
|
|
591
543
|
*
|
|
@@ -598,23 +550,43 @@ export class SafeMath {
|
|
|
598
550
|
* - Commonly used in bit manipulation and flag operations
|
|
599
551
|
*/
|
|
600
552
|
public static shl(value: u256, shift: i32): u256 {
|
|
601
|
-
if (shift <= 0)
|
|
602
|
-
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
if (shift >= 256) {
|
|
606
|
-
return new u256();
|
|
607
|
-
}
|
|
553
|
+
if (shift <= 0) return shift == 0 ? value.clone() : u256.Zero;
|
|
554
|
+
if (shift >= 256) return u256.Zero;
|
|
608
555
|
|
|
609
556
|
shift &= 255;
|
|
610
557
|
|
|
611
|
-
|
|
612
|
-
const
|
|
613
|
-
const
|
|
558
|
+
// GAS OPTIMIZATION: Unrolled manual shifting avoids array allocation of segments
|
|
559
|
+
const bits = 64;
|
|
560
|
+
const segShift = (shift / bits) | 0;
|
|
561
|
+
const bitShift = shift % bits;
|
|
562
|
+
const invShift = bits - bitShift;
|
|
563
|
+
|
|
564
|
+
let r0: u64 = 0,
|
|
565
|
+
r1: u64 = 0,
|
|
566
|
+
r2: u64 = 0,
|
|
567
|
+
r3: u64 = 0;
|
|
568
|
+
const i0 = value.lo1,
|
|
569
|
+
i1 = value.lo2,
|
|
570
|
+
i2 = value.hi1,
|
|
571
|
+
i3 = value.hi2;
|
|
572
|
+
|
|
573
|
+
if (segShift == 0) {
|
|
574
|
+
r0 = i0 << bitShift;
|
|
575
|
+
r1 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
576
|
+
r2 = (i2 << bitShift) | (bitShift == 0 ? 0 : i1 >>> invShift);
|
|
577
|
+
r3 = (i3 << bitShift) | (bitShift == 0 ? 0 : i2 >>> invShift);
|
|
578
|
+
} else if (segShift == 1) {
|
|
579
|
+
r1 = i0 << bitShift;
|
|
580
|
+
r2 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
581
|
+
r3 = (i2 << bitShift) | (bitShift == 0 ? 0 : i1 >>> invShift);
|
|
582
|
+
} else if (segShift == 2) {
|
|
583
|
+
r2 = i0 << bitShift;
|
|
584
|
+
r3 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
585
|
+
} else if (segShift == 3) {
|
|
586
|
+
r3 = i0 << bitShift;
|
|
587
|
+
}
|
|
614
588
|
|
|
615
|
-
|
|
616
|
-
const result = SafeMath.shlSegment(segments, segmentShift, bitShift, bitsPerSegment, 4);
|
|
617
|
-
return new u256(result[0], result[1], result[2], result[3]);
|
|
589
|
+
return new u256(r0, r1, r2, r3);
|
|
618
590
|
}
|
|
619
591
|
|
|
620
592
|
/**
|
|
@@ -631,23 +603,28 @@ export class SafeMath {
|
|
|
631
603
|
* - Overflow bits are truncated without error
|
|
632
604
|
*/
|
|
633
605
|
public static shl128(value: u128, shift: i32): u128 {
|
|
634
|
-
if (shift <= 0)
|
|
635
|
-
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
if (shift >= 128) {
|
|
639
|
-
return new u128();
|
|
640
|
-
}
|
|
606
|
+
if (shift <= 0) return shift == 0 ? value.clone() : u128.Zero;
|
|
607
|
+
if (shift >= 128) return u128.Zero;
|
|
641
608
|
|
|
642
609
|
shift &= 127;
|
|
610
|
+
const bits = 64;
|
|
611
|
+
const segShift = (shift / bits) | 0;
|
|
612
|
+
const bitShift = shift % bits;
|
|
613
|
+
const invShift = bits - bitShift;
|
|
614
|
+
|
|
615
|
+
let r0: u64 = 0,
|
|
616
|
+
r1: u64 = 0;
|
|
617
|
+
const i0 = value.lo,
|
|
618
|
+
i1 = value.hi;
|
|
619
|
+
|
|
620
|
+
if (segShift == 0) {
|
|
621
|
+
r0 = i0 << bitShift;
|
|
622
|
+
r1 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
623
|
+
} else if (segShift == 1) {
|
|
624
|
+
r1 = i0 << bitShift;
|
|
625
|
+
}
|
|
643
626
|
|
|
644
|
-
|
|
645
|
-
const segmentShift = (shift / bitsPerSegment) | 0;
|
|
646
|
-
const bitShift = shift % bitsPerSegment;
|
|
647
|
-
|
|
648
|
-
const segments = [value.lo, value.hi];
|
|
649
|
-
const result = SafeMath.shlSegment(segments, segmentShift, bitShift, bitsPerSegment, 2);
|
|
650
|
-
return new u128(result[0], result[1]);
|
|
627
|
+
return new u128(r0, r1);
|
|
651
628
|
}
|
|
652
629
|
|
|
653
630
|
/**
|
|
@@ -727,11 +704,11 @@ export class SafeMath {
|
|
|
727
704
|
* ```
|
|
728
705
|
*
|
|
729
706
|
* @warning Returns 1 for inputs 1, 2, and 3 (not just 1). This is because
|
|
730
|
-
*
|
|
707
|
+
* floor(√2) = floor(√3) = 1. Be aware of this when working with small values.
|
|
731
708
|
*
|
|
732
709
|
* @security No overflow possible as sqrt(u256.Max) < 2^128. Used in various DeFi
|
|
733
|
-
*
|
|
734
|
-
*
|
|
710
|
+
* protocols for computing prices from liquidity pools (e.g., Uniswap V2's
|
|
711
|
+
* geometric mean price calculation).
|
|
735
712
|
*
|
|
736
713
|
* @remarks
|
|
737
714
|
* - Uses Newton-Raphson method for values > 3
|
|
@@ -742,26 +719,22 @@ export class SafeMath {
|
|
|
742
719
|
* - Converges in O(log log n) iterations
|
|
743
720
|
*/
|
|
744
721
|
public static sqrt(y: u256): u256 {
|
|
745
|
-
if (u256.gt(y,
|
|
722
|
+
if (u256.gt(y, SafeMath.CONST_3)) {
|
|
746
723
|
let z = y;
|
|
747
724
|
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
const d = SafeMath.div(y, u246_2);
|
|
751
|
-
let x = SafeMath.add(d, u256.One);
|
|
725
|
+
// Initial guess: y / 2 + 1
|
|
726
|
+
let x = u256.add(u256.div(y, SafeMath.CONST_2), SafeMath.ONE);
|
|
752
727
|
|
|
753
728
|
while (u256.lt(x, z)) {
|
|
754
729
|
z = x;
|
|
755
|
-
|
|
756
|
-
const
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
x = SafeMath.div(y2, u246_2);
|
|
730
|
+
const divResult = u256.div(y, x);
|
|
731
|
+
const sum = u256.add(divResult, x);
|
|
732
|
+
x = u256.div(sum, SafeMath.CONST_2);
|
|
760
733
|
}
|
|
761
734
|
|
|
762
735
|
return z;
|
|
763
|
-
} else if (!
|
|
764
|
-
return
|
|
736
|
+
} else if (!y.isZero()) {
|
|
737
|
+
return SafeMath.ONE;
|
|
765
738
|
} else {
|
|
766
739
|
return u256.Zero;
|
|
767
740
|
}
|
|
@@ -782,12 +755,12 @@ export class SafeMath {
|
|
|
782
755
|
* ```
|
|
783
756
|
*
|
|
784
757
|
* @warning Large bases with even small exponents can overflow. For example,
|
|
785
|
-
*
|
|
786
|
-
*
|
|
758
|
+
* (2^128)^2 = 2^256 which overflows. Always consider the magnitude
|
|
759
|
+
* of your inputs.
|
|
787
760
|
*
|
|
788
761
|
* @security Used in compound interest calculations and bonding curves. Be extremely
|
|
789
|
-
*
|
|
790
|
-
*
|
|
762
|
+
* careful with user-supplied exponents as they can easily cause DoS through
|
|
763
|
+
* gas exhaustion (large exponents) or overflows.
|
|
791
764
|
*
|
|
792
765
|
* @remarks
|
|
793
766
|
* - Uses binary exponentiation (square-and-multiply) for O(log n) efficiency
|
|
@@ -796,21 +769,24 @@ export class SafeMath {
|
|
|
796
769
|
* - Gas cost increases with exponent bit count
|
|
797
770
|
*/
|
|
798
771
|
public static pow(base: u256, exponent: u256): u256 {
|
|
799
|
-
if (exponent.isZero()) return
|
|
772
|
+
if (exponent.isZero()) return SafeMath.ONE;
|
|
800
773
|
if (base.isZero()) return u256.Zero;
|
|
801
|
-
if (u256.eq(base,
|
|
774
|
+
if (u256.eq(base, SafeMath.ONE)) return SafeMath.ONE;
|
|
802
775
|
|
|
803
|
-
let result: u256 =
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
776
|
+
let result: u256 = SafeMath.ONE;
|
|
777
|
+
let b = base;
|
|
778
|
+
let e = exponent;
|
|
779
|
+
|
|
780
|
+
while (u256.gt(e, u256.Zero)) {
|
|
781
|
+
// Check LSB using bitwise for speed
|
|
782
|
+
if ((e.lo1 & 1) != 0) {
|
|
783
|
+
result = SafeMath.mul(result, b);
|
|
807
784
|
}
|
|
808
785
|
|
|
809
|
-
|
|
786
|
+
e = u256.shr(e, 1);
|
|
810
787
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
base = SafeMath.mul(base, base);
|
|
788
|
+
if (u256.gt(e, u256.Zero)) {
|
|
789
|
+
b = SafeMath.mul(b, b);
|
|
814
790
|
}
|
|
815
791
|
}
|
|
816
792
|
return result;
|
|
@@ -830,8 +806,8 @@ export class SafeMath {
|
|
|
830
806
|
* ```
|
|
831
807
|
*
|
|
832
808
|
* @security Commonly used for token decimal scaling. Ensure exponent values
|
|
833
|
-
*
|
|
834
|
-
*
|
|
809
|
+
* come from trusted sources (e.g., immutable token decimals) rather
|
|
810
|
+
* than user input to prevent reverts.
|
|
835
811
|
*
|
|
836
812
|
* @remarks
|
|
837
813
|
* - Optimized specifically for base 10 calculations
|
|
@@ -844,11 +820,9 @@ export class SafeMath {
|
|
|
844
820
|
throw new Revert('SafeMath: exponent too large, would overflow');
|
|
845
821
|
}
|
|
846
822
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
let result: u256 = u256.One;
|
|
823
|
+
let result: u256 = SafeMath.ONE;
|
|
850
824
|
for (let i: u8 = 0; i < exponent; i++) {
|
|
851
|
-
result = SafeMath.mul(result,
|
|
825
|
+
result = SafeMath.mul(result, SafeMath.CONST_10);
|
|
852
826
|
}
|
|
853
827
|
return result;
|
|
854
828
|
}
|
|
@@ -941,7 +915,7 @@ export class SafeMath {
|
|
|
941
915
|
*/
|
|
942
916
|
@inline
|
|
943
917
|
public static isEven(a: u256): bool {
|
|
944
|
-
return
|
|
918
|
+
return (a.lo1 & 1) == 0;
|
|
945
919
|
}
|
|
946
920
|
|
|
947
921
|
/**
|
|
@@ -952,7 +926,7 @@ export class SafeMath {
|
|
|
952
926
|
* @throws {Revert} When value equals u256.Max (would overflow)
|
|
953
927
|
*
|
|
954
928
|
* @warning At u256.Max, incrementing would wrap to 0. This function throws
|
|
955
|
-
*
|
|
929
|
+
* instead to prevent silent wraparound errors.
|
|
956
930
|
*
|
|
957
931
|
* @remarks
|
|
958
932
|
* - Equivalent to add(value, 1) but potentially more efficient
|
|
@@ -973,14 +947,14 @@ export class SafeMath {
|
|
|
973
947
|
* @throws {Revert} When value equals 0 (would underflow)
|
|
974
948
|
*
|
|
975
949
|
* @warning At 0, decrementing would wrap to u256.Max. This function throws
|
|
976
|
-
*
|
|
950
|
+
* instead to prevent silent wraparound errors.
|
|
977
951
|
*
|
|
978
952
|
* @remarks
|
|
979
953
|
* - Equivalent to sub(value, 1) but potentially more efficient
|
|
980
954
|
* - Safe against underflow at zero
|
|
981
955
|
*/
|
|
982
956
|
public static dec(value: u256): u256 {
|
|
983
|
-
if (
|
|
957
|
+
if (value.isZero()) {
|
|
984
958
|
throw new Revert('SafeMath: decrement underflow');
|
|
985
959
|
}
|
|
986
960
|
return value.preDec();
|
|
@@ -1002,15 +976,15 @@ export class SafeMath {
|
|
|
1002
976
|
* ```
|
|
1003
977
|
*
|
|
1004
978
|
* @warning Returns 0 for both input 0 and input 1. While log2(0) is mathematically
|
|
1005
|
-
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
979
|
+
* undefined and log2(1) = 0, this implementation returns 0 for both cases
|
|
980
|
+
* to avoid reverts and maintain gas efficiency in smart contracts. Callers
|
|
981
|
+
* requiring mathematical precision should handle these edge cases explicitly.
|
|
1008
982
|
*
|
|
1009
983
|
* @security Extensively tested for monotonicity and consistency. Critical for:
|
|
1010
|
-
*
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1013
|
-
*
|
|
984
|
+
* - Binary search algorithms in sorted data structures
|
|
985
|
+
* - Bit manipulation operations requiring position of highest bit
|
|
986
|
+
* - Rough categorization of value magnitudes in O(1) time
|
|
987
|
+
* - Efficient range checks in permission systems
|
|
1014
988
|
*
|
|
1015
989
|
* @remarks
|
|
1016
990
|
* - Returns the position of the highest set bit (MSB)
|
|
@@ -1021,16 +995,9 @@ export class SafeMath {
|
|
|
1021
995
|
* - More efficient than preciseLog when exact precision isn't needed
|
|
1022
996
|
*/
|
|
1023
997
|
public static approximateLog2(x: u256): u256 {
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
while (u256.gt(value, u256.One)) {
|
|
1029
|
-
value = u256.shr(value, 1);
|
|
1030
|
-
n = SafeMath.add(n, u256.One);
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
return n;
|
|
998
|
+
const bitLen = SafeMath.bitLength256(x);
|
|
999
|
+
if (bitLen == 0) return u256.Zero;
|
|
1000
|
+
return u256.fromU32(bitLen - 1);
|
|
1034
1001
|
}
|
|
1035
1002
|
|
|
1036
1003
|
/**
|
|
@@ -1052,18 +1019,18 @@ export class SafeMath {
|
|
|
1052
1019
|
* ```
|
|
1053
1020
|
*
|
|
1054
1021
|
* @warning This function has been extensively tested and validated for accuracy.
|
|
1055
|
-
*
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
*
|
|
1022
|
+
* The maximum error is bounded to 6 units (0.000006) across the entire
|
|
1023
|
+
* input domain. While the implementation is production-ready, extreme
|
|
1024
|
+
* values near u256 boundaries may experience precision degradation due
|
|
1025
|
+
* to the limitations of integer arithmetic at such scales.
|
|
1059
1026
|
*
|
|
1060
1027
|
* @security Critical for DeFi applications including:
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
1066
|
-
*
|
|
1028
|
+
* - Automated Market Makers (AMMs) for price calculations
|
|
1029
|
+
* - Interest rate models in lending protocols
|
|
1030
|
+
* - Option pricing using Black-Scholes formulas
|
|
1031
|
+
* - Bonding curve calculations
|
|
1032
|
+
* Incorrect logarithm calculations can lead to severe mispricing,
|
|
1033
|
+
* arbitrage opportunities, or protocol insolvency.
|
|
1067
1034
|
*
|
|
1068
1035
|
* @remarks
|
|
1069
1036
|
* - Algorithm: Decomposes x = 2^k * (1 + r) where 0 ≤ r < 1
|
|
@@ -1076,7 +1043,7 @@ export class SafeMath {
|
|
|
1076
1043
|
* - Monotonicity guaranteed across entire input range
|
|
1077
1044
|
*/
|
|
1078
1045
|
public static preciseLog(x: u256): u256 {
|
|
1079
|
-
if (x.isZero() || u256.eq(x,
|
|
1046
|
+
if (x.isZero() || u256.eq(x, SafeMath.ONE)) {
|
|
1080
1047
|
return u256.Zero;
|
|
1081
1048
|
}
|
|
1082
1049
|
|
|
@@ -1085,28 +1052,23 @@ export class SafeMath {
|
|
|
1085
1052
|
return u256.Zero;
|
|
1086
1053
|
}
|
|
1087
1054
|
|
|
1088
|
-
// integer part of log2(x)
|
|
1089
1055
|
const k: u32 = bitLen - 1;
|
|
1090
|
-
const
|
|
1091
|
-
const base: u256 = SafeMath.mul(u256.fromU32(k), LN2_SCALED);
|
|
1056
|
+
const base: u256 = SafeMath.mul(u256.fromU32(k), u256.fromU64(SafeMath.LN2_SCALED));
|
|
1092
1057
|
|
|
1093
|
-
|
|
1094
|
-
const pow2k = SafeMath.shl(u256.One, <i32>k);
|
|
1058
|
+
const pow2k = SafeMath.shl(SafeMath.ONE, <i32>k);
|
|
1095
1059
|
const xPrime = SafeMath.sub(x, pow2k);
|
|
1096
1060
|
|
|
1097
1061
|
if (xPrime.isZero()) {
|
|
1098
1062
|
return base;
|
|
1099
1063
|
}
|
|
1100
1064
|
|
|
1101
|
-
|
|
1102
|
-
const xPrimeTimes1e6 = SafeMath.mul(xPrime, u256.fromU64(1_000_000));
|
|
1065
|
+
const xPrimeTimes1e6 = SafeMath.mul(xPrime, u256.fromU64(SafeMath.SCALE_1E6));
|
|
1103
1066
|
const rScaled = SafeMath.div(xPrimeTimes1e6, pow2k);
|
|
1104
1067
|
|
|
1105
1068
|
if (u256.gt(rScaled, u256.fromU64(u64.MAX_VALUE))) {
|
|
1106
1069
|
throw new Revert('SafeMath: rScaled overflow, input too large');
|
|
1107
1070
|
}
|
|
1108
1071
|
|
|
1109
|
-
// approximate ln(1 + r)
|
|
1110
1072
|
const frac: u64 = SafeMath.polyLn1p3(rScaled.toU64());
|
|
1111
1073
|
|
|
1112
1074
|
return SafeMath.add(base, u256.fromU64(frac));
|
|
@@ -1127,15 +1089,15 @@ export class SafeMath {
|
|
|
1127
1089
|
* ```
|
|
1128
1090
|
*
|
|
1129
1091
|
* @warning Uses step-wise approximation based on bit length. The result has
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1092
|
+
* discrete jumps at powers of 2, with constant values between them.
|
|
1093
|
+
* Maximum error is ln(2) ≈ 0.693 (scaled: 693,147). For smooth,
|
|
1094
|
+
* continuous logarithm curves required in pricing models, use preciseLog.
|
|
1133
1095
|
*
|
|
1134
1096
|
* @security Suitable for applications where monotonicity matters more than precision:
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1097
|
+
* - Rough categorization of token amounts
|
|
1098
|
+
* - Tier-based reward systems
|
|
1099
|
+
* - Quick magnitude comparisons
|
|
1100
|
+
* Not recommended for precise financial calculations or smooth curves.
|
|
1139
1101
|
*
|
|
1140
1102
|
* @remarks
|
|
1141
1103
|
* - Algorithm: ln(x) ≈ (bitLength(x) - 1) * ln(2)
|
|
@@ -1146,7 +1108,7 @@ export class SafeMath {
|
|
|
1146
1108
|
* - Monotonically non-decreasing (required for security)
|
|
1147
1109
|
*/
|
|
1148
1110
|
public static approxLog(x: u256): u256 {
|
|
1149
|
-
if (x.isZero() || u256.eq(x,
|
|
1111
|
+
if (x.isZero() || u256.eq(x, SafeMath.ONE)) {
|
|
1150
1112
|
return u256.Zero;
|
|
1151
1113
|
}
|
|
1152
1114
|
|
|
@@ -1155,10 +1117,9 @@ export class SafeMath {
|
|
|
1155
1117
|
return u256.Zero;
|
|
1156
1118
|
}
|
|
1157
1119
|
|
|
1158
|
-
const LN2_SCALED: u64 = 693147; // ln(2)*1e6
|
|
1159
1120
|
const log2Count: u64 = (bitLen - 1) as u64;
|
|
1160
1121
|
|
|
1161
|
-
return SafeMath.mul(u256.fromU64(log2Count), u256.fromU64(LN2_SCALED));
|
|
1122
|
+
return SafeMath.mul(u256.fromU64(log2Count), u256.fromU64(SafeMath.LN2_SCALED));
|
|
1162
1123
|
}
|
|
1163
1124
|
|
|
1164
1125
|
/**
|
|
@@ -1176,13 +1137,13 @@ export class SafeMath {
|
|
|
1176
1137
|
* ```
|
|
1177
1138
|
*
|
|
1178
1139
|
* @warning Returns 0 for input 0, which technically requires 0 bits to represent.
|
|
1179
|
-
*
|
|
1140
|
+
* This differs from some implementations that might return 1 for consistency.
|
|
1180
1141
|
*
|
|
1181
1142
|
* @security Validated across all u256 segment boundaries. Used internally for:
|
|
1182
|
-
*
|
|
1183
|
-
*
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1143
|
+
* - Logarithm calculations (bitLength = floor(log2(x)) + 1 for x > 0)
|
|
1144
|
+
* - Efficient range determination in binary operations
|
|
1145
|
+
* - Gas optimization by determining operation complexity
|
|
1146
|
+
* - Overflow prediction in multiplication/exponentiation
|
|
1186
1147
|
*
|
|
1187
1148
|
* @remarks
|
|
1188
1149
|
* - Handles values across all four u64 segments of u256
|
|
@@ -1193,26 +1154,13 @@ export class SafeMath {
|
|
|
1193
1154
|
* - Relationship: bitLength(x) = approximateLog2(x) + 1 for x > 1
|
|
1194
1155
|
*/
|
|
1195
1156
|
public static bitLength256(x: u256): u32 {
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
if (x.
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
if (x.hi1 != 0) {
|
|
1206
|
-
const partial: u32 = SafeMath.bitLength64(x.hi1);
|
|
1207
|
-
return 128 + partial;
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
if (x.lo2 != 0) {
|
|
1211
|
-
const partial: u32 = SafeMath.bitLength64(x.lo2);
|
|
1212
|
-
return 64 + partial;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
return SafeMath.bitLength64(x.lo1);
|
|
1157
|
+
// GAS OPTIMIZATION: Use clz intrinsic to find MSB in 1 instruction.
|
|
1158
|
+
// Must explicit cast result to u32 for subtraction logic.
|
|
1159
|
+
if (x.hi2 != 0) return 256 - <u32>clz(x.hi2);
|
|
1160
|
+
if (x.hi1 != 0) return 192 - <u32>clz(x.hi1);
|
|
1161
|
+
if (x.lo2 != 0) return 128 - <u32>clz(x.lo2);
|
|
1162
|
+
if (x.lo1 != 0) return 64 - <u32>clz(x.lo1);
|
|
1163
|
+
return 0;
|
|
1216
1164
|
}
|
|
1217
1165
|
|
|
1218
1166
|
/**
|
|
@@ -1236,18 +1184,18 @@ export class SafeMath {
|
|
|
1236
1184
|
* ```
|
|
1237
1185
|
*
|
|
1238
1186
|
* @warning This function is optimized for internal use by preciseLog and requires
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1243
|
-
*
|
|
1187
|
+
* understanding of fixed-point arithmetic. The input uses a scaling factor
|
|
1188
|
+
* of 10^6, meaning rScaled=500000 represents z=0.5. Input must be strictly
|
|
1189
|
+
* less than 1,000,000 to represent valid z values in [0,1). Direct usage
|
|
1190
|
+
* outside of the logarithm calculation pipeline requires careful attention
|
|
1191
|
+
* to scaling conventions.
|
|
1244
1192
|
*
|
|
1245
1193
|
* @security The algorithm uses integer arithmetic throughout to avoid
|
|
1246
|
-
*
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1194
|
+
* floating-point vulnerabilities. All intermediate calculations
|
|
1195
|
+
* are designed to prevent overflow: maximum intermediate value
|
|
1196
|
+
* is approximately 1.11×10^11, well below u64.Max (≈1.84×10^19).
|
|
1197
|
+
* This ensures deterministic, reproducible results critical for
|
|
1198
|
+
* consensus in blockchain applications.
|
|
1251
1199
|
*
|
|
1252
1200
|
* @remarks
|
|
1253
1201
|
* Algorithm details:
|
|
@@ -1266,18 +1214,15 @@ export class SafeMath {
|
|
|
1266
1214
|
* - All divisions use banker's rounding via (numerator + divisor/2) / divisor
|
|
1267
1215
|
*/
|
|
1268
1216
|
public static polyLn1p3(rScaled: u64): u64 {
|
|
1269
|
-
|
|
1270
|
-
if (rScaled >= 1_000_000) {
|
|
1217
|
+
if (rScaled >= SafeMath.SCALE_1E6) {
|
|
1271
1218
|
throw new Revert('SafeMath.polyLn1p3: input out of range');
|
|
1272
1219
|
}
|
|
1273
1220
|
|
|
1274
|
-
// Handle the zero case explicitly
|
|
1275
1221
|
if (rScaled == 0) {
|
|
1276
1222
|
return 0;
|
|
1277
1223
|
}
|
|
1278
1224
|
|
|
1279
|
-
|
|
1280
|
-
const SCALE: u64 = 1_000_000;
|
|
1225
|
+
const SCALE: u64 = SafeMath.SCALE_1E6;
|
|
1281
1226
|
const HALF_SCALE: u64 = 500_000;
|
|
1282
1227
|
|
|
1283
1228
|
// Compute w = z / (2 + z)
|
|
@@ -1306,56 +1251,14 @@ export class SafeMath {
|
|
|
1306
1251
|
|
|
1307
1252
|
// ==================== Internal Helper Functions ====================
|
|
1308
1253
|
|
|
1309
|
-
/**
|
|
1310
|
-
* @internal
|
|
1311
|
-
* Calculates bit length of a u64 value.
|
|
1312
|
-
* Used internally by bitLength256 for individual segment processing.
|
|
1313
|
-
*/
|
|
1314
|
-
private static bitLength64(value: u64): u32 {
|
|
1315
|
-
if (value == 0) return 0;
|
|
1316
|
-
|
|
1317
|
-
let count: u32 = 0;
|
|
1318
|
-
let temp = value;
|
|
1319
|
-
while (temp > 0) {
|
|
1320
|
-
temp >>>= 1;
|
|
1321
|
-
count++;
|
|
1322
|
-
}
|
|
1323
|
-
return count;
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
/**
|
|
1327
|
-
* @internal
|
|
1328
|
-
* Helper for shift operations across word boundaries.
|
|
1329
|
-
*/
|
|
1330
|
-
private static shlSegment(
|
|
1331
|
-
segments: u64[],
|
|
1332
|
-
segmentShift: i32,
|
|
1333
|
-
bitShift: i32,
|
|
1334
|
-
bitsPerSegment: i32,
|
|
1335
|
-
fillCount: u8,
|
|
1336
|
-
): u64[] {
|
|
1337
|
-
const result = new Array<u64>(fillCount).fill(0);
|
|
1338
|
-
|
|
1339
|
-
for (let i = 0; i < segments.length; i++) {
|
|
1340
|
-
if (i + segmentShift < segments.length) {
|
|
1341
|
-
result[i + segmentShift] |= segments[i] << bitShift;
|
|
1342
|
-
}
|
|
1343
|
-
if (bitShift != 0 && i + segmentShift + 1 < segments.length) {
|
|
1344
|
-
result[i + segmentShift + 1] |= segments[i] >>> (bitsPerSegment - bitShift);
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
return result;
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
1254
|
/**
|
|
1352
1255
|
* @internal
|
|
1353
1256
|
* Modular addition helper that prevents overflow.
|
|
1354
1257
|
* Pre-condition: 0 <= x,y < m
|
|
1355
1258
|
*/
|
|
1356
1259
|
private static addModNoCarry(x: u256, y: u256, m: u256): u256 {
|
|
1357
|
-
const mMinusY =
|
|
1358
|
-
return u256.ge(x, mMinusY) ?
|
|
1260
|
+
const mMinusY = u256.sub(m, y);
|
|
1261
|
+
return u256.ge(x, mMinusY) ? u256.sub(x, mMinusY) : u256.add(x, y);
|
|
1359
1262
|
}
|
|
1360
1263
|
|
|
1361
1264
|
/**
|
|
@@ -1364,7 +1267,7 @@ export class SafeMath {
|
|
|
1364
1267
|
* Pre-condition: 0 <= x < m
|
|
1365
1268
|
*/
|
|
1366
1269
|
private static doubleModNoCarry(x: u256, m: u256): u256 {
|
|
1367
|
-
const mMinusX =
|
|
1368
|
-
return u256.ge(x, mMinusX) ?
|
|
1270
|
+
const mMinusX = u256.sub(m, x);
|
|
1271
|
+
return u256.ge(x, mMinusX) ? u256.sub(x, mMinusX) : u256.add(x, x);
|
|
1369
1272
|
}
|
|
1370
1273
|
}
|