github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/merkletree/split.go (about)

     1  package merkletree
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"math/big"
     7  	"strings"
     8  
     9  	"github.com/0xPolygon/supernets2-node/hex"
    10  	poseidon "github.com/iden3/go-iden3-crypto/goldenposeidon"
    11  )
    12  
    13  // maxBigIntLen is 256 bits (32 bytes)
    14  const maxBigIntLen = 32
    15  
    16  // wordLength is the number of bits of each ff limb
    17  const wordLength = 64
    18  
    19  // fea2scalar converts array of uint64 values into one *big.Int.
    20  func fea2scalar(v []uint64) *big.Int {
    21  	if len(v) != poseidon.NROUNDSF {
    22  		return big.NewInt(0)
    23  	}
    24  	res := new(big.Int).SetUint64(v[0])
    25  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[1]), 32))  //nolint:gomnd
    26  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[2]), 64))  //nolint:gomnd
    27  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[3]), 96))  //nolint:gomnd
    28  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[4]), 128)) //nolint:gomnd
    29  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[5]), 160)) //nolint:gomnd
    30  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[6]), 192)) //nolint:gomnd
    31  	res.Add(res, new(big.Int).Lsh(new(big.Int).SetUint64(v[7]), 224)) //nolint:gomnd
    32  	return res
    33  }
    34  
    35  // scalar2fea splits a *big.Int into array of 32bit uint64 values.
    36  func scalar2fea(value *big.Int) []uint64 {
    37  	val := make([]uint64, 8)                          //nolint:gomnd
    38  	mask, _ := new(big.Int).SetString("FFFFFFFF", 16) //nolint:gomnd
    39  	val[0] = new(big.Int).And(value, mask).Uint64()
    40  	val[1] = new(big.Int).And(new(big.Int).Rsh(value, 32), mask).Uint64()  //nolint:gomnd
    41  	val[2] = new(big.Int).And(new(big.Int).Rsh(value, 64), mask).Uint64()  //nolint:gomnd
    42  	val[3] = new(big.Int).And(new(big.Int).Rsh(value, 96), mask).Uint64()  //nolint:gomnd
    43  	val[4] = new(big.Int).And(new(big.Int).Rsh(value, 128), mask).Uint64() //nolint:gomnd
    44  	val[5] = new(big.Int).And(new(big.Int).Rsh(value, 160), mask).Uint64() //nolint:gomnd
    45  	val[6] = new(big.Int).And(new(big.Int).Rsh(value, 192), mask).Uint64() //nolint:gomnd
    46  	val[7] = new(big.Int).And(new(big.Int).Rsh(value, 224), mask).Uint64() //nolint:gomnd
    47  	return val
    48  }
    49  
    50  // h4ToScalar converts array of 4 uint64 into a unique 256 bits scalar.
    51  func h4ToScalar(h4 []uint64) *big.Int {
    52  	if len(h4) == 0 {
    53  		return new(big.Int)
    54  	}
    55  	result := new(big.Int).SetUint64(h4[0])
    56  
    57  	for i := 1; i < 4; i++ {
    58  		b2 := new(big.Int).SetUint64(h4[i])
    59  		b2.Lsh(b2, uint(wordLength*i))
    60  		result = result.Add(result, b2)
    61  	}
    62  
    63  	return result
    64  }
    65  
    66  // H4ToString converts array of 4 Scalars of 64 bits into an hex string.
    67  func H4ToString(h4 []uint64) string {
    68  	sc := h4ToScalar(h4)
    69  
    70  	return fmt.Sprintf("0x%064s", hex.EncodeToString(sc.Bytes()))
    71  }
    72  
    73  // StringToh4 converts an hex string into array of 4 Scalars of 64 bits.
    74  func StringToh4(str string) ([]uint64, error) {
    75  	if strings.HasPrefix(str, "0x") { // nolint
    76  		str = str[2:]
    77  	}
    78  
    79  	bi, ok := new(big.Int).SetString(str, hex.Base)
    80  	if !ok {
    81  		return nil, fmt.Errorf("Could not convert %q into big int", str)
    82  	}
    83  
    84  	return scalarToh4(bi), nil
    85  }
    86  
    87  // scalarToh4 converts a *big.Int into an array of 4 uint64
    88  func scalarToh4(s *big.Int) []uint64 {
    89  	b := ScalarToFilledByteSlice(s)
    90  
    91  	r := make([]uint64, 4) //nolint:gomnd
    92  
    93  	f, _ := hex.DecodeHex("0xFFFFFFFFFFFFFFFF")
    94  	fbe := binary.BigEndian.Uint64(f)
    95  
    96  	r[3] = binary.BigEndian.Uint64(b[0:8]) & fbe
    97  	r[2] = binary.BigEndian.Uint64(b[8:16]) & fbe
    98  	r[1] = binary.BigEndian.Uint64(b[16:24]) & fbe
    99  	r[0] = binary.BigEndian.Uint64(b[24:]) & fbe
   100  
   101  	return r
   102  }
   103  
   104  // ScalarToFilledByteSlice converts a *big.Int into an array of maxBigIntLen
   105  // bytes.
   106  func ScalarToFilledByteSlice(s *big.Int) []byte {
   107  	buf := make([]byte, maxBigIntLen)
   108  	return s.FillBytes(buf)
   109  }
   110  
   111  // h4ToFilledByteSlice converts an array of 4 uint64 into an array of
   112  // maxBigIntLen bytes.
   113  func h4ToFilledByteSlice(h4 []uint64) []byte {
   114  	return ScalarToFilledByteSlice(h4ToScalar(h4))
   115  }
   116  
   117  // string2fea converts an string into an array of 32bit uint64 values.
   118  func string2fea(s string) ([]uint64, error) {
   119  	bi, ok := new(big.Int).SetString(s, hex.Base)
   120  	if !ok {
   121  		return nil, fmt.Errorf("Could not convert %q into big int", s)
   122  	}
   123  	return scalar2fea(bi), nil
   124  }
   125  
   126  // fea2string converts an array of 32bit uint64 values into a string.
   127  func fea2string(fea []uint64) string {
   128  	bi := fea2scalar(fea)
   129  
   130  	biBytes := ScalarToFilledByteSlice(bi)
   131  
   132  	return hex.EncodeToHex(biBytes)
   133  }