forked from strangelove-ventures/horcrux
/
cosigner.go
145 lines (121 loc) · 3.4 KB
/
cosigner.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
138
139
140
141
142
143
144
145
package signer
import (
"context"
"time"
cometcrypto "github.com/cometbft/cometbft/crypto"
"github.com/google/uuid"
"github.com/strangelove-ventures/horcrux/signer/proto"
)
// Cosigner interface is a set of methods for an m-of-n threshold signature.
// This interface abstracts the underlying key storage and management
type Cosigner interface {
// Get the ID of the cosigner
// The ID is the shamir index: 1, 2, etc...
GetID() int
// Get the P2P URL (GRPC and Raft)
GetAddress() string
// Get the combined public key
GetPubKey(chainID string) (cometcrypto.PubKey, error)
VerifySignature(chainID string, payload, signature []byte) bool
// Get nonces for all cosigner shards
GetNonces(ctx context.Context, uuids []uuid.UUID) (CosignerUUIDNoncesMultiple, error)
// Sign the requested bytes
SetNoncesAndSign(ctx context.Context, req CosignerSetNoncesAndSignRequest) (*CosignerSignResponse, error)
}
type Cosigners []Cosigner
func (cosigners Cosigners) GetByID(id int) Cosigner {
for _, cosigner := range cosigners {
if cosigner.GetID() == id {
return cosigner
}
}
return nil
}
// CosignerSignRequest is sent to a co-signer to obtain their signature for the SignBytes
// The SignBytes should be a serialized block
type CosignerSignRequest struct {
ChainID string
SignBytes []byte
UUID uuid.UUID
}
type CosignerSignResponse struct {
NoncePublic []byte
Timestamp time.Time
Signature []byte
}
type CosignerNonce struct {
SourceID int
DestinationID int
PubKey []byte
Share []byte
Signature []byte
}
func (secretPart *CosignerNonce) toProto() *proto.Nonce {
return &proto.Nonce{
SourceID: int32(secretPart.SourceID),
DestinationID: int32(secretPart.DestinationID),
PubKey: secretPart.PubKey,
Share: secretPart.Share,
Signature: secretPart.Signature,
}
}
type CosignerNonces []CosignerNonce
func (secretParts CosignerNonces) toProto() (out []*proto.Nonce) {
for _, secretPart := range secretParts {
out = append(out, secretPart.toProto())
}
return
}
func CosignerNonceFromProto(secretPart *proto.Nonce) CosignerNonce {
return CosignerNonce{
SourceID: int(secretPart.SourceID),
DestinationID: int(secretPart.DestinationID),
PubKey: secretPart.PubKey,
Share: secretPart.Share,
Signature: secretPart.Signature,
}
}
func CosignerNoncesFromProto(secretParts []*proto.Nonce) []CosignerNonce {
out := make([]CosignerNonce, len(secretParts))
for i, secretPart := range secretParts {
out[i] = CosignerNonceFromProto(secretPart)
}
return out
}
type CosignerSignBlockRequest struct {
ChainID string
Block *Block
}
type CosignerSignBlockResponse struct {
Signature []byte
}
type CosignerUUIDNonces struct {
UUID uuid.UUID
Nonces CosignerNonces
}
func (n *CosignerUUIDNonces) For(id int) *CosignerUUIDNonces {
res := &CosignerUUIDNonces{UUID: n.UUID}
for _, nonce := range n.Nonces {
if nonce.DestinationID == id {
res.Nonces = append(res.Nonces, nonce)
}
}
return res
}
type CosignerUUIDNoncesMultiple []*CosignerUUIDNonces
func (n CosignerUUIDNoncesMultiple) toProto() []*proto.UUIDNonce {
out := make([]*proto.UUIDNonce, len(n))
for i, nonces := range n {
out[i] = &proto.UUIDNonce{
Uuid: nonces.UUID[:],
Nonces: nonces.Nonces.toProto(),
}
}
return out
}
type CosignerSetNoncesAndSignRequest struct {
ChainID string
Nonces *CosignerUUIDNonces
HRST HRSTKey
SignBytes []byte
}