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 }