Commit baf7ed6f authored by David Vorick's avatar David Vorick

try singing a transaction

parent 978b514e
......@@ -24,6 +24,10 @@ type InputSignatures struct {
// without repeates, and also checks that the largest element is less than or
// equal to the biggest allowed element.
func sortedUnique(elems []uint64, biggestAllowed int) (err error) {
if len(elems) == 0 {
return
}
biggest := elems[0]
for _, elem := range elems[1:] {
if elem <= biggest {
......@@ -152,23 +156,19 @@ func (s *State) validSignatures(t Transaction) (err error) {
publicKey := sigMap[sig.InputID].PossibleKeys[sig.PublicKeyIndex]
switch publicKey.Algorithm {
case ED25519Identifier:
// Check that the public key is a legal length.
if len(publicKey.Key) != crypto.PublicKeySize {
return errors.New("public key is invalid")
// Decode the public key and signature.
decodedPK, err := crypto.DecodePublicKey(publicKey.Key)
if err != nil {
return err
}
if len(sig.Signature) != crypto.SignatureSize {
return errors.New("signature is invalid")
decodedSig, err := crypto.DecodeSignature(sig.Signature)
if err != nil {
return err
}
// Decode the public key and signature from the data types.
var decodedPK crypto.PublicKey
var decodedSig crypto.Signature
copy(decodedPK[:], publicKey.Key)
copy(decodedSig[:], sig.Signature)
sigHash := t.SigHash(i)
if !crypto.VerifyBytes(sigHash[:], decodedPK, decodedSig) {
return errors.New("signature is invalid")
return errors.New("signature did not verify")
}
default:
return errors.New("public key algorithm not recognized")
......
package consensus
import (
"testing"
"time"
"github.com/NebulousLabs/Sia/crypto"
)
// signedOutputTxn funds itself by mining a block, and then uses the funds to
// create a signed output that is valid.
func signedOutputTxn(t *testing.T, s *State) (txn Transaction) {
// Create the keys and a siacoin output that adds coins to the keys.
sk, pk, err := crypto.GenerateSignatureKeys()
if err != nil {
t.Fatal(err)
}
spendConditions := SpendConditions{
NumSignatures: 1,
PublicKeys: []SiaPublicKey{
SiaPublicKey{
Algorithm: ED25519Identifier,
Key: pk[:],
},
},
}
coinAddress := spendConditions.CoinAddress()
minerPayouts := []SiacoinOutput{
SiacoinOutput{
Value: CalculateCoinbase(s.height() + 1),
SpendHash: coinAddress,
},
}
// Mine the block that creates the output.
b, err := mineTestingBlock(s.CurrentBlock().ID(), Timestamp(time.Now().Unix()), minerPayouts, nil, s.CurrentTarget())
if err != nil {
t.Fatal(err)
}
err = s.AcceptBlock(b)
if err != nil {
t.Fatal(err)
}
// Create the transaction that spends the output.
input := SiacoinInput{
OutputID: b.MinerPayoutID(0),
SpendConditions: spendConditions,
}
output := SiacoinOutput{
Value: CalculateCoinbase(s.height()),
SpendHash: ZeroAddress,
}
txn = Transaction{
SiacoinInputs: []SiacoinInput{input},
SiacoinOutputs: []SiacoinOutput{output},
}
// Sign the transaction.
sig := TransactionSignature{
InputID: input.OutputID,
CoveredFields: CoveredFields{WholeTransaction: true},
PublicKeyIndex: 0,
}
txn.Signatures = append(txn.Signatures, sig)
sigHash := txn.SigHash(0)
encodedSig, err := crypto.SignBytes(sigHash[:], sk)
if err != nil {
t.Fatal(err)
}
txn.Signatures[0].Signature = encodedSig[:]
return
}
// testSingleOutput creates a block with one transaction that has inputs and
// outputs, and verifies that the output is accepted into the state.
func testSingleOutput(t *testing.T, s *State) {
txn := signedOutputTxn(t, s)
b, err := mineTestingBlock(s.CurrentBlock().ID(), Timestamp(time.Now().Unix()), nullMinerPayouts(s.Height()+1), []Transaction{txn}, s.CurrentTarget())
if err != nil {
t.Fatal(err)
}
err = s.AcceptBlock(b)
if err != nil {
t.Fatal(err)
}
}
// TestSingleOutput creates a new state and uses it to call testSingleOutput.
func TestSingleOutput(t *testing.T) {
s := CreateGenesisState(Timestamp(time.Now().Unix()))
testSingleOutput(t, s)
}
......@@ -219,7 +219,10 @@ func (b Block) MerkleRoot() hash.Hash {
// MinerPayoutID returns the ID of the payout at the given index.
func (b Block) MinerPayoutID(i int) OutputID {
return OutputID(hash.HashAll(b.ID(), i))
return OutputID(hash.HashAll(
b.ID(),
i,
))
}
// FileContractID returns the id of a file contract given the index of the
......
......@@ -2,6 +2,7 @@ package crypto
import (
"crypto/rand"
"errors"
"github.com/agl/ed25519"
)
......@@ -18,6 +19,32 @@ type (
Signature *[ed25519.SignatureSize]byte
)
// DecodePublicKey takes a bytes slice and returns the corresponding public
// key. An error is returned if the byte slice is the wrong length.
func DecodePublicKey(encodedPK []byte) (pk PublicKey, err error) {
if len(encodedPK) != PublicKeySize {
err = errors.New("public key is invalid size")
return
}
var epk [PublicKeySize]byte
copy(epk[:], encodedPK)
pk = PublicKey(&epk)
return
}
func DecodeSignature(encodedSig []byte) (sig Signature, err error) {
if len(encodedSig) != SignatureSize {
err = errors.New("Signature is invalid size")
return
}
var esig [SignatureSize]byte
copy(esig[:], encodedSig)
sig = Signature(&esig)
return
}
// GenerateKeyPair creates a public-secret keypair that can be used to sign and
// verify messages.
func GenerateSignatureKeys() (sk SecretKey, pk PublicKey, err error) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment