Implement Transaction.Sign and Transaction.Verify
This commit is contained in:
parent
92be537fcd
commit
7e8c88867d
|
@ -2,7 +2,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
@ -61,6 +65,98 @@ func (tx *Transaction) SetID() {
|
||||||
tx.ID = hash[:]
|
tx.ID = hash[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TrimmedCopy creates a trimmed copy of Transaction to be used in signing
|
||||||
|
func (tx *Transaction) TrimmedCopy() Transaction {
|
||||||
|
var inputs []TXInput
|
||||||
|
var outputs []TXOutput
|
||||||
|
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
|
inputs = append(inputs, TXInput{vin.Txid, vin.Vout, []byte{}})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vout := range tx.Vout {
|
||||||
|
outputs = append(outputs, TXOutput{vout.Value, vout.ScriptPubKey})
|
||||||
|
}
|
||||||
|
|
||||||
|
txCopy := Transaction{tx.ID, inputs, outputs}
|
||||||
|
|
||||||
|
return txCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs each input of a Transaction
|
||||||
|
func (tx *Transaction) Sign(privKey ecdsa.PrivateKey, prevTx *Transaction) {
|
||||||
|
if tx.IsCoinbase() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
|
if bytes.Compare(vin.Txid, prevTx.ID) != 0 {
|
||||||
|
log.Panic("ERROR: Previous transaction is not correct")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
txCopy := tx.TrimmedCopy()
|
||||||
|
|
||||||
|
for inID, vin := range txCopy.Vin {
|
||||||
|
txCopy.Vin[inID].ScriptSig = prevTx.Vout[vin.Vout].ScriptPubKey
|
||||||
|
txCopy.SetID()
|
||||||
|
txCopy.Vin[inID].ScriptSig = []byte{}
|
||||||
|
|
||||||
|
r, s, err := ecdsa.Sign(rand.Reader, &privKey, txCopy.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Panic(err)
|
||||||
|
}
|
||||||
|
signature := append(r.Bytes(), s.Bytes()...)
|
||||||
|
|
||||||
|
tx.Vin[inID].ScriptSig = append(signature, tx.Vin[inID].ScriptSig...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify verifies signatures of Transaction inputs
|
||||||
|
func (tx *Transaction) Verify(prevTx *Transaction) bool {
|
||||||
|
sigLen := 64
|
||||||
|
|
||||||
|
if tx.IsCoinbase() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, vin := range tx.Vin {
|
||||||
|
if bytes.Compare(vin.Txid, prevTx.ID) != 0 {
|
||||||
|
log.Panic("ERROR: Previous transaction is not correct")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
txCopy := tx.TrimmedCopy()
|
||||||
|
curve := elliptic.P256()
|
||||||
|
|
||||||
|
for inID, vin := range tx.Vin {
|
||||||
|
txCopy.Vin[inID].ScriptSig = prevTx.Vout[vin.Vout].ScriptPubKey
|
||||||
|
txCopy.SetID()
|
||||||
|
txCopy.Vin[inID].ScriptSig = []byte{}
|
||||||
|
|
||||||
|
signature := vin.ScriptSig[:sigLen]
|
||||||
|
pubKey := vin.ScriptSig[sigLen:]
|
||||||
|
|
||||||
|
r := big.Int{}
|
||||||
|
s := big.Int{}
|
||||||
|
r.SetBytes(signature[:(sigLen / 2)])
|
||||||
|
s.SetBytes(signature[(sigLen / 2):])
|
||||||
|
|
||||||
|
x := big.Int{}
|
||||||
|
y := big.Int{}
|
||||||
|
keyLen := len(pubKey)
|
||||||
|
x.SetBytes(pubKey[:(keyLen / 2)])
|
||||||
|
y.SetBytes(pubKey[(keyLen / 2):])
|
||||||
|
|
||||||
|
rawPubKey := ecdsa.PublicKey{curve, &x, &y}
|
||||||
|
if ecdsa.Verify(&rawPubKey, txCopy.ID, &r, &s) == false {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// TXInput represents a transaction input
|
// TXInput represents a transaction input
|
||||||
type TXInput struct {
|
type TXInput struct {
|
||||||
Txid []byte
|
Txid []byte
|
||||||
|
|
Loading…
Reference in New Issue