-
Notifications
You must be signed in to change notification settings - Fork 0
/
transaction.go
154 lines (132 loc) · 4.04 KB
/
transaction.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package hackSDK
import (
"bytes"
"crypto/ecdsa"
"encoding/binary"
"errors"
"fmt"
"math/big"
"sort"
"github.com/annchain/OG/common/crypto/secp256k1"
)
var (
EmptyAddress = "0000000000000000000000000000000000000000"
EmptyHash = "0000000000000000000000000000000000000000000000000000000000000000"
EmptyUint64 = uint64(0)
EmptyBigInt = big.NewInt(0)
)
type Transaction struct {
Parents StringSet
From string
Nonce uint64
Guarantee *big.Int
}
type StringSet []string
func (s StringSet) Len() int { return len(s) }
func (s StringSet) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s StringSet) Less(i, j int) bool { return s[i] < s[j] }
func (tx *Transaction) SignatureTarget() ([]byte, error) {
msg := &bytes.Buffer{}
// write parents
sort.Sort(tx.Parents)
for _, parentHex := range tx.Parents {
pBytes, err := HexToBytes(parentHex)
if err != nil {
return nil, fmt.Errorf("invalid parent: %v", err)
}
binary.Write(msg, binary.BigEndian, pBytes)
}
// write nonce
binary.Write(msg, binary.BigEndian, tx.Nonce)
// write from, to
fromBytes, err := HexToBytes(tx.From)
if err != nil {
return nil, fmt.Errorf("invalid FROM: %v", err)
}
binary.Write(msg, binary.BigEndian, fromBytes)
toBytes, err := HexToBytes(EmptyAddress)
if err != nil {
return nil, fmt.Errorf("invalid TO: %v", err)
}
binary.Write(msg, binary.BigEndian, toBytes)
// write value
value := []byte{0}
binary.Write(msg, binary.BigEndian, value)
// write guarantee
guarantee := tx.Guarantee.Bytes()
if tx.Guarantee.Int64() == 0 {
guarantee = []byte{0}
}
binary.Write(msg, binary.BigEndian, guarantee)
return msg.Bytes(), nil
}
func (tx *Transaction) Sign(privBytes []byte) ([]byte, error) {
priv, err := toECDSA(privBytes, true)
if err != nil {
return nil, fmt.Errorf("ToECDSA error: %v. priv bytes: %x", err, privBytes)
}
msg, err := tx.SignatureTarget()
if err != nil {
return nil, fmt.Errorf("get signature target error: %v", err)
}
hash := Sha256(msg)
if len(hash) != 32 {
return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash))
}
seckey := paddedBigBytes(priv.D, priv.Params().BitSize/8)
return secp256k1.Sign(hash, seckey)
}
// toECDSA creates a private key with the given D value. The strict parameter
// controls whether the key's length should be enforced at the curve size or
// it can also accept legacy encodings (0 prefixes).
func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = s256()
if strict && 8*len(d) != priv.Params().BitSize {
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
}
priv.D = new(big.Int).SetBytes(d)
// The priv.D must < N
if priv.D.Cmp(secp256k1N) >= 0 {
return nil, fmt.Errorf("invalid private key, >=N")
}
// The priv.D must not be zero or negative.
if priv.D.Sign() <= 0 {
return nil, fmt.Errorf("invalid private key, zero or negative")
}
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
if priv.PublicKey.X == nil {
return nil, errors.New("invalid private key")
}
return priv, nil
}
// paddedBigBytes encodes a big integer as a big-endian byte slice. The length
// of the slice is at least n bytes.
func paddedBigBytes(bigint *big.Int, n int) []byte {
if bigint.BitLen()/8 >= n {
return bigint.Bytes()
}
ret := make([]byte, n)
readBits(bigint, ret)
return ret
}
// readBits encodes the absolute value of bigint as big-endian bytes. Callers must ensure
// that buf has enough space. If buf is too short the result will be incomplete.
func readBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
for j := 0; j < wordBytes && i > 0; j++ {
i--
buf[i] = byte(d)
d >>= 8
}
}
}
var (
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
// number of bits in a big.Word
wordBits = 32 << (uint64(^big.Word(0)) >> 63)
// number of bytes in a big.Word
wordBytes = wordBits / 8
)