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  }