-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
offchain_keyring.go
136 lines (116 loc) · 3.91 KB
/
offchain_keyring.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 ocr2key
import (
"bytes"
"crypto/ed25519"
"encoding/binary"
"errors"
"io"
"golang.org/x/crypto/nacl/box"
"golang.org/x/crypto/curve25519"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
)
var _ ocrtypes.OffchainKeyring = &OffchainKeyring{}
// OffchainKeyring contains the secret keys needed for the OCR nodes to share secrets
// and perform aggregation.
//
// This is currently an ed25519 signing key and a separate encryption key.
//
// All its functions should be thread-safe.
type OffchainKeyring struct {
signingKey ed25519.PrivateKey
encryptionKey [curve25519.ScalarSize]byte
}
func newOffchainKeyring(encryptionMaterial, signingMaterial io.Reader) (*OffchainKeyring, error) {
_, signingKey, err := ed25519.GenerateKey(signingMaterial)
if err != nil {
return nil, err
}
encryptionKey := [curve25519.ScalarSize]byte{}
_, err = encryptionMaterial.Read(encryptionKey[:])
if err != nil {
return nil, err
}
ok := &OffchainKeyring{
signingKey: signingKey,
encryptionKey: encryptionKey,
}
_, err = ok.configEncryptionPublicKey()
if err != nil {
return nil, err
}
return ok, nil
}
// NaclBoxOpenAnonymous decrypts a message that was encrypted using the OCR2 Offchain public key
func (ok *OffchainKeyring) NaclBoxOpenAnonymous(ciphertext []byte) (plaintext []byte, err error) {
if len(ciphertext) < box.Overhead {
return nil, errors.New("ciphertext too short")
}
publicKey := [curve25519.PointSize]byte(ok.ConfigEncryptionPublicKey())
decrypted, success := box.OpenAnonymous(nil, ciphertext, &publicKey, &ok.encryptionKey)
if !success {
return nil, errors.New("decryption failed")
}
return decrypted, nil
}
// OffchainSign signs message using private key
func (ok *OffchainKeyring) OffchainSign(msg []byte) (signature []byte, err error) {
return ed25519.Sign(ok.signingKey, msg), nil
}
// ConfigDiffieHellman returns the shared point obtained by multiplying someone's
// public key by a secret scalar ( in this case, the offchain key ring's encryption key.)
func (ok *OffchainKeyring) ConfigDiffieHellman(point [curve25519.PointSize]byte) ([curve25519.PointSize]byte, error) {
p, err := curve25519.X25519(ok.encryptionKey[:], point[:])
if err != nil {
return [curve25519.PointSize]byte{}, err
}
sharedPoint := [ed25519.PublicKeySize]byte{}
copy(sharedPoint[:], p)
return sharedPoint, nil
}
// OffchainPublicKey returns the public component of this offchain keyring.
func (ok *OffchainKeyring) OffchainPublicKey() ocrtypes.OffchainPublicKey {
var offchainPubKey [ed25519.PublicKeySize]byte
copy(offchainPubKey[:], ok.signingKey.Public().(ed25519.PublicKey)[:])
return offchainPubKey
}
// ConfigEncryptionPublicKey returns config public key
func (ok *OffchainKeyring) ConfigEncryptionPublicKey() ocrtypes.ConfigEncryptionPublicKey {
cpk, _ := ok.configEncryptionPublicKey()
return cpk
}
func (ok *OffchainKeyring) configEncryptionPublicKey() (ocrtypes.ConfigEncryptionPublicKey, error) {
rv, err := curve25519.X25519(ok.encryptionKey[:], curve25519.Basepoint)
if err != nil {
return [curve25519.PointSize]byte{}, err
}
var rvFixed [curve25519.PointSize]byte
copy(rvFixed[:], rv)
return rvFixed, nil
}
func (ok *OffchainKeyring) marshal() ([]byte, error) {
buffer := new(bytes.Buffer)
err := binary.Write(buffer, binary.LittleEndian, ok.signingKey)
if err != nil {
return nil, err
}
err = binary.Write(buffer, binary.LittleEndian, ok.encryptionKey)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
func (ok *OffchainKeyring) unmarshal(in []byte) error {
buffer := bytes.NewReader(in)
ok.signingKey = make(ed25519.PrivateKey, ed25519.PrivateKeySize)
err := binary.Read(buffer, binary.LittleEndian, &ok.signingKey)
if err != nil {
return err
}
ok.encryptionKey = [curve25519.ScalarSize]byte{}
err = binary.Read(buffer, binary.LittleEndian, &ok.encryptionKey)
if err != nil {
return err
}
_, err = ok.configEncryptionPublicKey()
return err
}