Skip to content

Commit

Permalink
Merge pull request #36 from blooo-io/feat/LDG-535--nano-app-implement…
Browse files Browse the repository at this point in the history
…-deploy-method

Feat/LDG-535--nano-app-implement-deploy-method
  • Loading branch information
n4l5u0r authored Dec 11, 2024
2 parents 0de853c + 4ee2f7a commit f3e8cf9
Show file tree
Hide file tree
Showing 22 changed files with 190 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/common/handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ int handler(uint8_t INS,
case INS_GET_APP_NAME:
return handleGetAppName();
break;
case INS_DEPLOY_MODULE:
handleDeployModule(cdata, p1, lc);
break;
default:
THROW(ERROR_INVALID_INSTRUCTION);
break;
Expand Down
2 changes: 2 additions & 0 deletions src/common/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

#define INS_EXPORT_PRIVATE_KEY 0x05

#define INS_DEPLOY_MODULE 0x06

#define INS_ENCRYPTED_AMOUNT_TRANSFER 0x10
#define INS_TRANSFER_TO_ENCRYPTED 0x11
#define INS_TRANSFER_TO_PUBLIC 0x12
Expand Down
1 change: 1 addition & 0 deletions src/common/responseCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ enum {
ERROR_BUFFER_OVERFLOW = 0x6B06,
ERROR_FAILED_CX_OPERATION = 0x6B07,
ERROR_INVALID_INSTRUCTION = 0x6D00,
ERROR_INVALID_SOURCE_LENGTH = 0x6B08,

// Error codes from the Ledger firmware
ERROR_DEVICE_LOCKED = 0x530C,
Expand Down
2 changes: 2 additions & 0 deletions src/common/ui/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,5 @@ extern const ux_flow_step_t *ux_sign_scheduled_amount_transfer[8];
void startInitialScheduledTransferDisplay(bool displayMemo);
void uiSignScheduledTransferPairFlowSignDisplay(void);
void uiSignScheduledTransferPairFlowDisplay(void);

void uiDeployModuleDisplay(void);
19 changes: 19 additions & 0 deletions src/common/ui/display_bagl.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,4 +794,23 @@ void uiSignScheduledTransferPairFlowDisplay(void) {
ux_flow_init(0, ux_sign_scheduled_transfer_pair_flow, NULL);
}

// Deploy Module
UX_STEP_NOCB(ux_deploy_module_1_step,
bnnn_paging,
{.title = "Version", .text = (char *) global.deployModule.versionDisplay});
UX_STEP_NOCB(ux_deploy_module_2_step,
bnnn_paging,
{.title = "TX hash", .text = (char *) global.deployModule.sourceHashDisplay});
UX_FLOW(ux_deploy_module,
&ux_sign_flow_shared_review,
&ux_sign_flow_account_sender_view,
&ux_deploy_module_1_step,
// &ux_deploy_module_2_step,
&ux_sign_flow_shared_sign,
&ux_sign_flow_shared_decline);

void uiDeployModuleDisplay() {
ux_flow_init(0, ux_deploy_module, NULL);
}

#endif
48 changes: 48 additions & 0 deletions src/deployModule.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "os.h"
#include "common/ui/display.h"
#include "common/responseCodes.h"
#include "common/sign.h"
#include "common/util.h"
#include "deployModule.h"

static deployModule_t *ctx_deploy_module = &global.deployModule;
static tx_state_t *tx_state = &global_tx_state;

#define P1_INITIAL 0x00
#define P1_SOURCE 0x01

void handleDeployModule(uint8_t *cdata, uint8_t p1, uint8_t lc) {
if (p1 == P1_INITIAL) {
cdata += parseKeyDerivationPath(cdata);
cx_sha256_init(&tx_state->hash);
cdata += hashAccountTransactionHeaderAndKind(cdata, DEPLOY_MODULE);

// hash the version and source length
updateHash((cx_hash_t *) &tx_state->hash, cdata, 8);
ctx_deploy_module->version = U4BE(cdata, 0);
ctx_deploy_module->sourceLength = U4BE(cdata, 4);
ctx_deploy_module->remainingSourceLength = ctx_deploy_module->sourceLength;
// TODO: Format the version
numberToText((uint8_t *) ctx_deploy_module->versionDisplay,
sizeof(ctx_deploy_module->versionDisplay),
ctx_deploy_module->version);
sendSuccessNoIdle();
}

else if (p1 == P1_SOURCE && ctx_deploy_module->remainingSourceLength > 0) {
if (ctx_deploy_module->remainingSourceLength < lc) {
THROW(ERROR_INVALID_SOURCE_LENGTH);
}

updateHash((cx_hash_t *) &tx_state->hash, cdata, lc);
ctx_deploy_module->remainingSourceLength -= lc;
if (ctx_deploy_module->remainingSourceLength > 0) {
sendSuccessNoIdle();
} else if (ctx_deploy_module->remainingSourceLength == 0) {
uiDeployModuleDisplay();
}

} else {
THROW(ERROR_INVALID_STATE);
}
}
25 changes: 25 additions & 0 deletions src/deployModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <stdint.h>
#include <stdbool.h>

/**
* Handles the DEPLOY_MODULE instruction, which deploys a module
*
*
*/
void handleDeployModule(uint8_t *cdata, uint8_t p1, uint8_t p2);

typedef struct {
uint32_t version;
uint32_t sourceLength;
uint32_t remainingSourceLength;
uint8_t sourceHash[32];
char sourceHashDisplay[65];
char versionDisplay[11];
} deployModule_t;

// typedef struct {
// uint8_t version[32];
// uint8_t sourceLength[32];
// } deployModuleBlob_t;
4 changes: 2 additions & 2 deletions src/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#include "signTransferToPublic.h"
#include "signTransferWithSchedule.h"
#include "signRegisterData.h"

#include "deployModule.h"
#include "ux.h"

#define LEGACY_PURPOSE 1105
Expand Down Expand Up @@ -124,7 +124,7 @@ typedef union {
signTransferToPublic_t signTransferToPublic;
signConfigureBaker_t signConfigureBaker;
signConfigureDelegationContext_t signConfigureDelegation;

deployModule_t deployModule;
transactionWithDataBlob_t withDataBlob;
} instructionContext;
extern instructionContext global;
Expand Down
54 changes: 54 additions & 0 deletions tests/application_client/boilerplate_command_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class P1(IntEnum):
P1_PROOFS = 0x08 # Sent for proof bytes
P1_NEW_OR_EXISTING = 0x09 # Sent for new/existing credential flag

# Parameter 1 for deploy module
P1_DEPLOY_MODULE_INITIAL = 0x00
P1_DEPLOY_MODULE_SOURCE = 0x01


class P2(IntEnum):
# Parameter 2 for sign for GET_PUBLIC_KEY.
Expand Down Expand Up @@ -78,6 +82,7 @@ class InsType(IntEnum):
SIGN_TRANSFER_WITH_SCHEDULE = 0x03
CREDENTIAL_DEPLOYMENT = 0x04
EXPORT_PRIVATE_KEY = 0x05
DEPLOY_MODULE = 0x06
ENCRYPTED_AMOUNT_TRANSFER = 0x10
TRANSFER_TO_ENCRYPTED = 0x11
TRANSFER_TO_PUBLIC = 0x12
Expand Down Expand Up @@ -737,5 +742,54 @@ def credential_deployment_part_3(
print("km--------sent new or existing", response)
yield response

@contextmanager
def deploy_module(
self,
path: str,
header_and_type: bytes,
version: int,
source: bytes,
) -> Generator[None, None, None]:

if version > 0xFFFFFFFF:
raise ValueError("Version must be less than 4294967296")
if len(source) > 0xFFFFFFFF:
raise ValueError("Source length must be less than 4294967296")

data = pack_derivation_path(path)
data += header_and_type
data += version.to_bytes(4, byteorder="big")
data += len(source).to_bytes(4, byteorder="big")
temp_response = self.backend.exchange(
cla=CLA,
ins=InsType.DEPLOY_MODULE,
p1=P1.P1_DEPLOY_MODULE_INITIAL,
p2=P2.P2_NONE,
data=data,
)
if temp_response.status != 0x9000:
raise ExceptionRAPDU(temp_response.status)

source_chunks = split_message(source, MAX_APDU_LEN)
last_chunk = source_chunks.pop()
for chunk in source_chunks:
temp_response = self.backend.exchange(
cla=CLA,
ins=InsType.DEPLOY_MODULE,
p1=P1.P1_DEPLOY_MODULE_SOURCE,
p2=P2.P2_NONE,
data=chunk,
)
if temp_response.status != 0x9000:
raise ExceptionRAPDU(temp_response.status)
with self.backend.exchange_async(
cla=CLA,
ins=InsType.DEPLOY_MODULE,
p1=P1.P1_DEPLOY_MODULE_SOURCE,
p2=P2.P2_NONE,
data=last_chunk,
) as response:
yield response

def get_async_response(self) -> Optional[RAPDU]:
return self.backend.last_async_response
Binary file added tests/snapshots/nanosp/test_deploy_module/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanosp/test_deploy_module/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanosp/test_deploy_module/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanosp/test_deploy_module/00003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanosp/test_deploy_module/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanosp/test_deploy_module/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanox/test_deploy_module/00000.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanox/test_deploy_module/00001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanox/test_deploy_module/00002.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanox/test_deploy_module/00003.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanox/test_deploy_module/00004.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/snapshots/nanox/test_deploy_module/00005.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions tests/test_deploy_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pytest

from application_client.boilerplate_command_sender import (
BoilerplateCommandSender,
Errors,
)
from application_client.boilerplate_response_unpacker import (
unpack_get_public_key_response,
)
from ragger.bip import calculate_public_key_and_chaincode, CurveChoice
from ragger.error import ExceptionRAPDU
from ragger.navigator import NavInsID, NavIns
from ragger.firmware import Firmware
from utils import navigate_until_text_and_compare, instructions_builder


@pytest.mark.active_test_scope
def test_deploy_module(
backend, firmware, navigator, test_name, default_screenshot_path
):
client = BoilerplateCommandSender(backend)
path = "m/1105/0/0/0/0/2/0/0"
header_and_type = bytes.fromhex(
"20a845815bd43a1999e90fbf971537a70392eb38f89e6bd32b3dd70e1a9551d7000000000000000a0000000000000064000000290000000063de5da700"
)
version = 1
source = b"source"

with client.deploy_module(
path=path, header_and_type=header_and_type, version=version, source=source
):
navigate_until_text_and_compare(
firmware, navigator, "Sign", default_screenshot_path, test_name
)

0 comments on commit f3e8cf9

Please sign in to comment.