github.com/onflow/flow-go@v0.33.17/consensus/hotstuff/signature.go (about)

     1  package hotstuff
     2  
     3  import (
     4  	"github.com/onflow/flow-go/crypto"
     5  	"github.com/onflow/flow-go/model/flow"
     6  )
     7  
     8  // RandomBeaconReconstructor encapsulates all methods needed by a Hotstuff leader to validate the
     9  // beacon votes and reconstruct a beacon signature.
    10  // The random beacon methods are based on a threshold signature scheme.
    11  type RandomBeaconReconstructor interface {
    12  	// Verify verifies the signature share under the signer's public key and the message agreed upon.
    13  	// The function is thread-safe and wait-free (i.e. allowing arbitrary many routines to
    14  	// execute the business logic, without interfering with each other).
    15  	// It allows concurrent verification of the given signature.
    16  	// Returns :
    17  	//  - model.InvalidSignerError if signerIndex is invalid
    18  	//  - model.ErrInvalidSignature if signerID is valid but signature is cryptographically invalid
    19  	//  - other error if there is an unexpected exception.
    20  	Verify(signerID flow.Identifier, sig crypto.Signature) error
    21  
    22  	// TrustedAdd adds a share to the internal signature shares store.
    23  	// There is no pre-check of the signature's validity _before_ adding it.
    24  	// It is the caller's responsibility to make sure the signature was previously verified.
    25  	// Nevertheless, the implementation guarantees safety (only correct threshold signatures
    26  	// are returned) through a post-check (verifying the threshold signature
    27  	// _after_ reconstruction before returning it).
    28  	// The function is thread-safe but locks its internal state, thereby permitting only
    29  	// one routine at a time to add a signature.
    30  	// Returns:
    31  	//  - (true, nil) if the signature has been added, and enough shares have been collected.
    32  	//  - (false, nil) if the signature has been added, but not enough shares were collected.
    33  	//  - (false, error) if there is any exception adding the signature share.
    34  	//      - model.InvalidSignerError if signerIndex is invalid (out of the valid range)
    35  	//  	- model.DuplicatedSignerError if the signer has been already added
    36  	//      - other error if there is an unexpected exception.
    37  	TrustedAdd(signerID flow.Identifier, sig crypto.Signature) (EnoughShares bool, err error)
    38  
    39  	// EnoughShares indicates whether enough shares have been accumulated in order to reconstruct
    40  	// a group signature. The function is thread-safe.
    41  	EnoughShares() bool
    42  
    43  	// Reconstruct reconstructs the group signature. The function is thread-safe but locks
    44  	// its internal state, thereby permitting only one routine at a time.
    45  	//
    46  	// Returns:
    47  	// - (signature, nil) if no error occurred
    48  	// - (nil, model.InsufficientSignaturesError) if not enough shares were collected
    49  	// - (nil, model.InvalidSignatureIncluded) if at least one collected share does not serialize to a valid BLS signature,
    50  	//    or if the constructed signature failed to verify against the group public key and stored message. This post-verification
    51  	//    is required  for safety, as `TrustedAdd` allows adding invalid signatures.
    52  	// - (nil, error) for any other unexpected error.
    53  	Reconstruct() (crypto.Signature, error)
    54  }
    55  
    56  // WeightedSignatureAggregator aggregates signatures of the same signature scheme and the
    57  // same message from different signers. The public keys and message are agreed upon upfront.
    58  // It is also recommended to only aggregate signatures generated with keys representing
    59  // equivalent security-bit level.
    60  // Furthermore, a weight [unsigned int64] is assigned to each signer ID. The
    61  // WeightedSignatureAggregator internally tracks the total weight of all collected signatures.
    62  // Implementations must be concurrency safe.
    63  type WeightedSignatureAggregator interface {
    64  	// Verify verifies the signature under the stored public keys and message.
    65  	// Expected errors during normal operations:
    66  	//  - model.InvalidSignerError if signerID is invalid (not a consensus participant)
    67  	//  - model.ErrInvalidSignature if signerID is valid but signature is cryptographically invalid
    68  	Verify(signerID flow.Identifier, sig crypto.Signature) error
    69  
    70  	// TrustedAdd adds a signature to the internal set of signatures and adds the signer's
    71  	// weight to the total collected weight, iff the signature is _not_ a duplicate. The
    72  	// total weight of all collected signatures (excluding duplicates) is returned regardless
    73  	// of any returned error.
    74  	// Expected errors during normal operations:
    75  	//  - model.InvalidSignerError if signerID is invalid (not a consensus participant)
    76  	//  - model.DuplicatedSignerError if the signer has been already added
    77  	TrustedAdd(signerID flow.Identifier, sig crypto.Signature) (totalWeight uint64, exception error)
    78  
    79  	// TotalWeight returns the total weight presented by the collected signatures.
    80  	TotalWeight() uint64
    81  
    82  	// Aggregate aggregates the signatures and returns the aggregated signature.
    83  	// The function performs a final verification and errors if the aggregated signature is invalid. This is
    84  	// required for the function safety since `TrustedAdd` allows adding invalid signatures.
    85  	// The function errors with:
    86  	//   - model.InsufficientSignaturesError if no signatures have been added yet
    87  	//   - model.InvalidSignatureIncludedError if:
    88  	//     -- some signature(s), included via TrustedAdd, fail to deserialize (regardless of the aggregated public key)
    89  	//     -- or all signatures deserialize correctly but some signature(s), included via TrustedAdd, are
    90  	//       invalid (while aggregated public key is valid)
    91  	//   - model.InvalidAggregatedKeyError if all signatures deserialize correctly but the signer's
    92  	//     staking public keys sum up to an invalid key (BLS identity public key).
    93  	//     Any aggregated signature would fail the cryptographic verification under the identity public
    94  	//     key and therefore such signature is considered invalid. Such scenario can only happen if
    95  	//     staking public keys of signers were forged to add up to the identity public key.
    96  	//     Under the assumption that all staking key PoPs are valid, this error case can only
    97  	//     happen if all signers are malicious and colluding. If there is at least one honest signer,
    98  	//     there is a negligible probability that the aggregated key is identity.
    99  	//
   100  	// The function is thread-safe.
   101  	Aggregate() (flow.IdentifierList, []byte, error)
   102  }
   103  
   104  // TimeoutSignatureAggregator aggregates timeout signatures for one particular view.
   105  // When instantiating a TimeoutSignatureAggregator, the following information is supplied:
   106  //   - The view for which the aggregator collects timeouts.
   107  //   - For each replicas that is authorized to send a timeout at this particular view:
   108  //     the node ID, public staking keys, and weight
   109  //
   110  // Timeouts for other views or from non-authorized replicas are rejected.
   111  // In their TimeoutObjects, replicas include a signature over the pair (view, newestQCView),
   112  // where `view` is the view number the timeout is for and `newestQCView` is the view of
   113  // the newest QC known to the replica. TimeoutSignatureAggregator collects these signatures,
   114  // internally tracks the total weight of all collected signatures. Note that in general the
   115  // signed messages are different, which makes the aggregation a comparatively expensive operation.
   116  // Upon calling `Aggregate`, the TimeoutSignatureAggregator aggregates all valid signatures collected
   117  // up to this point. The aggregate signature is guaranteed to be correct, as only valid signatures
   118  // are excepted as inputs.
   119  // TimeoutSignatureAggregator internally tracks the total weight of all collected signatures.
   120  // Implementations must be concurrency safe.
   121  type TimeoutSignatureAggregator interface {
   122  	// VerifyAndAdd verifies the signature under the stored public keys and adds the signature and the corresponding
   123  	// highest QC to the internal set. Internal set and collected weight is modified iff signature _is_ valid.
   124  	// The total weight of all collected signatures (excluding duplicates) is returned regardless
   125  	// of any returned error.
   126  	// Expected errors during normal operations:
   127  	//  - model.InvalidSignerError if signerID is invalid (not a consensus participant)
   128  	//  - model.DuplicatedSignerError if the signer has been already added
   129  	//  - model.ErrInvalidSignature if signerID is valid but signature is cryptographically invalid
   130  	VerifyAndAdd(signerID flow.Identifier, sig crypto.Signature, newestQCView uint64) (totalWeight uint64, exception error)
   131  
   132  	// TotalWeight returns the total weight presented by the collected signatures.
   133  	TotalWeight() uint64
   134  
   135  	// View returns the view that this instance is aggregating signatures for.
   136  	View() uint64
   137  
   138  	// Aggregate aggregates the signatures and returns with additional data.
   139  	// Aggregated signature will be returned as SigData of timeout certificate.
   140  	// Caller can be sure that resulting signature is valid.
   141  	// Expected errors during normal operations:
   142  	//  - model.InsufficientSignaturesError if no signatures have been added yet
   143  	Aggregate() (signersInfo []TimeoutSignerInfo, aggregatedSig crypto.Signature, exception error)
   144  }
   145  
   146  // TimeoutSignerInfo is a helper structure that stores the QC views that each signer
   147  // contributed to a TC. Used as result of TimeoutSignatureAggregator.Aggregate()
   148  type TimeoutSignerInfo struct {
   149  	NewestQCView uint64
   150  	Signer       flow.Identifier
   151  }
   152  
   153  // BlockSignatureData is an intermediate struct for Packer to pack the
   154  // aggregated signature data into raw bytes or unpack from raw bytes.
   155  type BlockSignatureData struct {
   156  	StakingSigners               flow.IdentifierList
   157  	RandomBeaconSigners          flow.IdentifierList
   158  	AggregatedStakingSig         []byte // if BLS is used, this is equivalent to crypto.Signature
   159  	AggregatedRandomBeaconSig    []byte // if BLS is used, this is equivalent to crypto.Signature
   160  	ReconstructedRandomBeaconSig crypto.Signature
   161  }
   162  
   163  // Packer packs aggregated signature data into raw bytes to be used in block header.
   164  type Packer interface {
   165  	// Pack serializes the provided BlockSignatureData into a precursor format of a QC.
   166  	// view is the view of the block that the aggregated signature is for.
   167  	// sig is the aggregated signature data.
   168  	// Expected error returns during normal operations:
   169  	//  * none; all errors are symptoms of inconsistent input data or corrupted internal state.
   170  	Pack(view uint64, sig *BlockSignatureData) (signerIndices []byte, sigData []byte, err error)
   171  
   172  	// Unpack de-serializes the provided signature data.
   173  	// sig is the aggregated signature data
   174  	// It returns:
   175  	//  - (sigData, nil) if successfully unpacked the signature data
   176  	//  - (nil, model.InvalidFormatError) if failed to unpack the signature data
   177  	Unpack(signerIdentities flow.IdentityList, sigData []byte) (*BlockSignatureData, error)
   178  }