forked from tendermint/tendermint
-
Notifications
You must be signed in to change notification settings - Fork 2
/
threshold_pubkey.go
92 lines (84 loc) · 2.7 KB
/
threshold_pubkey.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
package multisig
import (
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/tmhash"
)
// PubKeyMultisigThreshold implements a K of N threshold multisig.
type PubKeyMultisigThreshold struct {
K uint `json:"threshold"`
PubKeys []crypto.PubKey `json:"pubkeys"`
}
var _ crypto.PubKey = &PubKeyMultisigThreshold{}
// NewPubKeyMultisigThreshold returns a new PubKeyMultisigThreshold.
// Panics if len(pubkeys) < k or 0 >= k.
func NewPubKeyMultisigThreshold(k int, pubkeys []crypto.PubKey) crypto.PubKey {
if k <= 0 {
panic("threshold k of n multisignature: k <= 0")
}
if len(pubkeys) < k {
panic("threshold k of n multisignature: len(pubkeys) < k")
}
return &PubKeyMultisigThreshold{uint(k), pubkeys}
}
// VerifyBytes expects sig to be an amino encoded version of a MultiSignature.
// Returns true iff the multisignature contains k or more signatures
// for the correct corresponding keys,
// and all signatures are valid. (Not just k of the signatures)
// The multisig uses a bitarray, so multiple signatures for the same key is not
// a concern.
func (pk *PubKeyMultisigThreshold) VerifyBytes(msg []byte, marshalledSig []byte) bool {
var sig *Multisignature
err := cdc.UnmarshalBinaryBare(marshalledSig, &sig)
if err != nil {
return false
}
size := sig.BitArray.Size()
// ensure bit array is the correct size
if len(pk.PubKeys) != size {
return false
}
// ensure size of signature list
if len(sig.Sigs) < int(pk.K) || len(sig.Sigs) > size {
return false
}
// ensure at least k signatures are set
if sig.BitArray.NumTrueBitsBefore(size) < int(pk.K) {
return false
}
// index in the list of signatures which we are concerned with.
sigIndex := 0
for i := 0; i < size; i++ {
if sig.BitArray.GetIndex(i) {
if !pk.PubKeys[i].VerifyBytes(msg, sig.Sigs[sigIndex]) {
return false
}
sigIndex++
}
}
return true
}
// Bytes returns the amino encoded version of the PubKeyMultisigThreshold
func (pk *PubKeyMultisigThreshold) Bytes() []byte {
return cdc.MustMarshalBinaryBare(pk)
}
// Address returns tmhash(PubKeyMultisigThreshold.Bytes())
func (pk *PubKeyMultisigThreshold) Address() crypto.Address {
return crypto.Address(tmhash.Sum(pk.Bytes()))
}
// Equals returns true iff pk and other both have the same number of keys, and
// all constituent keys are the same, and in the same order.
func (pk *PubKeyMultisigThreshold) Equals(other crypto.PubKey) bool {
otherKey, sameType := other.(*PubKeyMultisigThreshold)
if !sameType {
return false
}
if pk.K != otherKey.K || len(pk.PubKeys) != len(otherKey.PubKeys) {
return false
}
for i := 0; i < len(pk.PubKeys); i++ {
if !pk.PubKeys[i].Equals(otherKey.PubKeys[i]) {
return false
}
}
return true
}