Skip to content

Commit

Permalink
Merge pull request #110 from LedgerHQ/j-berman-hf-v15
Browse files Browse the repository at this point in the history
support for hf 15 (view tags)
  • Loading branch information
fbeutin-ledger authored Jul 27, 2022
2 parents 440ed25 + 163e5d2 commit 31772fd
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 51 deletions.
10 changes: 9 additions & 1 deletion .github/workflows/lint-workflow.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
name: Code style check

on: [push, pull_request]
on:
push:
branches:
- master
- develop
pull_request:
branches:
- master
- develop

jobs:
job_lint:
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ endif
#DEFINES += MONERO_BETA

APPVERSION_M=1
APPVERSION_N=7
APPVERSION_P=8
APPVERSION_N=8
APPVERSION_P=0

APPVERSION=$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)
SPECVERSION="1.0"
Expand Down
51 changes: 51 additions & 0 deletions doc/developer/blue-app-commands.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
.. |eDRVout| replace:: :math:`\widetilde{\mathfrak{D}_\mathrm{out}}`
.. |AKout| replace:: :math:`\mathcal{AK}_\mathrm{amount}`
.. |eAKout| replace:: :math:`\widetilde{\mathcal{AK}_\mathrm{amount}}`
.. |vtf| replace:: :math:`\mathit{view_tag_full}`
.. |vt| replace:: :math:`\mathit{view_tag}`


.. |ctH| replace:: :math:`\mathcal{H}_\mathrm{commitment}`
Expand Down Expand Up @@ -198,6 +200,7 @@ To summarize, the signature process is:

- compute the range proof
- blind the amount
- compute the view tag

. Compute the final confidential ring signature

Expand Down Expand Up @@ -1142,6 +1145,54 @@ return |Img|.
+--------+-----------------------------------------------------------------+


Derive View Tag
~~~~~~~~~~~~~~~~~~

**Monero**

crypto::derive_view_tag.

**Description**

Derive the view tag of an output.

| compute |Drv| = |dec|[|spk|](|eDrv|)
| compute |vtf| = |Hs|("view_tag" \|, |Drv|, |idx|)
| compute |vt| = |vtf|[0:1]
return |vt|.

**Command**

+-----+-----+-----+-----+----------+
| CLA | INS | P1 | P2 | LC |
+=====+=====+=====+=====+==========+
| 03 | 3B | 00 | 00 | 25 or 45 |
+-----+-----+-----+-----+----------+

**Command data**

+--------+-----------------------------------------------------------------+
| Length | Value |
+========+=================================================================+
| 01 | 00 |
+--------+-----------------------------------------------------------------+
| 20 | encrypted key derivation |eDrv| |
+--------+-----------------------------------------------------------------+
| 20 | ephemeral hmac (optional, only during active transaction) |
+--------+-----------------------------------------------------------------+
| 04 | index |
+--------+-----------------------------------------------------------------+

**Response data**

+--------+-----------------------------------------------------------------+
| Length | Value |
+========+=================================================================+
| 01 | view tag |vt| |
+--------+-----------------------------------------------------------------+


Generate Keypair
~~~~~~~~~~~~~~~~

Expand Down
2 changes: 2 additions & 0 deletions src/monero_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int monero_apdu_derivation_to_scalar(void);
int monero_apdu_derive_public_key(void);
int monero_apdu_derive_secret_key(void);
int monero_apdu_generate_key_image(void);
int monero_apdu_derive_view_tag(void);
int monero_apdu_derive_subaddress_public_key(void);
int monero_apdu_get_subaddress(void);
int monero_apdu_get_subaddress_spend_public_key(void);
Expand Down Expand Up @@ -169,6 +170,7 @@ void monero_derive_public_key(unsigned char *x, unsigned char *drv_data, unsigne
unsigned char *ec_pub);
void monero_secret_key_to_public_key(unsigned char *ec_pub, unsigned char *ec_priv);
void monero_generate_key_image(unsigned char *img, unsigned char *P, unsigned char *x);
void monero_derive_view_tag(unsigned char *view_tag, unsigned char *drv_data, unsigned int out_idx);

void monero_derive_subaddress_public_key(unsigned char *x, unsigned char *pub,
unsigned char *drv_data, unsigned int index);
Expand Down
16 changes: 16 additions & 0 deletions src/monero_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,22 @@ void monero_generate_key_image(unsigned char *img, unsigned char *P, unsigned ch
monero_ecmul_k(img, I, x);
}

/* ----------------------------------------------------------------------- */
/* --- --- */
/* ----------------------------------------------------------------------- */
void monero_derive_view_tag(unsigned char *view_tag, unsigned char *drv_data,
unsigned int out_idx) {
unsigned char varint[8 + 32 + 8];
unsigned int len_varint;

os_memmove(varint, "view_tag", 8);
os_memmove(varint + 8, drv_data, 32);
len_varint = monero_encode_varint(varint + 8 + 32, 8, out_idx);
len_varint += 8 + 32;
monero_keccak_F(varint, len_varint, varint);
os_memmove(view_tag, varint, 1);
}

/* ======================================================================= */
/* SUB ADDRESS */
/* ======================================================================= */
Expand Down
4 changes: 4 additions & 0 deletions src/monero_dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ int check_ins_access() {
case INS_DERIVE_PUBLIC_KEY:
case INS_DERIVE_SECRET_KEY:
case INS_GEN_KEY_IMAGE:
case INS_DERIVE_VIEW_TAG:
case INS_SECRET_KEY_TO_PUBLIC_KEY:
case INS_SECRET_KEY_ADD:
case INS_GENERATE_KEYPAIR:
Expand Down Expand Up @@ -188,6 +189,9 @@ int monero_dispatch() {
case INS_GEN_KEY_IMAGE:
sw = monero_apdu_generate_key_image();
break;
case INS_DERIVE_VIEW_TAG:
sw = monero_apdu_derive_view_tag();
break;
case INS_SECRET_KEY_ADD:
sw = monero_apdu_sc_add();
break;
Expand Down
45 changes: 29 additions & 16 deletions src/monero_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,32 +177,45 @@ void monero_install(unsigned char netId) {
/* ----------------------------------------------------------------------- */
/* --- Reset --- */
/* ----------------------------------------------------------------------- */
const char* const monero_supported_client[] = {"0.17.0.", "0.17.1.", "0.17.2.", "0.17.3."};
#define MONERO_SUPPORTED_CLIENT_SIZE \
(sizeof(monero_supported_client) / sizeof(monero_supported_client[0]))
// Accept the following versions and their derivates
const char* const supported_clients[] = {"0.18."};
#define MONERO_SUPPORTED_CLIENT_SIZE (sizeof(supported_clients) / sizeof(supported_clients[0]))

// Explicitly refuse the following versions
const char* const refused_clients[] = {"0.18.0.0."};
#define MONERO_REFUSED_CLIENT_SIZE (sizeof(refused_clients) / sizeof(refused_clients[0]))

static bool is_client_version_valid(const char* client_version) {
// Check if version is explicitly refused
for (uint32_t i = 0; i < MONERO_REFUSED_CLIENT_SIZE; ++i) {
if (strcmp(PIC(refused_clients[i]), client_version) == 0) {
return false;
}
}
// Check if version is supported
for (uint32_t i = 0; i < MONERO_SUPPORTED_CLIENT_SIZE; ++i) {
// Use strncmp to allow supported version prefixing client version
unsigned int supported_clients_len = strlen(PIC(supported_clients[i]));
if (strncmp(PIC(supported_clients[i]), client_version, supported_clients_len) == 0) {
return true;
}
}
return false;
}

int monero_apdu_reset() {
unsigned int client_version_len;
char client_version[16];
memset(client_version, '\0', 16);
client_version_len = G_monero_vstate.io_length - G_monero_vstate.io_offset;
if (client_version_len > 14) {
THROW(SW_CLIENT_NOT_SUPPORTED + 1);
}
monero_io_fetch((unsigned char*)&client_version[0], client_version_len);
// Add '.' suffix to avoid 'X.1' prefixing 'X.10'
client_version[client_version_len] = '.';
client_version_len++;
client_version[client_version_len] = 0;
unsigned int i = 0;
while (i < MONERO_SUPPORTED_CLIENT_SIZE) {
unsigned int monero_supported_client_len = strlen((char*)PIC(monero_supported_client[i]));
if ((monero_supported_client_len <= client_version_len) &&
(os_memcmp((char*)PIC(monero_supported_client[i]), client_version,
monero_supported_client_len) == 0)) {
break;
}
i++;
}
if (i == MONERO_SUPPORTED_CLIENT_SIZE) {

if (!is_client_version_valid(client_version)) {
THROW(SW_CLIENT_NOT_SUPPORTED);
}

Expand Down
34 changes: 33 additions & 1 deletion src/monero_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,27 @@ int monero_apdu_generate_key_image(
return SW_OK;
}

/* ----------------------------------------------------------------------- */
/* --- --- */
/* ----------------------------------------------------------------------- */
int monero_apdu_derive_view_tag(
/*const crypto::key_derivation &derivation, const size_t output_index, crypto::view_tag &view_tag*/) {
unsigned char derivation[32];
unsigned int output_index;
unsigned char res[1];

// fetch
monero_io_fetch_decrypt(derivation, 32, TYPE_DERIVATION);
output_index = monero_io_fetch_u32();
monero_io_discard(0);

// derive and keep
monero_derive_view_tag(res, derivation, output_index);

monero_io_insert(res, 1);
return SW_OK;
}

/* ----------------------------------------------------------------------- */
/* --- --- */
/* ----------------------------------------------------------------------- */
Expand Down Expand Up @@ -692,7 +713,7 @@ int monero_apdu_get_subaddress_secret_key(/*const crypto::secret_key& sec, const
/* --- --- */
/* ----------------------------------------------------------------------- */

int monero_apu_generate_txout_keys(/*size_t tx_version, crypto::secret_key tx_sec, crypto::public_key Aout, crypto::public_key Bout, size_t output_index, bool is_change, bool is_subaddress, bool need_additional_key*/) {
int monero_apu_generate_txout_keys(/*size_t tx_version, crypto::secret_key tx_sec, crypto::public_key Aout, crypto::public_key Bout, size_t output_index, bool is_change, bool is_subaddress, bool need_additional_key, bool use_view_tags*/) {
// IN
unsigned int tx_version;
unsigned char tx_key[32];
Expand All @@ -704,10 +725,12 @@ int monero_apu_generate_txout_keys(/*size_t tx_version, crypto::secret_key tx_se
unsigned char is_subaddress;
unsigned char need_additional_txkeys;
unsigned char additional_txkey_sec[32];
unsigned char use_view_tags;
// OUT
unsigned char additional_txkey_pub[32];
#define amount_key tx_key
#define out_eph_public_key additional_txkey_sec
unsigned char view_tag[1];
// TMP
unsigned char derivation[32];

Expand All @@ -728,6 +751,7 @@ int monero_apu_generate_txout_keys(/*size_t tx_version, crypto::secret_key tx_se
} else {
monero_io_fetch(NULL, 32);
}
use_view_tags = monero_io_fetch_u8();

// update outkeys hash control
if (G_monero_vstate.tx_sig_mode == TRANSACTION_CREATE_REAL) {
Expand Down Expand Up @@ -769,13 +793,21 @@ int monero_apu_generate_txout_keys(/*size_t tx_version, crypto::secret_key tx_se
// compute ephemeral output key
monero_derive_public_key(out_eph_public_key, derivation, output_index, Bout);

// compute view tag
if (use_view_tags) {
monero_derive_view_tag(view_tag, derivation, output_index);
}

// send all
monero_io_discard(0);
monero_io_insert_encrypt(amount_key, 32, TYPE_AMOUNT_KEY);
monero_io_insert(out_eph_public_key, 32);
if (need_additional_txkeys) {
monero_io_insert(additional_txkey_pub, 32);
}
if (use_view_tags) {
monero_io_insert(view_tag, 1);
}
G_monero_vstate.tx_output_cnt++;
return SW_OK;
}
1 change: 1 addition & 0 deletions src/monero_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ typedef struct monero_v_state_s monero_v_state_t;
#define INS_DERIVE_PUBLIC_KEY 0x36
#define INS_DERIVE_SECRET_KEY 0x38
#define INS_GEN_KEY_IMAGE 0x3A
#define INS_DERIVE_VIEW_TAG 0x3B
#define INS_SECRET_KEY_ADD 0x3C
#define INS_GENERATE_KEYPAIR 0x40
#define INS_SECRET_SCAL_MUL_KEY 0x42
Expand Down
1 change: 1 addition & 0 deletions tests/monero_client/monero_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ def gen_txout_keys(self,
b"\x01" if is_change_addr else b"\x00",
b"\x01" if is_subaddress else b"\x00",
b"\x00" * 33, # additional_txkeys
b"\x00" * 33, # use_view_tags
))

self.device.send(cla=PROTOCOL_VERSION,
Expand Down
24 changes: 24 additions & 0 deletions tests/monero_client/monero_crypto_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,27 @@ def gen_key_derivation(self, pub_key: bytes, _priv_key: bytes) -> bytes:
assert len(response) == 32

return _d_in

def derive_view_tag(self, derivation: bytes, output_index: bytes) -> int:
ins: InsType = InsType.INS_DERIVE_VIEW_TAG

payload: bytes = b"".join([
derivation,
output_index,
])

self.device.send(cla=PROTOCOL_VERSION,
ins=ins,
p1=0,
p2=0,
option=0,
payload=payload)

sw, response = self.device.recv() # type: int, bytes

if not sw & 0x9000:
raise DeviceError(sw, ins)

assert len(response) == 1

return int.from_bytes(response, "big")
1 change: 1 addition & 0 deletions tests/monero_client/monero_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class InsType(enum.IntEnum):
INS_DERIVE_PUBLIC_KEY = 0x36
INS_DERIVE_SECRET_KEY = 0x38
INS_GEN_KEY_IMAGE = 0x3A
INS_DERIVE_VIEW_TAG = 0x3B
INS_SECRET_KEY_ADD = 0x3C
INS_GENERATE_KEYPAIR = 0x40
INS_SECRET_SCAL_MUL_KEY = 0x42
Expand Down
Loading

0 comments on commit 31772fd

Please sign in to comment.