toilscript 0.1.2 → 0.1.5

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.
@@ -0,0 +1,1007 @@
1
+ import { i128 } from './i128';
2
+ import { u128 } from './u128';
3
+ import { u256toDecimalString } from "../utils";
4
+ import {
5
+ __mul256, __u256carry, __u256carrySub, add64Local, sub64
6
+ } from '../globals';
7
+
8
+ @lazy const HEX_CHARS = '0123456789abcdef';
9
+
10
+ /**
11
+ * Represents a 256-bit unsigned integer.
12
+ * Optimized for gas efficiency with unrolled loops and direct memory access.
13
+ */
14
+ export class u256 {
15
+ /**
16
+ * Constructs a new `u256` with the specified 64-bit limbs.
17
+ * @constructor
18
+ * @param {u64} [lo1=0] - The lowest 64 bits.
19
+ * @param {u64} [lo2=0] - The 64 bits above `lo1`.
20
+ * @param {u64} [hi1=0] - The 64 bits above `lo2`.
21
+ * @param {u64} [hi2=0] - The highest 64 bits.
22
+ */
23
+ constructor(
24
+ public lo1: u64 = 0,
25
+ public lo2: u64 = 0,
26
+ public hi1: u64 = 0,
27
+ public hi2: u64 = 0,
28
+ ) {}
29
+
30
+ @inline static get Zero(): u256 { return new u256(0, 0, 0, 0); }
31
+ @inline static get One(): u256 { return new u256(1, 0, 0, 0); }
32
+ @inline static get Min(): u256 { return new u256(0, 0, 0, 0); }
33
+ @inline static get Max(): u256 { return new u256(-1, -1, -1, -1); }
34
+
35
+ /**
36
+ * A constant representing the maximum value for 256-bit unsigned integer.
37
+ * All bits set to 1.
38
+ * @returns {u256}
39
+ */
40
+ /**
41
+ * Creates a new `u256` from an existing `u256`.
42
+ * @param {u256} value - The source `u256` value.
43
+ * @returns {u256} - A new copy of the `value`.
44
+ */
45
+ @inline
46
+ static fromU256(value: u256): u256 {
47
+ return new u256(value.lo1, value.lo2, value.hi1, value.hi2);
48
+ }
49
+
50
+ /**
51
+ * Creates a new `u256` from a 128-bit unsigned integer.
52
+ * @param {u128} value - The 128-bit unsigned integer.
53
+ * @returns {u256} - The resulting 256-bit unsigned integer.
54
+ */
55
+ @inline
56
+ static fromU128(value: u128): u256 {
57
+ return new u256(value.lo, value.hi);
58
+ }
59
+
60
+ /**
61
+ * Creates a new `u256` from a 64-bit unsigned integer.
62
+ * @param {u64} value - The 64-bit unsigned integer.
63
+ * @returns {u256} - The resulting 256-bit unsigned integer.
64
+ */
65
+ @inline
66
+ static fromU64(value: u64): u256 {
67
+ if (value == 0) return u256.Zero;
68
+ if (value == 1) return u256.One;
69
+ return new u256(value);
70
+ }
71
+
72
+ /**
73
+ * Creates a new `u256` from a 64-bit signed integer (sign-extends).
74
+ * @param {i64} value - The 64-bit signed integer.
75
+ * @returns {u256} - The resulting 256-bit unsigned integer.
76
+ */
77
+ @inline
78
+ static fromI64(value: i64): u256 {
79
+ if (value == 0) return u256.Zero;
80
+ if (value == 1) return u256.One;
81
+ if (value == -1) return u256.Max;
82
+ let mask = value >> 63;
83
+ return new u256(<u64>value, mask, mask, mask);
84
+ }
85
+
86
+ /**
87
+ * Creates a new `u256` from a 32-bit unsigned integer.
88
+ * @param {u32} value - The 32-bit unsigned integer.
89
+ * @returns {u256} - The resulting 256-bit unsigned integer.
90
+ */
91
+ @inline
92
+ static fromU32(value: u32): u256 {
93
+ if (value == 0) return u256.Zero;
94
+ if (value == 1) return u256.One;
95
+ return new u256(value);
96
+ }
97
+
98
+ /**
99
+ * Creates a new `u256` from a 32-bit signed integer (sign-extends).
100
+ * @param {i32} value - The 32-bit signed integer.
101
+ * @returns {u256} - The resulting 256-bit unsigned integer.
102
+ */
103
+ @inline
104
+ static fromI32(value: i32): u256 {
105
+ if (value == 0) return u256.Zero;
106
+ if (value == 1) return u256.One;
107
+ if (value == -1) return u256.Max;
108
+ let mask: u64 = value >> 63;
109
+ return new u256(value, mask, mask, mask);
110
+ }
111
+
112
+ /**
113
+ * Creates a new `u256` from 8 separate 32-bit segments (lower to higher).
114
+ * @param {u32} l0 - Lower 32 bits of the first 64-bit segment.
115
+ * @param {u32} l1 - Higher 32 bits of the first 64-bit segment.
116
+ * @param {u32} l2 - Lower 32 bits of the second 64-bit segment.
117
+ * @param {u32} l3 - Higher 32 bits of the second 64-bit segment.
118
+ * @param {u32} h0 - Lower 32 bits of the third 64-bit segment.
119
+ * @param {u32} h1 - Higher 32 bits of the third 64-bit segment.
120
+ * @param {u32} h2 - Lower 32 bits of the fourth 64-bit segment.
121
+ * @param {u32} h3 - Higher 32 bits of the fourth 64-bit segment.
122
+ * @returns {u256} - The resulting 256-bit unsigned integer.
123
+ */
124
+ @inline
125
+ static fromBits(
126
+ l0: u32, l1: u32, l2: u32, l3: u32,
127
+ h0: u32, h1: u32, h2: u32, h3: u32,
128
+ ): u256 {
129
+ return new u256(
130
+ <u64>l0 | ((<u64>l1) << 32),
131
+ <u64>l2 | ((<u64>l3) << 32),
132
+ <u64>h0 | ((<u64>h1) << 32),
133
+ <u64>h2 | ((<u64>h3) << 32),
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Creates a new `u256` from an array of bytes or `Uint8Array`.
139
+ * @param {T} array - The source array of bytes (u8[] or Uint8Array).
140
+ * @param {boolean} [bigEndian=false] - Whether the bytes are in big-endian format.
141
+ * @throws {TypeError} If the generic type `T` is not supported.
142
+ * @returns {u256} - The resulting `u256`.
143
+ */
144
+ @inline
145
+ static fromBytes<T>(array: T, bigEndian: bool = false): u256 {
146
+ // @ts-ignore
147
+ if (array instanceof u8[]) {
148
+ return bigEndian
149
+ // @ts-ignore
150
+ ? u256.fromBytesBE(<u8[]>array)
151
+ // @ts-ignore
152
+ : u256.fromBytesLE(<u8[]>array);
153
+ } else if (array instanceof Uint8Array) {
154
+ return bigEndian
155
+ ? u256.fromUint8ArrayBE(<Uint8Array>array)
156
+ : u256.fromUint8ArrayLE(<Uint8Array>array);
157
+ } else {
158
+ throw new TypeError("Unsupported generic type");
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Creates a new `u256` from a little-endian array of bytes.
164
+ * @param {u8[]} array - A 32-byte array (little-endian).
165
+ * @returns {u256} - The resulting `u256`.
166
+ */
167
+ @inline
168
+ static fromBytesLE(array: u8[]): u256 {
169
+ if (array.length !== 32) throw new Error("Invalid length");
170
+ let buffer = array.dataStart;
171
+ return new u256(
172
+ load<u64>(buffer, 0),
173
+ load<u64>(buffer, 8),
174
+ load<u64>(buffer, 16),
175
+ load<u64>(buffer, 24),
176
+ );
177
+ }
178
+
179
+ /**
180
+ * Creates a new `u256` from a big-endian array of bytes.
181
+ * @param {u8[]} array - A 32-byte array (big-endian).
182
+ * @returns {u256} - The resulting `u256`.
183
+ */
184
+ @inline
185
+ static fromBytesBE(array: u8[]): u256 {
186
+ if (array.length !== 32) throw new Error("Invalid length");
187
+ let buffer = array.dataStart;
188
+ return new u256(
189
+ bswap<u64>(load<u64>(buffer, 24)),
190
+ bswap<u64>(load<u64>(buffer, 16)),
191
+ bswap<u64>(load<u64>(buffer, 8)),
192
+ bswap<u64>(load<u64>(buffer, 0))
193
+ );
194
+ }
195
+
196
+ /**
197
+ * Creates a new `u256` from a little-endian `Uint8Array`.
198
+ * @param {Uint8Array} array - A 32-byte `Uint8Array` (little-endian).
199
+ * @returns {u256} - The resulting `u256`.
200
+ */
201
+ @inline
202
+ static fromUint8ArrayLE(array: Uint8Array): u256 {
203
+ if (array.length !== 32) throw new Error("Invalid length");
204
+ let buffer = array.dataStart;
205
+ return new u256(
206
+ load<u64>(buffer, 0),
207
+ load<u64>(buffer, 8),
208
+ load<u64>(buffer, 16),
209
+ load<u64>(buffer, 24)
210
+ );
211
+ }
212
+
213
+ /**
214
+ * Creates a new `u256` from a big-endian `Uint8Array`.
215
+ * @param {Uint8Array} array - A 32-byte `Uint8Array` (big-endian).
216
+ * @returns {u256} - The resulting `u256`.
217
+ */
218
+ @inline
219
+ static fromUint8ArrayBE(array: Uint8Array): u256 {
220
+ if (array.length !== 32) throw new Error("Invalid length");
221
+ let buffer = array.dataStart;
222
+ return new u256(
223
+ bswap<u64>(load<u64>(buffer, 24)),
224
+ bswap<u64>(load<u64>(buffer, 16)),
225
+ bswap<u64>(load<u64>(buffer, 8)),
226
+ bswap<u64>(load<u64>(buffer, 0))
227
+ );
228
+ }
229
+
230
+ /**
231
+ * Creates a new `u256` from a 64-bit floating-point number.
232
+ * NOTE: This is only correct up to about 2^53.
233
+ * @param {f64} value - The 64-bit float value.
234
+ * @returns {u256} - The resulting `u256`.
235
+ */
236
+ @inline
237
+ static fromF64(value: f64): u256 {
238
+ let mask = u64(reinterpret<i64>(value) >> 63);
239
+ return new u256(<u64>value, mask, mask, mask);
240
+ }
241
+
242
+ /**
243
+ * Creates a new `u256` from a 32-bit floating-point number.
244
+ * NOTE: This is only correct up to about 2^23.
245
+ * @param {f32} value - The 32-bit float value.
246
+ * @returns {u256} - The resulting `u256`.
247
+ */
248
+ @inline
249
+ static fromF32(value: f32): u256 {
250
+ let mask = u64(reinterpret<i32>(value) >> 31);
251
+ return new u256(<u64>value, mask, mask, mask);
252
+ }
253
+
254
+ /**
255
+ * Creates a new `u256` from a generic value `T`.
256
+ * Supported types: bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, u128, u256, u8[], Uint8Array.
257
+ * @param {T} value - The source value.
258
+ * @throws {TypeError} If the type `T` is not supported.
259
+ * @returns {u256} - The resulting `u256`.
260
+ */
261
+ @inline
262
+ static from<T>(value: T): u256 {
263
+ if (value instanceof bool) return u256.fromU64(<u64>value);
264
+ else if (value instanceof i8) return u256.fromI64(<i64>value);
265
+ else if (value instanceof u8) return u256.fromU64(<u64>value);
266
+ else if (value instanceof i16) return u256.fromI64(<i64>value);
267
+ else if (value instanceof u16) return u256.fromU64(<u64>value);
268
+ else if (value instanceof i32) return u256.fromI64(<i64>value);
269
+ else if (value instanceof u32) return u256.fromU64(<u64>value);
270
+ else if (value instanceof i64) return u256.fromI64(<i64>value);
271
+ else if (value instanceof u64) return u256.fromU64(<u64>value);
272
+ else if (value instanceof f32) return u256.fromF64(<f64>value);
273
+ else if (value instanceof f64) return u256.fromF64(<f64>value);
274
+ else if (value instanceof u128) return u256.fromU128(<u128>value);
275
+ else if (value instanceof u256) return u256.fromU256(<u256>value);
276
+ else if (value instanceof u8[]) return u256.fromBytes(<u8[]>value);
277
+ else if (value instanceof Uint8Array) return u256.fromBytes(<Uint8Array>value);
278
+ else throw new TypeError("Unsupported generic type");
279
+ }
280
+
281
+ /**
282
+ * Parses a string in decimal or hexadecimal format into a `u256`.
283
+ * @param {string} str - The input string.
284
+ * @param {i32} [radix=10] - The base (10 for decimal, 16 for hexadecimal).
285
+ * @returns {u256} - The resulting `u256`.
286
+ */
287
+ @inline
288
+ static fromString(str: string, radix: i32 = 10): u256 {
289
+ assert(radix == 10 || radix == 16, "radix must be 10 or 16");
290
+ let len = str.length;
291
+ if (len == 0) return u256.Zero;
292
+ let result = u256.Zero; // Use cached Zero
293
+ if (radix == 10) {
294
+ for (let i = 0; i < len; i++) {
295
+ let c = str.charCodeAt(i);
296
+ assert(c >= 0x30 && c <= 0x39, "Invalid decimal digit");
297
+ let digit: u64 = c - 0x30;
298
+ result = result * u256.from(10) + u256.from(digit);
299
+ }
300
+ } else {
301
+ for (let i = 0; i < len; i++) {
302
+ let c = str.charCodeAt(i);
303
+ let digit: u64 = 0;
304
+ if (c >= 0x30 && c <= 0x39) digit = c - 0x30;
305
+ else if (c >= 0x41 && c <= 0x46) digit = c - 0x41 + 10;
306
+ else if (c >= 0x61 && c <= 0x66) digit = c - 0x61 + 10;
307
+ else assert(false, "Invalid hexadecimal digit");
308
+ result = result * u256.from(16) + u256.from(digit);
309
+ }
310
+ }
311
+ return result;
312
+ }
313
+
314
+ /**
315
+ * Checks if a given `u256` value is zero using the `!` operator.
316
+ * @param {u256} value - The `u256` to check.
317
+ * @returns {boolean} - True if zero, false otherwise.
318
+ */
319
+ @inline @operator.prefix('!')
320
+ static isEmpty(value: u256): bool {
321
+ return value.isZero();
322
+ }
323
+
324
+ /**
325
+ * Adds two `u256` values and returns a new `u256` with the sum.
326
+ * @param {u256} a - The first `u256` addend.
327
+ * @param {u256} b - The second `u256` addend.
328
+ * @returns {u256} - The sum of `a` and `b`.
329
+ */
330
+ @operator('+')
331
+ static add(a: u256, b: u256): u256 {
332
+ let lo1 = add64Local(a.lo1, b.lo1, 0);
333
+ let c1 = __u256carry;
334
+ let lo2 = add64Local(a.lo2, b.lo2, c1);
335
+ let c2 = __u256carry;
336
+ let hi1 = add64Local(a.hi1, b.hi1, c2);
337
+ let c3 = __u256carry;
338
+ let hi2 = add64Local(a.hi2, b.hi2, c3);
339
+ return new u256(lo1, lo2, hi1, hi2);
340
+ }
341
+
342
+ /**
343
+ * Divides `a` by `b` (integer division).
344
+ * @param {u256} a - The dividend.
345
+ * @param {u256} b - The divisor.
346
+ * @throws {Error} If `b` is zero.
347
+ * @returns {u256} - The quotient of the division.
348
+ * Optimized Division.
349
+ * Performs division in-place on clones to minimize object allocation.
350
+ */
351
+ @operator('/')
352
+ public static div(a: u256, b: u256): u256 {
353
+ if (b.isZero()) throw new Error('Division by zero');
354
+ if (a.isZero() || u256.lt(a, b)) return u256.Zero; // Return cached Zero
355
+ if (u256.eq(a, b)) return u256.One; // Return cached One
356
+
357
+ // Clone to mutate in-place
358
+ let n = a.clone();
359
+ let d = b.clone();
360
+ let result = u256.Zero.clone(); // Start with fresh Zero
361
+
362
+ const shift = u256.clz(d) - u256.clz(n);
363
+
364
+ // Shift d left by 'shift'
365
+ // Since d is a clone, we can mutate/reassign it
366
+ d = u256.shl(d, shift);
367
+
368
+ // Unrolled restore division
369
+ for (let i = shift; i >= 0; i--) {
370
+ if (u256.ge(n, d)) {
371
+ n.subAssign(d); // In-place subtract
372
+ result.orAssignBit(i); // In-place bit set
373
+ }
374
+ d.rshiftOne(); // In-place right shift by 1
375
+ }
376
+ return result;
377
+ }
378
+
379
+ /**
380
+ * Left-shifts a `u256` by the specified number of bits.
381
+ * @param {u256} value - The `u256` to shift.
382
+ * @param {i32} shift - The number of bits to shift (modulo 256).
383
+ * @returns {u256} - The shifted `u256`.
384
+ * Optimized Left Shift (Massacred allocation overhead).
385
+ * Unrolls the logic into local variables to avoid Array<u64> allocation.
386
+ */
387
+ @operator('<<')
388
+ public static shl(value: u256, shift: i32): u256 {
389
+ if (shift <= 0) return shift == 0 ? value.clone() : u256.Zero; // Return cached
390
+ if (shift >= 256) return u256.Zero; // Return cached
391
+
392
+ shift &= 255;
393
+
394
+ const bits = 64;
395
+ const segShift = (shift / bits) | 0;
396
+ const bitShift = shift % bits;
397
+ const invShift = bits - bitShift;
398
+
399
+ let r0: u64 = 0, r1: u64 = 0, r2: u64 = 0, r3: u64 = 0;
400
+ const i0 = value.lo1, i1 = value.lo2, i2 = value.hi1, i3 = value.hi2;
401
+
402
+ if (segShift == 0) {
403
+ r0 = i0 << bitShift;
404
+ r1 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
405
+ r2 = (i2 << bitShift) | (bitShift == 0 ? 0 : i1 >>> invShift);
406
+ r3 = (i3 << bitShift) | (bitShift == 0 ? 0 : i2 >>> invShift);
407
+ } else if (segShift == 1) {
408
+ r1 = i0 << bitShift;
409
+ r2 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
410
+ r3 = (i2 << bitShift) | (bitShift == 0 ? 0 : i1 >>> invShift);
411
+ } else if (segShift == 2) {
412
+ r2 = i0 << bitShift;
413
+ r3 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
414
+ } else if (segShift == 3) {
415
+ r3 = i0 << bitShift;
416
+ }
417
+
418
+ return new u256(r0, r1, r2, r3);
419
+ }
420
+
421
+ /**
422
+ * Subtracts `b` from `a` and returns a new `u256`.
423
+ * @param {u256} a - The minuend.
424
+ * @param {u256} b - The subtrahend.
425
+ * @returns {u256} - The difference `a - b`.
426
+ */
427
+ @operator('-')
428
+ static sub(a: u256, b: u256): u256 {
429
+ let lo1 = sub64(a.lo1, b.lo1, 0);
430
+ let b1 = __u256carrySub;
431
+ let lo2 = sub64(a.lo2, b.lo2, b1);
432
+ let b2 = __u256carrySub;
433
+ let hi1 = sub64(a.hi1, b.hi1, b2);
434
+ let b3 = __u256carrySub;
435
+ let hi2 = sub64(a.hi2, b.hi2, b3);
436
+ return new u256(lo1, lo2, hi1, hi2);
437
+ }
438
+
439
+ /**
440
+ * Bitwise OR between two `u256` values.
441
+ * @param {u256} a - The first operand.
442
+ * @param {u256} b - The second operand.
443
+ * @returns {u256} - The bitwise OR result.
444
+ */
445
+ @inline @operator('|')
446
+ static or(a: u256, b: u256): u256 {
447
+ return new u256(a.lo1 | b.lo1, a.lo2 | b.lo2, a.hi1 | b.hi1, a.hi2 | b.hi2);
448
+ }
449
+
450
+ /**
451
+ * Bitwise XOR between two `u256` values.
452
+ * @param {u256} a - The first operand.
453
+ * @param {u256} b - The second operand.
454
+ * @returns {u256} - The bitwise XOR result.
455
+ */
456
+ @inline @operator('^')
457
+ static xor(a: u256, b: u256): u256 {
458
+ return new u256(a.lo1 ^ b.lo1, a.lo2 ^ b.lo2, a.hi1 ^ b.hi1, a.hi2 ^ b.hi2);
459
+ }
460
+
461
+ /**
462
+ * Bitwise AND between two `u256` values.
463
+ * @param {u256} a - The first operand.
464
+ * @param {u256} b - The second operand.
465
+ * @returns {u256} - The bitwise AND result.
466
+ */
467
+ @inline @operator('&')
468
+ static and(a: u256, b: u256): u256 {
469
+ return new u256(a.lo1 & b.lo1, a.lo2 & b.lo2, a.hi1 & b.hi1, a.hi2 & b.hi2);
470
+ }
471
+
472
+ /**
473
+ * Right-shifts a `u256` by the specified number of bits (logical shift).
474
+ * @param {u256} value - The `u256` to shift.
475
+ * @param {i32} shift - The number of bits to shift (modulo 256).
476
+ * @returns {u256} - The shifted `u256`.
477
+ */
478
+ @operator('>>')
479
+ static shr(value: u256, shift: i32): u256 {
480
+ // If shift <= 0 => shift=0 means "no shift," shift<0 is arguably invalid.
481
+ // We just return a if shift=0, else zero if negative. Adjust to your preference.
482
+ if (shift <= 0) {
483
+ return shift == 0 ? value.clone() : u256.Zero;
484
+ }
485
+
486
+ // If shift >= 256 => the result is zero for a 256-bit integer
487
+ if (shift >= 256) {
488
+ return u256.Zero;
489
+ }
490
+
491
+ // Now shift is in [1..255]
492
+ // Some code likes to do shift &= 255; but after the above check, it’s no longer necessary.
493
+ // We'll keep it for consistency:
494
+ shift &= 255;
495
+
496
+ // If after masking shift is 0, that means the original shift was multiple of 256, but we handled it above
497
+ if (shift == 0) return value.clone();
498
+
499
+ const w = shift >>> 6; // how many full 64-bit words to drop
500
+ const b = shift & 63; // how many bits to shift within a word
501
+
502
+ let lo1 = value.lo1;
503
+ let lo2 = value.lo2;
504
+ let hi1 = value.hi1;
505
+ let hi2 = value.hi2;
506
+
507
+ // Shift words down by w words
508
+ if (w >= 4) return u256.Zero; // Return cached
509
+ else if (w == 3) { lo1 = hi2; lo2 = 0; hi1 = 0; hi2 = 0; }
510
+ else if (w == 2) { lo1 = hi1; lo2 = hi2; hi1 = 0; hi2 = 0; }
511
+ else if (w == 1) { lo1 = lo2; lo2 = hi1; hi1 = hi2; hi2 = 0; }
512
+
513
+ // Now apply the bit shift b
514
+ if (b > 0) {
515
+ const invB = 64 - b;
516
+ lo1 = (lo1 >>> b) | (lo2 << invB);
517
+ lo2 = (lo2 >>> b) | (hi1 << invB);
518
+ hi1 = (hi1 >>> b) | (hi2 << invB);
519
+ hi2 = hi2 >>> b;
520
+ }
521
+
522
+ return new u256(lo1, lo2, hi1, hi2);
523
+ }
524
+
525
+ /**
526
+ * Unsigned right shift operator (same as `shr` for `u256`).
527
+ * @param {u256} value - The `u256` to shift.
528
+ * @param {i32} shift - The number of bits to shift (modulo 256).
529
+ * @returns {u256} - The shifted `u256`.
530
+ */
531
+ @inline @operator('>>>')
532
+ static shr_u(value: u256, shift: i32): u256 {
533
+ return u256.shr(value, shift);
534
+ }
535
+
536
+ /**
537
+ * Checks if two `u256` values are equal.
538
+ * @param {u256} a - The first operand.
539
+ * @param {u256} b - The second operand.
540
+ * @returns {boolean} - True if the two values are equal, otherwise false.
541
+ */
542
+ @inline @operator('==')
543
+ static eq(a: u256, b: u256): bool {
544
+ return a.lo1 == b.lo1 && a.lo2 == b.lo2 && a.hi1 == b.hi1 && a.hi2 == b.hi2;
545
+ }
546
+
547
+ /**
548
+ * Checks if two `u256` values are not equal.
549
+ * @param {u256} a - The first operand.
550
+ * @param {u256} b - The second operand.
551
+ * @returns {boolean} - True if the two values differ, otherwise false.
552
+ */
553
+ @inline @operator('!=')
554
+ static ne(a: u256, b: u256): bool {
555
+ return !u256.eq(a, b);
556
+ }
557
+
558
+ /**
559
+ * Checks if `a < b`.
560
+ * @param {u256} a - The first operand.
561
+ * @param {u256} b - The second operand.
562
+ * @returns {boolean} - True if `a` is less than `b`, otherwise false.
563
+ */
564
+ @operator('<')
565
+ static lt(a: u256, b: u256): bool {
566
+ if (a.hi2 != b.hi2) return a.hi2 < b.hi2;
567
+ if (a.hi1 != b.hi1) return a.hi1 < b.hi1;
568
+ if (a.lo2 != b.lo2) return a.lo2 < b.lo2;
569
+ return a.lo1 < b.lo1;
570
+ }
571
+
572
+ @inline @operator('>')
573
+ static gt(a: u256, b: u256): bool { return b < a; }
574
+ @inline @operator('<=')
575
+ static le(a: u256, b: u256): bool { return !u256.gt(a, b); }
576
+ @inline @operator('>=')
577
+ static ge(a: u256, b: u256): bool { return !u256.lt(a, b); }
578
+
579
+ @inline @operator('*')
580
+ static mul(a: u256, b: u256): u256 {
581
+ return __mul256(a.lo1, a.lo2, a.hi1, a.hi2, b.lo1, b.lo2, b.hi1, b.hi2);
582
+ }
583
+
584
+ /**
585
+ * Counts the number of set bits (1s) in the `u256`.
586
+ * @param {u256} value - The `u256` to count bits for.
587
+ * @returns {i32} - The number of bits set to 1.
588
+ */
589
+ @inline
590
+ static popcnt(value: u256): i32 {
591
+ return <i32>(popcnt(value.lo1) + popcnt(value.lo2) + popcnt(value.hi1) + popcnt(value.hi2));
592
+ }
593
+
594
+ /**
595
+ * Counts leading zeros in the `u256`.
596
+ * @param {u256} value - The `u256` to evaluate.
597
+ * @returns {i32} - The number of leading zero bits.
598
+ */
599
+ @inline
600
+ static clz(value: u256): i32 {
601
+ if (value.hi2) return <i32>clz(value.hi2);
602
+ if (value.hi1) return <i32>(clz(value.hi1) + 64);
603
+ if (value.lo2) return <i32>(clz(value.lo2) + 128);
604
+ if (value.lo1) return <i32>(clz(value.lo1) + 192);
605
+ return 256;
606
+ }
607
+
608
+ /**
609
+ * Counts trailing zeros in the `u256`.
610
+ * @param {u256} value - The `u256` to evaluate.
611
+ * @returns {i32} - The number of trailing zero bits.
612
+ */
613
+ @inline
614
+ static ctz(value: u256): i32 {
615
+ if (value.lo1) return <i32>ctz(value.lo1);
616
+ if (value.lo2) return <i32>(ctz(value.lo2) + 64);
617
+ if (value.hi1) return <i32>(ctz(value.hi1) + 128);
618
+ if (value.hi2) return <i32>(ctz(value.hi2) + 192);
619
+ return 256;
620
+ }
621
+
622
+ /**
623
+ * Sets the value of this `u256` to another `u256`.
624
+ * @param {u256} value - The source `u256`.
625
+ * @returns {this} - The current instance.
626
+ */
627
+ @inline
628
+ set(value: u256): this {
629
+ this.lo1 = value.lo1; this.lo2 = value.lo2; this.hi1 = value.hi1; this.hi2 = value.hi2;
630
+ return this;
631
+ }
632
+
633
+ /**
634
+ * Sets the lower 128 bits of this `u256` from a `u128`, resetting the higher 128 bits to zero.
635
+ * @param {u128} value - The source 128-bit unsigned integer.
636
+ * @returns {this} - The current instance.
637
+ */
638
+ @inline
639
+ setU128(value: u128): this {
640
+ this.lo1 = value.lo; this.lo2 = value.hi; this.hi1 = 0; this.hi2 = 0;
641
+ return this;
642
+ }
643
+
644
+ /**
645
+ * Sets this `u256` to the sign-extended value of a 64-bit signed integer.
646
+ * @param {i64} value - The 64-bit signed integer.
647
+ * @returns {this} - The current instance.
648
+ */
649
+ @inline
650
+ setI64(value: i64): this {
651
+ let mask: u64 = value >> 63;
652
+ this.lo1 = <u64>value; this.lo2 = mask; this.hi1 = mask; this.hi2 = mask;
653
+ return this;
654
+ }
655
+
656
+ /**
657
+ * Sets this `u256` to the specified 64-bit unsigned integer, clearing higher bits.
658
+ * @param {u64} value - The 64-bit unsigned integer.
659
+ * @returns {this} - The current instance.
660
+ */
661
+ @inline
662
+ setU64(value: u64): this {
663
+ this.lo1 = value; this.lo2 = 0; this.hi1 = 0; this.hi2 = 0;
664
+ return this;
665
+ }
666
+
667
+ /**
668
+ * Sets this `u256` to the sign-extended value of a 32-bit signed integer.
669
+ * @param {i32} value - The 32-bit signed integer.
670
+ * @returns {this} - The current instance.
671
+ */
672
+ @inline
673
+ setI32(value: i32): this {
674
+ let mask: u64 = value >> 63;
675
+ this.lo1 = value; this.lo2 = mask; this.hi1 = mask; this.hi2 = mask;
676
+ return this;
677
+ }
678
+
679
+ /**
680
+ * Sets this `u256` to the specified 32-bit unsigned integer, clearing higher bits.
681
+ * @param {u32} value - The 32-bit unsigned integer.
682
+ * @returns {this} - The current instance.
683
+ */
684
+ @inline
685
+ setU32(value: u32): this {
686
+ this.lo1 = value; this.lo2 = 0; this.hi1 = 0; this.hi2 = 0;
687
+ return this;
688
+ }
689
+
690
+ /**
691
+ * Checks if this `u256` is equal to zero.
692
+ * @returns {boolean} - True if zero, false otherwise.
693
+ */
694
+ @inline
695
+ isZero(): bool {
696
+ return !(this.lo1 | this.lo2 | this.hi1 | this.hi2);
697
+ }
698
+
699
+ /**
700
+ * Performs a bitwise NOT operation (`~`) on the current `u256`.
701
+ * @returns {u256} - A new `u256` with inverted bits.
702
+ */
703
+ @inline @operator.prefix('~')
704
+ not(): u256 {
705
+ return new u256(~this.lo1, ~this.lo2, ~this.hi1, ~this.hi2);
706
+ }
707
+
708
+ /**
709
+ * A unary plus operator, returning the current `u256` without changes.
710
+ * @returns {u256} - The current `u256`.
711
+ */
712
+ @inline @operator.prefix('+')
713
+ pos(): u256 { return this; }
714
+
715
+ /**
716
+ * A unary negation operator (`-x`), computed as `~x + 1`.
717
+ * @returns {u256} - A new `u256` representing the negated value (mod 2^256).
718
+ */
719
+ @operator.prefix('-')
720
+ neg(): u256 {
721
+ let lo1 = ~this.lo1, lo2 = ~this.lo2, hi1 = ~this.hi1, hi2 = ~this.hi2;
722
+ let sum = lo1 + 1;
723
+ let carry = (sum < lo1) ? 1 : 0;
724
+ lo1 = sum;
725
+ sum = lo2 + carry;
726
+ carry = (sum < lo2) ? 1 : 0;
727
+ lo2 = sum;
728
+ sum = hi1 + carry;
729
+ carry = (sum < hi1) ? 1 : 0;
730
+ hi1 = sum;
731
+ hi2 = hi2 + carry;
732
+ return new u256(lo1, lo2, hi1, hi2);
733
+ }
734
+
735
+ @operator.prefix("++")
736
+ public preInc(): this {
737
+ let sum = this.lo1 + 1;
738
+ let carry = sum < this.lo1 ? 1 : 0;
739
+ this.lo1 = sum;
740
+ sum = this.lo2 + carry;
741
+ carry = sum < this.lo2 ? 1 : 0;
742
+ this.lo2 = sum;
743
+ sum = this.hi1 + carry;
744
+ carry = sum < this.hi1 ? 1 : 0;
745
+ this.hi1 = sum;
746
+ this.hi2 += carry;
747
+ return this;
748
+ }
749
+
750
+ @operator.prefix("--")
751
+ public preDec(): this {
752
+ let diff = this.lo1 - 1;
753
+ let borrow = (diff > this.lo1) ? 1 : 0;
754
+ this.lo1 = diff;
755
+ diff = this.lo2 - borrow;
756
+ borrow = (diff > this.lo2) ? 1 : 0;
757
+ this.lo2 = diff;
758
+ diff = this.hi1 - borrow;
759
+ borrow = (diff > this.hi1) ? 1 : 0;
760
+ this.hi1 = diff;
761
+ this.hi2 -= borrow;
762
+ return this;
763
+ }
764
+
765
+ @inline @operator.postfix('++')
766
+ postInc(): u256 { return this.clone().preInc(); }
767
+
768
+ @inline @operator.postfix('--')
769
+ postDec(): u256 { return this.clone().preDec(); }
770
+
771
+ /**
772
+ * Converts this `u256` to a generic type `T`.
773
+ * Supported types: bool, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, u256, u8[], Uint8Array, StaticArray<u8>, string.
774
+ * @returns {T} - The converted value.
775
+ */
776
+ @inline
777
+ as<T>(): T {
778
+ if (isReference<T>()) {
779
+ let typeName = nameof<T>();
780
+ if (typeName.indexOf("Array<u8>") >= 0) return changetype<T>(this.toBytes());
781
+ else if (typeName.indexOf("Uint8Array") >= 0) return changetype<T>(this.toUint8Array());
782
+ else if (typeName.indexOf("StaticArray<u8>") >= 0) return changetype<T>(this.toStaticBytes());
783
+ else if (typeName.indexOf("String") >= 0) return changetype<T>(this.toString());
784
+ else if (typeName.indexOf("u128") >= 0) return changetype<T>(this.toU128());
785
+ else if (typeName.indexOf("i128") >= 0) return changetype<T>(this.toI128());
786
+ else if (typeName.indexOf("u256") >= 0) return changetype<T>(this.toU256());
787
+ else throw new TypeError(`Unsupported generic type ${typeName}`);
788
+ } else {
789
+ if (isInteger<T>()) {
790
+ if (sizeof<T>() == 1) return <T><u64>this.toU64();
791
+ else if (sizeof<T>() == 2) return <T><u64>this.toU64();
792
+ else if (sizeof<T>() == 4) return <T><u64>this.toU64();
793
+ else if (sizeof<T>() == 8) return <T>this.toU64();
794
+ else throw new TypeError(`Unsupported generic type ${nameof<T>()}`);
795
+ } else if (isFloat<T>()) {
796
+ return <T><f64>this.toU64();
797
+ } else {
798
+ // bool
799
+ return <T>this.toBool();
800
+ }
801
+ }
802
+ }
803
+
804
+ /**
805
+ * Converts this `u256` to a signed 128-bit integer (i128).
806
+ * The highest bit of the 256-bit value is sign bit for i128.
807
+ * @returns {i128} - The resulting `i128`.
808
+ */
809
+ @inline
810
+ toI128(): i128 {
811
+ return new i128(this.lo1, (this.lo2 & 0x7FFFFFFFFFFFFFFF) | (this.hi2 & 0x8000000000000000));
812
+ }
813
+
814
+ /**
815
+ * Converts this `u256` to an unsigned 128-bit integer (u128).
816
+ * Truncates higher bits.
817
+ * @returns {u128} - The resulting `u128`.
818
+ */
819
+ @inline
820
+ toU128(): u128 { return new u128(this.lo1, this.lo2); }
821
+
822
+ /**
823
+ * Returns this `u256` itself, effectively a no-op for `u256`.
824
+ * @returns {u256} - The current `u256`.
825
+ */
826
+ @inline
827
+ toU256(): this { return this; }
828
+
829
+ /**
830
+ * Converts this `u256` to a signed 64-bit integer (i64).
831
+ * Truncates and treats the highest bit of the 256-bit as sign.
832
+ * @returns {i64} - The resulting 64-bit signed integer.
833
+ */
834
+ @inline
835
+ toI64(): i64 { return <i64>( (this.lo1 & 0x7FFFFFFFFFFFFFFF) | (this.hi2 & 0x8000000000000000) ); }
836
+
837
+ /**
838
+ * Converts this `u256` to an unsigned 64-bit integer (u64).
839
+ * Truncates higher bits.
840
+ * @returns {u64} - The resulting 64-bit unsigned integer.
841
+ */
842
+ @inline
843
+ toU64(): u64 { return this.lo1; }
844
+
845
+ /**
846
+ * Converts this `u256` to a signed 32-bit integer (i32).
847
+ * @returns {i32} - The resulting 32-bit signed integer.
848
+ */
849
+ @inline
850
+ toI32(): i32 { return <i32>this.toI64(); }
851
+
852
+ /**
853
+ * Converts this `u256` to an unsigned 32-bit integer (u32).
854
+ * Truncates higher bits.
855
+ * @returns {u32} - The resulting 32-bit unsigned integer.
856
+ */
857
+ @inline
858
+ toU32(): u32 { return <u32>this.lo1; }
859
+
860
+ /**
861
+ * Checks if the `u256` is non-zero, then returns `true`; otherwise `false`.
862
+ * @returns {boolean} - True if non-zero, otherwise false.
863
+ */
864
+ @inline
865
+ toBool(): bool { return <bool>(this.lo1 | this.lo2 | this.hi1 | this.hi2); }
866
+
867
+ /**
868
+ * Converts this `u256` to an array of 32 bytes (u8[]).
869
+ * @param {boolean} [bigEndian=false] - Output in big-endian if true, else little-endian.
870
+ * @returns {u8[]} - The resulting byte array.
871
+ */
872
+ @inline
873
+ toBytes(bigEndian: bool = false): u8[] {
874
+ let result = new Array<u8>(32);
875
+ this.toArrayBuffer(changetype<usize>(result.dataStart), bigEndian);
876
+ return result;
877
+ }
878
+
879
+ /**
880
+ * Converts this `u256` to a static array of 32 bytes (StaticArray<u8>).
881
+ * @param {boolean} [bigEndian=false] - Output in big-endian if true, else little-endian.
882
+ * @returns {StaticArray<u8>} - The resulting static byte array.
883
+ */
884
+ @inline
885
+ toStaticBytes(bigEndian: bool = false): StaticArray<u8> {
886
+ let result = new StaticArray<u8>(32);
887
+ this.toArrayBuffer(changetype<usize>(result), bigEndian);
888
+ return result;
889
+ }
890
+
891
+ /**
892
+ * Converts this `u256` to a `Uint8Array` of length 32.
893
+ * @param {boolean} [bigEndian=false] - Output in big-endian if true, else little-endian.
894
+ * @returns {Uint8Array} - The resulting `Uint8Array`.
895
+ */
896
+ @inline
897
+ toUint8Array(bigEndian: bool = false): Uint8Array {
898
+ let result = new Uint8Array(32);
899
+ this.toArrayBuffer(changetype<usize>(result.dataStart), bigEndian);
900
+ return result;
901
+ }
902
+
903
+ /**
904
+ * Creates and returns a clone (deep copy) of this `u256`.
905
+ * @returns {u256} - A new `u256` instance with the same value.
906
+ */
907
+ clone(): u256 { return new u256(this.lo1, this.lo2, this.hi1, this.hi2); }
908
+
909
+ /**
910
+ * Converts this `u256` to a string in either decimal or hexadecimal format.
911
+ * @param {i32} [radix=10] - The base (10 or 16).
912
+ * @throws {Error} If `radix` is not 10 or 16.
913
+ * @returns {string} - The string representation of the `u256`.
914
+ */
915
+ toString(radix: i32 = 10): string {
916
+ assert(radix == 10 || radix == 16, 'radix argument must be between 10 or 16');
917
+ if (this.isZero()) return '0';
918
+ if (radix == 16) {
919
+ let result = '';
920
+ let shift: i32 = 252 - (u256.clz(this) & ~3);
921
+ while (shift >= 0) {
922
+ // @ts-ignore
923
+ result += HEX_CHARS.charAt(<i32>((this >> shift).lo1 & 15));
924
+ shift -= 4;
925
+ }
926
+ return result;
927
+ }
928
+ return u256toDecimalString(this);
929
+ }
930
+
931
+ /**
932
+ * @private
933
+ * Stores this `u256` into a buffer in little-endian format.
934
+ * @param {usize} buffer - The buffer start pointer.
935
+ */
936
+ // --- INTERNAL HELPERS FOR DIV OPTIMIZATION ---
937
+ // These allow in-place mutation to avoid allocations inside the div loop.
938
+
939
+ /** In-place subtraction. Assumes this >= other. */
940
+ @inline
941
+ private subAssign(other: u256): void {
942
+ let lo1 = sub64(this.lo1, other.lo1, 0);
943
+ let b1 = __u256carrySub;
944
+ let lo2 = sub64(this.lo2, other.lo2, b1);
945
+ let b2 = __u256carrySub;
946
+ let hi1 = sub64(this.hi1, other.hi1, b2);
947
+ let b3 = __u256carrySub;
948
+ let hi2 = sub64(this.hi2, other.hi2, b3);
949
+ this.lo1 = lo1; this.lo2 = lo2; this.hi1 = hi1; this.hi2 = hi2;
950
+ }
951
+
952
+ /** In-place bit set: this |= (1 << bit) */
953
+ @inline
954
+ private orAssignBit(bit: i32): void {
955
+ const bits = 64;
956
+ const seg = (bit / bits) | 0;
957
+ const shift = bit % bits;
958
+ // FIX: Explicitly cast literal 1 to u64 to ensure proper 64-bit shifting
959
+ const mask: u64 = <u64>1 << shift;
960
+ if (seg == 0) this.lo1 |= mask;
961
+ else if (seg == 1) this.lo2 |= mask;
962
+ else if (seg == 2) this.hi1 |= mask;
963
+ else if (seg == 3) this.hi2 |= mask;
964
+ }
965
+
966
+ /** In-place right shift by 1. */
967
+ @inline
968
+ private rshiftOne(): void {
969
+ this.lo1 = (this.lo1 >>> 1) | (this.lo2 << 63);
970
+ this.lo2 = (this.lo2 >>> 1) | (this.hi1 << 63);
971
+ this.hi1 = (this.hi1 >>> 1) | (this.hi2 << 63);
972
+ this.hi2 = (this.hi2 >>> 1);
973
+ }
974
+
975
+ @inline
976
+ private toArrayBufferLE(buffer: usize): void {
977
+ store<u64>(buffer, this.lo1, 0);
978
+ store<u64>(buffer, this.lo2, 8);
979
+ store<u64>(buffer, this.hi1, 16);
980
+ store<u64>(buffer, this.hi2, 24);
981
+ }
982
+
983
+ /**
984
+ * @private
985
+ * Stores this `u256` into a buffer in big-endian format.
986
+ * @param {usize} buffer - The buffer start pointer.
987
+ */
988
+ @inline
989
+ private toArrayBufferBE(buffer: usize): void {
990
+ store<u64>(buffer, bswap(this.hi2), 0);
991
+ store<u64>(buffer, bswap(this.hi1), 8);
992
+ store<u64>(buffer, bswap(this.lo2), 16);
993
+ store<u64>(buffer, bswap(this.lo1), 24);
994
+ }
995
+
996
+ /**
997
+ * @private
998
+ * Stores this `u256` into a buffer in either little-endian or big-endian format.
999
+ * @param {usize} buffer - The buffer start pointer.
1000
+ * @param {boolean} [bigEndian=false] - Use big-endian if true, else little-endian.
1001
+ */
1002
+ @inline
1003
+ private toArrayBuffer(buffer: usize, bigEndian: bool = false): void {
1004
+ if (bigEndian) this.toArrayBufferBE(buffer);
1005
+ else this.toArrayBufferLE(buffer);
1006
+ }
1007
+ }