github.com/koko1123/flow-go-1@v0.29.6/consensus/hotstuff/signature/randombeacon_inspector.go (about)

     1  package signature
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/koko1123/flow-go-1/consensus/hotstuff/model"
     7  	"github.com/koko1123/flow-go-1/module/signature"
     8  	"github.com/onflow/flow-go/crypto"
     9  )
    10  
    11  // randomBeaconInspector implements hotstuff.RandomBeaconInspector interface.
    12  // All methods of this structure are concurrency-safe.
    13  type randomBeaconInspector struct {
    14  	inspector crypto.ThresholdSignatureInspector
    15  }
    16  
    17  // NewRandomBeaconInspector instantiates a new randomBeaconInspector.
    18  // The constructor errors with a `model.ConfigurationError` in any of the following cases
    19  //   - n is not between `ThresholdSignMinSize` and `ThresholdSignMaxSize`,
    20  //     for n the number of participants `n := len(publicKeyShares)`
    21  //   - threshold value is not in interval [1, n-1]
    22  //   - any input public key is not a BLS key
    23  func NewRandomBeaconInspector(
    24  	groupPublicKey crypto.PublicKey,
    25  	publicKeyShares []crypto.PublicKey,
    26  	threshold int,
    27  	message []byte,
    28  ) (*randomBeaconInspector, error) {
    29  	inspector, err := crypto.NewBLSThresholdSignatureInspector(
    30  		groupPublicKey,
    31  		publicKeyShares,
    32  		threshold,
    33  		message,
    34  		signature.RandomBeaconTag)
    35  	if err != nil {
    36  		if crypto.IsInvalidInputsError(err) {
    37  			return nil, model.NewConfigurationErrorf("invalid parametrization for BLS Threshold Signature Inspector: %w", err)
    38  		}
    39  		return nil, fmt.Errorf("unexpected exception while instantiating BLS Threshold Signature Inspector: %w", err)
    40  	}
    41  
    42  	return &randomBeaconInspector{
    43  		inspector: inspector,
    44  	}, nil
    45  }
    46  
    47  // Verify verifies the signature share under the signer's public key and the message agreed upon.
    48  // The function is thread-safe and wait-free (i.e. allowing arbitrary many routines to
    49  // execute the business logic, without interfering with each other).
    50  // It allows concurrent verification of the given signature.
    51  // Returns :
    52  //   - model.InvalidSignerError if signerIndex is invalid
    53  //   - model.ErrInvalidSignature if signerID is valid but signature is cryptographically invalid
    54  //   - other error if there is an unexpected exception.
    55  func (r *randomBeaconInspector) Verify(signerIndex int, share crypto.Signature) error {
    56  	valid, err := r.inspector.VerifyShare(signerIndex, share)
    57  	if err != nil {
    58  		if crypto.IsInvalidInputsError(err) {
    59  			return model.NewInvalidSignerError(err)
    60  		}
    61  		return fmt.Errorf("unexpected error verifying beacon signature from %d: %w", signerIndex, err)
    62  	}
    63  
    64  	if !valid { // invalid signature
    65  		return fmt.Errorf("invalid beacon share from signer Index %d: %w", signerIndex, model.ErrInvalidSignature)
    66  	}
    67  	return nil
    68  }
    69  
    70  // TrustedAdd adds a share to the internal signature shares store.
    71  // There is no pre-check of the signature's validity _before_ adding it.
    72  // It is the caller's responsibility to make sure the signature was previously verified.
    73  // Nevertheless, the implementation guarantees safety (only correct threshold signatures
    74  // are returned) through a post-check (verifying the threshold signature
    75  // _after_ reconstruction before returning it).
    76  // The function is thread-safe but locks its internal state, thereby permitting only
    77  // one routine at a time to add a signature.
    78  // Returns:
    79  //   - (true, nil) if the signature has been added, and enough shares have been collected.
    80  //   - (false, nil) if the signature has been added, but not enough shares were collected.
    81  //
    82  // The following errors are expected during normal operations:
    83  //   - model.InvalidSignerError if signerIndex is invalid (out of the valid range)
    84  //   - model.DuplicatedSignerError if the signer has been already added
    85  //   - other error if there is an unexpected exception.
    86  func (r *randomBeaconInspector) TrustedAdd(signerIndex int, share crypto.Signature) (bool, error) {
    87  	// Trusted add to the crypto layer
    88  	enough, err := r.inspector.TrustedAdd(signerIndex, share)
    89  	if err != nil {
    90  		if crypto.IsInvalidInputsError(err) {
    91  			return false, model.NewInvalidSignerError(err)
    92  		}
    93  		if crypto.IsDuplicatedSignerError(err) {
    94  			return false, model.NewDuplicatedSignerError(err)
    95  		}
    96  		return false, fmt.Errorf("unexpected error while adding share from %d: %w", signerIndex, err)
    97  	}
    98  	return enough, nil
    99  }
   100  
   101  // EnoughShares indicates whether enough shares have been accumulated in order to reconstruct
   102  // a group signature.
   103  //
   104  // The function is write-blocking
   105  func (r *randomBeaconInspector) EnoughShares() bool {
   106  	return r.inspector.EnoughShares()
   107  }
   108  
   109  // Reconstruct reconstructs the group signature. The function is thread-safe but locks
   110  // its internal state, thereby permitting only one routine at a time.
   111  //
   112  // Returns:
   113  //   - (signature, nil) if no error occurred
   114  //   - (nil, model.InsufficientSignaturesError) if not enough shares were collected
   115  //   - (nil, model.InvalidSignatureIncluded) if at least one collected share does not serialize to a valid BLS signature,
   116  //     or if the constructed signature failed to verify against the group public key and stored message. This post-verification
   117  //     is required  for safety, as `TrustedAdd` allows adding invalid signatures.
   118  //   - (nil, error) for any other unexpected error.
   119  func (r *randomBeaconInspector) Reconstruct() (crypto.Signature, error) {
   120  	sig, err := r.inspector.ThresholdSignature()
   121  	if err != nil {
   122  		if crypto.IsInvalidInputsError(err) {
   123  			return nil, model.NewInvalidSignatureIncludedError(err)
   124  		}
   125  		if crypto.IsNotEnoughSharesError(err) {
   126  			return nil, model.NewInsufficientSignaturesError(err)
   127  		}
   128  		return nil, fmt.Errorf("unexpected error during random beacon sig reconstruction: %w", err)
   129  	}
   130  	return sig, nil
   131  }