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 }