@@ -29,21 +29,16 @@ package enr
2929
3030import (
3131 "bytes"
32- "crypto/ecdsa"
3332 "errors"
3433 "fmt"
3534 "io"
3635 "sort"
3736
38- "github.com/ethersocial/go-esn/crypto"
39- "github.com/ethersocial/go-esn/crypto/sha3"
4037 "github.com/ethersocial/go-esn/rlp"
4138)
4239
4340const SizeLimit = 300 // maximum encoded size of a node record in bytes
4441
45- const ID_SECP256k1_KECCAK = ID ("secp256k1-keccak" ) // the default identity scheme
46-
4742var (
4843 errNoID = errors .New ("unknown or unspecified identity scheme" )
4944 errInvalidSig = errors .New ("invalid signature" )
@@ -80,8 +75,8 @@ func (r *Record) Seq() uint64 {
8075}
8176
8277// 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.
8580func (r * Record ) SetSeq (s uint64 ) {
8681 r .signature = nil
8782 r .raw = nil
@@ -104,33 +99,42 @@ func (r *Record) Load(e Entry) error {
10499 return & KeyError {Key : e .ENRKey (), Err : errNotFound }
105100}
106101
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.
109105func (r * Record ) Set (e Entry ) {
110- r .signature = nil
111- r .raw = nil
112106 blob , err := rlp .EncodeToBytes (e )
113107 if err != nil {
114108 panic (fmt .Errorf ("enr: can't encode %s: %v" , e .ENRKey (), err ))
115109 }
110+ r .invalidate ()
116111
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 ():
120117 // 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 ):
124120 // insert pair before i-th elem
125121 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 })
130128 }
129+ r .pairs = pairs
130+ }
131131
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
134138}
135139
136140// EncodeRLP implements rlp.Encoder. Encoding fails if
@@ -196,94 +200,79 @@ func (r *Record) DecodeRLP(s *rlp.Stream) error {
196200 return err
197201 }
198202
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 {
201208 return err
202209 }
203210 * r = dec
204211 return nil
205212}
206213
207- type s256raw []byte
208-
209- func (s256raw ) ENRKey () string { return "secp256k1" }
210-
211214// 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 .
213216func (r * Record ) NodeAddr () []byte {
214- var entry s256raw
215- if r . Load ( & entry ) ! = nil {
217+ _ , scheme := r . idScheme ()
218+ if scheme = = nil {
216219 return nil
217220 }
218- return crypto . Keccak256 ( entry )
221+ return scheme . NodeAddr ( r )
219222}
220223
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
229248}
230249
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 {} {
232252 list = append (list , r .seq )
233253 for _ , p := range r .pairs {
234254 list = append (list , p .k , p .v )
235255 }
236256 return list
237257}
238258
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
258265 }
259- if len (r . raw ) > SizeLimit {
260- return errTooBig
266+ if len (raw ) > SizeLimit {
267+ return nil , errTooBig
261268 }
262- return nil
269+ return raw , nil
263270}
264271
265- func (r * Record ) verifySignature () error {
266- // Get identity scheme, public key, signature.
272+ func (r * Record ) idScheme () (string , IdentityScheme ) {
267273 var id ID
268- var entry s256raw
269274 if err := r .Load (& id ); err != nil {
270- return err
271- } else if id != ID_SECP256k1_KECCAK {
272- return errNoID
275+ return "" , nil
273276 }
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 ))
289278}
0 commit comments