From c3e1244e52385eb9f6d49a94b10ee9a631a973c4 Mon Sep 17 00:00:00 2001 From: manolodewiner Date: Thu, 1 Mar 2018 12:22:36 +0100 Subject: [PATCH] unique-fulfillment and hash&sign --- .travis.yml | 2 +- src/transaction.js | 24 +++++++++++------------ test/transaction/test_cryptoconditions.js | 18 ++++++++++++++--- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d4f5cc..b0f09a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ before_install: -e BIGCHAINDB_KEYPAIR_PRIVATE=5C5Cknco7YxBRP9AgB1cbUVTL4FAcooxErLygw1DeG2D -e BIGCHAINDB_DATABASE_BACKEND=mongodb -e BIGCHAINDB_DATABASE_HOST=172.17.0.1 - bigchaindb/bigchaindb:1.3.0 + bigchaindb/bigchaindb:1.4.0 start - gem install cowsay - npm install -g codecov diff --git a/src/transaction.js b/src/transaction.js index f84cf4c..8c15f1c 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -30,14 +30,6 @@ export default class Transaction { } } - static hashTransaction(transaction) { - // Safely remove any tx id from the given transaction for hashing - const tx = { ...transaction } - delete tx.id - - return sha256Hash(Transaction.serializeTransactionIntoCanonicalString(tx)) - } - static makeTransactionTemplate() { const txTemplate = { 'id': null, @@ -58,8 +50,6 @@ export default class Transaction { tx.metadata = metadata tx.inputs = inputs tx.outputs = outputs - - tx.id = Transaction.hashTransaction(tx) return tx } @@ -246,15 +236,23 @@ export default class Transaction { signedTx.inputs.forEach((input, index) => { const privateKey = privateKeys[index] const privateKeyBuffer = Buffer.from(base58.decode(privateKey)) - const serializedTransaction = Transaction - .serializeTransactionIntoCanonicalString(transaction) + const serializedTransaction = + Transaction.serializeTransactionIntoCanonicalString(transaction) + + const transactionUniqueFulfillment = input.fulfills ? serializedTransaction + .concat(input.fulfills.transaction_id) + .concat(input.fulfills.output_index) : serializedTransaction + const transactionHash = sha256Hash(transactionUniqueFulfillment) const ed25519Fulfillment = new cc.Ed25519Sha256() - ed25519Fulfillment.sign(Buffer.from(serializedTransaction), privateKeyBuffer) + ed25519Fulfillment.sign(Buffer.from(transactionHash, 'hex'), privateKeyBuffer) const fulfillmentUri = ed25519Fulfillment.serializeUri() input.fulfillment = fulfillmentUri }) + const serializedTransaction = + Transaction.serializeTransactionIntoCanonicalString(signedTx) + signedTx.id = sha256Hash(serializedTransaction) return signedTx } } diff --git a/test/transaction/test_cryptoconditions.js b/test/transaction/test_cryptoconditions.js index 4673e17..65e389b 100644 --- a/test/transaction/test_cryptoconditions.js +++ b/test/transaction/test_cryptoconditions.js @@ -1,6 +1,7 @@ import test from 'ava' import cc from 'crypto-conditions' import { Ed25519Keypair, Transaction, ccJsonLoad } from '../../src' +import sha256Hash from '../../src/sha256Hash' test('Ed25519 condition encoding', t => { const publicKey = '4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS' @@ -53,16 +54,27 @@ test('Fulfillment correctly formed', t => { [Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))], alice.publicKey ) + // Sign in order to get the tx id, needed for the unique fulfillment in the transfer transaction + const signCreateTransaction = Transaction.signTransaction(txCreate, alice.privateKey) + const txTransfer = Transaction.makeTransferTransaction( - [{ tx: txCreate, output_index: 0 }], + [{ tx: signCreateTransaction, output_index: 0 }], [Transaction.makeOutput(Transaction.makeEd25519Condition(alice.publicKey))], {} ) - const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer) const txSigned = Transaction.signTransaction(txTransfer, alice.privateKey) + + // Here reconstruct the fulfillment of the transfer transaction + // The tx is serialized, and extended with tx_id and output index, and then hashed into bytes + const msg = Transaction.serializeTransactionIntoCanonicalString(txTransfer) + const msgUniqueFulfillment = txTransfer.inputs[0].fulfills ? msg + .concat(txTransfer.inputs[0].fulfills.transaction_id) + .concat(txTransfer.inputs[0].fulfills.output_index) : msg + const msgHash = sha256Hash(msgUniqueFulfillment) + t.truthy(cc.validateFulfillment( txSigned.inputs[0].fulfillment, txCreate.outputs[0].condition.uri, - Buffer.from(msg) + Buffer.from(msgHash, 'hex') )) })