1284 lines
42 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|