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 } // BigInt converts Uint to big.Int func (u Uint) BigInt() *big.Int { return new(big.Int).Set(u.i) } // 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)} } var _ CustomProtobufType = (*Uint)(nil) // 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 func (u Uint) LTE(u2 Uint) bool { return !u.GT(u2) } // 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)) } // Quo divides Uint with Uint func (u Uint) Quo(u2 Uint) (res Uint) { return NewUintFromBigInt(div(u.i, u2.i)) } // 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)} } // 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()) } // Quo divides Uint with uint64 func (u Uint) QuoUint64(u2 uint64) Uint { return u.Quo(NewUint(u2)) } // 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() } // MarshalJSON defines custom encoding scheme func (u Uint) MarshalJSON() ([]byte, error) { if u.i == nil { // Necessary since default Uint initialization has i.i as nil u.i = new(big.Int) } return marshalJSON(u.i) } // UnmarshalJSON defines custom decoding scheme func (u *Uint) UnmarshalJSON(bz []byte) error { if u.i == nil { // Necessary since default Uint initialization has i.i as nil u.i = new(big.Int) } return unmarshalJSON(u.i, bz) } // Marshal implements the gogo proto custom type interface. func (u Uint) Marshal() ([]byte, error) { if u.i == nil { u.i = new(big.Int) } return u.i.MarshalText() } // MarshalTo implements the gogo proto custom type interface. func (u *Uint) MarshalTo(data []byte) (n int, err error) { if u.i == nil { u.i = new(big.Int) } if u.i.BitLen() == 0 { // The value 0 copy(data, []byte{0x30}) return 1, nil } bz, err := u.Marshal() if err != nil { return 0, err } copy(data, bz) return len(bz), nil } // 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) } // 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 } // 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 }