github.com/klaytn/klaytn@v1.12.1/crypto/bls/blst/public_key.go (about) 1 // Copyright 2023 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package blst 18 19 import ( 20 "github.com/klaytn/klaytn/crypto/bls/types" 21 ) 22 23 type publicKey struct { 24 // Pointer to underlying blst struct, hence the name 'p' 25 p *blstPublicKey 26 } 27 28 func PublicKeyFromBytes(b []byte) (types.PublicKey, error) { 29 if len(b) != types.PublicKeyLength { 30 return nil, types.ErrPublicKeyLength(len(b)) 31 } 32 33 if pk, ok := publicKeyCache.Get(cacheKey(b)); ok { 34 return pk.(*publicKey).Copy(), nil 35 } 36 37 p := new(blstPublicKey).Uncompress(b) 38 if p == nil || !p.KeyValidate() { 39 return nil, types.ErrPublicKeyUnmarshal 40 } 41 42 pk := &publicKey{p: p} 43 publicKeyCache.Add(cacheKey(b), pk.Copy()) 44 return pk, nil 45 } 46 47 func MultiplePublicKeysFromBytes(bs [][]byte) ([]types.PublicKey, error) { 48 if len(bs) == 0 { 49 return nil, nil 50 } 51 for _, b := range bs { 52 if len(b) != types.PublicKeyLength { 53 return nil, types.ErrPublicKeyLength(len(b)) 54 } 55 } 56 57 // Separate cached and uncached element 58 pks := make([]types.PublicKey, len(bs)) 59 var batchIndices []int 60 var batchBytes [][]byte 61 for i, b := range bs { 62 if pk, ok := publicKeyCache.Get(cacheKey(b)); ok { 63 pks[i] = pk.(*publicKey).Copy() 64 } else { 65 batchIndices = append(batchIndices, i) 66 batchBytes = append(batchBytes, b) 67 } 68 } 69 70 // Compute on uncached elements 71 batchPs := new(blstPublicKey).BatchUncompress(batchBytes) 72 if batchPs == nil || len(batchPs) != len(batchBytes) { 73 return nil, types.ErrPublicKeyUnmarshal 74 } 75 76 // Merge cached and uncached elements 77 for i, outIdx := range batchIndices { 78 b := batchBytes[i] 79 p := batchPs[i] 80 81 if p == nil || !p.KeyValidate() { 82 return nil, types.ErrPublicKeyUnmarshal 83 } 84 85 pk := &publicKey{p: p} 86 publicKeyCache.Add(cacheKey(b), pk.Copy()) 87 pks[outIdx] = pk 88 } 89 90 return pks, nil 91 } 92 93 // AggregatePublicKeys assumes that given public keys has passed the KeyValidate() check 94 // i.e. they are not infinite and are on the right subgroup. 95 // 96 // PublicKey objects are expected to be returned by SecretKey.PublicKey(), PublicKeyFromBytes() 97 // and AggregatePublicKeysFromBytes(), and they all should be valid. 98 // Therefore AggregatePublicKeys skips the validatity check. 99 func AggregatePublicKeys(pks []types.PublicKey) (types.PublicKey, error) { 100 if len(pks) == 0 { 101 return nil, types.ErrEmptyArray 102 } 103 104 ps := make([]*blstPublicKey, len(pks)) 105 for i, pk := range pks { 106 ps[i] = pk.(*publicKey).p 107 } 108 109 agg := new(blstAggregatePublicKey) 110 groupcheck := false // alreaay checked in *PublicKeyFromBytes() 111 if !agg.Aggregate(ps, groupcheck) { 112 return nil, types.ErrPublicKeyAggregate 113 } 114 return &publicKey{p: agg.ToAffine()}, nil 115 } 116 117 func AggregatePublicKeysFromBytes(bs [][]byte) (types.PublicKey, error) { 118 pks, err := MultiplePublicKeysFromBytes(bs) 119 if err != nil { 120 return nil, err 121 } 122 return AggregatePublicKeys(pks) 123 } 124 125 func (pk *publicKey) Marshal() []byte { 126 return pk.p.Compress() 127 } 128 129 func (pk *publicKey) Copy() types.PublicKey { 130 np := *pk.p 131 return &publicKey{p: &np} 132 }