2019-02-19 14:59:03 -08:00
|
|
|
package types
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Uint wraps integer with 256 bit range bound
|
|
|
|
// Checks overflow, underflow and division by zero
|
|
|
|
// Exists in range from 0 to 2^256-1
|
|
|
|
type Uint struct {
|
|
|
|
i *big.Int
|
|
|
|
}
|
|
|
|
|
2019-11-18 18:39:33 -08:00
|
|
|
// BigInt converts Uint to big.Int
|
|
|
|
func (u Uint) BigInt() *big.Int {
|
|
|
|
return new(big.Int).Set(u.i)
|
|
|
|
}
|
|
|
|
|
2019-02-19 14:59:03 -08:00
|
|
|
// NewUintFromBigUint constructs Uint from big.Uint
|
|
|
|
func NewUintFromBigInt(i *big.Int) Uint {
|
|
|
|
u, err := checkNewUint(i)
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Errorf("overflow: %s", err))
|
|
|
|
}
|
|
|
|
return u
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewUint constructs Uint from int64
|
|
|
|
func NewUint(n uint64) Uint {
|
|
|
|
i := new(big.Int)
|
|
|
|
i.SetUint64(n)
|
|
|
|
return NewUintFromBigInt(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewUintFromString constructs Uint from string
|
|
|
|
func NewUintFromString(s string) Uint {
|
|
|
|
u, err := ParseUint(s)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return u
|
|
|
|
}
|
|
|
|
|
|
|
|
// ZeroUint returns unsigned zero.
|
|
|
|
func ZeroUint() Uint { return Uint{big.NewInt(0)} }
|
|
|
|
|
|
|
|
// OneUint returns Uint value with one.
|
|
|
|
func OneUint() Uint { return Uint{big.NewInt(1)} }
|
|
|
|
|
2020-01-24 07:32:00 -08:00
|
|
|
var _ CustomProtobufType = (*Uint)(nil)
|
|
|
|
|
2019-02-19 14:59:03 -08:00
|
|
|
// Uint64 converts Uint to uint64
|
|
|
|
// Panics if the value is out of range
|
|
|
|
func (u Uint) Uint64() uint64 {
|
|
|
|
if !u.i.IsUint64() {
|
|
|
|
panic("Uint64() out of bound")
|
|
|
|
}
|
|
|
|
return u.i.Uint64()
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsZero returns 1 if the uint equals to 0.
|
|
|
|
func (u Uint) IsZero() bool { return u.Equal(ZeroUint()) }
|
|
|
|
|
|
|
|
// Equal compares two Uints
|
|
|
|
func (u Uint) Equal(u2 Uint) bool { return equal(u.i, u2.i) }
|
|
|
|
|
|
|
|
// GT returns true if first Uint is greater than second
|
|
|
|
func (u Uint) GT(u2 Uint) bool { return gt(u.i, u2.i) }
|
|
|
|
|
|
|
|
// GTE returns true if first Uint is greater than second
|
|
|
|
func (u Uint) GTE(u2 Uint) bool { return u.GT(u2) || u.Equal(u2) }
|
|
|
|
|
|
|
|
// LT returns true if first Uint is lesser than second
|
|
|
|
func (u Uint) LT(u2 Uint) bool { return lt(u.i, u2.i) }
|
|
|
|
|
|
|
|
// LTE returns true if first Uint is lesser than or equal to the second
|
2019-12-12 08:44:54 -08:00
|
|
|
func (u Uint) LTE(u2 Uint) bool { return !u.GT(u2) }
|
2019-02-19 14:59:03 -08:00
|
|
|
|
|
|
|
// Add adds Uint from another
|
|
|
|
func (u Uint) Add(u2 Uint) Uint { return NewUintFromBigInt(new(big.Int).Add(u.i, u2.i)) }
|
|
|
|
|
|
|
|
// Add convert uint64 and add it to Uint
|
|
|
|
func (u Uint) AddUint64(u2 uint64) Uint { return u.Add(NewUint(u2)) }
|
|
|
|
|
|
|
|
// Sub adds Uint from another
|
|
|
|
func (u Uint) Sub(u2 Uint) Uint { return NewUintFromBigInt(new(big.Int).Sub(u.i, u2.i)) }
|
|
|
|
|
|
|
|
// SubUint64 adds Uint from another
|
|
|
|
func (u Uint) SubUint64(u2 uint64) Uint { return u.Sub(NewUint(u2)) }
|
|
|
|
|
|
|
|
// Mul multiplies two Uints
|
|
|
|
func (u Uint) Mul(u2 Uint) (res Uint) {
|
|
|
|
return NewUintFromBigInt(new(big.Int).Mul(u.i, u2.i))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mul multiplies two Uints
|
|
|
|
func (u Uint) MulUint64(u2 uint64) (res Uint) { return u.Mul(NewUint(u2)) }
|
|
|
|
|
2019-02-21 09:35:55 -08:00
|
|
|
// Quo divides Uint with Uint
|
|
|
|
func (u Uint) Quo(u2 Uint) (res Uint) { return NewUintFromBigInt(div(u.i, u2.i)) }
|
2019-02-19 14:59:03 -08:00
|
|
|
|
2019-12-19 13:46:43 -08:00
|
|
|
// Mod returns remainder after dividing with Uint
|
|
|
|
func (u Uint) Mod(u2 Uint) Uint {
|
|
|
|
if u2.IsZero() {
|
|
|
|
panic("division-by-zero")
|
|
|
|
}
|
|
|
|
return Uint{mod(u.i, u2.i)}
|
|
|
|
}
|
|
|
|
|
2020-01-07 07:17:01 -08:00
|
|
|
// Incr increments the Uint by one.
|
|
|
|
func (u Uint) Incr() Uint {
|
|
|
|
return u.Add(OneUint())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decr decrements the Uint by one.
|
|
|
|
// Decr will panic if the Uint is zero.
|
|
|
|
func (u Uint) Decr() Uint {
|
|
|
|
return u.Sub(OneUint())
|
|
|
|
}
|
|
|
|
|
2019-02-21 09:35:55 -08:00
|
|
|
// Quo divides Uint with uint64
|
|
|
|
func (u Uint) QuoUint64(u2 uint64) Uint { return u.Quo(NewUint(u2)) }
|
2019-02-19 14:59:03 -08:00
|
|
|
|
|
|
|
// Return the minimum of the Uints
|
|
|
|
func MinUint(u1, u2 Uint) Uint { return NewUintFromBigInt(min(u1.i, u2.i)) }
|
|
|
|
|
|
|
|
// Return the maximum of the Uints
|
|
|
|
func MaxUint(u1, u2 Uint) Uint { return NewUintFromBigInt(max(u1.i, u2.i)) }
|
|
|
|
|
|
|
|
// Human readable string
|
|
|
|
func (u Uint) String() string { return u.i.String() }
|
|
|
|
|
2020-01-24 07:32:00 -08:00
|
|
|
// MarshalJSON defines custom encoding scheme
|
|
|
|
func (u Uint) MarshalJSON() ([]byte, error) {
|
2019-02-19 14:59:03 -08:00
|
|
|
if u.i == nil { // Necessary since default Uint initialization has i.i as nil
|
|
|
|
u.i = new(big.Int)
|
|
|
|
}
|
2020-01-24 07:32:00 -08:00
|
|
|
return marshalJSON(u.i)
|
2019-02-19 14:59:03 -08:00
|
|
|
}
|
|
|
|
|
2020-01-24 07:32:00 -08:00
|
|
|
// UnmarshalJSON defines custom decoding scheme
|
|
|
|
func (u *Uint) UnmarshalJSON(bz []byte) error {
|
2019-02-19 14:59:03 -08:00
|
|
|
if u.i == nil { // Necessary since default Uint initialization has i.i as nil
|
|
|
|
u.i = new(big.Int)
|
|
|
|
}
|
2020-01-24 07:32:00 -08:00
|
|
|
return unmarshalJSON(u.i, bz)
|
2019-02-19 14:59:03 -08:00
|
|
|
}
|
|
|
|
|
2020-01-24 07:32:00 -08:00
|
|
|
// Marshal implements the gogo proto custom type interface.
|
|
|
|
func (u Uint) Marshal() ([]byte, error) {
|
|
|
|
if u.i == nil {
|
2019-02-19 14:59:03 -08:00
|
|
|
u.i = new(big.Int)
|
|
|
|
}
|
2020-01-24 07:32:00 -08:00
|
|
|
return u.i.MarshalText()
|
2019-02-19 14:59:03 -08:00
|
|
|
}
|
|
|
|
|
2020-01-24 07:32:00 -08:00
|
|
|
// MarshalTo implements the gogo proto custom type interface.
|
|
|
|
func (u *Uint) MarshalTo(data []byte) (n int, err error) {
|
|
|
|
if u.i == nil {
|
2019-02-19 14:59:03 -08:00
|
|
|
u.i = new(big.Int)
|
|
|
|
}
|
types: use (*math/big.Int).BitLen() == 0 to check if value is 0 (#8580)
Instead of using len((*math/big.Int).Bytes()) == 0, which expensively
creates a byte slice and marshals a value, on the majority hot path,
instead use the cheaper method .BitLen() to check if 0.
Benchmarking results, just from types:
name old time/op new time/op delta
CoinsAdditionIntersect/sizes:_A_1,_B_1-8 132ns ± 2% 126ns ±13% -4.55% (p=0.050 n=10+10)
CoinsAdditionIntersect/sizes:_A_5,_B_5-8 1.41µs ± 3% 1.41µs ± 2% ~ (p=1.000 n=10+10)
CoinsAdditionIntersect/sizes:_A_5,_B_20-8 2.30µs ± 1% 2.27µs ± 3% ~ (p=0.066 n=10+10)
CoinsAdditionIntersect/sizes:_A_1,_B_1000-8 30.9µs ± 3% 30.7µs ± 1% ~ (p=0.218 n=10+10)
CoinsAdditionIntersect/sizes:_A_2,_B_1000-8 31.4µs ± 3% 30.8µs ± 2% -1.94% (p=0.015 n=10+10)
CoinsAdditionNoIntersect/sizes:_A_1,_B_1-8 116ns ± 1% 114ns ± 4% ~ (p=0.142 n=10+10)
CoinsAdditionNoIntersect/sizes:_A_5,_B_5-8 1.11µs ± 1% 1.08µs ± 3% -2.36% (p=0.003 n=8+10)
CoinsAdditionNoIntersect/sizes:_A_5,_B_20-8 1.85µs ± 2% 1.82µs ± 1% -1.38% (p=0.001 n=10+9)
CoinsAdditionNoIntersect/sizes:_A_1,_B_1000-8 30.7µs ± 1% 30.6µs ± 3% ~ (p=0.393 n=10+10)
CoinsAdditionNoIntersect/sizes:_A_2,_B_1000-8 31.1µs ± 1% 30.7µs ± 2% -1.32% (p=0.015 n=10+10)
CoinsAdditionNoIntersect/sizes:_A_1000,_B_2-8 31.0µs ± 2% 30.7µs ± 2% ~ (p=0.190 n=10+10)
Bech32ifyPubKey-8 28.8µs ± 5% 28.8µs ± 3% ~ (p=0.965 n=10+8)
GetPubKeyFromBech32-8 38.8µs ± 3% 39.4µs ± 2% +1.70% (p=0.013 n=9+10)
ParseCoin-8 16.7µs ± 6% 15.8µs ± 4% -5.21% (p=0.001 n=10+10)
MarshalTo-8 521ns ± 5% 508ns ± 3% -2.56% (p=0.029 n=10+10)
UintMarshal-8 3.10µs ±17% 2.56µs ± 3% -17.45% (p=0.000 n=10+9)
IntMarshal-8 2.52µs ±10% 1.94µs ± 2% -23.10% (p=0.000 n=10+10)
name old alloc/op new alloc/op delta
Bech32ifyPubKey-8 4.02kB ± 0% 4.02kB ± 0% ~ (all equal)
GetPubKeyFromBech32-8 2.48kB ± 0% 2.48kB ± 0% ~ (all equal)
ParseCoin-8 2.21kB ± 0% 2.21kB ± 0% ~ (all equal)
MarshalTo-8 80.0B ± 0% 80.0B ± 0% ~ (all equal)
UintMarshal-8 440B ± 0% 392B ± 0% -10.91% (p=0.000 n=10+10)
IntMarshal-8 216B ± 0% 168B ± 0% -22.22% (p=0.000 n=10+10)
name old allocs/op new allocs/op delta
Bech32ifyPubKey-8 25.0 ± 0% 25.0 ± 0% ~ (all equal)
GetPubKeyFromBech32-8 85.0 ± 0% 85.0 ± 0% ~ (all equal)
ParseCoin-8 71.0 ± 0% 71.0 ± 0% ~ (all equal)
MarshalTo-8 2.00 ± 0% 2.00 ± 0% ~ (all equal)
UintMarshal-8 31.0 ± 0% 25.0 ± 0% -19.35% (p=0.000 n=10+10)
IntMarshal-8 24.0 ± 0% 18.0 ± 0% -25.00% (p=0.000 n=10+10)
name old speed new speed delta
UintMarshal-8 2.27MB/s ±15% 2.75MB/s ± 2% +20.87% (p=0.000 n=10+8)
IntMarshal-8 2.78MB/s ± 9% 3.60MB/s ± 2% +29.69% (p=0.000 n=10+10)
Fixes #8575
Co-authored-by: Alessio Treglia <alessio@tendermint.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
2021-02-15 02:53:10 -08:00
|
|
|
if u.i.BitLen() == 0 { // The value 0
|
2020-01-24 07:32:00 -08:00
|
|
|
copy(data, []byte{0x30})
|
|
|
|
return 1, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
bz, err := u.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
copy(data, bz)
|
|
|
|
return len(bz), nil
|
2019-02-19 14:59:03 -08:00
|
|
|
}
|
|
|
|
|
2020-01-24 07:32:00 -08:00
|
|
|
// Unmarshal implements the gogo proto custom type interface.
|
|
|
|
func (u *Uint) Unmarshal(data []byte) error {
|
|
|
|
if len(data) == 0 {
|
|
|
|
u = nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if u.i == nil {
|
|
|
|
u.i = new(big.Int)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := u.i.UnmarshalText(data); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if u.i.BitLen() > maxBitLen {
|
|
|
|
return fmt.Errorf("integer out of range; got: %d, max: %d", u.i.BitLen(), maxBitLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size implements the gogo proto custom type interface.
|
|
|
|
func (u *Uint) Size() int {
|
|
|
|
bz, _ := u.Marshal()
|
|
|
|
return len(bz)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Override Amino binary serialization by proxying to protobuf.
|
|
|
|
func (u Uint) MarshalAmino() ([]byte, error) { return u.Marshal() }
|
|
|
|
func (u *Uint) UnmarshalAmino(bz []byte) error { return u.Unmarshal(bz) }
|
|
|
|
|
2019-02-19 14:59:03 -08:00
|
|
|
// UintOverflow returns true if a given unsigned integer overflows and false
|
|
|
|
// otherwise.
|
|
|
|
func UintOverflow(i *big.Int) error {
|
|
|
|
if i.Sign() < 0 {
|
|
|
|
return errors.New("non-positive integer")
|
|
|
|
}
|
|
|
|
if i.BitLen() > 256 {
|
|
|
|
return fmt.Errorf("bit length %d greater than 256", i.BitLen())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ParseUint reads a string-encoded Uint value and return a Uint.
|
|
|
|
func ParseUint(s string) (Uint, error) {
|
|
|
|
i, ok := new(big.Int).SetString(s, 0)
|
|
|
|
if !ok {
|
|
|
|
return Uint{}, fmt.Errorf("cannot convert %q to big.Int", s)
|
|
|
|
}
|
|
|
|
return checkNewUint(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkNewUint(i *big.Int) (Uint, error) {
|
|
|
|
if err := UintOverflow(i); err != nil {
|
|
|
|
return Uint{}, err
|
|
|
|
}
|
|
|
|
return Uint{i}, nil
|
|
|
|
}
|
2019-12-19 13:46:43 -08:00
|
|
|
|
|
|
|
// RelativePow raises x to the power of n, where x (and the result, z) are scaled by factor b
|
|
|
|
// for example, RelativePow(210, 2, 100) = 441 (2.1^2 = 4.41)
|
|
|
|
func RelativePow(x Uint, n Uint, b Uint) (z Uint) {
|
|
|
|
if x.IsZero() {
|
|
|
|
if n.IsZero() {
|
|
|
|
z = b // 0^0 = 1
|
|
|
|
return
|
|
|
|
}
|
|
|
|
z = ZeroUint() // otherwise 0^a = 0
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
z = x
|
|
|
|
if n.Mod(NewUint(2)).Equal(ZeroUint()) {
|
|
|
|
z = b
|
|
|
|
}
|
|
|
|
|
|
|
|
halfOfB := b.Quo(NewUint(2))
|
|
|
|
n = n.Quo(NewUint(2))
|
|
|
|
|
|
|
|
for n.GT(ZeroUint()) {
|
|
|
|
xSquared := x.Mul(x)
|
|
|
|
xSquaredRounded := xSquared.Add(halfOfB)
|
|
|
|
|
|
|
|
x = xSquaredRounded.Quo(b)
|
|
|
|
|
|
|
|
if n.Mod(NewUint(2)).Equal(OneUint()) {
|
|
|
|
zx := z.Mul(x)
|
|
|
|
zxRounded := zx.Add(halfOfB)
|
|
|
|
z = zxRounded.Quo(b)
|
|
|
|
}
|
|
|
|
n = n.Quo(NewUint(2))
|
|
|
|
}
|
|
|
|
return z
|
|
|
|
}
|