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 }