Skip to content

Commit

Permalink
Add uint256 package and int256 wrapper (#1320)
Browse files Browse the repository at this point in the history
  • Loading branch information
roy-dydx authored Apr 4, 2024
1 parent 39981f1 commit b5ed196
Show file tree
Hide file tree
Showing 4 changed files with 759 additions and 3 deletions.
2 changes: 1 addition & 1 deletion protocol/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ require (
github.com/gorilla/mux v1.8.1
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/h2non/gock v1.2.0
github.com/holiman/uint256 v1.2.4
github.com/ory/dockertest v3.3.5+incompatible
github.com/pkg/errors v0.9.1
github.com/rakyll/statik v0.1.7
Expand Down Expand Up @@ -246,7 +247,6 @@ require (
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/hdevalence/ed25519consensus v0.1.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect
github.com/huandu/skiplist v1.2.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions protocol/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -927,8 +927,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8=
github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
Expand Down
194 changes: 194 additions & 0 deletions protocol/lib/int256/int256.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package int256

import (
"math/big"

"github.com/holiman/uint256"
)

// Signed wrapper for github.com/holiman/uint256.
//
// WARNING: Do not write to pointers until reading from all pointers is complete. This will cause incorrect
// behavior if the same pointer is passed in through multiple arguments.

type Int uint256.Int

var (
OneInt256 = NewInt(1)
TenInt256 = NewInt(10)
OneMillionInt256 = NewInt(1_000_000)

exp10Lookup = createExp10Lookup()
)

func (z *Int) String() string {
if z.Sign() >= 0 {
return (*uint256.Int)(z).Dec()
}
return "-" + (*uint256.Int)(new(uint256.Int).Neg((*uint256.Int)(z))).Dec()
}

// NewInt creates a new Int from an int64.
func NewInt(val int64) *Int {
if val < 0 {
u := uint256.NewInt(uint64(-val))
return (*Int)(u.Neg(u))
}
return (*Int)(uint256.NewInt(uint64(val)))
}

// NewUnsignedInt creates a new Int from a uint64.
func NewUnsignedInt(val uint64) *Int {
return (*Int)(uint256.NewInt(uint64(val)))
}

// MustFromBig creates a new Int from a big.Int. Panics on failure.
func MustFromBig(b *big.Int) *Int {
return (*Int)(uint256.MustFromBig(b))
}

// ToBig converts z to a big.Int.
func (z *Int) ToBig() *big.Int {
if z.Sign() >= 0 {
return (*uint256.Int)(z).ToBig()
}
r := new(uint256.Int).Neg((*uint256.Int)(z)).ToBig()
return r.Neg(r)
}

// Set sets z to the value of x.
func (z *Int) Set(x *Int) *Int {
return (*Int)((*uint256.Int)(z).Set((*uint256.Int)(x)))
}

// Set sets z to the value of a uint256.
func (z *Int) SetUint64(x uint64) *Int {
return (*Int)((*uint256.Int)(z).SetUint64(x))
}

// Sign returns -1 if z is negative, 0 if z is zero, and 1 if z is positive.
func (z *Int) Sign() int {
return (*uint256.Int)(z).Sign()
}

// IsZero returns true iff z is equal to 0.
func (z *Int) IsZero() bool {
return (*uint256.Int)(z).IsZero()
}

// Eq returns z == x.
func (z *Int) Eq(x *Int) bool {
return (*uint256.Int)(z).Eq((*uint256.Int)(x))
}

// Cmp returns -1 if z < x, 0 if z == x, and +1 if z > x.
func (z *Int) Cmp(x *Int) (r int) {
if z.Sign() >= 0 {
if x.Sign() >= 0 {
return (*uint256.Int)(z).Cmp((*uint256.Int)(x))
} else {
return 1
}
}
if x.Sign() >= 0 {
return -1
}
return (*uint256.Int)(z).Cmp((*uint256.Int)(x))
}

// Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int {
return (*Int)((*uint256.Int)(z).Neg((*uint256.Int)(x)))
}

// Abs sets z to the absolute value of x and returns z.
func (z *Int) Abs(x *Int) *Int {
return (*Int)((*uint256.Int)(z).Abs((*uint256.Int)(x)))
}

// Add sets z = x + y and returns z.
func (z *Int) Add(x, y *Int) *Int {
return (*Int)((*uint256.Int)(z).Add((*uint256.Int)(x), (*uint256.Int)(y)))
}

// Sub sets z = x - y and returns z.
func (z *Int) Sub(x, y *Int) *Int {
return (*Int)((*uint256.Int)(z).Sub((*uint256.Int)(x), (*uint256.Int)(y)))
}

// Mul sets z = x * y and returns z.
func (z *Int) Mul(x, y *Int) *Int {
if x.Sign() > 0 {
if y.Sign() > 0 {
return (*Int)(
(*uint256.Int)(z).Mul(
(*uint256.Int)(x),
(*uint256.Int)(y),
),
)
} else {
return z.Neg((*Int)(
(*uint256.Int)(z).Mul(
(*uint256.Int)(x),
new(uint256.Int).Neg((*uint256.Int)(y)),
),
))
}
}
if y.Sign() > 0 {
return z.Neg((*Int)(
(*uint256.Int)(z).Mul(
new(uint256.Int).Neg((*uint256.Int)(x)),
(*uint256.Int)(y),
),
))
}
return (*Int)((*uint256.Int)(z).Mul(
new(uint256.Int).Neg((*uint256.Int)(x)),
new(uint256.Int).Neg((*uint256.Int)(y)),
))
}

// Div sets z = x / y and returns z. If y is 0, z is set to 0.
func (z *Int) Div(x, y *Int) *Int {
return (*Int)((*uint256.Int)(z).SDiv((*uint256.Int)(x), (*uint256.Int)(y)))
}

func createExp10Lookup() map[uint64]uint256.Int {
lookup := make(map[uint64]uint256.Int, 100)
value := uint256.NewInt(1)
for i := 0; i < 100; i++ {
lookup[uint64(i)] = *new(uint256.Int).Set(value)
value.Mul(value, (*uint256.Int)(TenInt256))
}
return lookup
}

func mulExp10(z *uint256.Int, x *uint256.Int, y int64) *uint256.Int {
var abs uint64
if y < 0 {
abs = uint64(-y)
} else {
abs = uint64(y)
}
lookup, ok := exp10Lookup[abs]
var exp10 *uint256.Int
if ok {
exp10 = &lookup
} else {
exp10.Exp((*uint256.Int)(TenInt256), uint256.NewInt(abs))
}
if y < 0 {
return z.Div(x, exp10)
} else {
return z.Mul(x, exp10)
}
}

// MulExp10 sets z = x * 10^y and returns z.
func (z *Int) MulExp10(x *Int, y int64) *Int {
if x.Sign() >= 0 {
return (*Int)(mulExp10((*uint256.Int)(z), (*uint256.Int)(x), y))
}
return z.Neg((*Int)(mulExp10((*uint256.Int)(z), (*uint256.Int)(z.Neg(x)), y)))
}
Loading

0 comments on commit b5ed196

Please sign in to comment.