github.com/prysmaticlabs/prysm@v1.4.4/shared/interop/generate_keys.go (about)

     1  package interop
     2  
     3  import (
     4  	"encoding/binary"
     5  	"math/big"
     6  	"sync"
     7  
     8  	"github.com/pkg/errors"
     9  	"github.com/prysmaticlabs/prysm/shared/bls"
    10  	"github.com/prysmaticlabs/prysm/shared/hashutil"
    11  	"github.com/prysmaticlabs/prysm/shared/mputil"
    12  )
    13  
    14  const (
    15  	blsWithdrawalPrefixByte = byte(0)
    16  )
    17  
    18  // DeterministicallyGenerateKeys creates BLS private keys using a fixed curve order according to
    19  // the algorithm specified in the Ethereum beacon chain specification interop mock start section found here:
    20  // https://github.com/ethereum/eth2.0-pm/blob/a085c9870f3956d6228ed2a40cd37f0c6580ecd7/interop/mocked_start/README.md
    21  func DeterministicallyGenerateKeys(startIndex, numKeys uint64) ([]bls.SecretKey, []bls.PublicKey, error) {
    22  	privKeys := make([]bls.SecretKey, numKeys)
    23  	pubKeys := make([]bls.PublicKey, numKeys)
    24  	type keys struct {
    25  		secrets []bls.SecretKey
    26  		publics []bls.PublicKey
    27  	}
    28  	results, err := mputil.Scatter(int(numKeys), func(offset int, entries int, _ *sync.RWMutex) (interface{}, error) {
    29  		secs, pubs, err := deterministicallyGenerateKeys(uint64(offset)+startIndex, uint64(entries))
    30  		return &keys{secrets: secs, publics: pubs}, err
    31  	})
    32  	if err != nil {
    33  		return nil, nil, errors.Wrap(err, "failed to generate keys")
    34  	}
    35  	for _, result := range results {
    36  		if keysExtent, ok := result.Extent.(*keys); ok {
    37  			copy(privKeys[result.Offset:], keysExtent.secrets)
    38  			copy(pubKeys[result.Offset:], keysExtent.publics)
    39  		} else {
    40  			return nil, nil, errors.New("extent not of expected type")
    41  		}
    42  	}
    43  	return privKeys, pubKeys, nil
    44  }
    45  
    46  func deterministicallyGenerateKeys(startIndex, numKeys uint64) ([]bls.SecretKey, []bls.PublicKey, error) {
    47  	privKeys := make([]bls.SecretKey, numKeys)
    48  	pubKeys := make([]bls.PublicKey, numKeys)
    49  	for i := startIndex; i < startIndex+numKeys; i++ {
    50  		enc := make([]byte, 32)
    51  		binary.LittleEndian.PutUint32(enc, uint32(i))
    52  		hash := hashutil.Hash(enc)
    53  		// Reverse byte order to big endian for use with big ints.
    54  		b := reverseByteOrder(hash[:])
    55  		num := new(big.Int)
    56  		num = num.SetBytes(b)
    57  		order := new(big.Int)
    58  		var ok bool
    59  		order, ok = order.SetString(bls.CurveOrder, 10)
    60  		if !ok {
    61  			return nil, nil, errors.New("could not set bls curve order as big int")
    62  		}
    63  		num = num.Mod(num, order)
    64  		numBytes := num.Bytes()
    65  		// pad key at the start with zero bytes to make it into a 32 byte key
    66  		if len(numBytes) < 32 {
    67  			emptyBytes := make([]byte, 32-len(numBytes))
    68  			numBytes = append(emptyBytes, numBytes...)
    69  		}
    70  		priv, err := bls.SecretKeyFromBytes(numBytes)
    71  		if err != nil {
    72  			return nil, nil, errors.Wrapf(err, "could not create bls secret key at index %d from raw bytes", i)
    73  		}
    74  		privKeys[i-startIndex] = priv
    75  		pubKeys[i-startIndex] = priv.PublicKey()
    76  	}
    77  	return privKeys, pubKeys, nil
    78  }
    79  
    80  // Switch the endianness of a byte slice by reversing its order.
    81  func reverseByteOrder(input []byte) []byte {
    82  	b := input
    83  	for i := 0; i < len(b)/2; i++ {
    84  		b[i], b[len(b)-i-1] = b[len(b)-i-1], b[i]
    85  	}
    86  	return b
    87  }