-
Notifications
You must be signed in to change notification settings - Fork 175
/
signature.go
136 lines (121 loc) · 7.09 KB
/
signature.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package hotstuff
import (
"github.com/onflow/flow-go/crypto"
"github.com/onflow/flow-go/model/flow"
)
// RandomBeaconReconstructor encapsulates all methods needed by a Hotstuff leader to validate the
// beacon votes and reconstruct a beacon signature.
// The random beacon methods are based on a threshold signature scheme.
type RandomBeaconReconstructor interface {
// Verify verifies the signature share under the signer's public key and the message agreed upon.
// The function is thread-safe and wait-free (i.e. allowing arbitrary many routines to
// execute the business logic, without interfering with each other).
// It allows concurrent verification of the given signature.
// Returns :
// - model.InvalidSignerError if signerIndex is invalid
// - model.ErrInvalidSignature if signerID is valid but signature is cryptographically invalid
// - other error if there is an unexpected exception.
Verify(signerID flow.Identifier, sig crypto.Signature) error
// TrustedAdd adds a share to the internal signature shares store.
// There is no pre-check of the signature's validity _before_ adding it.
// It is the caller's responsibility to make sure the signature was previously verified.
// Nevertheless, the implementation guarantees safety (only correct threshold signatures
// are returned) through a post-check (verifying the threshold signature
// _after_ reconstruction before returning it).
// The function is thread-safe but locks its internal state, thereby permitting only
// one routine at a time to add a signature.
// Returns:
// - (true, nil) if the signature has been added, and enough shares have been collected.
// - (false, nil) if the signature has been added, but not enough shares were collected.
// - (false, error) if there is any exception adding the signature share.
// - model.InvalidSignerError if signerIndex is invalid (out of the valid range)
// - model.DuplicatedSignerError if the signer has been already added
// - other error if there is an unexpected exception.
TrustedAdd(signerID flow.Identifier, sig crypto.Signature) (EnoughShares bool, err error)
// EnoughShares indicates whether enough shares have been accumulated in order to reconstruct
// a group signature. The function is thread-safe.
EnoughShares() bool
// Reconstruct reconstructs the group signature. The function is thread-safe but locks
// its internal state, thereby permitting only one routine at a time.
//
// Returns:
// - (signature, nil) if no error occurred
// - (nil, model.InsufficientSignaturesError) if not enough shares were collected
// - (nil, model.InvalidSignatureIncluded) if at least one collected share does not serialize to a valid BLS signature,
// or if the constructed signature failed to verify against the group public key and stored message. This post-verification
// is required for safety, as `TrustedAdd` allows adding invalid signatures.
// - (nil, error) for any other unexpected error.
Reconstruct() (crypto.Signature, error)
}
// SigType is the aggregable signature type.
type SigType uint8
// SigType specifies the role of the signature in the protocol.
// Both types are aggregatable cryptographic signatures.
// * SigTypeRandomBeacon type is for random beacon signatures.
// * SigTypeStaking is for Hotstuff signatures.
const (
SigTypeStaking SigType = iota
SigTypeRandomBeacon
)
// Valid returns true if the signature is either SigTypeStaking or SigTypeRandomBeacon
// else return false
func (t SigType) Valid() bool {
return t == SigTypeStaking || t == SigTypeRandomBeacon
}
// WeightedSignatureAggregator aggregates signatures of the same signature scheme and the
// same message from different signers. The public keys and message are agreed upon upfront.
// It is also recommended to only aggregate signatures generated with keys representing
// equivalent security-bit level.
// Furthermore, a weight [unsigned int64] is assigned to each signer ID. The
// WeightedSignatureAggregator internally tracks the total weight of all collected signatures.
// Implementations must be concurrency safe.
type WeightedSignatureAggregator interface {
// Verify verifies the signature under the stored public keys and message.
// Expected errors during normal operations:
// - model.InvalidSignerError if signerID is invalid (not a consensus participant)
// - model.ErrInvalidSignature if signerID is valid but signature is cryptographically invalid
Verify(signerID flow.Identifier, sig crypto.Signature) error
// TrustedAdd adds a signature to the internal set of signatures and adds the signer's
// weight to the total collected weight, iff the signature is _not_ a duplicate. The
// total weight of all collected signatures (excluding duplicates) is returned regardless
// of any returned error.
// Expected errors during normal operations:
// - model.InvalidSignerError if signerID is invalid (not a consensus participant)
// - model.DuplicatedSignerError if the signer has been already added
TrustedAdd(signerID flow.Identifier, sig crypto.Signature) (totalWeight uint64, exception error)
// TotalWeight returns the total weight presented by the collected signatures.
TotalWeight() uint64
// Aggregate aggregates the signatures and returns the aggregated signature.
// The function performs a final verification and errors if the aggregated
// signature is not valid. This is required for the function safety since
// `TrustedAdd` allows adding invalid signatures.
// Expected errors during normal operations:
// - model.InsufficientSignaturesError if no signatures have been added yet
// - model.InvalidSignatureIncludedError if some signature(s), included via TrustedAdd, are invalid
Aggregate() ([]flow.Identifier, []byte, error)
}
// BlockSignatureData is an intermediate struct for Packer to pack the
// aggregated signature data into raw bytes or unpack from raw bytes.
type BlockSignatureData struct {
StakingSigners []flow.Identifier
RandomBeaconSigners []flow.Identifier
AggregatedStakingSig []byte // if BLS is used, this is equivalent to crypto.Signature
AggregatedRandomBeaconSig []byte // if BLS is used, this is equivalent to crypto.Signature
ReconstructedRandomBeaconSig crypto.Signature
}
// Packer packs aggregated signature data into raw bytes to be used in block header.
type Packer interface {
// Pack serializes the provided BlockSignatureData into a precursor format of a QC.
// blockID is the block that the aggregated signature is for.
// sig is the aggregated signature data.
// Expected error returns during normal operations:
// * none; all errors are symptoms of inconsistent input data or corrupted internal state.
Pack(blockID flow.Identifier, sig *BlockSignatureData) ([]flow.Identifier, []byte, error)
// Unpack de-serializes the provided signature data.
// blockID is the block that the aggregated sig is signed for
// sig is the aggregated signature data
// It returns:
// - (sigData, nil) if successfully unpacked the signature data
// - (nil, model.ErrInvalidFormat) if failed to unpack the signature data
Unpack(blockID flow.Identifier, signerIDs []flow.Identifier, sigData []byte) (*BlockSignatureData, error)
}