github.com/amazechain/amc@v0.1.3/common/crypto/bls/blst/public_key.go (about) 1 //go:build (android || (linux && amd64) || (linux && arm64) || (darwin && amd64) || (darwin && arm64) || (windows && amd64)) && !blst_disabled 2 3 package blst 4 5 import ( 6 "fmt" 7 8 "github.com/amazechain/amc/common/crypto/bls/common" 9 "github.com/amazechain/amc/common/hexutil" 10 "github.com/amazechain/amc/log" 11 lru "github.com/hashicorp/golang-lru" 12 "github.com/pkg/errors" 13 ) 14 15 var maxKeys = 1000000 16 var pubkeyCache, _ = lru.New(maxKeys) 17 18 const ( 19 BLSPubkeyLength = 48 20 ) 21 22 // PublicKey used in the BLS signature scheme. 23 type PublicKey struct { 24 p *blstPublicKey 25 } 26 27 // PublicKeyFromBytes creates a BLS public key from a BigEndian byte slice. 28 func PublicKeyFromBytes(pubKey []byte) (common.PublicKey, error) { 29 if len(pubKey) != BLSPubkeyLength { 30 return nil, fmt.Errorf("public key must be %d bytes", BLSPubkeyLength) 31 } 32 newKey := (*[BLSPubkeyLength]byte)(pubKey) 33 if cv, ok := pubkeyCache.Get(*newKey); ok { 34 return cv.(*PublicKey).Copy(), nil 35 } 36 // Subgroup check NOT done when decompressing pubkey. 37 p := new(blstPublicKey).Uncompress(pubKey) 38 if p == nil { 39 return nil, errors.New("could not unmarshal bytes into public key") 40 } 41 // Subgroup and infinity check 42 if !p.KeyValidate() { 43 // NOTE: the error is not quite accurate since it includes group check 44 return nil, common.ErrInfinitePubKey 45 } 46 pubKeyObj := &PublicKey{p: p} 47 copiedKey := pubKeyObj.Copy() 48 cacheKey := *newKey 49 pubkeyCache.Add(cacheKey, copiedKey) 50 return pubKeyObj, nil 51 } 52 53 // AggregatePublicKeys aggregates the provided raw public keys into a single key. 54 func AggregatePublicKeys(pubs [][]byte) (common.PublicKey, error) { 55 if len(pubs) == 0 { 56 return nil, errors.New("nil or empty public keys") 57 } 58 agg := new(blstAggregatePublicKey) 59 mulP1 := make([]*blstPublicKey, 0, len(pubs)) 60 for _, pubkey := range pubs { 61 pubKeyObj, err := PublicKeyFromBytes(pubkey) 62 if err != nil { 63 return nil, err 64 } 65 mulP1 = append(mulP1, pubKeyObj.(*PublicKey).p) 66 } 67 // No group check needed here since it is done in PublicKeyFromBytes 68 // Note the checks could be moved from PublicKeyFromBytes into Aggregate 69 // and take advantage of multi-threading. 70 agg.Aggregate(mulP1, false) 71 return &PublicKey{p: agg.ToAffine()}, nil 72 } 73 74 // Marshal a public key into a LittleEndian byte slice. 75 func (p *PublicKey) Marshal() []byte { 76 return p.p.Compress() 77 } 78 79 // Copy the public key to a new pointer reference. 80 func (p *PublicKey) Copy() common.PublicKey { 81 np := *p.p 82 return &PublicKey{p: &np} 83 } 84 85 // IsInfinite checks if the public key is infinite. 86 func (p *PublicKey) IsInfinite() bool { 87 zeroKey := new(blstPublicKey) 88 return p.p.Equals(zeroKey) 89 } 90 91 // Equals checks if the provided public key is equal to 92 // the current one. 93 func (p *PublicKey) Equals(p2 common.PublicKey) bool { 94 return p.p.Equals(p2.(*PublicKey).p) 95 } 96 97 // Aggregate two public keys. 98 func (p *PublicKey) Aggregate(p2 common.PublicKey) common.PublicKey { 99 100 agg := new(blstAggregatePublicKey) 101 // No group check here since it is checked at decompression time 102 agg.Add(p.p, false) 103 agg.Add(p2.(*PublicKey).p, false) 104 p.p = agg.ToAffine() 105 106 return p 107 } 108 109 func (p *PublicKey) UnmarshalJSON(input []byte) error { 110 log.Infof(string(input)) 111 log.Info("1111") 112 b := make([]byte, 0) 113 err := hexutil.UnmarshalFixedText("PublicKey", input, b[:]) 114 if err != nil { 115 return err 116 } 117 pubkey, err := PublicKeyFromBytes(b) 118 if err != nil { 119 p = pubkey.(*PublicKey) 120 } 121 return err 122 } 123 124 func (p *PublicKey) UnmarshalText(input []byte) error { 125 log.Infof(string(input)) 126 log.Info("1111") 127 b := make([]byte, 0) 128 err := hexutil.UnmarshalFixedText("PublicKey", input, b[:]) 129 if err != nil { 130 return err 131 } 132 pubkey, err := PublicKeyFromBytes(b) 133 if err != nil { 134 p = pubkey.(*PublicKey) 135 } 136 return err 137 } 138 139 func (p *PublicKey) MarshalText() ([]byte, error) { 140 return hexutil.Bytes(p.Marshal()).MarshalText() 141 } 142 143 // AggregateMultiplePubkeys aggregates the provided decompressed keys into a single key. 144 func AggregateMultiplePubkeys(pubkeys []common.PublicKey) common.PublicKey { 145 mulP1 := make([]*blstPublicKey, 0, len(pubkeys)) 146 for _, pubkey := range pubkeys { 147 mulP1 = append(mulP1, pubkey.(*PublicKey).p) 148 } 149 agg := new(blstAggregatePublicKey) 150 // No group check needed here since it is done in PublicKeyFromBytes 151 // Note the checks could be moved from PublicKeyFromBytes into Aggregate 152 // and take advantage of multi-threading. 153 agg.Aggregate(mulP1, false) 154 return &PublicKey{p: agg.ToAffine()} 155 }