@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btc-vision/btc-runtime",
3
- "version": "1.3.19",
3
+ "version": "1.3.20",
4
4
  "description": "Bitcoin Smart Contract Runtime",
5
5
  "main": "btc/index.ts",
6
6
  "scripts": {
@@ -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
  }