p2p/enr: use compact signature encoding

This commit is contained in:
Felix Lange 2017-12-05 11:47:22 +01:00
parent e490233414
commit 12ac6cd58b
2 changed files with 37 additions and 33 deletions

View file

@ -22,19 +22,18 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"errors" "errors"
"io" "io"
"math/big"
"sort" "sort"
"github.com/btcsuite/btcd/btcec"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/btcsuite/btcd/btcec"
) )
var () var (
errNoID = errors.New("unknown or unspecified identity scheme")
// The maximum encoded size of a node record is 300 bytes. Implementations should reject records larger than this size. errInvalidSigsize = errors.New("invalid signature size")
const (
ID_SECP256k1_KECCAK = "secp256k1-keccak" // "secp256k1-keccak" identity scheme identifier
) )
// Key is implemented by known node record key types. // Key is implemented by known node record key types.
@ -249,14 +248,11 @@ func (r *Record) signAndEncode(privkey *ecdsa.PrivateKey) error {
return err return err
} }
digest := crypto.Keccak256Hash(sigcontent) sig, err := (*btcec.PrivateKey)(privkey).Sign(crypto.Keccak256(sigcontent))
key := btcec.PrivateKey(*privkey)
signature, err := key.Sign(digest.Bytes())
if err != nil { if err != nil {
return err return err
} }
r.signature = signature.Serialize() r.signature = encodeCompactSignature(sig)
blob, err := rlp.EncodeToBytes(r.signature) blob, err := rlp.EncodeToBytes(r.signature)
if err != nil { if err != nil {
@ -271,35 +267,41 @@ func (r *Record) signAndEncode(privkey *ecdsa.PrivateKey) error {
return nil return nil
} }
func (r Record) verifySignature(sigcontent []byte) error { func (r *Record) verifySignature(sigcontent []byte) error {
// Get identity scheme, public key.
var id ID var id ID
_, err := r.Load(&id)
if err != nil {
return err
}
// currently "secp256k1-keccak" is the only known identity scheme
if id != ID_SECP256k1_KECCAK {
return errors.New("unknown identity scheme")
}
// get publickey from record
var secp256k1 Secp256k1 var secp256k1 Secp256k1
_, err = r.Load(&secp256k1) if _, err := r.Load(&id); err != nil {
if err != nil { return err
}
if id != ID_SECP256k1_KECCAK {
return errNoID
}
if _, err := r.Load(&secp256k1); err != nil {
return err return err
} }
digest := crypto.Keccak256Hash(sigcontent) // Verify the signature.
sig, err := parseCompactSignature(r.signature)
sign, err := btcec.ParseSignature(r.signature, btcec.S256())
if err != nil { if err != nil {
return err return err
} }
if !sig.Verify(crypto.Keccak256(sigcontent), (*btcec.PublicKey)(&secp256k1)) {
if !sign.Verify(digest.Bytes(), (*btcec.PublicKey)(&secp256k1)) {
return errors.New("signature is not valid") return errors.New("signature is not valid")
} }
return nil return nil
} }
func encodeCompactSignature(sig *btcec.Signature) []byte {
b := make([]byte, 64)
math.ReadBits(sig.R, b[:32])
math.ReadBits(sig.S, b[32:])
return b
}
func parseCompactSignature(sig []byte) (*btcec.Signature, error) {
if len(sig) != 64 {
return nil, errInvalidSigsize
}
return &btcec.Signature{R: new(big.Int).SetBytes(sig[:32]), S: new(big.Int).SetBytes(sig[32:])}, nil
}

View file

@ -33,7 +33,9 @@ func (DiscPort) ENRKey() string {
return "discv5" return "discv5"
} }
// ID is the name of identity scheme, e.g. "secp256k1-keccak". const ID_SECP256k1_KECCAK = "secp256k1-keccak" // identity scheme identifier
// ID is the name of the identity scheme, e.g. "secp256k1-keccak".
type ID string type ID string
func (ID) ENRKey() string { func (ID) ENRKey() string {