Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to unified address (zip 316) #128

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/Makefile.version
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This is the major version
APPVERSION_M=4
# This is the minor version
APPVERSION_N=2
APPVERSION_N=3
# This is the patch version
APPVERSION_P=2
APPVERSION_P=0
2 changes: 2 additions & 0 deletions app/rust/include/zip32.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ void zip32_ovk(uint32_t zip32_account, uint8_t *ovk);
void zip32_ivk(uint32_t zip32_account, uint8_t *ivk);

void zip32_fvk(uint32_t zip32_account, uint8_t *fvk_ptr);

void zip32_dfvk(uint32_t zip32_account, uint8_t *dfvk_ptr);
9 changes: 9 additions & 0 deletions app/rust/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ create_ztruct! {
}
}

create_ztruct! {
pub struct DiversifiableFullViewingKey {
pub ak: AkBytes,
pub nk: NkBytes,
pub ovk: OvkBytes,
pub dk: DkBytes
}
}

// https://zips.z.cash/zip-0032#specification-sapling-key-derivation
create_ztruct! {
pub struct SaplingExtendedFullViewingKey {
Expand Down
17 changes: 11 additions & 6 deletions app/rust/src/zip32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@ use crate::personalization::ZIP32_SAPLING_MASTER_PERSONALIZATION;
use crate::sapling::{
sapling_aknk_to_ivk, sapling_ask_to_ak, sapling_asknsk_to_ivk, sapling_nsk_to_nk,
};
use crate::types::{
diversifier_zero, AskBytes, Diversifier, DiversifierList10, DiversifierList20,
DiversifierList4, DkBytes, FullViewingKey, IvkBytes, NskBytes, OvkBytes,
SaplingExpandedSpendingKey, SaplingKeyBundle, Zip32MasterKey, Zip32MasterSpendingKey,
Zip32Path, Zip32Seed,
};
use crate::types::{diversifier_zero, AskBytes, DiversifiableFullViewingKey, Diversifier, DiversifierList10, DiversifierList20, DiversifierList4, DkBytes, FullViewingKey, IvkBytes, NskBytes, OvkBytes, SaplingExpandedSpendingKey, SaplingKeyBundle, Zip32MasterKey, Zip32MasterSpendingKey, Zip32Path, Zip32Seed};
use crate::zip32_extern::diversifier_is_valid;
use crate::{cryptoops, zip32};

Expand Down Expand Up @@ -258,6 +253,16 @@ pub(crate) fn zip32_sapling_fvk(k: &SaplingKeyBundle) -> FullViewingKey {
)
}

#[inline(never)]
pub(crate) fn zip32_sapling_dfvk(k: &SaplingKeyBundle) -> DiversifiableFullViewingKey {
DiversifiableFullViewingKey::new(
sapling_ask_to_ak(&k.ask()),
sapling_nsk_to_nk(&k.nsk()),
k.ovk(),
k.dk(),
)
}

fn zip32_sapling_derive_child(
ik: &mut Zip32MasterKey,
path_i: u32,
Expand Down
19 changes: 14 additions & 5 deletions app/rust/src/zip32_extern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,8 @@ use crate::constants::{DIV_DEFAULT_LIST_LEN, DIV_SIZE, ZIP32_COIN_TYPE, ZIP32_PU
use crate::sapling::{
sapling_aknk_to_ivk, sapling_ask_to_ak, sapling_asknsk_to_ivk, sapling_nsk_to_nk,
};
use crate::types::{
diversifier_zero, Diversifier, DiversifierList10, DiversifierList20, DiversifierList4,
FullViewingKey, IvkBytes, NskBytes, Zip32Seed,
};
use crate::zip32::{diversifier_group_hash_light, zip32_sapling_derive, zip32_sapling_fvk};
use crate::types::{diversifier_zero, DiversifiableFullViewingKey, Diversifier, DiversifierList10, DiversifierList20, DiversifierList4, FullViewingKey, IvkBytes, NskBytes, Zip32Seed};
use crate::zip32::{diversifier_group_hash_light, zip32_sapling_derive, zip32_sapling_fvk, zip32_sapling_dfvk};
use crate::{sapling, zip32};

#[no_mangle]
Expand Down Expand Up @@ -68,6 +65,18 @@ pub extern "C" fn zip32_fvk(account: u32, fvk_ptr: *mut FullViewingKey) {
fvk_out.to_bytes_mut().copy_from_slice(fvk.to_bytes());
}

#[no_mangle]
pub extern "C" fn zip32_dfvk(account: u32, dfvk_ptr: *mut DiversifiableFullViewingKey) {
let path = [ZIP32_PURPOSE, ZIP32_COIN_TYPE, account];
let dfvk_out = unsafe { &mut *dfvk_ptr };

let key_bundle = zip32_sapling_derive(&path);

let dfvk = zip32_sapling_dfvk(&key_bundle);

dfvk_out.to_bytes_mut().copy_from_slice(dfvk.to_bytes());
}

#[no_mangle]
pub extern "C" fn zip32_child_proof_key(
account: u32,
Expand Down
2 changes: 1 addition & 1 deletion app/src/addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ zxerr_t addr_getItem(int8_t displayIdx,
case addr_secp256k1: {
snprintf(outKey, outKeyLen, "BIP44 Path");

bip32_to_str(buffer, sizeof(buffer), hdPath.secp256k1_path, HDPATH_LEN_BIP44);
bip32_to_str(buffer, sizeof(buffer), hdPath.secp256k1_path, hdPath.pathLen);
pageString(outVal, outValLen, buffer, pageIdx, pageCount);

return zxerr_ok;
Expand Down
14 changes: 13 additions & 1 deletion app/src/apdu_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,13 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {

case INS_GET_ADDR_SECP256K1: {
CHECK_PIN_VALIDATED()
handleGetAddrSecp256K1(flags, tx, rx);
handleGetAddrSecp256K1(flags, tx, rx, false);
break;
}

case INS_GET_UNIFIED_ADDR_SECP256K1: {
CHECK_PIN_VALIDATED()
handleGetAddrSecp256K1(flags, tx, rx, true);
break;
}

Expand Down Expand Up @@ -91,6 +97,12 @@ void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
break;
}

case INS_GET_DFVK: {
CHECK_PIN_VALIDATED()
handleGetKeyDFVK(flags, tx, rx);
break;
}

case INS_INIT_TX: {
CHECK_PIN_VALIDATED()
handleInitTX(flags, tx, rx);
Expand Down
11 changes: 8 additions & 3 deletions app/src/coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ extern "C" {
#define HDPATH_3_DEFAULT (0u)
#define HDPATH_4_DEFAULT (0u)

#define HDPATH_0_TESTNET (0x80000000u | 0x2cu)
#define HDPATH_1_TESTNET (0x80000000u | 0x1u)
#define HDPATH_0_TESTNET (0x80000000u | 0x2cu)
#define HDPATH_1_TESTNET (0x80000000u | 0x1u)

#define HDPATH_0_ZIP32 (0x80000000u | 0x20u)
#define HDPATH_1_ZIP32 (0x80000000u | 0x85u)
Expand All @@ -59,6 +59,7 @@ extern "C" {
#define APDU_DATA_LENGTH_GET_IVK 4 // ZIP32-path
#define APDU_DATA_LENGTH_GET_OVK 4 // ZIP32-path
#define APDU_DATA_LENGTH_GET_FVK 4 // ZIP32-path
#define APDU_DATA_LENGTH_GET_DFVK 4 // ZIP32-path
#define APDU_DATA_LENGTH_GET_NF 44 // ZIP32-path + 8-byte note position + 32-byte note commitment
#define APDU_DATA_LENGTH_GET_ADDR_SAPLING 4 // ZIP32-path
#define APDU_DATA_LENGTH_GET_DIV_LIST 15 // ZIP32-path + 11-byte index
Expand All @@ -70,6 +71,7 @@ extern "C" {
#define INS_GET_ADDR_SAPLING_DIV 0x10
#define INS_GET_ADDR_SAPLING 0x11
#define INS_SIGN_SAPLING 0x12
#define INS_GET_UNIFIED_ADDR_SECP256K1 0x13

#define INS_GET_DIV_LIST 0x09

Expand All @@ -85,9 +87,10 @@ extern "C" {
#define INS_GET_OVK 0xf1
#define INS_GET_NF 0xf2
#define INS_GET_FVK 0xf3
#define INS_GET_DFVK 0xf4
#define INS_CRASH_TEST 0xff

typedef enum { key_ivk = 0, key_ovk = 1, key_fvk = 2, nf = 3 } key_type_e;
typedef enum { key_ivk = 0, key_ovk = 1, key_fvk = 2, nf = 3, key_dfvk = 4 } key_type_e;

#define VIEW_ADDRESS_OFFSET_SECP256K1 PK_LEN_SECP256K1
#define VIEW_ADDRESS_OFFSET_SAPLING ADDR_LEN_SAPLING
Expand All @@ -105,6 +108,7 @@ typedef enum { key_ivk = 0, key_ovk = 1, key_fvk = 2, nf = 3 } key_type_e;

#define HDPATH_LEN_BIP44 5
#define HDPATH_LEN_SAPLING 3
#define HDPATH_LEN_UNIFIED 3

typedef enum {
addr_not_set = 0,
Expand All @@ -118,6 +122,7 @@ typedef struct {
union {
struct {
uint32_t secp256k1_path[HDPATH_LEN_MAX];
uint8_t pathLen;
};
struct {
uint32_t sapling_path[3];
Expand Down
2 changes: 1 addition & 1 deletion app/src/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#pragma once

// CRYPTO File
#define CHECKSUM_LENGTH 4
#define CHECKSUM_LENGTH 4

#define ED25519_SK_SIZE 64

Expand Down
25 changes: 24 additions & 1 deletion app/src/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ static zxerr_t crypto_extractPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) {
uint8_t privateKeyData[64] = {0};

zxerr_t error = zxerr_unknown;
CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, hdPath.secp256k1_path, HDPATH_LEN_BIP44, privateKeyData, NULL));
CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, hdPath.secp256k1_path, hdPath.pathLen, privateKeyData, NULL));
CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey));
io_seproxyhal_io_heartbeat();
CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, &cx_publicKey));
Expand Down Expand Up @@ -1315,6 +1315,10 @@ typedef struct {
uint8_t fvk[AK_SIZE + NK_SIZE + OVK_SIZE];
} tmp_sapling_fvk;

typedef struct {
uint8_t dfvk[AK_SIZE + NK_SIZE + OVK_SIZE + DK_SIZE];
} tmp_sapling_dfvk;

// handleGetKeyFVK: return the full viewing key for a given path
zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t zip32Account, uint16_t *replyLen) {
zemu_log_stack("crypto_fvk_sapling");
Expand All @@ -1334,6 +1338,25 @@ zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t zip32Ac
return zxerr_ok;
}

// handleGetKeyDFVK: return the diversifiable full viewing key for a given path
zxerr_t crypto_dfvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t zip32Account, uint16_t *replyLen) {
zemu_log_stack("crypto_dfvk_sapling");

MEMZERO(buffer, bufferLen);
tmp_sapling_dfvk *out = (tmp_sapling_dfvk *)buffer;

if (bufferLen < AK_SIZE + NK_SIZE + OVK_SIZE + DK_SIZE) {
return zxerr_buffer_too_small;
}

// get diversifiable full viewing key
zip32_dfvk(zip32Account, out->dfvk);
CHECK_APP_CANARY()

*replyLen = AK_SIZE + NK_SIZE + OVK_SIZE + DK_SIZE;
return zxerr_ok;
}

// handleGetNullifier
zxerr_t crypto_nullifier_sapling(uint8_t *outputBuffer,
uint16_t outputBufferLen,
Expand Down
2 changes: 2 additions & 0 deletions app/src/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ zxerr_t crypto_ovk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint

zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen);

zxerr_t crypto_dfvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen);

zxerr_t crypto_nullifier_sapling(
uint8_t *outputBuffer, uint16_t outputBufferLen, uint32_t zip32_path, uint64_t notepos, uint8_t *cm, uint16_t *replyLen);

Expand Down
1 change: 1 addition & 0 deletions app/src/crypto/chacha.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include <stddef.h>
#include <stdint.h>

#include "zxmacros.h"

#if defined(__cplusplus)
Expand Down
4 changes: 2 additions & 2 deletions app/src/handlers/handler_addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#include "view_internal.h"
#include "zxmacros.h"

__Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
__Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx, bool isUnified) {
ZEMU_LOGF(100, "----[handleGetAddrSecp256K1]\n");
*tx = 0;

Expand All @@ -43,7 +43,7 @@ __Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}

extractHDPathTransparent(rx, OFFSET_DATA);
extractHDPathTransparent(rx, OFFSET_DATA, isUnified);

uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1];
uint16_t replyLen = 0;
Expand Down
37 changes: 35 additions & 2 deletions app/src/handlers/handler_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
#include "view_internal.h"
#include "zxmacros.h"



// Transmitted notes are stored on the blockchain in encrypted form.
// If the note was sent to Alice, she uses her incoming viewing key (IVK)
// to decrypt the note (so that she can subsequently send it).
Expand Down Expand Up @@ -142,6 +140,41 @@ __Z_INLINE void handleGetKeyFVK(volatile uint32_t *flags, volatile uint32_t *tx,
THROW(APDU_CODE_OK);
}

// Get the sapling diversifiable full viewing key (ak, nk, ovk)
__Z_INLINE void handleGetKeyDFVK(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) {
zemu_log("----[handleGetKeyDFVK]\n");

*tx = 0;
if (rx - APDU_MIN_LENGTH != APDU_DATA_LENGTH_GET_DFVK) {
ZEMU_LOGF(100, "Wrong length! %d\n", rx);
THROW(APDU_CODE_COMMAND_NOT_ALLOWED);
}

extractHDPathSapling(rx, OFFSET_DATA);

key_state.kind = key_dfvk;
uint16_t replyLen = 0;

zxerr_t err = crypto_dfvk_sapling(G_io_apdu_buffer,

IO_APDU_BUFFER_SIZE - 2, hdPath.sapling_path[2], &replyLen);

if (err != zxerr_ok) {
*tx = 0;
THROW(APDU_CODE_DATA_INVALID);
}
key_state.len = (uint8_t)replyLen;

if (app_mode_expert() || !keys_permission_granted) {
view_review_init(key_getItem, key_getNumItems, app_reply_key);
view_review_show(REVIEW_GENERIC);
*flags |= IO_ASYNCH_REPLY;
}

*tx = replyLen;
THROW(APDU_CODE_OK);
}

// Computing the note nullifier nf is required in order to spend the note.
// Computing nf requires the associated (private) nullifier deriving key nk
// and the note position pos.
Expand Down
20 changes: 17 additions & 3 deletions app/src/handlers/handler_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,19 @@
#include "view_internal.h"
#include "zxmacros.h"

__Z_INLINE void extractHDPathTransparent(uint32_t rx, uint32_t offset) {
if ((rx - offset) < sizeof(uint32_t) * HDPATH_LEN_BIP44) {
__Z_INLINE void extractHDPathTransparent(uint32_t rx, uint32_t offset, bool isUnified) {
uint8_t pathLen = HDPATH_LEN_BIP44;
if(isUnified){
pathLen = HDPATH_LEN_UNIFIED;
}

if ((rx - offset) < sizeof(uint32_t) * pathLen) {
THROW(APDU_CODE_WRONG_LENGTH);
}
hdPath.addressKind = addr_not_set;

MEMCPY(hdPath.secp256k1_path, G_io_apdu_buffer + offset, sizeof(uint32_t) * HDPATH_LEN_BIP44);
MEMCPY(hdPath.secp256k1_path, G_io_apdu_buffer + offset, sizeof(uint32_t) * pathLen);
hdPath.pathLen = pathLen;

const bool mainnet = hdPath.secp256k1_path[0] == HDPATH_0_DEFAULT && hdPath.secp256k1_path[1] == HDPATH_1_DEFAULT;
const bool testnet = hdPath.secp256k1_path[0] == HDPATH_0_TESTNET && hdPath.secp256k1_path[1] == HDPATH_1_TESTNET;
Expand All @@ -47,6 +53,14 @@ __Z_INLINE void extractHDPathTransparent(uint32_t rx, uint32_t offset) {
THROW(APDU_CODE_DATA_INVALID);
}

if(isUnified){
// Validate data
if ((hdPath.secp256k1_path[2] & MASK_HARDENED) == 0) {
ZEMU_LOGF(100, "error validating hardening\n");
THROW(APDU_CODE_DATA_INVALID);
}
}

hdPath.addressKind = addr_secp256k1;
}

Expand Down
8 changes: 7 additions & 1 deletion app/src/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ zxerr_t key_getItem(int8_t displayIdx,
array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32);
pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount);
return zxerr_ok;
case key_dfvk:
snprintf(outKey, outKeyLen, "Send DFVK?\n");
array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32);
pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount);
return zxerr_ok;
case nf:
zemu_log_stack("Send NF?");
snprintf(outKey, outKeyLen, "Send NF?");
Expand All @@ -87,9 +92,10 @@ zxerr_t key_getItem(int8_t displayIdx,
case key_ovk:
case key_ivk:
case key_fvk:
case key_dfvk:
case nf:
snprintf(outKey, outKeyLen, "Retrieve data?");
snprintf(outVal, outValLen, "IVKs, OVKs, FVKs or NFs");
snprintf(outVal, outValLen, "IVKs, OVKs, FVKs, DFVKs or NFs");
return zxerr_ok;
default:
return zxerr_unknown;
Expand Down
Loading
Loading