github.com/gochain/gochain/v3@v3.4.9/core/types/transaction_signing.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"errors"
    22  	"fmt"
    23  	"math/big"
    24  
    25  	"github.com/gochain/gochain/v3/common"
    26  	"github.com/gochain/gochain/v3/crypto"
    27  	"github.com/gochain/gochain/v3/params"
    28  )
    29  
    30  var (
    31  	ErrInvalidChainId = errors.New("invalid chain id for signer")
    32  )
    33  
    34  // sigCache is used to cache the derived sender and contains
    35  // the signer used to derive it.
    36  type sigCache struct {
    37  	signer Signer
    38  	from   common.Address
    39  }
    40  
    41  // MakeSigner returns a Signer based on the given chain config and block number.
    42  func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
    43  	var signer Signer
    44  	switch {
    45  	case config.IsEIP155(blockNumber):
    46  		signer = NewEIP155Signer(config.ChainId)
    47  	case config.IsHomestead(blockNumber):
    48  		signer = HomesteadSigner{}
    49  	default:
    50  		signer = FrontierSigner{}
    51  	}
    52  	return signer
    53  }
    54  
    55  // SignTx signs the transaction using the given signer and private key
    56  func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
    57  	h := s.Hash(tx)
    58  	sig, err := crypto.Sign(h[:], prv)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return tx.WithSignature(s, sig)
    63  }
    64  
    65  // Sender returns the address derived from the signature (V, R, S) using secp256k1
    66  // elliptic curve and an error if it failed deriving or upon an incorrect
    67  // signature.
    68  //
    69  // Sender may cache the address, allowing it to be used regardless of
    70  // signing method. The cache is invalidated if the cached signer does
    71  // not match the signer used in the current call.
    72  func Sender(signer Signer, tx *Transaction) (common.Address, error) {
    73  	if sc := tx.from.Load(); sc != nil {
    74  		sigCache := sc.(sigCache)
    75  		// If the signer used to derive from in a previous
    76  		// call is not the same as used current, invalidate
    77  		// the cache.
    78  		if sigCache.signer.Equal(signer) {
    79  			return sigCache.from, nil
    80  		}
    81  	}
    82  
    83  	addr, err := signer.Sender(tx)
    84  	if err != nil {
    85  		return common.Address{}, err
    86  	}
    87  
    88  	tx.from.Store(sigCache{signer: signer, from: addr})
    89  	return addr, nil
    90  }
    91  
    92  // Signer encapsulates transaction signature handling. Note that this interface is not a
    93  // stable API and may change at any time to accommodate new protocol rules.
    94  type Signer interface {
    95  	// Sender returns the sender address of the transaction.
    96  	Sender(tx *Transaction) (common.Address, error)
    97  	// SignatureValues returns the raw R, S, V values corresponding to the
    98  	// given signature.
    99  	SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
   100  	// Hash returns the hash to be signed.
   101  	Hash(tx *Transaction) common.Hash
   102  	// Equal returns true if the given signer is the same as the receiver.
   103  	Equal(Signer) bool
   104  }
   105  
   106  // EIP155Transaction implements Signer using the EIP155 rules.
   107  type EIP155Signer struct {
   108  	chainId, chainIdMul *big.Int
   109  }
   110  
   111  func NewEIP155Signer(chainId *big.Int) EIP155Signer {
   112  	if chainId == nil {
   113  		chainId = new(big.Int)
   114  	}
   115  	return EIP155Signer{
   116  		chainId:    chainId,
   117  		chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
   118  	}
   119  }
   120  
   121  func (s EIP155Signer) Equal(s2 Signer) bool {
   122  	eip155, ok := s2.(EIP155Signer)
   123  	return ok && eip155.chainId.Cmp(s.chainId) == 0
   124  }
   125  
   126  var big8 = big.NewInt(8)
   127  
   128  func (s EIP155Signer) Sender(tx *Transaction) (common.Address, error) {
   129  	if !tx.Protected() {
   130  		return HomesteadSigner{}.Sender(tx)
   131  	}
   132  	if tx.ChainId().Cmp(s.chainId) != 0 {
   133  		return common.Address{}, ErrInvalidChainId
   134  	}
   135  	V := new(big.Int).Sub(tx.data.V, s.chainIdMul)
   136  	V.Sub(V, big8)
   137  	return recoverPlain(s.Hash(tx), tx.data.R, tx.data.S, V, true)
   138  }
   139  
   140  // SignatureValues returns signature values. This signature
   141  // needs to be in the [R || S || V] format where V is 0 or 1.
   142  func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
   143  	R, S, V, err = HomesteadSigner{}.SignatureValues(tx, sig)
   144  	if err != nil {
   145  		return nil, nil, nil, err
   146  	}
   147  	if s.chainId.Sign() != 0 {
   148  		V = big.NewInt(int64(sig[64] + 35))
   149  		V.Add(V, s.chainIdMul)
   150  	}
   151  	return R, S, V, nil
   152  }
   153  
   154  // Hash returns the hash to be signed by the sender.
   155  // It does not uniquely identify the transaction.
   156  func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
   157  	return rlpHash([]interface{}{
   158  		tx.data.AccountNonce,
   159  		tx.data.Price,
   160  		tx.data.GasLimit,
   161  		tx.data.Recipient,
   162  		tx.data.Amount,
   163  		tx.data.Payload,
   164  		s.chainId, uint(0), uint(0),
   165  	})
   166  }
   167  
   168  // HomesteadTransaction implements TransactionInterface using the
   169  // homestead rules.
   170  type HomesteadSigner struct{ FrontierSigner }
   171  
   172  func (s HomesteadSigner) Equal(s2 Signer) bool {
   173  	_, ok := s2.(HomesteadSigner)
   174  	return ok
   175  }
   176  
   177  // SignatureValues returns signature values. This signature
   178  // needs to be in the [R || S || V] format where V is 0 or 1.
   179  func (hs HomesteadSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
   180  	return hs.FrontierSigner.SignatureValues(tx, sig)
   181  }
   182  
   183  func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
   184  	return recoverPlain(hs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, true)
   185  }
   186  
   187  type FrontierSigner struct{}
   188  
   189  func (s FrontierSigner) Equal(s2 Signer) bool {
   190  	_, ok := s2.(FrontierSigner)
   191  	return ok
   192  }
   193  
   194  // SignatureValues returns signature values. This signature
   195  // needs to be in the [R || S || V] format where V is 0 or 1.
   196  func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
   197  	if len(sig) != 65 {
   198  		panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
   199  	}
   200  	r = new(big.Int).SetBytes(sig[:32])
   201  	s = new(big.Int).SetBytes(sig[32:64])
   202  	v = new(big.Int).SetBytes([]byte{sig[64] + 27})
   203  	return r, s, v, nil
   204  }
   205  
   206  // Hash returns the hash to be signed by the sender.
   207  // It does not uniquely identify the transaction.
   208  func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
   209  	return rlpHash([]interface{}{
   210  		tx.data.AccountNonce,
   211  		tx.data.Price,
   212  		tx.data.GasLimit,
   213  		tx.data.Recipient,
   214  		tx.data.Amount,
   215  		tx.data.Payload,
   216  	})
   217  }
   218  
   219  func (fs FrontierSigner) Sender(tx *Transaction) (common.Address, error) {
   220  	return recoverPlain(fs.Hash(tx), tx.data.R, tx.data.S, tx.data.V, false)
   221  }
   222  
   223  func recoverPlain(sighash common.Hash, R, S, Vb *big.Int, homestead bool) (common.Address, error) {
   224  	if Vb.BitLen() > 8 {
   225  		return common.Address{}, ErrInvalidSig
   226  	}
   227  	V := byte(Vb.Uint64() - 27)
   228  	if !crypto.ValidateSignatureValues(V, R, S, homestead) {
   229  		return common.Address{}, ErrInvalidSig
   230  	}
   231  	// encode the signature in uncompressed format
   232  	r, s := R.Bytes(), S.Bytes()
   233  	sig := make([]byte, 65)
   234  	copy(sig[32-len(r):32], r)
   235  	copy(sig[64-len(s):64], s)
   236  	sig[64] = V
   237  	// recover the public key from the signature
   238  	pub, err := crypto.Ecrecover(sighash[:], sig)
   239  	if err != nil {
   240  		return common.Address{}, err
   241  	}
   242  	if len(pub) == 0 || pub[0] != 4 {
   243  		return common.Address{}, errors.New("invalid public key")
   244  	}
   245  	var addr common.Address
   246  	copy(addr[:], crypto.Keccak256(pub[1:])[12:])
   247  	return addr, nil
   248  }
   249  
   250  // deriveChainId derives the chain id from the given v parameter
   251  func deriveChainId(v *big.Int) *big.Int {
   252  	if v.BitLen() <= 64 {
   253  		v := v.Uint64()
   254  		if v == 27 || v == 28 {
   255  			return new(big.Int)
   256  		}
   257  		return new(big.Int).SetUint64((v - 35) / 2)
   258  	}
   259  	v = new(big.Int).Sub(v, big.NewInt(35))
   260  	return v.Div(v, big.NewInt(2))
   261  }