github.com/cloudflare/circl@v1.5.0/internal/conv/conv.go (about) 1 package conv 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math/big" 7 "strings" 8 ) 9 10 // BytesLe2Hex returns an hexadecimal string of a number stored in a 11 // little-endian order slice x. 12 func BytesLe2Hex(x []byte) string { 13 b := &strings.Builder{} 14 b.Grow(2*len(x) + 2) 15 fmt.Fprint(b, "0x") 16 if len(x) == 0 { 17 fmt.Fprint(b, "00") 18 } 19 for i := len(x) - 1; i >= 0; i-- { 20 fmt.Fprintf(b, "%02x", x[i]) 21 } 22 return b.String() 23 } 24 25 // BytesLe2BigInt converts a little-endian slice x into a big-endian 26 // math/big.Int. 27 func BytesLe2BigInt(x []byte) *big.Int { 28 n := len(x) 29 b := new(big.Int) 30 if len(x) > 0 { 31 y := make([]byte, n) 32 for i := 0; i < n; i++ { 33 y[n-1-i] = x[i] 34 } 35 b.SetBytes(y) 36 } 37 return b 38 } 39 40 // BytesBe2Uint64Le converts a big-endian slice x to a little-endian slice of uint64. 41 func BytesBe2Uint64Le(x []byte) []uint64 { 42 l := len(x) 43 z := make([]uint64, (l+7)/8) 44 blocks := l / 8 45 for i := 0; i < blocks; i++ { 46 z[i] = binary.BigEndian.Uint64(x[l-8*(i+1):]) 47 } 48 remBytes := l % 8 49 for i := 0; i < remBytes; i++ { 50 z[blocks] |= uint64(x[l-1-8*blocks-i]) << uint(8*i) 51 } 52 return z 53 } 54 55 // BigInt2BytesLe stores a positive big.Int number x into a little-endian slice z. 56 // The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros). 57 // If x does not fit in the slice or is negative, z is not modified. 58 func BigInt2BytesLe(z []byte, x *big.Int) { 59 xLen := (x.BitLen() + 7) >> 3 60 zLen := len(z) 61 if zLen >= xLen && x.Sign() >= 0 { 62 y := x.Bytes() 63 for i := 0; i < xLen; i++ { 64 z[i] = y[xLen-1-i] 65 } 66 for i := xLen; i < zLen; i++ { 67 z[i] = 0 68 } 69 } 70 } 71 72 // Uint64Le2BigInt converts a little-endian slice x into a big number. 73 func Uint64Le2BigInt(x []uint64) *big.Int { 74 n := len(x) 75 b := new(big.Int) 76 var bi big.Int 77 for i := n - 1; i >= 0; i-- { 78 bi.SetUint64(x[i]) 79 b.Lsh(b, 64) 80 b.Add(b, &bi) 81 } 82 return b 83 } 84 85 // Uint64Le2BytesLe converts a little-endian slice x to a little-endian slice of bytes. 86 func Uint64Le2BytesLe(x []uint64) []byte { 87 b := make([]byte, 8*len(x)) 88 n := len(x) 89 for i := 0; i < n; i++ { 90 binary.LittleEndian.PutUint64(b[i*8:], x[i]) 91 } 92 return b 93 } 94 95 // Uint64Le2BytesBe converts a little-endian slice x to a big-endian slice of bytes. 96 func Uint64Le2BytesBe(x []uint64) []byte { 97 b := make([]byte, 8*len(x)) 98 n := len(x) 99 for i := 0; i < n; i++ { 100 binary.BigEndian.PutUint64(b[i*8:], x[n-1-i]) 101 } 102 return b 103 } 104 105 // Uint64Le2Hex returns an hexadecimal string of a number stored in a 106 // little-endian order slice x. 107 func Uint64Le2Hex(x []uint64) string { 108 b := new(strings.Builder) 109 b.Grow(16*len(x) + 2) 110 fmt.Fprint(b, "0x") 111 if len(x) == 0 { 112 fmt.Fprint(b, "00") 113 } 114 for i := len(x) - 1; i >= 0; i-- { 115 fmt.Fprintf(b, "%016x", x[i]) 116 } 117 return b.String() 118 } 119 120 // BigInt2Uint64Le stores a positive big.Int number x into a little-endian slice z. 121 // The slice is modified if the bitlength of x <= 8*len(z) (padding with zeros). 122 // If x does not fit in the slice or is negative, z is not modified. 123 func BigInt2Uint64Le(z []uint64, x *big.Int) { 124 xLen := (x.BitLen() + 63) >> 6 // number of 64-bit words 125 zLen := len(z) 126 if zLen >= xLen && x.Sign() > 0 { 127 var y, yi big.Int 128 y.Set(x) 129 two64 := big.NewInt(1) 130 two64.Lsh(two64, 64).Sub(two64, big.NewInt(1)) 131 for i := 0; i < xLen; i++ { 132 yi.And(&y, two64) 133 z[i] = yi.Uint64() 134 y.Rsh(&y, 64) 135 } 136 } 137 for i := xLen; i < zLen; i++ { 138 z[i] = 0 139 } 140 }