Implement Transaction.Sign and Transaction.Verify

This commit is contained in:
Ivan Kuznetsov 2017-09-08 21:29:34 +07:00
parent 92be537fcd
commit 7e8c88867d
1 changed files with 96 additions and 0 deletions

View File

@ -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