github.com/status-im/status-go@v1.1.0/waku/common/helpers.go (about)

     1  package common
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	crand "crypto/rand"
     6  	"errors"
     7  	"fmt"
     8  	mrand "math/rand"
     9  
    10  	"github.com/ethereum/go-ethereum/common"
    11  )
    12  
    13  // IsPubKeyEqual checks that two public keys are equal
    14  func IsPubKeyEqual(a, b *ecdsa.PublicKey) bool {
    15  	if !ValidatePublicKey(a) {
    16  		return false
    17  	} else if !ValidatePublicKey(b) {
    18  		return false
    19  	}
    20  	// the curve is always the same, just compare the points
    21  	return a.X.Cmp(b.X) == 0 && a.Y.Cmp(b.Y) == 0
    22  }
    23  
    24  // ValidatePublicKey checks the format of the given public key.
    25  func ValidatePublicKey(k *ecdsa.PublicKey) bool {
    26  	return k != nil && k.X != nil && k.Y != nil && k.X.Sign() != 0 && k.Y.Sign() != 0
    27  }
    28  
    29  // BytesToUintLittleEndian converts the slice to 64-bit unsigned integer.
    30  func BytesToUintLittleEndian(b []byte) (res uint64) {
    31  	mul := uint64(1)
    32  	for i := 0; i < len(b); i++ {
    33  		res += uint64(b[i]) * mul
    34  		mul *= 256
    35  	}
    36  	return res
    37  }
    38  
    39  // BytesToUintBigEndian converts the slice to 64-bit unsigned integer.
    40  func BytesToUintBigEndian(b []byte) (res uint64) {
    41  	for i := 0; i < len(b); i++ {
    42  		res *= 256
    43  		res += uint64(b[i])
    44  	}
    45  	return res
    46  }
    47  
    48  // ContainsOnlyZeros checks if the data contain only zeros.
    49  func ContainsOnlyZeros(data []byte) bool {
    50  	for _, b := range data {
    51  		if b != 0 {
    52  			return false
    53  		}
    54  	}
    55  	return true
    56  }
    57  
    58  // GenerateSecureRandomData generates random data where extra security is required.
    59  // The purpose of this function is to prevent some bugs in software or in hardware
    60  // from delivering not-very-random data. This is especially useful for AES nonce,
    61  // where true randomness does not really matter, but it is very important to have
    62  // a unique nonce for every message.
    63  func GenerateSecureRandomData(length int) ([]byte, error) {
    64  	x := make([]byte, length)
    65  	y := make([]byte, length)
    66  	res := make([]byte, length)
    67  
    68  	_, err := crand.Read(x)
    69  	if err != nil {
    70  		return nil, err
    71  	} else if !ValidateDataIntegrity(x, length) {
    72  		return nil, errors.New("crypto/rand failed to generate secure random data")
    73  	}
    74  	_, err = mrand.Read(y) // nolint: gosec
    75  	if err != nil {
    76  		return nil, err
    77  	} else if !ValidateDataIntegrity(y, length) {
    78  		return nil, errors.New("math/rand failed to generate secure random data")
    79  	}
    80  	for i := 0; i < length; i++ {
    81  		res[i] = x[i] ^ y[i]
    82  	}
    83  	if !ValidateDataIntegrity(res, length) {
    84  		return nil, errors.New("failed to generate secure random data")
    85  	}
    86  	return res, nil
    87  }
    88  
    89  // GenerateRandomID generates a random string, which is then returned to be used as a key id
    90  func GenerateRandomID() (id string, err error) {
    91  	buf, err := GenerateSecureRandomData(KeyIDSize)
    92  	if err != nil {
    93  		return "", err
    94  	}
    95  	if !ValidateDataIntegrity(buf, KeyIDSize) {
    96  		return "", fmt.Errorf("error in generateRandomID: crypto/rand failed to generate random data")
    97  	}
    98  	id = common.Bytes2Hex(buf)
    99  	return id, err
   100  }
   101  
   102  // ValidateDataIntegrity returns false if the data have the wrong or contains all zeros,
   103  // which is the simplest and the most common bug.
   104  func ValidateDataIntegrity(k []byte, expectedSize int) bool {
   105  	if len(k) != expectedSize {
   106  		return false
   107  	}
   108  	if expectedSize > 3 && ContainsOnlyZeros(k) {
   109  		return false
   110  	}
   111  	return true
   112  }