-
Notifications
You must be signed in to change notification settings - Fork 4
/
tx_signing.go
104 lines (93 loc) · 2.76 KB
/
tx_signing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package types
import (
"crypto/ecdsa"
"errors"
"fmt"
"math/big"
"github.com/LemoFoundationLtd/lemochain-go/common"
"github.com/LemoFoundationLtd/lemochain-go/common/crypto"
)
var (
ErrPublicKey = errors.New("invalid public key")
)
// MakeSigner returns a Signer based on the given version and chainID.
func MakeSigner() Signer {
return DefaultSigner{}
}
// SignTx signs the transaction using the given signer and private key
func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
h := s.Hash(tx)
sig, err := crypto.Sign(h[:], prv)
if err != nil {
return nil, err
}
return tx.WithSignature(s, sig)
}
// Signer encapsulates transaction signature handling.
type Signer interface {
// Sender returns the sender address of the transaction.
GetSender(tx *Transaction) (common.Address, error)
// ParseSignature returns the raw R, S, V values corresponding to the
// given signature.
ParseSignature(tx *Transaction, sig []byte) (r, s, v *big.Int, err error)
// Hash returns the hash to be signed.
Hash(tx *Transaction) common.Hash
}
// DefaultSigner implements Signer.
type DefaultSigner struct {
}
func (s DefaultSigner) GetSender(tx *Transaction) (common.Address, error) {
sigHash := s.Hash(tx)
V, R, S := tx.data.V, tx.data.R, tx.data.S
if V.BitLen() > 32 {
return common.Address{}, ErrInvalidSig
}
_, _, v, _ := ParseV(V)
if !crypto.ValidateSignatureValues(v, R, S) {
return common.Address{}, ErrInvalidSig
}
// encode the signature in uncompressed format
rb, sb := R.Bytes(), S.Bytes()
sig := make([]byte, 65)
copy(sig[32-len(rb):32], rb)
copy(sig[64-len(sb):64], sb)
sig[64] = v
// recover the public key from the signature
pub, err := crypto.Ecrecover(sigHash[:], sig)
if err != nil {
return common.Address{}, err
}
if len(pub) == 0 || pub[0] != 4 {
return common.Address{}, ErrPublicKey
}
addr := crypto.PubToAddress(pub)
return addr, nil
}
// ParseSignature 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 DefaultSigner) ParseSignature(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
if len(sig) != 65 {
panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
}
R = new(big.Int).SetBytes(sig[:32])
S = new(big.Int).SetBytes(sig[32:64])
V = SetSecp256k1V(tx.data.V, sig[64])
return R, S, V, nil
}
// Hash returns the hash to be signed by the sender.
// It does not uniquely identify the transaction.
func (s DefaultSigner) Hash(tx *Transaction) common.Hash {
return rlpHash([]interface{}{
tx.Type(),
tx.Version(),
tx.ChainID(),
tx.data.Recipient,
tx.data.RecipientName,
tx.data.GasPrice,
tx.data.GasLimit,
tx.data.Amount,
tx.data.Data,
tx.data.Expiration,
tx.data.Message,
})
}