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 }