mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-06 19:06:42 +01:00
Remove Float16 related files & minor typos fixes
This commit is contained in:
@@ -1,132 +0,0 @@
|
|||||||
// Package common Float16 provides methods to work with Hermez custom half float
|
|
||||||
// precision, 16 bits, codification internally called Float16 has been adopted
|
|
||||||
// to encode large integers. This is done in order to save bits when L2
|
|
||||||
// transactions are published.
|
|
||||||
//nolint:gomnd
|
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/hermeznetwork/tracerr"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// ErrRoundingLoss is used when converted big.Int to Float16 causes rounding loss
|
|
||||||
ErrRoundingLoss = errors.New("input value causes rounding loss")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Float16 represents a float in a 16 bit format
|
|
||||||
type Float16 uint16
|
|
||||||
|
|
||||||
// Bytes return a byte array of length 2 with the Float16 value encoded in BigEndian
|
|
||||||
func (f16 Float16) Bytes() []byte {
|
|
||||||
var b [2]byte
|
|
||||||
binary.BigEndian.PutUint16(b[:], uint16(f16))
|
|
||||||
return b[:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Float16FromBytes returns a Float16 from a byte array of 2 bytes.
|
|
||||||
func Float16FromBytes(b []byte) *Float16 {
|
|
||||||
// WARNING b[:2] for a b where len(b)<2 can break
|
|
||||||
f16 := Float16(binary.BigEndian.Uint16(b[:2]))
|
|
||||||
return &f16
|
|
||||||
}
|
|
||||||
|
|
||||||
// BigInt converts the Float16 to a *big.Int integer
|
|
||||||
func (f16 *Float16) BigInt() *big.Int {
|
|
||||||
fl := int64(*f16)
|
|
||||||
|
|
||||||
m := big.NewInt(fl & 0x3FF)
|
|
||||||
e := big.NewInt(fl >> 11)
|
|
||||||
e5 := (fl >> 10) & 0x01
|
|
||||||
|
|
||||||
exp := big.NewInt(0).Exp(big.NewInt(10), e, nil)
|
|
||||||
res := m.Mul(m, exp)
|
|
||||||
|
|
||||||
if e5 != 0 && e.Cmp(big.NewInt(0)) != 0 {
|
|
||||||
res.Add(res, exp.Div(exp, big.NewInt(2)))
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// floorFix2Float converts a fix to a float, always rounding down
|
|
||||||
func floorFix2Float(_f *big.Int) Float16 {
|
|
||||||
zero := big.NewInt(0)
|
|
||||||
ten := big.NewInt(10)
|
|
||||||
e := int64(0)
|
|
||||||
|
|
||||||
m := big.NewInt(0)
|
|
||||||
m.Set(_f)
|
|
||||||
|
|
||||||
if m.Cmp(zero) == 0 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
s := big.NewInt(0).Rsh(m, 10)
|
|
||||||
|
|
||||||
for s.Cmp(zero) != 0 {
|
|
||||||
m.Div(m, ten)
|
|
||||||
s.Rsh(m, 10)
|
|
||||||
e++
|
|
||||||
}
|
|
||||||
|
|
||||||
return Float16(m.Int64() | e<<11)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFloat16 encodes a *big.Int integer as a Float16, returning error in
|
|
||||||
// case of loss during the encoding.
|
|
||||||
func NewFloat16(f *big.Int) (Float16, error) {
|
|
||||||
fl1 := floorFix2Float(f)
|
|
||||||
fi1 := fl1.BigInt()
|
|
||||||
fl2 := fl1 | 0x400
|
|
||||||
fi2 := fl2.BigInt()
|
|
||||||
|
|
||||||
m3 := (fl1 & 0x3FF) + 1
|
|
||||||
e3 := fl1 >> 11
|
|
||||||
|
|
||||||
if m3&0x400 == 0 {
|
|
||||||
m3 = 0x66
|
|
||||||
e3++
|
|
||||||
}
|
|
||||||
|
|
||||||
fl3 := m3 + e3<<11
|
|
||||||
fi3 := fl3.BigInt()
|
|
||||||
|
|
||||||
res := fl1
|
|
||||||
|
|
||||||
d := big.NewInt(0).Abs(fi1.Sub(fi1, f))
|
|
||||||
d2 := big.NewInt(0).Abs(fi2.Sub(fi2, f))
|
|
||||||
|
|
||||||
if d.Cmp(d2) == 1 {
|
|
||||||
res = fl2
|
|
||||||
d = d2
|
|
||||||
}
|
|
||||||
|
|
||||||
d3 := big.NewInt(0).Abs(fi3.Sub(fi3, f))
|
|
||||||
|
|
||||||
if d.Cmp(d3) == 1 {
|
|
||||||
res = fl3
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do rounding check
|
|
||||||
if res.BigInt().Cmp(f) == 0 {
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
return res, tracerr.Wrap(ErrRoundingLoss)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFloat16Floor encodes a big.Int integer as a Float16, rounding down in
|
|
||||||
// case of loss during the encoding.
|
|
||||||
func NewFloat16Floor(f *big.Int) Float16 {
|
|
||||||
fl1 := floorFix2Float(f)
|
|
||||||
fl2 := fl1 | 0x400
|
|
||||||
fi2 := fl2.BigInt()
|
|
||||||
|
|
||||||
if fi2.Cmp(f) < 1 {
|
|
||||||
return fl2
|
|
||||||
}
|
|
||||||
return fl1
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/hermeznetwork/tracerr"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConversionsFloat16(t *testing.T) {
|
|
||||||
testVector := map[Float16]string{
|
|
||||||
0x307B: "123000000",
|
|
||||||
0x1DC6: "454500",
|
|
||||||
0xFFFF: "10235000000000000000000000000000000",
|
|
||||||
0x0000: "0",
|
|
||||||
0x0400: "0",
|
|
||||||
0x0001: "1",
|
|
||||||
0x0401: "1",
|
|
||||||
0x0800: "0",
|
|
||||||
0x0c00: "5",
|
|
||||||
0x0801: "10",
|
|
||||||
0x0c01: "15",
|
|
||||||
}
|
|
||||||
|
|
||||||
for test := range testVector {
|
|
||||||
fix := test.BigInt()
|
|
||||||
|
|
||||||
assert.Equal(t, fix.String(), testVector[test])
|
|
||||||
|
|
||||||
bi := big.NewInt(0)
|
|
||||||
bi.SetString(testVector[test], 10)
|
|
||||||
|
|
||||||
fl, err := NewFloat16(bi)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
fx2 := fl.BigInt()
|
|
||||||
assert.Equal(t, fx2.String(), testVector[test])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFloorFix2FloatFloat16(t *testing.T) {
|
|
||||||
testVector := map[string]Float16{
|
|
||||||
"87999990000000000": 0x776f,
|
|
||||||
"87950000000000001": 0x776f,
|
|
||||||
"87950000000000000": 0x776f,
|
|
||||||
"87949999999999999": 0x736f,
|
|
||||||
}
|
|
||||||
|
|
||||||
for test := range testVector {
|
|
||||||
bi := big.NewInt(0)
|
|
||||||
bi.SetString(test, 10)
|
|
||||||
|
|
||||||
testFloat := NewFloat16Floor(bi)
|
|
||||||
|
|
||||||
assert.Equal(t, testFloat, testVector[test])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConversionLossesFloat16(t *testing.T) {
|
|
||||||
a := big.NewInt(1000)
|
|
||||||
b, err := NewFloat16(a)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
c := b.BigInt()
|
|
||||||
assert.Equal(t, c, a)
|
|
||||||
|
|
||||||
a = big.NewInt(1024)
|
|
||||||
b, err = NewFloat16(a)
|
|
||||||
assert.Equal(t, ErrRoundingLoss, tracerr.Unwrap(err))
|
|
||||||
c = b.BigInt()
|
|
||||||
assert.NotEqual(t, c, a)
|
|
||||||
|
|
||||||
a = big.NewInt(32767)
|
|
||||||
b, err = NewFloat16(a)
|
|
||||||
assert.Equal(t, ErrRoundingLoss, tracerr.Unwrap(err))
|
|
||||||
c = b.BigInt()
|
|
||||||
assert.NotEqual(t, c, a)
|
|
||||||
|
|
||||||
a = big.NewInt(32768)
|
|
||||||
b, err = NewFloat16(a)
|
|
||||||
assert.Equal(t, ErrRoundingLoss, tracerr.Unwrap(err))
|
|
||||||
c = b.BigInt()
|
|
||||||
assert.NotEqual(t, c, a)
|
|
||||||
|
|
||||||
a = big.NewInt(65536000)
|
|
||||||
b, err = NewFloat16(a)
|
|
||||||
assert.Equal(t, ErrRoundingLoss, tracerr.Unwrap(err))
|
|
||||||
c = b.BigInt()
|
|
||||||
assert.NotEqual(t, c, a)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFloat16(b *testing.B) {
|
|
||||||
newBigInt := func(s string) *big.Int {
|
|
||||||
bigInt, ok := new(big.Int).SetString(s, 10)
|
|
||||||
if !ok {
|
|
||||||
panic("Bad big int")
|
|
||||||
}
|
|
||||||
return bigInt
|
|
||||||
}
|
|
||||||
type pair struct {
|
|
||||||
Float16 Float16
|
|
||||||
BigInt *big.Int
|
|
||||||
}
|
|
||||||
testVector := []pair{
|
|
||||||
{0x307B, newBigInt("123000000")},
|
|
||||||
{0x1DC6, newBigInt("454500")},
|
|
||||||
{0xFFFF, newBigInt("10235000000000000000000000000000000")},
|
|
||||||
{0x0000, newBigInt("0")},
|
|
||||||
{0x0400, newBigInt("0")},
|
|
||||||
{0x0001, newBigInt("1")},
|
|
||||||
{0x0401, newBigInt("1")},
|
|
||||||
{0x0800, newBigInt("0")},
|
|
||||||
{0x0c00, newBigInt("5")},
|
|
||||||
{0x0801, newBigInt("10")},
|
|
||||||
{0x0c01, newBigInt("15")},
|
|
||||||
}
|
|
||||||
b.Run("floorFix2Float()", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
NewFloat16Floor(testVector[i%len(testVector)].BigInt)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("NewFloat16()", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, _ = NewFloat16(testVector[i%len(testVector)].BigInt)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
b.Run("Float16.BigInt()", func(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
testVector[i%len(testVector)].Float16.BigInt()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -24,8 +23,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrFloat40Overflow is used when a given nonce overflows the maximum
|
// ErrFloat40Overflow is used when a given Float40 overflows the
|
||||||
// capacity of the Float40 (2**40-1)
|
// maximum capacity of the Float40 (2**40-1)
|
||||||
ErrFloat40Overflow = errors.New("Float40 overflow, max value: 2**40 -1")
|
ErrFloat40Overflow = errors.New("Float40 overflow, max value: 2**40 -1")
|
||||||
// ErrFloat40E31 is used when the e > 31 when trying to convert a
|
// ErrFloat40E31 is used when the e > 31 when trying to convert a
|
||||||
// *big.Int to Float40
|
// *big.Int to Float40
|
||||||
@@ -88,15 +87,14 @@ func NewFloat40(f *big.Int) (Float40, error) {
|
|||||||
zero := big.NewInt(0)
|
zero := big.NewInt(0)
|
||||||
ten := big.NewInt(10)
|
ten := big.NewInt(10)
|
||||||
thres := big.NewInt(0x08_00_00_00_00)
|
thres := big.NewInt(0x08_00_00_00_00)
|
||||||
for bytes.Equal(zero.Bytes(), new(big.Int).Mod(m, ten).Bytes()) &&
|
for new(big.Int).Mod(m, ten).Cmp(zero) == 0 && m.Cmp(thres) >= 0 {
|
||||||
!bytes.Equal(zero.Bytes(), new(big.Int).Div(m, thres).Bytes()) {
|
|
||||||
m = new(big.Int).Div(m, ten)
|
m = new(big.Int).Div(m, ten)
|
||||||
e = new(big.Int).Add(e, big.NewInt(1))
|
e = new(big.Int).Add(e, big.NewInt(1))
|
||||||
}
|
}
|
||||||
if e.Int64() > 31 {
|
if e.Int64() > 31 {
|
||||||
return 0, ErrFloat40E31
|
return 0, ErrFloat40E31
|
||||||
}
|
}
|
||||||
if !bytes.Equal(zero.Bytes(), new(big.Int).Div(m, thres).Bytes()) {
|
if m.Cmp(thres) >= 0 {
|
||||||
return 0, ErrFloat40NotEnoughPrecission
|
return 0, ErrFloat40NotEnoughPrecission
|
||||||
}
|
}
|
||||||
r := new(big.Int).Add(m,
|
r := new(big.Int).Add(m,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ type PoolL2Tx struct {
|
|||||||
ToEthAddr ethCommon.Address `meddler:"to_eth_addr,zeroisnull"`
|
ToEthAddr ethCommon.Address `meddler:"to_eth_addr,zeroisnull"`
|
||||||
ToBJJ babyjub.PublicKeyComp `meddler:"to_bjj,zeroisnull"`
|
ToBJJ babyjub.PublicKeyComp `meddler:"to_bjj,zeroisnull"`
|
||||||
TokenID TokenID `meddler:"token_id"`
|
TokenID TokenID `meddler:"token_id"`
|
||||||
Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float40
|
Amount *big.Int `meddler:"amount,bigint"`
|
||||||
Fee FeeSelector `meddler:"fee"`
|
Fee FeeSelector `meddler:"fee"`
|
||||||
Nonce Nonce `meddler:"nonce"` // effective 40 bits used
|
Nonce Nonce `meddler:"nonce"` // effective 40 bits used
|
||||||
State PoolL2TxState `meddler:"state"`
|
State PoolL2TxState `meddler:"state"`
|
||||||
@@ -53,7 +53,7 @@ type PoolL2Tx struct {
|
|||||||
RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr,zeroisnull"`
|
RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr,zeroisnull"`
|
||||||
RqToBJJ babyjub.PublicKeyComp `meddler:"rq_to_bjj,zeroisnull"`
|
RqToBJJ babyjub.PublicKeyComp `meddler:"rq_to_bjj,zeroisnull"`
|
||||||
RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
|
RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
|
||||||
RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float40
|
RqAmount *big.Int `meddler:"rq_amount,bigintnull"`
|
||||||
RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
|
RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
|
||||||
RqNonce Nonce `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
|
RqNonce Nonce `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
|
||||||
AbsoluteFee float64 `meddler:"fee_usd,zeroisnull"`
|
AbsoluteFee float64 `meddler:"fee_usd,zeroisnull"`
|
||||||
@@ -126,7 +126,7 @@ func (tx *PoolL2Tx) SetID() error {
|
|||||||
// [ 48 bits ] fromIdx // 6 bytes
|
// [ 48 bits ] fromIdx // 6 bytes
|
||||||
// [ 16 bits ] chainId // 2 bytes
|
// [ 16 bits ] chainId // 2 bytes
|
||||||
// [ 32 bits ] signatureConstant // 4 bytes
|
// [ 32 bits ] signatureConstant // 4 bytes
|
||||||
// Total bits compressed data: 241 bits // 31 bytes in *big.Int representation
|
// Total bits compressed data: 225 bits // 29 bytes in *big.Int representation
|
||||||
func (tx *PoolL2Tx) TxCompressedData(chainID uint16) (*big.Int, error) {
|
func (tx *PoolL2Tx) TxCompressedData(chainID uint16) (*big.Int, error) {
|
||||||
var b [29]byte
|
var b [29]byte
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ func TxCompressedDataEmpty(chainID uint16) *big.Int {
|
|||||||
// [ 40 bits ] amountFloat40 // 5 bytes
|
// [ 40 bits ] amountFloat40 // 5 bytes
|
||||||
// [ 48 bits ] toIdx // 6 bytes
|
// [ 48 bits ] toIdx // 6 bytes
|
||||||
// [ 48 bits ] fromIdx // 6 bytes
|
// [ 48 bits ] fromIdx // 6 bytes
|
||||||
// Total bits compressed data: 193 bits // 25 bytes in *big.Int representation
|
// Total bits compressed data: 217 bits // 28 bytes in *big.Int representation
|
||||||
func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
|
func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
|
||||||
if tx.Amount == nil {
|
if tx.Amount == nil {
|
||||||
tx.Amount = big.NewInt(0)
|
tx.Amount = big.NewInt(0)
|
||||||
@@ -238,7 +238,7 @@ func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
|
|||||||
// [ 40 bits ] rqAmountFloat40 // 5 bytes
|
// [ 40 bits ] rqAmountFloat40 // 5 bytes
|
||||||
// [ 48 bits ] rqToIdx // 6 bytes
|
// [ 48 bits ] rqToIdx // 6 bytes
|
||||||
// [ 48 bits ] rqFromIdx // 6 bytes
|
// [ 48 bits ] rqFromIdx // 6 bytes
|
||||||
// Total bits compressed data: 193 bits // 25 bytes in *big.Int representation
|
// Total bits compressed data: 217 bits // 28 bytes in *big.Int representation
|
||||||
func (tx *PoolL2Tx) RqTxCompressedDataV2() (*big.Int, error) {
|
func (tx *PoolL2Tx) RqTxCompressedDataV2() (*big.Int, error) {
|
||||||
if tx.RqAmount == nil {
|
if tx.RqAmount == nil {
|
||||||
tx.RqAmount = big.NewInt(0)
|
tx.RqAmount = big.NewInt(0)
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ type ZKInputs struct {
|
|||||||
// ToEthAddr
|
// ToEthAddr
|
||||||
ToEthAddr []*big.Int `json:"toEthAddr"` // ethCommon.Address, len: [maxTx]
|
ToEthAddr []*big.Int `json:"toEthAddr"` // ethCommon.Address, len: [maxTx]
|
||||||
// AmountF encoded as float40
|
// AmountF encoded as float40
|
||||||
AmountF []*big.Int `json:"amountF"`
|
AmountF []*big.Int `json:"amountF"` // uint40 len: [maxTx]
|
||||||
|
|
||||||
// OnChain determines if is L1 (1/true) or L2 (0/false)
|
// OnChain determines if is L1 (1/true) or L2 (0/false)
|
||||||
OnChain []*big.Int `json:"onChain"` // bool, len: [maxTx]
|
OnChain []*big.Int `json:"onChain"` // bool, len: [maxTx]
|
||||||
@@ -479,7 +479,7 @@ func (z ZKInputs) ToHashGlobalData() ([]byte, error) {
|
|||||||
copy(newExitRoot, z.Metadata.NewExitRootRaw.Bytes())
|
copy(newExitRoot, z.Metadata.NewExitRootRaw.Bytes())
|
||||||
b = append(b, newExitRoot...)
|
b = append(b, newExitRoot...)
|
||||||
|
|
||||||
// [MAX_L1_TX * (2 * MAX_NLEVELS + 480) bits] L1TxsData
|
// [MAX_L1_TX * (2 * MAX_NLEVELS + 528) bits] L1TxsData
|
||||||
l1TxDataLen := (2*z.Metadata.MaxLevels + 528)
|
l1TxDataLen := (2*z.Metadata.MaxLevels + 528)
|
||||||
l1TxsDataLen := (z.Metadata.MaxL1Tx * l1TxDataLen)
|
l1TxsDataLen := (z.Metadata.MaxL1Tx * l1TxDataLen)
|
||||||
l1TxsData := make([]byte, l1TxsDataLen/8) //nolint:gomnd
|
l1TxsData := make([]byte, l1TxsDataLen/8) //nolint:gomnd
|
||||||
@@ -497,7 +497,7 @@ func (z ZKInputs) ToHashGlobalData() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
b = append(b, l1TxsDataAvailability...)
|
b = append(b, l1TxsDataAvailability...)
|
||||||
|
|
||||||
// [MAX_TX*(2*NLevels + 24) bits] L2TxsData
|
// [MAX_TX*(2*NLevels + 48) bits] L2TxsData
|
||||||
var l2TxsData []byte
|
var l2TxsData []byte
|
||||||
l2TxDataLen := 2*z.Metadata.NLevels + 48 //nolint:gomnd
|
l2TxDataLen := 2*z.Metadata.NLevels + 48 //nolint:gomnd
|
||||||
l2TxsDataLen := (z.Metadata.MaxTx * l2TxDataLen)
|
l2TxsDataLen := (z.Metadata.MaxTx * l2TxDataLen)
|
||||||
|
|||||||
Reference in New Issue
Block a user