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  }