github.com/amazechain/amc@v0.1.3/common/crypto/bls/blst/signature.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  	"bytes"
     7  	"fmt"
     8  	"sync"
     9  
    10  	"github.com/amazechain/amc/common/crypto/bls/common"
    11  	"github.com/amazechain/amc/common/crypto/rand"
    12  
    13  	"github.com/pkg/errors"
    14  	blst "github.com/supranational/blst/bindings/go"
    15  )
    16  
    17  var dst = []byte("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_")
    18  
    19  const scalarBytes = 32
    20  const randBitsEntropy = 64
    21  
    22  const BLSSignatureLength = 96
    23  
    24  // Signature used in the BLS signature scheme.
    25  type Signature struct {
    26  	s *blstSignature
    27  }
    28  
    29  // SignatureFromBytes creates a BLS signature from a LittleEndian byte slice.
    30  func SignatureFromBytes(sig []byte) (common.Signature, error) {
    31  	if len(sig) != BLSSignatureLength {
    32  		return nil, fmt.Errorf("signature must be %d bytes", BLSSignatureLength)
    33  	}
    34  	signature := new(blstSignature).Uncompress(sig)
    35  	if signature == nil {
    36  		return nil, errors.New("could not unmarshal bytes into signature")
    37  	}
    38  	// Group check signature. Do not check for infinity since an aggregated signature
    39  	// could be infinite.
    40  	if !signature.SigValidate(false) {
    41  		return nil, errors.New("signature not in group")
    42  	}
    43  	return &Signature{s: signature}, nil
    44  }
    45  
    46  // AggregateCompressedSignatures converts a list of compressed signatures into a single, aggregated sig.
    47  func AggregateCompressedSignatures(multiSigs [][]byte) (common.Signature, error) {
    48  	signature := new(blstAggregateSignature)
    49  	valid := signature.AggregateCompressed(multiSigs, true)
    50  	if !valid {
    51  		return nil, errors.New("provided signatures fail the group check and cannot be compressed")
    52  	}
    53  	return &Signature{s: signature.ToAffine()}, nil
    54  }
    55  
    56  // MultipleSignaturesFromBytes creates a group of BLS signatures from a LittleEndian 2d-byte slice.
    57  func MultipleSignaturesFromBytes(multiSigs [][]byte) ([]common.Signature, error) {
    58  	if len(multiSigs) == 0 {
    59  		return nil, fmt.Errorf("0 signatures provided to the method")
    60  	}
    61  	for _, s := range multiSigs {
    62  		if len(s) != BLSSignatureLength {
    63  			return nil, fmt.Errorf("signature must be %d bytes", BLSSignatureLength)
    64  		}
    65  	}
    66  	multiSignatures := new(blstSignature).BatchUncompress(multiSigs)
    67  	if len(multiSignatures) == 0 {
    68  		return nil, errors.New("could not unmarshal bytes into signature")
    69  	}
    70  	if len(multiSignatures) != len(multiSigs) {
    71  		return nil, errors.Errorf("wanted %d decompressed signatures but got %d", len(multiSigs), len(multiSignatures))
    72  	}
    73  	wrappedSigs := make([]common.Signature, len(multiSignatures))
    74  	for i, signature := range multiSignatures {
    75  		// Group check signature. Do not check for infinity since an aggregated signature
    76  		// could be infinite.
    77  		if !signature.SigValidate(false) {
    78  			return nil, errors.New("signature not in group")
    79  		}
    80  		copiedSig := signature
    81  		wrappedSigs[i] = &Signature{s: copiedSig}
    82  	}
    83  	return wrappedSigs, nil
    84  }
    85  
    86  // Verify a bls signature given a public key, a message.
    87  //
    88  // In IETF draft BLS specification:
    89  // Verify(PK, message, signature) -> VALID or INVALID: a verification
    90  //
    91  //	algorithm that outputs VALID if signature is a valid signature of
    92  //	message under public key PK, and INVALID otherwise.
    93  //
    94  // In the Ethereum proof of stake specification:
    95  // def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool
    96  func (s *Signature) Verify(pubKey common.PublicKey, msg []byte) bool {
    97  	// Signature and PKs are assumed to have been validated upon decompression!
    98  	return s.s.Verify(false, pubKey.(*PublicKey).p, false, msg, dst)
    99  }
   100  
   101  // AggregateVerify verifies each public key against its respective message. This is vulnerable to
   102  // rogue public-key attack. Each user must provide a proof-of-knowledge of the public key.
   103  //
   104  // Note: The msgs must be distinct. For maximum performance, this method does not ensure distinct
   105  // messages.
   106  //
   107  // In IETF draft BLS specification:
   108  // AggregateVerify((PK_1, message_1), ..., (PK_n, message_n),
   109  //
   110  //	signature) -> VALID or INVALID: an aggregate verification
   111  //	algorithm that outputs VALID if signature is a valid aggregated
   112  //	signature for a collection of public keys and messages, and
   113  //	outputs INVALID otherwise.
   114  //
   115  // In the Ethereum proof of stake specification:
   116  // def AggregateVerify(pairs: Sequence[PK: BLSPubkey, message: Bytes], signature: BLSSignature) -> bool
   117  //
   118  // Deprecated: Use FastAggregateVerify or use this method in spectests only.
   119  func (s *Signature) AggregateVerify(pubKeys []common.PublicKey, msgs [][32]byte) bool {
   120  	size := len(pubKeys)
   121  	if size == 0 {
   122  		return false
   123  	}
   124  	if size != len(msgs) {
   125  		return false
   126  	}
   127  	msgSlices := make([][]byte, len(msgs))
   128  	rawKeys := make([]*blstPublicKey, len(msgs))
   129  	for i := 0; i < size; i++ {
   130  		msgSlices[i] = msgs[i][:]
   131  		rawKeys[i] = pubKeys[i].(*PublicKey).p
   132  	}
   133  	// Signature and PKs are assumed to have been validated upon decompression!
   134  	return s.s.AggregateVerify(false, rawKeys, false, msgSlices, dst)
   135  }
   136  
   137  // FastAggregateVerify verifies all the provided public keys with their aggregated signature.
   138  //
   139  // In IETF draft BLS specification:
   140  // FastAggregateVerify(PK_1, ..., PK_n, message, signature) -> VALID
   141  //
   142  //	or INVALID: a verification algorithm for the aggregate of multiple
   143  //	signatures on the same message.  This function is faster than
   144  //	AggregateVerify.
   145  //
   146  // In the Ethereum proof of stake specification:
   147  // def FastAggregateVerify(PKs: Sequence[BLSPubkey], message: Bytes, signature: BLSSignature) -> bool
   148  func (s *Signature) FastAggregateVerify(pubKeys []common.PublicKey, msg [32]byte) bool {
   149  	if len(pubKeys) == 0 {
   150  		return false
   151  	}
   152  	rawKeys := make([]*blstPublicKey, len(pubKeys))
   153  	for i := 0; i < len(pubKeys); i++ {
   154  		rawKeys[i] = pubKeys[i].(*PublicKey).p
   155  	}
   156  	return s.s.FastAggregateVerify(true, rawKeys, msg[:], dst)
   157  }
   158  
   159  // Eth2FastAggregateVerify implements a wrapper on top of bls's FastAggregateVerify. It accepts G2_POINT_AT_INFINITY signature
   160  // when pubkeys empty.
   161  //
   162  // Spec code:
   163  // def eth2_fast_aggregate_verify(pubkeys: Sequence[BLSPubkey], message: Bytes32, signature: BLSSignature) -> bool:
   164  //
   165  //	"""
   166  //	Wrapper to ``bls.FastAggregateVerify`` accepting the ``G2_POINT_AT_INFINITY`` signature when ``pubkeys`` is empty.
   167  //	"""
   168  //	if len(pubkeys) == 0 and signature == G2_POINT_AT_INFINITY:
   169  //	    return True
   170  //	return bls.FastAggregateVerify(pubkeys, message, signature)
   171  func (s *Signature) Eth2FastAggregateVerify(pubKeys []common.PublicKey, msg [32]byte) bool {
   172  	if len(pubKeys) == 0 && bytes.Equal(s.Marshal(), common.InfiniteSignature[:]) {
   173  		return true
   174  	}
   175  	return s.FastAggregateVerify(pubKeys, msg)
   176  }
   177  
   178  // NewAggregateSignature creates a blank aggregate signature.
   179  func NewAggregateSignature() common.Signature {
   180  	sig := blst.HashToG2([]byte{'m', 'o', 'c', 'k'}, dst).ToAffine()
   181  	return &Signature{s: sig}
   182  }
   183  
   184  // AggregateSignatures converts a list of signatures into a single, aggregated sig.
   185  func AggregateSignatures(sigs []common.Signature) common.Signature {
   186  	if len(sigs) == 0 {
   187  		return nil
   188  	}
   189  
   190  	rawSigs := make([]*blstSignature, len(sigs))
   191  	for i := 0; i < len(sigs); i++ {
   192  		rawSigs[i] = sigs[i].(*Signature).s
   193  	}
   194  
   195  	// Signature and PKs are assumed to have been validated upon decompression!
   196  	signature := new(blstAggregateSignature)
   197  	signature.Aggregate(rawSigs, false)
   198  	return &Signature{s: signature.ToAffine()}
   199  }
   200  
   201  // VerifyMultipleSignatures verifies a non-singular set of signatures and its respective pubkeys and messages.
   202  // This method provides a safe way to verify multiple signatures at once. We pick a number randomly from 1 to max
   203  // uint64 and then multiply the signature by it. We continue doing this for all signatures and its respective pubkeys.
   204  // S* = S_1 * r_1 + S_2 * r_2 + ... + S_n * r_n
   205  // P'_{i,j} = P_{i,j} * r_i
   206  // e(S*, G) = \prod_{i=1}^n \prod_{j=1}^{m_i} e(P'_{i,j}, M_{i,j})
   207  // Using this we can verify multiple signatures safely.
   208  func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []common.PublicKey) (bool, error) {
   209  	if len(sigs) == 0 || len(pubKeys) == 0 {
   210  		return false, nil
   211  	}
   212  	rawSigs := new(blstSignature).BatchUncompress(sigs)
   213  
   214  	length := len(sigs)
   215  	if length != len(pubKeys) || length != len(msgs) {
   216  		return false, errors.Errorf("provided signatures, pubkeys and messages have differing lengths. S: %d, P: %d,M %d",
   217  			length, len(pubKeys), len(msgs))
   218  	}
   219  	mulP1Aff := make([]*blstPublicKey, length)
   220  	rawMsgs := make([]blst.Message, length)
   221  
   222  	for i := 0; i < length; i++ {
   223  		mulP1Aff[i] = pubKeys[i].(*PublicKey).p
   224  		rawMsgs[i] = msgs[i][:]
   225  	}
   226  	// Secure source of RNG
   227  	randGen := rand.NewGenerator()
   228  	randLock := new(sync.Mutex)
   229  
   230  	randFunc := func(scalar *blst.Scalar) {
   231  		var rbytes [scalarBytes]byte
   232  		randLock.Lock()
   233  		randGen.Read(rbytes[:]) // #nosec G104 -- Error will always be nil in `read` in math/rand
   234  		randLock.Unlock()
   235  		// Protect against the generator returning 0. Since the scalar value is
   236  		// derived from a big endian byte slice, we take the last byte.
   237  		rbytes[len(rbytes)-1] |= 0x01
   238  		scalar.FromBEndian(rbytes[:])
   239  	}
   240  	dummySig := new(blstSignature)
   241  
   242  	// Validate signatures since we uncompress them here. Public keys should already be validated.
   243  	return dummySig.MultipleAggregateVerify(rawSigs, true, mulP1Aff, false, rawMsgs, dst, randFunc, randBitsEntropy), nil
   244  }
   245  
   246  // Marshal a signature into a LittleEndian byte slice.
   247  func (s *Signature) Marshal() []byte {
   248  	return s.s.Compress()
   249  }
   250  
   251  // Copy returns a full deep copy of a signature.
   252  func (s *Signature) Copy() common.Signature {
   253  	sign := *s.s
   254  	return &Signature{s: &sign}
   255  }
   256  
   257  // VerifyCompressed verifies that the compressed signature and pubkey
   258  // are valid from the message provided.
   259  func VerifyCompressed(signature, pub, msg []byte) bool {
   260  	// Validate signature and PKs since we will uncompress them here
   261  	return new(blstSignature).VerifyCompressed(signature, true, pub, true, msg, dst)
   262  }