@btc-vision/btc-runtime 1.3.19 → 1.3.20
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 +1 -1
- package/runtime/types/SafeMath.ts +133 -8
package/package.json
CHANGED
|
@@ -391,6 +391,139 @@ export class SafeMath {
|
|
|
391
391
|
return n;
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
public static bitLength256(x: u256): u32 {
|
|
395
|
+
// If zero => bitlength is 0
|
|
396
|
+
if (u256.eq(x, u256.Zero)) {
|
|
397
|
+
return 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// hi2 != 0 => top 64 bits => bit positions 192..255
|
|
401
|
+
if (x.hi2 != 0) {
|
|
402
|
+
const partial: u32 = SafeMath.bitLength64(x.hi2);
|
|
403
|
+
return 192 + partial;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// hi1 != 0 => next 64 bits => bit positions 128..191
|
|
407
|
+
if (x.hi1 != 0) {
|
|
408
|
+
const partial: u32 = SafeMath.bitLength64(x.hi1);
|
|
409
|
+
return 128 + partial;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// lo2 != 0 => next 64 bits => bit positions 64..127
|
|
413
|
+
if (x.lo2 != 0) {
|
|
414
|
+
const partial: u32 = SafeMath.bitLength64(x.lo2);
|
|
415
|
+
return 64 + partial;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// else in lo1 => bit positions 0..63
|
|
419
|
+
return SafeMath.bitLength64(x.lo1);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
public static approxLog(x: u256): u256 {
|
|
423
|
+
// If x == 0 or x == 1, return 0 (ln(1)=0, ln(0) is undefined but we treat as 0)
|
|
424
|
+
if (x.isZero() || u256.eq(x, u256.One)) {
|
|
425
|
+
return u256.Zero;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 1) Find bit length
|
|
429
|
+
const bitLen: u32 = SafeMath.bitLength256(x);
|
|
430
|
+
// if bitLen=0 or 1 => that implies x <=1, but we already handled x=0,1 => just safe-check
|
|
431
|
+
if (bitLen <= 1) {
|
|
432
|
+
return u256.Zero;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 2) ln(x) ~ (bitLen - 1) * ln(2)
|
|
436
|
+
// We'll store ln(2) in a scaled integer. e.g., LN2_SCALED = 693147 => ln(2)*1e6
|
|
437
|
+
const LN2_SCALED: u64 = 693147; // approximate ln(2)*1e6
|
|
438
|
+
const log2Count: u64 = (bitLen - 1) as u64; // integer part of log2(x)
|
|
439
|
+
|
|
440
|
+
// Multiply in pure integer
|
|
441
|
+
return SafeMath.mul(u256.fromU64(log2Count), u256.fromU64(LN2_SCALED));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Return ln(x) * 1e6 for x>1. If x==0 or 1, returns 0.
|
|
446
|
+
* Uses: ln(x) = (k * ln(2)) + ln(1 + r),
|
|
447
|
+
* where k = floor(log2(x)) and r = (x - 2^k)/2^k
|
|
448
|
+
*/
|
|
449
|
+
@unsafe // UNTESTED.
|
|
450
|
+
public static preciseLog(x: u256): u256 {
|
|
451
|
+
if (x.isZero() || u256.eq(x, u256.One)) {
|
|
452
|
+
return u256.Zero;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const bitLen = SafeMath.bitLength256(x);
|
|
456
|
+
if (bitLen <= 1) {
|
|
457
|
+
return u256.Zero;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// integer part of log2(x)
|
|
461
|
+
const k: u32 = bitLen - 1;
|
|
462
|
+
const LN2_SCALED = u256.fromU64(693147); // ln(2)*1e6
|
|
463
|
+
const base: u256 = SafeMath.mul(u256.fromU32(k), LN2_SCALED);
|
|
464
|
+
|
|
465
|
+
// 2^k
|
|
466
|
+
const pow2k = SafeMath.shl(u256.One, <i32>k);
|
|
467
|
+
const xPrime = SafeMath.sub(x, pow2k); // leftover
|
|
468
|
+
|
|
469
|
+
if (xPrime.isZero()) {
|
|
470
|
+
// x was exactly 2^k => no fractional part
|
|
471
|
+
return base;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// rScaled = ((x - 2^k)*1e6)/2^k
|
|
475
|
+
const xPrimeTimes1e6 = SafeMath.mul(xPrime, u256.fromU64(1_000_000));
|
|
476
|
+
const rScaled = SafeMath.div(xPrimeTimes1e6, pow2k); // 0..999999
|
|
477
|
+
|
|
478
|
+
// approximate ln(1 + r)
|
|
479
|
+
const frac: u64 = SafeMath.polyLn1p3(rScaled.toU64());
|
|
480
|
+
|
|
481
|
+
return SafeMath.add(base, u256.fromU64(frac));
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
public static pow10(exponent: u8): u256 {
|
|
485
|
+
let result: u256 = u256.One;
|
|
486
|
+
for (let i: u8 = 0; i < exponent; i++) {
|
|
487
|
+
result = SafeMath.mul(result, u256.fromU32(10));
|
|
488
|
+
}
|
|
489
|
+
return result;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* polyLn1p3: 3-term polynomial for ln(1 + z), with z in [0,1).
|
|
494
|
+
* rScaled = z * 1e6
|
|
495
|
+
* returns (ln(1+z)) in scale=1e6
|
|
496
|
+
*/
|
|
497
|
+
// UNTESTED.
|
|
498
|
+
@unsafe
|
|
499
|
+
public static polyLn1p3(rScaled: u64): u64 {
|
|
500
|
+
// term1 = z
|
|
501
|
+
const term1: u64 = rScaled;
|
|
502
|
+
|
|
503
|
+
// term2 => z^2/2
|
|
504
|
+
const z2 = term1 * term1; // up to 1e12
|
|
505
|
+
const z2Div = (z2 / 1_000_000) >>> 1; // divide by scale and by 2
|
|
506
|
+
|
|
507
|
+
// term3 => z^3/3
|
|
508
|
+
const z3 = z2 * term1; // up to 1e18
|
|
509
|
+
const z3Div = z3 / (1_000_000 * 1_000_000) / 3; // => scale
|
|
510
|
+
|
|
511
|
+
// ln(1+z) ~ z - z^2/2 + z^3/3
|
|
512
|
+
return term1 - z2Div + z3Div;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
private static bitLength64(value: u64): u32 {
|
|
516
|
+
if (value == 0) return 0;
|
|
517
|
+
|
|
518
|
+
let count: u32 = 0;
|
|
519
|
+
let temp = value;
|
|
520
|
+
while (temp > 0) {
|
|
521
|
+
temp >>>= 1; // logical shift right
|
|
522
|
+
count++;
|
|
523
|
+
}
|
|
524
|
+
return count;
|
|
525
|
+
}
|
|
526
|
+
|
|
394
527
|
private static shlSegment(
|
|
395
528
|
segments: u64[],
|
|
396
529
|
segmentShift: i32,
|
|
@@ -411,12 +544,4 @@ export class SafeMath {
|
|
|
411
544
|
|
|
412
545
|
return result;
|
|
413
546
|
}
|
|
414
|
-
|
|
415
|
-
public static pow10(exponent: u8): u256 {
|
|
416
|
-
let result: u256 = u256.One;
|
|
417
|
-
for (let i: u8 = 0; i < exponent; i++) {
|
|
418
|
-
result = SafeMath.mul(result, u256.fromU32(10));
|
|
419
|
-
}
|
|
420
|
-
return result;
|
|
421
|
-
}
|
|
422
547
|
}
|