2021-12-04 16:42:11 +00:00

1284 lines
42 KiB
Go

// uint256: Fixed size 256-bit math library
// Copyright 2018-2020 uint256 Authors
// SPDX-License-Identifier: BSD-3-Clause
package uint256
import (
"bytes"
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"testing"
)
var (
bigtt256 = new(big.Int).Lsh(big.NewInt(1), 256)
bigtt255 = new(big.Int).Lsh(big.NewInt(1), 255)
unTestCases = []string{
"0",
"1",
"0x12cbafcee8f60f9f3fa308c90fde8d298772ffea667aa6bc109d5c661e7929a5",
"0x8000000000000000000000000000000000000000000000000000000000000000",
"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
}
// A collection of interesting input values for binary operators (especially for division).
// No expected results as big.Int can be used as the source of truth.
binTestCases = [][2]string{
{"0", "0"},
{"1", "0"},
{"1", "0x767676767676767676000000767676767676"},
{"2", "0"},
{"2", "1"},
{"0x12cbafcee8f60f9f3fa308c90fde8d298772ffea667aa6bc109d5c661e7929a5", "0x00000c76f4afb041407a8ea478d65024f5c3dfe1db1a1bb10c5ea8bec314ccf9"},
{"0x10000000000000000", "2"},
{"0x7000000000000000", "0x8000000000000000"},
{"0x8000000000000000", "0x8000000000000000"},
{"0x8000000000000001", "0x8000000000000000"},
{"0x80000000000000010000000000000000", "0x80000000000000000000000000000000"},
{"0x80000000000000000000000000000000", "0x80000000000000000000000000000001"},
{"0x478392145435897052", "0x111"},
{"0x767676767676767676000000767676767676", "0x2900760076761e00020076760000000076767676000000"},
{"0x12121212121212121212121212121212", "0x232323232323232323"},
{"0xfffff716b61616160b0b0b2b0b0b0becf4bef50a0df4f48b090b2b0bc60a0a00", "0xfffff716b61616160b0b0b2b0b230b000008010d0a2b00"},
{"0x50beb1c60141a0000dc2b0b0b0b0b0b410a0a0df4f40b090b2b0bc60a0a00", "0x2000110000000d0a300e750a000000090a0a"},
{"0x4b00000b41000b0b0b2b0b0b0b0b0b410a0aeff4f40b090b2b0bc60a0a1000", "0x4b00000b41000b0b0b2b0b0b0b0b0b410a0aeff4f40b0a0a"},
{"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", "7"},
{"0xf6376770abd3a36b20394c5664afef1194c801c3f05e42566f085ed24d002bb0", "0xb368d219438b7f3f"},
{"0", "0x10900000000000000000000000000000000000000000000000000"},
{"0x77676767676760000000000000001002e000000000000040000000e000000000", "0xfffc000000000000767676240000000000002b0576047"},
{"0x767676767676000000000076000000000000005600000000000000000000", "0x767676767676000000000076000000760000"},
{"0x8200000000000000000000000000000000000000000000000000000000000000", "0x8200000000000000fe000004000000ffff000000fffff700"},
{"0xdac7fff9ffd9e1322626262626262600", "0xd021262626262626"},
{"0x8000000000000001800000000000000080000000000000008000000000000000", "0x800000000000000080000000000000008000000000000000"},
{"0x00e8e8e8e2000100000009ea02000000000000ff3ffffff80000001000220000", "0x00e8e8e8e2000100000009ea02000000000000ff3ffffff800000010002280ff"},
{"0x000000c9700000000000000000023f00c00014ff000000000000000022300805", "0x00000000c9700000000000000000023f00c00014ff002c000000000000223108"},
{"0x40000000fd000000db0000000000000000000000000000000000000000000001", "0x40000000fd000000db0000000000000000000040000000fd000000db000001"},
{"0x40000000fd000000db0000000000000000000000000000000000000000000001", "0x40000000fd000000db0000000000000000000040000000fd000000db0000d3"},
{"0x001f000000000000000000000000000000200000000100000000000000000000", "0x0000000000000000000100000000ffffffffffffffff0000000000002e000000"},
{"0x7effffff80000000000000000000000000020000440000000000000000000001", "0x7effffff800000007effffff800000008000ff0000010000"},
{"0x5fd8fffffffffffffffffffffffffffffc090000ce700004d0c9ffffff000001", "0x2ffffffffffffffffffffffffffffffffff000000030000"},
{"0x62d8fffffffffffffffffffffffffffffc18000000000000000000ca00000001", "0x2ffffffffffffffffffffffffffffffffff200000000000"},
{"0x7effffff8000000000000000000000000000000000000000d900000000000001", "0x7effffff8000000000000000000000000000000000008001"},
{"0x0000000000000006400aff20ff00200004e7fd1eff08ffca0afd1eff08ffca0a", "0x00000000000000210000000000000022"},
{"0x00000000000000000000000000000000000000000000006d5adef08547abf7eb", "0x000000000000000000013590cab83b779e708b533b0eef3561483ddeefc841f5"},
{"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0x00e8e8e8e2000100000009ea02000000000000ff3ffffff80000001000220000", "0xffffffffffffffff7effffff800000007effffff800000008000ff0000010000"},
}
// A collection of interesting input values for ternary operators (addmod, mulmod).
ternTestCases = [][3]string{
{"0", "0", "0"},
{"1", "0", "0"},
{"1", "1", "0"},
{"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0"},
{"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "3", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
{"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
{"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "2"},
{"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "1"},
{"0xffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffff", "0xfffffffffffffffffffffffffffffffe00000000000000000000000000000002"},
{"0xffffffffffffffffffffffffffffffff", "0xffffffffffffffffffffffffffffffff", "0xfffffffffffffffffffffffffffffffe00000000000000000000000000000001"},
{"0xffffffffffffffffffffffffffff000004020041fffffffffc00000060000020", "0xffffffffffffffffffffffffffffffe6000000ffffffe60000febebeffffffff", "0xffffffffffffffffffe6000000ffffffe60000febebeffffffffffffffffffff"},
{"0xffffffffffffffffffffffffffffffff00ffffe6ff0000000000000060000020", "0xffffffffffffffffffffffffffffffffffe6000000ffff00e60000febebeffff", "0xffffffffffffffffffe6000000ffff00e60000fe0000ffff00e60000febebeff"},
{"0xfffffffffffffffffffffffff600000000005af50100bebe000000004a00be0a", "0xffffffffffffffffffffffffffffeaffdfd9fffffffffffff5f60000000000ff", "0xffffffffffffffffffffffeaffdfd9fffffffffffffff60000000000ffffffff"},
}
)
func hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
// toSatUint converts x to saturated uint value.
func toSatUint(x *Int) uint {
maxUint := ^uint(0)
z, overflow := x.Uint64WithOverflow()
if overflow || z > uint64(maxUint) {
return maxUint
}
return uint(z)
}
// bigToSatUint converts x to saturated uint value.
func bigToShiftAmount(x *big.Int) uint {
max := uint(256) // 256 is enough to zero the result.
if x.Cmp(new(big.Int).SetUint64(uint64(max))) > 0 {
return max
}
return uint(x.Uint64())
}
func checkOverflow(b *big.Int, f *Int, overflow bool) error {
max := big.NewInt(0).SetBytes(hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
shouldOverflow := b.Cmp(max) > 0
if overflow != shouldOverflow {
return fmt.Errorf("Overflow should be %v, was %v\nf= %x\nb= %x\b", shouldOverflow, overflow, f, b)
}
return nil
}
func randNums() (*big.Int, *Int, error) {
//How many bits? 0-256
nbits, _ := rand.Int(rand.Reader, big.NewInt(256))
//Max random value, a 130-bits integer, i.e 2^130
max := new(big.Int)
max.Exp(big.NewInt(2), big.NewInt(nbits.Int64()), nil)
b, _ := rand.Int(rand.Reader, max)
f, overflow := FromBig(b)
return b, f, checkOverflow(b, f, overflow)
}
func randHighNums() (*big.Int, *Int, error) {
//How many bits? 0-256
nbits := int64(256)
//Max random value, a 130-bits integer, i.e 2^130
max := new(big.Int)
max.Exp(big.NewInt(2), big.NewInt(nbits), nil)
//Generate cryptographically strong pseudo-random between 0 - max
b, _ := rand.Int(rand.Reader, max)
f, overflow := FromBig(b)
return b, f, checkOverflow(b, f, overflow)
}
func checkEq(b *big.Int, f *Int) bool {
f2, _ := FromBig(b)
return f.Eq(f2)
}
func requireEq(t *testing.T, exp *big.Int, got *Int, txt string) bool {
expF, _ := FromBig(exp)
if !expF.Eq(got) {
t.Errorf("got %x expected %x: %v\n", got, expF, txt)
return false
}
return true
}
func testRandomOp(t *testing.T, nativeFunc func(a, b, c *Int), bigintFunc func(a, b, c *big.Int)) {
for i := 0; i < 10000; i++ {
b1, f1, err := randNums()
if err != nil {
t.Fatal(err)
}
b2, f2, err := randNums()
if err != nil {
t.Fatal(err)
}
{ // Tests the op on the form: a.foo( a, b)
f1a, f2a := f1.Clone(), f2.Clone()
b1a, b2a := new(big.Int).Set(b1), new(big.Int).Set(b2)
nativeFunc(f1a, f1a, f2a)
bigintFunc(b1a, b1a, b2a)
//checkOverflow(b, f1, overflow)
if eq := checkEq(b1a, f1a); !eq {
bf, _ := FromBig(b1)
t.Fatalf("Expected equality:\nf1= %x\nf2= %x\n[ op ]==\nf = %x\nbf= %x\nb = %x\n", f1a, f2a, f1, bf, b1a)
}
}
{ // Tests the op on the form: a.foo( b, a)
f1a, f2a := f1.Clone(), f2.Clone()
b1a, b2a := new(big.Int).Set(b1), new(big.Int).Set(b2)
nativeFunc(f1a, f2a, f1a)
bigintFunc(b1a, b2a, b1a)
if eq := checkEq(b1a, f1a); !eq {
bf, _ := FromBig(b1)
t.Fatalf("Expected equality:\nf1= %x\nf2= %x\n[ op ]==\nf = %x\nbf= %x\nb = %x\n", f1a, f2a, f1, bf, b1a)
}
}
{ // Tests the op on the form: a.foo( a , a)
f1a := f1.Clone()
b1a := new(big.Int).Set(b1)
nativeFunc(f1a, f1a, f1a)
bigintFunc(b1a, b1a, b1a)
if eq := checkEq(b1a, f1a); !eq {
bf, _ := FromBig(b1)
t.Fatalf("Expected equality:\nf1= %x\nf2= %x\n[ op ]==\nf = %x\nbf= %x\nb = %x\n", f1a, f1a, f1, bf, b1a)
}
}
{ // Tests the op on the form: a.foo( b , b)
f1a, f2a := f1.Clone(), f2.Clone()
b1a, b2a := new(big.Int).Set(b1), new(big.Int).Set(b2)
nativeFunc(f1a, f2a, f2a)
bigintFunc(b1a, b2a, b2a)
if eq := checkEq(b1a, f1a); !eq {
bf, _ := FromBig(b1)
t.Fatalf("Expected equality:\nf1= %x\nf2= %x\n[ op ]==\nf = %x\nbf= %x\nb = %x\n", f2a, f2a, f1, bf, b1a)
}
}
}
}
func TestRandomSubOverflow(t *testing.T) {
for i := 0; i < 10000; i++ {
b, f1, err := randNums()
if err != nil {
t.Fatal(err)
}
b2, f2, err := randNums()
if err != nil {
t.Fatal(err)
}
f1a, f2a := f1.Clone(), f2.Clone()
_, overflow := f1.SubOverflow(f1, f2)
b.Sub(b, b2)
// check overflow
if have, want := overflow, b.Cmp(big.NewInt(0)) < 0; have != want {
t.Fatalf("underflow should be %v, was %v\nf= %x\nb= %x\b", have, want, f1, b)
}
if eq := checkEq(b, f1); !eq {
t.Fatalf("Expected equality:\nf1= %x\nf2= %x\n[ - ]==\nf= %x\nb= %x\n", f1a, f2a, f1, b)
}
}
}
func TestRandomSub(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.Sub(f2, f3)
},
func(b1, b2, b3 *big.Int) {
b1.Sub(b2, b3)
},
)
}
func TestRandomAdd(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.Add(f2, f3)
},
func(b1, b2, b3 *big.Int) {
b1.Add(b2, b3)
},
)
}
func TestRandomMul(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.Mul(f2, f3)
},
func(b1, b2, b3 *big.Int) {
b1.Mul(b2, b3)
},
)
}
func TestRandomMulOverflow(t *testing.T) {
for i := 0; i < 10000; i++ {
b, f1, err := randNums()
if err != nil {
t.Fatal(err)
}
b2, f2, err := randNums()
if err != nil {
t.Fatal(err)
}
f1a, f2a := f1.Clone(), f2.Clone()
_, overflow := f1.MulOverflow(f1, f2)
b.Mul(b, b2)
if err := checkOverflow(b, f1, overflow); err != nil {
t.Fatal(err)
}
if eq := checkEq(b, f1); !eq {
t.Fatalf("Expected equality:\nf1= %x\nf2= %x\n[ - ]==\nf= %x\nb= %x\n", f1a, f2a, f1, b)
}
}
}
func TestRandomSquare(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.squared()
},
func(b1, b2, b3 *big.Int) {
b1.Mul(b1, b1)
},
)
}
func TestRandomDiv(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.Div(f2, f3)
},
func(b1, b2, b3 *big.Int) {
if b3.Sign() == 0 {
b1.SetUint64(0)
} else {
b1.Div(b2, b3)
}
},
)
}
func TestRandomMod(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.Mod(f2, f3)
},
func(b1, b2, b3 *big.Int) {
if b3.Sign() == 0 {
b1.SetUint64(0)
} else {
b1.Mod(b2, b3)
}
},
)
}
func TestRandomSMod(t *testing.T) {
testRandomOp(t,
func(f1, f2, f3 *Int) {
f1.SMod(f2, f3)
},
func(b1, b2, b3 *big.Int) {
SMod(b1, b2, b3)
},
)
}
func TestRandomMulMod(t *testing.T) {
for i := 0; i < 10000; i++ {
b1, f1, err := randNums()
if err != nil {
t.Fatalf("Error getting a random number: %v", err)
}
b2, f2, err := randNums()
if err != nil {
t.Fatalf("Error getting a random number: %v", err)
}
b3, f3, err := randNums()
if err != nil {
t.Fatalf("Error getting a random number: %v", err)
}
b4, f4, _ := randNums()
for b4.Cmp(big.NewInt(0)) == 0 {
b4, f4, err = randNums()
if err != nil {
t.Fatalf("Error getting a random number: %v", err)
}
}
f1.MulMod(f2, f3, f4)
b1.Mod(big.NewInt(0).Mul(b2, b3), b4)
if !checkEq(b1, f1) {
t.Fatalf("Expected equality:\nf2= %x\nf3= %x\nf4= %x\n[ op ]==\nf = %x\nb = %x\n", f2, f3, f4, f1, b1)
}
}
}
func S256(x *big.Int) *big.Int {
if x.Cmp(bigtt255) < 0 {
return x
} else {
return new(big.Int).Sub(x, bigtt256)
}
}
func TestRandomAbs(t *testing.T) {
for i := 0; i < 10000; i++ {
b, f1, err := randHighNums()
if err != nil {
t.Fatal(err)
}
U256(b)
b2 := S256(big.NewInt(0).Set(b))
b2.Abs(b2)
f1a := new(Int).Abs(f1)
if eq := checkEq(b2, f1a); !eq {
bf, _ := FromBig(b2)
t.Fatalf("Expected equality:\nf1= %x\n[ abs ]==\nf = %x\nbf= %x\nb = %x\n", f1, f1a, bf, b2)
}
}
}
func TestRandomSDiv(t *testing.T) {
for i := 0; i < 10000; i++ {
b, f1, err := randHighNums()
if err != nil {
t.Fatal(err)
}
b2, f2, err := randHighNums()
if err != nil {
t.Fatal(err)
}
U256(b)
U256(b2)
f1a, f2a := f1.Clone(), f2.Clone()
f1aAbs, f2aAbs := new(Int).Abs(f1), new(Int).Abs(f2)
f1.SDiv(f1, f2)
if b2.BitLen() == 0 {
// zero
b = big.NewInt(0)
} else {
b = SDiv(b, b, b2)
}
if eq := checkEq(b, f1); !eq {
bf, _ := FromBig(b)
t.Fatalf("Expected equality:\nf1 = %x\nf2 = %x\n\n\nabs1= %x\nabs2= %x\n[sdiv]==\nf = %x\nbf = %x\nb = %x\n",
f1a, f2a, f1aAbs, f2aAbs, f1, bf, b)
}
}
}
func TestRandomLsh(t *testing.T) {
for i := 0; i < 10000; i++ {
b, f1, err := randNums()
if err != nil {
t.Fatal(err)
}
f1a := f1.Clone()
nbits, _ := rand.Int(rand.Reader, big.NewInt(256))
n := uint(nbits.Uint64())
f1.Lsh(f1, n)
b.Lsh(b, n)
if eq := checkEq(b, f1); !eq {
bf, _ := FromBig(b)
t.Fatalf("Expected equality:\nf1= %x\n n= %v\n[ << ]==\nf = %x\nbf= %x\nb = %x\n", f1a, n, f1, bf, b)
}
}
}
func TestRandomRsh(t *testing.T) {
for i := 0; i < 10000; i++ {
b, f1, err := randNums()
if err != nil {
t.Fatal(err)
}
f1a := f1.Clone()
nbits, _ := rand.Int(rand.Reader, big.NewInt(256))
n := uint(nbits.Uint64())
f1.Rsh(f1, n)
b.Rsh(b, n)
if eq := checkEq(b, f1); !eq {
t.Fatalf("Expected equality:\nf1= %x\n n= %v\n[ << ]==\nf= %x\nb= %x\n", f1a, n, f1, b)
}
}
}
func TestSRsh(t *testing.T) {
type testCase struct {
arg string
n uint
expected string
}
testCases := []testCase{
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 0, "FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 16, "FFFFFFFFEEEEDDDDCCCCBBBBAAAA999988887777666655554444333322221111"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 64, "FFFFFFFFFFFFFFFFFFFFEEEEDDDDCCCCBBBBAAAA999988887777666655554444"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 96, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEDDDDCCCCBBBBAAAA9999888877776666"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 127, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDDDDBBBB99997777555533331110"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 128, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEDDDDCCCCBBBBAAAA99998888"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 129, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7776EEEE6665DDDD5554CCCC444"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 192, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEDDDDCCCC"},
{"8000000000000000000000000000000000000000000000000000000000000000", 254, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE"},
{"8000000000000000000000000000000000000000000000000000000000000000", 255, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 256, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
{"FFFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 300, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"},
{"7FFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 16, "7FFFEEEEDDDDCCCCBBBBAAAA999988887777666655554444333322221111"},
{"7FFFEEEEDDDDCCCCBBBBAAAA9999888877776666555544443333222211110000", 256, ""},
}
for i := 0; i < len(testCases); i++ {
tc := &testCases[i]
arg := new(Int).SetBytes(hex2Bytes(tc.arg))
argCopy := new(Int).Set(arg)
expected := new(Int).SetBytes(hex2Bytes(tc.expected))
result := new(Int).SRsh(arg, tc.n)
if !result.Eq(expected) {
t.Logf("args: %s, %d\n", tc.arg, tc.n)
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
if !arg.Eq(argCopy) {
t.Errorf("Argument has been modified\n")
}
}
}
func TestByte(t *testing.T) {
z := new(Int).SetBytes(hex2Bytes("ABCDEF09080706050403020100000000000000000000000000000000000000ef"))
actual := z.Byte(NewInt(0))
expected := new(Int).SetBytes(hex2Bytes("00000000000000000000000000000000000000000000000000000000000000ab"))
if !actual.Eq(expected) {
t.Fatalf("Expected %x, got %x", expected, actual)
}
z = new(Int).SetBytes(hex2Bytes("ABCDEF09080706050403020100000000000000000000000000000000000000ef"))
actual = z.Byte(NewInt(31))
expected = new(Int).SetBytes(hex2Bytes("00000000000000000000000000000000000000000000000000000000000000ef"))
if !actual.Eq(expected) {
t.Fatalf("Expected %x, got %x", expected, actual)
}
z = new(Int).SetBytes(hex2Bytes("ABCDEF09080706050403020100000000000000000000000000000000000000ef"))
actual = z.Byte(NewInt(32))
expected = new(Int).SetBytes(hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"))
if !actual.Eq(expected) {
t.Fatalf("Expected %x, got %x", expected, actual)
}
z = new(Int).SetBytes(hex2Bytes("ABCDEF0908070605040302011111111111111111111111111111111111111111"))
actual = z.Byte(new(Int).SetBytes(hex2Bytes("f000000000000000000000000000000000000000000000000000000000000001")))
expected = new(Int).SetBytes(hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000"))
if !actual.Eq(expected) {
t.Fatalf("Expected %x, got %x", expected, actual)
}
}
func TestSignExtend(t *testing.T) {
type testCase struct {
arg string
n uint64
expected string
}
testCases := []testCase{
{"8080808080808080808080808080808080808080808080808080808080808080", 0, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80"},
{"8080808080808080808080808080808080808080808080808080808080808080", 1, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8080"},
{"8080808080808080808080808080808080808080808080808080808080808080", 2, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff808080"},
{"8080808080808080808080808080808080808080808080808080808080808080", 3, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80808080"},
{"8080808080808080808080808080808080808080808080808080808080808080", 30, "ff80808080808080808080808080808080808080808080808080808080808080"},
{"8080808080808080808080808080808080808080808080808080808080808080", 31, "8080808080808080808080808080808080808080808080808080808080808080"},
{"8080808080808080808080808080808080808080808080808080808080808080", 32, "8080808080808080808080808080808080808080808080808080808080808080"},
{"4040404040404040404040404040404040404040404040404040404040404040", 0, "40"},
{"4040404040404040404040404040404040404040404040404040404040404040", 1, "4040"},
{"4040404040404040404040404040404040404040404040404040404040404040", 30, "40404040404040404040404040404040404040404040404040404040404040"},
{"4040404040404040404040404040404040404040404040404040404040404040", 31, "4040404040404040404040404040404040404040404040404040404040404040"},
{"4040404040404040404040404040404040404040404040404040404040404040", 32, "4040404040404040404040404040404040404040404040404040404040404040"},
}
for i := 0; i < len(testCases); i++ {
tc := &testCases[i]
arg := new(Int).SetBytes(hex2Bytes(tc.arg))
argCopy := new(Int).Set(arg)
n := new(Int).SetUint64(tc.n)
nCopy := new(Int).Set(n)
expected := new(Int).SetBytes(hex2Bytes(tc.expected))
result := new(Int).ExtendSign(arg, n)
if !result.Eq(expected) {
t.Logf("args: %s, %d\n", tc.arg, tc.n)
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
if !arg.Eq(argCopy) {
t.Errorf("First argument has been modified\n")
}
if !n.Eq(nCopy) {
t.Errorf("Second argument has been modified\n")
}
}
}
func TestAddSubUint64(t *testing.T) {
type testCase struct {
arg string
n uint64
}
testCases := []testCase{
{"0", 1},
{"1", 0},
{"1", 1},
{"1", 3},
{"0x10000000000000000", 1},
{"0x100000000000000000000000000000000", 1},
{"0", 0xffffffffffffffff},
{"1", 0xffffffff},
{"0xffffffffffffffff", 1},
{"0xffffffffffffffff", 0xffffffffffffffff},
{"0x10000000000000000", 1},
{"0xfffffffffffffffffffffffffffffffff", 1},
{"0xfffffffffffffffffffffffffffffffff", 2},
}
for i := 0; i < len(testCases); i++ {
tc := &testCases[i]
bigArg, _ := new(big.Int).SetString(tc.arg, 0)
arg, _ := FromBig(bigArg)
{ // SubUint64
want, _ := FromBig(U256(new(big.Int).Sub(bigArg, new(big.Int).SetUint64(tc.n))))
have := new(Int).SetAllOne().SubUint64(arg, tc.n)
if !have.Eq(want) {
t.Logf("args: %s, %d\n", tc.arg, tc.n)
t.Logf("want : %x\n", want)
t.Logf("have : %x\n\n", have)
t.Fail()
}
}
{ // AddUint64
want, _ := FromBig(U256(new(big.Int).Add(bigArg, new(big.Int).SetUint64(tc.n))))
have := new(Int).AddUint64(arg, tc.n)
if !have.Eq(want) {
t.Logf("args: %s, %d\n", tc.arg, tc.n)
t.Logf("want : %x\n", want)
t.Logf("have : %x\n\n", have)
t.Fail()
}
}
}
}
func TestSGT(t *testing.T) {
x := new(Int).SetBytes(hex2Bytes("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"))
y := new(Int).SetBytes(hex2Bytes("00"))
actual := x.Sgt(y)
if actual {
t.Fatalf("Expected %v false", actual)
}
x = new(Int).SetBytes(hex2Bytes("00"))
y = new(Int).SetBytes(hex2Bytes("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"))
actual = x.Sgt(y)
if !actual {
t.Fatalf("Expected %v true", actual)
}
}
const (
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
)
var (
tt256m1 = new(big.Int).Sub(bigtt256, big.NewInt(1))
)
// U256 encodes as a 256 bit two's complement number. This operation is destructive.
func U256(x *big.Int) *big.Int {
return x.And(x, tt256m1)
}
// Exp implements exponentiation by squaring.
// The result is truncated to 256 bits.
func Exp(result, base, exponent *big.Int) *big.Int {
result.SetUint64(1)
for _, word := range exponent.Bits() {
for i := 0; i < wordBits; i++ {
if word&1 == 1 {
U256(result.Mul(result, base))
}
U256(base.Mul(base, base))
word >>= 1
}
}
return result
}
func SDiv(result, x, y *big.Int) *big.Int {
if y.Sign() == 0 {
return result.SetUint64(0)
}
sx := S256(x)
sy := S256(y)
n := new(big.Int)
if sx.Sign() == sy.Sign() {
n.SetInt64(1)
} else {
n.SetInt64(-1)
}
result.Div(sx.Abs(sx), sy.Abs(sy))
result.Mul(result, n)
return result
}
func SMod(result, x, y *big.Int) *big.Int {
if y.Sign() == 0 {
return result.SetUint64(0)
}
sx := S256(x)
sy := S256(y)
neg := sx.Sign() < 0
result.Mod(sx.Abs(sx), sy.Abs(sy))
if neg {
result.Neg(result)
}
return U256(result)
}
func addMod(result, x, y, mod *big.Int) *big.Int {
return result.Mod(result.Add(x, y), mod)
}
func mulMod(result, x, y, mod *big.Int) *big.Int {
return result.Mod(result.Mul(x, y), mod)
}
func referenceExp(base, exponent *big.Int) *big.Int {
// TODO: Maybe use the Exp() procedure from above?
res := new(big.Int)
return res.Exp(base, exponent, bigtt256)
}
func TestRandomExp(t *testing.T) {
for i := 0; i < 10000; i++ {
b_base, base, err := randNums()
if err != nil {
t.Fatal(err)
}
b_exp, exp, err := randNums()
if err != nil {
t.Fatal(err)
}
basecopy, expcopy := base.Clone(), exp.Clone()
f_res, overflow := FromBig(referenceExp(base.ToBig(), exp.ToBig()))
if overflow {
t.Fatal("FromBig(exp) overflow")
}
b_res := Exp(new(big.Int), b_base, b_exp)
if eq := checkEq(b_res, f_res); !eq {
bf, _ := FromBig(b_res)
t.Fatalf("Expected equality:\nbase= %x\nexp = %x\n[ ^ ]==\nf = %x\nbf= %x\nb = %x\n", basecopy, expcopy, f_res, bf, b_res)
}
}
}
func TestUnOp(t *testing.T) {
proc := func(t *testing.T, op func(a, b *Int) *Int, bigOp func(a, b *big.Int) *big.Int) {
for i := 0; i < len(unTestCases); i++ {
b1, _ := new(big.Int).SetString(unTestCases[i], 0)
f1orig, _ := FromBig(b1)
f1 := new(Int).Set(f1orig)
// Compare result with big.Int.
expected, _ := FromBig(bigOp(new(big.Int), b1))
result := op(new(Int), f1)
if !result.Eq(expected) {
t.Logf("arg : %s\n", unTestCases[i])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
// Check if arguments are unmodified.
if !f1.Eq(f1orig) {
t.Logf("arg : %s\n", unTestCases[i])
t.Errorf("first argument had been modified: %x\n", f1)
}
// Check if reusing args as result works correctly.
result = op(f1, f1)
if result != f1 {
t.Logf("arg : %s\n", unTestCases[i])
t.Errorf("unexpected pointer returned: %p, expected: %p\n", result, f1)
}
if !result.Eq(expected) {
t.Logf("arg : %s\n", unTestCases[i])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
}
}
t.Run("Not", func(t *testing.T) { proc(t, (*Int).Not, (*big.Int).Not) })
t.Run("Neg", func(t *testing.T) { proc(t, (*Int).Neg, (*big.Int).Neg) })
}
func TestBinOp(t *testing.T) {
proc := func(t *testing.T, op func(a, b, c *Int) *Int, bigOp func(a, b, c *big.Int) *big.Int) {
for i := 0; i < len(binTestCases); i++ {
b1, _ := new(big.Int).SetString(binTestCases[i][0], 0)
b2, _ := new(big.Int).SetString(binTestCases[i][1], 0)
f1orig, _ := FromBig(b1)
f2orig, _ := FromBig(b2)
f1 := new(Int).Set(f1orig)
f2 := new(Int).Set(f2orig)
// Compare result with big.Int.
expected, _ := FromBig(bigOp(new(big.Int), b1, b2))
result := op(new(Int), f1, f2)
if !result.Eq(expected) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
// Check if arguments are unmodified.
if !f1.Eq(f1orig) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Errorf("first argument had been modified: %x\n", f1)
}
if !f2.Eq(f2orig) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Errorf("second argument had been modified: %x\n", f2)
}
// Check if reusing args as result works correctly.
result = op(f1, f1, f2orig)
if result != f1 {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Errorf("unexpected pointer returned: %p, expected: %p\n", result, f1)
}
if !result.Eq(expected) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
result = op(f2, f1orig, f2)
if result != f2 {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Errorf("unexpected pointer returned: %p, expected: %p\n", result, f2)
}
if !result.Eq(expected) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
}
}
t.Run("Add", func(t *testing.T) { proc(t, (*Int).Add, (*big.Int).Add) })
t.Run("Sub", func(t *testing.T) { proc(t, (*Int).Sub, (*big.Int).Sub) })
t.Run("Mul", func(t *testing.T) { proc(t, (*Int).Mul, (*big.Int).Mul) })
t.Run("Div", func(t *testing.T) {
proc(t, (*Int).Div, func(z, x, y *big.Int) *big.Int {
if y.Sign() == 0 {
return z.SetUint64(0)
}
return z.Div(x, y)
})
})
t.Run("Mod", func(t *testing.T) {
proc(t, (*Int).Mod, func(z, x, y *big.Int) *big.Int {
if y.Sign() == 0 {
return z.SetUint64(0)
}
return z.Mod(x, y)
})
})
t.Run("SDiv", func(t *testing.T) { proc(t, (*Int).SDiv, SDiv) })
t.Run("SMod", func(t *testing.T) { proc(t, (*Int).SMod, SMod) })
t.Run("Exp", func(t *testing.T) { proc(t, (*Int).Exp, Exp) })
t.Run("And", func(t *testing.T) { proc(t, (*Int).And, (*big.Int).And) })
t.Run("Or", func(t *testing.T) { proc(t, (*Int).Or, (*big.Int).Or) })
t.Run("Xor", func(t *testing.T) { proc(t, (*Int).Xor, (*big.Int).Xor) })
t.Run("Lsh", func(t *testing.T) {
proc(t, func(z, x, y *Int) *Int {
return z.Lsh(x, toSatUint(y))
}, func(z, x, y *big.Int) *big.Int {
return z.Lsh(x, bigToShiftAmount(y))
})
})
t.Run("Rsh", func(t *testing.T) {
proc(t, func(z, x, y *Int) *Int {
return z.Rsh(x, toSatUint(y))
}, func(z, x, y *big.Int) *big.Int {
return z.Rsh(x, bigToShiftAmount(y))
})
})
}
func TestTernOp(t *testing.T) {
proc := func(t *testing.T, op func(a, b, c, d *Int) *Int, bigOp func(a, b, c, d *big.Int) *big.Int) {
for i := 0; i < len(ternTestCases); i++ {
b1, _ := new(big.Int).SetString(ternTestCases[i][0], 0)
b2, _ := new(big.Int).SetString(ternTestCases[i][1], 0)
b3, _ := new(big.Int).SetString(ternTestCases[i][2], 0)
f1orig, _ := FromBig(b1)
f2orig, _ := FromBig(b2)
f3orig, _ := FromBig(b3)
f1 := new(Int).Set(f1orig)
f2 := new(Int).Set(f2orig)
f3 := new(Int).Set(f3orig)
// Compare result with big.Int.
expected, _ := FromBig(bigOp(new(big.Int), b1, b2, b3))
result := op(new(Int), f1, f2, f3)
if !result.Eq(expected) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
// Check if arguments are unmodified.
if !f1.Eq(f1orig) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Errorf("first argument had been modified: %x\n", f1)
}
if !f2.Eq(f2orig) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Errorf("second argument had been modified: %x\n", f2)
}
if !f3.Eq(f3orig) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Errorf("third argument had been modified: %x\n", f3)
}
// Check if reusing args as result works correctly.
result = op(f1, f1, f2orig, f3orig)
if result != f1 {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Errorf("unexpected pointer returned: %p, expected: %p\n", result, f1)
}
if !result.Eq(expected) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
result = op(f2, f1orig, f2, f3orig)
if result != f2 {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Errorf("unexpected pointer returned: %p, expected: %p\n", result, f2)
}
if !result.Eq(expected) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
result = op(f3, f1orig, f2orig, f3)
if result != f3 {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Errorf("unexpected pointer returned: %p, expected: %p\n", result, f3)
}
if !result.Eq(expected) {
t.Logf("args: %s, %s, %s\n", ternTestCases[i][0], ternTestCases[i][1], ternTestCases[i][2])
t.Logf("exp : %x\n", expected)
t.Logf("got : %x\n\n", result)
t.Fail()
}
}
}
t.Run("AddMod", func(t *testing.T) {
proc(t, (*Int).AddMod, func(z, x, y, m *big.Int) *big.Int {
if m.Sign() == 0 {
return z.SetUint64(0)
}
return addMod(z, x, y, m)
})
})
t.Run("MulMod", func(t *testing.T) {
proc(t, (*Int).MulMod, func(z, x, y, m *big.Int) *big.Int {
if m.Sign() == 0 {
return z.SetUint64(0)
}
return mulMod(z, x, y, m)
})
})
}
func TestCmpOp(t *testing.T) {
proc := func(t *testing.T, op func(a, b *Int) bool, bigOp func(a, b *big.Int) bool) {
for i := 0; i < len(binTestCases); i++ {
b1, _ := new(big.Int).SetString(binTestCases[i][0], 0)
b2, _ := new(big.Int).SetString(binTestCases[i][1], 0)
f1orig, _ := FromBig(b1)
f2orig, _ := FromBig(b2)
f1 := new(Int).Set(f1orig)
f2 := new(Int).Set(f2orig)
// Compare result with big.Int.
expected := bigOp(b1, b2)
result := op(f1, f2)
if result != expected {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Logf("exp : %t\n", expected)
t.Logf("got : %t\n\n", result)
t.Fail()
}
// Check if arguments are unmodified.
if !f1.Eq(f1orig) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Errorf("first argument had been modified: %x\n", f1)
}
if !f2.Eq(f2orig) {
t.Logf("args: %s, %s\n", binTestCases[i][0], binTestCases[i][1])
t.Errorf("second argument had been modified: %x\n", f2)
}
}
}
t.Run("Eq", func(t *testing.T) { proc(t, (*Int).Eq, func(a, b *big.Int) bool { return a.Cmp(b) == 0 }) })
t.Run("Lt", func(t *testing.T) { proc(t, (*Int).Lt, func(a, b *big.Int) bool { return a.Cmp(b) < 0 }) })
t.Run("Gt", func(t *testing.T) { proc(t, (*Int).Gt, func(a, b *big.Int) bool { return a.Cmp(b) > 0 }) })
t.Run("SLt", func(t *testing.T) { proc(t, (*Int).Slt, func(a, b *big.Int) bool { return S256(a).Cmp(S256(b)) < 0 }) })
t.Run("SGt", func(t *testing.T) { proc(t, (*Int).Sgt, func(a, b *big.Int) bool { return S256(a).Cmp(S256(b)) > 0 }) })
t.Run("CmpEq", func(t *testing.T) {
proc(t, func(a, b *Int) bool { return a.Cmp(b) == 0 }, func(a, b *big.Int) bool { return a.Cmp(b) == 0 })
})
t.Run("CmpLt", func(t *testing.T) {
proc(t, func(a, b *Int) bool { return a.Cmp(b) < 0 }, func(a, b *big.Int) bool { return a.Cmp(b) < 0 })
})
t.Run("CmpGt", func(t *testing.T) {
proc(t, func(a, b *Int) bool { return a.Cmp(b) > 0 }, func(a, b *big.Int) bool { return a.Cmp(b) > 0 })
})
t.Run("LtUint64", func(t *testing.T) {
proc(t, func(a, b *Int) bool {
return a.LtUint64(b.Uint64())
}, func(a, b *big.Int) bool {
return a.Cmp(new(big.Int).SetUint64(b.Uint64())) < 0
})
})
t.Run("GtUint64", func(t *testing.T) {
proc(t, func(a, b *Int) bool {
return a.GtUint64(b.Uint64())
}, func(a, b *big.Int) bool {
return a.Cmp(new(big.Int).SetUint64(b.Uint64())) > 0
})
})
}
// TestFixedExpReusedArgs tests the cases in Exp() where the arguments (including result) alias the same objects.
func TestFixedExpReusedArgs(t *testing.T) {
f2 := Int{2, 0, 0, 0}
f2.Exp(&f2, &f2)
requireEq(t, big.NewInt(2*2), &f2, "")
// TODO: This is tested in TestBinOp().
f3 := Int{3, 0, 0, 0}
f4 := Int{4, 0, 0, 0}
f3.Exp(&f4, &f3)
requireEq(t, big.NewInt(4*4*4), &f3, "")
// TODO: This is tested in TestBinOp().
f5 := Int{5, 0, 0, 0}
f6 := Int{6, 0, 0, 0}
f6.Exp(&f6, &f5)
requireEq(t, big.NewInt(6*6*6*6*6), &f6, "")
f3 = Int{3, 0, 0, 0}
fr := new(Int).Exp(&f3, &f3)
requireEq(t, big.NewInt(3*3*3), fr, "")
}
func TestByteRepresentation(t *testing.T) {
a := big.NewInt(0xFF0AFcafe)
aa := new(Int).SetUint64(0xFF0afcafe)
bb := new(Int).SetBytes(a.Bytes())
if !aa.Eq(bb) {
t.Fatal("aa != bb")
}
check := func(padded []byte, expectedHex string) {
if expected := hex2Bytes(expectedHex); !bytes.Equal(padded, expected) {
t.Errorf("incorrect padded bytes: %x, expected: %x", padded, expected)
}
}
check(aa.PaddedBytes(32), "0000000000000000000000000000000000000000000000000000000ff0afcafe")
check(aa.PaddedBytes(20), "0000000000000000000000000000000ff0afcafe")
check(aa.PaddedBytes(40), "00000000000000000000000000000000000000000000000000000000000000000000000ff0afcafe")
bytearr := hex2Bytes("0e320219838e859b2f9f18b72e3d4073ca50b37d")
a = new(big.Int).SetBytes(bytearr)
aa = new(Int).SetBytes(bytearr)
bb = new(Int).SetBytes(a.Bytes())
if !aa.Eq(bb) {
t.Fatal("aa != bb")
}
check(aa.PaddedBytes(32), "0000000000000000000000000e320219838e859b2f9f18b72e3d4073ca50b37d")
check(aa.PaddedBytes(20), "0e320219838e859b2f9f18b72e3d4073ca50b37d")
check(aa.PaddedBytes(40), "00000000000000000000000000000000000000000e320219838e859b2f9f18b72e3d4073ca50b37d")
}
func TestWriteToSlice(t *testing.T) {
x1 := hex2Bytes("fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611")
a := big.NewInt(0).SetBytes(x1)
fa, _ := FromBig(a)
dest := make([]byte, 32)
fa.WriteToSlice(dest)
if !bytes.Equal(dest, x1) {
t.Errorf("got %x, expected %x", dest, x1)
}
fb := new(Int)
exp := make([]byte, 32)
fb.WriteToSlice(dest)
if !bytes.Equal(dest, exp) {
t.Errorf("got %x, expected %x", dest, exp)
}
// a too small buffer
// Should fill the lower parts, masking upper bytes
exp = hex2Bytes("683fd1e870eec79504c60144cc7f5fc2bad1e611")
dest = make([]byte, 20)
fa.WriteToSlice(dest)
if !bytes.Equal(dest, exp) {
t.Errorf("got %x, expected %x", dest, exp)
}
// a too large buffer, already filled with stuff
// Should fill the leftmost 32 bytes, not touch the other things
dest = hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
exp = hex2Bytes("fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611ffffffffffffffff")
fa.WriteToSlice(dest)
if !bytes.Equal(dest, exp) {
t.Errorf("got %x, expected %x", dest, x1)
}
// an empty slice, no panics please
dest = []byte{}
exp = []byte{}
fa.WriteToSlice(dest)
if !bytes.Equal(dest, exp) {
t.Errorf("got %x, expected %x", dest, x1)
}
}
func TestInt_WriteToArray(t *testing.T) {
x1 := hex2Bytes("0000000000000000000000000000d1e870eec79504c60144cc7f5fc2bad1e611")
a := big.NewInt(0).SetBytes(x1)
fa, _ := FromBig(a)
{
dest := [20]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
fa.WriteToArray20(&dest)
exp := hex2Bytes("0000d1e870eec79504c60144cc7f5fc2bad1e611")
if !bytes.Equal(dest[:], exp) {
t.Errorf("got %x, expected %x", dest, exp)
}
}
{
dest := [32]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
fa.WriteToArray32(&dest)
exp := hex2Bytes("0000000000000000000000000000d1e870eec79504c60144cc7f5fc2bad1e611")
if !bytes.Equal(dest[:], exp) {
t.Errorf("got %x, expected %x", dest, exp)
}
}
}
type gethAddress [20]byte
// SetBytes sets the address to the value of b.
// If b is larger than len(a) it will panic.
func (a *gethAddress) setBytes(b []byte) {
if len(b) > len(a) {
b = b[len(b)-20:]
}
copy(a[20-len(b):], b)
}
// BytesToAddress returns Address with value b.
// If b is larger than len(h), b will be cropped from the left.
func bytesToAddress(b []byte) gethAddress {
var a gethAddress
a.setBytes(b)
return a
}
type gethHash [32]byte
// SetBytes sets the address to the value of b.
// If b is larger than len(a) it will panic.
func (a *gethHash) setBytes(b []byte) {
if len(b) > len(a) {
b = b[len(b)-32:]
}
copy(a[32-len(b):], b)
}
// BytesToHash returns gethHash with value b.
// If b is larger than len(h), b will be cropped from the left.
func bytesToHash(b []byte) gethHash {
var a gethHash
a.setBytes(b)
return a
}
func TestByte20Representation(t *testing.T) {
for i, tt := range []string{
"1337fafafa0e320219838e859b2f9f18b72e3d4073ca50b37d",
"fafafa0e320219838e859b2f9f18b72e3d4073ca50b37d",
"0e320219838e859b2f9f18b72e3d4073ca50b37d",
"320219838e859b2f9f18b72e3d4073ca50b37d",
"838e859b2f9f18b72e3d4073ca50b37d",
"38e859b2f9f18b72e3d4073ca50b37d",
"f18b72e3d4073ca50b37d",
"b37d",
"01",
"",
"00",
} {
bytearr := hex2Bytes(tt)
// big.Int -> address
a := big.NewInt(0).SetBytes(bytearr)
exp := bytesToAddress(a.Bytes())
// uint256.Int -> address
b := new(Int).SetBytes(bytearr)
got := gethAddress(b.Bytes20())
if got != exp {
t.Errorf("testcase %d: got %x exp %x", i, got, exp)
}
}
}
func TestByte32Representation(t *testing.T) {
for i, tt := range []string{
"1337fafafa0e320219838e859b2f9f18b72e3d4073ca50b37d",
"fafafa0e320219838e859b2f9f18b72e3d4073ca50b37d",
"0e320219838e859b2f9f18b72e3d4073ca50b37d",
"320219838e859b2f9f18b72e3d4073ca50b37d",
"838e859b2f9f18b72e3d4073ca50b37d",
"38e859b2f9f18b72e3d4073ca50b37d",
"f18b72e3d4073ca50b37d",
"b37d",
"01",
"",
"00",
} {
bytearr := hex2Bytes(tt)
// big.Int -> hash
a := big.NewInt(0).SetBytes(bytearr)
exp := bytesToHash(a.Bytes())
// uint256.Int -> address
b := new(Int).SetBytes(bytearr)
got := gethHash(b.Bytes32())
if got != exp {
t.Errorf("testcase %d: got %x exp %x", i, got, exp)
}
}
}