@@ -29,21 +29,16 @@ package enr
29
29
30
30
import (
31
31
"bytes"
32
- "crypto/ecdsa"
33
32
"errors"
34
33
"fmt"
35
34
"io"
36
35
"sort"
37
36
38
- "github.com/ethereum/go-ethereum/crypto"
39
- "github.com/ethereum/go-ethereum/crypto/sha3"
40
37
"github.com/ethereum/go-ethereum/rlp"
41
38
)
42
39
43
40
const SizeLimit = 300 // maximum encoded size of a node record in bytes
44
41
45
- const ID_SECP256k1_KECCAK = ID ("secp256k1-keccak" ) // the default identity scheme
46
-
47
42
var (
48
43
errNoID = errors .New ("unknown or unspecified identity scheme" )
49
44
errInvalidSig = errors .New ("invalid signature" )
@@ -80,8 +75,8 @@ func (r *Record) Seq() uint64 {
80
75
}
81
76
82
77
// SetSeq updates the record sequence number. This invalidates any signature on the record.
83
- // Calling SetSeq is usually not required because signing the redord increments the
84
- // sequence number.
78
+ // Calling SetSeq is usually not required because setting any key in a signed record
79
+ // increments the sequence number.
85
80
func (r * Record ) SetSeq (s uint64 ) {
86
81
r .signature = nil
87
82
r .raw = nil
@@ -104,33 +99,42 @@ func (r *Record) Load(e Entry) error {
104
99
return & KeyError {Key : e .ENRKey (), Err : errNotFound }
105
100
}
106
101
107
- // Set adds or updates the given entry in the record.
108
- // It panics if the value can't be encoded.
102
+ // Set adds or updates the given entry in the record. It panics if the value can't be
103
+ // encoded. If the record is signed, Set increments the sequence number and invalidates
104
+ // the sequence number.
109
105
func (r * Record ) Set (e Entry ) {
110
- r .signature = nil
111
- r .raw = nil
112
106
blob , err := rlp .EncodeToBytes (e )
113
107
if err != nil {
114
108
panic (fmt .Errorf ("enr: can't encode %s: %v" , e .ENRKey (), err ))
115
109
}
110
+ r .invalidate ()
116
111
117
- i := sort .Search (len (r .pairs ), func (i int ) bool { return r .pairs [i ].k >= e .ENRKey () })
118
-
119
- if i < len (r .pairs ) && r .pairs [i ].k == e .ENRKey () {
112
+ pairs := make ([]pair , len (r .pairs ))
113
+ copy (pairs , r .pairs )
114
+ i := sort .Search (len (pairs ), func (i int ) bool { return pairs [i ].k >= e .ENRKey () })
115
+ switch {
116
+ case i < len (pairs ) && pairs [i ].k == e .ENRKey ():
120
117
// element is present at r.pairs[i]
121
- r .pairs [i ].v = blob
122
- return
123
- } else if i < len (r .pairs ) {
118
+ pairs [i ].v = blob
119
+ case i < len (r .pairs ):
124
120
// insert pair before i-th elem
125
121
el := pair {e .ENRKey (), blob }
126
- r .pairs = append (r .pairs , pair {})
127
- copy (r .pairs [i + 1 :], r .pairs [i :])
128
- r .pairs [i ] = el
129
- return
122
+ pairs = append (pairs , pair {})
123
+ copy (pairs [i + 1 :], pairs [i :])
124
+ pairs [i ] = el
125
+ default :
126
+ // element should be placed at the end of r.pairs
127
+ pairs = append (pairs , pair {e .ENRKey (), blob })
130
128
}
129
+ r .pairs = pairs
130
+ }
131
131
132
- // element should be placed at the end of r.pairs
133
- r .pairs = append (r .pairs , pair {e .ENRKey (), blob })
132
+ func (r * Record ) invalidate () {
133
+ if r .signature == nil {
134
+ r .seq ++
135
+ }
136
+ r .signature = nil
137
+ r .raw = nil
134
138
}
135
139
136
140
// EncodeRLP implements rlp.Encoder. Encoding fails if
@@ -196,94 +200,79 @@ func (r *Record) DecodeRLP(s *rlp.Stream) error {
196
200
return err
197
201
}
198
202
199
- // Verify signature.
200
- if err = dec .verifySignature (); err != nil {
203
+ _ , scheme := dec .idScheme ()
204
+ if scheme == nil {
205
+ return errNoID
206
+ }
207
+ if err := scheme .Verify (& dec , dec .signature ); err != nil {
201
208
return err
202
209
}
203
210
* r = dec
204
211
return nil
205
212
}
206
213
207
- type s256raw []byte
208
-
209
- func (s256raw ) ENRKey () string { return "secp256k1" }
210
-
211
214
// NodeAddr returns the node address. The return value will be nil if the record is
212
- // unsigned.
215
+ // unsigned or uses an unknown identity scheme .
213
216
func (r * Record ) NodeAddr () []byte {
214
- var entry s256raw
215
- if r . Load ( & entry ) ! = nil {
217
+ _ , scheme := r . idScheme ()
218
+ if scheme = = nil {
216
219
return nil
217
220
}
218
- return crypto . Keccak256 ( entry )
221
+ return scheme . NodeAddr ( r )
219
222
}
220
223
221
- // Sign signs the record with the given private key. It updates the record's identity
222
- // scheme, public key and increments the sequence number. Sign returns an error if the
223
- // encoded record is larger than the size limit.
224
- func (r * Record ) Sign (privkey * ecdsa.PrivateKey ) error {
225
- r .seq = r .seq + 1
226
- r .Set (ID_SECP256k1_KECCAK )
227
- r .Set (Secp256k1 (privkey .PublicKey ))
228
- return r .signAndEncode (privkey )
224
+ // SetSig sets the record signature. It returns an error if the encoded record is larger
225
+ // than the size limit or if the signature is invalid according to the passed scheme.
226
+ func (r * Record ) SetSig (idscheme string , sig []byte ) error {
227
+ // Check that "id" is set and matches the given scheme. This panics because
228
+ // inconsitencies here are always implementation bugs in the signing function calling
229
+ // this method.
230
+ id , s := r .idScheme ()
231
+ if s == nil {
232
+ panic (errNoID )
233
+ }
234
+ if id != idscheme {
235
+ panic (fmt .Errorf ("identity scheme mismatch in Sign: record has %s, want %s" , id , idscheme ))
236
+ }
237
+
238
+ // Verify against the scheme.
239
+ if err := s .Verify (r , sig ); err != nil {
240
+ return err
241
+ }
242
+ raw , err := r .encode (sig )
243
+ if err != nil {
244
+ return err
245
+ }
246
+ r .signature , r .raw = sig , raw
247
+ return nil
229
248
}
230
249
231
- func (r * Record ) appendPairs (list []interface {}) []interface {} {
250
+ // AppendElements appends the sequence number and entries to the given slice.
251
+ func (r * Record ) AppendElements (list []interface {}) []interface {} {
232
252
list = append (list , r .seq )
233
253
for _ , p := range r .pairs {
234
254
list = append (list , p .k , p .v )
235
255
}
236
256
return list
237
257
}
238
258
239
- func (r * Record ) signAndEncode (privkey * ecdsa.PrivateKey ) error {
240
- // Put record elements into a flat list. Leave room for the signature.
241
- list := make ([]interface {}, 1 , len (r .pairs )* 2 + 2 )
242
- list = r .appendPairs (list )
243
-
244
- // Sign the tail of the list.
245
- h := sha3 .NewKeccak256 ()
246
- rlp .Encode (h , list [1 :])
247
- sig , err := crypto .Sign (h .Sum (nil ), privkey )
248
- if err != nil {
249
- return err
250
- }
251
- sig = sig [:len (sig )- 1 ] // remove v
252
-
253
- // Put signature in front.
254
- r .signature , list [0 ] = sig , sig
255
- r .raw , err = rlp .EncodeToBytes (list )
256
- if err != nil {
257
- return err
259
+ func (r * Record ) encode (sig []byte ) (raw []byte , err error ) {
260
+ list := make ([]interface {}, 1 , 2 * len (r .pairs )+ 1 )
261
+ list [0 ] = sig
262
+ list = r .AppendElements (list )
263
+ if raw , err = rlp .EncodeToBytes (list ); err != nil {
264
+ return nil , err
258
265
}
259
- if len (r . raw ) > SizeLimit {
260
- return errTooBig
266
+ if len (raw ) > SizeLimit {
267
+ return nil , errTooBig
261
268
}
262
- return nil
269
+ return raw , nil
263
270
}
264
271
265
- func (r * Record ) verifySignature () error {
266
- // Get identity scheme, public key, signature.
272
+ func (r * Record ) idScheme () (string , IdentityScheme ) {
267
273
var id ID
268
- var entry s256raw
269
274
if err := r .Load (& id ); err != nil {
270
- return err
271
- } else if id != ID_SECP256k1_KECCAK {
272
- return errNoID
275
+ return "" , nil
273
276
}
274
- if err := r .Load (& entry ); err != nil {
275
- return err
276
- } else if len (entry ) != 33 {
277
- return fmt .Errorf ("invalid public key" )
278
- }
279
-
280
- // Verify the signature.
281
- list := make ([]interface {}, 0 , len (r .pairs )* 2 + 1 )
282
- list = r .appendPairs (list )
283
- h := sha3 .NewKeccak256 ()
284
- rlp .Encode (h , list )
285
- if ! crypto .VerifySignature (entry , h .Sum (nil ), r .signature ) {
286
- return errInvalidSig
287
- }
288
- return nil
277
+ return string (id ), FindIdentityScheme (string (id ))
289
278
}
0 commit comments