arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/leaf.go
common/leaf.goRaw
  1package common
  2
  3import (
  4	"bytes"
  5	"encoding/binary"
  6	"fmt"
  7	"math"
  8	"math/big"
  9
 10	eth "github.com/ethereum/go-ethereum/common"
 11	"github.com/iden3/go-iden3-crypto/poseidon"
 12	cryptoUtils "github.com/iden3/go-iden3-crypto/utils"
 13)
 14
 15// Leaf is the data structure stored in the Leaf of the MerkleTree
 16type Leaf struct {
 17	TokenID TokenID
 18	Nonce   uint64   // max of 40 bits used
 19	Balance *big.Int // max of 192 bits used
 20	Ax      *big.Int
 21	Ay      *big.Int
 22	EthAddr eth.Address
 23}
 24
 25// Bytes returns the bytes representing the Leaf, in a way that each BigInt is represented by 32 bytes, in spite of the BigInt could be represented in less bytes (due a small big.Int), so in this way each BigInt is always 32 bytes and can be automatically parsed from a byte array.
 26func (l *Leaf) Bytes() ([32 * 5]byte, error) {
 27	var b [32 * 5]byte
 28
 29	if l.Nonce >= uint64(math.Pow(2, 40)) {
 30		return b, fmt.Errorf("%s Nonce", ErrNumOverflow)
 31	}
 32	if len(l.Balance.Bytes()) > 24 {
 33		return b, fmt.Errorf("%s Balance", ErrNumOverflow)
 34	}
 35
 36	var tokenIDBytes [4]byte
 37	binary.LittleEndian.PutUint32(tokenIDBytes[:], uint32(l.TokenID))
 38	var nonceBytes [8]byte
 39	binary.LittleEndian.PutUint64(nonceBytes[:], l.Nonce)
 40
 41	copy(b[0:4], tokenIDBytes[:])
 42	copy(b[4:9], nonceBytes[:])
 43	copy(b[32:64], SwapEndianness(l.Balance.Bytes())) // SwapEndianness, as big.Int uses BigEndian
 44	copy(b[64:96], SwapEndianness(l.Ax.Bytes()))
 45	copy(b[96:128], SwapEndianness(l.Ay.Bytes()))
 46	copy(b[128:148], l.EthAddr.Bytes())
 47
 48	return b, nil
 49}
 50
 51// BigInts returns the [5]*big.Int, where each *big.Int is inside the Finite Field
 52func (l *Leaf) BigInts() ([5]*big.Int, error) {
 53	e := [5]*big.Int{}
 54
 55	b, err := l.Bytes()
 56	if err != nil {
 57		return e, err
 58	}
 59
 60	e[0] = new(big.Int).SetBytes(SwapEndianness(b[0:32]))
 61	e[1] = new(big.Int).SetBytes(SwapEndianness(b[32:64]))
 62	e[2] = new(big.Int).SetBytes(SwapEndianness(b[64:96]))
 63	e[3] = new(big.Int).SetBytes(SwapEndianness(b[96:128]))
 64	e[4] = new(big.Int).SetBytes(SwapEndianness(b[128:160]))
 65
 66	return e, nil
 67}
 68
 69// HashValue returns the value of the Leaf, which is the Poseidon hash of its *big.Int representation
 70func (l *Leaf) HashValue() (*big.Int, error) {
 71	toHash := [poseidon.T]*big.Int{}
 72	lBI, err := l.BigInts()
 73	if err != nil {
 74		return nil, err
 75	}
 76	copy(toHash[:], lBI[:])
 77
 78	v, err := poseidon.Hash(toHash)
 79	return v, err
 80}
 81
 82// LeafFromBigInts returns a Leaf from a [5]*big.Int
 83func LeafFromBigInts(e [5]*big.Int) (*Leaf, error) {
 84	if !cryptoUtils.CheckBigIntArrayInField(e[:]) {
 85		return nil, ErrNotInFF
 86	}
 87	var b [32 * 5]byte
 88	copy(b[0:32], SwapEndianness(e[0].Bytes())) // SwapEndianness, as big.Int uses BigEndian
 89	copy(b[32:64], SwapEndianness(e[1].Bytes()))
 90	copy(b[64:96], SwapEndianness(e[2].Bytes()))
 91	copy(b[96:128], SwapEndianness(e[3].Bytes()))
 92	copy(b[128:160], SwapEndianness(e[4].Bytes()))
 93
 94	return LeafFromBytes(b)
 95}
 96
 97// LeafFromBytes returns a Leaf from a byte array
 98func LeafFromBytes(b [32 * 5]byte) (*Leaf, error) {
 99	tokenID := binary.LittleEndian.Uint32(b[0:4])
100	nonce := binary.LittleEndian.Uint64(b[4:12])
101	if !bytes.Equal(b[9:12], []byte{0, 0, 0}) { // alternatively: if nonce >= uint64(math.Pow(2, 40)) {
102		return nil, fmt.Errorf("%s Nonce", ErrNumOverflow)
103	}
104	balance := new(big.Int).SetBytes(SwapEndianness(b[32:56])) // b[32:56], as Balance is 192 bits (24 bytes)
105	if !bytes.Equal(b[56:64], []byte{0, 0, 0, 0, 0, 0, 0, 0}) {
106		return nil, fmt.Errorf("%s Balance", ErrNumOverflow)
107	}
108	ax := new(big.Int).SetBytes(SwapEndianness(b[64:96])) // SwapEndianness, as big.Int uses BigEndian
109	ay := new(big.Int).SetBytes(SwapEndianness(b[96:128]))
110	ethAddr := eth.BytesToAddress(b[128:148])
111
112	if !cryptoUtils.CheckBigIntInField(balance) {
113		return nil, ErrNotInFF
114	}
115	if !cryptoUtils.CheckBigIntInField(ax) {
116		return nil, ErrNotInFF
117	}
118	if !cryptoUtils.CheckBigIntInField(ay) {
119		return nil, ErrNotInFF
120	}
121
122	l := Leaf{
123		TokenID: TokenID(tokenID),
124		Nonce:   nonce,
125		Balance: balance,
126		Ax:      ax,
127		Ay:      ay,
128		EthAddr: ethAddr,
129	}
130	return &l, nil
131}