// uint256: Fixed size 256-bit math library
// Copyright 2020 uint256 Authors
// SPDX-License-Identifier: BSD-3-Clause

package uint256

import (
	"database/sql"
	"database/sql/driver"
	"encoding"
	"encoding/binary"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math"
	"math/big"
	"math/bits"
	"strings"
)

const (
	maxWords = 256 / bits.UintSize // number of big.Words in 256-bit

	// The constants below work as compile-time checks: in case evaluated to
	// negative value it cannot be assigned to uint type and compilation fails.
	// These particular expressions check if maxWords either 4 or 8 matching
	// 32-bit and 64-bit architectures.
	_ uint = -(maxWords & (maxWords - 1)) // maxWords is power of two.
	_ uint = -(maxWords & ^(4 | 8))       // maxWords is 4 or 8.
)

// Compile time interface checks
var (
	_ driver.Valuer            = (*Int)(nil)
	_ sql.Scanner              = (*Int)(nil)
	_ encoding.TextMarshaler   = (*Int)(nil)
	_ encoding.TextUnmarshaler = (*Int)(nil)
	_ json.Marshaler           = (*Int)(nil)
	_ json.Unmarshaler         = (*Int)(nil)
)

// ToBig returns a big.Int version of z.
// Return `nil` if z is nil
func (z *Int) ToBig() *big.Int {
	if z == nil {
		return nil
	}
	var b *big.Int
	z.IntoBig(&b)
	return b
}

// IntoBig sets a provided big.Int to the value of z.
// Sets `nil` if z is nil (thus the double pointer).
func (z *Int) IntoBig(b **big.Int) {
	if z == nil {
		*b = nil
		return
	}
	if *b == nil {
		*b = new(big.Int)
	}
	switch maxWords { // Compile-time check.
	case 4: // 64-bit architectures.
		if words := (*b).Bits(); cap(words) >= 4 {
			// Enough underlying space to set all the uint256 data
			words = words[:4]

			words[0] = big.Word(z[0])
			words[1] = big.Word(z[1])
			words[2] = big.Word(z[2])
			words[3] = big.Word(z[3])

			// Feed it back to normalize (up or down within the big.Int)
			(*b).SetBits(words)
		} else {
			// Not enough space to set all the words, have to allocate
			words := [4]big.Word{big.Word(z[0]), big.Word(z[1]), big.Word(z[2]), big.Word(z[3])}
			(*b).SetBits(words[:])
		}
	case 8: // 32-bit architectures.
		if words := (*b).Bits(); cap(words) >= 8 {
			// Enough underlying space to set all the uint256 data
			words = words[:8]

			words[0], words[1] = big.Word(z[0]), big.Word(z[0]>>32)
			words[2], words[3] = big.Word(z[1]), big.Word(z[1]>>32)
			words[4], words[5] = big.Word(z[2]), big.Word(z[2]>>32)
			words[6], words[7] = big.Word(z[3]), big.Word(z[3]>>32)

			// Feed it back to normalize (up or down within the big.Int)
			(*b).SetBits(words)
		} else {
			// Not enough space to set all the words, have to allocate
			words := [8]big.Word{
				big.Word(z[0]), big.Word(z[0] >> 32),
				big.Word(z[1]), big.Word(z[1] >> 32),
				big.Word(z[2]), big.Word(z[2] >> 32),
				big.Word(z[3]), big.Word(z[3] >> 32),
			}
			(*b).SetBits(words[:])
		}
	}
}

// FromBig is a convenience-constructor from big.Int.
// Returns a new Int and whether overflow occurred.
// OBS: If b is `nil`, this method returns `nil, false`
func FromBig(b *big.Int) (*Int, bool) {
	if b == nil {
		return nil, false
	}
	z := &Int{}
	overflow := z.SetFromBig(b)
	return z, overflow
}

// MustFromBig is a convenience-constructor from big.Int.
// Returns a new Int and panics if overflow occurred.
// OBS: If b is `nil`, this method does _not_ panic, but
// instead returns `nil`
func MustFromBig(b *big.Int) *Int {
	if b == nil {
		return nil
	}
	z := &Int{}
	if z.SetFromBig(b) {
		panic("overflow")
	}
	return z
}

// Float64 returns the float64 value nearest to x.
//
// Note: The `big.Float` version of `Float64` also returns an 'Accuracy', indicating
// whether the value was too small or too large to be represented by a
// `float64`. However, the `uint256` type is unable to represent values
// out of scope (|x| < math.SmallestNonzeroFloat64 or |x| > math.MaxFloat64),
// therefore this method does not return any accuracy.
func (z *Int) Float64() float64 {
	if z.IsUint64() {
		return float64(z.Uint64())
	}
	// See [1] for a detailed walkthrough of IEEE 754 conversion
	//
	// 1: https://www.wikihow.com/Convert-a-Number-from-Decimal-to-IEEE-754-Floating-Point-Representation

	bitlen := uint64(z.BitLen())

	// Normalize the number, by shifting it so that the MSB is shifted out.
	y := new(Int).Lsh(z, uint(1+256-bitlen))
	// The number with the leading 1 shifted out is the fraction.
	fraction := y[3]

	// The exp is calculated from the number of shifts, adjusted with the bias.
	// double-precision uses 1023 as bias
	biased_exp := 1023 + bitlen - 1

	// The IEEE 754 double-precision layout is as follows:
	//  1 sign bit (we don't bother with this, since it's always zero for uints)
	// 11 exponent bits
	// 52 fraction bits
	// --------
	// 64 bits

	return math.Float64frombits(biased_exp<<52 | fraction>>12)
}

// SetFromHex sets z from the given string, interpreted as a hexadecimal number.
// OBS! This method is _not_ strictly identical to the (*big.Int).SetString(..., 16) method.
// Notable differences:
// - This method _require_ "0x" or "0X" prefix.
// - This method does not accept zero-prefixed hex, e.g. "0x0001"
// - This method does not accept underscore input, e.g. "100_000",
// - This method does not accept negative zero as valid, e.g "-0x0",
//   - (this method does not accept any negative input as valid)
func (z *Int) SetFromHex(hex string) error {
	return z.fromHex(hex)
}

// fromHex is the internal implementation of parsing a hex-string.
func (z *Int) fromHex(hex string) error {
	if err := checkNumberS(hex); err != nil {
		return err
	}
	if len(hex) > 66 {
		return ErrBig256Range
	}
	z.Clear()
	end := len(hex)
	for i := 0; i < 4; i++ {
		start := end - 16
		if start < 2 {
			start = 2
		}
		for ri := start; ri < end; ri++ {
			nib := bintable[hex[ri]]
			if nib == badNibble {
				return ErrSyntax
			}
			z[i] = z[i] << 4
			z[i] += uint64(nib)
		}
		end = start
	}
	return nil
}

// FromHex is a convenience-constructor to create an Int from
// a hexadecimal string. The string is required to be '0x'-prefixed
// Numbers larger than 256 bits are not accepted.
func FromHex(hex string) (*Int, error) {
	var z Int
	if err := z.fromHex(hex); err != nil {
		return nil, err
	}
	return &z, nil
}

// MustFromHex is a convenience-constructor to create an Int from
// a hexadecimal string.
// Returns a new Int and panics if any error occurred.
func MustFromHex(hex string) *Int {
	var z Int
	if err := z.fromHex(hex); err != nil {
		panic(err)
	}
	return &z
}

// UnmarshalText implements encoding.TextUnmarshaler. This method
// can unmarshal either hexadecimal or decimal.
// - For hexadecimal, the input _must_ be prefixed with 0x or 0X
func (z *Int) UnmarshalText(input []byte) error {
	if len(input) >= 2 && input[0] == '0' && (input[1] == 'x' || input[1] == 'X') {
		return z.fromHex(string(input))
	}
	return z.SetFromDecimal(string(input))
}

// SetFromBig converts a big.Int to Int and sets the value to z.
// TODO: Ensure we have sufficient testing, esp for negative bigints.
func (z *Int) SetFromBig(b *big.Int) bool {
	z.Clear()
	words := b.Bits()
	overflow := len(words) > maxWords

	switch maxWords { // Compile-time check.
	case 4: // 64-bit architectures.
		if len(words) > 0 {
			z[0] = uint64(words[0])
			if len(words) > 1 {
				z[1] = uint64(words[1])
				if len(words) > 2 {
					z[2] = uint64(words[2])
					if len(words) > 3 {
						z[3] = uint64(words[3])
					}
				}
			}
		}
	case 8: // 32-bit architectures.
		numWords := len(words)
		if overflow {
			numWords = maxWords
		}
		for i := 0; i < numWords; i++ {
			if i%2 == 0 {
				z[i/2] = uint64(words[i])
			} else {
				z[i/2] |= uint64(words[i]) << 32
			}
		}
	}

	if b.Sign() == -1 {
		z.Neg(z)
	}
	return overflow
}

// Format implements fmt.Formatter. It accepts the formats
// 'b' (binary), 'o' (octal with 0 prefix), 'O' (octal with 0o prefix),
// 'd' (decimal), 'x' (lowercase hexadecimal), and
// 'X' (uppercase hexadecimal).
// Also supported are the full suite of package fmt's format
// flags for integral types, including '+' and ' ' for sign
// control, '#' for leading zero in octal and for hexadecimal,
// a leading "0x" or "0X" for "%#x" and "%#X" respectively,
// specification of minimum digits precision, output field
// width, space or zero padding, and '-' for left or right
// justification.
func (z *Int) Format(s fmt.State, ch rune) {
	z.ToBig().Format(s, ch)
}

// SetBytes8 is identical to SetBytes(in[:8]), but panics is input is too short
func (z *Int) SetBytes8(in []byte) *Int {
	_ = in[7] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = binary.BigEndian.Uint64(in[0:8])
	return z
}

// SetBytes16 is identical to SetBytes(in[:16]), but panics is input is too short
func (z *Int) SetBytes16(in []byte) *Int {
	_ = in[15] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = binary.BigEndian.Uint64(in[0:8])
	z[0] = binary.BigEndian.Uint64(in[8:16])
	return z
}

// SetBytes16 is identical to SetBytes(in[:24]), but panics is input is too short
func (z *Int) SetBytes24(in []byte) *Int {
	_ = in[23] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = binary.BigEndian.Uint64(in[0:8])
	z[1] = binary.BigEndian.Uint64(in[8:16])
	z[0] = binary.BigEndian.Uint64(in[16:24])
	return z
}

func (z *Int) SetBytes32(in []byte) *Int {
	_ = in[31] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = binary.BigEndian.Uint64(in[0:8])
	z[2] = binary.BigEndian.Uint64(in[8:16])
	z[1] = binary.BigEndian.Uint64(in[16:24])
	z[0] = binary.BigEndian.Uint64(in[24:32])
	return z
}

func (z *Int) SetBytes1(in []byte) *Int {
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = uint64(in[0])
	return z
}

func (z *Int) SetBytes9(in []byte) *Int {
	_ = in[8] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = uint64(in[0])
	z[0] = binary.BigEndian.Uint64(in[1:9])
	return z
}

func (z *Int) SetBytes17(in []byte) *Int {
	_ = in[16] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = uint64(in[0])
	z[1] = binary.BigEndian.Uint64(in[1:9])
	z[0] = binary.BigEndian.Uint64(in[9:17])
	return z
}

func (z *Int) SetBytes25(in []byte) *Int {
	_ = in[24] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = uint64(in[0])
	z[2] = binary.BigEndian.Uint64(in[1:9])
	z[1] = binary.BigEndian.Uint64(in[9:17])
	z[0] = binary.BigEndian.Uint64(in[17:25])
	return z
}

func (z *Int) SetBytes2(in []byte) *Int {
	_ = in[1] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = uint64(binary.BigEndian.Uint16(in[0:2]))
	return z
}

func (z *Int) SetBytes10(in []byte) *Int {
	_ = in[9] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = uint64(binary.BigEndian.Uint16(in[0:2]))
	z[0] = binary.BigEndian.Uint64(in[2:10])
	return z
}

func (z *Int) SetBytes18(in []byte) *Int {
	_ = in[17] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = uint64(binary.BigEndian.Uint16(in[0:2]))
	z[1] = binary.BigEndian.Uint64(in[2:10])
	z[0] = binary.BigEndian.Uint64(in[10:18])
	return z
}

func (z *Int) SetBytes26(in []byte) *Int {
	_ = in[25] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = uint64(binary.BigEndian.Uint16(in[0:2]))
	z[2] = binary.BigEndian.Uint64(in[2:10])
	z[1] = binary.BigEndian.Uint64(in[10:18])
	z[0] = binary.BigEndian.Uint64(in[18:26])
	return z
}

func (z *Int) SetBytes3(in []byte) *Int {
	_ = in[2] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16
	return z
}

func (z *Int) SetBytes11(in []byte) *Int {
	_ = in[10] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16
	z[0] = binary.BigEndian.Uint64(in[3:11])
	return z
}

func (z *Int) SetBytes19(in []byte) *Int {
	_ = in[18] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16
	z[1] = binary.BigEndian.Uint64(in[3:11])
	z[0] = binary.BigEndian.Uint64(in[11:19])
	return z
}

func (z *Int) SetBytes27(in []byte) *Int {
	_ = in[26] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = uint64(binary.BigEndian.Uint16(in[1:3])) | uint64(in[0])<<16
	z[2] = binary.BigEndian.Uint64(in[3:11])
	z[1] = binary.BigEndian.Uint64(in[11:19])
	z[0] = binary.BigEndian.Uint64(in[19:27])
	return z
}

func (z *Int) SetBytes4(in []byte) *Int {
	_ = in[3] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = uint64(binary.BigEndian.Uint32(in[0:4]))
	return z
}

func (z *Int) SetBytes12(in []byte) *Int {
	_ = in[11] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = uint64(binary.BigEndian.Uint32(in[0:4]))
	z[0] = binary.BigEndian.Uint64(in[4:12])
	return z
}

func (z *Int) SetBytes20(in []byte) *Int {
	_ = in[19] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = uint64(binary.BigEndian.Uint32(in[0:4]))
	z[1] = binary.BigEndian.Uint64(in[4:12])
	z[0] = binary.BigEndian.Uint64(in[12:20])
	return z
}

func (z *Int) SetBytes28(in []byte) *Int {
	_ = in[27] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = uint64(binary.BigEndian.Uint32(in[0:4]))
	z[2] = binary.BigEndian.Uint64(in[4:12])
	z[1] = binary.BigEndian.Uint64(in[12:20])
	z[0] = binary.BigEndian.Uint64(in[20:28])
	return z
}

func (z *Int) SetBytes5(in []byte) *Int {
	_ = in[4] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = bigEndianUint40(in[0:5])
	return z
}

func (z *Int) SetBytes13(in []byte) *Int {
	_ = in[12] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = bigEndianUint40(in[0:5])
	z[0] = binary.BigEndian.Uint64(in[5:13])
	return z
}

func (z *Int) SetBytes21(in []byte) *Int {
	_ = in[20] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = bigEndianUint40(in[0:5])
	z[1] = binary.BigEndian.Uint64(in[5:13])
	z[0] = binary.BigEndian.Uint64(in[13:21])
	return z
}

func (z *Int) SetBytes29(in []byte) *Int {
	_ = in[28] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = bigEndianUint40(in[0:5])
	z[2] = binary.BigEndian.Uint64(in[5:13])
	z[1] = binary.BigEndian.Uint64(in[13:21])
	z[0] = binary.BigEndian.Uint64(in[21:29])
	return z
}

func (z *Int) SetBytes6(in []byte) *Int {
	_ = in[5] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = bigEndianUint48(in[0:6])
	return z
}

func (z *Int) SetBytes14(in []byte) *Int {
	_ = in[13] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = bigEndianUint48(in[0:6])
	z[0] = binary.BigEndian.Uint64(in[6:14])
	return z
}

func (z *Int) SetBytes22(in []byte) *Int {
	_ = in[21] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = bigEndianUint48(in[0:6])
	z[1] = binary.BigEndian.Uint64(in[6:14])
	z[0] = binary.BigEndian.Uint64(in[14:22])
	return z
}

func (z *Int) SetBytes30(in []byte) *Int {
	_ = in[29] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = bigEndianUint48(in[0:6])
	z[2] = binary.BigEndian.Uint64(in[6:14])
	z[1] = binary.BigEndian.Uint64(in[14:22])
	z[0] = binary.BigEndian.Uint64(in[22:30])
	return z
}

func (z *Int) SetBytes7(in []byte) *Int {
	_ = in[6] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2], z[1] = 0, 0, 0
	z[0] = bigEndianUint56(in[0:7])
	return z
}

func (z *Int) SetBytes15(in []byte) *Int {
	_ = in[14] // bounds check hint to compiler; see golang.org/issue/14808
	z[3], z[2] = 0, 0
	z[1] = bigEndianUint56(in[0:7])
	z[0] = binary.BigEndian.Uint64(in[7:15])
	return z
}

func (z *Int) SetBytes23(in []byte) *Int {
	_ = in[22] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = 0
	z[2] = bigEndianUint56(in[0:7])
	z[1] = binary.BigEndian.Uint64(in[7:15])
	z[0] = binary.BigEndian.Uint64(in[15:23])
	return z
}

func (z *Int) SetBytes31(in []byte) *Int {
	_ = in[30] // bounds check hint to compiler; see golang.org/issue/14808
	z[3] = bigEndianUint56(in[0:7])
	z[2] = binary.BigEndian.Uint64(in[7:15])
	z[1] = binary.BigEndian.Uint64(in[15:23])
	z[0] = binary.BigEndian.Uint64(in[23:31])
	return z
}

// Utility methods that are "missing" among the bigEndian.UintXX methods.

func bigEndianUint40(b []byte) uint64 {
	_ = b[4] // bounds check hint to compiler; see golang.org/issue/14808
	return uint64(b[4]) | uint64(b[3])<<8 | uint64(b[2])<<16 | uint64(b[1])<<24 |
		uint64(b[0])<<32
}

func bigEndianUint48(b []byte) uint64 {
	_ = b[5] // bounds check hint to compiler; see golang.org/issue/14808
	return uint64(b[5]) | uint64(b[4])<<8 | uint64(b[3])<<16 | uint64(b[2])<<24 |
		uint64(b[1])<<32 | uint64(b[0])<<40
}

func bigEndianUint56(b []byte) uint64 {
	_ = b[6] // bounds check hint to compiler; see golang.org/issue/14808
	return uint64(b[6]) | uint64(b[5])<<8 | uint64(b[4])<<16 | uint64(b[3])<<24 |
		uint64(b[2])<<32 | uint64(b[1])<<40 | uint64(b[0])<<48
}

// MarshalSSZAppend _almost_ implements the fastssz.Marshaler (see below) interface.
// Originally, this method was named `MarshalSSZTo`, and ostensibly implemented the interface.
// However, it was noted (https://github.com/holiman/uint256/issues/170) that the
// actual implementation did not match the intended semantics of the interface: it
// inserted the data instead of appending.
//
// Therefore, the `MarshalSSZTo` has been removed: to force users into making a choice:
//   - Use `MarshalSSZAppend`: this is the method that appends to the destination buffer,
//     and returns a potentially newly allocated buffer. This method will become `MarshalSSZTo`
//     in some future release.
//   - Or use `MarshalSSZInto`: this is the original method which places the data into
//     the destination buffer, without ever reallocating.
//
// fastssz.Marshaler interface:
//
//	 https://github.com/ferranbt/fastssz/blob/main/interface.go#L4
//		type Marshaler interface {
//			MarshalSSZTo(dst []byte) ([]byte, error)
//			MarshalSSZ() ([]byte, error)
//			SizeSSZ() int
//		}
func (z *Int) MarshalSSZAppend(dst []byte) ([]byte, error) {
	dst = binary.LittleEndian.AppendUint64(dst, z[0])
	dst = binary.LittleEndian.AppendUint64(dst, z[1])
	dst = binary.LittleEndian.AppendUint64(dst, z[2])
	dst = binary.LittleEndian.AppendUint64(dst, z[3])
	return dst, nil
}

// MarshalSSZInto is the first attempt to implement the fastssz.Marshaler interface,
// but which does not obey the intended semantics. See MarshalSSZAppend and
// - https://github.com/holiman/uint256/pull/171
// - https://github.com/holiman/uint256/issues/170
// @deprecated
func (z *Int) MarshalSSZInto(dst []byte) ([]byte, error) {
	if len(dst) < 32 {
		return nil, fmt.Errorf("%w: have %d, want %d bytes", ErrBadBufferLength, len(dst), 32)
	}
	binary.LittleEndian.PutUint64(dst[0:8], z[0])
	binary.LittleEndian.PutUint64(dst[8:16], z[1])
	binary.LittleEndian.PutUint64(dst[16:24], z[2])
	binary.LittleEndian.PutUint64(dst[24:32], z[3])

	return dst[32:], nil
}

// MarshalSSZ implements the fastssz.Marshaler interface and returns the integer
// marshalled into a newly allocated byte slice.
func (z *Int) MarshalSSZ() ([]byte, error) {
	blob, _ := z.MarshalSSZAppend(make([]byte, 0, 32)) // ignore error, cannot fail, surely have 32 byte space in blob
	return blob, nil
}

// SizeSSZ implements the fastssz.Marshaler interface and returns the byte size
// of the 256 bit int.
func (*Int) SizeSSZ() int {
	return 32
}

// UnmarshalSSZ implements the fastssz.Unmarshaler interface and parses an encoded
// integer into the local struct.
func (z *Int) UnmarshalSSZ(buf []byte) error {
	if len(buf) != 32 {
		return fmt.Errorf("%w: have %d, want %d bytes", ErrBadEncodedLength, len(buf), 32)
	}
	z[0] = binary.LittleEndian.Uint64(buf[0:8])
	z[1] = binary.LittleEndian.Uint64(buf[8:16])
	z[2] = binary.LittleEndian.Uint64(buf[16:24])
	z[3] = binary.LittleEndian.Uint64(buf[24:32])

	return nil
}

// HashTreeRoot implements the fastssz.HashRoot interface's non-dependent part.
func (z *Int) HashTreeRoot() ([32]byte, error) {
	b, _ := z.MarshalSSZAppend(make([]byte, 0, 32)) // ignore error, cannot fail
	var hash [32]byte
	copy(hash[:], b)
	return hash, nil
}

// EncodeRLP implements the rlp.Encoder interface from go-ethereum
// and writes the RLP encoding of z to w.
func (z *Int) EncodeRLP(w io.Writer) error {
	if z == nil {
		_, err := w.Write([]byte{0x80})
		return err
	}
	nBits := z.BitLen()
	if nBits == 0 {
		_, err := w.Write([]byte{0x80})
		return err
	}
	if nBits <= 7 {
		_, err := w.Write([]byte{byte(z[0])})
		return err
	}
	nBytes := byte((nBits + 7) / 8)
	var b [33]byte
	binary.BigEndian.PutUint64(b[1:9], z[3])
	binary.BigEndian.PutUint64(b[9:17], z[2])
	binary.BigEndian.PutUint64(b[17:25], z[1])
	binary.BigEndian.PutUint64(b[25:33], z[0])
	b[32-nBytes] = 0x80 + nBytes
	_, err := w.Write(b[32-nBytes:])
	return err
}

// MarshalText implements encoding.TextMarshaler
// MarshalText marshals using the decimal representation (compatible with big.Int)
func (z *Int) MarshalText() ([]byte, error) {
	return []byte(z.Dec()), nil
}

// MarshalJSON implements json.Marshaler.
// MarshalJSON marshals using the 'decimal string' representation. This is _not_ compatible
// with big.Int: big.Int marshals into JSON 'native' numeric format.
//
// The JSON  native format is, on some platforms, (e.g. javascript), limited to 53-bit large
// integer space. Thus, U256 uses string-format, which is not compatible with
// big.int (big.Int refuses to unmarshal a string representation).
func (z *Int) MarshalJSON() ([]byte, error) {
	return []byte(`"` + z.Dec() + `"`), nil
}

// UnmarshalJSON implements json.Unmarshaler. UnmarshalJSON accepts either
// - Quoted string: either hexadecimal OR decimal
// - Not quoted string: only decimal
func (z *Int) UnmarshalJSON(input []byte) error {
	if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' {
		// if not quoted, it must be decimal
		return z.SetFromDecimal(string(input))
	}
	return z.UnmarshalText(input[1 : len(input)-1])
}

// String returns the decimal encoding of b.
func (z *Int) String() string {
	return z.Dec()
}

const (
	hextable  = "0123456789abcdef"
	bintable  = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\a\b\t\xff\xff\xff\xff\xff\xff\xff\n\v\f\r\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\n\v\f\r\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
	badNibble = 0xff
)

// Hex encodes z in 0x-prefixed hexadecimal form.
func (z *Int) Hex() string {
	// This implementation is not optimal, it allocates a full
	// 66-byte output buffer which it fills. It could instead allocate a smaller
	// buffer, and omit the final crop-stage.
	output := make([]byte, 66)
	nibbles := (z.BitLen() + 3) / 4 // nibbles [0,64]
	if nibbles == 0 {
		nibbles = 1
	}
	// Start with the most significant
	zWord := (nibbles - 1) / 16
	for i := zWord; i >= 0; i-- {
		off := (3 - i) * 16
		output[off+2] = hextable[byte(z[i]>>60)&0xf]
		output[off+3] = hextable[byte(z[i]>>56)&0xf]
		output[off+4] = hextable[byte(z[i]>>52)&0xf]
		output[off+5] = hextable[byte(z[i]>>48)&0xf]
		output[off+6] = hextable[byte(z[i]>>44)&0xf]
		output[off+7] = hextable[byte(z[i]>>40)&0xf]
		output[off+8] = hextable[byte(z[i]>>36)&0xf]
		output[off+9] = hextable[byte(z[i]>>32)&0xf]
		output[off+10] = hextable[byte(z[i]>>28)&0xf]
		output[off+11] = hextable[byte(z[i]>>24)&0xf]
		output[off+12] = hextable[byte(z[i]>>20)&0xf]
		output[off+13] = hextable[byte(z[i]>>16)&0xf]
		output[off+14] = hextable[byte(z[i]>>12)&0xf]
		output[off+15] = hextable[byte(z[i]>>8)&0xf]
		output[off+16] = hextable[byte(z[i]>>4)&0xf]
		output[off+17] = hextable[byte(z[i]&0xF)&0xf]
	}
	output[64-nibbles] = '0'
	output[65-nibbles] = 'x'
	return string(output[64-nibbles:])
}

// Scan implements the database/sql Scanner interface.
// It decodes a string, because that is what postgres uses for its numeric type
func (dst *Int) Scan(src interface{}) error {
	if src == nil {
		dst.Clear()
		return nil
	}
	switch src := src.(type) {
	case string:
		return dst.scanScientificFromString(src)
	case []byte:
		return dst.scanScientificFromString(string(src))
	}
	return errors.New("unsupported type")
}

func (dst *Int) scanScientificFromString(src string) error {
	if len(src) == 0 {
		dst.Clear()
		return nil
	}
	idx := strings.IndexByte(src, 'e')
	if idx == -1 {
		return dst.SetFromDecimal(src)
	}
	if err := dst.SetFromDecimal(src[:idx]); err != nil {
		return err
	}
	if src[(idx+1):] == "0" {
		return nil
	}
	exp := new(Int)
	if err := exp.SetFromDecimal(src[(idx + 1):]); err != nil {
		return err
	}
	if exp.GtUint64(77) { // 10**78 is larger than 2**256
		return ErrBig256Range
	}
	exp.Exp(NewInt(10), exp)
	if _, overflow := dst.MulOverflow(dst, exp); overflow {
		return ErrBig256Range
	}
	return nil
}

// Value implements the database/sql/driver Valuer interface.
// It encodes a base 10 string.
// In Postgres, this will work with both integer and the Numeric/Decimal types
// In MariaDB/MySQL, this will work with the Numeric/Decimal types up to 65 digits, however any more and you should use either VarChar or Char(79)
// In SqLite, use TEXT
func (src *Int) Value() (driver.Value, error) {
	return src.Dec(), nil
}

var (
	ErrEmptyString      = errors.New("empty hex string")
	ErrSyntax           = errors.New("invalid hex string")
	ErrMissingPrefix    = errors.New("hex string without 0x prefix")
	ErrEmptyNumber      = errors.New("hex string \"0x\"")
	ErrLeadingZero      = errors.New("hex number with leading zero digits")
	ErrBig256Range      = errors.New("hex number > 256 bits")
	ErrBadBufferLength  = errors.New("bad ssz buffer length")
	ErrBadEncodedLength = errors.New("bad ssz encoded length")
)

func checkNumberS(input string) error {
	l := len(input)
	if l == 0 {
		return ErrEmptyString
	}
	if l < 2 || input[0] != '0' ||
		(input[1] != 'x' && input[1] != 'X') {
		return ErrMissingPrefix
	}
	if l == 2 {
		return ErrEmptyNumber
	}
	if len(input) > 3 && input[2] == '0' {
		return ErrLeadingZero
	}
	return nil
}
