forked from gnolang/gno
-
Notifications
You must be signed in to change notification settings - Fork 0
/
secrets_common.go
193 lines (157 loc) · 4.61 KB
/
secrets_common.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package main
import (
"errors"
"fmt"
"os"
"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/bft/privval"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/p2p"
)
var (
errInvalidPrivateKey = errors.New("invalid validator private key")
errPublicKeyMismatch = errors.New("public key does not match private key derivation")
errAddressMismatch = errors.New("address does not match public key")
errInvalidSignStateStep = errors.New("invalid sign state step value")
errInvalidSignStateHeight = errors.New("invalid sign state height value")
errInvalidSignStateRound = errors.New("invalid sign state round value")
errSignatureMismatch = errors.New("signature does not match signature bytes")
errSignatureValuesMissing = errors.New("missing signature value")
errInvalidNodeKey = errors.New("invalid node p2p key")
)
// saveSecretData saves the given data as Amino JSON to the path
func saveSecretData(data any, path string) error {
// Get Amino JSON
marshalledData, err := amino.MarshalJSONIndent(data, "", "\t")
if err != nil {
return fmt.Errorf("unable to marshal data into JSON, %w", err)
}
// Save the data to disk
if err := os.WriteFile(path, marshalledData, 0o644); err != nil {
return fmt.Errorf("unable to save data to path, %w", err)
}
return nil
}
// isValidDirectory verifies the directory at the given path exists
func isValidDirectory(dirPath string) bool {
fileInfo, err := os.Stat(dirPath)
if err != nil {
return false
}
// Check if the path is indeed a directory
return fileInfo.IsDir()
}
type secretData interface {
privval.FilePVKey | privval.FilePVLastSignState | p2p.NodeKey
}
// readSecretData reads the secret data from the given path
func readSecretData[T secretData](
path string,
) (*T, error) {
dataRaw, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("unable to read data, %w", err)
}
var data T
if err := amino.UnmarshalJSON(dataRaw, &data); err != nil {
return nil, fmt.Errorf("unable to unmarshal data, %w", err)
}
return &data, nil
}
// validateValidatorKey validates the validator's private key
func validateValidatorKey(key *privval.FilePVKey) error {
// Make sure the private key is set
if key.PrivKey == nil {
return errInvalidPrivateKey
}
// Make sure the public key is derived
// from the private one
if !key.PrivKey.PubKey().Equals(key.PubKey) {
return errPublicKeyMismatch
}
// Make sure the address is derived
// from the public key
if key.PubKey.Address().Compare(key.Address) != 0 {
return errAddressMismatch
}
return nil
}
// validateValidatorState validates the validator's last sign state
func validateValidatorState(state *privval.FilePVLastSignState) error {
// Make sure the sign step is valid
if state.Step < 0 {
return errInvalidSignStateStep
}
// Make sure the height is valid
if state.Height < 0 {
return errInvalidSignStateHeight
}
// Make sure the round is valid
if state.Round < 0 {
return errInvalidSignStateRound
}
return nil
}
// validateValidatorStateSignature validates the signature section
// of the last sign validator state
func validateValidatorStateSignature(
state *privval.FilePVLastSignState,
key crypto.PubKey,
) error {
// Make sure the signature and signature bytes are valid
signBytesPresent := state.SignBytes != nil
signaturePresent := state.Signature != nil
if signBytesPresent && !signaturePresent ||
!signBytesPresent && signaturePresent {
return errSignatureValuesMissing
}
if !signaturePresent {
// No need to verify further
return nil
}
// Make sure the signature bytes match the signature
if !key.VerifyBytes(state.SignBytes, state.Signature) {
return errSignatureMismatch
}
return nil
}
// validateNodeKey validates the node's p2p key
func validateNodeKey(key *p2p.NodeKey) error {
if key.PrivKey == nil {
return errInvalidNodeKey
}
return nil
}
// verifySecretsKey verifies the secrets key value from the passed in arguments
func verifySecretsKey(args []string) error {
// Check if any key is set
if len(args) == 0 {
return nil
}
// Check if more than 1 key is set
if len(args) > 1 {
return errInvalidSecretsKey
}
// Verify the set key
key := args[0]
if key != nodeIDKey &&
key != validatorPrivateKeyKey &&
key != validatorStateKey {
return fmt.Errorf(
"invalid secrets key value [%s, %s, %s]",
validatorPrivateKeyKey,
validatorStateKey,
nodeIDKey,
)
}
return nil
}
// getAvailableSecretsKeys formats and returns the available secret keys (constants)
func getAvailableSecretsKeys() string {
return fmt.Sprintf(
"[%s, %s, %s]",
validatorPrivateKeyKey,
nodeIDKey,
validatorStateKey,
)
}