From c0854f6f17a8066803e44e1db833095d7ea58df6 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Sat, 6 Nov 2021 16:07:41 -0500 Subject: [PATCH] uint256: Add bit length support. This adds support for determining the minimum number of bits required to represent the current value of a uint256 along with associated tests to ensure proper functionality. This is part of a series of commits to fully implement the uint256 package. --- .../staging/primitives/uint256/uint256.go | 21 ++++- .../primitives/uint256/uint256_test.go | 77 +++++++++++++++++++ 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/internal/staging/primitives/uint256/uint256.go b/internal/staging/primitives/uint256/uint256.go index b397774d..7ae21811 100644 --- a/internal/staging/primitives/uint256/uint256.go +++ b/internal/staging/primitives/uint256/uint256.go @@ -26,11 +26,11 @@ var ( // 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 whether or not the value can be +// and other convenience methods such as determining the minimum number of bits +// required to represent the current value and whether or not the value can be // represented as a uint64 without loss of precision. // -// Future commits will implement other convenience methods such as determining -// the minimum number of bits required to represent the current value and text +// Future commits will implement other convenience methods such as text // formatting with base conversion. type Uint256 struct { // The uint256 is represented as 4 unsigned 64-bit integers in base 2^64. @@ -1326,3 +1326,18 @@ func (n *Uint256) Xor(n2 *Uint256) *Uint256 { n.n[3] ^= n2.n[3] return n } + +// BitLen returns the minimum number of bits required to represent the uint256. +// The result is 0 when the value is 0. +func (n *Uint256) BitLen() uint16 { + if w := n.n[3]; w > 0 { + return uint16(bits.Len64(w)) + 192 + } + if w := n.n[2]; w > 0 { + return uint16(bits.Len64(w)) + 128 + } + if w := n.n[1]; w > 0 { + return uint16(bits.Len64(w)) + 64 + } + return uint16(bits.Len64(n.n[0])) +} diff --git a/internal/staging/primitives/uint256/uint256_test.go b/internal/staging/primitives/uint256/uint256_test.go index f1f194b4..d12b08c0 100644 --- a/internal/staging/primitives/uint256/uint256_test.go +++ b/internal/staging/primitives/uint256/uint256_test.go @@ -3320,3 +3320,80 @@ func TestUint256XorRandom(t *testing.T) { } } } + +// TestUint256BitLen ensures determining the minimum number of bits required to +// represent a uint256 works as expected. +func TestUint256BitLen(t *testing.T) { + t.Parallel() + + tests := []struct { + name string // test description + n string // hex encoded value + want uint16 // expected result + }{{ + name: "zero", + n: "0", + want: 0, + }, { + name: "one", + n: "1", + want: 1, + }, { + name: "two", + n: "2", + want: 2, + }, { + name: "2^32 - 1", + n: "ffffffff", + want: 32, + }, { + name: "2^32", + n: "100000000", + want: 33, + }, { + name: "2^64 - 2", + n: "fffffffffffffffe", + want: 64, + }, { + name: "2^64 - 1", + n: "ffffffffffffffff", + want: 64, + }, { + name: "2^64", + n: "10000000000000000", + want: 65, + }, { + name: "2^128 - 1", + n: "ffffffffffffffffffffffffffffffff", + want: 128, + }, { + name: "2^128", + n: "100000000000000000000000000000000", + want: 129, + }, { + name: "2^192 - 1", + n: "ffffffffffffffffffffffffffffffffffffffffffffffff", + want: 192, + }, { + name: "2^192", + n: "1000000000000000000000000000000000000000000000000", + want: 193, + }, { + name: "2^255 - 1", + n: "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + want: 255, + }, { + name: "2^256 - 1", + n: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + want: 256, + }} + + for _, test := range tests { + got := hexToUint256(test.n).BitLen() + if got != test.want { + t.Errorf("%q: wrong result -- got: %v, want: %v", test.name, got, + test.want) + continue + } + } +}