Skip to content

Commit

Permalink
add output optional script data hash handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mkv-vcm committed Sep 23, 2021
1 parent 31292d6 commit d127ddd
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/cardano.h
Expand Up @@ -22,6 +22,7 @@ STATIC_ASSERT(LOVELACE_MAX_SUPPLY < LOVELACE_INVALID, "bad LOVELACE_INVALID");
#define ED25519_SIGNATURE_LENGTH 64
#define SCRIPT_HASH_LENGTH 28
#define SCRIPT_DATA_HASH_LENGTH 32
#define OUTPUT_DATA_HASH_LENGTH 32

#define MINTING_POLICY_ID_SIZE 28
#define ASSET_NAME_SIZE_MAX 32
Expand Down
104 changes: 98 additions & 6 deletions src/signTxOutput.c
Expand Up @@ -27,6 +27,7 @@ bool signTxOutput_isFinished()
case STATE_OUTPUT_TOP_LEVEL_DATA:
case STATE_OUTPUT_ASSET_GROUP:
case STATE_OUTPUT_TOKEN:
case STATE_OUTPUT_DATA_HASH:
case STATE_OUTPUT_CONFIRM:
return false;

Expand Down Expand Up @@ -61,7 +62,11 @@ static inline void advanceState()
ASSERT(subctx->currentAssetGroup == 0);
subctx->state = STATE_OUTPUT_ASSET_GROUP;
} else {
subctx->state = STATE_OUTPUT_CONFIRM;
if (subctx->includeDataHash) {
subctx->state = STATE_OUTPUT_DATA_HASH;
} else {
subctx->state = STATE_OUTPUT_CONFIRM;
}
}
break;

Expand All @@ -84,12 +89,21 @@ static inline void advanceState()

if (subctx->currentAssetGroup == subctx->numAssetGroups) {
// the whole token bundle has been received
subctx->state = STATE_OUTPUT_CONFIRM;
if (subctx->includeDataHash) {
subctx->state = STATE_OUTPUT_DATA_HASH;
} else {
subctx->state = STATE_OUTPUT_CONFIRM;
}
} else {
subctx->state = STATE_OUTPUT_ASSET_GROUP;
}
break;

case STATE_OUTPUT_DATA_HASH:
ASSERT(subctx->dataHashReceived);
subctx->state = STATE_OUTPUT_CONFIRM;
break;

case STATE_OUTPUT_CONFIRM:
subctx->state = STATE_OUTPUT_FINISHED;
break;
Expand Down Expand Up @@ -165,7 +179,8 @@ static void signTx_handleOutput_addressBytes()
subctx->stateData.output.address.buffer,
subctx->stateData.output.address.size,
subctx->stateData.output.adaAmount,
subctx->numAssetGroups
subctx->numAssetGroups,
subctx->includeDataHash
);
}

Expand Down Expand Up @@ -257,7 +272,8 @@ static void signTx_handleOutput_addressParams()
&BODY_CTX->txHashBuilder,
addressBuffer, addressSize,
subctx->stateData.output.adaAmount,
subctx->numAssetGroups
subctx->numAssetGroups,
subctx->includeDataHash
);
}

Expand Down Expand Up @@ -330,6 +346,8 @@ static void signTxOutput_handleTopLevelDataAPDU(uint8_t* wireDataBuffer, size_t
ASSERT_TYPE(subctx->numAssetGroups, uint16_t);
subctx->numAssetGroups = (uint16_t) numAssetGroups;

subctx->includeDataHash = signTx_parseIncluded(parse_u1be(&view));

VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA);
}
{
Expand Down Expand Up @@ -532,18 +550,86 @@ static void signTxOutput_handleTokenAPDU(uint8_t* wireDataBuffer, size_t wireDat
txHashBuilder_addOutput_token(
&BODY_CTX->txHashBuilder,
subctx->stateData.token.assetNameBytes, subctx->stateData.token.assetNameSize,
subctx->stateData.token.amount
subctx->stateData.token.amount,
subctx->includeDataHash
);
TRACE();
}

signTxOutput_handleToken_ui_runStep();
}

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

enum {
HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY_HASH = 3500,
HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND,
HANDLE_SCRIPT_DATA_HASH_STEP_INVALID,
};

static void signTxOutput_handleScriptDataHash_ui_runStep()
{
output_context_t* subctx = accessSubcontext();
TRACE("UI step %d", subctx->ui_step);
ui_callback_fn_t* this_fn = signTxOutput_handleScriptDataHash_ui_runStep;

UI_STEP_BEGIN(subctx->ui_step, this_fn);

UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY_HASH) {
ui_displayHexBufferScreen("Script data hash", subctx->stateData.dataHash, OUTPUT_DATA_HASH_LENGTH, this_fn);
}
UI_STEP(HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND) {
respondSuccessEmptyMsg();

advanceState();
}
UI_STEP_END(HANDLE_SCRIPT_DATA_HASH_STEP_INVALID);
}

static void signTxOutput_handleScriptDataHashAPDU(uint8_t* wireDataBuffer, size_t wireDataSize)
{
{
// sanity checks
CHECK_STATE(STATE_OUTPUT_DATA_HASH);
ASSERT(wireDataSize < BUFFER_SIZE_PARANOIA);
}
output_context_t* subctx = accessSubcontext();
{
// parse data
TRACE_BUFFER(wireDataBuffer, wireDataSize);

read_view_t view = make_read_view(wireDataBuffer, wireDataBuffer + wireDataSize);
STATIC_ASSERT(SIZEOF(subctx->stateData.dataHash) == OUTPUT_DATA_HASH_LENGTH, "wrong script data hash length");
view_copyWireToBuffer(subctx->stateData.dataHash, &view, OUTPUT_DATA_HASH_LENGTH);
VALIDATE(view_remainingSize(&view) == 0, ERR_INVALID_DATA);

subctx->dataHashReceived = true;
}
{
// add to tx
TRACE("Adding script data hash to tx hash");
txHashBuilder_addOutput_dataHash(&BODY_CTX->txHashBuilder, subctx->stateData.dataHash, SIZEOF(subctx->stateData.dataHash));
}

{
// select UI step
switch (subctx->outputSecurityPolicy) {
# define CASE(POLICY, UI_STEP) case POLICY: {subctx->ui_step=UI_STEP; break;}
CASE(POLICY_SHOW_BEFORE_RESPONSE, HANDLE_SCRIPT_DATA_HASH_STEP_DISPLAY_HASH);
CASE(POLICY_ALLOW_WITHOUT_PROMPT, HANDLE_SCRIPT_DATA_HASH_STEP_RESPOND);
# undef CASE
default:
THROW(ERR_NOT_IMPLEMENTED);
}
}

signTxOutput_handleScriptDataHash_ui_runStep();
}

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

enum {
HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 3500,
HANDLE_CONFIRM_STEP_FINAL_CONFIRM = 3600,
HANDLE_CONFIRM_STEP_RESPOND,
HANDLE_CONFIRM_STEP_INVALID,
};
Expand Down Expand Up @@ -615,6 +701,7 @@ enum {
APDU_INSTRUCTION_TOP_LEVEL_DATA = 0x30,
APDU_INSTRUCTION_ASSET_GROUP = 0x31,
APDU_INSTRUCTION_TOKEN = 0x32,
APDU_INSTRUCTION_SCRIPT_DATA_HASH = 0x34,
APDU_INSTRUCTION_CONFIRM = 0x33,
};

Expand All @@ -624,6 +711,7 @@ bool signTxOutput_isValidInstruction(uint8_t p2)
case APDU_INSTRUCTION_TOP_LEVEL_DATA:
case APDU_INSTRUCTION_ASSET_GROUP:
case APDU_INSTRUCTION_TOKEN:
case APDU_INSTRUCTION_SCRIPT_DATA_HASH:
case APDU_INSTRUCTION_CONFIRM:
return true;

Expand All @@ -649,6 +737,10 @@ void signTxOutput_handleAPDU(uint8_t p2, uint8_t* wireDataBuffer, size_t wireDat
signTxOutput_handleTokenAPDU(wireDataBuffer, wireDataSize);
break;

case APDU_INSTRUCTION_SCRIPT_DATA_HASH:
signTxOutput_handleScriptDataHashAPDU(wireDataBuffer, wireDataSize);
break;

case APDU_INSTRUCTION_CONFIRM:
signTxOutput_handleConfirmAPDU(wireDataBuffer, wireDataSize);
break;
Expand Down
8 changes: 6 additions & 2 deletions src/signTxOutput.h
Expand Up @@ -20,8 +20,9 @@ typedef enum {
STATE_OUTPUT_TOP_LEVEL_DATA = 2510,
STATE_OUTPUT_ASSET_GROUP = 2511,
STATE_OUTPUT_TOKEN = 2512,
STATE_OUTPUT_CONFIRM = 2513,
STATE_OUTPUT_FINISHED = 2514
STATE_OUTPUT_DATA_HASH = 2513,
STATE_OUTPUT_CONFIRM = 2514,
STATE_OUTPUT_FINISHED = 2515
} sign_tx_output_state_t;


Expand All @@ -48,6 +49,8 @@ typedef struct {
uint16_t currentAssetGroup;
uint16_t numTokens;
uint16_t currentToken;
bool includeDataHash;
bool dataHashReceived;

// this affects whether amounts and tokens are shown
security_policy_t outputSecurityPolicy;
Expand All @@ -58,6 +61,7 @@ typedef struct {
token_group_t tokenGroup;
output_token_amount_t token;
};
uint8_t dataHash[OUTPUT_DATA_HASH_LENGTH];
} stateData;

} output_context_t;
Expand Down
34 changes: 28 additions & 6 deletions src/txHashBuilder.c
Expand Up @@ -197,7 +197,8 @@ void txHashBuilder_addOutput_topLevelData(
tx_hash_builder_t* builder,
const uint8_t* addressBuffer, size_t addressSize,
uint64_t amount,
uint16_t numAssetGroups
uint16_t numAssetGroups,
bool includeDataHash
)
{
_TRACE("state = %d, remainingOutputs = %u", builder->state, builder->remainingOutputs);
Expand All @@ -213,7 +214,7 @@ void txHashBuilder_addOutput_topLevelData(
// Unsigned[amount]
// ]
{
BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2);
BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2 + includeDataHash);
{
BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, addressSize);
BUILDER_APPEND_DATA(addressBuffer, addressSize);
Expand All @@ -222,7 +223,11 @@ void txHashBuilder_addOutput_topLevelData(
BUILDER_APPEND_CBOR(CBOR_TYPE_UNSIGNED, amount);
}
}
builder->state = TX_HASH_BUILDER_IN_OUTPUTS;
if (includeDataHash) {
builder->state = TX_HASH_BUILDER_IN_OUTPUTS_DATA_HASH;
} else {
builder->state = TX_HASH_BUILDER_IN_OUTPUTS;
}
} else {
builder->multiassetData.remainingAssetGroups = numAssetGroups;
// Array(2)[
Expand All @@ -235,7 +240,7 @@ void txHashBuilder_addOutput_topLevelData(
// ]
// ]
{
BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2);
BUILDER_APPEND_CBOR(CBOR_TYPE_ARRAY, 2 + includeDataHash);
{
BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, addressSize);
BUILDER_APPEND_DATA(addressBuffer, addressSize);
Expand Down Expand Up @@ -342,18 +347,35 @@ void txHashBuilder_addOutput_tokenGroup(
void txHashBuilder_addOutput_token(
tx_hash_builder_t* builder,
const uint8_t* assetNameBuffer, size_t assetNameSize,
uint64_t amount
uint64_t amount,
bool includeDataHash
)
{
ASSERT(assetNameSize <= ASSET_NAME_SIZE_MAX);

addToken(builder, assetNameBuffer, assetNameSize, amount,
TX_HASH_BUILDER_IN_OUTPUTS_TOKEN,
TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP,
TX_HASH_BUILDER_IN_OUTPUTS,
includeDataHash ? TX_HASH_BUILDER_IN_OUTPUTS_DATA_HASH : TX_HASH_BUILDER_IN_OUTPUTS,
CBOR_TYPE_UNSIGNED);
}

void txHashBuilder_addOutput_dataHash(
tx_hash_builder_t* builder,
const uint8_t* dataHashBuffer, size_t dataHashSize
)
{
ASSERT(dataHashSize == OUTPUT_DATA_HASH_LENGTH);
ASSERT(builder->state == TX_HASH_BUILDER_IN_OUTPUTS_DATA_HASH);

{
BUILDER_APPEND_CBOR(CBOR_TYPE_BYTES, dataHashSize);
BUILDER_APPEND_DATA(dataHashBuffer, dataHashSize);
}
builder->state = TX_HASH_BUILDER_IN_OUTPUTS;
}


static void txHashBuilder_assertCanLeaveOutputs(tx_hash_builder_t* builder)
{
_TRACE("state = %d, remainingOutputs = %u", builder->state, builder->remainingOutputs);
Expand Down
11 changes: 9 additions & 2 deletions src/txHashBuilder.h
Expand Up @@ -36,6 +36,7 @@ typedef enum {
TX_HASH_BUILDER_IN_OUTPUTS_TOP_LEVEL_DATA = 310,
TX_HASH_BUILDER_IN_OUTPUTS_ASSET_GROUP = 311,
TX_HASH_BUILDER_IN_OUTPUTS_TOKEN = 312,
TX_HASH_BUILDER_IN_OUTPUTS_DATA_HASH = 313,
TX_HASH_BUILDER_IN_FEE = 400,
TX_HASH_BUILDER_IN_TTL = 500,
TX_HASH_BUILDER_IN_CERTIFICATES = 600,
Expand Down Expand Up @@ -112,7 +113,8 @@ void txHashBuilder_addOutput_topLevelData(
tx_hash_builder_t* builder,
const uint8_t* addressBuffer, size_t addressSize,
uint64_t amount,
uint16_t numAssetGroups
uint16_t numAssetGroups,
bool includeDataHash
);
void txHashBuilder_addOutput_tokenGroup(
tx_hash_builder_t* builder,
Expand All @@ -122,7 +124,12 @@ void txHashBuilder_addOutput_tokenGroup(
void txHashBuilder_addOutput_token(
tx_hash_builder_t* builder,
const uint8_t* assetNameBuffer, size_t assetNameSize,
uint64_t amount
uint64_t amount,
bool includeDataHash
);
void txHashBuilder_addOutput_dataHash(
tx_hash_builder_t* builder,
const uint8_t* dataHashBuffer, size_t dataHashSize
);

void txHashBuilder_addFee(tx_hash_builder_t* builder, uint64_t fee);
Expand Down
16 changes: 13 additions & 3 deletions src/txHashBuilder_test.c
Expand Up @@ -152,6 +152,16 @@ static void addMultiassetMint(tx_hash_builder_t* builder)
addTwoMultiassetTokenGroups(builder, &txHashBuilder_addMint_tokenGroup, &addMintTokenProxy);
}

static void outputTokenHandler(
tx_hash_builder_t* builder,
const uint8_t* assetNameBuffer, size_t assetNameSize,
uint64_t amount
)
{
txHashBuilder_addOutput_token(builder, assetNameBuffer, assetNameSize, amount, false);
}


static void addMultiassetOutput(tx_hash_builder_t* builder)
{
uint8_t tmp[70];
Expand All @@ -160,10 +170,10 @@ static void addMultiassetOutput(tx_hash_builder_t* builder)
builder,
tmp, tmpSize,
outputs[1].amount,
2
2, false
);

addTwoMultiassetTokenGroups(builder, &txHashBuilder_addOutput_tokenGroup, &txHashBuilder_addOutput_token);
addTwoMultiassetTokenGroups(builder, &txHashBuilder_addOutput_tokenGroup, &outputTokenHandler);
}

static void addOutputs(tx_hash_builder_t* builder)
Expand All @@ -179,7 +189,7 @@ static void addOutputs(tx_hash_builder_t* builder)
builder,
tmp, tmpSize,
it->amount,
0
0, false
);
}

Expand Down

0 comments on commit d127ddd

Please sign in to comment.