github.com/klaytn/klaytn@v1.12.1/crypto/bls/blst/signature.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 "crypto/rand" 21 "fmt" 22 "sync" 23 24 "github.com/klaytn/klaytn/crypto/bls/types" 25 "github.com/pkg/errors" 26 ) 27 28 type signature struct { 29 // Pointer to underlying blst struct, hence the name 'p' 30 p *blstSignature 31 } 32 33 func SignatureFromBytes(b []byte) (types.Signature, error) { 34 if len(b) != types.SignatureLength { 35 return nil, types.ErrSignatureLength(len(b)) 36 } 37 38 if s, ok := signatureCache.Get(cacheKey(b)); ok { 39 return s.(*signature).Copy(), nil 40 } 41 42 p := new(blstSignature).Uncompress(b) 43 // Do not check for infinity since an aggregated signature could be infinite. 44 if p == nil || !p.SigValidate(false) { 45 return nil, types.ErrSignatureUnmarshal 46 } 47 48 s := &signature{p: p} 49 signatureCache.Add(cacheKey(b), s.Copy()) 50 return s, nil 51 } 52 53 func MultipleSignaturesFromBytes(bs [][]byte) ([]types.Signature, error) { 54 if len(bs) == 0 { 55 return nil, nil 56 } 57 for _, b := range bs { 58 if len(b) != types.SignatureLength { 59 return nil, types.ErrSignatureLength(len(b)) 60 } 61 } 62 63 // Separate cached and uncached element 64 sigs := make([]types.Signature, len(bs)) 65 var batchIndices []int 66 var batchBytes [][]byte 67 for i, b := range bs { 68 if sig, ok := signatureCache.Get(cacheKey(b)); ok { 69 sigs[i] = sig.(*signature).Copy() 70 } else { 71 batchIndices = append(batchIndices, i) 72 batchBytes = append(batchBytes, b) 73 } 74 } 75 76 // Compute on uncached elements 77 batchPs := new(blstSignature).BatchUncompress(batchBytes) 78 if batchPs == nil || len(batchPs) != len(batchBytes) { 79 return nil, types.ErrSignatureUnmarshal 80 } 81 82 // Merge cached and uncached elements 83 for i, outIdx := range batchIndices { 84 p := batchPs[i] 85 b := batchBytes[i] 86 87 // Do not check for infinity since an aggregated signature could be infinite. 88 if p == nil || !p.SigValidate(false) { 89 return nil, types.ErrSignatureUnmarshal 90 } 91 92 sig := &signature{p: p} 93 signatureCache.Add(cacheKey(b), sig.Copy()) 94 sigs[outIdx] = sig 95 } 96 97 return sigs, nil 98 } 99 100 // AggregateSignatures assumes that given signatures has passed the SigValidate() check 101 // i.e. they are on the right subgroup. 102 // 103 // Signature objects are expected to be returned by Sign(), SignatureFromBytes() 104 // and AggregateSignaturesFromBytes(), and they all should be valid. 105 // Therefore AggregateSignatures skips the validatity check. 106 func AggregateSignatures(sigs []types.Signature) (types.Signature, error) { 107 if len(sigs) == 0 { 108 return nil, types.ErrEmptyArray 109 } 110 111 ps := make([]*blstSignature, len(sigs)) 112 for i, sig := range sigs { 113 ps[i] = sig.(*signature).p 114 } 115 116 agg := new(blstAggregateSignature) 117 groupcheck := false // alreaay checked in *SignatureFromBytes() 118 if !agg.Aggregate(ps, groupcheck) { 119 return nil, types.ErrSignatureAggregate 120 } 121 return &signature{p: agg.ToAffine()}, nil 122 } 123 124 func AggregateSignaturesFromBytes(bs [][]byte) (types.Signature, error) { 125 pks, err := MultipleSignaturesFromBytes(bs) 126 if err != nil { 127 return nil, err 128 } 129 return AggregateSignatures(pks) 130 } 131 132 func (s *signature) Marshal() []byte { 133 return s.p.Compress() 134 } 135 136 func (s *signature) Copy() types.Signature { 137 np := *s.p 138 return &signature{p: &np} 139 } 140 141 func sign(sk types.SecretKey, msg []byte, dst []byte) types.Signature { 142 sig := new(blstSignature).Sign( 143 sk.(*secretKey).p, msg, dst) 144 return &signature{p: sig} 145 } 146 147 func Sign(sk types.SecretKey, msg []byte) types.Signature { 148 return sign(sk, msg, types.DomainSeparationTagSig) 149 } 150 151 // draft-irtf-cfrg-bls-signature-05 section 3.3.2. PopProve 152 func PopProve(sk types.SecretKey) types.Signature { 153 msg := sk.PublicKey().Marshal() 154 return sign(sk, msg, types.DomainSeparationTagPop) 155 } 156 157 func verify(sig types.Signature, msg []byte, pk types.PublicKey, dst []byte) bool { 158 sigGroupCheck := false // alreaay checked in *SignatureFromBytes() 159 pkValidate := false // alreaay checked in *PublicKeyFromBytes() 160 return sig.(*signature).p.Verify( 161 sigGroupCheck, pk.(*publicKey).p, pkValidate, msg, dst) 162 } 163 164 func Verify(sig types.Signature, msg []byte, pk types.PublicKey) bool { 165 return verify(sig, msg, pk, types.DomainSeparationTagSig) 166 } 167 168 // draft-irtf-cfrg-bls-signature-05 section 3.3.3. PopVerify 169 func PopVerify(pk types.PublicKey, sig types.Signature) bool { 170 msg := pk.Marshal() 171 return verify(sig, msg, pk, types.DomainSeparationTagPop) 172 } 173 174 func FastAggregateVerify(sig types.Signature, msg []byte, pks []types.PublicKey) bool { 175 pubPs := make([]*blstPublicKey, len(pks)) 176 for i := 0; i < len(pks); i++ { 177 pubPs[i] = pks[i].(*publicKey).p 178 } 179 180 sigGroupCheck := false // alreaay checked in *SignatureFromBytes() 181 return sig.(*signature).p.FastAggregateVerify( 182 sigGroupCheck, pubPs, msg, types.DomainSeparationTagSig) 183 } 184 185 func VerifySignature(sigb []byte, msg [32]byte, pk types.PublicKey) (bool, error) { 186 sig, err := SignatureFromBytes(sigb) 187 if err != nil { 188 return false, err 189 } 190 sigGroupCheck := false // alreaay checked in SignatureFromBytes() 191 pkValidate := false // alreaay checked in *PublicKeyFromBytes() 192 ok := sig.(*signature).p.Verify( 193 sigGroupCheck, pk.(*publicKey).p, pkValidate, msg[:], types.DomainSeparationTagSig) 194 return ok, nil 195 } 196 197 // https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407 198 func VerifyMultipleSignatures(sigbs [][]byte, msgs [][32]byte, pks []types.PublicKey) (bool, error) { 199 if len(sigbs) == 0 { 200 return false, nil 201 } 202 if len(sigbs) != len(msgs) || len(msgs) != len(pks) { 203 return false, errors.Errorf("Unmatched sigs, msgs, pubkeys lengths: %d, %d, %d", len(sigbs), len(msgs), len(pks)) 204 } 205 count := len(sigbs) 206 207 // Benefit from cache 208 sigs, err := MultipleSignaturesFromBytes(sigbs) 209 if err != nil { 210 return false, err 211 } 212 213 // Convert to blst pointers 214 var ( 215 sigPs = make([]*blstSignature, count) 216 pkPs = make([]*blstPublicKey, count) 217 msgPs = make([]blstMessage, count) 218 ) 219 for i := 0; i < len(sigs); i++ { 220 sigPs[i] = sigs[i].(*signature).p 221 pkPs[i] = pks[i].(*publicKey).p 222 msgPs[i] = msgs[i][:] 223 } 224 225 // Supply random source 226 var randErr error 227 randLock := new(sync.Mutex) 228 randFunc := func(outScalar *blstScalar) { 229 var r [blstScalarBytes]byte 230 randLock.Lock() 231 _, err := rand.Read(r[:]) 232 randLock.Unlock() 233 234 if err != nil { 235 randErr = err 236 } 237 outScalar.FromBEndian(r[:]) 238 } 239 240 dummy := new(blstSignature) 241 sigGroupCheck := false // alreaay checked in MultipleSignaturesFromBytes() 242 pkValidate := false // alreaay checked in *PublicKeyFromBytes() 243 ok := dummy.MultipleAggregateVerify( 244 sigPs, sigGroupCheck, pkPs, pkValidate, msgPs, types.DomainSeparationTagSig, randFunc, blstRandBits) 245 246 if randErr != nil { 247 return false, fmt.Errorf("verify aborted: %s", randErr.Error()) 248 } else { 249 return ok, nil 250 } 251 }