|
|
@@ -29,9 +29,6 @@ import (
|
|
|
|
|
|
var (
|
|
|
ErrInvalidChainId = errors.New("invalid chain id for signer")
|
|
|
-
|
|
|
- errAbstractSigner = errors.New("abstract signer")
|
|
|
- abstractSignerAddress = common.HexToAddress("ffffffffffffffffffffffffffffffffffffffff")
|
|
|
)
|
|
|
|
|
|
// sigCache is used to cache the derived sender and contains
|
|
|
@@ -62,12 +59,9 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- return s.WithSignature(tx, sig)
|
|
|
+ return tx.WithSignature(s, sig)
|
|
|
}
|
|
|
|
|
|
-// Sender derives the sender from the tx using the signer derivation
|
|
|
-// functions.
|
|
|
-
|
|
|
// Sender returns the address derived from the signature (V, R, S) using secp256k1
|
|
|
// elliptic curve and an error if it failed deriving or upon an incorrect
|
|
|
// signature.
|
|
|
@@ -86,33 +80,30 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- pubkey, err := signer.PublicKey(tx)
|
|
|
+ addr, err := signer.Sender(tx)
|
|
|
if err != nil {
|
|
|
return common.Address{}, err
|
|
|
}
|
|
|
- var addr common.Address
|
|
|
- copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
|
|
|
tx.from.Store(sigCache{signer: signer, from: addr})
|
|
|
return addr, nil
|
|
|
}
|
|
|
|
|
|
+// Signer encapsulates transaction signature handling. Note that this interface is not a
|
|
|
+// stable API and may change at any time to accommodate new protocol rules.
|
|
|
type Signer interface {
|
|
|
- // Hash returns the rlp encoded hash for signatures
|
|
|
+ // Sender returns the sender address of the transaction.
|
|
|
+ Sender(tx *Transaction) (common.Address, error)
|
|
|
+ // SignatureValues returns the raw R, S, V values corresponding to the
|
|
|
+ // given signature.
|
|
|
+ SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
|
|
|
+ // Hash returns the hash to be signed.
|
|
|
Hash(tx *Transaction) common.Hash
|
|
|
- // PubilcKey returns the public key derived from the signature
|
|
|
- PublicKey(tx *Transaction) ([]byte, error)
|
|
|
- // WithSignature returns a copy of the transaction with the given signature.
|
|
|
- // The signature must be encoded in [R || S || V] format where V is 0 or 1.
|
|
|
- WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
|
|
|
- // Checks for equality on the signers
|
|
|
+ // Equal returns true if the given signer is the same as the receiver.
|
|
|
Equal(Signer) bool
|
|
|
}
|
|
|
|
|
|
-// EIP155Transaction implements TransactionInterface using the
|
|
|
-// EIP155 rules
|
|
|
+// EIP155Transaction implements Signer using the EIP155 rules.
|
|
|
type EIP155Signer struct {
|
|
|
- HomesteadSigner
|
|
|
-
|
|
|
chainId, chainIdMul *big.Int
|
|
|
}
|
|
|
|
|
|
@@ -131,55 +122,32 @@ func (s EIP155Signer) Equal(s2 Signer) bool {
|
|
|
return ok && eip155.chainId.Cmp(s.chainId) == 0
|
|
|
}
|
|
|
|
|
|
-func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
|
|
- // if the transaction is not protected fall back to homestead signer
|
|
|
+var big8 = big.NewInt(8)
|
|
|
+
|
|
|
+func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
|
|
|
if !tx.Protected() {
|
|
|
- return (HomesteadSigner{}).PublicKey(tx)
|
|
|
+ return HomesteadSigner{}.Sender(tx)
|
|
|
}
|
|
|
-
|
|
|
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
|
- return nil, ErrInvalidChainId
|
|
|
- }
|
|
|
-
|
|
|
- V := byte(new(big.Int).Sub(tx.data.V, s.chainIdMul).Uint64() - 35)
|
|
|
- if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
|
|
- return nil, ErrInvalidSig
|
|
|
- }
|
|
|
- // encode the signature in uncompressed format
|
|
|
- R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
|
|
|
- sig := make([]byte, 65)
|
|
|
- copy(sig[32-len(R):32], R)
|
|
|
- copy(sig[64-len(S):64], S)
|
|
|
- sig[64] = V
|
|
|
-
|
|
|
- // recover the public key from the signature
|
|
|
- hash := s.Hash(tx)
|
|
|
- pub, err := crypto.Ecrecover(hash[:], sig)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- if len(pub) == 0 || pub[0] != 4 {
|
|
|
- return nil, errors.New("invalid public key")
|
|
|
+ return common.Address{}, ErrInvalidChainId
|
|
|
}
|
|
|
- return pub, nil
|
|
|
+ V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
|
|
|
+ V.Sub(V, big8)
|
|
|
+ return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
|
|
|
}
|
|
|
|
|
|
// WithSignature returns a new transaction with the given signature. This signature
|
|
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
|
|
-func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
|
|
- if len(sig) != 65 {
|
|
|
- panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
|
|
|
+func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
|
+ R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
|
|
|
+ if err != nil {
|
|
|
+ return nil, nil, nil, err
|
|
|
}
|
|
|
-
|
|
|
- cpy := &Transaction{data: tx.data}
|
|
|
- cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
|
|
- cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
|
|
- cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
|
|
if s.chainId.Sign() != 0 {
|
|
|
- cpy.data.V = big.NewInt(int64(sig[64] + 35))
|
|
|
- cpy.data.V.Add(cpy.data.V, s.chainIdMul)
|
|
|
+ V = big.NewInt(int64(sig[64] + 35))
|
|
|
+ V.Add(V, s.chainIdMul)
|
|
|
}
|
|
|
- return cpy, nil
|
|
|
+ return R, S, V, nil
|
|
|
}
|
|
|
|
|
|
// Hash returns the hash to be signed by the sender.
|
|
|
@@ -205,44 +173,14 @@ func (s HomesteadSigner) Equal(s2 Signer) bool {
|
|
|
return ok
|
|
|
}
|
|
|
|
|
|
-// WithSignature returns a new transaction with the given signature. This signature
|
|
|
+// SignatureValues returns signature values. This signature
|
|
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
|
|
-func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
|
|
- if len(sig) != 65 {
|
|
|
- panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
|
|
- }
|
|
|
- cpy := &Transaction{data: tx.data}
|
|
|
- cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
|
|
- cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
|
|
- cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
|
|
|
- return cpy, nil
|
|
|
+func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
|
|
|
+ return hs.FrontierSigner.SignatureValues(tx, sig)
|
|
|
}
|
|
|
|
|
|
-func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
|
|
- if tx.data.V.BitLen() > 8 {
|
|
|
- return nil, ErrInvalidSig
|
|
|
- }
|
|
|
- V := byte(tx.data.V.Uint64() - 27)
|
|
|
- if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
|
|
- return nil, ErrInvalidSig
|
|
|
- }
|
|
|
- // encode the snature in uncompressed format
|
|
|
- r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
|
|
|
- sig := make([]byte, 65)
|
|
|
- copy(sig[32-len(r):32], r)
|
|
|
- copy(sig[64-len(s):64], s)
|
|
|
- sig[64] = V
|
|
|
-
|
|
|
- // recover the public key from the snature
|
|
|
- hash := hs.Hash(tx)
|
|
|
- pub, err := crypto.Ecrecover(hash[:], sig)
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- if len(pub) == 0 || pub[0] != 4 {
|
|
|
- return nil, errors.New("invalid public key")
|
|
|
- }
|
|
|
- return pub, nil
|
|
|
+func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
|
+ return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
|
|
|
}
|
|
|
|
|
|
type FrontierSigner struct{}
|
|
|
@@ -252,20 +190,19 @@ func (s FrontierSigner) Equal(s2 Signer) bool {
|
|
|
return ok
|
|
|
}
|
|
|
|
|
|
-// WithSignature returns a new transaction with the given signature. This signature
|
|
|
+// SignatureValues returns signature values. This signature
|
|
|
// needs to be in the [R || S || V] format where V is 0 or 1.
|
|
|
-func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
|
|
+func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
|
|
|
if len(sig) != 65 {
|
|
|
- panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
|
|
+ panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
|
|
|
}
|
|
|
- cpy := &Transaction{data: tx.data}
|
|
|
- cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
|
|
- cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
|
|
- cpy.data.V = new(big.Int).SetBytes([]byte{sig[64] + 27})
|
|
|
- return cpy, nil
|
|
|
+ r = new(big.Int).SetBytes(sig[:32])
|
|
|
+ s = new(big.Int).SetBytes(sig[32:64])
|
|
|
+ v = new(big.Int).SetBytes([]byte{sig[64] + 27})
|
|
|
+ return r, s, v, nil
|
|
|
}
|
|
|
|
|
|
-// Hash returns the hash to be sned by the sender.
|
|
|
+// Hash returns the hash to be signed by the sender.
|
|
|
// It does not uniquely identify the transaction.
|
|
|
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
|
|
return rlpHash([]interface{}{
|
|
|
@@ -278,32 +215,35 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
-func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
|
|
- if tx.data.V.BitLen() > 8 {
|
|
|
- return nil, ErrInvalidSig
|
|
|
- }
|
|
|
+func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
|
+ return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
|
|
|
+}
|
|
|
|
|
|
- V := byte(tx.data.V.Uint64() - 27)
|
|
|
- if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
|
|
|
- return nil, ErrInvalidSig
|
|
|
+func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
|
|
|
+ if Vb.BitLen() > 8 {
|
|
|
+ return common.Address{}, ErrInvalidSig
|
|
|
+ }
|
|
|
+ V := byte(Vb.Uint64() - 27)
|
|
|
+ if !crypto.ValidateSignatureValues(V, R, S, homestead) {
|
|
|
+ return common.Address{}, ErrInvalidSig
|
|
|
}
|
|
|
// encode the snature in uncompressed format
|
|
|
- r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
|
|
|
+ r, s := R.Bytes(), S.Bytes()
|
|
|
sig := make([]byte, 65)
|
|
|
copy(sig[32-len(r):32], r)
|
|
|
copy(sig[64-len(s):64], s)
|
|
|
sig[64] = V
|
|
|
-
|
|
|
// recover the public key from the snature
|
|
|
- hash := fs.Hash(tx)
|
|
|
- pub, err := crypto.Ecrecover(hash[:], sig)
|
|
|
+ pub, err := crypto.Ecrecover(sighash[:], sig)
|
|
|
if err != nil {
|
|
|
- return nil, err
|
|
|
+ return common.Address{}, err
|
|
|
}
|
|
|
if len(pub) == 0 || pub[0] != 4 {
|
|
|
- return nil, errors.New("invalid public key")
|
|
|
+ return common.Address{}, errors.New("invalid public key")
|
|
|
}
|
|
|
- return pub, nil
|
|
|
+ var addr common.Address
|
|
|
+ copy(addr[:], crypto.Keccak256(pub[1:])[12:])
|
|
|
+ return addr, nil
|
|
|
}
|
|
|
|
|
|
// deriveChainId derives the chain id from the given v parameter
|