github.com/prysmaticlabs/prysm@v1.4.4/shared/bls/blst/public_key.go (about) 1 // +build linux,amd64 linux,arm64 darwin,amd64 windows,amd64 2 // +build !blst_disabled 3 4 package blst 5 6 import ( 7 "fmt" 8 9 "github.com/dgraph-io/ristretto" 10 "github.com/pkg/errors" 11 "github.com/prysmaticlabs/prysm/shared/bls/common" 12 "github.com/prysmaticlabs/prysm/shared/featureconfig" 13 "github.com/prysmaticlabs/prysm/shared/params" 14 ) 15 16 var maxKeys = int64(1000000) 17 var pubkeyCache, _ = ristretto.NewCache(&ristretto.Config{ 18 NumCounters: maxKeys, 19 MaxCost: 1 << 26, // ~64mb is cache max size 20 BufferItems: 64, 21 }) 22 23 // PublicKey used in the BLS signature scheme. 24 type PublicKey struct { 25 p *blstPublicKey 26 } 27 28 // PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice. 29 func PublicKeyFromBytes(pubKey []byte) (common.PublicKey, error) { 30 if featureconfig.Get().SkipBLSVerify { 31 return &PublicKey{}, nil 32 } 33 if len(pubKey) != params.BeaconConfig().BLSPubkeyLength { 34 return nil, fmt.Errorf("public key must be %d bytes", params.BeaconConfig().BLSPubkeyLength) 35 } 36 if cv, ok := pubkeyCache.Get(string(pubKey)); ok { 37 return cv.(*PublicKey).Copy(), nil 38 } 39 // Subgroup check NOT done when decompressing pubkey. 40 p := new(blstPublicKey).Uncompress(pubKey) 41 if p == nil { 42 return nil, errors.New("could not unmarshal bytes into public key") 43 } 44 // Subgroup and infinity check 45 if !p.KeyValidate() { 46 // NOTE: the error is not quite accurate since it includes group check 47 return nil, common.ErrInfinitePubKey 48 } 49 pubKeyObj := &PublicKey{p: p} 50 copiedKey := pubKeyObj.Copy() 51 pubkeyCache.Set(string(pubKey), copiedKey, 48) 52 return pubKeyObj, nil 53 } 54 55 // AggregatePublicKeys aggregates the provided raw public keys into a single key. 56 func AggregatePublicKeys(pubs [][]byte) (common.PublicKey, error) { 57 if featureconfig.Get().SkipBLSVerify { 58 return &PublicKey{}, nil 59 } 60 if pubs == nil || len(pubs) == 0 { 61 return nil, errors.New("nil or empty public keys") 62 } 63 agg := new(blstAggregatePublicKey) 64 mulP1 := make([]*blstPublicKey, 0, len(pubs)) 65 for _, pubkey := range pubs { 66 pubKeyObj, err := PublicKeyFromBytes(pubkey) 67 if err != nil { 68 return nil, err 69 } 70 mulP1 = append(mulP1, pubKeyObj.(*PublicKey).p) 71 } 72 // No group check needed here since it is done in PublicKeyFromBytes 73 // Note the checks could be moved from PublicKeyFromBytes into Aggregate 74 // and take advantage of multi-threading. 75 agg.Aggregate(mulP1, false) 76 return &PublicKey{p: agg.ToAffine()}, nil 77 } 78 79 // Marshal a public key into a LittleEndian byte slice. 80 func (p *PublicKey) Marshal() []byte { 81 return p.p.Compress() 82 } 83 84 // Copy the public key to a new pointer reference. 85 func (p *PublicKey) Copy() common.PublicKey { 86 np := *p.p 87 return &PublicKey{p: &np} 88 } 89 90 // IsInfinite checks if the public key is infinite. 91 func (p *PublicKey) IsInfinite() bool { 92 zeroKey := new(blstPublicKey) 93 return p.p.Equals(zeroKey) 94 } 95 96 // Aggregate two public keys. 97 func (p *PublicKey) Aggregate(p2 common.PublicKey) common.PublicKey { 98 if featureconfig.Get().SkipBLSVerify { 99 return p 100 } 101 102 agg := new(blstAggregatePublicKey) 103 // No group check here since it is checked at decompression time 104 agg.Add(p.p, false) 105 agg.Add(p2.(*PublicKey).p, false) 106 p.p = agg.ToAffine() 107 108 return p 109 }