Skip to content

Commit 598c4a2

Browse files
committed
Implement slot decryption signatures
1 parent 8ca5f26 commit 598c4a2

File tree

4 files changed

+146
-8
lines changed

4 files changed

+146
-8
lines changed

rolling-shutter/keyperimpl/gnosis/handlers.go

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
obskeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/chainobserver/db/keyper"
1515
corekeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/database"
1616
"github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/gnosis/database"
17+
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/identitypreimage"
1718
"github.com/shutter-network/rolling-shutter/rolling-shutter/p2pmsg"
1819
"github.com/shutter-network/rolling-shutter/rolling-shutter/shdb"
1920
)
@@ -26,7 +27,7 @@ func (h *DecryptionKeySharesHandler) MessagePrototypes() []p2pmsg.Message {
2627
return []p2pmsg.Message{&p2pmsg.DecryptionKeyShares{}}
2728
}
2829

29-
func (h *DecryptionKeySharesHandler) ValidateMessage(_ context.Context, msg p2pmsg.Message) (pubsub.ValidationResult, error) {
30+
func (h *DecryptionKeySharesHandler) ValidateMessage(ctx context.Context, msg p2pmsg.Message) (pubsub.ValidationResult, error) {
3031
keyShares := msg.(*p2pmsg.DecryptionKeyShares)
3132
extra, ok := keyShares.Extra.(*p2pmsg.DecryptionKeyShares_Gnosis)
3233
if !ok {
@@ -42,7 +43,54 @@ func (h *DecryptionKeySharesHandler) ValidateMessage(_ context.Context, msg p2pm
4243
if extra.Gnosis.TxPointer > math.MaxInt64 {
4344
return pubsub.ValidationReject, errors.New("tx pointer too large")
4445
}
45-
// TODO: check signature
46+
47+
keyperDB := corekeyperdatabase.New(h.dbpool)
48+
eon, err := keyperDB.GetEon(ctx, int64(keyShares.Eon))
49+
if err != nil {
50+
return pubsub.ValidationReject, errors.Wrapf(err, "failed to get eon from database for eon %d", keyShares.Eon)
51+
}
52+
obsKeyperDB := obskeyperdatabase.New(h.dbpool)
53+
keyperSet, err := obsKeyperDB.GetKeyperSetByKeyperConfigIndex(ctx, eon.KeyperConfigIndex)
54+
if err != nil {
55+
return pubsub.ValidationReject, errors.Wrapf(err,
56+
"failed to get keyper set from database for keyper set index %d (eon %d)",
57+
eon.KeyperConfigIndex,
58+
keyShares.Eon,
59+
)
60+
}
61+
if keyShares.KeyperIndex >= uint64(len(keyperSet.Keypers)) {
62+
return pubsub.ValidationReject, errors.Errorf(
63+
"keyper index %d out of range for keyper set %d (eon %d)",
64+
keyShares.KeyperIndex,
65+
eon.KeyperConfigIndex,
66+
keyShares.Eon,
67+
)
68+
}
69+
keyperAddressStr := keyperSet.Keypers[keyShares.KeyperIndex]
70+
keyperAddress, err := shdb.DecodeAddress(keyperAddressStr)
71+
if err != nil {
72+
return pubsub.ValidationReject, errors.Wrap(err, "failed to decode keyper address from database")
73+
}
74+
75+
identityPreimages := []identitypreimage.IdentityPreimage{}
76+
for _, share := range keyShares.Shares {
77+
identityPreimage := identitypreimage.IdentityPreimage(share.EpochID)
78+
identityPreimages = append(identityPreimages, identityPreimage)
79+
}
80+
slotDecryptionSignatureData := SlotDecryptionSignatureData{
81+
InstanceID: keyShares.InstanceID,
82+
Eon: keyShares.Eon,
83+
Slot: extra.Gnosis.Slot,
84+
TxPointer: extra.Gnosis.TxPointer,
85+
IdentityPreimages: identityPreimages,
86+
}
87+
signatureValid, err := CheckSlotDecryptionSignature(&slotDecryptionSignatureData, extra.Gnosis.Signature, keyperAddress)
88+
if err != nil {
89+
return pubsub.ValidationReject, errors.Wrap(err, "failed to check slot decryption signature")
90+
}
91+
if !signatureValid {
92+
return pubsub.ValidationReject, errors.New("slot decryption signature invalid")
93+
}
4694

4795
return pubsub.ValidationAccept, nil
4896
}
@@ -193,7 +241,29 @@ func (h *DecryptionKeysHandler) ValidateMessage(ctx context.Context, msg p2pmsg.
193241
signers = append(signers, signer)
194242
}
195243

196-
// TODO: check signatures
244+
identityPreimages := []identitypreimage.IdentityPreimage{}
245+
for _, key := range keys.Keys {
246+
identityPreimage := identitypreimage.IdentityPreimage(key.Identity)
247+
identityPreimages = append(identityPreimages, identityPreimage)
248+
}
249+
slotDecryptionSignatureData := SlotDecryptionSignatureData{
250+
InstanceID: keys.InstanceID,
251+
Eon: keys.Eon,
252+
Slot: extra.Gnosis.Slot,
253+
TxPointer: extra.Gnosis.TxPointer,
254+
IdentityPreimages: identityPreimages,
255+
}
256+
for signatureIndex := 0; signatureIndex < len(extra.Gnosis.Signatures); signatureIndex++ {
257+
signature := extra.Gnosis.Signatures[signatureIndex]
258+
signer := signers[signatureIndex]
259+
signatureValid, err := CheckSlotDecryptionSignature(&slotDecryptionSignatureData, signature, signer)
260+
if err != nil {
261+
return pubsub.ValidationReject, errors.Wrap(err, "failed to check slot decryption signature")
262+
}
263+
if !signatureValid {
264+
return pubsub.ValidationReject, errors.New("slot decryption signature invalid")
265+
}
266+
}
197267

198268
return pubsub.ValidationAccept, nil
199269
}

rolling-shutter/keyperimpl/gnosis/keyper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func (kpr *Keyper) Start(ctx context.Context, runner service.Runner) error {
7272
}
7373
messageSender.AddMessageHandler(&DecryptionKeySharesHandler{kpr.dbpool})
7474
messageSender.AddMessageHandler(&DecryptionKeysHandler{kpr.dbpool})
75-
messagingMiddleware := NewMessagingMiddleware(messageSender, kpr.dbpool)
75+
messagingMiddleware := NewMessagingMiddleware(messageSender, kpr.dbpool, kpr.config)
7676

7777
kpr.core, err = keyper.New(
7878
&kprconfig.Config{

rolling-shutter/keyperimpl/gnosis/messagingmiddleware.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ import (
1414
obskeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/chainobserver/db/keyper"
1515
corekeyperdatabase "github.com/shutter-network/rolling-shutter/rolling-shutter/keyper/database"
1616
"github.com/shutter-network/rolling-shutter/rolling-shutter/keyperimpl/gnosis/database"
17+
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/identitypreimage"
1718
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/retry"
1819
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/service"
1920
"github.com/shutter-network/rolling-shutter/rolling-shutter/p2p"
2021
"github.com/shutter-network/rolling-shutter/rolling-shutter/p2pmsg"
2122
)
2223

2324
type MessagingMiddleware struct {
25+
config *Config
2426
messaging p2p.Messaging
2527
dbpool *pgxpool.Pool
2628
}
@@ -56,8 +58,8 @@ func (h *WrappedMessageHandler) HandleMessage(ctx context.Context, msg p2pmsg.Me
5658
return replacedMsgs, nil
5759
}
5860

59-
func NewMessagingMiddleware(messaging p2p.Messaging, dbpool *pgxpool.Pool) *MessagingMiddleware {
60-
return &MessagingMiddleware{messaging: messaging, dbpool: dbpool}
61+
func NewMessagingMiddleware(messaging p2p.Messaging, dbpool *pgxpool.Pool, config *Config) *MessagingMiddleware {
62+
return &MessagingMiddleware{messaging: messaging, dbpool: dbpool, config: config}
6163
}
6264

6365
func (i *MessagingMiddleware) Start(_ context.Context, runner service.Runner) error {
@@ -133,7 +135,22 @@ func (i *MessagingMiddleware) interceptDecryptionKeyShares(
133135
return nil, nil
134136
}
135137

136-
signature := []byte("signed")
138+
identityPreimages := []identitypreimage.IdentityPreimage{}
139+
for _, share := range originalMsg.Shares {
140+
identityPreimages = append(identityPreimages, identitypreimage.IdentityPreimage(share.EpochID))
141+
}
142+
slotDecryptionSignatureData := SlotDecryptionSignatureData{
143+
InstanceID: i.config.InstanceID,
144+
Eon: originalMsg.Eon,
145+
Slot: uint64(currentDecryptionTrigger.Block),
146+
TxPointer: uint64(currentDecryptionTrigger.TxPointer),
147+
IdentityPreimages: identityPreimages,
148+
}
149+
signature, err := ComputeSlotDecryptionSignature(&slotDecryptionSignatureData, i.config.Gnosis.PrivateKey.Key)
150+
if err != nil {
151+
return nil, errors.Wrapf(err, "failed to compute slot decryption signature")
152+
}
153+
137154
err = queries.InsertSlotDecryptionSignature(ctx, database.InsertSlotDecryptionSignatureParams{
138155
Eon: currentDecryptionTrigger.Eon,
139156
Block: currentDecryptionTrigger.Block,
@@ -155,7 +172,7 @@ func (i *MessagingMiddleware) interceptDecryptionKeyShares(
155172
Gnosis: &p2pmsg.GnosisDecryptionKeySharesExtra{
156173
Slot: uint64(currentDecryptionTrigger.Block),
157174
TxPointer: uint64(currentDecryptionTrigger.TxPointer),
158-
Signature: []byte("signed"),
175+
Signature: signature,
159176
},
160177
}
161178
return msg, nil
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package gnosis
2+
3+
import (
4+
"bytes"
5+
"crypto/ecdsa"
6+
"encoding/binary"
7+
8+
"github.com/ethereum/go-ethereum/common"
9+
"github.com/ethereum/go-ethereum/crypto"
10+
11+
"github.com/shutter-network/rolling-shutter/rolling-shutter/medley/identitypreimage"
12+
)
13+
14+
type SlotDecryptionSignatureData struct {
15+
InstanceID uint64
16+
Eon uint64
17+
Slot uint64
18+
TxPointer uint64
19+
IdentityPreimages []identitypreimage.IdentityPreimage
20+
}
21+
22+
func HashSlotDecryptionSignatureData(data *SlotDecryptionSignatureData) common.Hash {
23+
// all fields are fixed size and identity preimages are ordered, so there is no malleability if we just append all fields
24+
buf := new(bytes.Buffer)
25+
_ = binary.Write(buf, binary.BigEndian, data.InstanceID)
26+
_ = binary.Write(buf, binary.BigEndian, data.Eon)
27+
_ = binary.Write(buf, binary.BigEndian, data.Slot)
28+
_ = binary.Write(buf, binary.BigEndian, data.TxPointer)
29+
for _, preimage := range data.IdentityPreimages {
30+
_ = binary.Write(buf, binary.BigEndian, preimage)
31+
}
32+
return crypto.Keccak256Hash(buf.Bytes())
33+
}
34+
35+
func ComputeSlotDecryptionSignature(
36+
data *SlotDecryptionSignatureData,
37+
key *ecdsa.PrivateKey,
38+
) ([]byte, error) {
39+
h := HashSlotDecryptionSignatureData(data)
40+
return crypto.Sign(h.Bytes(), key)
41+
}
42+
43+
func CheckSlotDecryptionSignature(data *SlotDecryptionSignatureData, signature []byte, address common.Address) (bool, error) {
44+
h := HashSlotDecryptionSignatureData(data)
45+
signerPubkey, err := crypto.SigToPub(h.Bytes(), signature)
46+
if err != nil {
47+
return false, err
48+
}
49+
signerAddress := crypto.PubkeyToAddress(*signerPubkey)
50+
return signerAddress == address, nil
51+
}

0 commit comments

Comments
 (0)