github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/signature.go (about)

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