forked from Consensys/handel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrypto.go
137 lines (118 loc) · 4.05 KB
/
crypto.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
137
package handel
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
)
// PublicKey represents either a generic individual or aggregate public key. It
// contain methods to verify a signature and to combine multiple public
// keys together to verify signatures.
type PublicKey interface {
// VerifySignature takes a message and a signature and returns an error iif
// the signature is invalid with respect to this public key and the message.
VerifySignature(msg []byte, sig Signature) error
// Combine combines the two public keys together to produce an aggregate
// public key. The resulting public key must be valid and able to verify
// aggregated signatures valid under the aggregate public key.
Combine(PublicKey) PublicKey
// String returns an easy representation of the public key (hex, etc).
String() string
}
// SecretKey represents a secret key. This interface is mostly needed to run the
// tests in a generic way
type SecretKey interface {
// Sign the given message using the given randomness source.
Sign(msg []byte, r io.Reader) (Signature, error)
}
// Constructor creates empty signatures of the required type suitable for
// unmarshalling and empty public keys of the required type suitable for
// aggregation. See package bn256 for an example.
type Constructor interface {
// Signature returns a fresh empty signature suitable for unmarshaling
Signature() Signature
// PublicKey returns a fresh empty public key suitable for aggregation
PublicKey() PublicKey
}
// Signature holds methods to pass from/to a binary representation and to
// combine signatures together
type Signature interface {
MarshalBinary() ([]byte, error)
UnmarshalBinary([]byte) error
// Combine aggregates the two signature together producing an unique
// signature that can be verified by the combination of both
// respective public keys that produced the original signatures.
Combine(Signature) Signature
}
// MultiSignature represents an aggregated signature alongside with its bitset.
// The signature is the aggregation of all individual signatures from the nodes
// whose index is set in the bitset.
type MultiSignature struct {
BitSet
Signature
}
// MarshalBinary implements the binary.Marshaller interface
func (m *MultiSignature) MarshalBinary() ([]byte, error) {
var b bytes.Buffer
bs, err := m.BitSet.MarshalBinary()
if err != nil {
return nil, err
}
length := uint16(len(bs))
sig, err := m.Signature.MarshalBinary()
if err != nil {
return nil, err
}
binary.Write(&b, binary.BigEndian, length)
b.Write(bs)
b.Write(sig)
return b.Bytes(), nil
}
// Unmarshal reads a multisignature from the given slice, using the *empty*
// signature and bitset interface given.
func (m *MultiSignature) Unmarshal(b []byte, s Signature, nbs func(b int) BitSet) error {
var buff = bytes.NewBuffer(b)
var length uint16
if err := binary.Read(buff, binary.BigEndian, &length); err != nil {
return err
}
bitset := buff.Next(int(length))
if len(bitset) < int(length) {
return errors.New("bitset received smaller than expected")
}
bs := nbs(int(length))
if err := bs.UnmarshalBinary(bitset); err != nil {
return err
}
if err := s.UnmarshalBinary(buff.Bytes()); err != nil {
return err
}
m.BitSet = bs
m.Signature = s
return nil
}
func (m *MultiSignature) String() string {
return fmt.Sprintf("{bitset %d/%d}",
m.BitSet.Cardinality(), m.BitSet.BitLength())
}
// VerifyMultiSignature verifies a multisignature against the given message, aby
// aggregating all public keys from the registry. It returns nil if the
// verification was sucessful, an error otherwise.
func VerifyMultiSignature(msg []byte, ms *MultiSignature, reg Registry, cons Constructor) error {
n := ms.BitSet.BitLength()
if n != reg.Size() {
return errors.New("verify multisignature: inconsistent sizes")
}
aggregate := cons.PublicKey()
for i := 0; i < n; i++ {
if ms.BitSet.Get(i) {
id, ok := reg.Identity(i)
if !ok {
return fmt.Errorf("registry returned empty identity at %d", i)
}
aggregate = aggregate.Combine(id.PublicKey())
}
}
return aggregate.VerifySignature(msg, ms.Signature)
}