uint256: Add bitwise or support.
This adds support to compute the bitwise or of two uint256s along with associated tests to ensure proper functionality. This is part of a series of commits to fully implement the uint256 package.
This commit is contained in:
parent
3ce3e33056
commit
269eee2069
@ -24,12 +24,12 @@ var (
|
||||
//
|
||||
// It currently implements the primary arithmetic operations (addition,
|
||||
// subtraction, multiplication, squaring, division, negation), bitwise
|
||||
// operations (lsh, rsh, not), comparison operations (equals, less, greater,
|
||||
// operations (lsh, rsh, not, or), 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 represented as a
|
||||
// uint64 without loss of precision.
|
||||
//
|
||||
// Future commits will implement bitwise operations (or, and, xor), and other
|
||||
// Future commits will implement bitwise operations (and, xor), and other
|
||||
// convenience methods such as determining the minimum number of bits required
|
||||
// to represent the current value and text formatting with base conversion.
|
||||
type Uint256 struct {
|
||||
@ -1287,3 +1287,16 @@ func (n *Uint256) Not() *Uint256 {
|
||||
n.n[3] = ^n.n[3]
|
||||
return n
|
||||
}
|
||||
|
||||
// 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 (n *Uint256) Or(n2 *Uint256) *Uint256 {
|
||||
n.n[0] |= n2.n[0]
|
||||
n.n[1] |= n2.n[1]
|
||||
n.n[2] |= n2.n[2]
|
||||
n.n[3] |= n2.n[3]
|
||||
return n
|
||||
}
|
||||
|
||||
@ -3038,3 +3038,97 @@ func TestUint256NotRandom(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUint256Or ensures that computing the bitwise or of two uint256s works
|
||||
// as expected for edge cases.
|
||||
func TestUint256Or(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string // test description
|
||||
n1 string // first hex encoded test value
|
||||
n2 string // second hex encoded test value
|
||||
want string // expected hex encoded result
|
||||
}{{
|
||||
name: "0 | 0",
|
||||
n1: "0",
|
||||
n2: "0",
|
||||
want: "0",
|
||||
}, {
|
||||
name: "2^256-1 | 0",
|
||||
n1: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
n2: "0",
|
||||
want: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
}, {
|
||||
name: "0 | 2^256-1",
|
||||
n1: "0",
|
||||
n2: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
want: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
}, {
|
||||
name: "2^256-1 | 2^256-1",
|
||||
n1: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
n2: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
want: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
}, {
|
||||
name: "alternating bits",
|
||||
n1: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
|
||||
n2: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
|
||||
want: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
}, {
|
||||
name: "alternating bits 2",
|
||||
n1: "5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a",
|
||||
n2: "a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5",
|
||||
want: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
}}
|
||||
|
||||
for _, test := range tests {
|
||||
// Parse test hex.
|
||||
n1 := hexToUint256(test.n1)
|
||||
n2 := hexToUint256(test.n2)
|
||||
want := hexToUint256(test.want)
|
||||
|
||||
// Ensure bitwise or of the two values produces the expected result.
|
||||
got := new(Uint256).Set(n1).Or(n2)
|
||||
if !got.Eq(want) {
|
||||
t.Errorf("%q: unexpected result -- got: %x, want: %x", test.name,
|
||||
got, want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUint256OrRandom ensures that computing the bitwise or of uint256s created
|
||||
// from random values works as expected by also performing the same operation
|
||||
// with big ints and comparing the results.
|
||||
func TestUint256OrRandom(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Use a unique random seed each test instance and log it if the tests fail.
|
||||
seed := time.Now().Unix()
|
||||
rng := rand.New(rand.NewSource(seed))
|
||||
defer func(t *testing.T, seed int64) {
|
||||
if t.Failed() {
|
||||
t.Logf("random seed: %d", seed)
|
||||
}
|
||||
}(t, seed)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
// Generate big integer and uint256 pairs.
|
||||
bigN1, n1 := randBigIntAndUint256(t, rng)
|
||||
bigN2, n2 := randBigIntAndUint256(t, rng)
|
||||
|
||||
// Calculate the bitwise or of the values using big ints.
|
||||
bigIntResult := new(big.Int).Or(bigN1, bigN2)
|
||||
|
||||
// Calculate the bitwise or of the values using uint256s.
|
||||
uint256Result := new(Uint256).Set(n1).Or(n2)
|
||||
|
||||
// Ensure they match.
|
||||
bigIntResultHex := fmt.Sprintf("%064x", bigIntResult.Bytes())
|
||||
uint256ResultHex := fmt.Sprintf("%064x", uint256Result.Bytes())
|
||||
if bigIntResultHex != uint256ResultHex {
|
||||
t.Fatalf("mismatched or n: %x -- got %x, want %x", n1, bigIntResult,
|
||||
uint256Result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user