Skip to content

Commit

Permalink
include script data hash in transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
mkv-vcm committed Sep 16, 2021
1 parent 2b4082c commit 98d83f6
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 21 deletions.
1 change: 1 addition & 0 deletions src/cardano.h
Expand Up @@ -21,6 +21,7 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID");
#define CATALYST_REGISTRATION_PAYLOAD_HASH_LENGTH 32
#define ED25519_SIGNATURE_LENGTH 64
#define SCRIPT_HASH_LENGTH 28
#define SCRIPT_DATA_HASH_LENGTH 32

#define MINTING_POLICY_ID_SIZE 28
#define ASSET_NAME_SIZE_MAX 32
Expand Down
94 changes: 91 additions & 3 deletions src/signTx.c
Expand Up @@ -89,7 +89,8 @@ static inline void advanceStage()
ctx->numWithdrawals,
ctx->includeAuxData,
ctx->includeValidityIntervalStart,
ctx->includeMint
ctx->includeMint,
ctx->includeScriptDataHash
);
txHashBuilder_enterInputs(&BODY_CTX->txHashBuilder);
}
Expand Down Expand Up @@ -192,12 +193,21 @@ static inline void advanceStage()
if (ctx->includeMint) {
ASSERT(BODY_CTX->mintReceived);
}
ctx->stage = SIGN_STAGE_BODY_SCRIPT_DATA_HASH;
if (ctx->includeScriptDataHash) {
break;
}

case SIGN_STAGE_BODY_SCRIPT_DATA_HASH:
if (ctx->includeScriptDataHash) {
ASSERT(BODY_CTX->scriptDataHashReceived);
}
txHashBuilder_addNetworkId(&BODY_CTX->txHashBuilder, ctx->commonTxData.networkId);
ctx->stage = SIGN_STAGE_CONFIRM;
break;

case SIGN_STAGE_CONFIRM:
ctx->stage = SIGN_STAGE_WITNESSES;
txHashBuilder_addNetworkId(&BODY_CTX->txHashBuilder, ctx->commonTxData.networkId);
initTxWitnessCtx();

break;
Expand Down Expand Up @@ -395,6 +405,7 @@ static void signTx_handleInitAPDU(uint8_t p2, uint8_t* wireDataBuffer, size_t wi
uint8_t includeAuxData;
uint8_t includeValidityIntervalStart;
uint8_t includeMint;
uint8_t includeScriptDataHash;
uint8_t txSigningMode;

uint8_t numInputs[4];
Expand Down Expand Up @@ -427,6 +438,9 @@ static void signTx_handleInitAPDU(uint8_t p2, uint8_t* wireDataBuffer, size_t wi
ctx->includeMint = signTx_parseIncluded(wireHeader->includeMint);
TRACE("Include mint %d", ctx->includeMint);

ctx->includeScriptDataHash = signTx_parseIncluded(wireHeader->includeScriptDataHash);
TRACE("Include script data hash %d", ctx->includeScriptDataHash);

ctx->commonTxData.txSigningMode = wireHeader->txSigningMode;
TRACE("Signing mode %d", (int) ctx->commonTxData.txSigningMode);
switch (ctx->commonTxData.txSigningMode) {
Expand Down Expand Up @@ -1582,6 +1596,77 @@ static void signTx_handleMintAPDU(uint8_t p2, uint8_t* wireDataBuffer, size_t wi
signTxMint_handleAPDU(p2, wireDataBuffer, wireDataSize);
}

// ========================= SCRIPT DATA HASH ==========================


enum {
HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY = 1200,
HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND,
HANDLE_SCRIPT_DATA_HASH_STEP_INVALID,
};

static void signTx_handleScriptDataHash_ui_runStep()
{
TRACE("UI step %d", ctx->ui_step);
ui_callback_fn_t* this_fn = signTx_handleScriptDataHash_ui_runStep;

UI_STEP_BEGIN(ctx->ui_step, this_fn);

UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY) {
ui_displayHexBufferScreen("Script data hash", BODY_CTX->stageData.scriptDataHash, SCRIPT_DATA_HASH_LENGTH, this_fn);
}
UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND) {
respondSuccessEmptyMsg();
advanceStage();
}
UI_STEP_END(HANDLE_FEE_STEP_INVALID);
}

static void signTx_handleScriptDataHashAPDU(uint8_t p2, uint8_t* wireDataBuffer, size_t wireDataSize)
{
{
// sanity checks
CHECK_STAGE(SIGN_STAGE_BODY_SCRIPT_DATA_HASH);

VALIDATE(p2 == P2_UNUSED, ERR_INVALID_REQUEST_PARAMETERS);
ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA);
}
{
// parse data
TRACE_BUFFER(wireDataBuffer, wireDataSize);

read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize);
STATIC_ASSERT(SIZEOF(BODY_CTX->stageData.scriptDataHash) == SCRIPT_DATA_HASH_LENGTH, "wrong script data hash length");
view_copyWireToBuffer(BODY_CTX->stageData.scriptDataHash, &view, SCRIPT_DATA_HASH_LENGTH);
VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA);

BODY_CTX->scriptDataHashReceived = true;
}

{
// add to tx
TRACE("Adding script data hash to tx hash");
txHashBuilder_addScriptDataHash(&BODY_CTX->txHashBuilder, BODY_CTX->stageData.scriptDataHash, SIZEOF(BODY_CTX->stageData.scriptDataHash));
}

security_policy_t policy = POLICY_SHOW_BEFORE_RESPONSE;//policyForSignTxScriptDataHash(ctx->commonTxData.txSigningMode, BODY_CTX->stageData.fee);
TRACE("Policy: %d", (int) policy);
ENSURE_NOT_DENIED(policy);

{
// select UI steps
switch (policy) {
# define CASE(POLICY, UI_STEP) case POLICY: {ctx->ui_step=UI_STEP; break;}
CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY);
CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND);
# undef CASE
default:
THROW(ERR_NOT_IMPLEMENTED);
}
}

signTx_handleScriptDataHash_ui_runStep();
}

// ============================== CONFIRM ==============================

Expand Down Expand Up @@ -1804,6 +1889,7 @@ static subhandler_fn_t* lookup_subhandler(uint8_t p1)
CASE(0x07, signTx_handleWithdrawalAPDU);
CASE(0x09, signTx_handleValidityIntervalStartAPDU);
CASE(0x0b, signTx_handleMintAPDU);
CASE(0x0c, signTx_handleScriptDataHashAPDU);
CASE(0x0a, signTx_handleConfirmAPDU);
CASE(0x0f, signTx_handleWitnessAPDU);
DEFAULT(NULL)
Expand Down Expand Up @@ -1843,7 +1929,8 @@ void signTx_handleAPDU(
case SIGN_STAGE_BODY_WITHDRAWALS:
case SIGN_STAGE_BODY_VALIDITY_INTERVAL:
case SIGN_STAGE_BODY_MINT:
case SIGN_STAGE_BODY_MINT_SUBMACHINE: {
case SIGN_STAGE_BODY_MINT_SUBMACHINE:
case SIGN_STAGE_BODY_SCRIPT_DATA_HASH: {
explicit_bzero(&BODY_CTX->stageData, SIZEOF(BODY_CTX->stageData));
break;
}
Expand Down Expand Up @@ -1887,6 +1974,7 @@ ins_sign_tx_body_context_t* accessBodyContext()
case SIGN_STAGE_BODY_VALIDITY_INTERVAL:
case SIGN_STAGE_BODY_MINT:
case SIGN_STAGE_BODY_MINT_SUBMACHINE:
case SIGN_STAGE_BODY_SCRIPT_DATA_HASH:
case SIGN_STAGE_CONFIRM:
return &(ctx->txPartCtx.body_ctx);

Expand Down
8 changes: 6 additions & 2 deletions src/signTx.h
Expand Up @@ -37,8 +37,9 @@ typedef enum {
SIGN_STAGE_BODY_VALIDITY_INTERVAL = 34,
SIGN_STAGE_BODY_MINT = 35,
SIGN_STAGE_BODY_MINT_SUBMACHINE = 36,
SIGN_STAGE_CONFIRM = 37,
SIGN_STAGE_WITNESSES = 38,
SIGN_STAGE_BODY_SCRIPT_DATA_HASH = 37,
SIGN_STAGE_CONFIRM = 38,
SIGN_STAGE_WITNESSES = 39,
} sign_tx_stage_t;

enum {
Expand Down Expand Up @@ -108,6 +109,7 @@ typedef struct {
bool ttlReceived;
bool validityIntervalStartReceived;
bool mintReceived;
bool scriptDataHashReceived;

// TODO move these to commonTxData?
tx_hash_builder_t txHashBuilder;
Expand All @@ -119,6 +121,7 @@ typedef struct {
sign_tx_certificate_data_t certificate;
sign_tx_withdrawal_data_t withdrawal;
uint64_t validityIntervalStart;
uint8_t scriptDataHash[SCRIPT_DATA_HASH_LENGTH];
} stageData; // TODO rename to reflect single-APDU scope

union {
Expand Down Expand Up @@ -148,6 +151,7 @@ typedef struct {
uint16_t numWithdrawals; // reward withdrawals
bool includeValidityIntervalStart;
bool includeMint;
bool includeScriptDataHash;
uint16_t numWitnesses;

uint8_t auxDataHash[AUX_DATA_HASH_LENGTH];
Expand Down
54 changes: 42 additions & 12 deletions src/txHashBuilder.c
Expand Up @@ -64,7 +64,8 @@ void txHashBuilder_init(
uint16_t numWithdrawals,
bool includeAuxData,
bool includeValidityIntervalStart,
bool includeMint
bool includeMint,
bool includeScriptDataHash
)
{
TRACE("numInputs = %u", numInputs);
Expand Down Expand Up @@ -108,10 +109,13 @@ void txHashBuilder_init(
builder->includeMint = includeMint;
if (includeMint) numItems++;

builder->includeScriptDataHash = includeScriptDataHash;
if (includeScriptDataHash) numItems++;

// network id always included
numItems++;

ASSERT((4 <= numItems) && (numItems <= 10));
ASSERT((4 <= numItems) && (numItems <= 11));

_TRACE("Serializing tx body with %u items", numItems);
BUILDER_APPEND_CBOR(CBOR_TYPE_MAP, numItems);
Expand Down Expand Up @@ -1183,25 +1187,31 @@ static void txHashBuilder_assertCanLeaveMint(tx_hash_builder_t* builder)
ASSERT(builder->multiassetData.remainingTokens == 0);
}

void txHashBuilder_addNetworkId(tx_hash_builder_t* builder, uint8_t networkId)
void txHashBuilder_addScriptDataHash(
tx_hash_builder_t* builder,
const uint8_t* scriptHashData, size_t scriptHashDataSize
)
{
_TRACE("state = %d", builder->state);

ASSERT(scriptHashDataSize == SCRIPT_DATA_HASH_LENGTH);
txHashBuilder_assertCanLeaveMint(builder);
ASSERT(builder->includeScriptDataHash);

// add network id item into the main tx body map
BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_BODY_KEY_NETWORK_ID);
BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, networkId);

builder->state = TX_HASH_BUILDER_IN_NETWORK_ID;
{
BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_BODY_KEY_SCRIPT_HASH_DATA);
BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, scriptHashDataSize);
BUILDER_APPEND_DATA(scriptHashData, scriptHashDataSize);
}
builder->state = TX_HASH_BUILDER_IN_SCRIPT_HASH_DATA;
}

static void txHashBuilder_assertCanLeaveNetworkId(tx_hash_builder_t* builder)
static void txHashBuilder_assertCanLeaveScriptDataHash(tx_hash_builder_t* builder)
{
_TRACE("state = %d", builder->state);
_TRACE("state = %u", builder->state);

switch (builder->state) {
case TX_HASH_BUILDER_IN_NETWORK_ID:
case TX_HASH_BUILDER_IN_SCRIPT_HASH_DATA:
break;

case TX_HASH_BUILDER_IN_MINT:
Expand All @@ -1212,14 +1222,34 @@ static void txHashBuilder_assertCanLeaveNetworkId(tx_hash_builder_t* builder)
case TX_HASH_BUILDER_IN_TTL:
case TX_HASH_BUILDER_IN_FEE:
txHashBuilder_assertCanLeaveMint(builder);
ASSERT(!builder->includeValidityIntervalStart);
ASSERT(!builder->includeScriptDataHash);
break;

default:
ASSERT(false);
}
}

void txHashBuilder_addNetworkId(tx_hash_builder_t* builder, uint8_t networkId)
{
_TRACE("state = %d", builder->state);

txHashBuilder_assertCanLeaveScriptDataHash(builder);

// add network id item into the main tx body map
BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, TX_BODY_KEY_NETWORK_ID);
BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, networkId);

builder->state = TX_HASH_BUILDER_IN_NETWORK_ID;
}

static void txHashBuilder_assertCanLeaveNetworkId(tx_hash_builder_t* builder)
{
_TRACE("state = %d", builder->state);

ASSERT(builder->state == TX_HASH_BUILDER_IN_NETWORK_ID);
}

void txHashBuilder_finalize(tx_hash_builder_t* builder, uint8_t* outBuffer, size_t outSize)
{
txHashBuilder_assertCanLeaveNetworkId(builder);
Expand Down
15 changes: 12 additions & 3 deletions src/txHashBuilder.h
Expand Up @@ -15,6 +15,7 @@ enum {
TX_BODY_KEY_AUX_DATA = 7,
TX_BODY_KEY_VALIDITY_INTERVAL_START = 8,
TX_BODY_KEY_MINT = 9,
TX_BODY_KEY_SCRIPT_HASH_DATA = 11,
TX_BODY_KEY_NETWORK_ID = 15,
};

Expand Down Expand Up @@ -53,8 +54,9 @@ typedef enum {
TX_HASH_BUILDER_IN_MINT_TOP_LEVEL_DATA = 1010,
TX_HASH_BUILDER_IN_MINT_ASSET_GROUP = 1011,
TX_HASH_BUILDER_IN_MINT_TOKEN = 1012,
TX_HASH_BUILDER_IN_NETWORK_ID = 1100,
TX_HASH_BUILDER_FINISHED = 1200,
TX_HASH_BUILDER_IN_SCRIPT_HASH_DATA = 1100,
TX_HASH_BUILDER_IN_NETWORK_ID = 1200,
TX_HASH_BUILDER_FINISHED = 1300,
} tx_hash_builder_state_t;

typedef struct {
Expand All @@ -66,6 +68,7 @@ typedef struct {
bool includeAuxData;
bool includeValidityIntervalStart;
bool includeMint;
bool includeScriptDataHash;

union {
struct {
Expand Down Expand Up @@ -93,7 +96,8 @@ void txHashBuilder_init(
uint16_t numWithdrawals,
bool includeAuxData,
bool includeValidityIntervalStart,
bool includeMint
bool includeMint,
bool includeScriptDataHash
);

void txHashBuilder_enterInputs(tx_hash_builder_t* builder);
Expand Down Expand Up @@ -216,6 +220,11 @@ void txHashBuilder_addMint_token(
int64_t amount
);

void txHashBuilder_addScriptDataHash(
tx_hash_builder_t* builder,
const uint8_t* scriptHashData, size_t scriptHashDataSize
);

void txHashBuilder_addNetworkId(tx_hash_builder_t* builder, uint8_t networkId);

void txHashBuilder_finalize(
Expand Down
3 changes: 2 additions & 1 deletion src/txHashBuilder_test.c
Expand Up @@ -359,7 +359,8 @@ void run_txHashBuilder_test()
numCertificates, ARRAY_LEN(withdrawals),
true, // metadata
true, // validity interval start
true // mint
true, // mint
false // script hash data
);

txHashBuilder_enterInputs(&builder);
Expand Down

0 comments on commit 98d83f6

Please sign in to comment.