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 }