Transaction
3426AFE3D38091…F32DDB5B9306
Block 77,237 · index 0 · indexed
Summary
- Hash
- 3426AFE3D38091826F1046F1977C06D324765C332C622AFF5105F32DDB5B9306
- Block
- 77,237
- Size
- 76896 bytes
- Gas used
- 101,680,337 / 122,016,357
- Fee
- 122017ugnot
- Status
- success
Messages
Arguments · 23
- #1uint256
- #2README.md
- #3# uint256 256-bit unsigned integer arithmetic for GnoSwap. ## Overview Fixed-size 256-bit unsigned integer library optimized for AMM calculations with precise `MulDiv` operations. The unsuffixed `Add`, `Sub`, and `Mul` methods return the low 256 bits; the corresponding `AddOverflow`, `SubOverflow`, and `MulOverflow` variants also report an overflow/underflow flag. ## Features - Fixed 256-bit size (4 uint64 values) - Explicit overflow detection via `*Overflow` variants - Optimized `MulDiv` for precise calculations - Decimal string conversion - Range: 0 to 2^256-1 ## Usage ```go package main import u256 "gno.land/p/gnoswap/uint256/v1" func main() { a := u256.NewUint(1000) b := u256.MustFromDecimal("1000000000000000000") result, overflow := new(u256.Uint).AddOverflow(a, b) if overflow { panic("unsigned addition overflow") } println(result.ToString()) // 1000000000000001000 // MulDiv calculates floor(a*b/c). The denominator must be non-zero, // and the quotient must fit in 256 bits; otherwise it panics. c := u256.NewUint(3) println(u256.MulDiv(a, b, c).ToString()) // 333333333333333333333 } ``` ## Credits Ported from [holiman/uint256](https://github.com/holiman/uint256)
- #4arithmetic.gno
- #5// arithmetic provides arithmetic operations for Uint objects. // This includes basic binary operations such as addition, subtraction, multiplication, division, and modulo operations // as well as overflow checks, and negation. These functions are essential for numeric // calculations using 256-bit unsigned integers. package uint256 import ( "math/bits" ) // Add sets z to the sum x+y and returns z. // // Parameters: // - x: the first addend; its 256-bit value is added modulo 2^256 // - y: the second addend; its 256-bit value is added modulo 2^256 // // Returns: // - result: z containing x+y modulo 2^256; any carry beyond bit 255 is discarded func (z *Uint) Add(x, y *Uint) *Uint { var carry uint64 z[0], carry = bits.Add64(x[0], y[0], 0) z[1], carry = bits.Add64(x[1], y[1], carry) z[2], carry = bits.Add64(x[2], y[2], carry) z[3], _ = bits.Add64(x[3], y[3], carry) return z } // AddOverflow sets z to the sum x+y and returns z and true if overflow occurred. // // Parameters: // - x: the first addend // - y: the second addend // // Returns: // - result: z containing x+y modulo 2^256 // - overflow: true when x+y exceeds the 256-bit range func (z *Uint) AddOverflow(x, y *Uint) (*Uint, bool) { var carry uint64 z[0], carry = bits.Add64(x[0], y[0], 0) z[1], carry = bits.Add64(x[1], y[1], carry) z[2], carry = bits.Add64(x[2], y[2], carry) z[3], carry = bits.Add64(x[3], y[3], carry) return z, carry != 0 } // Sub sets z to the difference x-y and returns z. // // Parameters: // - x: the minuend // - y: the subtrahend // // Returns: // - result: z containing x-y modulo 2^256; underflow wraps in the unsigned representation func (z *Uint) Sub(x, y *Uint) *Uint { var carry uint64 z[0], carry = bits.Sub64(x[0], y[0], 0) z[1], carry = bits.Sub64(x[1], y[1], carry) z[2], carry = bits.Sub64(x[2], y[2], carry) z[3], _ = bits.Sub64(x[3], y[3], carry) return z } // SubOverflow sets z to the difference x-y and returns z and true if underflow occurred. // // Parameters: // - x: the minuend // - y: the subtrahend // // Returns: // - result: z containing x-y modulo 2^256 // - underflow: true when x is less than y func (z *Uint) SubOverflow(x, y *Uint) (*Uint, bool) { var carry uint64 z[0], carry = bits.Sub64(x[0], y[0], 0) z[1], carry = bits.Sub64(x[1], y[1], carry) z[2], carry = bits.Sub64(x[2], y[2], carry) z[3], carry = bits.Sub64(x[3], y[3], carry) return z, carry != 0 } // Neg returns -x mod 2^256. // // Parameters: // - x: the value whose additive inverse modulo 2^256 is computed // // Returns: // - result: z containing -x modulo 2^256 func (z *Uint) Neg(x *Uint) *Uint { return z.Sub(Zero(), x) } // Mul sets z to the product x*y and returns z. // // Parameters: // - x: the first multiplicand // - y: the second multiplicand // // Returns: // - result: z containing the low 256 bits of x*y func (z *Uint) Mul(x, y *Uint) *Uint { var ( res Uint carry uint64 res1, res2, res3 uint64 ) carry, res[0] = bits.Mul64(x[0], y[0]) carry, res1 = umulHop(carry, x[1], y[0]) carry, res2 = umulHop(carry, x[2], y[0]) res3 = x[3]*y[0] + carry carry, res[1] = umulHop(res1, x[0], y[1]) carry, res2 = umulStep(res2, x[1], y[1], carry) res3 = res3 + x[2]*y[1] + carry carry, res[2] = umulHop(res2, x[0], y[2]) res3 = res3 + x[1]*y[2] + carry res[3] = res3 + x[0]*y[3] return z.Set(&res) } // MulOverflow sets z to the product x*y and returns z and true if overflow occurred. // // Parameters: // - x: the first multiplicand // - y: the second multiplicand // // Returns: // - result: z containing the low 256 bits of x*y // - overflow: true when the full product needs more than 256 bits func (z *Uint) MulOverflow(x, y *Uint) (*Uint, bool) { p := umul(x, y) copy(z[:], p[:4]) return z, (p[4] | p[5] | p[6] | p[7]) != 0 } // Div sets z to the quotient x/y and returns z. // It panics if y == 0. // // Parameters: // - x: the dividend // - y: the non-zero divisor; zero causes a division-by-zero panic // // Returns: // - result: z containing the unsigned quotient x/y func (z *Uint) Div(x, y *Uint) *Uint { if y.IsZero() { panic("division by zero") } if y.Gt(x) { return z.Clear() } if x.Eq(y) { return z.SetOne() } // Shortcut some cases if x.IsUint64() { return z.SetUint64(x.Uint64() / y.Uint64()) } // At this point, we know // x/y ; x > y > 0 var quot Uint udivrem(quot[:], x[:], y) return z.Set(") } // Mod sets z to the modulus x%y and returns z. // It panics if y == 0. // // Parameters: // - x: the dividend // - y: the non-zero divisor; zero causes a modulo-by-zero panic // // Returns: // - result: z containing the unsigned remainder x%y func (z *Uint) Mod(x, y *Uint) *Uint { if y.IsZero() { panic("modulo by zero") } if x.IsZero() { return z.Clear() } switch x.Cmp(y) { case -1: // x < y copy(z[:], x[:]) return z case 0: // x == y return z.Clear() // They are equal } // At this point: // x != 0 // y != 0 // x > y // Shortcut trivial case if x.IsUint64() { return z.SetUint64(x.Uint64() % y.Uint64()) } var quot Uint *z = udivrem(quot[:], x[:], y) return z } // MulMod sets z to (x * y) mod m and returns z. // It panics if m == 0. // // Parameters: // - x: the first multiplicand // - y: the second multiplicand // - m: the non-zero modulus; zero causes a modulo-by-zero panic // // Returns: // - result: z containing (x*y) modulo m func (z *Uint) MulMod(x, y, m *Uint) *Uint { if m.IsZero() { panic("modulo by zero") } if x.IsZero() || y.IsZero() { return z.Clear() } p := umul(x, y) if m[3] != 0 { mu := Reciprocal(m) r := reduce4(p, m, mu) return z.Set(&r) } var ( pl Uint ph Uint ) pl[0], pl[1], pl[2], pl[3] = p[0], p[1], p[2], p[3] ph[0], ph[1], ph[2], ph[3] = p[4], p[5], p[6], p[7] // If the multiplication is within 256 bits use Mod(). if ph.IsZero() { return z.Mod(&pl, m) } var quot [8]uint64 rem := udivrem(quot[:], p[:], m) return z.Set(&rem) } // DivMod sets z to the quotient x/y and m to the modulus x%y, returning the pair (z, m). // It panics if y == 0. // // Parameters: // - x: the dividend // - y: the non-zero divisor; zero causes a division-by-zero panic // - m: the destination overwritten with x modulo y // // Returns: // - quotient: z containing x/y // - remainder: m containing x%y func (z *Uint) DivMod(x, y, m *Uint) (*Uint, *Uint) { if y.IsZero() { panic("division by zero") } switch x.Cmp(y) { case -1: // x < y return z.Clear(), m.Set(x) case 0: // x == y return z.SetOne(), m.Clear() } // At this point: // x != 0 // y != 0 // x > y // Shortcut trivial case if x.IsUint64() { x0, y0 := x.Uint64(), y.Uint64() return z.SetUint64(x0 / y0), m.SetUint64(x0 % y0) } var quot Uint *m = udivrem(quot[:], x[:], y) *z = quot return z, m } // udivrem divides u by d and produces both quotient and remainder. // The quotient is stored in provided quot - len(u)-len(d)+1 words. // It loosely follows the Knuth's division algorithm (sometimes referenced as "schoolbook" division) using 64-bit words. // See Knuth, Volume 2, section 4.3.1, Algorithm D. func udivrem(quot, u []uint64, d *Uint) (rem Uint) { var dLen int for i := len(d) - 1; i >= 0; i-- { if d[i] != 0 { dLen = i + 1 break } } shift := uint(bits.LeadingZeros64(d[dLen-1])) var dnStorage Uint dn := dnStorage[:dLen] for i := dLen - 1; i > 0; i-- { dn[i] = (d[i] << shift) | (d[i-1] >> (64 - shift)) } dn[0] = d[0] << shift var uLen int for i := len(u) - 1; i >= 0; i-- { if u[i] != 0 { uLen = i + 1 break } } if uLen < dLen { copy(rem[:], u) return rem } var unStorage [9]uint64 un := unStorage[:uLen+1] un[uLen] = u[uLen-1] >> (64 - shift) for i := uLen - 1; i > 0; i-- { un[i] = (u[i] << shift) | (u[i-1] >> (64 - shift)) } un[0] = u[0] << shift if dLen == 1 { r := udivremBy1(quot, un, dn[0]) rem.SetUint64(r >> shift) return rem } udivremKnuth(quot, un, dn) for i := 0; i < dLen-1; i++ { rem[i] = (un[i] >> shift) | (un[i+1] << (64 - shift)) } rem[dLen-1] = un[dLen-1] >> shift return rem } // umul computes full 256 x 256 -> 512 multiplication. func umul(x, y *Uint) [8]uint64 { var res [8]uint64 topX := highestNonZeroWord(x) topY := highestNonZeroWord(y) if topX < 0 || topY < 0 { return res } lenX := topX + 1 lenY := topY + 1 for i := 0; i < lenX; i++ { xi := x[i] if xi == 0 { continue } var carry uint64 k := i for j := 0; j < lenY; j++ { hi, lo := bits.Mul64(xi, y[j]) lo, c := bits.Add64(lo, res[k], 0) hi += c lo, c = bits.Add64(lo, carry, 0) hi += c res[k] = lo carry = hi k++ } res[i+lenY] = carry } return res } // highestNonZeroWord returns the highest index with non-zero value or -1 if the Uint is zero. func highestNonZeroWord(u *Uint) int { for i := 3; i >= 0; i-- { if u[i] != 0 { return i } } return -1 } // umulStep computes (hi * 2^64 + lo) = z + (x * y) + carry. func umulStep(z, x, y, carry uint64) (hi, lo uint64) { hi, lo = bits.Mul64(x, y) lo, carry = bits.Add64(lo, carry, 0) hi += carry lo, carry = bits.Add64(lo, z, 0) hi += carry return hi, lo } // umulHop computes (hi * 2^64 + lo) = z + (x * y) func umulHop(z, x, y uint64) (hi, lo uint64) { hi, lo = bits.Mul64(x, y) lo, carry := bits.Add64(lo, z, 0) hi += carry return hi, lo } // udivremBy1 divides u by single normalized word d and produces both quotient and remainder. // The quotient is stored in provided quot. func udivremBy1(quot, u []uint64, d uint64) (rem uint64) { reciprocal := reciprocal2by1(d) rem = u[len(u)-1] // Set the top word as remainder. for j := len(u) - 2; j >= 0; j-- { quot[j], rem = udivrem2by1(rem, u[j], d, reciprocal) } return rem } // udivremKnuth implements the division of u by normalized multiple word d from the Knuth's division algorithm. // The quotient is stored in provided quot - len(u)-len(d) words. // Updates u to contain the remainder - len(d) words. func udivremKnuth(quot, u, d []uint64) { dLen := len(d) dh := d[dLen-1] dl := d[dLen-2] reciprocal := reciprocal2by1(dh) for j := len(u) - dLen - 1; j >= 0; j-- { u2 := u[j+dLen] u1 := u[j+dLen-1] u0 := u[j+dLen-2] var qhat, rhat uint64 if u2 >= dh { // Division overflows. qhat = 18446744073709551615 // max uint64 // NOTE: Add "qhat one to big" adjustment (not needed for correctness, but helps avoiding "add back" case). } else { qhat, rhat = udivrem2by1(u2, u1, dh, reciprocal) ph, pl := bits.Mul64(qhat, dl) if ph > rhat || (ph == rhat && pl > u0) { qhat-- // NOTE: Add "qhat one to big" adjustment (not needed for correctness, but helps avoiding "add back" case). } } // Multiply and subtract. borrow := subMulTo(u[j:], d, qhat) u[j+dLen] = u2 - borrow if u2 < borrow { // Too much subtracted, add back. qhat-- u[j+dLen] += addTo(u[j:], d) } quot[j] = qhat // Store quotient digit. } } // isBitSet returns true if bit n-th is set, where n = 0 is LSB. // The n must be <= 255. func (z *Uint) isBitSet(n uint) bool { return (z[n/64] & (1 << (n % 64))) != 0 } // IsOverflow reports whether the highest bit of z is set. // // Returns: // - overflow: true when z has bit 255 set func (z *Uint) IsOverflow() bool { return z.isBitSet(255) } // addTo computes x += y. // Requires len(x) >= len(y). func addTo(x, y []uint64) uint64 { var carry uint64 for i := 0; i < len(y); i++ { x[i], carry = bits.Add64(x[i], y[i], carry) } return carry } // subMulTo computes x -= y * multiplier. // Requires len(x) >= len(y). func subMulTo(x, y []uint64, multiplier uint64) uint64 { var borrow uint64 for i := 0; i < len(y); i++ { s, carry1 := bits.Sub64(x[i], borrow, 0) ph, pl := bits.Mul64(y[i], multiplier) t, carry2 := bits.Sub64(s, pl, 0) x[i] = t borrow = ph + carry1 + carry2 } return borrow } // reciprocal2by1 computes <^d, ^0> / d. func reciprocal2by1(d uint64) uint64 { reciprocal, _ := bits.Div64(^d, 18446744073709551615, d) return reciprocal } // udivrem2by1 divides <uh, ul> / d and produces both quotient and remainder. // It uses the provided d's reciprocal. // Implementation ported from https://github.com/chfast/intx and is based on // "Improved division by invariant integers", Algorithm 4. func udivrem2by1(uh, ul, d, reciprocal uint64) (quot, rem uint64) { qh, ql := bits.Mul64(reciprocal, uh) ql, carry := bits.Add64(ql, ul, 0) qh, _ = bits.Add64(qh, uh, carry) qh++ r := ul - qh*d if r > ql { qh-- r += d } if r >= d { qh++ r -= d } return qh, r }
- #6bitwise.gno
- #7// bitwise contains bitwise operations for Uint instances. // This file includes functions to perform bitwise AND, OR, XOR, and NOT operations, as well as bit shifting. // These operations are crucial for manipulating individual bits within a 256-bit unsigned integer. package uint256 // Or sets z to the bitwise OR of x and y and returns z. // // Parameters: // - x: First 256-bit operand. // - y: Second 256-bit operand. // // Returns: // - z: The 256-bit bitwise OR x | y, stored in the receiver. func (z *Uint) Or(x, y *Uint) *Uint { z[0] = x[0] | y[0] z[1] = x[1] | y[1] z[2] = x[2] | y[2] z[3] = x[3] | y[3] return z } // And sets z to the bitwise AND of x and y and returns z. // // Parameters: // - x: First 256-bit operand. // - y: Second 256-bit operand. // // Returns: // - z: The 256-bit bitwise AND x & y, stored in the receiver. func (z *Uint) And(x, y *Uint) *Uint { z[0] = x[0] & y[0] z[1] = x[1] & y[1] z[2] = x[2] & y[2] z[3] = x[3] & y[3] return z } // Not sets z to the bitwise complement of x and returns z. // // Parameters: // - x: 256-bit operand whose bits are complemented. // // Returns: // - z: The 256-bit bitwise complement ^x, stored in the receiver. func (z *Uint) Not(x *Uint) *Uint { z[3], z[2], z[1], z[0] = ^x[3], ^x[2], ^x[1], ^x[0] return z } // AndNot sets z to x AND NOT y and returns z. // // Parameters: // - x: First 256-bit operand. // - y: Operand whose bits are cleared from x. // // Returns: // - z: The 256-bit bit pattern x &^ y, stored in the receiver. func (z *Uint) AndNot(x, y *Uint) *Uint { z[0] = x[0] &^ y[0] z[1] = x[1] &^ y[1] z[2] = x[2] &^ y[2] z[3] = x[3] &^ y[3] return z } // Xor sets z to the bitwise exclusive OR of x and y and returns z. // // Parameters: // - x: First 256-bit operand. // - y: Second 256-bit operand. // // Returns: // - z: The 256-bit bitwise exclusive OR x ^ y, stored in the receiver. func (z *Uint) Xor(x, y *Uint) *Uint { z[0] = x[0] ^ y[0] z[1] = x[1] ^ y[1] z[2] = x[2] ^ y[2] z[3] = x[3] ^ y[3] return z } // Lsh sets z to x left-shifted by n bits and returns z. // Bits shifted beyond the 256-bit width are discarded; n >= 256 produces zero. // // Parameters: // - x: 256-bit operand to shift. // - n: Number of bit positions to shift left. // // Returns: // - z: The low 256 bits of x << n, stored in the receiver. func (z *Uint) Lsh(x *Uint, n uint) *Uint { if x.IsZero() { return z.Clear() } if n == 0 { return z.Set(x) } return z.lsh(x, n) } // lsh performs left shift without overflow checking func (z *Uint) lsh(x *Uint, n uint) *Uint { // n % 64 == 0 if n&0x3f == 0 { switch n { case 0: return z.Set(x) case 64: return z.lsh64(x) case 128: return z.lsh128(x) case 192: return z.lsh192(x) default: return z.Clear() } } var a, b uint64 // Big swaps first switch { case n > 192: z.lsh192(x) n -= 192 goto sh192 case n > 128: z.lsh128(x) n -= 128 goto sh128 case n > 64: z.lsh64(x) n -= 64 goto sh64 default: z.Set(x) } // remaining shifts a = z[0] >> (64 - n) z[0] = z[0] << n sh64: b = z[1] >> (64 - n) z[1] = (z[1] << n) | a sh128: a = z[2] >> (64 - n) z[2] = (z[2] << n) | b sh192: z[3] = (z[3] << n) | a return z } // Rsh sets z to x logically right-shifted by n bits and returns z. // Zero bits are shifted in from the left, and n >= 256 produces zero. // // Parameters: // - x: 256-bit operand to shift. // - n: Number of bit positions to shift right. // // Returns: // - z: The 256-bit logical right shift x >> n, stored in the receiver. func (z *Uint) Rsh(x *Uint, n uint) *Uint { // n % 64 == 0 if n&0x3f == 0 { switch n { case 0: return z.Set(x) case 64: return z.rsh64(x) case 128: return z.rsh128(x) case 192: return z.rsh192(x) default: return z.Clear() } } var a, b uint64 // Big swaps first switch { case n > 192: if n > 256 { return z.Clear() } z.rsh192(x) n -= 192 goto sh192 case n > 128: z.rsh128(x) n -= 128 goto sh128 case n > 64: z.rsh64(x) n -= 64 goto sh64 default: z.Set(x) } // remaining shifts a = z[3] << (64 - n) z[3] = z[3] >> n sh64: b = z[2] << (64 - n) z[2] = (z[2] >> n) | a sh128: a = z[1] << (64 - n) z[1] = (z[1] >> n) | b sh192: z[0] = (z[0] >> n) | a return z } // SRsh sets z to x arithmetically right-shifted by n bits and returns z. // The top bit is treated as a sign bit: negative patterns receive one-fill, // while non-negative patterns use the logical right shift. // // Parameters: // - x: 256-bit two's-complement bit pattern to shift. // - n: Number of bit positions to shift right. // // Returns: // - z: The arithmetic right shift of x, stored in the receiver; n >= 256 // yields all ones for a negative x and zero otherwise. func (z *Uint) SRsh(x *Uint, n uint) *Uint { // If the MSB is 0, SRsh is same as Rsh. if !x.isBitSet(255) { return z.Rsh(x, n) } if n%64 == 0 { switch n { case 0: return z.Set(x) case 64: return z.srsh64(x) case 128: return z.srsh128(x) case 192: return z.srsh192(x) default: return z.SetAllOne() } } var a uint64 = 18446744073709551615 << (64 - n%64) // Big swaps first switch { case n > 192: if n > 256 { return z.SetAllOne() } z.srsh192(x) n -= 192 goto sh192 case n > 128: z.srsh128(x) n -= 128 goto sh128 case n > 64: z.srsh64(x) n -= 64 goto sh64 default: z.Set(x) } // remaining shifts z[3], a = (z[3]>>n)|a, z[3]<<(64-n) sh64: z[2], a = (z[2]>>n)|a, z[2]<<(64-n) sh128: z[1], a = (z[1]>>n)|a, z[1]<<(64-n) sh192: z[0] = (z[0] >> n) | a return z } func (z *Uint) lsh64(x *Uint) *Uint { z[3], z[2], z[1], z[0] = x[2], x[1], x[0], 0 return z } func (z *Uint) lsh128(x *Uint) *Uint { z[3], z[2], z[1], z[0] = x[1], x[0], 0, 0 return z } func (z *Uint) lsh192(x *Uint) *Uint { z[3], z[2], z[1], z[0] = x[0], 0, 0, 0 return z } func (z *Uint) rsh64(x *Uint) *Uint { z[3], z[2], z[1], z[0] = 0, x[3], x[2], x[1] return z } func (z *Uint) rsh128(x *Uint) *Uint { z[3], z[2], z[1], z[0] = 0, 0, x[3], x[2] return z } func (z *Uint) rsh192(x *Uint) *Uint { z[3], z[2], z[1], z[0] = 0, 0, 0, x[3] return z } func (z *Uint) srsh64(x *Uint) *Uint { z[3], z[2], z[1], z[0] = 18446744073709551615, x[3], x[2], x[1] return z } func (z *Uint) srsh128(x *Uint) *Uint { z[3], z[2], z[1], z[0] = 18446744073709551615, 18446744073709551615, x[3], x[2] return z } func (z *Uint) srsh192(x *Uint) *Uint { z[3], z[2], z[1], z[0] = 18446744073709551615, 18446744073709551615, 18446744073709551615, x[3] return z }
- #8cmp.gno
- #9// cmp (or, comparisons) includes methods for comparing Uint instances. // These comparison functions cover a range of operations including equality checks, less than/greater than // evaluations, and specialized comparisons such as signed greater than. These are fundamental for logical // decision making based on Uint values. package uint256 import "math/bits" // Cmp compares z and x and returns -1 if z < x, 0 if z == x, or +1 if z > x. // // Parameters: // - x: the Uint value compared with z // // Returns: // - r: -1 when z<x, 0 when z==x, or +1 when z>x func (z *Uint) Cmp(x *Uint) (r int) { // z < x <=> z - x < 0 i.e. when subtraction overflows. d0, carry := bits.Sub64(z[0], x[0], 0) d1, carry := bits.Sub64(z[1], x[1], carry) d2, carry := bits.Sub64(z[2], x[2], carry) d3, carry := bits.Sub64(z[3], x[3], carry) if carry == 1 { return -1 } if d0|d1|d2|d3 == 0 { return 0 } return 1 } // IsZero returns true if z equals 0. // // Returns: // - isZero: true when all four words of z are zero func (z *Uint) IsZero() bool { return (z[0] | z[1] | z[2] | z[3]) == 0 } // Sign returns the sign of z interpreted as a two's complement signed number. // It returns -1 if z < 0, 0 if z == 0, or +1 if z > 0. // // Returns: // - sign: -1, 0, or +1 according to z interpreted as a two's-complement signed value func (z *Uint) Sign() int { if z.IsZero() { return 0 } if z[3] < 0x8000000000000000 { return 1 } return -1 } // Lt returns true if z is less than x. // // Parameters: // - x: the comparison operand // // Returns: // - less: true when z<x func (z *Uint) Lt(x *Uint) bool { // z < x <=> z - x < 0 i.e. when subtraction overflows. _, carry := bits.Sub64(z[0], x[0], 0) _, carry = bits.Sub64(z[1], x[1], carry) _, carry = bits.Sub64(z[2], x[2], carry) _, carry = bits.Sub64(z[3], x[3], carry) return carry != 0 } // Gt returns true if z is greater than x. // // Parameters: // - x: the comparison operand // // Returns: // - greater: true when z>x func (z *Uint) Gt(x *Uint) bool { return x.Lt(z) } // Lte returns true if z is less than or equal to x. // // Parameters: // - x: the comparison operand // // Returns: // - lessOrEqual: true when z<=x func (z *Uint) Lte(x *Uint) bool { return !x.Lt(z) } // Gte returns true if z is greater than or equal to x. // // Parameters: // - x: the comparison operand // // Returns: // - greaterOrEqual: true when z>=x func (z *Uint) Gte(x *Uint) bool { return !z.Lt(x) } // Eq returns true if z equals x. // // Parameters: // - x: the comparison operand // // Returns: // - equal: true when z and x have identical 256-bit values func (z *Uint) Eq(x *Uint) bool { return (z[0] == x[0]) && (z[1] == x[1]) && (z[2] == x[2]) && (z[3] == x[3]) } // Neq returns true if z does not equal x. // // Parameters: // - x: the comparison operand // // Returns: // - notEqual: true when z and x differ func (z *Uint) Neq(x *Uint) bool { return !z.Eq(x) }
- #10conversion.gno
- #11// conversions contains methods for converting Uint instances to other types and vice versa. // This includes conversions to and from basic types such as uint64 and int32, as well as string representations // and byte slices. Additionally, it covers marshaling and unmarshaling for JSON and other text formats. package uint256 import ( "encoding/binary" "strconv" ) // Uint64 returns the lower 64 bits of z as a uint64. // // Returns: // - value: the low 64 bits of z func (z *Uint) Uint64() uint64 { return z[0] } // Int64 returns the lower 64 bits of z as an int64. // // Returns: // - value: the low 64 bits of z interpreted as int64 func (z *Uint) Int64() int64 { return int64(z.Uint64()) } // Uint64WithOverflow returns the lower 64 bits of z and true if overflow occurred. // // Returns: // - value: the low 64 bits of z // - overflow: true when any upper 192 bits are non-zero func (z *Uint) Uint64WithOverflow() (uint64, bool) { return z[0], (z[1] | z[2] | z[3]) != 0 } // SetUint64 sets z to the value of x and returns z. // // Parameters: // - x: the uint64 value assigned to z // // Returns: // - result: z after setting it to x func (z *Uint) SetUint64(x uint64) *Uint { z[3], z[2], z[1], z[0] = 0, 0, 0, x return z } // IsUint64 reports whether z can be represented as a uint64. // // Returns: // - fits: true when z is representable in 64 bits func (z *Uint) IsUint64() bool { return (z[1] | z[2] | z[3]) == 0 } // Dec returns the decimal representation of z. // // Returns: // - decimal: the base-10 representation of z func (z *Uint) Dec() string { if z.IsZero() { return "0" } if z.IsUint64() { return strconv.FormatUint(z.Uint64(), 10) } // The max uint64 value being 18446744073709551615, the largest // power-of-ten below that is 10000000000000000000. // When we do a DivMod using that number, the remainder that we // get back is the lower part of the output. // // The ascii-output of remainder will never exceed 19 bytes (since it will be // below 10000000000000000000). // // Algorithm example using 100 as divisor // // 12345 % 100 = 45 (rem) // 12345 / 100 = 123 (quo) // -> output '45', continue iterate on 123 var ( // out is 98 bytes long: 78 (max size of a string without leading zeroes, // plus slack so we can copy 19 bytes every iteration). // We init it with zeroes, because when strconv appends the ascii representations, // it will omit leading zeroes. out [98]byte divisor Uint y = *z // copy z to avoid modifying it pos = len(out) // position to write to buf [19]byte // buffer to write uint64:s to bufSlice []byte = buf[:0] // slice for strconv.AppendUint ) // Initialize out array with '0's for i := range out { out[i] = '0' } // Set divisor to 10^19 divisor.SetUint64(10000000000000000000) for { // Obtain Q and R for divisor var quot Uint rem := udivrem(quot[:], y[:], &divisor) y = quot // Set Q for next loop // Convert the R to ascii representation bufSlice = strconv.AppendUint(bufSlice[:0], rem.Uint64(), 10) // Copy in the ascii digits copy(out[pos-len(bufSlice):], bufSlice) if y.IsZero() { break } // Move 19 digits left pos -= 19 } // skip leading zeroes by only using the 'used size' of bufSlice return string(out[pos-len(bufSlice):]) } // ToString returns the decimal string representation of z. // Returns an empty string if z is nil. This method doesn't exist in holiman's uint256. // // Returns: // - decimal: z in base 10, or an empty string when z is nil func (z *Uint) ToString() string { if z == nil { return "" } return z.Dec() } // SetBytes interprets buf as a big-endian unsigned integer and sets z to that value. // If buf is larger than 32 bytes, uses only the last 32 bytes. Returns z. // // Parameters: // - buf: the big-endian byte sequence; if longer than 32 bytes, only its final 32 bytes are used // // Returns: // - result: z after decoding the selected big-endian bytes func (z *Uint) SetBytes(buf []byte) *Uint { switch l := len(buf); l { case 0: z.Clear() case 1: z.SetBytes1(buf) case 2: z.SetBytes2(buf) case 3: z.SetBytes3(buf) case 4: z.SetBytes4(buf) case 5: z.SetBytes5(buf) case 6: z.SetBytes6(buf) case 7: z.SetBytes7(buf) case 8: z.SetBytes8(buf) case 9: z.SetBytes9(buf) case 10: z.SetBytes10(buf) case 11: z.SetBytes11(buf) case 12: z.SetBytes12(buf) case 13: z.SetBytes13(buf) case 14: z.SetBytes14(buf) case 15: z.SetBytes15(buf) case 16: z.SetBytes16(buf) case 17: z.SetBytes17(buf) case 18: z.SetBytes18(buf) case 19: z.SetBytes19(buf) case 20: z.SetBytes20(buf) case 21: z.SetBytes21(buf) case 22: z.SetBytes22(buf) case 23: z.SetBytes23(buf) case 24: z.SetBytes24(buf) case 25: z.SetBytes25(buf) case 26: z.SetBytes26(buf) case 27: z.SetBytes27(buf) case 28: z.SetBytes28(buf) case 29: z.SetBytes29(buf) case 30: z.SetBytes30(buf) case 31: z.SetBytes31(buf) default: z.SetBytes32(buf[l-32:]) } return z } // SetBytes1 sets z from a 1-byte big-endian slice and returns z. // Panics if input is shorter than 1 byte. // // Parameters: // - in: the first byte is decoded in big-endian order; it must be present // // Returns: // - result: z after decoding the first byte of in func (z *Uint) SetBytes1(in []byte) *Uint { z[3], z[2], z[1] = 0, 0, 0 z[0] = uint64(in[0]) return z } // SetBytes2 sets z from a 2-byte big-endian slice and returns z. // Panics if input is shorter than 2 bytes. // // Parameters: // - in: the byte sequence whose first 2 bytes are decoded in big-endian order; it must contain at least 2 bytes // // Returns: // - result: z after decoding the first 2 bytes of in in big-endian order func (z *Uint) SetBytes2(in []byte) *Uint { _ = in[1] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = uint64(binary.BigEndian.Uint16(in[0:2])) return z } // SetBytes3 sets z from a 3-byte big-endian slice and returns z. // Panics if input is shorter than 3 bytes. // // Parameters: // - in: the byte sequence whose first 3 bytes are decoded in big-endian order; it must contain at least 3 bytes // // Returns: // - result: z after decoding the first 3 bytes of in in big-endian order func (z *Uint) SetBytes3(in []byte) *Uint { _ = in[2] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16 return z } // SetBytes4 sets z from a 4-byte big-endian slice and returns z. // Panics if input is shorter than 4 bytes. // // Parameters: // - in: the byte sequence whose first 4 bytes are decoded in big-endian order; it must contain at least 4 bytes // // Returns: // - result: z after decoding the first 4 bytes of in in big-endian order func (z *Uint) SetBytes4(in []byte) *Uint { _ = in[3] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = uint64(binary.BigEndian.Uint32(in[0:4])) return z } // SetBytes5 sets z from a 5-byte big-endian slice and returns z. // Panics if input is shorter than 5 bytes. // // Parameters: // - in: the byte sequence whose first 5 bytes are decoded in big-endian order; it must contain at least 5 bytes // // Returns: // - result: z after decoding the first 5 bytes of in in big-endian order func (z *Uint) SetBytes5(in []byte) *Uint { _ = in[4] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = bigEndianUint40(in[0:5]) return z } // SetBytes6 sets z from a 6-byte big-endian slice and returns z. // Panics if input is shorter than 6 bytes. // // Parameters: // - in: the byte sequence whose first 6 bytes are decoded in big-endian order; it must contain at least 6 bytes // // Returns: // - result: z after decoding the first 6 bytes of in in big-endian order func (z *Uint) SetBytes6(in []byte) *Uint { _ = in[5] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = bigEndianUint48(in[0:6]) return z } // SetBytes7 sets z from a 7-byte big-endian slice and returns z. // Panics if input is shorter than 7 bytes. // // Parameters: // - in: the byte sequence whose first 7 bytes are decoded in big-endian order; it must contain at least 7 bytes // // Returns: // - result: z after decoding the first 7 bytes of in in big-endian order func (z *Uint) SetBytes7(in []byte) *Uint { _ = in[6] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = bigEndianUint56(in[0:7]) return z } // SetBytes8 sets z from an 8-byte big-endian slice and returns z. // Panics if input is shorter than 8 bytes. // // Parameters: // - in: the byte sequence whose first 8 bytes are decoded in big-endian order; it must contain at least 8 bytes // // Returns: // - result: z after decoding the first 8 bytes of in in big-endian order func (z *Uint) SetBytes8(in []byte) *Uint { _ = in[7] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2], z[1] = 0, 0, 0 z[0] = binary.BigEndian.Uint64(in[0:8]) return z } // SetBytes9 sets z from a 9-byte big-endian slice and returns z. // Panics if input is shorter than 9 bytes. // // Parameters: // - in: the byte sequence whose first 9 bytes are decoded in big-endian order; it must contain at least 9 bytes // // Returns: // - result: z after decoding the first 9 bytes of in in big-endian order func (z *Uint) SetBytes9(in []byte) *Uint { _ = in[8] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = uint64(in[0]) z[0] = binary.BigEndian.Uint64(in[1:9]) return z } // SetBytes10 sets z from a 10-byte big-endian slice and returns z. // Panics if input is shorter than 10 bytes. // // Parameters: // - in: the byte sequence whose first 10 bytes are decoded in big-endian order; it must contain at least 10 bytes // // Returns: // - result: z after decoding the first 10 bytes of in in big-endian order func (z *Uint) SetBytes10(in []byte) *Uint { _ = in[9] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = uint64(binary.BigEndian.Uint16(in[0:2])) z[0] = binary.BigEndian.Uint64(in[2:10]) return z } // SetBytes11 sets z from an 11-byte big-endian slice and returns z. // Panics if input is shorter than 11 bytes. // // Parameters: // - in: the byte sequence whose first 11 bytes are decoded in big-endian order; it must contain at least 11 bytes // // Returns: // - result: z after decoding the first 11 bytes of in in big-endian order func (z *Uint) SetBytes11(in []byte) *Uint { _ = in[10] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16 z[0] = binary.BigEndian.Uint64(in[3:11]) return z } // SetBytes12 sets z from a 12-byte big-endian slice and returns z. // Panics if input is shorter than 12 bytes. // // Parameters: // - in: the byte sequence whose first 12 bytes are decoded in big-endian order; it must contain at least 12 bytes // // Returns: // - result: z after decoding the first 12 bytes of in in big-endian order func (z *Uint) SetBytes12(in []byte) *Uint { _ = in[11] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = uint64(binary.BigEndian.Uint32(in[0:4])) z[0] = binary.BigEndian.Uint64(in[4:12]) return z } // SetBytes13 sets z from a 13-byte big-endian slice and returns z. // Panics if input is shorter than 13 bytes. // // Parameters: // - in: the byte sequence whose first 13 bytes are decoded in big-endian order; it must contain at least 13 bytes // // Returns: // - result: z after decoding the first 13 bytes of in in big-endian order func (z *Uint) SetBytes13(in []byte) *Uint { _ = in[12] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = bigEndianUint40(in[0:5]) z[0] = binary.BigEndian.Uint64(in[5:13]) return z } // SetBytes14 sets z from a 14-byte big-endian slice and returns z. // Panics if input is shorter than 14 bytes. // // Parameters: // - in: the byte sequence whose first 14 bytes are decoded in big-endian order; it must contain at least 14 bytes // // Returns: // - result: z after decoding the first 14 bytes of in in big-endian order func (z *Uint) SetBytes14(in []byte) *Uint { _ = in[13] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = bigEndianUint48(in[0:6]) z[0] = binary.BigEndian.Uint64(in[6:14]) return z } // SetBytes15 sets z from a 15-byte big-endian slice and returns z. // Panics if input is shorter than 15 bytes. // // Parameters: // - in: the byte sequence whose first 15 bytes are decoded in big-endian order; it must contain at least 15 bytes // // Returns: // - result: z after decoding the first 15 bytes of in in big-endian order func (z *Uint) SetBytes15(in []byte) *Uint { _ = in[14] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = bigEndianUint56(in[0:7]) z[0] = binary.BigEndian.Uint64(in[7:15]) return z } // SetBytes16 sets z from a 16-byte big-endian slice and returns z. // Panics if input is shorter than 16 bytes. // // Parameters: // - in: the byte sequence whose first 16 bytes are decoded in big-endian order; it must contain at least 16 bytes // // Returns: // - result: z after decoding the first 16 bytes of in in big-endian order func (z *Uint) SetBytes16(in []byte) *Uint { _ = in[15] // bounds check hint to compiler; see golang.org/issue/14808 z[3], z[2] = 0, 0 z[1] = binary.BigEndian.Uint64(in[0:8]) z[0] = binary.BigEndian.Uint64(in[8:16]) return z } // SetBytes17 sets z from a 17-byte big-endian slice and returns z. // Panics if input is shorter than 17 bytes. // // Parameters: // - in: the byte sequence whose first 17 bytes are decoded in big-endian order; it must contain at least 17 bytes // // Returns: // - result: z after decoding the first 17 bytes of in in big-endian order func (z *Uint) SetBytes17(in []byte) *Uint { _ = in[16] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = uint64(in[0]) z[1] = binary.BigEndian.Uint64(in[1:9]) z[0] = binary.BigEndian.Uint64(in[9:17]) return z } // SetBytes18 sets z from an 18-byte big-endian slice and returns z. // Panics if input is shorter than 18 bytes. // // Parameters: // - in: the byte sequence whose first 18 bytes are decoded in big-endian order; it must contain at least 18 bytes // // Returns: // - result: z after decoding the first 18 bytes of in in big-endian order func (z *Uint) SetBytes18(in []byte) *Uint { _ = in[17] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = uint64(binary.BigEndian.Uint16(in[0:2])) z[1] = binary.BigEndian.Uint64(in[2:10]) z[0] = binary.BigEndian.Uint64(in[10:18]) return z } // SetBytes19 sets z from a 19-byte big-endian slice and returns z. // Panics if input is shorter than 19 bytes. // // Parameters: // - in: the byte sequence whose first 19 bytes are decoded in big-endian order; it must contain at least 19 bytes // // Returns: // - result: z after decoding the first 19 bytes of in in big-endian order func (z *Uint) SetBytes19(in []byte) *Uint { _ = in[18] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16 z[1] = binary.BigEndian.Uint64(in[3:11]) z[0] = binary.BigEndian.Uint64(in[11:19]) return z } // SetBytes20 sets z from a 20-byte big-endian slice and returns z. // Panics if input is shorter than 20 bytes. // // Parameters: // - in: the byte sequence whose first 20 bytes are decoded in big-endian order; it must contain at least 20 bytes // // Returns: // - result: z after decoding the first 20 bytes of in in big-endian order func (z *Uint) SetBytes20(in []byte) *Uint { _ = in[19] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = uint64(binary.BigEndian.Uint32(in[0:4])) z[1] = binary.BigEndian.Uint64(in[4:12]) z[0] = binary.BigEndian.Uint64(in[12:20]) return z } // SetBytes21 sets z from a 21-byte big-endian slice and returns z. // Panics if input is shorter than 21 bytes. // // Parameters: // - in: the byte sequence whose first 21 bytes are decoded in big-endian order; it must contain at least 21 bytes // // Returns: // - result: z after decoding the first 21 bytes of in in big-endian order func (z *Uint) SetBytes21(in []byte) *Uint { _ = in[20] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = bigEndianUint40(in[0:5]) z[1] = binary.BigEndian.Uint64(in[5:13]) z[0] = binary.BigEndian.Uint64(in[13:21]) return z } // SetBytes22 sets z from a 22-byte big-endian slice and returns z. // Panics if input is shorter than 22 bytes. // // Parameters: // - in: the byte sequence whose first 22 bytes are decoded in big-endian order; it must contain at least 22 bytes // // Returns: // - result: z after decoding the first 22 bytes of in in big-endian order func (z *Uint) SetBytes22(in []byte) *Uint { _ = in[21] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = bigEndianUint48(in[0:6]) z[1] = binary.BigEndian.Uint64(in[6:14]) z[0] = binary.BigEndian.Uint64(in[14:22]) return z } // SetBytes23 sets z from a 23-byte big-endian slice and returns z. // Panics if input is shorter than 23 bytes. // // Parameters: // - in: the byte sequence whose first 23 bytes are decoded in big-endian order; it must contain at least 23 bytes // // Returns: // - result: z after decoding the first 23 bytes of in in big-endian order func (z *Uint) SetBytes23(in []byte) *Uint { _ = in[22] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = bigEndianUint56(in[0:7]) z[1] = binary.BigEndian.Uint64(in[7:15]) z[0] = binary.BigEndian.Uint64(in[15:23]) return z } // SetBytes24 sets z from a 24-byte big-endian slice and returns z. // Panics if input is shorter than 24 bytes. // // Parameters: // - in: the byte sequence whose first 24 bytes are decoded in big-endian order; it must contain at least 24 bytes // // Returns: // - result: z after decoding the first 24 bytes of in in big-endian order func (z *Uint) SetBytes24(in []byte) *Uint { _ = in[23] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = 0 z[2] = binary.BigEndian.Uint64(in[0:8]) z[1] = binary.BigEndian.Uint64(in[8:16]) z[0] = binary.BigEndian.Uint64(in[16:24]) return z } // SetBytes25 sets z from a 25-byte big-endian slice and returns z. // Panics if input is shorter than 25 bytes. // // Parameters: // - in: the byte sequence whose first 25 bytes are decoded in big-endian order; it must contain at least 25 bytes // // Returns: // - result: z after decoding the first 25 bytes of in in big-endian order func (z *Uint) SetBytes25(in []byte) *Uint { _ = in[24] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = uint64(in[0]) z[2] = binary.BigEndian.Uint64(in[1:9]) z[1] = binary.BigEndian.Uint64(in[9:17]) z[0] = binary.BigEndian.Uint64(in[17:25]) return z } // SetBytes26 sets z from a 26-byte big-endian slice and returns z. // Panics if input is shorter than 26 bytes. // // Parameters: // - in: the byte sequence whose first 26 bytes are decoded in big-endian order; it must contain at least 26 bytes // // Returns: // - result: z after decoding the first 26 bytes of in in big-endian order func (z *Uint) SetBytes26(in []byte) *Uint { _ = in[25] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = uint64(binary.BigEndian.Uint16(in[0:2])) z[2] = binary.BigEndian.Uint64(in[2:10]) z[1] = binary.BigEndian.Uint64(in[10:18]) z[0] = binary.BigEndian.Uint64(in[18:26]) return z } // SetBytes27 sets z from a 27-byte big-endian slice and returns z. // Panics if input is shorter than 27 bytes. // // Parameters: // - in: the byte sequence whose first 27 bytes are decoded in big-endian order; it must contain at least 27 bytes // // Returns: // - result: z after decoding the first 27 bytes of in in big-endian order func (z *Uint) SetBytes27(in []byte) *Uint { _ = in[26] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16 z[2] = binary.BigEndian.Uint64(in[3:11]) z[1] = binary.BigEndian.Uint64(in[11:19]) z[0] = binary.BigEndian.Uint64(in[19:27]) return z } // SetBytes28 sets z from a 28-byte big-endian slice and returns z. // Panics if input is shorter than 28 bytes. // // Parameters: // - in: the byte sequence whose first 28 bytes are decoded in big-endian order; it must contain at least 28 bytes // // Returns: // - result: z after decoding the first 28 bytes of in in big-endian order func (z *Uint) SetBytes28(in []byte) *Uint { _ = in[27] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = uint64(binary.BigEndian.Uint32(in[0:4])) z[2] = binary.BigEndian.Uint64(in[4:12]) z[1] = binary.BigEndian.Uint64(in[12:20]) z[0] = binary.BigEndian.Uint64(in[20:28]) return z } // SetBytes29 sets z from a 29-byte big-endian slice and returns z. // Panics if input is shorter than 29 bytes. // // Parameters: // - in: the byte sequence whose first 29 bytes are decoded in big-endian order; it must contain at least 29 bytes // // Returns: // - result: z after decoding the first 29 bytes of in in big-endian order func (z *Uint) SetBytes29(in []byte) *Uint { _ = in[28] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = bigEndianUint40(in[0:5]) z[2] = binary.BigEndian.Uint64(in[5:13]) z[1] = binary.BigEndian.Uint64(in[13:21]) z[0] = binary.BigEndian.Uint64(in[21:29]) return z } // SetBytes30 sets z from a 30-byte big-endian slice and returns z. // Panics if input is shorter than 30 bytes. // // Parameters: // - in: the byte sequence whose first 30 bytes are decoded in big-endian order; it must contain at least 30 bytes // // Returns: // - result: z after decoding the first 30 bytes of in in big-endian order func (z *Uint) SetBytes30(in []byte) *Uint { _ = in[29] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = bigEndianUint48(in[0:6]) z[2] = binary.BigEndian.Uint64(in[6:14]) z[1] = binary.BigEndian.Uint64(in[14:22]) z[0] = binary.BigEndian.Uint64(in[22:30]) return z } // SetBytes31 sets z from a 31-byte big-endian slice and returns z. // Panics if input is shorter than 31 bytes. // // Parameters: // - in: the byte sequence whose first 31 bytes are decoded in big-endian order; it must contain at least 31 bytes // // Returns: // - result: z after decoding the first 31 bytes of in in big-endian order func (z *Uint) SetBytes31(in []byte) *Uint { _ = in[30] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = bigEndianUint56(in[0:7]) z[2] = binary.BigEndian.Uint64(in[7:15]) z[1] = binary.BigEndian.Uint64(in[15:23]) z[0] = binary.BigEndian.Uint64(in[23:31]) return z } // SetBytes32 sets z from a 32-byte big-endian slice and returns z. // Panics if input is shorter than 32 bytes. // // Parameters: // - in: the byte sequence whose first 32 bytes are decoded in big-endian order; it must contain at least 32 bytes // // Returns: // - result: z after decoding the first 32 bytes of in in big-endian order func (z *Uint) SetBytes32(in []byte) *Uint { _ = in[31] // bounds check hint to compiler; see golang.org/issue/14808 z[3] = binary.BigEndian.Uint64(in[0:8]) z[2] = binary.BigEndian.Uint64(in[8:16]) z[1] = binary.BigEndian.Uint64(in[16:24]) z[0] = binary.BigEndian.Uint64(in[24:32]) return z } // Utility methods that are "missing" among the bigEndian.UintXX methods. // bigEndianUint40 returns the uint64 value represented by the 5 bytes in big-endian order. func bigEndianUint40(b []byte) uint64 { _ = b[4] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[4]) | uint64(b[3])<<8 | uint64(b[2])<<16 | uint64(b[1])<<24 | uint64(b[0])<<32 } // bigEndianUint56 returns the uint64 value represented by the 7 bytes in big-endian order. func bigEndianUint56(b []byte) uint64 { _ = b[6] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[6]) | uint64(b[5])<<8 | uint64(b[4])<<16 | uint64(b[3])<<24 | uint64(b[2])<<32 | uint64(b[1])<<40 | uint64(b[0])<<48 } // bigEndianUint48 returns the uint64 value represented by the 6 bytes in big-endian order. func bigEndianUint48(b []byte) uint64 { _ = b[5] // bounds check hint to compiler; see golang.org/issue/14808 return uint64(b[5]) | uint64(b[4])<<8 | uint64(b[3])<<16 | uint64(b[2])<<24 | uint64(b[1])<<32 | uint64(b[0])<<40 }
- #12doc.gno
- #13// Package uint256 implements 256-bit unsigned integer arithmetic for GnoSwap. // // This package provides a Uint type that represents a 256-bit unsigned integer, // stored as four uint64 values in little-endian order. The unsuffixed Add, Sub, // and Mul methods return the low 256 bits; AddOverflow, SubOverflow, and // MulOverflow additionally report an overflow/underflow flag. MulDiv and // MulDivRoundingUp panic on a zero denominator or an unrepresentable result; // the rounding variant also panics if adding one to its result would overflow. // // The implementation is optimized for gas efficiency while maintaining // compatibility with Ethereum's uint256 semantics, ensuring consistent // behavior across different blockchain environments. package uint256
- #14fullmath.gno
- #15// REF: https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol // fullmath implements Uniswap V3's FullMath library. // // This library provides advanced fixed-point math operations that are essential // for Uniswap V3's tick math and liquidity calculations. It enables precise // calculations of (a * b / denominator) with full 512-bit intermediate precision. // // NOTE: Unlike the base arithmetic methods in the uint256 package, which return // low-256-bit values (or values plus overflow flags in their `*Overflow` // variants), functions in this file panic on invalid inputs to maintain // behavioral compatibility with the original Solidity implementation. // // This design choice is intentional because: // 1. These functions are typically used in hot paths where error handling would add overhead // 2. Invalid inputs (like zero denominator) represent programming errors, not runtime conditions // 3. Staying close to the Solidity implementation makes protocol porting more reliable // // If you need error-returning versions, wrap these functions with appropriate error handling. package uint256 // MulDiv computes floor((a * b) / denominator) with a full 512-bit intermediate product. // // Parameters: // - a: First non-negative 256-bit multiplicand. // - b: Second non-negative 256-bit multiplicand. // - denominator: Non-zero 256-bit divisor. // // Returns: // - quotient: The exact floor quotient when it fits in 256 bits. // // Panics if denominator is zero or the quotient is at least 2^256. func MulDiv(a, b, denominator *Uint) *Uint { if denominator.IsZero() { panic("denominator must be greater than 0") } // 512-bit product (8 limbs of 64 bits) p := umul(a, b) if (p[4] | p[5] | p[6] | p[7]) == 0 { var lo Uint lo[0], lo[1], lo[2], lo[3] = p[0], p[1], p[2], p[3] return new(Uint).Div(&lo, denominator) } // optional early overflow check: // If hi >= denominator then floor((hi*2^256 + lo) / denominator) >= 2^256, which is overflow. { var hi Uint hi[0], hi[1], hi[2], hi[3] = p[4], p[5], p[6], p[7] if denominator.Lte(&hi) { panic("overflow: denominator(" + denominator.ToString() + ") must be greater than hi(" + hi.ToString() + ")") } } // perform 512 / 256 division // udivrem stores quotient into `quot` (len(u) - len(d) + 1 words) // we pass 8 words to be safe. var quot [8]uint64 udivrem(quot[:], p[:], denominator) // ignore remainder if (quot[4] | quot[5] | quot[6] | quot[7]) != 0 { panic("uint256: MulDiv overflow (high quotient words non-zero)") } // return lower 256 bits of quotient var z Uint copy(z[:], quot[:4]) return &z } // MulDivRoundingUp computes ceil((a * b) / denominator) with a full 512-bit intermediate product. // // Parameters: // - a: First non-negative 256-bit multiplicand. // - b: Second non-negative 256-bit multiplicand. // - denominator: Non-zero 256-bit divisor. // // Returns: // - quotient: The ceiling quotient; it is one greater than the floor quotient // exactly when the product has a non-zero remainder. // // Panics if denominator is zero or rounding the result exceeds 256 bits. func MulDivRoundingUp(a, b, denominator *Uint) *Uint { result := MulDiv(a, b, denominator) // Check if there's a remainder mulModResult := new(Uint).MulMod(a, b, denominator) // If there's no remainder, return the result as-is if mulModResult.IsZero() { return result } // Add 1 to round up, but check for overflow if result.Eq(MaxUint256()) { panic("overflow: result(" + result.ToString() + ") + 1 would exceed MAX_UINT256") } return result.Add(result, &Uint{1, 0, 0, 0}) } // DivRoundingUp computes ceil(x / y) for unsigned 256-bit operands. // // Parameters: // - x: Non-negative 256-bit dividend. // - y: Non-zero 256-bit divisor. // // Returns: // - quotient: The quotient rounded toward positive infinity. // // Panics if y is zero. func DivRoundingUp(x, y *Uint) *Uint { div, mod := new(Uint).DivMod(x, y, new(Uint)) if !mod.IsZero() { div.Add(div, &Uint{1, 0, 0, 0}) } return div }
- #16gnomod.toml
- #17module = "gno.land/p/gnoswap/uint256/v1" gno = "0.9"
- #18mod.gno
- #19package uint256 import ( "math/bits" ) // Reciprocal computes the 320-bit reciprocal estimate used by Barrett reduction. // // The implementation is specialized for a four-word modulus with m[3] non-zero // (2^192 <= m < 2^256). For a modulus whose most-significant word is zero it // returns an all-zero estimate instead of running the refinement steps. // // Parameters: // - m: Four-word unsigned modulus; its most-significant word selects the supported range. // // Returns: // - mu: Five little-endian uint64 words containing the reciprocal estimate for m. func Reciprocal(m *Uint) (mu [5]uint64) { if m[3] == 0 { return mu } s := bits.LeadingZeros64(m[3]) // Replace with leadingZeros(m) for general case p := 255 - s // floor(log_2(m)), m>0 // 0 or a power of 2? // Check if at least one bit is set in m[2], m[1] or m[0], // or at least two bits in m[3] if m[0]|m[1]|m[2]|(m[3]&(m[3]-1)) == 0 { mu[4] = 18446744073709551615 >> uint(p&63) mu[3] = 18446744073709551615 mu[2] = 18446744073709551615 mu[1] = 18446744073709551615 mu[0] = 18446744073709551615 return mu } // Maximise division precision by left-aligning divisor var ( y Uint // left-aligned copy of m r0 uint32 // estimate of 2^31/y ) y.Lsh(m, uint(s)) // 1/2 < y < 1 // Extract most significant 32 bits yh := uint32(y[3] >> 32) if yh == 0x80000000 { // Avoid overflow in division r0 = 0xffffffff } else { r0, _ = bits.Div32(0x80000000, 0, yh) } // First iteration: 32 -> 64 t1 := uint64(r0) // 2^31/y t1 *= t1 // 2^62/y^2 t1, _ = bits.Mul64(t1, y[3]) // 2^62/y^2 * 2^64/y / 2^64 = 2^62/y r1 := uint64(r0) << 32 // 2^63/y r1 -= t1 // 2^63/y - 2^62/y = 2^62/y r1 *= 2 // 2^63/y if (r1 | (y[3] << 1)) == 0 { r1 = 18446744073709551615 } // Second iteration: 64 -> 128 // square: 2^126/y^2 a2h, a2l := bits.Mul64(r1, r1) // multiply by y: e2h:e2l:b2h = 2^126/y^2 * 2^128/y / 2^128 = 2^126/y b2h, _ := bits.Mul64(a2l, y[2]) c2h, c2l := bits.Mul64(a2l, y[3]) d2h, d2l := bits.Mul64(a2h, y[2]) e2h, e2l := bits.Mul64(a2h, y[3]) b2h, c := bits.Add64(b2h, c2l, 0) e2l, c = bits.Add64(e2l, c2h, c) e2h, _ = bits.Add64(e2h, 0, c) _, c = bits.Add64(b2h, d2l, 0) e2l, c = bits.Add64(e2l, d2h, c) e2h, _ = bits.Add64(e2h, 0, c) // subtract: t2h:t2l = 2^127/y - 2^126/y = 2^126/y t2l, b := bits.Sub64(0, e2l, 0) t2h, _ := bits.Sub64(r1, e2h, b) // double: r2h:r2l = 2^127/y r2l, c := bits.Add64(t2l, t2l, 0) r2h, _ := bits.Add64(t2h, t2h, c) if (r2h | r2l | (y[3] << 1)) == 0 { r2h = 18446744073709551615 r2l = 18446744073709551615 } // Third iteration: 128 -> 192 // square r2 (keep 256 bits): 2^190/y^2 a3h, a3l := bits.Mul64(r2l, r2l) b3h, b3l := bits.Mul64(r2l, r2h) c3h, c3l := bits.Mul64(r2h, r2h) a3h, c = bits.Add64(a3h, b3l, 0) c3l, c = bits.Add64(c3l, b3h, c) c3h, _ = bits.Add64(c3h, 0, c) a3h, c = bits.Add64(a3h, b3l, 0) c3l, c = bits.Add64(c3l, b3h, c) c3h, _ = bits.Add64(c3h, 0, c) // multiply by y: q = 2^190/y^2 * 2^192/y / 2^192 = 2^190/y x0 := a3l x1 := a3h x2 := c3l x3 := c3h var q0, q1, q2, q3, q4, t0 uint64 q0, _ = bits.Mul64(x2, y[0]) q1, t0 = bits.Mul64(x3, y[0]) q0, c = bits.Add64(q0, t0, 0) q1, _ = bits.Add64(q1, 0, c) t1, _ = bits.Mul64(x1, y[1]) q0, c = bits.Add64(q0, t1, 0) q2, t0 = bits.Mul64(x3, y[1]) q1, c = bits.Add64(q1, t0, c) q2, _ = bits.Add64(q2, 0, c) t1, t0 = bits.Mul64(x2, y[1]) q0, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) q2, _ = bits.Add64(q2, 0, c) t1, t0 = bits.Mul64(x1, y[2]) q0, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) q3, t0 = bits.Mul64(x3, y[2]) q2, c = bits.Add64(q2, t0, c) q3, _ = bits.Add64(q3, 0, c) t1, _ = bits.Mul64(x0, y[2]) q0, c = bits.Add64(q0, t1, 0) t1, t0 = bits.Mul64(x2, y[2]) q1, c = bits.Add64(q1, t0, c) q2, c = bits.Add64(q2, t1, c) q3, _ = bits.Add64(q3, 0, c) t1, t0 = bits.Mul64(x1, y[3]) q1, c = bits.Add64(q1, t0, 0) q2, c = bits.Add64(q2, t1, c) q4, t0 = bits.Mul64(x3, y[3]) q3, c = bits.Add64(q3, t0, c) q4, _ = bits.Add64(q4, 0, c) t1, t0 = bits.Mul64(x0, y[3]) q0, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) t1, t0 = bits.Mul64(x2, y[3]) q2, c = bits.Add64(q2, t0, c) q3, c = bits.Add64(q3, t1, c) q4, _ = bits.Add64(q4, 0, c) // subtract: t3 = 2^191/y - 2^190/y = 2^190/y _, b = bits.Sub64(0, q0, 0) _, b = bits.Sub64(0, q1, b) t3l, b := bits.Sub64(0, q2, b) t3m, b := bits.Sub64(r2l, q3, b) t3h, _ := bits.Sub64(r2h, q4, b) // double: r3 = 2^191/y r3l, c := bits.Add64(t3l, t3l, 0) r3m, c := bits.Add64(t3m, t3m, c) r3h, _ := bits.Add64(t3h, t3h, c) // Fourth iteration: 192 -> 320 // square r3 a4h, a4l := bits.Mul64(r3l, r3l) b4h, b4l := bits.Mul64(r3l, r3m) c4h, c4l := bits.Mul64(r3l, r3h) d4h, d4l := bits.Mul64(r3m, r3m) e4h, e4l := bits.Mul64(r3m, r3h) f4h, f4l := bits.Mul64(r3h, r3h) b4h, c = bits.Add64(b4h, c4l, 0) e4l, c = bits.Add64(e4l, c4h, c) e4h, _ = bits.Add64(e4h, 0, c) a4h, c = bits.Add64(a4h, b4l, 0) d4l, c = bits.Add64(d4l, b4h, c) d4h, c = bits.Add64(d4h, e4l, c) f4l, c = bits.Add64(f4l, e4h, c) f4h, _ = bits.Add64(f4h, 0, c) a4h, c = bits.Add64(a4h, b4l, 0) d4l, c = bits.Add64(d4l, b4h, c) d4h, c = bits.Add64(d4h, e4l, c) f4l, c = bits.Add64(f4l, e4h, c) f4h, _ = bits.Add64(f4h, 0, c) // multiply by y x1, x0 = bits.Mul64(d4h, y[0]) x3, x2 = bits.Mul64(f4h, y[0]) t1, t0 = bits.Mul64(f4l, y[0]) x1, c = bits.Add64(x1, t0, 0) x2, c = bits.Add64(x2, t1, c) x3, _ = bits.Add64(x3, 0, c) t1, t0 = bits.Mul64(d4h, y[1]) x1, c = bits.Add64(x1, t0, 0) x2, c = bits.Add64(x2, t1, c) x4, t0 := bits.Mul64(f4h, y[1]) x3, c = bits.Add64(x3, t0, c) x4, _ = bits.Add64(x4, 0, c) t1, t0 = bits.Mul64(d4l, y[1]) x0, c = bits.Add64(x0, t0, 0) x1, c = bits.Add64(x1, t1, c) t1, t0 = bits.Mul64(f4l, y[1]) x2, c = bits.Add64(x2, t0, c) x3, c = bits.Add64(x3, t1, c) x4, _ = bits.Add64(x4, 0, c) t1, t0 = bits.Mul64(a4h, y[2]) x0, c = bits.Add64(x0, t0, 0) x1, c = bits.Add64(x1, t1, c) t1, t0 = bits.Mul64(d4h, y[2]) x2, c = bits.Add64(x2, t0, c) x3, c = bits.Add64(x3, t1, c) x5, t0 := bits.Mul64(f4h, y[2]) x4, c = bits.Add64(x4, t0, c) x5, _ = bits.Add64(x5, 0, c) t1, t0 = bits.Mul64(d4l, y[2]) x1, c = bits.Add64(x1, t0, 0) x2, c = bits.Add64(x2, t1, c) t1, t0 = bits.Mul64(f4l, y[2]) x3, c = bits.Add64(x3, t0, c) x4, c = bits.Add64(x4, t1, c) x5, _ = bits.Add64(x5, 0, c) t1, t0 = bits.Mul64(a4h, y[3]) x1, c = bits.Add64(x1, t0, 0) x2, c = bits.Add64(x2, t1, c) t1, t0 = bits.Mul64(d4h, y[3]) x3, c = bits.Add64(x3, t0, c) x4, c = bits.Add64(x4, t1, c) x6, t0 := bits.Mul64(f4h, y[3]) x5, c = bits.Add64(x5, t0, c) x6, _ = bits.Add64(x6, 0, c) t1, t0 = bits.Mul64(a4l, y[3]) x0, c = bits.Add64(x0, t0, 0) x1, c = bits.Add64(x1, t1, c) t1, t0 = bits.Mul64(d4l, y[3]) x2, c = bits.Add64(x2, t0, c) x3, c = bits.Add64(x3, t1, c) t1, t0 = bits.Mul64(f4l, y[3]) x4, c = bits.Add64(x4, t0, c) x5, c = bits.Add64(x5, t1, c) x6, _ = bits.Add64(x6, 0, c) // subtract _, b = bits.Sub64(0, x0, 0) _, b = bits.Sub64(0, x1, b) r4l, b := bits.Sub64(0, x2, b) r4k, b := bits.Sub64(0, x3, b) r4j, b := bits.Sub64(r3l, x4, b) r4i, b := bits.Sub64(r3m, x5, b) r4h, _ := bits.Sub64(r3h, x6, b) // Multiply candidate for 1/4y by y, with full precision x0 = r4l x1 = r4k x2 = r4j x3 = r4i x4 = r4h q1, q0 = bits.Mul64(x0, y[0]) q3, q2 = bits.Mul64(x2, y[0]) q5, q4 := bits.Mul64(x4, y[0]) t1, t0 = bits.Mul64(x1, y[0]) q1, c = bits.Add64(q1, t0, 0) q2, c = bits.Add64(q2, t1, c) t1, t0 = bits.Mul64(x3, y[0]) q3, c = bits.Add64(q3, t0, c) q4, c = bits.Add64(q4, t1, c) q5, _ = bits.Add64(q5, 0, c) t1, t0 = bits.Mul64(x0, y[1]) q1, c = bits.Add64(q1, t0, 0) q2, c = bits.Add64(q2, t1, c) t1, t0 = bits.Mul64(x2, y[1]) q3, c = bits.Add64(q3, t0, c) q4, c = bits.Add64(q4, t1, c) q6, t0 := bits.Mul64(x4, y[1]) q5, c = bits.Add64(q5, t0, c) q6, _ = bits.Add64(q6, 0, c) t1, t0 = bits.Mul64(x1, y[1]) q2, c = bits.Add64(q2, t0, 0) q3, c = bits.Add64(q3, t1, c) t1, t0 = bits.Mul64(x3, y[1]) q4, c = bits.Add64(q4, t0, c) q5, c = bits.Add64(q5, t1, c) q6, _ = bits.Add64(q6, 0, c) t1, t0 = bits.Mul64(x0, y[2]) q2, c = bits.Add64(q2, t0, 0) q3, c = bits.Add64(q3, t1, c) t1, t0 = bits.Mul64(x2, y[2]) q4, c = bits.Add64(q4, t0, c) q5, c = bits.Add64(q5, t1, c) q7, t0 := bits.Mul64(x4, y[2]) q6, c = bits.Add64(q6, t0, c) q7, _ = bits.Add64(q7, 0, c) t1, t0 = bits.Mul64(x1, y[2]) q3, c = bits.Add64(q3, t0, 0) q4, c = bits.Add64(q4, t1, c) t1, t0 = bits.Mul64(x3, y[2]) q5, c = bits.Add64(q5, t0, c) q6, c = bits.Add64(q6, t1, c) q7, _ = bits.Add64(q7, 0, c) t1, t0 = bits.Mul64(x0, y[3]) q3, c = bits.Add64(q3, t0, 0) q4, c = bits.Add64(q4, t1, c) t1, t0 = bits.Mul64(x2, y[3]) q5, c = bits.Add64(q5, t0, c) q6, c = bits.Add64(q6, t1, c) q8, t0 := bits.Mul64(x4, y[3]) q7, c = bits.Add64(q7, t0, c) q8, _ = bits.Add64(q8, 0, c) t1, t0 = bits.Mul64(x1, y[3]) q4, c = bits.Add64(q4, t0, 0) q5, c = bits.Add64(q5, t1, c) t1, t0 = bits.Mul64(x3, y[3]) q6, c = bits.Add64(q6, t0, c) q7, c = bits.Add64(q7, t1, c) q8, _ = bits.Add64(q8, 0, c) // Final adjustment // subtract q from 1/4 _, b = bits.Sub64(0, q0, 0) _, b = bits.Sub64(0, q1, b) _, b = bits.Sub64(0, q2, b) _, b = bits.Sub64(0, q3, b) _, b = bits.Sub64(0, q4, b) _, b = bits.Sub64(0, q5, b) _, b = bits.Sub64(0, q6, b) _, b = bits.Sub64(0, q7, b) _, b = bits.Sub64(uint64(1)<<62, q8, b) // decrement the result x0, t := bits.Sub64(r4l, 1, 0) x1, t = bits.Sub64(r4k, 0, t) x2, t = bits.Sub64(r4j, 0, t) x3, t = bits.Sub64(r4i, 0, t) x4, _ = bits.Sub64(r4h, 0, t) // commit the decrement if the subtraction underflowed (reciprocal was too large) if b != 0 { r4h, r4i, r4j, r4k, r4l = x4, x3, x2, x1, x0 } // Shift to correct bit alignment, truncating excess bits p = (p & 63) - 1 x0, c = bits.Add64(r4l, r4l, 0) x1, c = bits.Add64(r4k, r4k, c) x2, c = bits.Add64(r4j, r4j, c) x3, c = bits.Add64(r4i, r4i, c) x4, _ = bits.Add64(r4h, r4h, c) if p < 0 { r4h, r4i, r4j, r4k, r4l = x4, x3, x2, x1, x0 p = 0 // avoid negative shift below } { r := uint(p) // right shift l := uint(64 - r) // left shift x0 = (r4l >> r) | (r4k << l) x1 = (r4k >> r) | (r4j << l) x2 = (r4j >> r) | (r4i << l) x3 = (r4i >> r) | (r4h << l) x4 = (r4h >> r) } if p > 0 { r4h, r4i, r4j, r4k, r4l = x4, x3, x2, x1, x0 } mu[0] = r4l mu[1] = r4k mu[2] = r4j mu[3] = r4i mu[4] = r4h return mu } // reduce4 computes the least non-negative residue of x modulo m // // requires a four-word modulus (m[3] > 1) and its inverse (mu) func reduce4(x [8]uint64, m *Uint, mu [5]uint64) (z Uint) { // NB: Most variable names in the comments match the pseudocode for // Barrett reduction in the Handbook of Applied Cryptography. // q1 = x/2^192 x0 := x[3] x1 := x[4] x2 := x[5] x3 := x[6] x4 := x[7] // q2 = q1 * mu; q3 = q2 / 2^320 var q0, q1, q2, q3, q4, q5, t0, t1, c uint64 q0, _ = bits.Mul64(x3, mu[0]) q1, t0 = bits.Mul64(x4, mu[0]) q0, c = bits.Add64(q0, t0, 0) q1, _ = bits.Add64(q1, 0, c) t1, _ = bits.Mul64(x2, mu[1]) q0, c = bits.Add64(q0, t1, 0) q2, t0 = bits.Mul64(x4, mu[1]) q1, c = bits.Add64(q1, t0, c) q2, _ = bits.Add64(q2, 0, c) t1, t0 = bits.Mul64(x3, mu[1]) q0, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) q2, _ = bits.Add64(q2, 0, c) t1, t0 = bits.Mul64(x2, mu[2]) q0, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) q3, t0 = bits.Mul64(x4, mu[2]) q2, c = bits.Add64(q2, t0, c) q3, _ = bits.Add64(q3, 0, c) t1, _ = bits.Mul64(x1, mu[2]) q0, c = bits.Add64(q0, t1, 0) t1, t0 = bits.Mul64(x3, mu[2]) q1, c = bits.Add64(q1, t0, c) q2, c = bits.Add64(q2, t1, c) q3, _ = bits.Add64(q3, 0, c) t1, _ = bits.Mul64(x0, mu[3]) q0, c = bits.Add64(q0, t1, 0) t1, t0 = bits.Mul64(x2, mu[3]) q1, c = bits.Add64(q1, t0, c) q2, c = bits.Add64(q2, t1, c) q4, t0 = bits.Mul64(x4, mu[3]) q3, c = bits.Add64(q3, t0, c) q4, _ = bits.Add64(q4, 0, c) t1, t0 = bits.Mul64(x1, mu[3]) q0, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) t1, t0 = bits.Mul64(x3, mu[3]) q2, c = bits.Add64(q2, t0, c) q3, c = bits.Add64(q3, t1, c) q4, _ = bits.Add64(q4, 0, c) t1, t0 = bits.Mul64(x0, mu[4]) _, c = bits.Add64(q0, t0, 0) q1, c = bits.Add64(q1, t1, c) t1, t0 = bits.Mul64(x2, mu[4]) q2, c = bits.Add64(q2, t0, c) q3, c = bits.Add64(q3, t1, c) q5, t0 = bits.Mul64(x4, mu[4]) q4, c = bits.Add64(q4, t0, c) q5, _ = bits.Add64(q5, 0, c) t1, t0 = bits.Mul64(x1, mu[4]) q1, c = bits.Add64(q1, t0, 0) q2, c = bits.Add64(q2, t1, c) t1, t0 = bits.Mul64(x3, mu[4]) q3, c = bits.Add64(q3, t0, c) q4, c = bits.Add64(q4, t1, c) q5, _ = bits.Add64(q5, 0, c) // Drop the fractional part of q3 q0 = q1 q1 = q2 q2 = q3 q3 = q4 q4 = q5 // r1 = x mod 2^320 x0 = x[0] x1 = x[1] x2 = x[2] x3 = x[3] x4 = x[4] // r2 = q3 * m mod 2^320 var r0, r1, r2, r3, r4 uint64 r4, r3 = bits.Mul64(q0, m[3]) _, t0 = bits.Mul64(q1, m[3]) r4, _ = bits.Add64(r4, t0, 0) t1, r2 = bits.Mul64(q0, m[2]) r3, c = bits.Add64(r3, t1, 0) _, t0 = bits.Mul64(q2, m[2]) r4, _ = bits.Add64(r4, t0, c) t1, t0 = bits.Mul64(q1, m[2]) r3, c = bits.Add64(r3, t0, 0) r4, _ = bits.Add64(r4, t1, c) t1, r1 = bits.Mul64(q0, m[1]) r2, c = bits.Add64(r2, t1, 0) t1, t0 = bits.Mul64(q2, m[1]) r3, c = bits.Add64(r3, t0, c) r4, _ = bits.Add64(r4, t1, c) t1, t0 = bits.Mul64(q1, m[1]) r2, c = bits.Add64(r2, t0, 0) r3, c = bits.Add64(r3, t1, c) _, t0 = bits.Mul64(q3, m[1]) r4, _ = bits.Add64(r4, t0, c) t1, r0 = bits.Mul64(q0, m[0]) r1, c = bits.Add64(r1, t1, 0) t1, t0 = bits.Mul64(q2, m[0]) r2, c = bits.Add64(r2, t0, c) r3, c = bits.Add64(r3, t1, c) _, t0 = bits.Mul64(q4, m[0]) r4, _ = bits.Add64(r4, t0, c) t1, t0 = bits.Mul64(q1, m[0]) r1, c = bits.Add64(r1, t0, 0) r2, c = bits.Add64(r2, t1, c) t1, t0 = bits.Mul64(q3, m[0]) r3, c = bits.Add64(r3, t0, c) r4, _ = bits.Add64(r4, t1, c) // r = r1 - r2 var b uint64 r0, b = bits.Sub64(x0, r0, 0) r1, b = bits.Sub64(x1, r1, b) r2, b = bits.Sub64(x2, r2, b) r3, b = bits.Sub64(x3, r3, b) r4, b = bits.Sub64(x4, r4, b) // if r<0 then r+=m if b != 0 { r0, c = bits.Add64(r0, m[0], 0) r1, c = bits.Add64(r1, m[1], c) r2, c = bits.Add64(r2, m[2], c) r3, c = bits.Add64(r3, m[3], c) r4, _ = bits.Add64(r4, 0, c) } // while (r>=m) r-=m for { // q = r - m q0, b = bits.Sub64(r0, m[0], 0) q1, b = bits.Sub64(r1, m[1], b) q2, b = bits.Sub64(r2, m[2], b) q3, b = bits.Sub64(r3, m[3], b) q4, b = bits.Sub64(r4, 0, b) // if borrow break if b != 0 { break } // r = q r4, r3, r2, r1, r0 = q4, q3, q2, q1, q0 } z[3], z[2], z[1], z[0] = r3, r2, r1, r0 return z }
- #20uint256.gno
- #21package uint256 import ( "errors" "math/bits" "strconv" ) const ErrBig256Range = "decimal number > 256 bits" // Uint represents a 256-bit unsigned integer. // It is stored as an array of 4 uint64 in little-endian order, // where arr[0] is the least significant and arr[3] is the most significant. type Uint [4]uint64 // NewUint returns a new Uint initialized with the given uint64 value. // // Parameters: // - val: the initial uint64 value // // Returns: // - result: a new Uint initialized to val func NewUint(val uint64) *Uint { return &Uint{val, 0, 0, 0} } // NewUintFromInt64 returns a new Uint initialized with the given int64 value. // Panics if val is negative. // // Parameters: // - val: the initial non-negative int64 value; a negative value panics // // Returns: // - result: a new Uint initialized to val func NewUintFromInt64(val int64) *Uint { if val < 0 { panic("val is negative") } return &Uint{uint64(val), 0, 0, 0} } // Zero returns a new Uint with value 0. // // Returns: // - result: a new zero-valued Uint func Zero() *Uint { return &Uint{0, 0, 0, 0} } // One returns a new Uint with value 1. // // Returns: // - result: a new Uint containing one func One() *Uint { return &Uint{1, 0, 0, 0} } // MaxUint256 returns the maximum 256-bit unsigned integer (2^256-1). // // Returns: // - result: a new Uint containing 2^256-1 func MaxUint256() *Uint { return &Uint{18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615} } // SetAllOne sets z to the maximum 256-bit value (all bits set to 1) and returns z. // // Returns: // - result: z after setting every bit to one func (z *Uint) SetAllOne() *Uint { z[3], z[2], z[1], z[0] = 18446744073709551615, 18446744073709551615, 18446744073709551615, 18446744073709551615 return z } // Set sets z to x and returns z. // // Parameters: // - x: the Uint value copied into z // // Returns: // - result: z after copying x func (z *Uint) Set(x *Uint) *Uint { *z = *x return z } // SetOne sets z to 1 and returns z. // // Returns: // - result: z after setting it to one func (z *Uint) SetOne() *Uint { z[3], z[2], z[1], z[0] = 0, 0, 0, 1 return z } // SetFromDecimal sets z from a decimal string and returns an error if invalid. // Accepts an optional leading "+" sign but rejects underscores and negative values. // Returns ErrBig256Range if the number exceeds 256 bits. // // Parameters: // - s: the decimal text to parse; a leading + is accepted, while negatives and underscores are rejected // // Returns: // - err: nil on success; otherwise the parse or range error func (z *Uint) SetFromDecimal(s string) (err error) { sLen := len(s) // Remove max one leading + if sLen > 0 && s[0] == '+' { s = s[1:] sLen-- } // Remove any number of leading zeroes if sLen > 0 && s[0] == '0' { var i int var c rune for i, c = range s { if c != '0' { break } } s = s[i:] sLen = len(s) } // maxUint256Str is the string representation of the maximum uint256 value. maxUint256Str := "115792089237316195423570985008687907853269984665640564039457584007913129639935" maxLen := len(maxUint256Str) if sLen < maxLen { return z.fromDecimal(s) } if sLen == maxLen { if s > maxUint256Str { return errors.New(ErrBig256Range) } return z.fromDecimal(s) } return errors.New(ErrBig256Range) } // FromDecimal creates a new Uint from a decimal string. // Returns an error if the number exceeds 256 bits or is invalid. // // Parameters: // - decimal: the decimal text representing a non-negative value within 256 bits // // Returns: // - value: a new parsed Uint, or nil on error // - err: nil on success; otherwise an invalid-format or 256-bit-range error func FromDecimal(decimal string) (*Uint, error) { var z Uint if err := z.SetFromDecimal(decimal); err != nil { return nil, err } return &z, nil } // MustFromDecimal creates a new Uint from a decimal string. // Panics if the string is invalid or the number exceeds 256 bits. // // Parameters: // - decimal: the decimal text representing a non-negative value within 256 bits // // Returns: // - result: a new parsed Uint; invalid or out-of-range input panics func MustFromDecimal(decimal string) *Uint { var z Uint if err := z.SetFromDecimal(decimal); err != nil { panic(err) } return &z } // multipliers holds the values that are needed for fromDecimal var multipliers = [5]Uint{ {0, 0, 0, 0}, // 1 (no multiplication needed in the first round) {10000000000000000000, 0, 0, 0}, // 10 ^ 19 {687399551400673280, 5421010862427522170, 0, 0}, // 10 ^ 38 {5332261958806667264, 17004971331911604867, 2938735877055718769, 0}, // 10 ^ 57 {0, 8607968719199866880, 532749306367912313, 1593091911132452277}, // 10 ^ 76 } // fromDecimal parses a decimal string by processing it in 19-character chunks. // Each chunk is multiplied by the appropriate power of 10 and accumulated. func (z *Uint) fromDecimal(bs string) error { // first clear the input z.Clear() // the maximum value of uint64 is 18446744073709551615, which is 20 characters // one less means that a string of 19 9's is always within the uint64 limit var ( num uint64 err error remaining = len(bs) ) if remaining == 0 { return errors.New("EOF") } // We proceed in steps of 19 characters (nibbles), from least significant to most significant. // This means that the first (up to) 19 characters do not need to be multiplied. // In the second iteration, our slice of 19 characters needs to be multiplied // by a factor of 10^19. Et cetera. for i := range multipliers { if remaining <= 0 { return nil // Done } if remaining > 19 { num, err = strconv.ParseUint(bs[remaining-19:remaining], 10, 64) } else { // Final round num, err = strconv.ParseUint(bs, 10, 64) } if err != nil { return err } // add that number to our running total if i == 0 { z.SetUint64(num) } else { base := &Uint{uint64(num), 0, 0, 0} // Check for overflow in multiplication base, overflow := base.MulOverflow(base, &multipliers[i]) if overflow { return errors.New(ErrBig256Range) } // Check for overflow in addition base, overflow = base.AddOverflow(base, z) if overflow { return errors.New(ErrBig256Range) } z.Set(base) } // Chop off another 19 characters if remaining > 19 { bs = bs[0 : remaining-19] } remaining -= 19 } return nil } // Byte returns the value of the byte at position n as a Uint. // Position n is counted from the left (0 = most significant byte). // Returns 0 if n >= 32. // // Parameters: // - n: the zero-based byte position counted from the most-significant byte; positions 32 and above yield zero // // Returns: // - result: z containing the selected byte as a Uint, or zero when n is outside the 32-byte value func (z *Uint) Byte(n *Uint) *Uint { // in z, z[0] is the least significant if number, overflow := n.Uint64WithOverflow(); !overflow { if number < 32 { number := z[4-1-number/8] offset := (n[0] & 0x7) << 3 // 8*(n.d % 8) z[0] = (number & (0xff00000000000000 >> offset)) >> (56 - offset) z[3], z[2], z[1] = 0, 0, 0 return z } } return z.Clear() } // BitLen returns the number of bits required to represent z. // BitLen(0) returns 0. // // Returns: // - bits: the number of significant bits in z, with zero represented by 0 func (z *Uint) BitLen() int { switch { case z[3] != 0: return 192 + bits.Len64(z[3]) case z[2] != 0: return 128 + bits.Len64(z[2]) case z[1] != 0: return 64 + bits.Len64(z[1]) default: return bits.Len64(z[0]) } } // ByteLen returns the number of bytes required to represent z. // ByteLen(0) returns 0. // // Returns: // - bytes: the number of bytes needed to represent z, with zero represented by 0 func (z *Uint) ByteLen() int { return (z.BitLen() + 7) / 8 } // Clear sets z to 0 and returns z. // // Returns: // - result: z after setting it to zero func (z *Uint) Clear() *Uint { z[3], z[2], z[1], z[0] = 0, 0, 0, 0 return z } // Clone returns a new Uint with the same value as z. // // Returns: // - result: a newly allocated Uint with the same value as z func (z *Uint) Clone() *Uint { var x Uint x[0] = z[0] x[1] = z[1] x[2] = z[2] x[3] = z[3] return &x }
- #22/gno.MemPackageType
- #23 MPUserAll
Result log
msg:0,success:true,log:,events:[]