uint256

package module
v0.0.0-...-db7e0ea Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2023 License: ISC Imports: 4 Imported by: 0

README

uint256

Build Status ISC License Doc

Fixed Precision Unsigned 256-bit Integer Arithmetic

This package implements highly optimized allocation free fixed precision unsigned 256-bit integer arithmetic.

The following is a brief overview of the main features and benefits:

  • Strong focus on performance and correctness
    • Every operation is faster than the stdlib big.Int equivalent and most operations, including the primary math operations, are significantly faster (see performance comparison benchmarks)
  • Allocation free
    • All non-formatting operations with the specialized type are allocation free
  • Supports boolean comparison, bitwise logic, and bitwise shift operations
  • All operations are performed modulo 2^256
  • Ergonomic API with unary-style arguments as well as some binary variants
    • eg: n.SetUint64(1).Lsh(64).SubUint64(1) is equivalent to n = 1<<64 - 1
    • eg: n.Div2(n1, n2) is equivalent to n = n1/n2
  • Conversion-free support for interoperation with native uint64 integers
  • Direct conversion to and from little and big endian byte arrays
  • Full support for formatted output and common base conversions
    • Producing formatted output uses fewer allocations than big.Int
  • 100% test coverage
  • Comprehensive benchmarks

The primary big.Int operations that are NOT currently provided:

  • Modular arithmetic with moduli other than 2^256
  • Signed arithmetic
    • A caller could fairly easily implement it with 2's complement if desired since Negate is provided
  • Remainders from division

These operations may be implemented in the future if the need arises.

Note About Standard Library math/big.Int Conversions

This package provides convenience methods for converting to and from standard library big.Ints, however, callers should make an active effort to avoid that unless it is absolutely necessary as conversion to big.Int requires an unavoidable allocation in most circumstances and big.Int is also slower for every operation, often to a significant degree. Further, big.Ints often cause further allocations while performing arithmetic, notably multiplication and division.

Regarding the aforementioned allocations, standard library big.Ints internally require heap allocations to operate, so conversion to a new big.Int necessarily causes an allocation. This means the ToBig method will always incur at least one allocation.

One feature of big.Ints is that they attempt to reuse their internal buffer when possible, so the number of allocations due to conversion can sometimes be reduced if reusing the same variable is an option. This package provides a PutBig method which allows callers to reuse an existing big.Int for this purpose.

Do note however that even when reusing a big.Int, it will naturally still require an allocation for the internal buffer unless it has already previously allocated one large enough to be reused.

Categorized Uint256 Summary

This section summarizes the majority of the available operations provided by category. See the full documentation for additional details about individual methods and additional available methods.

Arithmetic Methods
Operation Native Equiv Methods
Add Assign n += x Add, AddUint64
Add n = x + y Add2
Subtract Assign n -= x Sub, SubUint64
Subtract n = x - y Sub2
Multiply Assign n *= x Mul, MulUint64
Multiply n = x * y Mul2
Divide Assign n /= x Div
Divide n = x / y Div2
Square Assign n *= n Square
Square n = x * x SquareVal
Negate Assign n = -n Negate
Negate n = -x NegateVal
Comparison Methods
Operation Native Equiv Methods
Equality x == y Eq, EqUint64
Less Than x < y Lt, LtUint64
Less Or Equal x <= y LtEq, LtEqUint64
Greater Than x > y Gt, GtUint64
Greater Or Equal x >= y GtEq, GtEqUint64
Comparison n/a Cmp, CmpUint64
Bitwise Methods
Operation Native Equiv Method
And Assign n &= x And
Or Assign n |= x Or
Xor Assign n ^= x Xor
Not Assign n = ^x Not
Left Shift Assign n <<= x Lsh
Left Shift n = x << y LshVal
Right Shift Assign n >>= x Rsh
Right Shift n = x >> y RshVal
Bit Length n/a BitLen
Conversion Methods
Operation Methods
From Big Endian SetBytes, SetByteSlice
To Big Endian Bytes, PutBytes, PutBytesUnchecked
From Little Endian SetBytesLE, SetByteSliceLE
To Little Endian BytesLE, PutBytesLE, PutBytesUncheckedLE
From math/big.Int SetBig
To math/big.Int ToBig, PutBig
Misc Convenience Methods
Operation Method
Can represent with uint32? IsUint32
Value modulo 2^32 Uint32
Can represent with uint64? IsUint64
Value modulo 2^64 Uint64
Set to 0 Zero
Is equal to zero? IsZero
Is the value odd? IsOdd
Output Formatting Methods
Operation Method
Binary/Octal/Decimal/Hex Text
Standard Formatted output (fmt.Formatter) Format
Standard Unformatted output (fmt.Stringer) String

Uint256 Performance Comparison

The following benchmark results demonstrate the performance of most operations as compared to standard library big.Ints. The benchmarks are from a Ryzen 7 1700 processor and are the result of feeding benchstat 10 iterations of each.

Arithmetic Methods
Name big.Int Time/Op Uint256 Time/Op Delta vs big.Int
Add 158ns ± 2% 2ns ± 1% -98.67%
AddUint64 44.4ns ± 3% 3.4ns ± 2% -92.27%
Sub 53.9ns ± 1% 2.1ns ± 1% -96.12%
SubUint64 44.8ns ± 1% 3.4ns ± 2% -92.37%
Mul 419ns ± 1% 10ns ± 2% -97.64%
MulUint64 263ns ± 1% 4ns ± 1% -98.30%
Square 418ns ± 0% 7ns ± 2% -98.39%
Div/num_lt_den 75.4ns ± 1% 3.4ns ± 1% -95.51%
Div/num_eq_den 253ns ± 2% 4ns ± 3% -98.56%
Div/1_by_1_near 53.8ns ± 2% 4.5ns ± 2% -91.63%
Div/1_by_1_far 31.4ns ± 2% 14.6ns ± 2% -53.64%
Div/2_by_1_near 36.9ns ± 1% 10.1ns ± 2% -72.63%
Div/2_by_1_far 49.1ns ± 1% 28.8ns ± 1% -41.29%
Div/3_by_1_near 43.2ns ± 1% 13.7ns ± 3% -68.24%
Div/3_by_1_far 57.0ns ± 1% 43.6ns ± 1% -23.59%
Div/4_by_1_near 49.7ns ± 4% 18.0ns ± 1% -63.87%
Div/4_by_1_far 65.2ns ± 4% 57.8ns ± 2% -11.41%
Div/2_by_2_near 237ns ± 1% 22ns ± 3% -90.81%
Div/2_by_2_far 237ns ± 1% 30ns ± 3% -87.17%
Div/3_by_2_near 258ns ± 1% 29ns ± 1% -88.60%
Div/3_by_2_far 257ns ± 1% 50ns ± 2% -80.42%
Div/4_by_2_near 312ns ± 2% 40ns ± 3% -87.27%
Div/4_by_2_far 310ns ± 1% 71ns ± 3% -77.19%
Div/3_by_3_near 239ns ± 2% 21ns ± 2% -91.39%
Div/3_by_3_far 242ns ± 4% 33ns ± 3% -86.33%
Div/4_by_3_near 279ns ± 6% 31ns ± 1% -89.01%
Div/4_by_3_far 271ns ± 1% 46ns ± 3% -82.99%
Div/4_by_4_near 252ns ± 3% 20ns ± 3% -91.99%
Div/4_by_4_far 249ns ± 2% 36ns ± 2% -85.65%
DivRandom 202ns ± 1% 23ns ± 1% -88.43%
DivUint64 129ns ± 1% 47ns ± 0% -63.34%
Negate 47.3ns ± 2% 1.5ns ± 2% -96.91%
Comparison Methods
Name big.Int Time/Op Uint256 Time/Op Delta vs big.Int
Eq 12.7ns ± 1% 2.1ns ± 1% -83.72%
Lt 12.6ns ± 1% 3.0ns ± 1% -75.96%
Gt 12.6ns ± 1% 3.0ns ± 1% -75.91%
Cmp 12.6ns ± 1% 7.7ns ± 1% -39.01%
CmpUint64 5.93ns ± 2% 3.70ns ± 1% -37.60%
Bitwise Methods
Name big.Int Time/Op Uint256 Time/Op Delta vs big.Int
Lsh/bits_0 7.15ns ± 3% 2.58ns ± 1% -63.94%
Lsh/bits_1 14.8ns ± 1% 4.2ns ± 1% -71.40%
Lsh/bits_64 16.7ns ± 1% 2.7ns ± 1% -84.00%
Lsh/bits_128 16.9ns ± 2% 2.7ns ± 0% -84.21%
Lsh/bits_192 16.6ns ± 1% 2.6ns ± 1% -84.19%
Lsh/bits_255 16.3ns ± 2% 2.8ns ± 2% -83.11%
Lsh/bits_256 16.9ns ± 2% 2.6ns ± 2% -84.77%
Rsh/bits_0 8.76ns ± 2% 2.57ns ± 1% -70.63%
Rsh/bits_1 14.4ns ± 2% 4.3ns ± 2% -70.28%
Rsh/bits_64 12.8ns ± 1% 2.9ns ± 2% -77.31%
Rsh/bits_128 11.8ns ± 0% 2.9ns ± 2% -75.51%
Rsh/bits_192 10.5ns ± 2% 2.6ns ± 1% -75.17%
Rsh/bits_255 10.5ns ± 3% 2.8ns ± 2% -73.89%
Rsh/bits_256 5.50ns ± 1% 2.58ns ± 2% -53.15%
Not 25.4ns ± 2% 3.3ns ± 2% -86.79%
Or 17.9ns ± 5% 3.4ns ± 6% -80.94%
And 16.7ns ± 2% 3.4ns ± 0% -79.93%
Xor 17.9ns ± 1% 3.4ns ± 2% -80.91%
BitLen/bits_64 2.24ns ± 1% 1.94ns ± 3% -13.04%
BitLen/bits_128 2.25ns ± 2% 1.96ns ± 2% -13.17%
BitLen/bits_192 2.25ns ± 1% 1.60ns ± 1% -28.65%
BitLen/bits_255 2.26ns ± 2% 1.61ns ± 1% -29.04%
Conversion Methods
Name big.Int Time/Op Uint256 Time/Op Delta vs big.Int
SetBytes 9.09ns ±13% 3.05ns ± 1% -66.43%
SetBytesLE 59.9ns ± 4% 3.1ns ± 2% -94.76%
Bytes 61.3ns ± 1% 13.8ns ± 3% -77.49%
BytesLE 83.5ns ± 2% 13.9ns ± 2% -83.32%
Misc Convenience Methods
Name big.Int Time/Op Uint256 Time/Op Delta vs big.Int
Zero 2.99ns ± 2% 1.29ns ± 1% -56.82%
IsZero 1.78ns ± 0% 1.63ns ± 2% -8.23%
IsOdd 3.62ns ± 4% 1.64ns ± 1% -54.65%
Output Formatting Methods
Name big.Int Time/Op Uint256 Time/Op Delta vs big.Int
Text/base_2 579ns ± 3% 496ns ± 2% -14.37%
Text/base_8 266ns ± 1% 227ns ± 1% -14.58%
Text/base_10 536ns ± 1% 458ns ± 2% -14.58%
Text/base_16 205ns ± 2% 180ns ± 4% -11.90%
Format/base_2 987ns ±15% 852ns ± 2% -13.64%
Format/base_8 620ns ± 6% 544ns ± 3% -12.31%
Format/base_10 888ns ± 1% 726ns ± 1% -18.25%
Format/base_16 565ns ± 1% 449ns ± 1% -20.41%

Installation and Updating

This package is part of the github.com/EXCCoin/exccd/math/uint256 module. Use the standard go tooling for working with modules to incorporate it.

Examples

  • Basic Usage
    Demonstrates calculating the result of a dividing a max unsigned 256-bit integer by a max unsigned 128-bit integer and outputting that result in hex with leading zeros.

License

Package uint256 is licensed under the copyfree ISC License.

Documentation

Overview

Package uint256 implements highly optimized fixed precision unsigned 256-bit integer arithmetic.

Example (BasicUsage)

This example demonstrates calculating the result of dividing a max unsigned 256-bit integer by a max unsigned 128-bit integer and outputting that result in hex with leading zeros.

package main

import (
	"fmt"

	"github.com/EXCCoin/exccd/math/uint256"
)

func main() {
	// Calculate maxUint256 / maxUint128 and output it in hex with leading zeros.
	maxUint128 := new(uint256.Uint256).SetUint64(1).Lsh(128).SubUint64(1)
	result := new(uint256.Uint256).Not().Div(maxUint128)
	fmt.Printf("result: %064x\n", result)

}
Output:

result: 0000000000000000000000000000000100000000000000000000000000000001

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type OutputBase

type OutputBase int

OutputBase represents a specific base to use for the string representation of a number.

const (
	// OutputBaseBinary indicates a string representation of a uint256 in
	// base 2.
	OutputBaseBinary OutputBase = 2

	// OutputBaseOctal indicates a string representation of a uint256 in base 8.
	OutputBaseOctal OutputBase = 8

	// OutputBaseDecimal indicates a string representation of a uint256 in base
	// 10.
	OutputBaseDecimal OutputBase = 10

	// OutputBaseHex indicates a string representation of a uint256 in base 16.
	OutputBaseHex OutputBase = 16
)

These constants define the supported output bases.

type Uint256

type Uint256 struct {
	// contains filtered or unexported fields
}

Uint256 implements high-performance, zero-allocation, unsigned 256-bit fixed-precision arithmetic. All operations are performed modulo 2^256, so callers may rely on "wrap around" semantics.

It implements the primary arithmetic operations (addition, subtraction, multiplication, squaring, division, negation), bitwise operations (lsh, rsh, not, or, and, xor), comparison operations (equals, less, greater, cmp), interpreting and producing big and little endian bytes, and other convenience methods such as determining the minimum number of bits required to represent the current value, whether or not the value can be represented as a uint64 without loss of precision, and text formatting with base conversion.

Should it be absolutely necessary, conversion to the standard library math/big.Int can be accomplished by using the ToBig or PutBig methods. However, that should typically be avoided when possible as conversion to big.Ints requires allocations and is slower for every operation, often to a significant degree.

func (*Uint256) Add

func (n *Uint256) Add(n2 *Uint256) *Uint256

Add adds the passed uint256 to the existing one modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Add(n2).AddUin64(1) so that n = n + n2 + 1.

func (*Uint256) Add2

func (n *Uint256) Add2(n1, n2 *Uint256) *Uint256

Add2 adds the passed two uint256s together modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Add2(n1, n2).AddUint64(1) so that n = n1 + n2 + 1.

func (*Uint256) AddUint64

func (n *Uint256) AddUint64(n2 uint64) *Uint256

AddUint64 adds the passed uint64 to the existing uint256 modulo 2^256 and stores the result in n.

The scalar is returned to support chaining. This enables syntax like: n.AddUint64(2).MulUint64(2) so that n = (n + 2) * 2.

func (*Uint256) And

func (n *Uint256) And(n2 *Uint256) *Uint256

And computes the bitwise and of the uint256 and the passed uint256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.And(n2).AddUint64(1) so that n = (n & n2) + 1.

func (*Uint256) BitLen

func (n *Uint256) BitLen() uint16

BitLen returns the minimum number of bits required to represent the uint256. The result is 0 when the value is 0.

func (*Uint256) Bytes

func (n *Uint256) Bytes() [32]byte

Bytes unpacks the uint256 to a 32-byte big-endian array.

See PutBytes and PutBytesUnchecked for variants that allow an array or slice to be passed which can be useful to cut down on the number of allocations by allowing the caller to reuse a buffer or write directly into part of a larger buffer.

func (*Uint256) BytesLE

func (n *Uint256) BytesLE() [32]byte

BytesLE unpacks the uint256 to a 32-byte little-endian array.

See PutBytesLE and PutBytesUncheckedLE for variants that allow an array or slice to be passed which can be useful to cut down on the number of allocations by allowing the caller to reuse a buffer or write directly into part of a larger buffer.

func (*Uint256) Cmp

func (n *Uint256) Cmp(n2 *Uint256) int

Cmp compares the two uint256s and returns -1, 0, or 1 depending on whether the uint256 is less than, equal to, or greater than the given one.

That is, it returns:

-1 when n <  n2
 0 when n == n2
+1 when n >  n2

func (*Uint256) CmpUint64

func (n *Uint256) CmpUint64(n2 uint64) int

CmpUint64 compares the uint256 with the given uint64 and returns -1, 0, or 1 depending on whether the uint256 is less than, equal to, or greater than the uint64.

That is, it returns:

-1 when n <  n2
 0 when n == n2
+1 when n >  n2

func (*Uint256) Div

func (n *Uint256) Div(divisor *Uint256) *Uint256

Div divides the existing value in n by the passed uint256 divisor modulo 2^256 and stores the result in n. It will panic if the divisor is 0.

This implements truncated division like native Go integers.

The uint256 is returned to support chaining. This enables syntax like: n.Div(n2).AddUint64(1) so that n = (n / n2) + 1.

func (*Uint256) Div2

func (n *Uint256) Div2(dividend, divisor *Uint256) *Uint256

Div2 divides the passed uint256 dividend by the passed uint256 divisor modulo 2^256 and stores the result in n. It will panic if the divisor is 0.

This implements truncated division like native Go integers and it is safe to alias the arguments.

The uint256 is returned to support chaining. This enables syntax like: n.Div2(n1, n2).AddUint64(1) so that n = (n1 / n2) + 1.

func (*Uint256) DivUint64

func (n *Uint256) DivUint64(divisor uint64) *Uint256

DivUint64 divides the existing value in n by the passed uint64 divisor modulo 2^256 and stores the result in n. It will panic if the divisor is 0.

This implements truncated division like native Go integers.

The uint256 is returned to support chaining. This enables syntax like: n.DivUint64(2).AddUint64(1) so that n = (n / 2) + 1.

func (*Uint256) Eq

func (n *Uint256) Eq(n2 *Uint256) bool

Eq returns whether or not the two uint256s represent the same value.

func (*Uint256) EqUint64

func (n *Uint256) EqUint64(n2 uint64) bool

EqUint64 returns whether or not the uint256 represents the same value as the given uint64.

func (Uint256) Format

func (n Uint256) Format(s fmt.State, ch rune)

Format implements fmt.Formatter. It accepts the following format verbs:

'v' default format which is decimal
's' default string format which is decimal
'b' binary
'o' octal with 0 prefix when accompanied by #
'O' octal with 0o prefix
'd' decimal
'x' lowercase hexadecimal
'X' uppercase hexadecimal

It also supports the full suite of the fmt package format flags for integral types:

'#' output base prefix:
    binary: 0b (%#b)
    octal: 0 (%#o)
    hex: 0x (%#x) or 0X (%#X)
'-' pad with spaces on the right (left-justify field)
'0' pad with leading zeros rather than spaces

Finally, it supports specification of the minimum number of digits (precision) and output field width. Examples:

%#.64x  default width, precision 64, lowercase hex with 0x prefix
%256b   width 256, default precision, binary with leading zeros
%12.3O  width 12, precision 3, octal with 0o prefix

func (*Uint256) Gt

func (n *Uint256) Gt(n2 *Uint256) bool

Gt returns whether or not the uint256 is greater than the given one. That is, it returns true when n > n2.

func (*Uint256) GtEq

func (n *Uint256) GtEq(n2 *Uint256) bool

GtEq returns whether or not the uint256 is greater than or equal to the given one. That is, it returns true when n >= n2.

func (*Uint256) GtEqUint64

func (n *Uint256) GtEqUint64(n2 uint64) bool

GtEqUint64 returns whether or not the uint256 is greater than or equal to the given uint64. That is, it returns true when n >= n2.

func (*Uint256) GtUint64

func (n *Uint256) GtUint64(n2 uint64) bool

GtUint64 returns whether or not the uint256 is greater than the given uint64. That is, it returns true when n > n2.

func (*Uint256) IsOdd

func (n *Uint256) IsOdd() bool

IsOdd returns whether or not the uint256 is odd.

func (*Uint256) IsUint32

func (n *Uint256) IsUint32() bool

IsUint32 returns whether or not the uint256 can be converted to a uint32 without any loss of precision. In other words, 0 <= n < 2^32.

func (*Uint256) IsUint64

func (n *Uint256) IsUint64() bool

IsUint64 returns whether or not the uint256 can be converted to a uint64 without any loss of precision. In other words, 0 <= n < 2^64.

func (*Uint256) IsZero

func (n *Uint256) IsZero() bool

IsZero returns whether or not the uint256 is equal to zero.

func (*Uint256) Lsh

func (n *Uint256) Lsh(bits uint32) *Uint256

Lsh shifts the uint256 to the left the given number of bits and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Lsh(2).AddUint64(1) so that n = (n << 2) + 1.

func (*Uint256) LshVal

func (n *Uint256) LshVal(n2 *Uint256, bits uint32) *Uint256

LshVal shifts the passed uint256 to the left the given number of bits and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.LshVal(n2, 2).AddUint64(1) so that n = (n2 << 2) + 1.

func (*Uint256) Lt

func (n *Uint256) Lt(n2 *Uint256) bool

Lt returns whether or not the uint256 is less than the given one. That is, it returns true when n < n2.

func (*Uint256) LtEq

func (n *Uint256) LtEq(n2 *Uint256) bool

LtEq returns whether or not the uint256 is less than or equal to the given one. That is, it returns true when n <= n2.

func (*Uint256) LtEqUint64

func (n *Uint256) LtEqUint64(n2 uint64) bool

LtEqUint64 returns whether or not the uint256 is less than or equal to the given uint64. That is, it returns true when n <= n2.

func (*Uint256) LtUint64

func (n *Uint256) LtUint64(n2 uint64) bool

LtUint64 returns whether or not the uint256 is less than the given uint64. That is, it returns true when n < n2.

func (*Uint256) Mul

func (n *Uint256) Mul(n2 *Uint256) *Uint256

Mul multiplies the passed uint256 by the existing value in n modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Mul(n2).AddUint64(1) so that n = (n * n2) + 1.

func (*Uint256) Mul2

func (n *Uint256) Mul2(n1, n2 *Uint256) *Uint256

Mul2 multiplies the passed uint256s together modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Mul2(n1, n2).AddUint64(1) so that n = (n1 * n2) + 1.

func (*Uint256) MulUint64

func (n *Uint256) MulUint64(n2 uint64) *Uint256

MulUint64 multiplies the uint256 by the passed uint64 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.MulUint64(2).Add(n2) so that n = 2 * n + n2.

func (*Uint256) Negate

func (n *Uint256) Negate() *Uint256

Negate negates the uint256 modulo 2^256. In other words, n will be set to its two's complement.

The uint256 is returned to support chaining. This enables syntax like: n.Negate().AddUint64(1) so that n = -n + 1.

func (*Uint256) NegateVal

func (n *Uint256) NegateVal(n2 *Uint256) *Uint256

NegateVal negates the passed uint256 modulo 2^256 and stores the result in n. In other words, n will be set to the two's complement of the passed uint256.

The uint256 is returned to support chaining. This enables syntax like: n.NegateVal(n2).AddUint64(1) so that n = -n2 + 1.

func (*Uint256) Not

func (n *Uint256) Not() *Uint256

Not computes the bitwise not of the uint256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Not().AddUint64(1) so that n = ^n + 1.

func (*Uint256) Or

func (n *Uint256) Or(n2 *Uint256) *Uint256

Or computes the bitwise or of the uint256 and the passed uint256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Or(n2).AddUint64(1) so that n = (n | n2) + 1.

func (*Uint256) PutBig

func (n *Uint256) PutBig(out *big.Int)

PutBig sets the passed existing stdlib big integer to the value the uint256 currently represents.

This can sometimes be useful to reduce the number of allocations due to conversion if reusing the same variable is an option. The reason is that stdlib big integers internally allocate space on the heap to perform their operations and attempt to reuse that internal buffer when possible.

Do note however that even when reusing a big integer, it will naturally still require an allocation for the internal buffer unless it has already allocated one large enough to be reused. Moreover, they often require further allocations while performing arithmetic, notably multiplication and division.

Applications that are performance sensitive should consider avoiding conversion to big integers altogether when possible.

See ToBig for a variant that returns the uint256 as a new stdlib big integer instead which can sometimes be more ergonomic in contexts where additional allocations are not a concern.

func (*Uint256) PutBytes

func (n *Uint256) PutBytes(b *[32]byte)

PutBytes unpacks the uint256 to a 32-byte big-endian value using the passed byte array.

There is a similar function, PutBytesUnchecked, which unpacks the uint256 into a slice that must have at least 32 bytes available. This version is provided since it can be useful to write directly into an array that is type checked.

Alternatively, there is also Bytes, which unpacks the uint256 into a new array and returns that which can sometimes be more ergonomic in applications that aren't concerned about an additional copy.

func (*Uint256) PutBytesLE

func (n *Uint256) PutBytesLE(b *[32]byte)

PutBytesLE unpacks the uint256 to a 32-byte little-endian value using the passed byte array.

There is a similar function, PutBytesUncheckedLE, which unpacks the uint256 into a slice that must have at least 32 bytes available. This version is provided since it can be useful to write directly into an array that is type checked.

Alternatively, there is also BytesLE, which unpacks the uint256 into a new array and returns that which can sometimes be more ergonomic in applications that aren't concerned about an additional copy.

func (*Uint256) PutBytesUnchecked

func (n *Uint256) PutBytesUnchecked(b []byte)

PutBytesUnchecked unpacks the uint256 to a 32-byte big-endian value directly into the passed byte slice. The target slice must must have at least 32 bytes available or it will panic.

There is a similar function, PutBytes, which unpacks the uint256 into a 32-byte array directly. This version is provided since it can be useful to write directly into part of a larger buffer without needing a separate allocation.

func (*Uint256) PutBytesUncheckedLE

func (n *Uint256) PutBytesUncheckedLE(b []byte)

PutBytesUncheckedLE unpacks the uint256 to a 32-byte little-endian value directly into the passed byte slice. The target slice must must have at least 32 bytes available or it will panic.

There is a similar function, PutBytesLE, which unpacks the uint256 into a 32-byte array directly. This version is provided since it can be useful to write directly into part of a larger buffer without needing a separate allocation.

func (*Uint256) Rsh

func (n *Uint256) Rsh(bits uint32) *Uint256

Rsh shifts the uint256 to the right the given number of bits and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Rsh(2).AddUint64(1) so that n = (n >> 2) + 1.

func (*Uint256) RshVal

func (n *Uint256) RshVal(n2 *Uint256, bits uint32) *Uint256

RshVal shifts the passed uint256 to the right the given number of bits and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.RshVal(n2, 2).AddUint64(1) so that n = (n2 >> 2) + 1.

func (*Uint256) Set

func (n *Uint256) Set(n2 *Uint256) *Uint256

Set sets the uint256 equal to the same value as the passed one.

The uint256 is returned to support chaining. This enables syntax like: n := new(Uint256).Set(n2).AddUint64(1) so that n = n2 + 1 where n2 is not modified.

func (*Uint256) SetBig

func (n *Uint256) SetBig(n2 *big.Int) *Uint256

SetBig sets the uint256 to the passed standard library big integer modulo 2^256.

The resulting uint256 will be set to the 2's complement of the provided value when it is negative.

The uint256 is returned to support chaining. This enables syntax like: n := new(Uint256).SetBig(n2).AddUint64(1) so that n = n2 + 1 where n2 is not modified.

PERFORMANCE NOTE: When the caller expects values to potentially be larger than a max uint256, it is _highly_ recommended to reduce the value mod 2^256 prior to calling this method for better performance.

The reason is that this method requires an allocation and copy when the provided big integer is larger than a max uint256 in order to reduce it without modifying the provided arg. The caller can avoid this allocation by performing the mod 2^256 prior to calling this method with the value.

More concretely, it is around 3 to 4 times faster to perform the reduction caller side as well as avoiding the allocation.

func (*Uint256) SetByteSlice

func (n *Uint256) SetByteSlice(b []byte) *Uint256

SetByteSlice interprets the provided slice as a 256-bit big-endian unsigned integer (meaning it is truncated to the final 32 bytes so that it is modulo 2^256), and sets the uint256 to the result.

The uint256 is returned to support chaining. This enables syntax like: n := new(Uint256).SetByteSlice(n2Slice).AddUint64(1) so that n = n2 + 1.

func (*Uint256) SetByteSliceLE

func (n *Uint256) SetByteSliceLE(b []byte) *Uint256

SetByteSliceLE interprets the provided slice as a 256-bit little-endian unsigned integer (meaning it is truncated to the first 32 bytes so that it is modulo 2^256), and sets the uint256 to the result.

The uint256 is returned to support chaining. This enables syntax like: n := new(Uint256).SetByteSliceLE(n2Slice).AddUint64(1) so that n = n2 + 1.

func (*Uint256) SetBytes

func (n *Uint256) SetBytes(b *[32]byte) *Uint256

SetBytes interprets the provided array as a 256-bit big-endian unsigned integer and sets the uint256 to the result.

The uint256 is returned to support chaining. This enables syntax like: n := new(Uint256).SetBytes(n2Bytes).AddUint64(1) so that n = n2 + 1.

func (*Uint256) SetBytesLE

func (n *Uint256) SetBytesLE(b *[32]byte) *Uint256

SetBytesLE interprets the provided array as a 256-bit little-endian unsigned integer and sets the uint256 to the result.

func (*Uint256) SetUint64

func (n *Uint256) SetUint64(n2 uint64) *Uint256

SetUint64 sets the uint256 to the passed unsigned 64-bit integer. This is a convenience function since it is fairly common to perform arithmetic with small native integers.

The uint256 is returned to support chaining. This enables syntax like: n := new(Uint256).SetUint64(2).Mul(n2) so that n = 2 * n2.

func (*Uint256) Square

func (n *Uint256) Square() *Uint256

Square squares the uint256 modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Square().Mul(n2) so that n = n^2 * n2.

func (*Uint256) SquareVal

func (n *Uint256) SquareVal(n2 *Uint256) *Uint256

SquareVal squares the passed uint256 modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.SquareVal(n2).Mul(n2) so that n = n2^2 * n2 = n2^3.

func (Uint256) String

func (n Uint256) String() string

String returns the scalar as a human-readable decimal string.

func (*Uint256) Sub

func (n *Uint256) Sub(n2 *Uint256) *Uint256

Sub subtracts the given uint256 from the existing one modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Sub(n2).AddUint64(1) so that n = n - n2 + 1.

func (*Uint256) Sub2

func (n *Uint256) Sub2(n1, n2 *Uint256) *Uint256

Sub2 subtracts the second given uint256 from the first modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Sub2(n1, n2).AddUint64(1) so that n = n1 - n2 + 1.

func (*Uint256) SubUint64

func (n *Uint256) SubUint64(n2 uint64) *Uint256

SubUint64 subtracts the given uint64 from the uint256 modulo 2^256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.SubUint64(1).MulUint64(3) so that n = (n - 1) * 3.

func (*Uint256) Text

func (n *Uint256) Text(base OutputBase) string

Text returns the string representation of the uint256 in the given base which must be on of the supported bases as defined by the OutputBase type.

It will return "<nil>" when the uint256 pointer is nil and a message that indicates the base is not supported along with the value in base 10 in the case the caller goes out of its way to call it with an invalid base.

func (*Uint256) ToBig

func (n *Uint256) ToBig() *big.Int

ToBig returns the uint256 as a stdlib big integer.

Note that this is nearly guaranteed to cause two allocations. Applications that are performance sensitive should consider using PutBig instead or avoid conversion to big integers altogether when possible.

See PutBig for a variant that allows an existing big integer to be reused which can be useful to cut down on the number of allocations by allowing the caller to reuse a big integer that already has an internal buffer allocated.

func (*Uint256) Uint32

func (n *Uint256) Uint32() uint32

Uint32 returns the uint32 representation of the value. In other words, it returns the low-order 32 bits of the value as a uint32 which is equivalent to the value modulo 2^32. The caller can determine if this method can be used without truncation with the IsUint32 method.

func (*Uint256) Uint64

func (n *Uint256) Uint64() uint64

Uint64 returns the uint64 representation of the value. In other words, it returns the low-order 64 bits of the value as a uint64 which is equivalent to the value modulo 2^64. The caller can determine if this method can be used without truncation with the IsUint64 method.

func (*Uint256) Xor

func (n *Uint256) Xor(n2 *Uint256) *Uint256

Xor computes the bitwise exclusive or of the uint256 and the passed uint256 and stores the result in n.

The uint256 is returned to support chaining. This enables syntax like: n.Xor(n2).AddUint64(1) so that n = (n ^ n2) + 1.

func (*Uint256) Zero

func (n *Uint256) Zero()

Zero sets the uint256 to zero. A newly created uint256 is already set to zero. This function can be useful to clear an existing uint256 for reuse.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL