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  }