From e9eef65f2439c4e7b1f8a64adfc75d2e2baca8b9 Mon Sep 17 00:00:00 2001 From: Juan Leni Date: Tue, 23 Jul 2024 18:00:48 +0200 Subject: [PATCH] applying clang format (#110) * applying clang format * cargo +nightly fmt --- app/rust/include/rslib.h | 56 +- app/rust/src/commitments.rs | 52 +- app/rust/src/constants.rs | 8 +- app/rust/src/zip32.rs | 186 +- app/src/addr.c | 96 +- app/src/addr.h | 9 +- app/src/apdu_handler.c | 1360 +++++++------- app/src/c_api/rust.c | 265 +-- app/src/chacha.c | 183 +- app/src/chacha.h | 10 +- app/src/coin.h | 106 +- app/src/common/actions.c | 1 + app/src/common/actions.h | 45 +- app/src/common/main.c | 30 +- app/src/common/tx.c | 94 +- app/src/common/tx.h | 12 +- app/src/constants.h | 156 +- app/src/crypto.c | 2490 ++++++++++++------------- app/src/crypto.h | 118 +- app/src/index_NU5.h | 26 +- app/src/index_sapling.c | 21 +- app/src/index_sapling.h | 121 +- app/src/jubjub.c | 520 +++--- app/src/jubjub.h | 54 +- app/src/key.c | 117 +- app/src/key.h | 8 +- app/src/nvdata.c | 462 ++--- app/src/nvdata.h | 93 +- app/src/parser.c | 669 ++++--- app/src/parser.h | 32 +- app/src/parser_common.h | 96 +- app/src/parser_impl.c | 120 +- app/src/parser_impl.h | 143 +- app/src/parser_txdef.h | 4 +- app/src/sighash.c | 315 ++-- app/src/sighash.h | 28 +- app/src/txid.c | 673 +++---- app/src/txid.h | 7 +- app/src/zcash_utils.h | 18 +- app/src/zip-0317.c | 45 +- app/src/zip-0317.h | 3 +- tests_zemu/tests/txs_advanced.test.ts | 28 +- 42 files changed, 4317 insertions(+), 4563 deletions(-) diff --git a/app/rust/include/rslib.h b/app/rust/include/rslib.h index 8e991fa0..612390c2 100644 --- a/app/rust/include/rslib.h +++ b/app/rust/include/rslib.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include "parser_common.h" #include "parser_txdef.h" @@ -10,17 +10,14 @@ * ********************************************************************************/ // ZIP32 functions -void get_pkd(const uint8_t *seed_ptr, uint32_t pos, - const uint8_t *diversifier_ptr, uint8_t *pkd); +void get_pkd(const uint8_t *seed_ptr, uint32_t pos, const uint8_t *diversifier_ptr, uint8_t *pkd); -void get_pkd_from_seed(const uint8_t *seed_ptr, uint32_t pos, - const uint8_t *start_index, uint8_t *diversifier_ptr, - uint8_t *pkd); +void get_pkd_from_seed( + const uint8_t *seed_ptr, uint32_t pos, const uint8_t *start_index, uint8_t *diversifier_ptr, uint8_t *pkd); void get_diversifier_list(const uint8_t *sk_ptr, uint8_t *diversifier_list); -void get_diversifier_fromlist(const uint8_t *diversifier_list, - uint8_t *diversifier); +void get_diversifier_fromlist(const uint8_t *diversifier_list, uint8_t *diversifier); bool is_valid_diversifier(const uint8_t *diversifier); @@ -34,14 +31,11 @@ void get_default_diversifier_list_withstartindex(const uint8_t *seed_ptr, uint8_t *startindex, uint8_t *diversifier_list); -void get_default_diversifier_without_start_index(const uint8_t *see_ptr, - uint32_t pos, - uint8_t *default_diversifier); +void get_default_diversifier_without_start_index(const uint8_t *see_ptr, uint32_t pos, uint8_t *default_diversifier); void zip32_master(const uint8_t *seed_ptr, uint8_t *sk_ptr, uint8_t *dk_ptr); -void zip32_child_ask_nsk(const uint8_t *seed_ptr, uint8_t *ask, uint8_t *nsk, - const uint32_t pos); +void zip32_child_ask_nsk(const uint8_t *seed_ptr, uint8_t *ask, uint8_t *nsk, const uint32_t pos); void zip32_nsk_from_seed(const uint8_t *seed_ptr, uint8_t *nsk); @@ -51,46 +45,35 @@ void zip32_ovk(const uint8_t *seed_ptr, uint8_t *ovk, uint32_t pos); void zip32_fvk(const uint8_t *seed_ptr, uint8_t *fvk, uint32_t pos); -void zip32_child_proof_key(const uint8_t *seed_ptr, uint8_t *ak_ptr, - uint8_t *nsk_ptr, uint32_t pos); +void zip32_child_proof_key(const uint8_t *seed_ptr, uint8_t *ak_ptr, uint8_t *nsk_ptr, uint32_t pos); // Rseed -void rseed_get_esk_epk(const uint8_t *seed_ptr, uint8_t *d_ptr, - uint8_t *output_esk_ptr, uint8_t *output_epk_ptr); +void rseed_get_esk_epk(const uint8_t *seed_ptr, uint8_t *d_ptr, uint8_t *output_esk_ptr, uint8_t *output_epk_ptr); void rseed_get_rcm(const uint8_t *input, uint8_t *output_ptr); // Commitments -void compute_note_commitment(uint8_t *inputptr, const uint8_t *rcmptr, - uint64_t value, - const uint8_t *diversifier_ptr, - const uint8_t *pkd); +void compute_note_commitment( + uint8_t *inputptr, const uint8_t *rcmptr, uint64_t value, const uint8_t *diversifier_ptr, const uint8_t *pkd); -void compute_note_commitment_fullpoint(uint8_t *inputptr, const uint8_t *rcmptr, - uint64_t value, - const uint8_t *diversifier_ptr, - const uint8_t *pkd); +void compute_note_commitment_fullpoint( + uint8_t *inputptr, const uint8_t *rcmptr, uint64_t value, const uint8_t *diversifier_ptr, const uint8_t *pkd); -void compute_value_commitment(const uint64_t value, const uint8_t *rcmptr, - uint8_t *output); +void compute_value_commitment(const uint64_t value, const uint8_t *rcmptr, uint8_t *output); -void compute_nullifier(uint8_t *ncmptr, uint64_t pos, const uint8_t *nsk_ptr, - uint8_t *outputptr); +void compute_nullifier(uint8_t *ncmptr, uint64_t pos, const uint8_t *nsk_ptr, uint8_t *outputptr); // Note encryption void blake2b_prf(uint8_t *inputptr, uint8_t *outptr); -void ka_to_key(uint8_t *esk_ptr, uint8_t *pkd_ptr, uint8_t *epk_ptr, - uint8_t *output_ptr); +void ka_to_key(uint8_t *esk_ptr, uint8_t *pkd_ptr, uint8_t *epk_ptr, uint8_t *output_ptr); -void prepare_enccompact_input(uint8_t *d, uint64_t value, uint8_t *rcm, - uint8_t memotype, uint8_t *output); +void prepare_enccompact_input(uint8_t *d, uint64_t value, uint8_t *rcm, uint8_t memotype, uint8_t *output); // RedJubjub void random_fr(uint8_t *alpha_ptr); -void randomized_secret_from_seed(uint8_t *seed_ptr, uint32_t pos, - uint8_t *alpha_ptr, uint8_t *output_ptr); +void randomized_secret_from_seed(uint8_t *seed_ptr, uint32_t pos, uint8_t *alpha_ptr, uint8_t *output_ptr); void get_rk(uint8_t *ask_ptr, uint8_t *alpha_ptr, uint8_t *output_ptr); void rsk_to_rk(const uint8_t *rsk_ptr, uint8_t *rk_ptr); @@ -100,7 +83,6 @@ void randomize_pk(uint8_t *alpha_ptr, uint8_t *pk_ptr); void sign_redjubjub(uint8_t *key_ptr, uint8_t *msg_ptr, uint8_t *out_ptr); // Session key -void sessionkey_agree(uint8_t *scalar_ptr, uint8_t *point_ptr, - uint8_t *output_ptr); +void sessionkey_agree(uint8_t *scalar_ptr, uint8_t *point_ptr, uint8_t *output_ptr); void pubkey_gen(uint8_t *scalar_ptr, uint8_t *output_ptr); diff --git a/app/rust/src/commitments.rs b/app/rust/src/commitments.rs index 9fcdffc9..b5d8d8c9 100644 --- a/app/rust/src/commitments.rs +++ b/app/rust/src/commitments.rs @@ -6,7 +6,7 @@ use crate::bolos::c_zemu_log_stack; use crate::pedersen::*; use crate::redjubjub::*; use crate::zeccrypto::prf_ock; -use crate::zip32::{group_hash_from_div, nsk_to_nk,zip32_nsk_from_seed}; +use crate::zip32::{group_hash_from_div, nsk_to_nk, zip32_nsk_from_seed}; pub const PEDERSEN_RANDOMNESS_BASE: AffineNielsPoint = AffinePoint::from_raw_unchecked( Fq::from_raw([ @@ -180,15 +180,14 @@ pub fn prepare_and_hash_input_commitment( g_d_ptr: *const [u8; 32], pkd_ptr: *const [u8; 32], output_ptr: *mut [u8; 32], -) { +) { let gd = unsafe { &*g_d_ptr }; let pkd = unsafe { &*pkd_ptr }; - let mut prepared_msg = [0u8; 73]; + let mut prepared_msg = [0u8; 73]; let mut input_hash = [0u8; 73]; let output_msg = unsafe { &mut *output_ptr }; - let vbytes = write_u64_tobytes(value); input_hash[0..8].copy_from_slice(&vbytes); @@ -282,12 +281,13 @@ pub extern "C" fn compute_nullifier( } #[no_mangle] -pub extern "C" fn compute_note_commitment(input_ptr: *mut [u8; 32], - rcm_ptr: *const [u8; 32], - value: u64, - diversifier_ptr: *const [u8; 11], - pkd_ptr: *const [u8; 32]) { - +pub extern "C" fn compute_note_commitment( + input_ptr: *mut [u8; 32], + rcm_ptr: *const [u8; 32], + value: u64, + diversifier_ptr: *const [u8; 11], + pkd_ptr: *const [u8; 32], +) { let mut gd = [0u8; 32]; let diversifier = unsafe { &*diversifier_ptr }; group_hash_from_div(diversifier, &mut gd); @@ -303,14 +303,14 @@ pub extern "C" fn compute_note_commitment(input_ptr: *mut [u8; 32], out.copy_from_slice(&extended_to_u_bytes(&e)); } - #[no_mangle] pub extern "C" fn compute_note_commitment_fullpoint( input_ptr: *mut [u8; 32], rcm_ptr: *const [u8; 32], value: u64, diversifier_ptr: *const [u8; 11], - pkd_ptr: *const [u8; 32]) { + pkd_ptr: *const [u8; 32], +) { let mut gd = [0u8; 32]; let diversifier = unsafe { &*diversifier_ptr }; @@ -333,7 +333,6 @@ pub extern "C" fn compute_value_commitment( rcm_ptr: *const [u8; 32], output_ptr: *mut [u8; 32], ) { - let rc = unsafe { &*rcm_ptr }; let output_msg = unsafe { &mut *output_ptr }; @@ -366,7 +365,7 @@ mod tests { let rcm = [0u8; 32]; let output = [0u8; 32]; - let div = &div_ptr ; + let div = &div_ptr; group_hash_from_div(div, &mut gd); @@ -382,14 +381,14 @@ mod tests { rcm.as_ptr() as *const [u8; 32], v, div.as_ptr() as *const [u8; 11], - pkd.as_ptr() as *const [u8; 32] + pkd.as_ptr() as *const [u8; 32], ); assert_eq!( output, [ - 51, 107, 65, 49, 174, 10, 181, 105, 255, 123, 174, 149, 217, 191, 95, - 76, 7, 90, 151, 132, 85, 143, 180, 30, 26, 35, 160, 160, 197, 140, 21, 95 + 51, 107, 65, 49, 174, 10, 181, 105, 255, 123, 174, 149, 217, 191, 95, 76, 7, 90, + 151, 132, 85, 143, 180, 30, 26, 35, 160, 160, 197, 140, 21, 95 ] ); } @@ -512,26 +511,27 @@ mod tests { let pos: u64 = 2578461368; let seed: [u8; 32] = [ - 176,142,61,152,218,67,28,239,69,102,161,60,27,179,72,185, - 130,247,216,231,67,180,59,182,37,87,186,81,153,75,18,87, + 176, 142, 61, 152, 218, 67, 28, 239, 69, 102, 161, 60, 27, 179, 72, 185, 130, 247, 216, + 231, 67, 180, 59, 182, 37, 87, 186, 81, 153, 75, 18, 87, ]; let cm: [u8; 32] = [ 0x21, 0xc9, 0x46, 0x98, 0xca, 0x32, 0x4b, 0x4c, 0xba, 0xce, 0x29, 0x1d, 0x27, 0xab, 0xb6, 0x8a, 0xa, 0xaf, 0x27, 0x37, 0xdc, 0x45, 0x56, 0x54, 0x1c, 0x7f, 0xcd, 0xe8, - 0xce, 0x11, 0xdd, 0xe8]; + 0xce, 0x11, 0xdd, 0xe8, + ]; let mut nsk = [0u8; 32]; - zip32_nsk_from_seed(&seed,&mut nsk); + zip32_nsk_from_seed(&seed, &mut nsk); let mut nf = [0u8; 32]; - compute_nullifier(&cm, pos, &nsk,&mut nf); - + compute_nullifier(&cm, pos, &nsk, &mut nf); let nftest: [u8; 32] = [ - 0x25,0xf1,0xf2,0xcf,0x5e,0x2c,0x2b,0xc3,0x1d,0x7,0xb6,0x6f, - 0x4d,0x54,0xf0,0x90,0xad,0x89,0xb1,0x98,0x89,0x3f,0x12,0xad, - 0xae,0x44,0x7d,0xdf,0x84,0xe2,0x14,0x5a]; + 0x25, 0xf1, 0xf2, 0xcf, 0x5e, 0x2c, 0x2b, 0xc3, 0x1d, 0x7, 0xb6, 0x6f, 0x4d, 0x54, + 0xf0, 0x90, 0xad, 0x89, 0xb1, 0x98, 0x89, 0x3f, 0x12, 0xad, 0xae, 0x44, 0x7d, 0xdf, + 0x84, 0xe2, 0x14, 0x5a, + ]; assert_eq!(nf, nftest); } diff --git a/app/rust/src/constants.rs b/app/rust/src/constants.rs index ab08772a..3f653e3c 100644 --- a/app/rust/src/constants.rs +++ b/app/rust/src/constants.rs @@ -67,12 +67,12 @@ pub const ENC_COMPACT_SIZE: usize = COMPACT_NOTE_SIZE + 16; pub const ENC_CIPHERTEXT_SIZE: usize = NOTE_PLAINTEXT_SIZE + 16; pub const OUT_CIPHERTEXT_SIZE: usize = OUT_PLAINTEXT_SIZE + 16; -pub const DIV_SIZE: usize = 11; +pub const DIV_SIZE: usize = 11; pub const DIV_DEFAULT_LIST_LEN: usize = 4; -pub const MAX_SIZE_BUF_ADDR: usize = 143; +pub const MAX_SIZE_BUF_ADDR: usize = 143; -pub const FIRSTVALUE: u32 = 32 ^ 0x8000_0000; -pub const COIN_TYPE: u32 = 133 ^ 0x8000_0000; +pub const FIRSTVALUE: u32 = 32 ^ 0x8000_0000; +pub const COIN_TYPE: u32 = 133 ^ 0x8000_0000; pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk"; diff --git a/app/rust/src/zip32.rs b/app/rust/src/zip32.rs index c77e3058..4b190da6 100644 --- a/app/rust/src/zip32.rs +++ b/app/rust/src/zip32.rs @@ -14,17 +14,13 @@ use core::mem; use jubjub::{AffinePoint, ExtendedPoint, Fr}; use crate::commitments::bytes_to_extended; -use crate::constants::{AK_NK, AK_NSK, ASK_NSK, - COIN_TYPE, - CRH_IVK_PERSONALIZATION, - DIV_SIZE, DIV_DEFAULT_LIST_LEN, - DK,DK_AK_NK, - FIRSTVALUE, - PROVING_KEY_BASE}; +use crate::constants::{ + AK_NK, AK_NSK, ASK_NSK, COIN_TYPE, CRH_IVK_PERSONALIZATION, DIV_DEFAULT_LIST_LEN, DIV_SIZE, DK, + DK_AK_NK, FIRSTVALUE, PROVING_KEY_BASE, +}; use crate::pedersen::extended_to_bytes; use crate::{bolos, c_check_app_canary, constants}; - extern "C" { fn zemu_log_stack(buffer: *const u8); } @@ -471,7 +467,7 @@ pub fn derive_zip32_fvk_fromseedandpath(seed: &[u8; 32], path: &[u32]) -> [u8; 9 let mut expkey: [u8; 96]; crate::heart_beat(); expkey = expandedspendingkey_zip32(&key); //96 - //master divkey + //master divkey let mut divkey = [0u8; 32]; divkey.copy_from_slice(&diversifier_key_zip32(&key)); //32 for &p in path { @@ -523,7 +519,6 @@ pub fn derive_zip32_fvk_fromseedandpath(seed: &[u8; 32], path: &[u32]) -> [u8; 9 #[inline(never)] pub fn master_nsk_from_seed(seed: &[u8; 32]) -> [u8; 32] { - let tmp = master_spending_key_zip32(seed); //64 let mut key = [0u8; 32]; //32 @@ -536,7 +531,11 @@ pub fn master_nsk_from_seed(seed: &[u8; 32]) -> [u8; 32] { } #[inline(never)] -pub fn derive_zip32_child_fromseedandpath(seed: &[u8; 32], path: &[u32], child_components: u8) -> [u8; 96] { +pub fn derive_zip32_child_fromseedandpath( + seed: &[u8; 32], + path: &[u32], + child_components: u8, +) -> [u8; 96] { //ASSERT: len(path) == len(harden) c_zemu_log_stack(b"derive_zip32_child\x00\n".as_ref()); let mut tmp = master_spending_key_zip32(seed); //64 @@ -595,10 +594,10 @@ pub fn derive_zip32_child_fromseedandpath(seed: &[u8; 32], path: &[u32], child_c // Get nk from nsk = k[64..96] let nk_tmp = PROVING_KEY_BASE.multiply_bits(&nsk.to_bytes()); - let nk = AffinePoint::from(nk_tmp);//.to_bytes(); + let nk = AffinePoint::from(nk_tmp); //.to_bytes(); let mut result = [0u8; 96]; - match child_components{ + match child_components { AK_NK => { result[0..32].copy_from_slice(&ak); result[32..64].copy_from_slice(&nk.to_bytes()); @@ -636,25 +635,18 @@ pub fn group_hash_from_div(diversifier_ptr: *const [u8; 11], gd_ptr: *mut [u8; 3 } #[no_mangle] -pub fn get_dk( - seed_ptr: *const [u8; 32], - dk_ptr: *mut [u8; 32], - pos: u32, -) { +pub fn get_dk(seed_ptr: *const [u8; 32], dk_ptr: *mut [u8; 32], pos: u32) { let seed = unsafe { &*seed_ptr }; let dk = unsafe { &mut *dk_ptr }; const FIRSTVALUE: u32 = 32 ^ 0x8000_0000; const COIN_TYPE: u32 = 133 ^ 0x8000_0000; //hardened, fixed value from https://github.com/adityapk00/librustzcash/blob/master/zcash_client_backend/src/constants/mainnet.rs - let k = derive_zip32_child_fromseedandpath(seed, - &[FIRSTVALUE, COIN_TYPE, pos], - DK); //consistent with zecwallet + let k = derive_zip32_child_fromseedandpath(seed, &[FIRSTVALUE, COIN_TYPE, pos], DK); //consistent with zecwallet // k = dk || ... dk.copy_from_slice(&k[0..32]); } - #[inline(never)] pub fn nsk_to_nk(nsk_ptr: *const [u8; 32], nk_ptr: *mut [u8; 32]) { let nsk = unsafe { &*nsk_ptr }; @@ -664,27 +656,23 @@ pub fn nsk_to_nk(nsk_ptr: *const [u8; 32], nk_ptr: *mut [u8; 32]) { } #[no_mangle] -pub extern "C" fn zip32_ivk( - seed_ptr: *const [u8; 32], - ivk_ptr: *mut [u8; 32], - pos: u32, -) { +pub extern "C" fn zip32_ivk(seed_ptr: *const [u8; 32], ivk_ptr: *mut [u8; 32], pos: u32) { c_zemu_log_stack(b"zip32_ivk\x00\n".as_ref()); let seed = unsafe { &*seed_ptr }; let ivk = unsafe { &mut *ivk_ptr }; crate::heart_beat(); - let k = derive_zip32_child_fromseedandpath(seed, - &[FIRSTVALUE, COIN_TYPE, pos], - AK_NK); //consistent with zecwallet + let k = derive_zip32_child_fromseedandpath(seed, &[FIRSTVALUE, COIN_TYPE, pos], AK_NK); //consistent with zecwallet // k = ak || nk // ak = k[0..32] // nk = k[32..64] - let tmp_ivk = aknk_to_ivk(&k[0..32].try_into().unwrap(), - &k[32..64].try_into().unwrap()); + let tmp_ivk = aknk_to_ivk( + &k[0..32].try_into().unwrap(), + &k[32..64].try_into().unwrap(), + ); ivk.copy_from_slice(&tmp_ivk) } @@ -692,29 +680,35 @@ pub extern "C" fn zip32_ivk( pub extern "C" fn get_default_diversifier_without_start_index( seed_ptr: *const [u8; 32], pos: u32, - diversifier_ptr: *mut [u8; 11]) -{ + diversifier_ptr: *mut [u8; 11], +) { c_zemu_log_stack(b"get_pkd_from_seed\x00\n".as_ref()); let seed = unsafe { &*seed_ptr }; - let mut start = [0u8;11]; - let div = unsafe {&mut *diversifier_ptr}; + let mut start = [0u8; 11]; + let div = unsafe { &mut *diversifier_ptr }; - let mut div_list = [0u8;DIV_SIZE*DIV_DEFAULT_LIST_LEN]; + let mut div_list = [0u8; DIV_SIZE * DIV_DEFAULT_LIST_LEN]; - let dk = derive_zip32_child_fromseedandpath(&seed, - &[FIRSTVALUE, COIN_TYPE, pos], - DK_AK_NK); + let dk = derive_zip32_child_fromseedandpath(&seed, &[FIRSTVALUE, COIN_TYPE, pos], DK_AK_NK); let mut found = false; while !found { - ff1aes_list_with_startingindex_default(&dk[0..32].try_into().unwrap(), - &mut start, &mut div_list); + ff1aes_list_with_startingindex_default( + &dk[0..32].try_into().unwrap(), + &mut start, + &mut div_list, + ); for i in 0..DIV_DEFAULT_LIST_LEN { - if !found && is_valid_diversifier( - &div_list[i*DIV_SIZE..(i+1)*DIV_SIZE].try_into().unwrap()) { - found = true; - div.copy_from_slice(&div_list[i*DIV_SIZE..(i+1)*DIV_SIZE]); + if !found + && is_valid_diversifier( + &div_list[i * DIV_SIZE..(i + 1) * DIV_SIZE] + .try_into() + .unwrap(), + ) + { + found = true; + div.copy_from_slice(&div_list[i * DIV_SIZE..(i + 1) * DIV_SIZE]); } } crate::heart_beat(); @@ -751,11 +745,7 @@ pub extern "C" fn zip32_ovk(seed_ptr: *const [u8; 32], ovk_ptr: *mut [u8; 32], p //this function is consistent with zecwallet code #[no_mangle] -pub extern "C" fn zip32_fvk( - seed_ptr: *const [u8; 32], - fvk_ptr: *mut [u8; 96], - pos: u32, -){ +pub extern "C" fn zip32_fvk(seed_ptr: *const [u8; 32], fvk_ptr: *mut [u8; 96], pos: u32) { c_zemu_log_stack(b"zip32_fvk\x00\n".as_ref()); let seed = unsafe { &*seed_ptr }; @@ -767,7 +757,6 @@ pub extern "C" fn zip32_fvk( fvk.copy_from_slice(&k[0..96]); } - #[no_mangle] pub extern "C" fn zip32_child_proof_key( seed_ptr: *const [u8; 32], @@ -781,9 +770,7 @@ pub extern "C" fn zip32_child_proof_key( const FIRSTVALUE: u32 = 32 ^ 0x8000_0000; const COIN_TYPE: u32 = 133 ^ 0x8000_0000; //hardened, fixed value from https://github.com/adityapk00/librustzcash/blob/master/zcash_client_backend/src/constants/mainnet.rs - let k = derive_zip32_child_fromseedandpath(seed, - &[FIRSTVALUE, COIN_TYPE, pos], - AK_NSK); //consistent with zecwallet + let k = derive_zip32_child_fromseedandpath(seed, &[FIRSTVALUE, COIN_TYPE, pos], AK_NSK); //consistent with zecwallet // k = ak || nsk ak.copy_from_slice(&k[0..32]); @@ -801,18 +788,13 @@ pub extern "C" fn zip32_child_ask_nsk( let ask = unsafe { &mut *ask_ptr }; let nsk = unsafe { &mut *nsk_ptr }; - let k = derive_zip32_child_fromseedandpath(seed, - &[FIRSTVALUE, COIN_TYPE, pos], - ASK_NSK); //consistent with zecwallet; + let k = derive_zip32_child_fromseedandpath(seed, &[FIRSTVALUE, COIN_TYPE, pos], ASK_NSK); //consistent with zecwallet; ask.copy_from_slice(&k[0..32]); nsk.copy_from_slice(&k[32..64]); } #[no_mangle] -pub extern "C" fn zip32_nsk_from_seed( - seed_ptr: *const [u8; 32], - nsk_ptr: *mut [u8; 32], -) { +pub extern "C" fn zip32_nsk_from_seed(seed_ptr: *const [u8; 32], nsk_ptr: *mut [u8; 32]) { let seed = unsafe { &*seed_ptr }; let nsk = unsafe { &mut *nsk_ptr }; @@ -838,11 +820,11 @@ pub extern "C" fn get_diversifier_list_withstartindex( start_index: *const [u8; 11], diversifier_list_ptr: *mut [u8; 220], ) { - let mut dk = [0u8; 32]; + let mut dk = [0u8; 32]; let seed = unsafe { &*seed_ptr }; let start = unsafe { &*start_index }; let diversifier = unsafe { &mut *diversifier_list_ptr }; - get_dk(seed,&mut dk,pos); + get_dk(seed, &mut dk, pos); ff1aes_list_with_startingindex(&mut dk, start, diversifier); } @@ -854,11 +836,11 @@ pub extern "C" fn get_default_diversifier_list_withstartindex( diversifier_list_ptr: *mut [u8; 44], ) { c_zemu_log_stack(b"get_default_divlist_withstartidx\x00\n".as_ref()); - let mut dk = [0u8; 32]; + let mut dk = [0u8; 32]; let seed = unsafe { &*seed_ptr }; let start = unsafe { &mut *start_index }; let diversifier = unsafe { &mut *diversifier_list_ptr }; - get_dk(seed,&mut dk,pos); + get_dk(seed, &mut dk, pos); ff1aes_list_with_startingindex_default(&mut dk, start, diversifier); } @@ -868,46 +850,50 @@ pub extern "C" fn get_pkd_from_seed( pos: u32, start_index: *mut [u8; 11], diversifier_ptr: *mut [u8; 11], - pkd_ptr: *mut [u8; 32]) -{ + pkd_ptr: *mut [u8; 32], +) { c_zemu_log_stack(b"get_pkd_from_seed\x00\n".as_ref()); let seed = unsafe { &*seed_ptr }; let start = unsafe { &mut *start_index }; - let div = unsafe {&mut *diversifier_ptr}; + let div = unsafe { &mut *diversifier_ptr }; - let mut div_list = [0u8;DIV_SIZE*DIV_DEFAULT_LIST_LEN]; + let mut div_list = [0u8; DIV_SIZE * DIV_DEFAULT_LIST_LEN]; crate::heart_beat(); - let dk_ak_nk = derive_zip32_child_fromseedandpath(&seed, - &[FIRSTVALUE, - COIN_TYPE, pos], - DK_AK_NK); + let dk_ak_nk = + derive_zip32_child_fromseedandpath(&seed, &[FIRSTVALUE, COIN_TYPE, pos], DK_AK_NK); let mut found = false; while !found { - ff1aes_list_with_startingindex_default(&mut dk_ak_nk[0..32].try_into().unwrap(), - start, &mut div_list); - for i in 0..DIV_DEFAULT_LIST_LEN - { - if !found && is_valid_diversifier( - &div_list[i*DIV_SIZE..(i+1)*DIV_SIZE].try_into().unwrap()) + ff1aes_list_with_startingindex_default( + &mut dk_ak_nk[0..32].try_into().unwrap(), + start, + &mut div_list, + ); + for i in 0..DIV_DEFAULT_LIST_LEN { + if !found + && is_valid_diversifier( + &div_list[i * DIV_SIZE..(i + 1) * DIV_SIZE] + .try_into() + .unwrap(), + ) { found = true; - div.copy_from_slice(&div_list[i*DIV_SIZE..(i+1)*DIV_SIZE]); + div.copy_from_slice(&div_list[i * DIV_SIZE..(i + 1) * DIV_SIZE]); } } crate::heart_beat(); } - let ivk = aknk_to_ivk(&dk_ak_nk[32..64].try_into().unwrap(), - &dk_ak_nk[64..96].try_into().unwrap()); + let ivk = aknk_to_ivk( + &dk_ak_nk[32..64].try_into().unwrap(), + &dk_ak_nk[64..96].try_into().unwrap(), + ); let pkd = unsafe { &mut *pkd_ptr }; let tmp_pkd = default_pkd(&ivk, div); pkd.copy_from_slice(&tmp_pkd); } - - #[no_mangle] pub extern "C" fn is_valid_diversifier(div_ptr: *const [u8; 11]) -> bool { let div = unsafe { &*div_ptr }; @@ -934,10 +920,10 @@ pub extern "C" fn get_pkd( pkd_ptr: *mut [u8; 32], ) { c_zemu_log_stack(b"get_pkd\x00\n".as_ref()); - let ivk_ptr = &mut [0u8;32]; + let ivk_ptr = &mut [0u8; 32]; let diversifier = unsafe { &*diversifier_ptr }; let pkd = unsafe { &mut *pkd_ptr }; - zip32_ivk(seed_ptr,ivk_ptr, pos); + zip32_ivk(seed_ptr, ivk_ptr, pos); let tmp_pkd = default_pkd(ivk_ptr, &diversifier); pkd.copy_from_slice(&tmp_pkd) @@ -979,16 +965,13 @@ mod tests { assert_eq!(keys[0..32], dk); } - #[test] fn test_zip32_childaddress() { let seed = [0u8; 32]; let p: u32 = 0x8000_0001; - let dk_ak_nk = derive_zip32_child_fromseedandpath(&seed, &[p], - DK_AK_NK); - let ask_nsk = derive_zip32_child_fromseedandpath(&seed, &[p], - ASK_NSK); + let dk_ak_nk = derive_zip32_child_fromseedandpath(&seed, &[p], DK_AK_NK); + let ask_nsk = derive_zip32_child_fromseedandpath(&seed, &[p], ASK_NSK); let mut dk = [0u8; 32]; dk.copy_from_slice(&dk_ak_nk[0..32]); @@ -1004,8 +987,6 @@ mod tests { let mut nsk = [0u8; 32]; nsk.copy_from_slice(&ask_nsk[32..64]); - - let ask_test: [u8; 32] = [ 0x66, 0x5e, 0xd6, 0xf7, 0xb7, 0x93, 0xaf, 0xa1, 0x82, 0x21, 0xe1, 0x57, 0xba, 0xd5, 0x43, 0x3c, 0x54, 0x23, 0xf4, 0xfe, 0xc9, 0x46, 0xe0, 0x8e, 0xd6, 0x30, 0xa0, 0xc6, @@ -1049,7 +1030,6 @@ mod tests { ); } - #[test] fn test_zip32_childaddress_ledgerkey() { //e91db3f6c120a86ece0de8d21d452dcdcb708d563494e60a6cee676f5047ded7 @@ -1062,10 +1042,8 @@ mod tests { let p: u32 = 1000 | 0x8000_0000; - let dk_ak_nk = derive_zip32_child_fromseedandpath(&seed, &[p], - DK_AK_NK); - let ask_nsk = derive_zip32_child_fromseedandpath(&seed, &[p], - ASK_NSK); + let dk_ak_nk = derive_zip32_child_fromseedandpath(&seed, &[p], DK_AK_NK); + let ask_nsk = derive_zip32_child_fromseedandpath(&seed, &[p], ASK_NSK); let mut dk = [0u8; 32]; dk.copy_from_slice(&dk_ak_nk[0..32]); @@ -1081,7 +1059,6 @@ mod tests { let mut nsk = [0u8; 32]; nsk.copy_from_slice(&ask_nsk[32..64]); - let ivk = aknk_to_ivk(&ak_derived, &nk_derived); let mut ivk_ledger = [0u8; 32]; @@ -1089,7 +1066,7 @@ mod tests { "2ed10dec7ea979feeddc9bf6e6368f4036706c2e3a82838d65bb4f070253bc01", &mut ivk_ledger, ) - .expect("dec"); + .expect("dec"); assert_eq!(ivk, ivk_ledger); let mut list = [0u8; 110]; @@ -1104,9 +1081,10 @@ mod tests { ); assert_eq!( pk_d, - [109, 255, 96, 20, 93, 103, 87, 237, 184, 196, 67, - 152, 20, 153, 76, 170, 233, 83, 16, 159, 77, 168, - 66, 205, 173, 118, 107, 251, 202, 197, 255, 27] + [ + 109, 255, 96, 20, 93, 103, 87, 237, 184, 196, 67, 152, 20, 153, 76, 170, 233, 83, + 16, 159, 77, 168, 66, 205, 173, 118, 107, 251, 202, 197, 255, 27 + ] ); } diff --git a/app/src/addr.c b/app/src/addr.c index 552061c0..c14576c1 100644 --- a/app/src/addr.c +++ b/app/src/addr.c @@ -14,6 +14,8 @@ * limitations under the License. ********************************************************************************/ +#include + #include "actions.h" #include "app_mode.h" #include "coin.h" @@ -21,61 +23,61 @@ #include "zxerror.h" #include "zxformat.h" #include "zxmacros.h" -#include zxerr_t addr_getNumItems(uint8_t *num_items) { - zemu_log_stack("addr_getNumItems"); - *num_items = 1; - if (app_mode_expert()) { - *num_items = 2; - } - return zxerr_ok; + zemu_log_stack("addr_getNumItems"); + *num_items = 1; + if (app_mode_expert()) { + *num_items = 2; + } + return zxerr_ok; } -zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, uint8_t pageIdx, +zxerr_t addr_getItem(int8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outVal, + uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { - ZEMU_LOGF(200, "[addr_getItem] %d/%d\n", displayIdx, pageIdx) + ZEMU_LOGF(200, "[addr_getItem] %d/%d\n", displayIdx, pageIdx) - switch (displayIdx) { - case 0: - switch (action_addrResponse.kind) { - case addr_secp256k1: - snprintf(outKey, outKeyLen, "Unshielded"); - pageString(outVal, outValLen, - (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1), - pageIdx, pageCount); - return zxerr_ok; + switch (displayIdx) { + case 0: + switch (action_addrResponse.kind) { + case addr_secp256k1: + snprintf(outKey, outKeyLen, "Unshielded"); + pageString(outVal, outValLen, (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SECP256K1), pageIdx, + pageCount); + return zxerr_ok; - case addr_sapling: - snprintf(outKey, outKeyLen, "Shielded"); - pageString(outVal, outValLen, - (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SAPLING), - pageIdx, pageCount); - return zxerr_ok; + case addr_sapling: + snprintf(outKey, outKeyLen, "Shielded"); + pageString(outVal, outValLen, (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SAPLING), pageIdx, + pageCount); + return zxerr_ok; - case addr_sapling_div: - snprintf(outKey, outKeyLen, "Shielded with div"); - pageString(outVal, outValLen, - (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SAPLING), - pageIdx, pageCount); - return zxerr_ok; + case addr_sapling_div: + snprintf(outKey, outKeyLen, "Shielded with div"); + pageString(outVal, outValLen, (char *)(G_io_apdu_buffer + VIEW_ADDRESS_OFFSET_SAPLING), pageIdx, + pageCount); + return zxerr_ok; - default: - return zxerr_no_data; - } - case 1: { - if (!app_mode_expert()) { - return zxerr_no_data; - } + default: + return zxerr_no_data; + } + case 1: { + if (!app_mode_expert()) { + return zxerr_no_data; + } - snprintf(outKey, outKeyLen, "Your Path"); - char buffer[300]; - bip32_to_str(buffer, sizeof(buffer), hdPath, HDPATH_LEN_DEFAULT); - pageString(outVal, outValLen, buffer, pageIdx, pageCount); - return zxerr_ok; - } - default: - return zxerr_no_data; - } + snprintf(outKey, outKeyLen, "Your Path"); + char buffer[300]; + bip32_to_str(buffer, sizeof(buffer), hdPath, HDPATH_LEN_DEFAULT); + pageString(outVal, outValLen, buffer, pageIdx, pageCount); + return zxerr_ok; + } + default: + return zxerr_no_data; + } } diff --git a/app/src/addr.h b/app/src/addr.h index 51df2a33..df747cc8 100644 --- a/app/src/addr.h +++ b/app/src/addr.h @@ -21,14 +21,19 @@ extern "C" { #endif #include + #include "zxerror.h" /// Return the number of items in the address view zxerr_t addr_getNumItems(uint8_t *num_items); /// Gets an specific item from the address view (including paging) -zxerr_t addr_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, uint8_t pageIdx, +zxerr_t addr_getItem(int8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outValue, + uint16_t outValueLen, + uint8_t pageIdx, uint8_t *pageCount); #ifdef __cplusplus diff --git a/app/src/apdu_handler.c b/app/src/apdu_handler.c index d8cb10c8..dccb27ce 100644 --- a/app/src/apdu_handler.c +++ b/app/src/apdu_handler.c @@ -15,8 +15,6 @@ * limitations under the License. ********************************************************************************/ -#include "app_main.h" - #include #include #include @@ -24,212 +22,199 @@ #include "actions.h" #include "addr.h" +#include "apdu_errors.h" +#include "app_main.h" #include "app_mode.h" #include "coin.h" #include "crypto.h" -#include "tx.h" -#include "view.h" -#include "apdu_errors.h" -#include "zxmacros.h" - #include "key.h" #include "nvdata.h" #include "parser.h" - +#include "tx.h" +#include "view.h" #include "view_internal.h" +#include "zxmacros.h" __Z_INLINE void handle_getversion(volatile uint32_t *tx) { #ifdef DEBUG - G_io_apdu_buffer[0] = 0xFF; + G_io_apdu_buffer[0] = 0xFF; #else - G_io_apdu_buffer[0] = 0; + G_io_apdu_buffer[0] = 0; #endif - G_io_apdu_buffer[1] = LEDGER_MAJOR_VERSION; - G_io_apdu_buffer[2] = LEDGER_MINOR_VERSION; - G_io_apdu_buffer[3] = LEDGER_PATCH_VERSION; - // SDK won't reply any APDU message if the device is locked --> Set - // device_locked = false - G_io_apdu_buffer[4] = 0; - - G_io_apdu_buffer[5] = (TARGET_ID >> 24) & 0xFF; - G_io_apdu_buffer[6] = (TARGET_ID >> 16) & 0xFF; - G_io_apdu_buffer[7] = (TARGET_ID >> 8) & 0xFF; - G_io_apdu_buffer[8] = (TARGET_ID >> 0) & 0xFF; - - *tx += 9; - THROW(APDU_CODE_OK); + G_io_apdu_buffer[1] = LEDGER_MAJOR_VERSION; + G_io_apdu_buffer[2] = LEDGER_MINOR_VERSION; + G_io_apdu_buffer[3] = LEDGER_PATCH_VERSION; + // SDK won't reply any APDU message if the device is locked --> Set + // device_locked = false + G_io_apdu_buffer[4] = 0; + + G_io_apdu_buffer[5] = (TARGET_ID >> 24) & 0xFF; + G_io_apdu_buffer[6] = (TARGET_ID >> 16) & 0xFF; + G_io_apdu_buffer[7] = (TARGET_ID >> 8) & 0xFF; + G_io_apdu_buffer[8] = (TARGET_ID >> 0) & 0xFF; + + *tx += 9; + THROW(APDU_CODE_OK); } __Z_INLINE void extractHDPath(uint32_t rx, uint32_t offset) { - if ((rx - offset) < sizeof(uint32_t) * HDPATH_LEN_DEFAULT) { - THROW(APDU_CODE_WRONG_LENGTH); - } + if ((rx - offset) < sizeof(uint32_t) * HDPATH_LEN_DEFAULT) { + THROW(APDU_CODE_WRONG_LENGTH); + } - MEMCPY(hdPath, G_io_apdu_buffer + offset, - sizeof(uint32_t) * HDPATH_LEN_DEFAULT); + MEMCPY(hdPath, G_io_apdu_buffer + offset, sizeof(uint32_t) * HDPATH_LEN_DEFAULT); - const bool mainnet = - hdPath[0] == HDPATH_0_DEFAULT && hdPath[1] == HDPATH_1_DEFAULT; + const bool mainnet = hdPath[0] == HDPATH_0_DEFAULT && hdPath[1] == HDPATH_1_DEFAULT; - const bool testnet = - hdPath[0] == HDPATH_0_TESTNET && hdPath[1] == HDPATH_1_TESTNET; + const bool testnet = hdPath[0] == HDPATH_0_TESTNET && hdPath[1] == HDPATH_1_TESTNET; - if (!mainnet && !testnet) { - THROW(APDU_CODE_DATA_INVALID); - } + if (!mainnet && !testnet) { + THROW(APDU_CODE_DATA_INVALID); + } } __Z_INLINE bool process_chunk(__Z_UNUSED volatile uint32_t *tx, uint32_t rx) { - const uint8_t payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE]; - - if (rx < OFFSET_DATA) { - THROW(APDU_CODE_WRONG_LENGTH); - } - - uint32_t added; - switch (payloadType) { - case 0: - tx_initialize(); - tx_reset(); - return false; - case 1: - added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA); - if (added != rx - OFFSET_DATA) { - THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL); - } - return false; - case 2: - added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA); - if (added != rx - OFFSET_DATA) { - THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL); - } - return true; - } - THROW(APDU_CODE_INVALIDP1P2); -} + const uint8_t payloadType = G_io_apdu_buffer[OFFSET_PAYLOAD_TYPE]; -__Z_INLINE void handleExtractSpendSignature(volatile uint32_t *tx, - uint32_t rx) { - zemu_log("----[handleExtractSpendSignature]\n"); + if (rx < OFFSET_DATA) { + THROW(APDU_CODE_WRONG_LENGTH); + } - *tx = 0; - if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + uint32_t added; + switch (payloadType) { + case 0: + tx_initialize(); + tx_reset(); + return false; + case 1: + added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA); + if (added != rx - OFFSET_DATA) { + THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL); + } + return false; + case 2: + added = tx_append(&(G_io_apdu_buffer[OFFSET_DATA]), rx - OFFSET_DATA); + if (added != rx - OFFSET_DATA) { + THROW(APDU_CODE_OUTPUT_BUFFER_TOO_SMALL); + } + return true; + } + THROW(APDU_CODE_INVALIDP1P2); +} - zxerr_t err = - crypto_extract_spend_signature(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); +__Z_INLINE void handleExtractSpendSignature(volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleExtractSpendSignature]\n"); - if (err == zxerr_ok) { - *tx = 64; - THROW(APDU_CODE_OK); - } else { *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } -} + if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } -__Z_INLINE void handleExtractTransparentSignature(volatile uint32_t *tx, - uint32_t rx) { - zemu_log("----[handleExtractTransparentSignature]\n"); + zxerr_t err = crypto_extract_spend_signature(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); - *tx = 0; - if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + if (err == zxerr_ok) { + *tx = 64; + THROW(APDU_CODE_OK); + } else { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } +} - zxerr_t err = crypto_extract_transparent_signature(G_io_apdu_buffer, - IO_APDU_BUFFER_SIZE - 2); +__Z_INLINE void handleExtractTransparentSignature(volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleExtractTransparentSignature]\n"); - if (err == zxerr_ok) { - *tx = 64; - THROW(APDU_CODE_OK); - } else { - view_idle_show(0, NULL); *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } + if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + zxerr_t err = crypto_extract_transparent_signature(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + + if (err == zxerr_ok) { + *tx = 64; + THROW(APDU_CODE_OK); + } else { + view_idle_show(0, NULL); + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } } __Z_INLINE void handleExtractSpendData(volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleExtractSpendData]\n"); + zemu_log("----[handleExtractSpendData]\n"); - *tx = 0; - if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } - - zxerr_t err = crypto_extract_spend_proofkeyandrnd(G_io_apdu_buffer, - IO_APDU_BUFFER_SIZE - 2); - view_tx_state(); - if (err == zxerr_ok) { - *tx = 128; // SPEND_EXTRACT_LEN - THROW(APDU_CODE_OK); - } else { *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } + if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + zxerr_t err = crypto_extract_spend_proofkeyandrnd(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2); + view_tx_state(); + if (err == zxerr_ok) { + *tx = 128; // SPEND_EXTRACT_LEN + THROW(APDU_CODE_OK); + } else { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } } __Z_INLINE void handleExtractOutputData(volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleExtractOutputData]\n"); + zemu_log("----[handleExtractOutputData]\n"); - *tx = 0; - if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } - - uint16_t replyLen = 0; - zxerr_t err = crypto_extract_output_rnd(G_io_apdu_buffer, - IO_APDU_BUFFER_SIZE - 2, &replyLen); - view_tx_state(); - if (err == zxerr_ok) { - *tx = replyLen; - THROW(APDU_CODE_OK); - } else { *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } + if (rx != APDU_MIN_LENGTH || G_io_apdu_buffer[OFFSET_DATA_LEN] != 0) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + uint16_t replyLen = 0; + zxerr_t err = crypto_extract_output_rnd(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, &replyLen); + view_tx_state(); + if (err == zxerr_ok) { + *tx = replyLen; + THROW(APDU_CODE_OK); + } else { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } } -__Z_INLINE void handleInitTX(volatile uint32_t *flags, volatile uint32_t *tx, - uint32_t rx) { - if (!process_chunk(tx, rx)) { - THROW(APDU_CODE_OK); - } +__Z_INLINE void handleInitTX(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + if (!process_chunk(tx, rx)) { + THROW(APDU_CODE_OK); + } - zemu_log("----[handleInitTX]\n"); + zemu_log("----[handleInitTX]\n"); - *tx = 0; - const uint8_t *message = tx_get_buffer(); - const uint16_t messageLength = tx_get_buffer_length(); + *tx = 0; + const uint8_t *message = tx_get_buffer(); + const uint16_t messageLength = tx_get_buffer_length(); + + zxerr_t err = crypto_extracttx_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength); + if (err != zxerr_ok) { + transaction_reset(); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + G_io_apdu_buffer[0] = err; + *tx = 1; + THROW(APDU_CODE_EXTRACT_TRANSACTION_FAIL); + } - zxerr_t err = crypto_extracttx_sapling( - G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength); - if (err != zxerr_ok) { - transaction_reset(); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - G_io_apdu_buffer[0] = err; - *tx = 1; - THROW(APDU_CODE_EXTRACT_TRANSACTION_FAIL); - } - - err = crypto_hash_messagebuffer(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, messageLength); - if (err != zxerr_ok) { - transaction_reset(); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - G_io_apdu_buffer[0] = err; - *tx = 1; - THROW(APDU_CODE_HASH_MSG_BUF_FAIL); - } + err = crypto_hash_messagebuffer(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength); + if (err != zxerr_ok) { + transaction_reset(); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + G_io_apdu_buffer[0] = err; + *tx = 1; + THROW(APDU_CODE_HASH_MSG_BUF_FAIL); + } - //////////// + //////////// - view_review_init(tx_getItem, tx_getNumItems, app_reply_hash); + view_review_init(tx_getItem, tx_getNumItems, app_reply_hash); - view_review_show(REVIEW_TXN); - *flags |= IO_ASYNCH_REPLY; + view_review_show(REVIEW_TXN); + *flags |= IO_ASYNCH_REPLY; } // Transmitted notes are stored on the blockchain in encrypted form. @@ -237,624 +222,597 @@ __Z_INLINE void handleInitTX(volatile uint32_t *flags, volatile uint32_t *tx, // to decrypt the note (so that she can subsequently send it). // This function also returns the default diversifier to reduce interactions // between host and device -__Z_INLINE void handleGetKeyIVK(volatile uint32_t *flags, volatile uint32_t *tx, - uint32_t rx) { - zemu_log("----[handleGetKeyIVK]\n"); - - *tx = 0; - if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_IVK || - G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_IVK) { - zemu_log("Wrong length!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } +__Z_INLINE void handleGetKeyIVK(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetKeyIVK]\n"); - uint32_t zip32path = 0; - parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, - DATA_LENGTH_GET_IVK, &zip32path); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - if (prserr != parser_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.kind = key_ivk; - uint16_t replyLen = 0; - - zxerr_t err = crypto_ivk_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, - zip32path, &replyLen); - if (err != zxerr_ok) { *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.len = (uint8_t)replyLen; + if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_IVK || + G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_IVK) { + zemu_log("Wrong length!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + uint32_t zip32path = 0; + parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_IVK, &zip32path); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (prserr != parser_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.kind = key_ivk; + uint16_t replyLen = 0; - view_review_init(key_getItem, key_getNumItems, app_reply_key); - view_review_show(REVIEW_TXN); - *flags |= IO_ASYNCH_REPLY; + zxerr_t err = crypto_ivk_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, zip32path, &replyLen); + if (err != zxerr_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.len = (uint8_t)replyLen; + + view_review_init(key_getItem, key_getNumItems, app_reply_key); + view_review_show(REVIEW_TXN); + *flags |= IO_ASYNCH_REPLY; } // If Bob sends a note to Alice (stored on the blockchain in encrypted form), // he can decrypt using his outgoing viewing key (OVK). -__Z_INLINE void handleGetKeyOVK(volatile uint32_t *flags, volatile uint32_t *tx, - uint32_t rx) { - zemu_log("----[handleGetKeyOVK]\n"); - - *tx = 0; - if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_OVK || - G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_OVK) { - zemu_log("Wrong length!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } +__Z_INLINE void handleGetKeyOVK(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetKeyOVK]\n"); - uint32_t zip32path = 0; - parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, - DATA_LENGTH_GET_OVK, &zip32path); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - if (prserr != parser_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.kind = key_ovk; - uint16_t replyLen = 0; - - zxerr_t err = crypto_ovk_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, - zip32path, &replyLen); - if (err != zxerr_ok) { *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.len = (uint8_t)replyLen; + if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_OVK || + G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_OVK) { + zemu_log("Wrong length!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - view_review_init(key_getItem, key_getNumItems, app_reply_key); - view_review_show(REVIEW_TXN); - *flags |= IO_ASYNCH_REPLY; + uint32_t zip32path = 0; + parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_OVK, &zip32path); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (prserr != parser_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.kind = key_ovk; + uint16_t replyLen = 0; + + zxerr_t err = crypto_ovk_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, zip32path, &replyLen); + if (err != zxerr_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.len = (uint8_t)replyLen; + + view_review_init(key_getItem, key_getNumItems, app_reply_key); + view_review_show(REVIEW_TXN); + *flags |= IO_ASYNCH_REPLY; } // Get the sapling full viewing key (ak, nk, ovk) -__Z_INLINE void handleGetKeyFVK(volatile uint32_t *flags, volatile uint32_t *tx, - uint32_t rx) { - zemu_log("----[handleGetKeyFVK]\n"); - - *tx = 0; - if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_FVK || - G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_FVK) { - zemu_log("Wrong length!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } +__Z_INLINE void handleGetKeyFVK(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetKeyFVK]\n"); - uint32_t zip32path = 0; - parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, - DATA_LENGTH_GET_FVK, &zip32path); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - if (prserr != parser_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.kind = key_fvk; - uint16_t replyLen = 0; - - zxerr_t err = crypto_fvk_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, - zip32path, &replyLen); - if (err != zxerr_ok) { *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.len = (uint8_t)replyLen; + if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_FVK || + G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_FVK) { + zemu_log("Wrong length!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + uint32_t zip32path = 0; + parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_FVK, &zip32path); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (prserr != parser_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.kind = key_fvk; + uint16_t replyLen = 0; - view_review_init(key_getItem, key_getNumItems, app_reply_key); - view_review_show(REVIEW_TXN); - *flags |= IO_ASYNCH_REPLY; + zxerr_t err = crypto_fvk_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, zip32path, &replyLen); + if (err != zxerr_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.len = (uint8_t)replyLen; + + view_review_init(key_getItem, key_getNumItems, app_reply_key); + view_review_show(REVIEW_TXN); + *flags |= IO_ASYNCH_REPLY; } // 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. // (nk is part of the full viewing key fvk = (ak, nk, ovk) ) -__Z_INLINE void handleGetNullifier(volatile uint32_t *flags, - volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleGetNullifier]\n"); - - *tx = 0; - if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_NF || - G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_NF) { - zemu_log("Wrong length!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } +__Z_INLINE void handleGetNullifier(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetNullifier]\n"); - uint32_t zip32path = 0; - parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, - DATA_LENGTH_GET_NF, &zip32path); - if (prserr != parser_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - *tx = 0; - zemu_log("Failed to get seed!\n"); - THROW(APDU_CODE_DATA_INVALID); - } - - // get note position from payload - uint64_t notepos = 0; - memcpy(¬epos, G_io_apdu_buffer + OFFSET_DATA + ZIP32_PATH_SIZE, - NOTE_POSITION_SIZE); - - // get note commitment from payload - uint8_t cm[NOTE_COMMITMENT_SIZE] = {0}; - memcpy(cm, - G_io_apdu_buffer + OFFSET_DATA + ZIP32_PATH_SIZE + NOTE_POSITION_SIZE, - NOTE_COMMITMENT_SIZE); - - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - - key_state.kind = nf; - uint16_t replyLen = 0; - - // this needs to get Full viewing key = (ak, nk, ovk) and note position, to - // then compute nullifier G_io_apdu_buffer contains zip32path, note position, - // note commitment - zxerr_t err = crypto_nullifier_sapling( - G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, notepos, cm, &replyLen); - if (err != zxerr_ok) { - zemu_log("Failed to get nullifier!\n"); *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - key_state.len = (uint8_t)replyLen; + if (rx < APDU_MIN_LENGTH || rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_NF || + G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_NF) { + zemu_log("Wrong length!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + uint32_t zip32path = 0; + parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_NF, &zip32path); + if (prserr != parser_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + *tx = 0; + zemu_log("Failed to get seed!\n"); + THROW(APDU_CODE_DATA_INVALID); + } + + // get note position from payload + uint64_t notepos = 0; + memcpy(¬epos, G_io_apdu_buffer + OFFSET_DATA + ZIP32_PATH_SIZE, NOTE_POSITION_SIZE); + + // get note commitment from payload + uint8_t cm[NOTE_COMMITMENT_SIZE] = {0}; + memcpy(cm, G_io_apdu_buffer + OFFSET_DATA + ZIP32_PATH_SIZE + NOTE_POSITION_SIZE, NOTE_COMMITMENT_SIZE); + + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + + key_state.kind = nf; + uint16_t replyLen = 0; + + // this needs to get Full viewing key = (ak, nk, ovk) and note position, to + // then compute nullifier G_io_apdu_buffer contains zip32path, note position, + // note commitment + zxerr_t err = crypto_nullifier_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, notepos, cm, &replyLen); + if (err != zxerr_ok) { + zemu_log("Failed to get nullifier!\n"); + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + key_state.len = (uint8_t)replyLen; - view_review_init(key_getItem, key_getNumItems, app_reply_key); - view_review_show(REVIEW_TXN); - *flags |= IO_ASYNCH_REPLY; + view_review_init(key_getItem, key_getNumItems, app_reply_key); + view_review_show(REVIEW_TXN); + *flags |= IO_ASYNCH_REPLY; } __Z_INLINE void handleCheckandSign(volatile uint32_t *tx, uint32_t rx) { - if (!process_chunk(tx, rx)) { - THROW(APDU_CODE_OK); - } - *tx = 0; - - zemu_log("----[handleCheckandSign]\n"); + if (!process_chunk(tx, rx)) { + THROW(APDU_CODE_OK); + } + *tx = 0; - const uint8_t *message = tx_get_buffer(); - const uint16_t messageLength = tx_get_buffer_length(); + zemu_log("----[handleCheckandSign]\n"); - const uint8_t txVersion = G_io_apdu_buffer[OFFSET_P2]; + const uint8_t *message = tx_get_buffer(); + const uint16_t messageLength = tx_get_buffer_length(); - char buffer[20]; - snprintf(buffer, sizeof(buffer), "Tx Version is %d", txVersion); - zemu_log_stack(buffer); + const uint8_t txVersion = G_io_apdu_buffer[OFFSET_P2]; - if (!((txVersion == TX_VERSION_SAPLING) || (txVersion == TX_VERSION_NU5))) { - zemu_log("Unhandled tx version\n"); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_UNHANDLED_TX_VERSION); - } + char buffer[20]; + snprintf(buffer, sizeof(buffer), "Tx Version is %d", txVersion); + zemu_log_stack(buffer); - if (get_state() != STATE_PROCESSED_ALL_EXTRACTIONS) { - zemu_log("[handleCheckandSign] not STATE_PROCESSED_ALL_EXTRACTIONS\n"); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_UNPROCESSED_TX); - } + if (!((txVersion == TX_VERSION_SAPLING) || (txVersion == TX_VERSION_NU5))) { + zemu_log("Unhandled tx version\n"); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_UNHANDLED_TX_VERSION); + } - set_state(STATE_CHECKING_ALL_TXDATA); - view_tx_state(); + if (get_state() != STATE_PROCESSED_ALL_EXTRACTIONS) { + zemu_log("[handleCheckandSign] not STATE_PROCESSED_ALL_EXTRACTIONS\n"); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_UNPROCESSED_TX); + } - zxerr_t err = crypto_check_prevouts(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_PREVOUT_INVALID); - } - - err = crypto_check_sequence(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_SEQUENCE_INVALID); - } - - err = crypto_check_outputs(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, - messageLength, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_OUTPUTS_INVALID); - } - - err = crypto_check_joinsplits(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_JOINSPLIT_INVALID); - } - - // /!\ the valuebalance is different to the total value - err = crypto_check_valuebalance(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_BAD_VALUEBALANCE); - } - - err = crypto_checkspend_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, messageLength, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_SPEND_INVALID); - } - - err = crypto_checkoutput_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, messageLength, txVersion); - if (err != zxerr_ok) { - zemu_log("----[crypto_checkoutput_sapling failed]\n"); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_OUTPUT_CONTENT_INVALID); - } - - err = crypto_checkencryptions_sapling(G_io_apdu_buffer, - IO_APDU_BUFFER_SIZE - 3, message); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_ENCRYPTION_INVALID); - } - - set_state(STATE_VERIFIED_ALL_TXDATA); - view_tx_state(); - - err = crypto_sign_and_check_transparent(G_io_apdu_buffer, - IO_APDU_BUFFER_SIZE - 3, message, - messageLength, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_CHECK_SIGN_TR_FAIL); - } - - err = crypto_signspends_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, messageLength, txVersion); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_SIGN_SPEND_FAIL); - } - - err = crypto_hash_messagebuffer(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, - message, messageLength); - if (err != zxerr_ok) { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_idle_show(0, NULL); - transaction_reset(); - THROW(APDU_CODE_HASH_MSG_BUF_FAIL); - } + set_state(STATE_CHECKING_ALL_TXDATA); + view_tx_state(); - set_state(STATE_SIGNED_TX); - view_tx_state(); + zxerr_t err = crypto_check_prevouts(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_PREVOUT_INVALID); + } - *tx = 32; - THROW(APDU_CODE_OK); -} + err = crypto_check_sequence(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_SEQUENCE_INVALID); + } -__Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, - volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleGetAddrSecp256K1]\n"); + err = crypto_check_outputs(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_OUTPUTS_INVALID); + } - extractHDPath(rx, OFFSET_DATA); - *tx = 0; - uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; - uint16_t replyLen = 0; + err = crypto_check_joinsplits(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_JOINSPLIT_INVALID); + } - zxerr_t err = crypto_fillAddress_secp256k1( - G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, &replyLen); - if (err != zxerr_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } + // /!\ the valuebalance is different to the total value + err = crypto_check_valuebalance(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_BAD_VALUEBALANCE); + } - action_addrResponse.kind = addr_secp256k1; - action_addrResponse.len = replyLen; + err = crypto_checkspend_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_SPEND_INVALID); + } - if (requireConfirmation) { - view_review_init(addr_getItem, addr_getNumItems, app_reply_address); - view_review_show(REVIEW_ADDRESS); - *flags |= IO_ASYNCH_REPLY; - return; - } - *tx = replyLen; - THROW(APDU_CODE_OK); -} + err = crypto_checkoutput_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, txVersion); + if (err != zxerr_ok) { + zemu_log("----[crypto_checkoutput_sapling failed]\n"); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_OUTPUT_CONTENT_INVALID); + } -__Z_INLINE void handleGetAddrSaplingDiv(volatile uint32_t *flags, - volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleGetAddrSaplingDiv]\n"); + err = crypto_checkencryptions_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_ENCRYPTION_INVALID); + } - *tx = 0; - if (rx < APDU_MIN_LENGTH) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + set_state(STATE_VERIFIED_ALL_TXDATA); + view_tx_state(); - if (rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_ADDR_DIV) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + err = crypto_sign_and_check_transparent(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_CHECK_SIGN_TR_FAIL); + } - if (G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_ADDR_DIV) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + err = crypto_signspends_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength, txVersion); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_SIGN_SPEND_FAIL); + } - uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; + err = crypto_hash_messagebuffer(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, message, messageLength); + if (err != zxerr_ok) { + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_idle_show(0, NULL); + transaction_reset(); + THROW(APDU_CODE_HASH_MSG_BUF_FAIL); + } - uint16_t replyLen = 0; + set_state(STATE_SIGNED_TX); + view_tx_state(); - zemu_log_stack("handleGetAddrSapling_withdiv"); + *tx = 32; + THROW(APDU_CODE_OK); +} - parser_addr_div_t parser_addr; - MEMZERO(&parser_addr, sizeof(parser_addr_div_t)); +__Z_INLINE void handleGetAddrSecp256K1(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetAddrSecp256K1]\n"); - parser_error_t parseErr = parser_sapling_path_with_div(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_ADDR_DIV, &parser_addr); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - if (parseErr != parser_ok) { + extractHDPath(rx, OFFSET_DATA); *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - zxerr_t err = crypto_fillAddress_with_diversifier_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, parser_addr.path, - parser_addr.div, &replyLen); - if (err != zxerr_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - action_addrResponse.kind = addr_sapling_div; - action_addrResponse.len = replyLen; - - if (requireConfirmation) { - view_review_init(addr_getItem, addr_getNumItems, app_reply_address); - view_review_show(REVIEW_ADDRESS); - *flags |= IO_ASYNCH_REPLY; - return; - } - *tx = replyLen; - THROW(APDU_CODE_OK); + uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; + uint16_t replyLen = 0; + + zxerr_t err = crypto_fillAddress_secp256k1(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, &replyLen); + if (err != zxerr_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + + action_addrResponse.kind = addr_secp256k1; + action_addrResponse.len = replyLen; + + if (requireConfirmation) { + view_review_init(addr_getItem, addr_getNumItems, app_reply_address); + view_review_show(REVIEW_ADDRESS); + *flags |= IO_ASYNCH_REPLY; + return; + } + *tx = replyLen; + THROW(APDU_CODE_OK); } -__Z_INLINE void handleGetDiversifierList(volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleGetDiversifierList]\n"); +__Z_INLINE void handleGetAddrSaplingDiv(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetAddrSaplingDiv]\n"); - *tx = 0; - if (rx < APDU_MIN_LENGTH) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + *tx = 0; + if (rx < APDU_MIN_LENGTH) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - if (rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_DIV_LIST) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + if (rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_ADDR_DIV) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - if (G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_DIV_LIST) { - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + if (G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_ADDR_DIV) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - uint16_t replyLen = 0; + uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; - zemu_log_stack("handleGetDiversifierList"); + uint16_t replyLen = 0; - parser_addr_div_t parser_addr; - MEMZERO(&parser_addr, sizeof(parser_addr_div_t)); + zemu_log_stack("handleGetAddrSapling_withdiv"); - parser_error_t prserr = parser_sapling_path_with_div( - G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_DIV_LIST, &parser_addr); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - if (prserr != parser_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - zxerr_t err = crypto_diversifier_with_startindex( - G_io_apdu_buffer, parser_addr.path, parser_addr.div, &replyLen); + parser_addr_div_t parser_addr; + MEMZERO(&parser_addr, sizeof(parser_addr_div_t)); - if (err == zxerr_ok) { + parser_error_t parseErr = + parser_sapling_path_with_div(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_ADDR_DIV, &parser_addr); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (parseErr != parser_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + zxerr_t err = crypto_fillAddress_with_diversifier_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 3, parser_addr.path, + parser_addr.div, &replyLen); + if (err != zxerr_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + action_addrResponse.kind = addr_sapling_div; + action_addrResponse.len = replyLen; + + if (requireConfirmation) { + view_review_init(addr_getItem, addr_getNumItems, app_reply_address); + view_review_show(REVIEW_ADDRESS); + *flags |= IO_ASYNCH_REPLY; + return; + } *tx = replyLen; THROW(APDU_CODE_OK); - } else { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } } -__Z_INLINE void handleGetAddrSapling(volatile uint32_t *flags, - volatile uint32_t *tx, uint32_t rx) { - zemu_log("----[handleGetAddrSapling]\n"); +__Z_INLINE void handleGetDiversifierList(volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetDiversifierList]\n"); + + *tx = 0; + if (rx < APDU_MIN_LENGTH) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - *tx = 0; - if (rx < APDU_MIN_LENGTH) { - zemu_log("Missing data!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + if (rx - APDU_MIN_LENGTH != DATA_LENGTH_GET_DIV_LIST) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - if (rx != (uint32_t)(DATA_LENGTH_GET_ADDR_SAPLING + APDU_MIN_LENGTH)) { - zemu_log("Wrong length!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + if (G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_DIV_LIST) { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - if (G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_ADDR_SAPLING) { - zemu_log("Wrong offset data length!\n"); - THROW(APDU_CODE_COMMAND_NOT_ALLOWED); - } + uint16_t replyLen = 0; - uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; + zemu_log_stack("handleGetDiversifierList"); - uint32_t zip32path = 0; - parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_ADDR_SAPLING, &zip32path); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - if (prserr != parser_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - uint16_t replyLen = 0; - zxerr_t err = crypto_fillAddress_sapling( - G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, zip32path, &replyLen); - if (err != zxerr_ok) { - *tx = 0; - THROW(APDU_CODE_DATA_INVALID); - } - action_addrResponse.kind = addr_sapling; - action_addrResponse.len = replyLen; - - if (requireConfirmation) { - view_review_init(addr_getItem, addr_getNumItems, app_reply_address); - view_review_show(REVIEW_ADDRESS); - *flags |= IO_ASYNCH_REPLY; - return; - } + parser_addr_div_t parser_addr; + MEMZERO(&parser_addr, sizeof(parser_addr_div_t)); - *tx = replyLen; - THROW(APDU_CODE_OK); + parser_error_t prserr = + parser_sapling_path_with_div(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_DIV_LIST, &parser_addr); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (prserr != parser_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + zxerr_t err = crypto_diversifier_with_startindex(G_io_apdu_buffer, parser_addr.path, parser_addr.div, &replyLen); + + if (err == zxerr_ok) { + *tx = replyLen; + THROW(APDU_CODE_OK); + } else { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } } -__Z_INLINE void handleSignSapling() { THROW(APDU_CODE_COMMAND_NOT_ALLOWED); } +__Z_INLINE void handleGetAddrSapling(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + zemu_log("----[handleGetAddrSapling]\n"); -void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { - uint16_t sw = 0; + *tx = 0; + if (rx < APDU_MIN_LENGTH) { + zemu_log("Missing data!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } + + if (rx != (uint32_t)(DATA_LENGTH_GET_ADDR_SAPLING + APDU_MIN_LENGTH)) { + zemu_log("Wrong length!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - BEGIN_TRY { - TRY { - if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { - THROW(APDU_CODE_CLA_NOT_SUPPORTED); - } + if (G_io_apdu_buffer[OFFSET_DATA_LEN] != DATA_LENGTH_GET_ADDR_SAPLING) { + zemu_log("Wrong offset data length!\n"); + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); + } - if (rx < APDU_MIN_LENGTH) { - THROW(APDU_CODE_WRONG_LENGTH); - } - - switch (G_io_apdu_buffer[OFFSET_INS]) { - case INS_GET_VERSION: { - handle_getversion(tx); - break; - } - - case INS_GET_ADDR_SECP256K1: { - CHECK_PIN_VALIDATED() - handleGetAddrSecp256K1(flags, tx, rx); - break; - } - - case INS_GET_IVK: { - CHECK_PIN_VALIDATED() - handleGetKeyIVK(flags, tx, rx); - break; - } - - case INS_GET_OVK: { - CHECK_PIN_VALIDATED() - handleGetKeyOVK(flags, tx, rx); - break; - } - - case INS_GET_NF: { - CHECK_PIN_VALIDATED() - handleGetNullifier(flags, tx, rx); - break; - } - - case INS_GET_FVK: { - zemu_log("----[INS_GET_FVK]\n"); - CHECK_PIN_VALIDATED() - handleGetKeyFVK(flags, tx, rx); - break; - } - - case INS_INIT_TX: { - CHECK_PIN_VALIDATED() - handleInitTX(flags, tx, rx); - break; - } - - case INS_EXTRACT_SPEND: { - CHECK_PIN_VALIDATED() - handleExtractSpendData(tx, rx); - break; - } - - case INS_EXTRACT_OUTPUT: { - CHECK_PIN_VALIDATED() - handleExtractOutputData(tx, rx); - break; - } - - case INS_CHECKANDSIGN: { - CHECK_PIN_VALIDATED() - handleCheckandSign(tx, rx); - break; - } - - case INS_EXTRACT_SPENDSIG: { - CHECK_PIN_VALIDATED() - handleExtractSpendSignature(tx, rx); - break; - } - - case INS_EXTRACT_TRANSSIG: { - CHECK_PIN_VALIDATED() - handleExtractTransparentSignature(tx, rx); - break; - } - - case INS_GET_ADDR_SAPLING: { - CHECK_PIN_VALIDATED() - handleGetAddrSapling(flags, tx, rx); - break; - } - - case INS_GET_DIV_LIST: { - CHECK_PIN_VALIDATED() - handleGetDiversifierList(tx, rx); - break; - } - - case INS_GET_ADDR_SAPLING_DIV: { - CHECK_PIN_VALIDATED() - handleGetAddrSaplingDiv(flags, tx, rx); - break; - } - - case INS_SIGN_SAPLING: { - CHECK_PIN_VALIDATED() - handleSignSapling(); - break; - } - - default: - THROW(APDU_CODE_INS_NOT_SUPPORTED); - } - } - CATCH(EXCEPTION_IO_RESET) { THROW(EXCEPTION_IO_RESET); } - CATCH_OTHER(e) { - switch (e & 0xF000) { - case 0x6000: - case APDU_CODE_OK: - sw = e; - break; - default: - sw = 0x6800 | (e & 0x7FF); - break; - } - G_io_apdu_buffer[*tx] = sw >> 8; - G_io_apdu_buffer[*tx + 1] = sw; - *tx += 2; - } - FINALLY {} - } - END_TRY; + uint8_t requireConfirmation = G_io_apdu_buffer[OFFSET_P1]; + + uint32_t zip32path = 0; + parser_error_t prserr = parser_sapling_path(G_io_apdu_buffer + OFFSET_DATA, DATA_LENGTH_GET_ADDR_SAPLING, &zip32path); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + if (prserr != parser_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + uint16_t replyLen = 0; + zxerr_t err = crypto_fillAddress_sapling(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE - 2, zip32path, &replyLen); + if (err != zxerr_ok) { + *tx = 0; + THROW(APDU_CODE_DATA_INVALID); + } + action_addrResponse.kind = addr_sapling; + action_addrResponse.len = replyLen; + + if (requireConfirmation) { + view_review_init(addr_getItem, addr_getNumItems, app_reply_address); + view_review_show(REVIEW_ADDRESS); + *flags |= IO_ASYNCH_REPLY; + return; + } + + *tx = replyLen; + THROW(APDU_CODE_OK); +} + +__Z_INLINE void handleSignSapling() { + THROW(APDU_CODE_COMMAND_NOT_ALLOWED); +} + +void handleApdu(volatile uint32_t *flags, volatile uint32_t *tx, uint32_t rx) { + uint16_t sw = 0; + + BEGIN_TRY { + TRY { + if (G_io_apdu_buffer[OFFSET_CLA] != CLA) { + THROW(APDU_CODE_CLA_NOT_SUPPORTED); + } + + if (rx < APDU_MIN_LENGTH) { + THROW(APDU_CODE_WRONG_LENGTH); + } + + switch (G_io_apdu_buffer[OFFSET_INS]) { + case INS_GET_VERSION: { + handle_getversion(tx); + break; + } + + case INS_GET_ADDR_SECP256K1: { + CHECK_PIN_VALIDATED() + handleGetAddrSecp256K1(flags, tx, rx); + break; + } + + case INS_GET_IVK: { + CHECK_PIN_VALIDATED() + handleGetKeyIVK(flags, tx, rx); + break; + } + + case INS_GET_OVK: { + CHECK_PIN_VALIDATED() + handleGetKeyOVK(flags, tx, rx); + break; + } + + case INS_GET_NF: { + CHECK_PIN_VALIDATED() + handleGetNullifier(flags, tx, rx); + break; + } + + case INS_GET_FVK: { + zemu_log("----[INS_GET_FVK]\n"); + CHECK_PIN_VALIDATED() + handleGetKeyFVK(flags, tx, rx); + break; + } + + case INS_INIT_TX: { + CHECK_PIN_VALIDATED() + handleInitTX(flags, tx, rx); + break; + } + + case INS_EXTRACT_SPEND: { + CHECK_PIN_VALIDATED() + handleExtractSpendData(tx, rx); + break; + } + + case INS_EXTRACT_OUTPUT: { + CHECK_PIN_VALIDATED() + handleExtractOutputData(tx, rx); + break; + } + + case INS_CHECKANDSIGN: { + CHECK_PIN_VALIDATED() + handleCheckandSign(tx, rx); + break; + } + + case INS_EXTRACT_SPENDSIG: { + CHECK_PIN_VALIDATED() + handleExtractSpendSignature(tx, rx); + break; + } + + case INS_EXTRACT_TRANSSIG: { + CHECK_PIN_VALIDATED() + handleExtractTransparentSignature(tx, rx); + break; + } + + case INS_GET_ADDR_SAPLING: { + CHECK_PIN_VALIDATED() + handleGetAddrSapling(flags, tx, rx); + break; + } + + case INS_GET_DIV_LIST: { + CHECK_PIN_VALIDATED() + handleGetDiversifierList(tx, rx); + break; + } + + case INS_GET_ADDR_SAPLING_DIV: { + CHECK_PIN_VALIDATED() + handleGetAddrSaplingDiv(flags, tx, rx); + break; + } + + case INS_SIGN_SAPLING: { + CHECK_PIN_VALIDATED() + handleSignSapling(); + break; + } + + default: + THROW(APDU_CODE_INS_NOT_SUPPORTED); + } + } + CATCH(EXCEPTION_IO_RESET) { + THROW(EXCEPTION_IO_RESET); + } + CATCH_OTHER(e) { + switch (e & 0xF000) { + case 0x6000: + case APDU_CODE_OK: + sw = e; + break; + default: + sw = 0x6800 | (e & 0x7FF); + break; + } + G_io_apdu_buffer[*tx] = sw >> 8; + G_io_apdu_buffer[*tx + 1] = sw; + *tx += 2; + } + FINALLY { + } + } + END_TRY; } diff --git a/app/src/c_api/rust.c b/app/src/c_api/rust.c index 1520e884..89e61a9e 100644 --- a/app/src/c_api/rust.c +++ b/app/src/c_api/rust.c @@ -1,178 +1,183 @@ +#include +#include +#include +#include + #include "aes.h" #include "coin.h" #include "cx.h" #include "jubjub.h" #include "os.h" -#include -#include -#include -#include #include "zcash_utils.h" -#define CTX_REDJUBJUB "Zcash_RedJubjubH" -#define CTX_REDJUBJUB_LEN 16 -#define CTX_REDJUBJUB_HASH_LEN 64 +#define CTX_REDJUBJUB "Zcash_RedJubjubH" +#define CTX_REDJUBJUB_LEN 16 +#define CTX_REDJUBJUB_HASH_LEN 64 -#define CTX_EXPAND_SEED "Zcash_ExpandSeed" -#define CTX_EXPAND_SEED_LEN 16 +#define CTX_EXPAND_SEED "Zcash_ExpandSeed" +#define CTX_EXPAND_SEED_LEN 16 #define CTX_EXPAND_SEED_HASH_LEN 64 #include #include #include -#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || \ - defined(TARGET_NANOS2) || defined(TARGET_STAX) +#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) #include "lcx_rng.h" unsigned char *bolos_cx_rng(uint8_t *buffer, size_t len) { - cx_rng_no_throw(buffer, len); - return buffer; + cx_rng_no_throw(buffer, len); + return buffer; } #endif -zxerr_t c_blake2b32_withpersonal(const uint8_t *person, const uint8_t *a, - uint32_t a_len, uint8_t *out) { - if (person == NULL || a == NULL || out == NULL) { - return zxerr_no_data; - } - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)person, 16)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 256)); - return zxerr_ok; +zxerr_t c_blake2b32_withpersonal(const uint8_t *person, const uint8_t *a, uint32_t a_len, uint8_t *out) { + if (person == NULL || a == NULL || out == NULL) { + return zxerr_no_data; + } + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)person, 16)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 256)); + return zxerr_ok; }; -zxerr_t c_blake2b64_withpersonal(const uint8_t *person, const uint8_t *a, - uint32_t a_len, uint8_t *out) { - if (person == NULL || a == NULL || out == NULL) { - return zxerr_no_data; - } +zxerr_t c_blake2b64_withpersonal(const uint8_t *person, const uint8_t *a, uint32_t a_len, uint8_t *out) { + if (person == NULL || a == NULL || out == NULL) { + return zxerr_no_data; + } - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 512, NULL, 0, (uint8_t *)person, 16)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 512)); - return zxerr_ok; + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 512, NULL, 0, (uint8_t *)person, 16)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, a, a_len, out, 512)); + return zxerr_ok; }; -zxerr_t c_zcash_blake2b_redjubjub(const uint8_t *a, uint32_t a_len, - const uint8_t *b, uint32_t b_len, uint8_t *out) { - if (a == NULL || b == NULL || out == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_REDJUBJUB_HASH_LEN, NULL, 0,(uint8_t *)CTX_REDJUBJUB, CTX_REDJUBJUB_LEN)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out, CTX_REDJUBJUB_HASH_LEN)); - return zxerr_ok; +zxerr_t c_zcash_blake2b_redjubjub(const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, uint8_t *out) { + if (a == NULL || b == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 8 * CTX_REDJUBJUB_HASH_LEN, NULL, 0, (uint8_t *)CTX_REDJUBJUB, CTX_REDJUBJUB_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out, CTX_REDJUBJUB_HASH_LEN)); + return zxerr_ok; } -zxerr_t c_zcash_blake2b_expand_seed(const uint8_t *a, uint32_t a_len, - const uint8_t *b, uint32_t b_len, uint8_t *out) { - if (a == NULL || b == NULL || out == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0,(uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out,CTX_EXPAND_SEED_HASH_LEN)); - return zxerr_ok; +zxerr_t c_zcash_blake2b_expand_seed(const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, uint8_t *out) { + if (a == NULL || b == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, + CTX_EXPAND_SEED_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, b, b_len, out, CTX_EXPAND_SEED_HASH_LEN)); + return zxerr_ok; } -zxerr_t c_zcash_blake2b_expand_vec_two(const uint8_t *a, uint32_t a_len, - const uint8_t *b, uint32_t b_len, - const uint8_t *c, uint32_t c_len, - uint8_t *out) { - if (a == NULL || b == NULL || c == NULL || out == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, c, c_len, out, CTX_EXPAND_SEED_HASH_LEN)); - return zxerr_ok; +zxerr_t c_zcash_blake2b_expand_vec_two( + const uint8_t *a, uint32_t a_len, const uint8_t *b, uint32_t b_len, const uint8_t *c, uint32_t c_len, uint8_t *out) { + if (a == NULL || b == NULL || c == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, + CTX_EXPAND_SEED_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, c, c_len, out, CTX_EXPAND_SEED_HASH_LEN)); + return zxerr_ok; } -zxerr_t c_zcash_blake2b_expand_vec_four(const uint8_t *a, uint32_t a_len, - const uint8_t *b, uint32_t b_len, - const uint8_t *c, uint32_t c_len, - const uint8_t *d, uint32_t d_len, - const uint8_t *e, uint32_t e_len, - uint8_t *out) { - if (a == NULL || b == NULL || c == NULL || d == NULL || e == NULL || out == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, CTX_EXPAND_SEED_LEN)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, c, c_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, d, d_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, e, e_len, out, CTX_EXPAND_SEED_HASH_LEN)); - return zxerr_ok; +zxerr_t c_zcash_blake2b_expand_vec_four(const uint8_t *a, + uint32_t a_len, + const uint8_t *b, + uint32_t b_len, + const uint8_t *c, + uint32_t c_len, + const uint8_t *d, + uint32_t d_len, + const uint8_t *e, + uint32_t e_len, + uint8_t *out) { + if (a == NULL || b == NULL || c == NULL || d == NULL || e == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 8 * CTX_EXPAND_SEED_HASH_LEN, NULL, 0, (uint8_t *)CTX_EXPAND_SEED, + CTX_EXPAND_SEED_LEN)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, b, b_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, c, c_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, d, d_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, e, e_len, out, CTX_EXPAND_SEED_HASH_LEN)); + return zxerr_ok; } -zxerr_t zcash_blake2b_hash_two(const uint8_t *perso, uint32_t perso_len, - const uint8_t *a, uint32_t a_len, const uint8_t *b, - uint32_t b_len, uint8_t *out, uint32_t out_len) { - if (perso == NULL || a == NULL || b == NULL || out == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t zcashHashBlake2b = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&zcashHashBlake2b, 8 * out_len, NULL, 0, (uint8_t *)perso, perso_len)); - CHECK_CX_OK(cx_hash_no_throw(&zcashHashBlake2b.header, 0, a, a_len, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&zcashHashBlake2b.header, CX_LAST, b, b_len, out, out_len)); - return zxerr_ok; +zxerr_t zcash_blake2b_hash_two(const uint8_t *perso, + uint32_t perso_len, + const uint8_t *a, + uint32_t a_len, + const uint8_t *b, + uint32_t b_len, + uint8_t *out, + uint32_t out_len) { + if (perso == NULL || a == NULL || b == NULL || out == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t zcashHashBlake2b = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&zcashHashBlake2b, 8 * out_len, NULL, 0, (uint8_t *)perso, perso_len)); + CHECK_CX_OK(cx_hash_no_throw(&zcashHashBlake2b.header, 0, a, a_len, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&zcashHashBlake2b.header, CX_LAST, b, b_len, out, out_len)); + return zxerr_ok; } -uint16_t fp_uint64_to_str(char *out, uint16_t outLen, const uint64_t value, - uint8_t decimals) { - return fpuint64_to_str(out, outLen, value, decimals); +uint16_t fp_uint64_to_str(char *out, uint16_t outLen, const uint64_t value, uint8_t decimals) { + return fpuint64_to_str(out, outLen, value, decimals); } -void check_canary() {} +void check_canary() { +} -void _zemu_log_stack(uint8_t *buffer) { zemu_log_stack((char *)buffer); } +void _zemu_log_stack(uint8_t *buffer) { + zemu_log_stack((char *)buffer); +} -void c_aes256_encryptblock(const uint8_t *key, const uint8_t *in, - uint8_t *out) { - struct AES_ctx ctx; - AES_init_ctx(&ctx, key); +void c_aes256_encryptblock(const uint8_t *key, const uint8_t *in, uint8_t *out) { + struct AES_ctx ctx; + AES_init_ctx(&ctx, key); - // encrypts in place, so we copy and encrypt - MEMCPY(out, in, AES_BLOCKLEN); - AES_ECB_encrypt(&ctx, out); + // encrypts in place, so we copy and encrypt + MEMCPY(out, in, AES_BLOCKLEN); + AES_ECB_encrypt(&ctx, out); } void c_jubjub_scalarmult(uint8_t *point, const uint8_t *scalar) { - jubjub_extendedpoint p; - jubjub_fq scal; - MEMCPY(scal, scalar, JUBJUB_FIELD_BYTES); - SWAP_ENDIAN_BYTES(scal); - - if (jubjub_extendedpoint_frombytes(&p, point) != zxerr_ok || - jubjub_extendedpoint_scalarmult(&p, scal) != zxerr_ok || - jubjub_extendedpoint_tobytes(point, &p) != zxerr_ok) { - - MEMZERO(point, JUBJUB_FIELD_BYTES); - } + jubjub_extendedpoint p; + jubjub_fq scal; + MEMCPY(scal, scalar, JUBJUB_FIELD_BYTES); + SWAP_ENDIAN_BYTES(scal); + + if (jubjub_extendedpoint_frombytes(&p, point) != zxerr_ok || jubjub_extendedpoint_scalarmult(&p, scal) != zxerr_ok || + jubjub_extendedpoint_tobytes(point, &p) != zxerr_ok) { + MEMZERO(point, JUBJUB_FIELD_BYTES); + } } void c_jubjub_spending_base_scalarmult(uint8_t *point, const uint8_t *scalar) { - jubjub_extendedpoint p; - jubjub_fq scal; - MEMCPY(scal, scalar, JUBJUB_FIELD_BYTES); - SWAP_ENDIAN_BYTES(scal); - MEMCPY(&p, &JUBJUB_GEN, sizeof(jubjub_extendedpoint)); - if (jubjub_extendedpoint_scalarmult(&p, scal) != zxerr_ok || - jubjub_extendedpoint_tobytes(point, &p) != zxerr_ok) { - - MEMZERO(point, JUBJUB_FIELD_BYTES); - } + jubjub_extendedpoint p; + jubjub_fq scal; + MEMCPY(scal, scalar, JUBJUB_FIELD_BYTES); + SWAP_ENDIAN_BYTES(scal); + MEMCPY(&p, &JUBJUB_GEN, sizeof(jubjub_extendedpoint)); + if (jubjub_extendedpoint_scalarmult(&p, scal) != zxerr_ok || jubjub_extendedpoint_tobytes(point, &p) != zxerr_ok) { + MEMZERO(point, JUBJUB_FIELD_BYTES); + } } void io_heart_beat() { diff --git a/app/src/chacha.c b/app/src/chacha.c index 236b3898..e2c3cbdc 100644 --- a/app/src/chacha.c +++ b/app/src/chacha.c @@ -15,116 +15,113 @@ // Adapted by Zondax #include "chacha.h" + #include "app_main.h" #include "coin.h" #include "cx.h" #include "os.h" #include "zxmacros.h" -#define U8TO32_LITTLE(p) \ - (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ - ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) // sigma contains the ChaCha constants, which happen to be an ASCII string. -static const uint8_t sigma[16] = {'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', - '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}; +static const uint8_t sigma[16] = {'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}; #define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) // QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. -#define QUARTERROUND(a, b, c, d) \ - x[a] += x[b]; \ - x[d] = ROTATE(x[d] ^ x[a], 16); \ - x[c] += x[d]; \ - x[b] = ROTATE(x[b] ^ x[c], 12); \ - x[a] += x[b]; \ - x[d] = ROTATE(x[d] ^ x[a], 8); \ - x[c] += x[d]; \ - x[b] = ROTATE(x[b] ^ x[c], 7); +#define QUARTERROUND(a, b, c, d) \ + x[a] += x[b]; \ + x[d] = ROTATE(x[d] ^ x[a], 16); \ + x[c] += x[d]; \ + x[b] = ROTATE(x[b] ^ x[c], 12); \ + x[a] += x[b]; \ + x[d] = ROTATE(x[d] ^ x[a], 8); \ + x[c] += x[d]; \ + x[b] = ROTATE(x[b] ^ x[c], 7); -void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32], - const uint8_t nonce[16]) { - uint32_t x[16]; - MEMCPY(x, sigma, sizeof(sigma)); - MEMCPY(&x[4], key, 32); - MEMCPY(&x[12], nonce, 16); - for (size_t i = 0; i < 20; i += 2) { - QUARTERROUND(0, 4, 8, 12) - QUARTERROUND(1, 5, 9, 13) - QUARTERROUND(2, 6, 10, 14) - QUARTERROUND(3, 7, 11, 15) - QUARTERROUND(0, 5, 10, 15) - QUARTERROUND(1, 6, 11, 12) - QUARTERROUND(2, 7, 8, 13) - QUARTERROUND(3, 4, 9, 14) - } - MEMCPY(out, &x[0], sizeof(uint32_t) * 4); - MEMCPY(&out[16], &x[12], sizeof(uint32_t) * 4); +void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32], const uint8_t nonce[16]) { + uint32_t x[16]; + MEMCPY(x, sigma, sizeof(sigma)); + MEMCPY(&x[4], key, 32); + MEMCPY(&x[12], nonce, 16); + for (size_t i = 0; i < 20; i += 2) { + QUARTERROUND(0, 4, 8, 12) + QUARTERROUND(1, 5, 9, 13) + QUARTERROUND(2, 6, 10, 14) + QUARTERROUND(3, 7, 11, 15) + QUARTERROUND(0, 5, 10, 15) + QUARTERROUND(1, 6, 11, 12) + QUARTERROUND(2, 7, 8, 13) + QUARTERROUND(3, 4, 9, 14) + } + MEMCPY(out, &x[0], sizeof(uint32_t) * 4); + MEMCPY(&out[16], &x[12], sizeof(uint32_t) * 4); } -#define U32TO8_LITTLE(p, v) \ - { \ - (p)[0] = (v >> 0) & 0xff; \ - (p)[1] = (v >> 8) & 0xff; \ - (p)[2] = (v >> 16) & 0xff; \ - (p)[3] = (v >> 24) & 0xff; \ - } +#define U32TO8_LITTLE(p, v) \ + { \ + (p)[0] = (v >> 0) & 0xff; \ + (p)[1] = (v >> 8) & 0xff; \ + (p)[2] = (v >> 16) & 0xff; \ + (p)[3] = (v >> 24) & 0xff; \ + } // chacha_core performs 20 rounds of ChaCha on the input words in // |input| and writes the 64 output bytes to |output|. void chacha_core(uint8_t *output, const uint32_t *input) { - uint32_t x[16]; - int i; - MEMCPY(x, input, sizeof(uint32_t) * 16); - for (i = 20; i > 0; i -= 2) { - QUARTERROUND(0, 4, 8, 12) - QUARTERROUND(1, 5, 9, 13) - QUARTERROUND(2, 6, 10, 14) - QUARTERROUND(3, 7, 11, 15) - QUARTERROUND(0, 5, 10, 15) - QUARTERROUND(1, 6, 11, 12) - QUARTERROUND(2, 7, 8, 13) - QUARTERROUND(3, 4, 9, 14) - } - for (i = 0; i < 16; ++i) { - x[i] += input[i]; - } - for (i = 0; i < 16; ++i) { - U32TO8_LITTLE(output + 4 * i, x[i]); - } + uint32_t x[16]; + int i; + MEMCPY(x, input, sizeof(uint32_t) * 16); + for (i = 20; i > 0; i -= 2) { + QUARTERROUND(0, 4, 8, 12) + QUARTERROUND(1, 5, 9, 13) + QUARTERROUND(2, 6, 10, 14) + QUARTERROUND(3, 7, 11, 15) + QUARTERROUND(0, 5, 10, 15) + QUARTERROUND(1, 6, 11, 12) + QUARTERROUND(2, 7, 8, 13) + QUARTERROUND(3, 4, 9, 14) + } + for (i = 0; i < 16; ++i) { + x[i] += input[i]; + } + for (i = 0; i < 16; ++i) { + U32TO8_LITTLE(output + 4 * i, x[i]); + } } -void chacha(uint8_t *out, const uint8_t *in, size_t in_len, const uint8_t *key, - const uint8_t *nonce, uint32_t counter) { - uint32_t input[16]; - uint8_t buf[64]; - size_t todo, i; - input[0] = U8TO32_LITTLE(sigma + 0); - input[1] = U8TO32_LITTLE(sigma + 4); - input[2] = U8TO32_LITTLE(sigma + 8); - input[3] = U8TO32_LITTLE(sigma + 12); - input[4] = U8TO32_LITTLE(key + 0); - input[5] = U8TO32_LITTLE(key + 4); - input[6] = U8TO32_LITTLE(key + 8); - input[7] = U8TO32_LITTLE(key + 12); - input[8] = U8TO32_LITTLE(key + 16); - input[9] = U8TO32_LITTLE(key + 20); - input[10] = U8TO32_LITTLE(key + 24); - input[11] = U8TO32_LITTLE(key + 28); - input[12] = counter; - input[13] = U8TO32_LITTLE(nonce + 0); - input[14] = U8TO32_LITTLE(nonce + 4); - input[15] = U8TO32_LITTLE(nonce + 8); - while (in_len > 0) { - todo = sizeof(buf); - if (in_len < todo) { - todo = in_len; - } - chacha_core(buf, input); - io_seproxyhal_io_heartbeat(); - for (i = 0; i < todo; i++) { - out[i] = in[i] ^ buf[i]; +void chacha(uint8_t *out, const uint8_t *in, size_t in_len, const uint8_t *key, const uint8_t *nonce, uint32_t counter) { + uint32_t input[16]; + uint8_t buf[64]; + size_t todo, i; + input[0] = U8TO32_LITTLE(sigma + 0); + input[1] = U8TO32_LITTLE(sigma + 4); + input[2] = U8TO32_LITTLE(sigma + 8); + input[3] = U8TO32_LITTLE(sigma + 12); + input[4] = U8TO32_LITTLE(key + 0); + input[5] = U8TO32_LITTLE(key + 4); + input[6] = U8TO32_LITTLE(key + 8); + input[7] = U8TO32_LITTLE(key + 12); + input[8] = U8TO32_LITTLE(key + 16); + input[9] = U8TO32_LITTLE(key + 20); + input[10] = U8TO32_LITTLE(key + 24); + input[11] = U8TO32_LITTLE(key + 28); + input[12] = counter; + input[13] = U8TO32_LITTLE(nonce + 0); + input[14] = U8TO32_LITTLE(nonce + 4); + input[15] = U8TO32_LITTLE(nonce + 8); + while (in_len > 0) { + todo = sizeof(buf); + if (in_len < todo) { + todo = in_len; + } + chacha_core(buf, input); + io_seproxyhal_io_heartbeat(); + for (i = 0; i < todo; i++) { + out[i] = in[i] ^ buf[i]; + } + out += todo; + in += todo; + in_len -= todo; + input[12]++; } - out += todo; - in += todo; - in_len -= todo; - input[12]++; - } } diff --git a/app/src/chacha.h b/app/src/chacha.h index a9414c0a..025cf574 100644 --- a/app/src/chacha.h +++ b/app/src/chacha.h @@ -23,12 +23,10 @@ extern "C" { // CRYPTO_hchacha20 computes the HChaCha20 function, which should only be used // as part of XChaCha20. -void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32], - const uint8_t nonce[16]); +void CRYPTO_hchacha20(uint8_t out[32], const uint8_t key[32], const uint8_t nonce[16]); -void chacha(uint8_t *out, const uint8_t *in, size_t in_len, const uint8_t *key, - const uint8_t *nonce, uint32_t counter); +void chacha(uint8_t *out, const uint8_t *in, size_t in_len, const uint8_t *key, const uint8_t *nonce, uint32_t counter); #if defined(__cplusplus) -} // extern C -#endif // OPENSSL_HEADER_CHACHA_INTERNAL +} // extern C +#endif // OPENSSL_HEADER_CHACHA_INTERNAL diff --git a/app/src/coin.h b/app/src/coin.h index 645720ad..91c1f6d3 100644 --- a/app/src/coin.h +++ b/app/src/coin.h @@ -19,18 +19,18 @@ extern "C" { #endif -#define CLA 0x85 +#define CLA 0x85 #define HDPATH_LEN_DEFAULT 5 -#define HDPATH_0_DEFAULT (0x80000000u | 0x2cu) -#define HDPATH_1_DEFAULT (0x80000000u | 0x85) -#define HDPATH_2_DEFAULT (0x80000000u | 0u) -#define HDPATH_3_DEFAULT (0u) -#define HDPATH_4_DEFAULT (0u) +#define HDPATH_0_DEFAULT (0x80000000u | 0x2cu) +#define HDPATH_1_DEFAULT (0x80000000u | 0x85) +#define HDPATH_2_DEFAULT (0x80000000u | 0u) +#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) // compressed key #define PK_LEN_SECP256K1 33u @@ -42,61 +42,61 @@ extern "C" { #define LEN_IVK 32u // ak, nsk -#define LEN_PGK 64u - -#define ENABLE_SDK_MULT 0 - -#define DATA_LENGTH_GET_IVK 4 // ZIP32-path -#define DATA_LENGTH_GET_OVK 4 // ZIP32-path -#define DATA_LENGTH_GET_FVK 4 // ZIP32-path -#define DATA_LENGTH_GET_NF 44 // ZIP32-path + 8-byte note position + 32-byte note commitment -#define DATA_LENGTH_GET_ADDR_SAPLING 4 // ZIP32-path -#define DATA_LENGTH_GET_DIV_LIST 15 // ZIP32-path + 11-byte index -#define DATA_LENGTH_GET_ADDR_DIV 15 // ZIP32-path + 11-byte div - -#define INS_GET_VERSION 0x00 -#define INS_GET_ADDR_SECP256K1 0x01 -#define INS_SIGN_SECP256K1 0x02 -#define INS_GET_DIV_LIST 0x09 -#define INS_GET_ADDR_SAPLING_DIV 0x10 -#define INS_GET_ADDR_SAPLING 0x11 -#define INS_SIGN_SAPLING 0x12 - -#define INS_INIT_TX 0xa0 -#define INS_KEY_EXCHANGE 0xaa -#define INS_EXTRACT_SPEND 0xa1 -#define INS_EXTRACT_OUTPUT 0xa2 -#define INS_CHECKANDSIGN 0xa3 -#define INS_EXTRACT_SPENDSIG 0xa4 -#define INS_EXTRACT_TRANSSIG 0xa5 - -#define INS_GET_IVK 0xf0 -#define INS_GET_OVK 0xf1 -#define INS_GET_NF 0xf2 -#define INS_GET_FVK 0xf3 -#define INS_CRASH_TEST 0xff +#define LEN_PGK 64u + +#define ENABLE_SDK_MULT 0 + +#define DATA_LENGTH_GET_IVK 4 // ZIP32-path +#define DATA_LENGTH_GET_OVK 4 // ZIP32-path +#define DATA_LENGTH_GET_FVK 4 // ZIP32-path +#define DATA_LENGTH_GET_NF 44 // ZIP32-path + 8-byte note position + 32-byte note commitment +#define DATA_LENGTH_GET_ADDR_SAPLING 4 // ZIP32-path +#define DATA_LENGTH_GET_DIV_LIST 15 // ZIP32-path + 11-byte index +#define DATA_LENGTH_GET_ADDR_DIV 15 // ZIP32-path + 11-byte div + +#define INS_GET_VERSION 0x00 +#define INS_GET_ADDR_SECP256K1 0x01 +#define INS_SIGN_SECP256K1 0x02 +#define INS_GET_DIV_LIST 0x09 +#define INS_GET_ADDR_SAPLING_DIV 0x10 +#define INS_GET_ADDR_SAPLING 0x11 +#define INS_SIGN_SAPLING 0x12 + +#define INS_INIT_TX 0xa0 +#define INS_KEY_EXCHANGE 0xaa +#define INS_EXTRACT_SPEND 0xa1 +#define INS_EXTRACT_OUTPUT 0xa2 +#define INS_CHECKANDSIGN 0xa3 +#define INS_EXTRACT_SPENDSIG 0xa4 +#define INS_EXTRACT_TRANSSIG 0xa5 + +#define INS_GET_IVK 0xf0 +#define INS_GET_OVK 0xf1 +#define INS_GET_NF 0xf2 +#define INS_GET_FVK 0xf3 +#define INS_CRASH_TEST 0xff typedef enum { - addr_secp256k1 = 0, - addr_sapling = 1, - addr_sapling_div = 2, + addr_secp256k1 = 0, + addr_sapling = 1, + addr_sapling_div = 2, } address_kind_e; typedef enum { key_ivk = 0, key_ovk = 1, key_fvk = 2, nf = 3 } key_type_e; #define VIEW_ADDRESS_OFFSET_SECP256K1 PK_LEN_SECP256K1 -#define VIEW_ADDRESS_OFFSET_SAPLING ADDR_LEN_SAPLING +#define VIEW_ADDRESS_OFFSET_SAPLING ADDR_LEN_SAPLING -#define MENU_MAIN_APP_LINE1 "Zcash Shielded" -#define MENU_MAIN_APP_LINE2 "Ready" -#define APPVERSION_LINE1 "Zcash Shielded" -#define APPVERSION_LINE2 ("v" APPVERSION) +#define MENU_MAIN_APP_LINE1 "Zcash Shielded" +#define MENU_MAIN_APP_LINE2 "Ready" +#define APPVERSION_LINE1 "Zcash Shielded" +#define APPVERSION_LINE2 ("v" APPVERSION) -#define MENU_MAIN_APP_LINE2_SECRET "?" -#define COIN_SECRET_REQUIRED_CLICKS 0 +#define MENU_MAIN_APP_LINE2_SECRET "?" +#define COIN_SECRET_REQUIRED_CLICKS 0 -#define COIN_AMOUNT_DECIMAL_PLACES 18 -#define CRYPTO_BLOB_SKIP_BYTES 0 +#define COIN_AMOUNT_DECIMAL_PLACES 18 +#define CRYPTO_BLOB_SKIP_BYTES 0 #ifdef __cplusplus } diff --git a/app/src/common/actions.c b/app/src/common/actions.c index ce4d0916..1d146b26 100644 --- a/app/src/common/actions.c +++ b/app/src/common/actions.c @@ -15,6 +15,7 @@ ********************************************************************************/ #include "actions.h" + #include "tx.h" address_state_t action_addrResponse; diff --git a/app/src/common/actions.h b/app/src/common/actions.h index 9142e2e9..7df06879 100644 --- a/app/src/common/actions.h +++ b/app/src/common/actions.h @@ -15,56 +15,57 @@ ********************************************************************************/ #pragma once +#include +#include + #include "apdu_codes.h" +#include "apdu_errors.h" #include "app_main.h" #include "coin.h" #include "crypto.h" #include "nvdata.h" #include "parser.h" #include "tx.h" -#include "apdu_errors.h" -#include -#include typedef struct { - address_kind_e kind; - uint8_t len; + address_kind_e kind; + uint8_t len; } address_state_t; typedef struct { - key_type_e kind; - uint8_t len; + key_type_e kind; + uint8_t len; } key_state_t; extern address_state_t action_addrResponse; extern key_state_t key_state; __Z_INLINE void app_reject() { - transaction_reset(); - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - view_tx_state(); - set_code(G_io_apdu_buffer, 0, APDU_CODE_COMMAND_NOT_ALLOWED); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); + transaction_reset(); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + view_tx_state(); + set_code(G_io_apdu_buffer, 0, APDU_CODE_COMMAND_NOT_ALLOWED); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); } __Z_INLINE void app_reply_key() { - set_code(G_io_apdu_buffer, key_state.len, APDU_CODE_OK); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, key_state.len + 2); + set_code(G_io_apdu_buffer, key_state.len, APDU_CODE_OK); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, key_state.len + 2); } __Z_INLINE void app_reply_address() { - set_code(G_io_apdu_buffer, action_addrResponse.len, APDU_CODE_OK); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, action_addrResponse.len + 2); + set_code(G_io_apdu_buffer, action_addrResponse.len, APDU_CODE_OK); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, action_addrResponse.len + 2); } __Z_INLINE void app_reply_error() { - MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); - set_code(G_io_apdu_buffer, 0, APDU_CODE_DATA_INVALID); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); + MEMZERO(G_io_apdu_buffer, IO_APDU_BUFFER_SIZE); + set_code(G_io_apdu_buffer, 0, APDU_CODE_DATA_INVALID); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); } __Z_INLINE void app_reply_hash() { - view_tx_state(); - set_code(G_io_apdu_buffer, 32, APDU_CODE_OK); - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 32 + 2); + view_tx_state(); + set_code(G_io_apdu_buffer, 32, APDU_CODE_OK); + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 32 + 2); } diff --git a/app/src/common/main.c b/app/src/common/main.c index d7eb28e6..332418dd 100644 --- a/app/src/common/main.c +++ b/app/src/common/main.c @@ -14,25 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ +#include + #include "app_main.h" #include "view.h" -#include - __attribute__((section(".boot"))) int main(void) { - // exit critical section - __asm volatile("cpsie i"); + // exit critical section + __asm volatile("cpsie i"); - view_init(); - os_boot(); + view_init(); + os_boot(); - BEGIN_TRY { - TRY { - app_init(); - app_main(); + BEGIN_TRY { + TRY { + app_init(); + app_main(); + } + CATCH_OTHER(e) { + } + FINALLY { + } } - CATCH_OTHER(e) {} - FINALLY {} - } - END_TRY; + END_TRY; } diff --git a/app/src/common/tx.c b/app/src/common/tx.c index 175bea2a..86b72169 100644 --- a/app/src/common/tx.c +++ b/app/src/common/tx.c @@ -15,22 +15,23 @@ ********************************************************************************/ #include "tx.h" + +#include + #include "apdu_codes.h" #include "buffering.h" #include "parser.h" #include "zxmacros.h" -#include // Ram uint8_t ram_buffer[RAM_BUFFER_SIZE]; // Flash typedef struct { - uint8_t buffer[FLASH_BUFFER_SIZE]; + uint8_t buffer[FLASH_BUFFER_SIZE]; } storage_t; -#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || \ - defined(TARGET_NANOS2) || defined(TARGET_STAX) +#if defined(TARGET_NANOS) || defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) storage_t NV_CONST N_appdata_impl __attribute__((aligned(64))); #define N_appdata (*(NV_VOLATILE storage_t *)PIC(&N_appdata_impl)) #endif @@ -39,72 +40,77 @@ static parser_tx_t tx_obj; static parser_context_t ctx_parsed_tx; void tx_initialize() { - buffering_init(ram_buffer, sizeof(ram_buffer), (uint8_t *)N_appdata.buffer, - sizeof(N_appdata.buffer)); + buffering_init(ram_buffer, sizeof(ram_buffer), (uint8_t *)N_appdata.buffer, sizeof(N_appdata.buffer)); } -void tx_reset() { buffering_reset(); } +void tx_reset() { + buffering_reset(); +} uint32_t tx_append(unsigned char *buffer, uint32_t length) { - return buffering_append(buffer, length); + return buffering_append(buffer, length); } -uint32_t tx_get_buffer_length() { return buffering_get_buffer()->pos; } +uint32_t tx_get_buffer_length() { + return buffering_get_buffer()->pos; +} -uint8_t *tx_get_buffer() { return buffering_get_buffer()->data; } +uint8_t *tx_get_buffer() { + return buffering_get_buffer()->data; +} const char *tx_parse() { - MEMZERO(&tx_obj, sizeof(tx_obj)); + MEMZERO(&tx_obj, sizeof(tx_obj)); - uint8_t err = - parser_parse(&ctx_parsed_tx, tx_get_buffer(), tx_get_buffer_length()); + uint8_t err = parser_parse(&ctx_parsed_tx, tx_get_buffer(), tx_get_buffer_length()); - if (err != parser_ok) { - return parser_getErrorDescription(err); - } + if (err != parser_ok) { + return parser_getErrorDescription(err); + } - err = parser_validate(); - CHECK_APP_CANARY() + err = parser_validate(); + CHECK_APP_CANARY() - if (err != parser_ok) { - return parser_getErrorDescription(err); - } + if (err != parser_ok) { + return parser_getErrorDescription(err); + } - return NULL; + return NULL; } zxerr_t tx_getNumItems(uint8_t *num_items) { - parser_error_t err = parser_getNumItems(num_items); + parser_error_t err = parser_getNumItems(num_items); - if (err != parser_ok) { - return zxerr_no_data; - } + if (err != parser_ok) { + return zxerr_no_data; + } - return zxerr_ok; + return zxerr_ok; } -zxerr_t tx_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, uint8_t pageIdx, +zxerr_t tx_getItem(int8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outVal, + uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { - uint8_t numItems = 0; + uint8_t numItems = 0; - CHECK_ZXERR(tx_getNumItems(&numItems)) + CHECK_ZXERR(tx_getNumItems(&numItems)) - if (displayIdx < 0 || displayIdx >= numItems) { - return zxerr_no_data; - } + if (displayIdx < 0 || displayIdx >= numItems) { + return zxerr_no_data; + } - parser_error_t err = parser_getItem(displayIdx, outKey, outKeyLen, outVal, - outValLen, pageIdx, pageCount); + parser_error_t err = parser_getItem(displayIdx, outKey, outKeyLen, outVal, outValLen, pageIdx, pageCount); - // Convert error codes - if (err == parser_no_data || err == parser_display_idx_out_of_range || - err == parser_display_page_out_of_range) { - return zxerr_no_data; - } + // Convert error codes + if (err == parser_no_data || err == parser_display_idx_out_of_range || err == parser_display_page_out_of_range) { + return zxerr_no_data; + } - if (err != parser_ok) - return zxerr_unknown; + if (err != parser_ok) return zxerr_unknown; - return zxerr_ok; + return zxerr_ok; } diff --git a/app/src/common/tx.h b/app/src/common/tx.h index 7a501fcb..113a4744 100644 --- a/app/src/common/tx.h +++ b/app/src/common/tx.h @@ -20,10 +20,10 @@ #include "zxerror.h" #if defined(TARGET_NANOX) || defined(TARGET_NANOS2) || defined(TARGET_STAX) -#define RAM_BUFFER_SIZE 8192 +#define RAM_BUFFER_SIZE 8192 #define FLASH_BUFFER_SIZE 16384 #elif defined(TARGET_NANOS) -#define RAM_BUFFER_SIZE 0 +#define RAM_BUFFER_SIZE 0 #define FLASH_BUFFER_SIZE 8192 #endif @@ -56,6 +56,10 @@ const char *tx_parse(); zxerr_t tx_getNumItems(uint8_t *num_items); /// Gets an specific item from the transaction (including paging) -zxerr_t tx_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, uint8_t pageIdx, +zxerr_t tx_getItem(int8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outValue, + uint16_t outValueLen, + uint8_t pageIdx, uint8_t *pageCount); diff --git a/app/src/constants.h b/app/src/constants.h index 9d95186c..757c1732 100644 --- a/app/src/constants.h +++ b/app/src/constants.h @@ -17,91 +17,91 @@ #pragma once // CRYPTO File -#define CHECKSUM_LENGTH 4 - -#define SK_SECP256K1_SIZE 32 -#define PUB_KEY_SIZE 32 -#define DER_MAX_SIZE 73 -#define AK_SIZE 32 -#define NSK_SIZE 32 -#define ASK_SIZE 32 -#define DK_SIZE 32 -#define NK_SIZE 32 -#define ED25519_SK_SIZE 64 -#define IVK_SIZE 32 -#define ZIP32_SEED_SIZE 64 -#define ZIP32_PATH_SIZE 4 -#define RND_SIZE 32 -#define NULLIFIER_SIZE 32 -#define RK_SIZE 32 - -#define ESK_SIZE 32 -#define EPK_SIZE 32 -#define NOTE_POSITION_SIZE 8 -#define NOTE_COMMITMENT_SIZE 32 -#define VALUE_COMMITMENT_SIZE 32 -#define ANCHOR_SIZE 32 -#define HASH_SIZE 32 -#define SESSION_KEY_SIZE 32 -#define GD_SIZE 32 -#define SHARED_KEY_SIZE 32 -#define OUT_KEY_SIZE 32 -#define ENC_CIPHER_SIZE 64 -#define ENC_CIPHER_HALVE_SIZE 32 - -#define OUTPUT_ENC_MEMO_SIZE 564 - 52 +#define CHECKSUM_LENGTH 4 + +#define SK_SECP256K1_SIZE 32 +#define PUB_KEY_SIZE 32 +#define DER_MAX_SIZE 73 +#define AK_SIZE 32 +#define NSK_SIZE 32 +#define ASK_SIZE 32 +#define DK_SIZE 32 +#define NK_SIZE 32 +#define ED25519_SK_SIZE 64 +#define IVK_SIZE 32 +#define ZIP32_SEED_SIZE 64 +#define ZIP32_PATH_SIZE 4 +#define RND_SIZE 32 +#define NULLIFIER_SIZE 32 +#define RK_SIZE 32 + +#define ESK_SIZE 32 +#define EPK_SIZE 32 +#define NOTE_POSITION_SIZE 8 +#define NOTE_COMMITMENT_SIZE 32 +#define VALUE_COMMITMENT_SIZE 32 +#define ANCHOR_SIZE 32 +#define HASH_SIZE 32 +#define SESSION_KEY_SIZE 32 +#define GD_SIZE 32 +#define SHARED_KEY_SIZE 32 +#define OUT_KEY_SIZE 32 +#define ENC_CIPHER_SIZE 64 +#define ENC_CIPHER_HALVE_SIZE 32 + +#define OUTPUT_ENC_MEMO_SIZE 564 - 52 #define OUTPUT_ENC_AEAD_TAG_SIZE 580 - 564 -#define OUTPUT_OUT_SIZE 80 // OutputDescription, field out_ciphertext: [u8; 80], - -#define COMPACT_OUT_SIZE 53 -#define PRF_INPUT_SIZE 128 -#define MAX_SIZE 161 -#define SIG_R_SIZE 32 -#define SIG_S_SIZE 32 -#define SCRIPT_CONSTS_SIZE 4 -#define PEDERSEN_INPUT_SIZE 73 -#define CHACHA_NONCE_SIZE 12 - -#define MASK_HARDENED 0x80000000 - -#define VERSION_SIZE 2 -#define CHECKSUM_SIZE 4 -#define VERSION_P2SH 0x1CBD -#define VERSION_P2PKH 0x1CB8 -#define BECH32_HRP "zs" -#define BECH32_HRP_TEST "ztestsapling" +#define OUTPUT_OUT_SIZE 80 // OutputDescription, field out_ciphertext: [u8; 80], + +#define COMPACT_OUT_SIZE 53 +#define PRF_INPUT_SIZE 128 +#define MAX_SIZE 161 +#define SIG_R_SIZE 32 +#define SIG_S_SIZE 32 +#define SCRIPT_CONSTS_SIZE 4 +#define PEDERSEN_INPUT_SIZE 73 +#define CHACHA_NONCE_SIZE 12 + +#define MASK_HARDENED 0x80000000 + +#define VERSION_SIZE 2 +#define CHECKSUM_SIZE 4 +#define VERSION_P2SH 0x1CBD +#define VERSION_P2PKH 0x1CB8 +#define BECH32_HRP "zs" +#define BECH32_HRP_TEST "ztestsapling" // NVDATA File // fixme: maybe increase some of these -#define T_IN_LIST_SIZE 5 -#define T_OUT_LIST_SIZE 5 -#define SPEND_LIST_SIZE 5 -#define OUTPUT_LIST_SIZE 5 - -#define PREVOUT_SIZE 36 -#define SEQUENCE_SIZE 4 -#define T_OUTPUT_SIZE 34 // script size (26) + value size (uint64_t -> 8) - -#define PKD_SIZE 32 -#define RCM_SIZE 32 -#define ALPHA_SIZE 32 -#define DIV_SIZE 11 -#define DIV_INDEX_SIZE 11 -#define DIV_LIST_LENGTH 20 +#define T_IN_LIST_SIZE 5 +#define T_OUT_LIST_SIZE 5 +#define SPEND_LIST_SIZE 5 +#define OUTPUT_LIST_SIZE 5 + +#define PREVOUT_SIZE 36 +#define SEQUENCE_SIZE 4 +#define T_OUTPUT_SIZE 34 // script size (26) + value size (uint64_t -> 8) + +#define PKD_SIZE 32 +#define RCM_SIZE 32 +#define ALPHA_SIZE 32 +#define DIV_SIZE 11 +#define DIV_INDEX_SIZE 11 +#define DIV_LIST_LENGTH 20 #define DIV_DEFAULT_LIST_LEN 4 -#define MAX_SIZE_BUF_ADDR 143 +#define MAX_SIZE_BUF_ADDR 143 -#define SESSION_KEY_SIZE 32 +#define SESSION_KEY_SIZE 32 -#define OVK_SIZE 32 -#define OVK_SET_SIZE 1 + OVK_SIZE -#define RSEED_SIZE 32 -#define RCM_V_SIZE 32 +#define OVK_SIZE 32 +#define OVK_SET_SIZE 1 + OVK_SIZE +#define RSEED_SIZE 32 +#define RCM_V_SIZE 32 -#define SCRIPT_SIZE 26 -#define PATH_SIZE 5 +#define SCRIPT_SIZE 26 +#define PATH_SIZE 5 -#define SIGNATURE_SIZE SIG_R_SIZE + SIG_S_SIZE +#define SIGNATURE_SIZE SIG_R_SIZE + SIG_S_SIZE -#define TX_VERSION_SAPLING 4 -#define TX_VERSION_NU5 5 +#define TX_VERSION_SAPLING 4 +#define TX_VERSION_NU5 5 diff --git a/app/src/crypto.c b/app/src/crypto.c index 469b1a64..abbe1243 100644 --- a/app/src/crypto.c +++ b/app/src/crypto.c @@ -15,6 +15,7 @@ ********************************************************************************/ #include "crypto.h" + #include "base58.h" #include "bech32.h" #include "chacha.h" @@ -35,156 +36,152 @@ uint32_t hdPath[HDPATH_LEN_DEFAULT]; -#define CHECK_ZXERROR_AND_CLEAN(CALL) \ - do { \ - zxerr_t __zxerror = CALL; \ - if (__zxerror != zxerr_ok) { \ - MEMZERO(&tmp, sizeof(tmp)); \ - MEMZERO(buffer, bufferLen); \ - return __zxerror; \ - } \ - } while (0); +#define CHECK_ZXERROR_AND_CLEAN(CALL) \ + do { \ + zxerr_t __zxerror = CALL; \ + if (__zxerror != zxerr_ok) { \ + MEMZERO(&tmp, sizeof(tmp)); \ + MEMZERO(buffer, bufferLen); \ + return __zxerror; \ + } \ + } while (0); typedef enum { - EXTRACT_SAPLING_E0 = 0xE0, - EXTRACT_SAPLING_E1 = 0xE1, - EXTRACT_SAPLING_E2 = 0xE2, - EXTRACT_SAPLING_E3 = 0xE3, - EXTRACT_SAPLING_E4 = 0xE4, - EXTRACT_SAPLING_E5 = 0xE5, - EXTRACT_SAPLING_E6 = 0xE6, - EXTRACT_SAPLING_E7 = 0xE7, - EXTRACT_SAPLING_E8 = 0xE8, - EXTRACT_SAPLING_E9 = 0xE9, - EXTRACT_SAPLING_EA = 0xEA, - EXTRACT_SAPLING_EB = 0xEB, - EXTRACT_SAPLING_EC = 0xEC, - EXTRACT_SAPLING_ED = 0xED, + EXTRACT_SAPLING_E0 = 0xE0, + EXTRACT_SAPLING_E1 = 0xE1, + EXTRACT_SAPLING_E2 = 0xE2, + EXTRACT_SAPLING_E3 = 0xE3, + EXTRACT_SAPLING_E4 = 0xE4, + EXTRACT_SAPLING_E5 = 0xE5, + EXTRACT_SAPLING_E6 = 0xE6, + EXTRACT_SAPLING_E7 = 0xE7, + EXTRACT_SAPLING_E8 = 0xE8, + EXTRACT_SAPLING_E9 = 0xE9, + EXTRACT_SAPLING_EA = 0xEA, + EXTRACT_SAPLING_EB = 0xEB, + EXTRACT_SAPLING_EC = 0xEC, + EXTRACT_SAPLING_ED = 0xED, } extract_sapling_e; #include "cx.h" typedef struct { - uint8_t publicKey[PK_LEN_SECP256K1]; - uint8_t address[50]; + uint8_t publicKey[PK_LEN_SECP256K1]; + uint8_t address[50]; } __attribute__((packed)) answer_t; zxerr_t ripemd160(uint8_t *in, uint16_t inLen, uint8_t *out) { - if (in == NULL || out == NULL) { - return zxerr_no_data; - } + if (in == NULL || out == NULL) { + return zxerr_no_data; + } - cx_ripemd160_t rip160; - cx_ripemd160_init(&rip160); - const cx_err_t error = cx_hash_no_throw(&rip160.header, CX_LAST, in, inLen, out, CX_RIPEMD160_SIZE); + cx_ripemd160_t rip160; + cx_ripemd160_init(&rip160); + const cx_err_t error = cx_hash_no_throw(&rip160.header, CX_LAST, in, inLen, out, CX_RIPEMD160_SIZE); - return error == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; + return error == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; } // According to 5.6 Encodings of Addresses and Keys typedef struct { - // [ADDRESS ] - // [EXTENDED RIPEMD-160][Checksum 4-bytes] - // [EXTENDED RIPEMD-160][Checksum-------------------------] - // [version][RIPEMD-160] - union { - uint8_t address[VERSION_SIZE + CX_RIPEMD160_SIZE + CHECKSUM_SIZE]; - - struct { - uint8_t extended_ripe[VERSION_SIZE + CX_RIPEMD160_SIZE]; - uint8_t sha256_checksum[CX_SHA256_SIZE]; + // [ADDRESS ] + // [EXTENDED RIPEMD-160][Checksum 4-bytes] + // [EXTENDED RIPEMD-160][Checksum-------------------------] + // [version][RIPEMD-160] + union { + uint8_t address[VERSION_SIZE + CX_RIPEMD160_SIZE + CHECKSUM_SIZE]; + + struct { + uint8_t extended_ripe[VERSION_SIZE + CX_RIPEMD160_SIZE]; + uint8_t sha256_checksum[CX_SHA256_SIZE]; + }; + + union { + // [EXTENDED RIPEMD-160] + // [version][RIPEMD-160] + struct { + uint8_t version[VERSION_SIZE]; + uint8_t ripe_sha256_pk[CX_RIPEMD160_SIZE]; + }; + }; }; + // Temporary buffers union { - // [EXTENDED RIPEMD-160] - // [version][RIPEMD-160] - struct { - uint8_t version[VERSION_SIZE]; - uint8_t ripe_sha256_pk[CX_RIPEMD160_SIZE]; - }; + uint8_t sha256_pk[CX_SHA256_SIZE]; + uint8_t sha256_extended_ripe[CX_SHA256_SIZE]; }; - }; - - // Temporary buffers - union { - uint8_t sha256_pk[CX_SHA256_SIZE]; - uint8_t sha256_extended_ripe[CX_SHA256_SIZE]; - }; } __attribute__((packed)) address_temp_t; static zxerr_t crypto_extractPublicKey(uint8_t *pubKey, uint16_t pubKeyLen) { - if (pubKey == NULL || pubKeyLen < PK_LEN_SECP256K1) { - return zxerr_invalid_crypto_settings; - } + if (pubKey == NULL || pubKeyLen < PK_LEN_SECP256K1) { + return zxerr_invalid_crypto_settings; + } - cx_ecfp_public_key_t cx_publicKey = {0}; - cx_ecfp_private_key_t cx_privateKey = {0}; - uint8_t privateKeyData[64] = {0}; + cx_ecfp_public_key_t cx_publicKey = {0}; + cx_ecfp_private_key_t cx_privateKey = {0}; + uint8_t privateKeyData[64] = {0}; - zxerr_t error = zxerr_unknown; - CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, hdPath, HDPATH_LEN_DEFAULT, privateKeyData, NULL)); - CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey)); - CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, &cx_publicKey)); - CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &cx_publicKey, &cx_privateKey, 1)); + zxerr_t error = zxerr_unknown; + CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, hdPath, HDPATH_LEN_DEFAULT, privateKeyData, NULL)); + CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey)); + CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, &cx_publicKey)); + CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &cx_publicKey, &cx_privateKey, 1)); - cx_publicKey.W[0] = cx_publicKey.W[64] & 1 ? 0x03 : 0x02; // "Compress" public key in place - memcpy(pubKey, cx_publicKey.W, PK_LEN_SECP256K1); - error = zxerr_ok; + cx_publicKey.W[0] = cx_publicKey.W[64] & 1 ? 0x03 : 0x02; // "Compress" public key in place + memcpy(pubKey, cx_publicKey.W, PK_LEN_SECP256K1); + error = zxerr_ok; catch_cx_error: - MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); - MEMZERO(privateKeyData, sizeof(privateKeyData)); + MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); + MEMZERO(privateKeyData, sizeof(privateKeyData)); - if (error != zxerr_ok) { - MEMZERO(pubKey, pubKeyLen); - } + if (error != zxerr_ok) { + MEMZERO(pubKey, pubKeyLen); + } - return error; + return error; } // handleGetAddrSecp256K1 -zxerr_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t buffer_len, - uint16_t *replyLen) { - if (buffer_len < sizeof(answer_t)) { - return zxerr_unknown; - } - - zemu_log_stack("crypto_fillAddress_secp256k1"); - - *replyLen = 0; - MEMZERO(buffer, buffer_len); - answer_t *const answer = (answer_t *)buffer; - - CHECK_ZXERR(crypto_extractPublicKey(answer->publicKey, - sizeof_field(answer_t, publicKey))); - - address_temp_t address_temp; - - // extended-ripemd-160 = [version][ripemd-160(sha256(pk))] - address_temp.version[0] = VERSION_P2PKH >> 8; - address_temp.version[1] = VERSION_P2PKH & 0xFF; - cx_hash_sha256(answer->publicKey, PK_LEN_SECP256K1, address_temp.sha256_pk, - CX_SHA256_SIZE); // SHA256 - CHECK_ZXERR(ripemd160(address_temp.sha256_pk, CX_SHA256_SIZE, - address_temp.ripe_sha256_pk)); // RIPEMD-160 - - // checksum = sha256(sha256(extended-ripe)) - cx_hash_sha256(address_temp.extended_ripe, CX_RIPEMD160_SIZE + VERSION_SIZE, - address_temp.sha256_extended_ripe, CX_SHA256_SIZE); - cx_hash_sha256(address_temp.sha256_extended_ripe, CX_SHA256_SIZE, - address_temp.sha256_checksum, CX_SHA256_SIZE); - - // 7. 25 bytes BTC address = [extended ripemd-160][checksum] - // Encode as base58 - size_t outLen = sizeof_field(answer_t, address); - int err = encode_base58(address_temp.address, - VERSION_SIZE + CX_RIPEMD160_SIZE + CHECKSUM_SIZE, - answer->address, &outLen); - if (err != 0) { - return zxerr_unknown; - } - *replyLen = PK_LEN_SECP256K1 + outLen; - return zxerr_ok; +zxerr_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t buffer_len, uint16_t *replyLen) { + if (buffer_len < sizeof(answer_t)) { + return zxerr_unknown; + } + + zemu_log_stack("crypto_fillAddress_secp256k1"); + + *replyLen = 0; + MEMZERO(buffer, buffer_len); + answer_t *const answer = (answer_t *)buffer; + + CHECK_ZXERR(crypto_extractPublicKey(answer->publicKey, sizeof_field(answer_t, publicKey))); + + address_temp_t address_temp; + + // extended-ripemd-160 = [version][ripemd-160(sha256(pk))] + address_temp.version[0] = VERSION_P2PKH >> 8; + address_temp.version[1] = VERSION_P2PKH & 0xFF; + cx_hash_sha256(answer->publicKey, PK_LEN_SECP256K1, address_temp.sha256_pk, + CX_SHA256_SIZE); // SHA256 + CHECK_ZXERR(ripemd160(address_temp.sha256_pk, CX_SHA256_SIZE, + address_temp.ripe_sha256_pk)); // RIPEMD-160 + + // checksum = sha256(sha256(extended-ripe)) + cx_hash_sha256(address_temp.extended_ripe, CX_RIPEMD160_SIZE + VERSION_SIZE, address_temp.sha256_extended_ripe, + CX_SHA256_SIZE); + cx_hash_sha256(address_temp.sha256_extended_ripe, CX_SHA256_SIZE, address_temp.sha256_checksum, CX_SHA256_SIZE); + + // 7. 25 bytes BTC address = [extended ripemd-160][checksum] + // Encode as base58 + size_t outLen = sizeof_field(answer_t, address); + int err = + encode_base58(address_temp.address, VERSION_SIZE + CX_RIPEMD160_SIZE + CHECKSUM_SIZE, answer->address, &outLen); + if (err != 0) { + return zxerr_unknown; + } + *replyLen = PK_LEN_SECP256K1 + outLen; + return zxerr_ok; } zxerr_t crypto_fillSaplingSeed(uint8_t *sk) { @@ -198,13 +195,12 @@ zxerr_t crypto_fillSaplingSeed(uint8_t *sk) { zxerr_t error = zxerr_unknown; io_seproxyhal_io_heartbeat(); - CATCH_CXERROR(os_derive_bip32_with_seed_no_throw(HDW_NORMAL, CX_CURVE_Ed25519, - path, HDPATH_LEN_DEFAULT, sk, - NULL, NULL, 0)); + CATCH_CXERROR( + os_derive_bip32_with_seed_no_throw(HDW_NORMAL, CX_CURVE_Ed25519, path, HDPATH_LEN_DEFAULT, sk, NULL, NULL, 0)); io_seproxyhal_io_heartbeat(); error = zxerr_ok; - catch_cx_error: +catch_cx_error: if (error != zxerr_ok) { MEMZERO(sk, 64); } @@ -213,1392 +209,1277 @@ zxerr_t crypto_fillSaplingSeed(uint8_t *sk) { } // handleInitTX step 1/2 -zxerr_t crypto_extracttx_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen) { - zemu_log_stack("crypto_extracttx_sapling"); - MEMZERO(buffer, bufferLen); - uint8_t t_in_len = *txdata; - uint8_t t_out_len = *(txdata + 1); - uint8_t spend_len = *(txdata + 2); - uint8_t output_len = *(txdata + 3); - - transaction_reset(); - - if ((spend_len > 0 && output_len < 2) || - (spend_len == 0 && output_len == 1)) { - return (zxerr_t)EXTRACT_SAPLING_E0; - } - - if (txdatalen < 4 || txdatalen - 4 != t_in_len * T_IN_INPUT_LEN + - t_out_len * T_OUT_INPUT_LEN + - spend_len * SPEND_INPUT_LEN + - output_len * OUTPUT_INPUT_LEN) { - return (zxerr_t)EXTRACT_SAPLING_E1; - } - - if (t_in_len == 0 && t_out_len == 0 && spend_len == 0 && output_len == 0) { - return (zxerr_t)EXTRACT_SAPLING_E2; - } - - uint8_t *start = (uint8_t *)txdata; - start += 4; - - parser_context_t pars_ctx; - parser_error_t pars_err; - - for (int i = 0; i < t_in_len; i++) { - uint32_t *path = (uint32_t *)(start + INDEX_INPUT_TIN_PATH); - uint8_t *script = (uint8_t *)(start + INDEX_INPUT_TIN_SCRIPT); - - pars_ctx.offset = 0; - pars_ctx.buffer = start + INDEX_INPUT_TIN_VALUE; - pars_ctx.bufferLen = 8; - uint64_t v = 0; - pars_err = _readUInt64(&pars_ctx, &v); - if (pars_err != parser_ok) { - return (zxerr_t)EXTRACT_SAPLING_E3; - } - zxerr_t err = t_inlist_append_item(path, script, v); - if (err != zxerr_ok) { - return (zxerr_t)EXTRACT_SAPLING_E4; - } - start += T_IN_INPUT_LEN; - } +zxerr_t crypto_extracttx_sapling(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen) { + zemu_log_stack("crypto_extracttx_sapling"); + MEMZERO(buffer, bufferLen); + uint8_t t_in_len = *txdata; + uint8_t t_out_len = *(txdata + 1); + uint8_t spend_len = *(txdata + 2); + uint8_t output_len = *(txdata + 3); - for (int i = 0; i < t_out_len; i++) { - uint8_t *addr = (uint8_t *)(start + INDEX_INPUT_TOUT_ADDR); - pars_ctx.offset = 0; - pars_ctx.buffer = start + INDEX_INPUT_TOUT_VALUE; - pars_ctx.bufferLen = 8; - uint64_t v = 0; - pars_err = _readUInt64(&pars_ctx, &v); - if (pars_err != parser_ok) { - return (zxerr_t)EXTRACT_SAPLING_E5; - } - zxerr_t err = t_outlist_append_item(addr, v); - if (err != zxerr_ok) { - return (zxerr_t)EXTRACT_SAPLING_E6; - } - start += T_OUT_INPUT_LEN; - } + transaction_reset(); - for (int i = 0; i < spend_len; i++) { - pars_ctx.offset = 0; - pars_ctx.buffer = start + INDEX_INPUT_SPENDPOS; - pars_ctx.bufferLen = 4; - uint32_t p = 0; - pars_err = _readUInt32(&pars_ctx, &p); - if (pars_err != parser_ok) { - return (zxerr_t)EXTRACT_SAPLING_E7; + if ((spend_len > 0 && output_len < 2) || (spend_len == 0 && output_len == 1)) { + return (zxerr_t)EXTRACT_SAPLING_E0; } - pars_ctx.offset = 0; - pars_ctx.buffer = start + INDEX_INPUT_INPUTVALUE; - pars_ctx.bufferLen = 8; - uint64_t v = 0; - pars_err = _readUInt64(&pars_ctx, &v); - if (pars_err != parser_ok) { - return (zxerr_t)EXTRACT_SAPLING_E8; + if (txdatalen < 4 || txdatalen - 4 != t_in_len * T_IN_INPUT_LEN + t_out_len * T_OUT_INPUT_LEN + + spend_len * SPEND_INPUT_LEN + output_len * OUTPUT_INPUT_LEN) { + return (zxerr_t)EXTRACT_SAPLING_E1; } - uint8_t *div = start + INDEX_INPUT_INPUTDIV; - uint8_t *pkd = start + INDEX_INPUT_INPUTPKD; - uint8_t rnd1[RND_SIZE]; - uint8_t rnd2[RND_SIZE]; - random_fr(rnd1); - random_fr(rnd2); - - zxerr_t err = spendlist_append_item(p, v, div, pkd, rnd1, rnd2); - if (err != zxerr_ok) { - return (zxerr_t)EXTRACT_SAPLING_E9; + if (t_in_len == 0 && t_out_len == 0 && spend_len == 0 && output_len == 0) { + return (zxerr_t)EXTRACT_SAPLING_E2; } - start += SPEND_INPUT_LEN; - } - - for (int i = 0; i < output_len; i++) { - uint8_t *div = start + INDEX_INPUT_OUTPUTDIV; - uint8_t *pkd = start + INDEX_INPUT_OUTPUTPKD; - pars_ctx.offset = 0; - pars_ctx.buffer = start + INDEX_INPUT_OUTPUTVALUE; - pars_ctx.bufferLen = 8; - uint64_t v = 0; - pars_err = _readUInt64(&pars_ctx, &v); - if (pars_err != parser_ok) { - return (zxerr_t)EXTRACT_SAPLING_EA; + uint8_t *start = (uint8_t *)txdata; + start += 4; + + parser_context_t pars_ctx; + parser_error_t pars_err; + + for (int i = 0; i < t_in_len; i++) { + uint32_t *path = (uint32_t *)(start + INDEX_INPUT_TIN_PATH); + uint8_t *script = (uint8_t *)(start + INDEX_INPUT_TIN_SCRIPT); + + pars_ctx.offset = 0; + pars_ctx.buffer = start + INDEX_INPUT_TIN_VALUE; + pars_ctx.bufferLen = 8; + uint64_t v = 0; + pars_err = _readUInt64(&pars_ctx, &v); + if (pars_err != parser_ok) { + return (zxerr_t)EXTRACT_SAPLING_E3; + } + zxerr_t err = t_inlist_append_item(path, script, v); + if (err != zxerr_ok) { + return (zxerr_t)EXTRACT_SAPLING_E4; + } + start += T_IN_INPUT_LEN; } - uint8_t *memotype = start + INDEX_INPUT_OUTPUTMEMO; - uint8_t *ovk = start + INDEX_INPUT_OUTPUTOVK; - - if (ovk[0] != 0x00 && ovk[0] != 0x01) { - return (zxerr_t)EXTRACT_SAPLING_EB; + for (int i = 0; i < t_out_len; i++) { + uint8_t *addr = (uint8_t *)(start + INDEX_INPUT_TOUT_ADDR); + pars_ctx.offset = 0; + pars_ctx.buffer = start + INDEX_INPUT_TOUT_VALUE; + pars_ctx.bufferLen = 8; + uint64_t v = 0; + pars_err = _readUInt64(&pars_ctx, &v); + if (pars_err != parser_ok) { + return (zxerr_t)EXTRACT_SAPLING_E5; + } + zxerr_t err = t_outlist_append_item(addr, v); + if (err != zxerr_ok) { + return (zxerr_t)EXTRACT_SAPLING_E6; + } + start += T_OUT_INPUT_LEN; } - uint8_t hash_seed[OVK_SET_SIZE] = {0}; - if (ovk[0] == 0x00) { - cx_rng(hash_seed + 1, OVK_SIZE); - ovk = hash_seed; + for (int i = 0; i < spend_len; i++) { + pars_ctx.offset = 0; + pars_ctx.buffer = start + INDEX_INPUT_SPENDPOS; + pars_ctx.bufferLen = 4; + uint32_t p = 0; + pars_err = _readUInt32(&pars_ctx, &p); + if (pars_err != parser_ok) { + return (zxerr_t)EXTRACT_SAPLING_E7; + } + + pars_ctx.offset = 0; + pars_ctx.buffer = start + INDEX_INPUT_INPUTVALUE; + pars_ctx.bufferLen = 8; + uint64_t v = 0; + pars_err = _readUInt64(&pars_ctx, &v); + if (pars_err != parser_ok) { + return (zxerr_t)EXTRACT_SAPLING_E8; + } + + uint8_t *div = start + INDEX_INPUT_INPUTDIV; + uint8_t *pkd = start + INDEX_INPUT_INPUTPKD; + uint8_t rnd1[RND_SIZE]; + uint8_t rnd2[RND_SIZE]; + random_fr(rnd1); + random_fr(rnd2); + + zxerr_t err = spendlist_append_item(p, v, div, pkd, rnd1, rnd2); + if (err != zxerr_ok) { + return (zxerr_t)EXTRACT_SAPLING_E9; + } + start += SPEND_INPUT_LEN; } - uint8_t rnd1[RND_SIZE] = {0}; - uint8_t rnd2[RND_SIZE] = {0}; - random_fr(rnd1); - cx_rng(rnd2, RND_SIZE); - zxerr_t err = outputlist_append_item(div, pkd, v, *memotype, ovk, rnd1, rnd2); - if (err != zxerr_ok) { - return (zxerr_t)EXTRACT_SAPLING_EC; + for (int i = 0; i < output_len; i++) { + uint8_t *div = start + INDEX_INPUT_OUTPUTDIV; + uint8_t *pkd = start + INDEX_INPUT_OUTPUTPKD; + + pars_ctx.offset = 0; + pars_ctx.buffer = start + INDEX_INPUT_OUTPUTVALUE; + pars_ctx.bufferLen = 8; + uint64_t v = 0; + pars_err = _readUInt64(&pars_ctx, &v); + if (pars_err != parser_ok) { + return (zxerr_t)EXTRACT_SAPLING_EA; + } + + uint8_t *memotype = start + INDEX_INPUT_OUTPUTMEMO; + uint8_t *ovk = start + INDEX_INPUT_OUTPUTOVK; + + if (ovk[0] != 0x00 && ovk[0] != 0x01) { + return (zxerr_t)EXTRACT_SAPLING_EB; + } + + uint8_t hash_seed[OVK_SET_SIZE] = {0}; + if (ovk[0] == 0x00) { + cx_rng(hash_seed + 1, OVK_SIZE); + ovk = hash_seed; + } + + uint8_t rnd1[RND_SIZE] = {0}; + uint8_t rnd2[RND_SIZE] = {0}; + random_fr(rnd1); + cx_rng(rnd2, RND_SIZE); + zxerr_t err = outputlist_append_item(div, pkd, v, *memotype, ovk, rnd1, rnd2); + if (err != zxerr_ok) { + return (zxerr_t)EXTRACT_SAPLING_EC; + } + start += OUTPUT_INPUT_LEN; } - start += OUTPUT_INPUT_LEN; - } - uint64_t tx_value__flash = get_totalvalue(); + uint64_t tx_value__flash = get_totalvalue(); #ifdef HAVE_ZIP0317 - if (tx_value__flash != zip_0317(t_in_len, t_out_len, spend_len, output_len)) { - return (zxerr_t)EXTRACT_SAPLING_ED; - } + if (tx_value__flash != zip_0317(t_in_len, t_out_len, spend_len, output_len)) { + return (zxerr_t)EXTRACT_SAPLING_ED; + } #else - if (tx_value__flash != 1000) { - return (zxerr_t)EXTRACT_SAPLING_ED; - } + if (tx_value__flash != 1000) { + return (zxerr_t)EXTRACT_SAPLING_ED; + } #endif - if (spend_len > 0) { - set_state(STATE_PROCESSED_INPUTS); // need both spend info and output info - // (as spend > 0 => output >= 2) - } else if (output_len > 0) { - set_state( - STATE_PROCESSED_SPEND_EXTRACTIONS); // we can have shielded outputs only - } else { - set_state(STATE_PROCESSED_ALL_EXTRACTIONS); // We can have transparent - // inputs/outputs only - } - - return zxerr_ok; // some code for all_good + if (spend_len > 0) { + set_state(STATE_PROCESSED_INPUTS); // need both spend info and output info + // (as spend > 0 => output >= 2) + } else if (output_len > 0) { + set_state(STATE_PROCESSED_SPEND_EXTRACTIONS); // we can have shielded outputs only + } else { + set_state(STATE_PROCESSED_ALL_EXTRACTIONS); // We can have transparent + // inputs/outputs only + } + + return zxerr_ok; // some code for all_good } typedef struct { - union { - // STEP 1 - struct { - uint8_t zip32_seed[ZIP32_SEED_SIZE]; - uint8_t sk[ED25519_SK_SIZE]; - } step1; - - struct { - uint8_t ask[ASK_SIZE]; - uint8_t nsk[NSK_SIZE]; - } step2; - }; + union { + // STEP 1 + struct { + uint8_t zip32_seed[ZIP32_SEED_SIZE]; + uint8_t sk[ED25519_SK_SIZE]; + } step1; + + struct { + uint8_t ask[ASK_SIZE]; + uint8_t nsk[NSK_SIZE]; + } step2; + }; } tmp_spendinfo_s; // handleExtractSpendData -zxerr_t crypto_extract_spend_proofkeyandrnd(uint8_t *buffer, - uint16_t bufferLen) { - if (!spendlist_more_extract()) { - return zxerr_unknown; - } +zxerr_t crypto_extract_spend_proofkeyandrnd(uint8_t *buffer, uint16_t bufferLen) { + if (!spendlist_more_extract()) { + return zxerr_unknown; + } - if (get_state() != STATE_PROCESSED_INPUTS) { - return zxerr_unknown; - } + if (get_state() != STATE_PROCESSED_INPUTS) { + return zxerr_unknown; + } - uint8_t *out = (uint8_t *)buffer; - MEMZERO(out, bufferLen); + uint8_t *out = (uint8_t *)buffer; + MEMZERO(out, bufferLen); - const spend_item_t *next = spendlist_extract_next(); - if (next == NULL) { - return zxerr_unknown; - } + const spend_item_t *next = spendlist_extract_next(); + if (next == NULL) { + return zxerr_unknown; + } - tmp_spendinfo_s tmp = {0}; + tmp_spendinfo_s tmp = {0}; - CHECK_ZXERROR_AND_CLEAN(crypto_fillSaplingSeed(tmp.step1.zip32_seed)) - CHECK_APP_CANARY() + CHECK_ZXERROR_AND_CLEAN(crypto_fillSaplingSeed(tmp.step1.zip32_seed)) + CHECK_APP_CANARY() - // Gets ak and nsk - zip32_child_proof_key(tmp.step1.zip32_seed, out, out + AK_SIZE, next->path); - CHECK_APP_CANARY() + // Gets ak and nsk + zip32_child_proof_key(tmp.step1.zip32_seed, out, out + AK_SIZE, next->path); + CHECK_APP_CANARY() - MEMZERO(&tmp, sizeof(tmp_spendinfo_s)); + MEMZERO(&tmp, sizeof(tmp_spendinfo_s)); - MEMCPY(out + AK_SIZE + NSK_SIZE, next->rcmvalue, RCM_SIZE); - MEMCPY(out + AK_SIZE + NSK_SIZE + RCM_SIZE, next->alpha, ALPHA_SIZE); + MEMCPY(out + AK_SIZE + NSK_SIZE, next->rcmvalue, RCM_SIZE); + MEMCPY(out + AK_SIZE + NSK_SIZE + RCM_SIZE, next->alpha, ALPHA_SIZE); - if (!spendlist_more_extract()) { - set_state(STATE_PROCESSED_SPEND_EXTRACTIONS); - } + if (!spendlist_more_extract()) { + set_state(STATE_PROCESSED_SPEND_EXTRACTIONS); + } - return zxerr_ok; + return zxerr_ok; } // handleExtractOutputData -zxerr_t crypto_extract_output_rnd(uint8_t *buffer, uint16_t bufferLen, - uint16_t *replyLen) { - if (!outputlist_more_extract()) { - return zxerr_unknown; - } - - if (get_state() != STATE_PROCESSED_SPEND_EXTRACTIONS) { - return zxerr_unknown; - } - - uint8_t *out = (uint8_t *)buffer; - MEMZERO(out, bufferLen); - - const output_item_t *next = outputlist_extract_next(); - if (next == NULL) { - return zxerr_unknown; - } - MEMCPY(out, next->rcmvalue, RCM_V_SIZE); - MEMCPY(out + RCM_V_SIZE, next->rseed, RSEED_SIZE); - - if (next->ovk[0] == 0x00) { - MEMCPY(out + RCM_V_SIZE + RSEED_SIZE, next->ovk + 1, OVK_SIZE); - *replyLen = RCM_V_SIZE + RSEED_SIZE + OVK_SIZE; - } else { - *replyLen = RCM_V_SIZE + RSEED_SIZE; - } - - if (!outputlist_more_extract()) { - set_state(STATE_PROCESSED_ALL_EXTRACTIONS); - } - return zxerr_ok; +zxerr_t crypto_extract_output_rnd(uint8_t *buffer, uint16_t bufferLen, uint16_t *replyLen) { + if (!outputlist_more_extract()) { + return zxerr_unknown; + } + + if (get_state() != STATE_PROCESSED_SPEND_EXTRACTIONS) { + return zxerr_unknown; + } + + uint8_t *out = (uint8_t *)buffer; + MEMZERO(out, bufferLen); + + const output_item_t *next = outputlist_extract_next(); + if (next == NULL) { + return zxerr_unknown; + } + MEMCPY(out, next->rcmvalue, RCM_V_SIZE); + MEMCPY(out + RCM_V_SIZE, next->rseed, RSEED_SIZE); + + if (next->ovk[0] == 0x00) { + MEMCPY(out + RCM_V_SIZE + RSEED_SIZE, next->ovk + 1, OVK_SIZE); + *replyLen = RCM_V_SIZE + RSEED_SIZE + OVK_SIZE; + } else { + *replyLen = RCM_V_SIZE + RSEED_SIZE; + } + + if (!outputlist_more_extract()) { + set_state(STATE_PROCESSED_ALL_EXTRACTIONS); + } + return zxerr_ok; } // handleCheckandSign step 1/11 -zxerr_t crypto_check_prevouts(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint8_t tx_version) { - zemu_log_stack("crypto_check_prevouts"); - MEMZERO(buffer, bufferLen); - - if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; - } - - uint8_t hash[HASH_SIZE] = {0}; - size_t prevouts_hash_offset = 0; - if (tx_version == TX_VERSION_SAPLING) { - sapling_transparent_prevouts_hash(txdata, hash); - prevouts_hash_offset = SAPLING_INDEX_HASH_PREVOUTSHASH; - } else if (tx_version == TX_VERSION_NU5) { - nu5_transparent_prevouts_hash(txdata, hash); - prevouts_hash_offset = NU5_INDEX_HASH_PREVOUTSHASH; - } else { - return zxerr_unknown; - } - - if (MEMCMP(hash, txdata + start_sighashdata() + prevouts_hash_offset, - HASH_SIZE) != 0) { - return zxerr_unknown; - } - return zxerr_ok; +zxerr_t crypto_check_prevouts(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version) { + zemu_log_stack("crypto_check_prevouts"); + MEMZERO(buffer, bufferLen); + + if (get_state() != STATE_CHECKING_ALL_TXDATA) { + return zxerr_unknown; + } + + uint8_t hash[HASH_SIZE] = {0}; + size_t prevouts_hash_offset = 0; + if (tx_version == TX_VERSION_SAPLING) { + sapling_transparent_prevouts_hash(txdata, hash); + prevouts_hash_offset = SAPLING_INDEX_HASH_PREVOUTSHASH; + } else if (tx_version == TX_VERSION_NU5) { + nu5_transparent_prevouts_hash(txdata, hash); + prevouts_hash_offset = NU5_INDEX_HASH_PREVOUTSHASH; + } else { + return zxerr_unknown; + } + + if (MEMCMP(hash, txdata + start_sighashdata() + prevouts_hash_offset, HASH_SIZE) != 0) { + return zxerr_unknown; + } + return zxerr_ok; } // handleCheckandSign step 2/11 -zxerr_t crypto_check_sequence(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint8_t tx_version) { - zemu_log_stack("crypto_check_sequence"); - MEMZERO(buffer, bufferLen); - - if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; - } - - uint8_t hash[HASH_SIZE] = {0}; - size_t sequence_hash_offset = 0; - - if (tx_version == TX_VERSION_SAPLING) { - sapling_transparent_sequence_hash(txdata, hash); - sequence_hash_offset = SAPLING_INDEX_HASH_SEQUENCEHASH; - } else if (tx_version == TX_VERSION_NU5) { - nu5_transparent_sequence_hash(txdata, hash); - sequence_hash_offset = NU5_INDEX_HASH_SEQUENCEHASH; - } else { - return zxerr_unknown; - } - - if (MEMCMP(hash, txdata + start_sighashdata() + sequence_hash_offset, - HASH_SIZE) != 0) { - return zxerr_unknown; - } - return zxerr_ok; -} +zxerr_t crypto_check_sequence(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version) { + zemu_log_stack("crypto_check_sequence"); + MEMZERO(buffer, bufferLen); -// handleCheckandSign step 3/11 -zxerr_t crypto_check_outputs(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint16_t txdatalen, - const uint8_t tx_version) { - zemu_log_stack("crypto_check_outputs"); - if (start_sighashdata() + SAPLING_LENGTH_HASH_DATA != txdatalen) { - return zxerr_unknown; - } - - if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; - } - - MEMZERO(buffer, bufferLen); - uint8_t hash[HASH_SIZE] = {0}; - size_t sapling_outputs_hash_offset = 0; - - if (tx_version == TX_VERSION_SAPLING) { - v4_transparent_outputs_hash(hash); - sapling_outputs_hash_offset = SAPLING_INDEX_HASH_OUTPUTSHASH; - } else if (tx_version == TX_VERSION_NU5) { - nu5_transparent_outputs_hash(hash); - sapling_outputs_hash_offset = NU5_INDEX_HASH_OUTPUTSHASH; - } else { - return zxerr_unknown; - } - - if (MEMCMP(hash, txdata + start_sighashdata() + sapling_outputs_hash_offset, - HASH_SIZE) != 0) { - return zxerr_unknown; - } - return zxerr_ok; + if (get_state() != STATE_CHECKING_ALL_TXDATA) { + return zxerr_unknown; + } + + uint8_t hash[HASH_SIZE] = {0}; + size_t sequence_hash_offset = 0; + + if (tx_version == TX_VERSION_SAPLING) { + sapling_transparent_sequence_hash(txdata, hash); + sequence_hash_offset = SAPLING_INDEX_HASH_SEQUENCEHASH; + } else if (tx_version == TX_VERSION_NU5) { + nu5_transparent_sequence_hash(txdata, hash); + sequence_hash_offset = NU5_INDEX_HASH_SEQUENCEHASH; + } else { + return zxerr_unknown; + } + + if (MEMCMP(hash, txdata + start_sighashdata() + sequence_hash_offset, HASH_SIZE) != 0) { + return zxerr_unknown; + } + return zxerr_ok; } -// handleCheckandSign step 4/11 -zxerr_t crypto_check_joinsplits(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint8_t tx_version) { - if (tx_version == TX_VERSION_SAPLING) { - zemu_log_stack("crypto_check_joinsplits"); - MEMZERO(buffer, bufferLen); +// handleCheckandSign step 3/11 +zxerr_t crypto_check_outputs( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version) { + zemu_log_stack("crypto_check_outputs"); + if (start_sighashdata() + SAPLING_LENGTH_HASH_DATA != txdatalen) { + return zxerr_unknown; + } if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; + return zxerr_unknown; } + MEMZERO(buffer, bufferLen); uint8_t hash[HASH_SIZE] = {0}; - if (MEMCMP(hash, - txdata + start_sighashdata() + SAPLING_INDEX_HASH_JOINSPLITSHASH, - HASH_SIZE) != 0) { - return zxerr_unknown; + size_t sapling_outputs_hash_offset = 0; + + if (tx_version == TX_VERSION_SAPLING) { + v4_transparent_outputs_hash(hash); + sapling_outputs_hash_offset = SAPLING_INDEX_HASH_OUTPUTSHASH; + } else if (tx_version == TX_VERSION_NU5) { + nu5_transparent_outputs_hash(hash); + sapling_outputs_hash_offset = NU5_INDEX_HASH_OUTPUTSHASH; + } else { + return zxerr_unknown; + } + + if (MEMCMP(hash, txdata + start_sighashdata() + sapling_outputs_hash_offset, HASH_SIZE) != 0) { + return zxerr_unknown; } - } - return zxerr_ok; + return zxerr_ok; } -// handleCheckandSign step 5/11 -zxerr_t crypto_check_valuebalance(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint8_t tx_version) { - zemu_log_stack("crypto_check_valuebalance"); - MEMZERO(buffer, bufferLen); - - if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; - } - parser_context_t pars_ctx; - parser_error_t pars_err; - size_t value_balance_offset = 0; - if (tx_version == TX_VERSION_SAPLING) { - value_balance_offset = SAPLING_INDEX_HASH_VALUEBALANCE; - } else if (tx_version == TX_VERSION_NU5) { - value_balance_offset = NU5_INDEX_HASH_VALUEBALANCE; - } else { - return zxerr_unknown; - } - pars_ctx.offset = 0; - pars_ctx.buffer = txdata + start_sighashdata() + value_balance_offset; - pars_ctx.bufferLen = 8; - int64_t v = 0; - pars_err = _readInt64(&pars_ctx, &v); - if (pars_err != parser_ok) { - return 0; - } - - int64_t valuebalance = get_valuebalance(); - int64_t *value_flash = (int64_t *)&valuebalance; - if (MEMCMP(&v, value_flash, 8) != 0) { - return zxerr_unknown; - } - return zxerr_ok; +// handleCheckandSign step 4/11 +zxerr_t crypto_check_joinsplits(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version) { + if (tx_version == TX_VERSION_SAPLING) { + zemu_log_stack("crypto_check_joinsplits"); + MEMZERO(buffer, bufferLen); + + if (get_state() != STATE_CHECKING_ALL_TXDATA) { + return zxerr_unknown; + } + + uint8_t hash[HASH_SIZE] = {0}; + if (MEMCMP(hash, txdata + start_sighashdata() + SAPLING_INDEX_HASH_JOINSPLITSHASH, HASH_SIZE) != 0) { + return zxerr_unknown; + } + } + return zxerr_ok; } -typedef struct { - union { - struct { - uint8_t pedersen_input[PEDERSEN_INPUT_SIZE]; - }; - struct { - uint8_t pedersen_hash[HASH_SIZE]; - }; +// handleCheckandSign step 5/11 +zxerr_t crypto_check_valuebalance(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version) { + zemu_log_stack("crypto_check_valuebalance"); + MEMZERO(buffer, bufferLen); - struct { - uint8_t ncm_full[NOTE_COMMITMENT_SIZE]; - }; - struct { - uint8_t nf[NULLIFIER_SIZE]; - }; + if (get_state() != STATE_CHECKING_ALL_TXDATA) { + return zxerr_unknown; + } + parser_context_t pars_ctx; + parser_error_t pars_err; + size_t value_balance_offset = 0; + if (tx_version == TX_VERSION_SAPLING) { + value_balance_offset = SAPLING_INDEX_HASH_VALUEBALANCE; + } else if (tx_version == TX_VERSION_NU5) { + value_balance_offset = NU5_INDEX_HASH_VALUEBALANCE; + } else { + return zxerr_unknown; + } + pars_ctx.offset = 0; + pars_ctx.buffer = txdata + start_sighashdata() + value_balance_offset; + pars_ctx.bufferLen = 8; + int64_t v = 0; + pars_err = _readInt64(&pars_ctx, &v); + if (pars_err != parser_ok) { + return 0; + } - struct { - uint8_t spend_hash[HASH_SIZE]; + int64_t valuebalance = get_valuebalance(); + int64_t *value_flash = (int64_t *)&valuebalance; + if (MEMCMP(&v, value_flash, 8) != 0) { + return zxerr_unknown; + } + return zxerr_ok; +} + +typedef struct { + union { + struct { + uint8_t pedersen_input[PEDERSEN_INPUT_SIZE]; + }; + struct { + uint8_t pedersen_hash[HASH_SIZE]; + }; + + struct { + uint8_t ncm_full[NOTE_COMMITMENT_SIZE]; + }; + struct { + uint8_t nf[NULLIFIER_SIZE]; + }; + + struct { + uint8_t spend_hash[HASH_SIZE]; + }; }; - }; } tmp_buf_checkspend; typedef struct { - union { - // STEP 1 - struct { - uint8_t zip32_seed[ZIP32_SEED_SIZE]; - } step1; - - struct { - uint8_t ask[ASK_SIZE]; - uint8_t nsk[NSK_SIZE]; - } step2; - - struct { - uint8_t rk[PUB_KEY_SIZE]; - uint8_t nsk[NSK_SIZE]; - } step3; - - struct { - uint8_t cv[VALUE_COMMITMENT_SIZE]; - uint8_t nsk[NSK_SIZE]; - } step4; - }; + union { + // STEP 1 + struct { + uint8_t zip32_seed[ZIP32_SEED_SIZE]; + } step1; + + struct { + uint8_t ask[ASK_SIZE]; + uint8_t nsk[NSK_SIZE]; + } step2; + + struct { + uint8_t rk[PUB_KEY_SIZE]; + uint8_t nsk[NSK_SIZE]; + } step3; + + struct { + uint8_t cv[VALUE_COMMITMENT_SIZE]; + uint8_t nsk[NSK_SIZE]; + } step4; + }; } tmp_checkspend; // handleCheckandSign step 6/11 -zxerr_t crypto_checkspend_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen, - const uint8_t tx_version) { - zemu_log_stack("crypto_checkspend_sapling"); - MEMZERO(buffer, bufferLen); - - const size_t length_hash_data = (tx_version == TX_VERSION_SAPLING) - ? SAPLING_LENGTH_HASH_DATA - : NU5_LENGTH_HASH_DATA; - - if (length_t_in_data() + length_spenddata() + length_outputdata() + - length_hash_data != - txdatalen) { - return zxerr_unknown; - } +zxerr_t crypto_checkspend_sapling( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version) { + zemu_log_stack("crypto_checkspend_sapling"); + MEMZERO(buffer, bufferLen); - if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; - } + const size_t length_hash_data = (tx_version == TX_VERSION_SAPLING) ? SAPLING_LENGTH_HASH_DATA : NU5_LENGTH_HASH_DATA; - uint8_t *out = buffer; - tmp_buf_checkspend *const tmp_buf = (tmp_buf_checkspend *)buffer; + if (length_t_in_data() + length_spenddata() + length_outputdata() + length_hash_data != txdatalen) { + return zxerr_unknown; + } - uint8_t *start_spenddata = - (uint8_t *)(txdata + length_t_in_data() + length_spend_old_data()); - uint8_t *start_spendolddata = (uint8_t *)(txdata + length_t_in_data()); + if (get_state() != STATE_CHECKING_ALL_TXDATA) { + return zxerr_unknown; + } - tmp_checkspend tmp = {0}; + uint8_t *out = buffer; + tmp_buf_checkspend *const tmp_buf = (tmp_buf_checkspend *)buffer; - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - const uint8_t spendListSize = spendlist_len(); + uint8_t *start_spenddata = (uint8_t *)(txdata + length_t_in_data() + length_spend_old_data()); + uint8_t *start_spendolddata = (uint8_t *)(txdata + length_t_in_data()); - for (uint8_t i = 0; i < spendListSize; i++) { - CHECK_ZXERROR_AND_CLEAN(crypto_fillSaplingSeed(tmp.step1.zip32_seed)) - const spend_item_t *item = spendlist_retrieve_item(i); - if (item == NULL) { - return zxerr_unknown; - } + tmp_checkspend tmp = {0}; - // we later need nsk - zip32_child_ask_nsk(tmp.step1.zip32_seed, tmp.step2.ask, tmp.step2.nsk, - item->path); - io_seproxyhal_io_heartbeat(); + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + const uint8_t spendListSize = spendlist_len(); + + for (uint8_t i = 0; i < spendListSize; i++) { + CHECK_ZXERROR_AND_CLEAN(crypto_fillSaplingSeed(tmp.step1.zip32_seed)) + const spend_item_t *item = spendlist_retrieve_item(i); + if (item == NULL) { + return zxerr_unknown; + } + + // we later need nsk + zip32_child_ask_nsk(tmp.step1.zip32_seed, tmp.step2.ask, tmp.step2.nsk, item->path); + io_seproxyhal_io_heartbeat(); + + get_rk(tmp.step2.ask, (uint8_t *)item->alpha, tmp.step3.rk); + if (MEMCMP(tmp.step3.rk, start_spenddata + INDEX_SPEND_RK + i * SPEND_TX_LEN, PUB_KEY_SIZE) != 0) { + CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + } + + // step4.cv = step3.rk. + compute_value_commitment(item->value, item->rcmvalue, tmp.step4.cv); + if (MEMCMP(tmp.step4.cv, start_spenddata + INDEX_SPEND_VALUECMT + i * SPEND_TX_LEN, VALUE_COMMITMENT_SIZE) != 0) { + CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + } + io_seproxyhal_io_heartbeat(); + + compute_note_commitment_fullpoint(tmp_buf->pedersen_hash, + start_spendolddata + INDEX_SPEND_OLD_RCM + i * SPEND_OLD_TX_LEN, item->value, + item->div, item->pkd); + + uint64_t notepos = 0; + { + parser_context_t pars_ctx; + parser_error_t pars_err; + + pars_ctx.offset = 0; + pars_ctx.buffer = start_spendolddata + INDEX_SPEND_OLD_NOTEPOS + i * SPEND_OLD_TX_LEN; + pars_ctx.bufferLen = 8; + pars_err = _readUInt64(&pars_ctx, ¬epos); + if (pars_err != parser_ok) { + CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + } + } + compute_nullifier(tmp_buf->ncm_full, notepos, tmp.step4.nsk, tmp_buf->nf); + if (MEMCMP(tmp_buf->nf, start_spenddata + INDEX_SPEND_NF + i * SPEND_TX_LEN, NULLIFIER_SIZE) != 0) { + CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + } - get_rk(tmp.step2.ask, (uint8_t *)item->alpha, tmp.step3.rk); - if (MEMCMP(tmp.step3.rk, - start_spenddata + INDEX_SPEND_RK + i * SPEND_TX_LEN, - PUB_KEY_SIZE) != 0) { - CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + MEMZERO(out, bufferLen); + MEMZERO(&tmp, sizeof(tmp_checkspend)); } - // step4.cv = step3.rk. - compute_value_commitment(item->value, item->rcmvalue, tmp.step4.cv); - if (MEMCMP(tmp.step4.cv, - start_spenddata + INDEX_SPEND_VALUECMT + i * SPEND_TX_LEN, - VALUE_COMMITMENT_SIZE) != 0) { - CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + size_t sapling_spend_offset = 0; + if (tx_version == TX_VERSION_SAPLING) { + if (spendlist_len() > 0) { + shielded_spend_hash(start_spenddata, length_spend_new_data(), tmp_buf->spend_hash); + } + sapling_spend_offset = SAPLING_INDEX_HASH_SHIELDEDSPENDHASH; + } else if (tx_version == TX_VERSION_NU5) { + nu5_hash_sapling_spends(start_spenddata, tmp_buf->spend_hash); + sapling_spend_offset = NU5_INDEX_HASH_SHIELDEDSPENDHASH; + } else { + CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) } - io_seproxyhal_io_heartbeat(); - compute_note_commitment_fullpoint(tmp_buf->pedersen_hash, - start_spendolddata + INDEX_SPEND_OLD_RCM + - i * SPEND_OLD_TX_LEN, - item->value, item->div, item->pkd); - - uint64_t notepos = 0; - { - parser_context_t pars_ctx; - parser_error_t pars_err; - - pars_ctx.offset = 0; - pars_ctx.buffer = - start_spendolddata + INDEX_SPEND_OLD_NOTEPOS + i * SPEND_OLD_TX_LEN; - pars_ctx.bufferLen = 8; - pars_err = _readUInt64(&pars_ctx, ¬epos); - if (pars_err != parser_ok) { + if (MEMCMP(tmp_buf->spend_hash, txdata + start_sighashdata() + sapling_spend_offset, HASH_SIZE) != 0) { CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) - } - } - compute_nullifier(tmp_buf->ncm_full, notepos, tmp.step4.nsk, tmp_buf->nf); - if (MEMCMP(tmp_buf->nf, start_spenddata + INDEX_SPEND_NF + i * SPEND_TX_LEN, - NULLIFIER_SIZE) != 0) { - CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) } - MEMZERO(out, bufferLen); - MEMZERO(&tmp, sizeof(tmp_checkspend)); - } - - size_t sapling_spend_offset = 0; - if (tx_version == TX_VERSION_SAPLING) { - if (spendlist_len() > 0) { - shielded_spend_hash(start_spenddata, length_spend_new_data(), - tmp_buf->spend_hash); - } - sapling_spend_offset = SAPLING_INDEX_HASH_SHIELDEDSPENDHASH; - } else if (tx_version == TX_VERSION_NU5) { - nu5_hash_sapling_spends(start_spenddata, tmp_buf->spend_hash); - sapling_spend_offset = NU5_INDEX_HASH_SHIELDEDSPENDHASH; - } else { - CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) - } - - if (MEMCMP(tmp_buf->spend_hash, - txdata + start_sighashdata() + sapling_spend_offset, - HASH_SIZE) != 0) { - CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) - } - MEMZERO(out, bufferLen); - - return zxerr_ok; // or some code for ok + + return zxerr_ok; // or some code for ok } typedef struct { - uint8_t shielded_output_hash[HASH_SIZE]; + uint8_t shielded_output_hash[HASH_SIZE]; } tmp_buf_checkoutput; typedef struct { - union { - struct { - uint8_t gd[GD_SIZE]; // computed from receiver diversifier - uint8_t pkd[PKD_SIZE]; // get this from host and show on screen for - // verification - } step2; - - struct { - uint8_t pedersen_input[PEDERSEN_INPUT_SIZE]; - } step3; - - struct { - uint8_t notecommitment[NOTE_COMMITMENT_SIZE]; - uint8_t valuecommitment[VALUE_COMMITMENT_SIZE]; - } step4; - }; + union { + struct { + uint8_t gd[GD_SIZE]; // computed from receiver diversifier + uint8_t pkd[PKD_SIZE]; // get this from host and show on screen for + // verification + } step2; + + struct { + uint8_t pedersen_input[PEDERSEN_INPUT_SIZE]; + } step3; + + struct { + uint8_t notecommitment[NOTE_COMMITMENT_SIZE]; + uint8_t valuecommitment[VALUE_COMMITMENT_SIZE]; + } step4; + }; } tmp_checkoutput; // handleCheckandSign step 7/11 -zxerr_t crypto_checkoutput_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen, - const uint8_t tx_version) { - zemu_log_stack("crypto_checkoutput_sapling"); - MEMZERO(buffer, bufferLen); - - if (get_state() != STATE_CHECKING_ALL_TXDATA) { - return zxerr_unknown; - } - - const size_t length_hash_data = (tx_version == TX_VERSION_SAPLING) - ? SAPLING_LENGTH_HASH_DATA - : NU5_LENGTH_HASH_DATA; - if (length_t_in_data() + length_spenddata() + length_outputdata() + - length_hash_data != - txdatalen) { - return zxerr_unknown; - } - - const uint8_t *start_outputdata = - (uint8_t *)(txdata + length_t_in_data() + length_spenddata()); - - zemu_log_stack("crypto_checkoutput_sapling"); - - tmp_checkoutput ncm = {0}; - - uint8_t rcm[RCM_SIZE] = {0}; - - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - const uint8_t outputListLen = outputlist_len(); - for (uint8_t i = 0; i < outputListLen; i++) { - const output_item_t *item = outputlist_retrieve_item(i); - if (item == NULL) { - MEMZERO(&ncm, sizeof(tmp_checkoutput)); - return zxerr_unknown; - } - - rseed_get_rcm(item->rseed, rcm); - io_seproxyhal_io_heartbeat(); - - compute_note_commitment(ncm.step4.notecommitment, rcm, item->value, - item->div, item->pkd); - io_seproxyhal_io_heartbeat(); - - compute_value_commitment(item->value, item->rcmvalue, - ncm.step4.valuecommitment); - io_seproxyhal_io_heartbeat(); +zxerr_t crypto_checkoutput_sapling( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version) { + zemu_log_stack("crypto_checkoutput_sapling"); + MEMZERO(buffer, bufferLen); - if (MEMCMP(ncm.step4.valuecommitment, - start_outputdata + INDEX_OUTPUT_VALUECMT + i * OUTPUT_TX_LEN, - VALUE_COMMITMENT_SIZE) != 0) { - MEMZERO(&ncm, sizeof(tmp_checkoutput)); - return zxerr_unknown; + if (get_state() != STATE_CHECKING_ALL_TXDATA) { + return zxerr_unknown; } - if (MEMCMP(ncm.step4.notecommitment, - start_outputdata + INDEX_OUTPUT_NOTECMT + i * OUTPUT_TX_LEN, - NOTE_COMMITMENT_SIZE) != 0) { - MEMZERO(&ncm, sizeof(tmp_checkoutput)); - return zxerr_unknown; + const size_t length_hash_data = (tx_version == TX_VERSION_SAPLING) ? SAPLING_LENGTH_HASH_DATA : NU5_LENGTH_HASH_DATA; + if (length_t_in_data() + length_spenddata() + length_outputdata() + length_hash_data != txdatalen) { + return zxerr_unknown; } - MEMZERO(&ncm, sizeof(tmp_checkoutput)); - } + const uint8_t *start_outputdata = (uint8_t *)(txdata + length_t_in_data() + length_spenddata()); + + zemu_log_stack("crypto_checkoutput_sapling"); + + tmp_checkoutput ncm = {0}; - tmp_buf_checkoutput *const tmp_buf = (tmp_buf_checkoutput *)buffer; + uint8_t rcm[RCM_SIZE] = {0}; - size_t sapling_output_offset = 0; - if (tx_version == TX_VERSION_SAPLING) { - if (outputlist_len() > 0) { - shielded_output_hash(start_outputdata, length_outputdata(), - tmp_buf->shielded_output_hash); + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + const uint8_t outputListLen = outputlist_len(); + for (uint8_t i = 0; i < outputListLen; i++) { + const output_item_t *item = outputlist_retrieve_item(i); + if (item == NULL) { + MEMZERO(&ncm, sizeof(tmp_checkoutput)); + return zxerr_unknown; + } + + rseed_get_rcm(item->rseed, rcm); + io_seproxyhal_io_heartbeat(); + + compute_note_commitment(ncm.step4.notecommitment, rcm, item->value, item->div, item->pkd); + io_seproxyhal_io_heartbeat(); + + compute_value_commitment(item->value, item->rcmvalue, ncm.step4.valuecommitment); + io_seproxyhal_io_heartbeat(); + + if (MEMCMP(ncm.step4.valuecommitment, start_outputdata + INDEX_OUTPUT_VALUECMT + i * OUTPUT_TX_LEN, + VALUE_COMMITMENT_SIZE) != 0) { + MEMZERO(&ncm, sizeof(tmp_checkoutput)); + return zxerr_unknown; + } + + if (MEMCMP(ncm.step4.notecommitment, start_outputdata + INDEX_OUTPUT_NOTECMT + i * OUTPUT_TX_LEN, + NOTE_COMMITMENT_SIZE) != 0) { + MEMZERO(&ncm, sizeof(tmp_checkoutput)); + return zxerr_unknown; + } + + MEMZERO(&ncm, sizeof(tmp_checkoutput)); } - sapling_output_offset = SAPLING_INDEX_HASH_SHIELDEDOUTPUTHASH; - } else if (tx_version == TX_VERSION_NU5) { - nu5_hash_sapling_outputs(start_outputdata, tmp_buf->shielded_output_hash); - sapling_output_offset = NU5_INDEX_HASH_SHIELDEDOUTPUTHASH; - } else { - return zxerr_unknown; - } - if (MEMCMP(tmp_buf->shielded_output_hash, - txdata + start_sighashdata() + sapling_output_offset, - HASH_SIZE) != 0) { - return zxerr_unknown; - } + tmp_buf_checkoutput *const tmp_buf = (tmp_buf_checkoutput *)buffer; + + size_t sapling_output_offset = 0; + if (tx_version == TX_VERSION_SAPLING) { + if (outputlist_len() > 0) { + shielded_output_hash(start_outputdata, length_outputdata(), tmp_buf->shielded_output_hash); + } + sapling_output_offset = SAPLING_INDEX_HASH_SHIELDEDOUTPUTHASH; + } else if (tx_version == TX_VERSION_NU5) { + nu5_hash_sapling_outputs(start_outputdata, tmp_buf->shielded_output_hash); + sapling_output_offset = NU5_INDEX_HASH_SHIELDEDOUTPUTHASH; + } else { + return zxerr_unknown; + } + + if (MEMCMP(tmp_buf->shielded_output_hash, txdata + start_sighashdata() + sapling_output_offset, HASH_SIZE) != 0) { + return zxerr_unknown; + } - return zxerr_ok; // or some code for ok + return zxerr_ok; // or some code for ok } typedef struct { - union { - // STEP 1 - struct { // MAX SIZE --> 160 - uint8_t dummy[MAX_SIZE - EPK_SIZE - ESK_SIZE]; - uint8_t epk[EPK_SIZE]; // computed from receiver diversifier - uint8_t esk[ESK_SIZE]; - } step1; - - struct { - uint8_t chachanonce[CHACHA_NONCE_SIZE]; - uint8_t compactout[COMPACT_OUT_SIZE]; - uint8_t sharedkey[SHARED_KEY_SIZE]; - uint8_t epk[EPK_SIZE]; - uint8_t esk[ESK_SIZE]; - } step2; - - struct { - uint8_t dummy[MAX_SIZE - OVK_SIZE - VALUE_COMMITMENT_SIZE - - NOTE_COMMITMENT_SIZE - EPK_SIZE - ESK_SIZE]; - uint8_t ovk[OVK_SIZE]; - uint8_t valuecmt[VALUE_COMMITMENT_SIZE]; - uint8_t notecmt[NOTE_COMMITMENT_SIZE]; - uint8_t epk[EPK_SIZE]; - uint8_t esk[ESK_SIZE]; - } step3; - - struct { - uint8_t dummy[MAX_SIZE - PRF_INPUT_SIZE - ESK_SIZE]; - uint8_t prfinput[PRF_INPUT_SIZE]; - uint8_t esk[ESK_SIZE]; - } step4; - - struct { - uint8_t outkey[OUT_KEY_SIZE]; - uint8_t dummy[MAX_SIZE - OUT_KEY_SIZE - PKD_SIZE - ESK_SIZE]; - uint8_t pkd[PKD_SIZE]; - uint8_t esk[ESK_SIZE]; - } step5; - - struct { - uint8_t outkey[OUT_KEY_SIZE]; - uint8_t - dummy[MAX_SIZE - OUT_KEY_SIZE - ENC_CIPHER_SIZE - CHACHA_NONCE_SIZE]; - uint8_t chachanonce[CHACHA_NONCE_SIZE]; - uint8_t encciph[ENC_CIPHER_SIZE]; - } step6; - - struct { - uint8_t hashseed[OVK_SET_SIZE]; - uint8_t outkey[OUT_KEY_SIZE]; - uint8_t encciph_part1[ENC_CIPHER_HALVE_SIZE]; - uint8_t encciph_part2[ENC_CIPHER_HALVE_SIZE]; - uint8_t chachanonce[CHACHA_NONCE_SIZE]; - } step3b; - struct { - uint8_t hashseed[OVK_SET_SIZE]; - uint8_t outkey[OUT_KEY_SIZE]; - uint8_t encciph[ENC_CIPHER_SIZE]; - uint8_t chachanonce[CHACHA_NONCE_SIZE]; - } step4b; - }; + union { + // STEP 1 + struct { // MAX SIZE --> 160 + uint8_t dummy[MAX_SIZE - EPK_SIZE - ESK_SIZE]; + uint8_t epk[EPK_SIZE]; // computed from receiver diversifier + uint8_t esk[ESK_SIZE]; + } step1; + + struct { + uint8_t chachanonce[CHACHA_NONCE_SIZE]; + uint8_t compactout[COMPACT_OUT_SIZE]; + uint8_t sharedkey[SHARED_KEY_SIZE]; + uint8_t epk[EPK_SIZE]; + uint8_t esk[ESK_SIZE]; + } step2; + + struct { + uint8_t dummy[MAX_SIZE - OVK_SIZE - VALUE_COMMITMENT_SIZE - NOTE_COMMITMENT_SIZE - EPK_SIZE - ESK_SIZE]; + uint8_t ovk[OVK_SIZE]; + uint8_t valuecmt[VALUE_COMMITMENT_SIZE]; + uint8_t notecmt[NOTE_COMMITMENT_SIZE]; + uint8_t epk[EPK_SIZE]; + uint8_t esk[ESK_SIZE]; + } step3; + + struct { + uint8_t dummy[MAX_SIZE - PRF_INPUT_SIZE - ESK_SIZE]; + uint8_t prfinput[PRF_INPUT_SIZE]; + uint8_t esk[ESK_SIZE]; + } step4; + + struct { + uint8_t outkey[OUT_KEY_SIZE]; + uint8_t dummy[MAX_SIZE - OUT_KEY_SIZE - PKD_SIZE - ESK_SIZE]; + uint8_t pkd[PKD_SIZE]; + uint8_t esk[ESK_SIZE]; + } step5; + + struct { + uint8_t outkey[OUT_KEY_SIZE]; + uint8_t dummy[MAX_SIZE - OUT_KEY_SIZE - ENC_CIPHER_SIZE - CHACHA_NONCE_SIZE]; + uint8_t chachanonce[CHACHA_NONCE_SIZE]; + uint8_t encciph[ENC_CIPHER_SIZE]; + } step6; + + struct { + uint8_t hashseed[OVK_SET_SIZE]; + uint8_t outkey[OUT_KEY_SIZE]; + uint8_t encciph_part1[ENC_CIPHER_HALVE_SIZE]; + uint8_t encciph_part2[ENC_CIPHER_HALVE_SIZE]; + uint8_t chachanonce[CHACHA_NONCE_SIZE]; + } step3b; + struct { + uint8_t hashseed[OVK_SET_SIZE]; + uint8_t outkey[OUT_KEY_SIZE]; + uint8_t encciph[ENC_CIPHER_SIZE]; + uint8_t chachanonce[CHACHA_NONCE_SIZE]; + } step4b; + }; } tmp_enc; // handleCheckandSign step 8/11 -zxerr_t crypto_checkencryptions_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata) { - zemu_log_stack("crypto_checkencryptions_sapling"); - MEMZERO(buffer, bufferLen); - tmp_enc *tmp = (tmp_enc *)buffer; - - const uint8_t *start_outputdata = - (uint8_t *)(txdata + length_t_in_data() + length_spenddata()); - - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - for (uint8_t i = 0; i < outputlist_len(); i++) { - // retrieve info on list of outputs stored in flash - const output_item_t *item = outputlist_retrieve_item(i); - if (item == NULL) { - return zxerr_unknown; - } - // compute random ephemeral private and public keys (esk,epk) from seed and - // diversifier - rseed_get_esk_epk(item->rseed, (uint8_t *)item->div, tmp->step1.esk, - tmp->step1.epk); - CHECK_APP_CANARY() - - // compare the computed epk to that provided in the transaction data - if (MEMCMP(tmp->step1.epk, - start_outputdata + INDEX_OUTPUT_EPK + i * OUTPUT_TX_LEN, - EPK_SIZE) != 0) { - return zxerr_unknown; - } +zxerr_t crypto_checkencryptions_sapling(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata) { + zemu_log_stack("crypto_checkencryptions_sapling"); + MEMZERO(buffer, bufferLen); + tmp_enc *tmp = (tmp_enc *)buffer; - // get shared key (used as encryption key) from esk, epk and pkd - ka_to_key(tmp->step1.esk, (uint8_t *)item->pkd, tmp->step1.epk, - tmp->step2.sharedkey); - CHECK_APP_CANARY() - // encode (div, value rseed and memotype) into step2.compactout ready to be - // encrypted - prepare_enccompact_input((uint8_t *)item->div, item->value, - (uint8_t *)item->rseed, item->memotype, - tmp->step2.compactout); - CHECK_APP_CANARY() - MEMZERO(tmp->step2.chachanonce, CHACHA_NONCE_SIZE); - // encrypt the previously obtained encoding, and store it in - // step2.compactoutput (reusing the same memory for input and output) - chacha(tmp->step2.compactout, tmp->step2.compactout, COMPACT_OUT_SIZE, - tmp->step2.sharedkey, tmp->step2.chachanonce, 1); - CHECK_APP_CANARY() - // check that the computed encryption is the same as that provided in the - // transaction data - if (MEMCMP(tmp->step2.compactout, - start_outputdata + INDEX_OUTPUT_ENC + i * OUTPUT_TX_LEN, - COMPACT_OUT_SIZE) != 0) { - return zxerr_unknown; - } - - // if an ovk was provided - if (item->ovk[0] != 0x00) { - // copy ovk, the value commitment and note-commitment from flash memory - // and transaction to local tmp structure so as to hash - MEMCPY(tmp->step3.ovk, item->ovk + 1, OVK_SIZE); - MEMCPY(tmp->step3.valuecmt, - start_outputdata + INDEX_OUTPUT_VALUECMT + i * OUTPUT_TX_LEN, - VALUE_COMMITMENT_SIZE); - MEMCPY(tmp->step3.notecmt, - start_outputdata + INDEX_OUTPUT_NOTECMT + i * OUTPUT_TX_LEN, - NOTE_COMMITMENT_SIZE); - // Note that tmp->step4.prfinput is the same memory chunk as the - // concatenation of tmp->step3.ovk || tmp->step3.valuecmt || - // tmp->step3.notecmt || tmp->step3.epk so next we hash that - // concatenation, and store hash in tmp->step5.outkey - blake2b_prf(tmp->step4.prfinput, tmp->step5.outkey); - CHECK_APP_CANARY() - - // get pkd from flash memory, store it in tmp->step5.pkd - MEMCPY(tmp->step5.pkd, item->pkd, PKD_SIZE); - - MEMZERO(tmp->step6.chachanonce, CHACHA_NONCE_SIZE); - - // tmp->step6.encciph = tmp->step5.pkd || tmp->step5.esk - // encrypt that, using as encryption key the output of the blake2b PRF - // store resulting ciphertext in tmp->step6.encciph - chacha(tmp->step6.encciph, tmp->step6.encciph, ENC_CIPHER_SIZE, - tmp->step6.outkey, tmp->step6.chachanonce, 1); - CHECK_APP_CANARY() - - // check that the computed encryption is the same as that provided in the - // transaction data - if (MEMCMP(tmp->step6.encciph, - start_outputdata + INDEX_OUTPUT_OUT + i * OUTPUT_TX_LEN, - ENC_CIPHER_SIZE) != 0) { - return zxerr_unknown; - } + const uint8_t *start_outputdata = (uint8_t *)(txdata + length_t_in_data() + length_spenddata()); - // if no ovk was provided - } else { - // copy the contents of flash memory for ovk, and hash it. This hash will - // be the encryption key - MEMCPY(tmp->step3b.hashseed, item->ovk, OVK_SET_SIZE); - cx_hash_sha256(tmp->step3b.hashseed, OVK_SET_SIZE, tmp->step3b.outkey, - CX_SHA256_SIZE); - // replace the first 0x00 of the copied ovk with 0x01, hash again, this - // will be the first half of the plaintext to encrypt - tmp->step3b.hashseed[0] = 0x01; - cx_hash_sha256(tmp->step3b.hashseed, OVK_SET_SIZE, - tmp->step3b.encciph_part1, CX_SHA256_SIZE); - // replace the first 0x01 of the copied ovk with 0x02, hash again, this - // will be the second half of the plaintext to encrypt - tmp->step3b.hashseed[0] = 0x02; - cx_hash_sha256(tmp->step3b.hashseed, OVK_SET_SIZE, - tmp->step3b.encciph_part2, CX_SHA256_SIZE); - MEMZERO(tmp->step3b.chachanonce, CHACHA_NONCE_SIZE); - // tmp->step4b.encciph = tmp->step3b.encciph_part1 || - // tmp->step3b.encciph_part2 encrypt and compare computed encryption to - // that provided in the transaction data - chacha(tmp->step4b.encciph, tmp->step4b.encciph, ENC_CIPHER_SIZE, - tmp->step4b.outkey, tmp->step4b.chachanonce, 1); - if (MEMCMP(tmp->step4b.encciph, - start_outputdata + INDEX_OUTPUT_OUT + i * OUTPUT_TX_LEN, - ENC_CIPHER_SIZE) != 0) { - return zxerr_unknown; - } + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + for (uint8_t i = 0; i < outputlist_len(); i++) { + // retrieve info on list of outputs stored in flash + const output_item_t *item = outputlist_retrieve_item(i); + if (item == NULL) { + return zxerr_unknown; + } + // compute random ephemeral private and public keys (esk,epk) from seed and + // diversifier + rseed_get_esk_epk(item->rseed, (uint8_t *)item->div, tmp->step1.esk, tmp->step1.epk); + CHECK_APP_CANARY() + + // compare the computed epk to that provided in the transaction data + if (MEMCMP(tmp->step1.epk, start_outputdata + INDEX_OUTPUT_EPK + i * OUTPUT_TX_LEN, EPK_SIZE) != 0) { + return zxerr_unknown; + } + + // get shared key (used as encryption key) from esk, epk and pkd + ka_to_key(tmp->step1.esk, (uint8_t *)item->pkd, tmp->step1.epk, tmp->step2.sharedkey); + CHECK_APP_CANARY() + // encode (div, value rseed and memotype) into step2.compactout ready to be + // encrypted + prepare_enccompact_input((uint8_t *)item->div, item->value, (uint8_t *)item->rseed, item->memotype, + tmp->step2.compactout); + CHECK_APP_CANARY() + MEMZERO(tmp->step2.chachanonce, CHACHA_NONCE_SIZE); + // encrypt the previously obtained encoding, and store it in + // step2.compactoutput (reusing the same memory for input and output) + chacha(tmp->step2.compactout, tmp->step2.compactout, COMPACT_OUT_SIZE, tmp->step2.sharedkey, tmp->step2.chachanonce, + 1); + CHECK_APP_CANARY() + // check that the computed encryption is the same as that provided in the + // transaction data + if (MEMCMP(tmp->step2.compactout, start_outputdata + INDEX_OUTPUT_ENC + i * OUTPUT_TX_LEN, COMPACT_OUT_SIZE) != 0) { + return zxerr_unknown; + } + + // if an ovk was provided + if (item->ovk[0] != 0x00) { + // copy ovk, the value commitment and note-commitment from flash memory + // and transaction to local tmp structure so as to hash + MEMCPY(tmp->step3.ovk, item->ovk + 1, OVK_SIZE); + MEMCPY(tmp->step3.valuecmt, start_outputdata + INDEX_OUTPUT_VALUECMT + i * OUTPUT_TX_LEN, VALUE_COMMITMENT_SIZE); + MEMCPY(tmp->step3.notecmt, start_outputdata + INDEX_OUTPUT_NOTECMT + i * OUTPUT_TX_LEN, NOTE_COMMITMENT_SIZE); + // Note that tmp->step4.prfinput is the same memory chunk as the + // concatenation of tmp->step3.ovk || tmp->step3.valuecmt || + // tmp->step3.notecmt || tmp->step3.epk so next we hash that + // concatenation, and store hash in tmp->step5.outkey + blake2b_prf(tmp->step4.prfinput, tmp->step5.outkey); + CHECK_APP_CANARY() + + // get pkd from flash memory, store it in tmp->step5.pkd + MEMCPY(tmp->step5.pkd, item->pkd, PKD_SIZE); + + MEMZERO(tmp->step6.chachanonce, CHACHA_NONCE_SIZE); + + // tmp->step6.encciph = tmp->step5.pkd || tmp->step5.esk + // encrypt that, using as encryption key the output of the blake2b PRF + // store resulting ciphertext in tmp->step6.encciph + chacha(tmp->step6.encciph, tmp->step6.encciph, ENC_CIPHER_SIZE, tmp->step6.outkey, tmp->step6.chachanonce, 1); + CHECK_APP_CANARY() + + // check that the computed encryption is the same as that provided in the + // transaction data + if (MEMCMP(tmp->step6.encciph, start_outputdata + INDEX_OUTPUT_OUT + i * OUTPUT_TX_LEN, ENC_CIPHER_SIZE) != 0) { + return zxerr_unknown; + } + + // if no ovk was provided + } else { + // copy the contents of flash memory for ovk, and hash it. This hash will + // be the encryption key + MEMCPY(tmp->step3b.hashseed, item->ovk, OVK_SET_SIZE); + cx_hash_sha256(tmp->step3b.hashseed, OVK_SET_SIZE, tmp->step3b.outkey, CX_SHA256_SIZE); + // replace the first 0x00 of the copied ovk with 0x01, hash again, this + // will be the first half of the plaintext to encrypt + tmp->step3b.hashseed[0] = 0x01; + cx_hash_sha256(tmp->step3b.hashseed, OVK_SET_SIZE, tmp->step3b.encciph_part1, CX_SHA256_SIZE); + // replace the first 0x01 of the copied ovk with 0x02, hash again, this + // will be the second half of the plaintext to encrypt + tmp->step3b.hashseed[0] = 0x02; + cx_hash_sha256(tmp->step3b.hashseed, OVK_SET_SIZE, tmp->step3b.encciph_part2, CX_SHA256_SIZE); + MEMZERO(tmp->step3b.chachanonce, CHACHA_NONCE_SIZE); + // tmp->step4b.encciph = tmp->step3b.encciph_part1 || + // tmp->step3b.encciph_part2 encrypt and compare computed encryption to + // that provided in the transaction data + chacha(tmp->step4b.encciph, tmp->step4b.encciph, ENC_CIPHER_SIZE, tmp->step4b.outkey, tmp->step4b.chachanonce, + 1); + if (MEMCMP(tmp->step4b.encciph, start_outputdata + INDEX_OUTPUT_OUT + i * OUTPUT_TX_LEN, ENC_CIPHER_SIZE) != 0) { + return zxerr_unknown; + } + } + CHECK_APP_CANARY() + MEMZERO(buffer, bufferLen); } - CHECK_APP_CANARY() - MEMZERO(buffer, bufferLen); - } - MEMZERO(buffer, bufferLen); - return zxerr_ok; // or some code for ok + MEMZERO(buffer, bufferLen); + return zxerr_ok; // or some code for ok } static zxerr_t address_to_script(uint8_t *address, uint8_t *output) { - if (address == NULL || output == NULL) { - return zxerr_no_data; - } - - uint8_t script[SCRIPT_SIZE] = {0}; - script[0] = 0x19; - script[1] = 0x76; - script[2] = 0xa9; - script[3] = 0x14; - - uint8_t tmp[HASH_SIZE] = {0}; - cx_hash_sha256(address, PK_LEN_SECP256K1, tmp, CX_SHA256_SIZE); - - CHECK_ZXERR(ripemd160(tmp, CX_SHA256_SIZE, script + SCRIPT_CONSTS_SIZE)); - io_seproxyhal_io_heartbeat(); - - script[24] = 0x88; - script[25] = 0xac; - MEMCPY(output, script, SCRIPT_SIZE); - return zxerr_ok; + if (address == NULL || output == NULL) { + return zxerr_no_data; + } + + uint8_t script[SCRIPT_SIZE] = {0}; + script[0] = 0x19; + script[1] = 0x76; + script[2] = 0xa9; + script[3] = 0x14; + + uint8_t tmp[HASH_SIZE] = {0}; + cx_hash_sha256(address, PK_LEN_SECP256K1, tmp, CX_SHA256_SIZE); + + CHECK_ZXERR(ripemd160(tmp, CX_SHA256_SIZE, script + SCRIPT_CONSTS_SIZE)); + io_seproxyhal_io_heartbeat(); + + script[24] = 0x88; + script[25] = 0xac; + MEMCPY(output, script, SCRIPT_SIZE); + return zxerr_ok; } typedef struct { - union { - // STEP 1 - struct { - uint8_t r[SIG_R_SIZE]; - uint8_t s[SIG_S_SIZE]; - uint8_t v; - // DER signature max size should be 73 - // https://bitcoin.stackexchange.com/questions/77191/what-is-the-maximum-size-of-a-der-encoded-ecdsa-signature#77192 - uint8_t der_signature[DER_MAX_SIZE]; - } step1; - - struct { - uint8_t rs[SIG_R_SIZE + SIG_S_SIZE]; - uint8_t dummy[DER_MAX_SIZE + 1]; - } step2; - }; + union { + // STEP 1 + struct { + uint8_t r[SIG_R_SIZE]; + uint8_t s[SIG_S_SIZE]; + uint8_t v; + // DER signature max size should be 73 + // https://bitcoin.stackexchange.com/questions/77191/what-is-the-maximum-size-of-a-der-encoded-ecdsa-signature#77192 + uint8_t der_signature[DER_MAX_SIZE]; + } step1; + + struct { + uint8_t rs[SIG_R_SIZE + SIG_S_SIZE]; + uint8_t dummy[DER_MAX_SIZE + 1]; + } step2; + }; } __attribute__((packed)) signature_tr; // handleCheckandSign step 9/11 -zxerr_t crypto_sign_and_check_transparent(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen, - const uint8_t tx_version) { - zemu_log_stack("crypto_sign_and_check_transparent"); - if (t_inlist_len() == 0) { - return zxerr_ok; - } - MEMZERO(buffer, bufferLen); - - // todo: not always SAPLING_LENGTH_HASH_DATA - if (length_t_in_data() + length_spenddata() + length_outputdata() + - SAPLING_LENGTH_HASH_DATA != - txdatalen) { - return zxerr_unknown; - } - - if (get_state() != STATE_VERIFIED_ALL_TXDATA) { - return zxerr_unknown; - } - - uint8_t *start_tindata = (uint8_t *)txdata; - uint8_t *start_signdata = (uint8_t *)(txdata + start_sighashdata()); - - uint8_t *out = (uint8_t *)buffer; - MEMZERO(out, bufferLen); - - cx_ecfp_public_key_t cx_publicKey = {0}; - cx_ecfp_private_key_t cx_privateKey = {0}; - uint8_t privateKeyData[64] = {0}; - uint8_t pubKey[PUB_KEY_SIZE + 1] = {0}; - uint8_t script[SCRIPT_SIZE] = {0}; - uint8_t message_digest[HASH_SIZE] = {0}; - - unsigned int info = 0; - signature_tr *const signature = (signature_tr *)buffer; - // Temporarily get sk from Ed25519 - zxerr_t error = zxerr_unknown; - CHECK_APP_CANARY() - const u_int8_t tInListLen = t_inlist_len(); - for (uint8_t i = 0; i < tInListLen; i++) { - const t_input_item_t *item = t_inlist_retrieve_item(i); - - CATCH_CXERROR(os_derive_bip32_no_throw( - CX_CURVE_256K1, item->path, HDPATH_LEN_DEFAULT, privateKeyData, NULL)); - CATCH_CXERROR(cx_ecfp_init_private_key_no_throw( - CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey)); - CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, - &cx_publicKey)); - CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &cx_publicKey, - &cx_privateKey, 1)); - io_seproxyhal_io_heartbeat(); +zxerr_t crypto_sign_and_check_transparent( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version) { + zemu_log_stack("crypto_sign_and_check_transparent"); + if (t_inlist_len() == 0) { + return zxerr_ok; + } + MEMZERO(buffer, bufferLen); + + // todo: not always SAPLING_LENGTH_HASH_DATA + if (length_t_in_data() + length_spenddata() + length_outputdata() + SAPLING_LENGTH_HASH_DATA != txdatalen) { + return zxerr_unknown; + } + + if (get_state() != STATE_VERIFIED_ALL_TXDATA) { + return zxerr_unknown; + } - for (int j = 0; j < PUB_KEY_SIZE; j++) { - pubKey[j] = cx_publicKey.W[SIG_S_SIZE + SIG_R_SIZE - j]; - } - cx_publicKey.W[0] = cx_publicKey.W[SIG_S_SIZE + SIG_R_SIZE] & 1 - ? 0x03 - : 0x02; // "Compress" public key in place - if ((cx_publicKey.W[SIG_R_SIZE] & 1) != 0) { - pubKey[PUB_KEY_SIZE - 1] |= 0x80; - } - MEMCPY(pubKey, cx_publicKey.W, PK_LEN_SECP256K1); - address_to_script(pubKey, script); - if (MEMCMP(script, - (uint8_t *)(start_tindata + INDEX_TIN_SCRIPT + i * T_IN_TX_LEN), - SCRIPT_SIZE) != 0) { - goto catch_cx_error; - } - if (MEMCMP(item->script, script, SCRIPT_SIZE) != 0) { - goto catch_cx_error; - } - - uint64_t value = 0; - { - parser_context_t pars_ctx; - parser_error_t pars_err; - - pars_ctx.offset = 0; - pars_ctx.buffer = start_tindata + INDEX_TIN_VALUE + i * T_IN_TX_LEN; - pars_ctx.bufferLen = 8; - pars_err = _readUInt64(&pars_ctx, &value); - if (pars_err != parser_ok) { - goto catch_cx_error; - } - } - - if (value != item->value) { - goto catch_cx_error; - } - signature_script_hash(start_tindata, start_signdata, - SAPLING_LENGTH_HASH_DATA, - start_tindata + i * T_IN_TX_LEN, T_IN_TX_LEN, i, - tx_version, message_digest); - size_t signatureLen = DER_MAX_SIZE; - CATCH_CXERROR(cx_ecdsa_sign_no_throw( - &cx_privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, message_digest, - CX_SHA256_SIZE, signature->step1.der_signature, &signatureLen, &info)); - - if (convertDERtoRSV(signature->step1.der_signature, info, - signature->step1.r, signature->step1.s, - &signature->step1.v) != no_error || - transparent_signatures_append(signature->step2.rs) != zxerr_ok) { - goto catch_cx_error; - } - } - error = zxerr_ok; + uint8_t *start_tindata = (uint8_t *)txdata; + uint8_t *start_signdata = (uint8_t *)(txdata + start_sighashdata()); + + uint8_t *out = (uint8_t *)buffer; + MEMZERO(out, bufferLen); + + cx_ecfp_public_key_t cx_publicKey = {0}; + cx_ecfp_private_key_t cx_privateKey = {0}; + uint8_t privateKeyData[64] = {0}; + uint8_t pubKey[PUB_KEY_SIZE + 1] = {0}; + uint8_t script[SCRIPT_SIZE] = {0}; + uint8_t message_digest[HASH_SIZE] = {0}; + + unsigned int info = 0; + signature_tr *const signature = (signature_tr *)buffer; + // Temporarily get sk from Ed25519 + zxerr_t error = zxerr_unknown; + CHECK_APP_CANARY() + const u_int8_t tInListLen = t_inlist_len(); + for (uint8_t i = 0; i < tInListLen; i++) { + const t_input_item_t *item = t_inlist_retrieve_item(i); + + CATCH_CXERROR(os_derive_bip32_no_throw(CX_CURVE_256K1, item->path, HDPATH_LEN_DEFAULT, privateKeyData, NULL)); + CATCH_CXERROR(cx_ecfp_init_private_key_no_throw(CX_CURVE_256K1, privateKeyData, SK_SECP256K1_SIZE, &cx_privateKey)); + CATCH_CXERROR(cx_ecfp_init_public_key_no_throw(CX_CURVE_256K1, NULL, 0, &cx_publicKey)); + CATCH_CXERROR(cx_ecfp_generate_pair_no_throw(CX_CURVE_256K1, &cx_publicKey, &cx_privateKey, 1)); + io_seproxyhal_io_heartbeat(); + + for (int j = 0; j < PUB_KEY_SIZE; j++) { + pubKey[j] = cx_publicKey.W[SIG_S_SIZE + SIG_R_SIZE - j]; + } + cx_publicKey.W[0] = cx_publicKey.W[SIG_S_SIZE + SIG_R_SIZE] & 1 ? 0x03 : 0x02; // "Compress" public key in place + if ((cx_publicKey.W[SIG_R_SIZE] & 1) != 0) { + pubKey[PUB_KEY_SIZE - 1] |= 0x80; + } + MEMCPY(pubKey, cx_publicKey.W, PK_LEN_SECP256K1); + address_to_script(pubKey, script); + if (MEMCMP(script, (uint8_t *)(start_tindata + INDEX_TIN_SCRIPT + i * T_IN_TX_LEN), SCRIPT_SIZE) != 0) { + goto catch_cx_error; + } + if (MEMCMP(item->script, script, SCRIPT_SIZE) != 0) { + goto catch_cx_error; + } + + uint64_t value = 0; + { + parser_context_t pars_ctx; + parser_error_t pars_err; + + pars_ctx.offset = 0; + pars_ctx.buffer = start_tindata + INDEX_TIN_VALUE + i * T_IN_TX_LEN; + pars_ctx.bufferLen = 8; + pars_err = _readUInt64(&pars_ctx, &value); + if (pars_err != parser_ok) { + goto catch_cx_error; + } + } + + if (value != item->value) { + goto catch_cx_error; + } + signature_script_hash(start_tindata, start_signdata, SAPLING_LENGTH_HASH_DATA, start_tindata + i * T_IN_TX_LEN, + T_IN_TX_LEN, i, tx_version, message_digest); + size_t signatureLen = DER_MAX_SIZE; + CATCH_CXERROR(cx_ecdsa_sign_no_throw(&cx_privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256, message_digest, + CX_SHA256_SIZE, signature->step1.der_signature, &signatureLen, &info)); + + if (convertDERtoRSV(signature->step1.der_signature, info, signature->step1.r, signature->step1.s, + &signature->step1.v) != no_error || + transparent_signatures_append(signature->step2.rs) != zxerr_ok) { + goto catch_cx_error; + } + } + error = zxerr_ok; catch_cx_error: - MEMZERO(&cx_publicKey, sizeof(cx_publicKey)); - MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); - MEMZERO(privateKeyData, sizeof(privateKeyData)); - MEMZERO(pubKey, sizeof(pubKey)); - MEMZERO(script, sizeof(script)); - MEMZERO(message_digest, sizeof(message_digest)); - - return error; + MEMZERO(&cx_publicKey, sizeof(cx_publicKey)); + MEMZERO(&cx_privateKey, sizeof(cx_privateKey)); + MEMZERO(privateKeyData, sizeof(privateKeyData)); + MEMZERO(pubKey, sizeof(pubKey)); + MEMZERO(script, sizeof(script)); + MEMZERO(message_digest, sizeof(message_digest)); + + return error; } typedef struct { - union { - // STEP 1 - struct { - uint8_t zip32_seed[ZIP32_SEED_SIZE]; - } step1; - - struct { - uint8_t ask[ASK_SIZE]; - uint8_t nsk[NSK_SIZE]; - } step2; - // STEP 2 - struct { - uint8_t rsk[ASK_SIZE]; - } step3; - }; + union { + // STEP 1 + struct { + uint8_t zip32_seed[ZIP32_SEED_SIZE]; + } step1; + + struct { + uint8_t ask[ASK_SIZE]; + uint8_t nsk[NSK_SIZE]; + } step2; + // STEP 2 + struct { + uint8_t rsk[ASK_SIZE]; + } step3; + }; } tmp_sign_s; // handleCheckandSign step 10/11 -zxerr_t crypto_signspends_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen, - const uint8_t tx_version) { - zemu_log_stack("crypto_signspends_sapling"); - if (spendlist_len() == 0) { - return zxerr_ok; - } - - MEMZERO(buffer, bufferLen); - - if (get_state() != STATE_VERIFIED_ALL_TXDATA) { - return zxerr_unknown; - } - - if (length_t_in_data() + length_spenddata() + length_outputdata() + - SAPLING_LENGTH_HASH_DATA != - txdatalen) { - return zxerr_unknown; - } - - uint8_t *start_signdata = (uint8_t *)(txdata + start_sighashdata()); - uint8_t message[HASH_SIZE + 32] = {0}; - signature_hash(txdata, start_signdata, SAPLING_LENGTH_HASH_DATA, tx_version, - message + 32); - tmp_sign_s tmp = {0}; - - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - // Temporarily get sk from Ed25519 - const uint8_t spendListLen = spendlist_len(); - for (uint8_t i = 0; i < spendListLen; i++) { - CHECK_ZXERROR_AND_CLEAN(crypto_fillSaplingSeed(tmp.step1.zip32_seed)) - const spend_item_t *item = spendlist_retrieve_item(i); - if (item == NULL) { - CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) +zxerr_t crypto_signspends_sapling( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version) { + zemu_log_stack("crypto_signspends_sapling"); + if (spendlist_len() == 0) { + return zxerr_ok; } - // combining these causes a stack overflow - randomized_secret_from_seed(tmp.step1.zip32_seed, item->path, - (uint8_t *)item->alpha, tmp.step3.rsk); - rsk_to_rk((uint8_t *)tmp.step3.rsk, message); - sign_redjubjub(tmp.step3.rsk, message, buffer); - io_seproxyhal_io_heartbeat(); - CHECK_ZXERROR_AND_CLEAN(spend_signatures_append(buffer)) - MEMZERO(&tmp, sizeof(tmp_sign_s)); - CHECK_APP_CANARY() - } + MEMZERO(buffer, bufferLen); + + if (get_state() != STATE_VERIFIED_ALL_TXDATA) { + return zxerr_unknown; + } + + if (length_t_in_data() + length_spenddata() + length_outputdata() + SAPLING_LENGTH_HASH_DATA != txdatalen) { + return zxerr_unknown; + } + + uint8_t *start_signdata = (uint8_t *)(txdata + start_sighashdata()); + uint8_t message[HASH_SIZE + 32] = {0}; + signature_hash(txdata, start_signdata, SAPLING_LENGTH_HASH_DATA, tx_version, message + 32); + tmp_sign_s tmp = {0}; + + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + // Temporarily get sk from Ed25519 + const uint8_t spendListLen = spendlist_len(); + for (uint8_t i = 0; i < spendListLen; i++) { + CHECK_ZXERROR_AND_CLEAN(crypto_fillSaplingSeed(tmp.step1.zip32_seed)) + const spend_item_t *item = spendlist_retrieve_item(i); + if (item == NULL) { + CHECK_ZXERROR_AND_CLEAN(zxerr_unknown) + } + // combining these causes a stack overflow + randomized_secret_from_seed(tmp.step1.zip32_seed, item->path, (uint8_t *)item->alpha, tmp.step3.rsk); + rsk_to_rk((uint8_t *)tmp.step3.rsk, message); + + sign_redjubjub(tmp.step3.rsk, message, buffer); + io_seproxyhal_io_heartbeat(); + CHECK_ZXERROR_AND_CLEAN(spend_signatures_append(buffer)) + MEMZERO(&tmp, sizeof(tmp_sign_s)); + CHECK_APP_CANARY() + } - MEMZERO(&tmp, sizeof(tmp_sign_s)); - return zxerr_ok; + MEMZERO(&tmp, sizeof(tmp_sign_s)); + return zxerr_ok; } // handleExtractTransparentSignature -zxerr_t crypto_extract_transparent_signature(uint8_t *buffer, - uint16_t bufferLen) { - if (!transparent_signatures_more_extract()) { - return zxerr_unknown; - } - - if (get_state() != STATE_SIGNED_TX) { - return zxerr_unknown; - } - - MEMZERO(buffer, bufferLen); - return get_next_transparent_signature(buffer); +zxerr_t crypto_extract_transparent_signature(uint8_t *buffer, uint16_t bufferLen) { + if (!transparent_signatures_more_extract()) { + return zxerr_unknown; + } + + if (get_state() != STATE_SIGNED_TX) { + return zxerr_unknown; + } + + MEMZERO(buffer, bufferLen); + return get_next_transparent_signature(buffer); } // handleExtractSpendSignature zxerr_t crypto_extract_spend_signature(uint8_t *buffer, uint16_t bufferLen) { - if (!spend_signatures_more_extract()) { - return zxerr_unknown; - } + if (!spend_signatures_more_extract()) { + return zxerr_unknown; + } - if (get_state() != STATE_SIGNED_TX) { - return zxerr_unknown; - } + if (get_state() != STATE_SIGNED_TX) { + return zxerr_unknown; + } - MEMZERO(buffer, bufferLen); - return get_next_spend_signature(buffer); + MEMZERO(buffer, bufferLen); + return get_next_spend_signature(buffer); } // handleInitTX step 2/2 -- AND -- handleCheckandSign step 11/11 -zxerr_t crypto_hash_messagebuffer(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, uint16_t txdataLen) { - if (bufferLen < CX_SHA256_SIZE) { - return zxerr_unknown; - } - cx_hash_sha256(txdata, txdataLen, buffer, CX_SHA256_SIZE); // SHA256 - return zxerr_ok; +zxerr_t crypto_hash_messagebuffer(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, uint16_t txdataLen) { + if (bufferLen < CX_SHA256_SIZE) { + return zxerr_unknown; + } + cx_hash_sha256(txdata, txdataLen, buffer, CX_SHA256_SIZE); // SHA256 + return zxerr_ok; } typedef struct { - uint8_t ivk[IVK_SIZE]; - uint8_t default_div[DIV_SIZE]; + uint8_t ivk[IVK_SIZE]; + uint8_t default_div[DIV_SIZE]; } tmp_sapling_ivk_and_default_div; // handleGetKeyIVK: return the incoming viewing key for a given path and the // default diversifier -zxerr_t crypto_ivk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, - uint16_t *replyLen) { - zemu_log_stack("crypto_ivk_sapling"); +zxerr_t crypto_ivk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen) { + zemu_log_stack("crypto_ivk_sapling"); - tmp_sapling_ivk_and_default_div *out = - (tmp_sapling_ivk_and_default_div *)buffer; - MEMZERO(buffer, bufferLen); + tmp_sapling_ivk_and_default_div *out = (tmp_sapling_ivk_and_default_div *)buffer; + MEMZERO(buffer, bufferLen); - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; - // Temporarily get sk from Ed25519 - if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { - MEMZERO(buffer, bufferLen); + // Temporarily get sk from Ed25519 + if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { + MEMZERO(buffer, bufferLen); + MEMZERO(zip32_seed, sizeof(zip32_seed)); + *replyLen = 0; + return zxerr_unknown; + } + + CHECK_APP_CANARY() + // get incomming viewing key + zip32_ivk(zip32_seed, out->ivk, p); + CHECK_APP_CANARY() + // get default diversifier for start index 0 + get_default_diversifier_without_start_index(zip32_seed, p, out->default_div); MEMZERO(zip32_seed, sizeof(zip32_seed)); - *replyLen = 0; - return zxerr_unknown; - } - - CHECK_APP_CANARY() - // get incomming viewing key - zip32_ivk(zip32_seed, out->ivk, p); - CHECK_APP_CANARY() - // get default diversifier for start index 0 - get_default_diversifier_without_start_index(zip32_seed, p, out->default_div); - MEMZERO(zip32_seed, sizeof(zip32_seed)); - CHECK_APP_CANARY() - *replyLen = IVK_SIZE + DIV_SIZE; - return zxerr_ok; + CHECK_APP_CANARY() + *replyLen = IVK_SIZE + DIV_SIZE; + return zxerr_ok; } // handleGetKeyOVK -zxerr_t crypto_ovk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, - uint16_t *replyLen) { - MEMZERO(buffer, bufferLen); +zxerr_t crypto_ovk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen) { + MEMZERO(buffer, bufferLen); - zemu_log_stack("crypto_ovk_sapling"); - uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; + zemu_log_stack("crypto_ovk_sapling"); + uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; - // Temporarily get sk from Ed25519 - if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { - MEMZERO(zip32_seed, sizeof(zip32_seed)); - MEMZERO(buffer, bufferLen); - *replyLen = 0; - return zxerr_unknown; - } - CHECK_APP_CANARY() + // Temporarily get sk from Ed25519 + if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { + MEMZERO(zip32_seed, sizeof(zip32_seed)); + MEMZERO(buffer, bufferLen); + *replyLen = 0; + return zxerr_unknown; + } + CHECK_APP_CANARY() - zip32_ovk(zip32_seed, buffer, p); - CHECK_APP_CANARY() - MEMZERO(zip32_seed, sizeof(zip32_seed)); + zip32_ovk(zip32_seed, buffer, p); + CHECK_APP_CANARY() + MEMZERO(zip32_seed, sizeof(zip32_seed)); - *replyLen = OVK_SIZE; - return zxerr_ok; + *replyLen = OVK_SIZE; + return zxerr_ok; } typedef struct { - uint8_t fvk[AK_SIZE + NK_SIZE + OVK_SIZE]; + uint8_t fvk[AK_SIZE + NK_SIZE + OVK_SIZE]; } tmp_sapling_fvk; // handleGetKeyFVK: return the full viewing key for a given path -zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, - uint16_t *replyLen) { - - zemu_log_stack("crypto_fvk_sapling"); +zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen) { + zemu_log_stack("crypto_fvk_sapling"); - MEMZERO(buffer, bufferLen); - tmp_sapling_fvk *out = (tmp_sapling_fvk *)buffer; + MEMZERO(buffer, bufferLen); + tmp_sapling_fvk *out = (tmp_sapling_fvk *)buffer; - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; - // Temporarily get sk from Ed25519 - if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { - MEMZERO(zip32_seed, sizeof(zip32_seed)); - MEMZERO(buffer, bufferLen); - *replyLen = 0; - return zxerr_unknown; - } - CHECK_APP_CANARY() + // Temporarily get sk from Ed25519 + if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { + MEMZERO(zip32_seed, sizeof(zip32_seed)); + MEMZERO(buffer, bufferLen); + *replyLen = 0; + return zxerr_unknown; + } + CHECK_APP_CANARY() - // get full viewing key - zip32_fvk(zip32_seed, out->fvk, p); - CHECK_APP_CANARY() + // get full viewing key + zip32_fvk(zip32_seed, out->fvk, p); + CHECK_APP_CANARY() - MEMZERO(zip32_seed, sizeof(zip32_seed)); - *replyLen = AK_SIZE + NK_SIZE + OVK_SIZE; - return zxerr_ok; + MEMZERO(zip32_seed, sizeof(zip32_seed)); + *replyLen = AK_SIZE + NK_SIZE + OVK_SIZE; + return zxerr_ok; } // handleGetNullifier -zxerr_t crypto_nullifier_sapling(uint8_t *buffer, uint16_t bufferLen, - uint64_t notepos, uint8_t *cm, - uint16_t *replyLen) { - zemu_log_stack("crypto_nullifier_sapling"); +zxerr_t crypto_nullifier_sapling(uint8_t *buffer, uint16_t bufferLen, uint64_t notepos, uint8_t *cm, uint16_t *replyLen) { + zemu_log_stack("crypto_nullifier_sapling"); + + MEMZERO(buffer, bufferLen); - MEMZERO(buffer, bufferLen); + uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; + uint8_t nsk[NSK_SIZE] = {0}; - uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; - uint8_t nsk[NSK_SIZE] = {0}; + if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { + MEMZERO(zip32_seed, sizeof(zip32_seed)); + MEMZERO(buffer, bufferLen); + *replyLen = 0; + return zxerr_unknown; + } + CHECK_APP_CANARY() + // nk can be computed from nsk which itself can be computed from the seed. + zip32_nsk_from_seed(zip32_seed, nsk); + compute_nullifier(cm, notepos, nsk, buffer); + CHECK_APP_CANARY() - if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { MEMZERO(zip32_seed, sizeof(zip32_seed)); - MEMZERO(buffer, bufferLen); - *replyLen = 0; - return zxerr_unknown; - } - CHECK_APP_CANARY() - // nk can be computed from nsk which itself can be computed from the seed. - zip32_nsk_from_seed(zip32_seed, nsk); - compute_nullifier(cm, notepos, nsk, buffer); - CHECK_APP_CANARY() - - MEMZERO(zip32_seed, sizeof(zip32_seed)); - MEMZERO(nsk, sizeof(nsk)); - *replyLen = NULLIFIER_SIZE; - return zxerr_ok; + MEMZERO(nsk, sizeof(nsk)); + *replyLen = NULLIFIER_SIZE; + return zxerr_ok; } // handleGetDiversifierList -zxerr_t crypto_diversifier_with_startindex(uint8_t *buffer, uint32_t p, - const uint8_t *startindex, - uint16_t *replylen) { - zemu_log_stack("crypto_get_diversifiers_sapling"); +zxerr_t crypto_diversifier_with_startindex(uint8_t *buffer, uint32_t p, const uint8_t *startindex, uint16_t *replylen) { + zemu_log_stack("crypto_get_diversifiers_sapling"); - // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last - // part of hdPath - uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; + // the path in zip32 is [FIRST_VALUE, COIN_TYPE, p] where p is u32 and last + // part of hdPath + uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; - // Temporarily get sk from Ed25519 - if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { - MEMZERO(zip32_seed, sizeof(zip32_seed)); - *replylen = 0; - return zxerr_unknown; - } - CHECK_APP_CANARY() + // Temporarily get sk from Ed25519 + if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { + MEMZERO(zip32_seed, sizeof(zip32_seed)); + *replylen = 0; + return zxerr_unknown; + } + CHECK_APP_CANARY() - get_diversifier_list_withstartindex(zip32_seed, p, startindex, buffer); - for (int i = 0; i < DIV_LIST_LENGTH; i++) { - if (!is_valid_diversifier(buffer + i * DIV_SIZE)) { - MEMZERO(buffer + i * DIV_SIZE, DIV_SIZE); + get_diversifier_list_withstartindex(zip32_seed, p, startindex, buffer); + for (int i = 0; i < DIV_LIST_LENGTH; i++) { + if (!is_valid_diversifier(buffer + i * DIV_SIZE)) { + MEMZERO(buffer + i * DIV_SIZE, DIV_SIZE); + } } - } - MEMZERO(zip32_seed, sizeof(zip32_seed)); - *replylen = DIV_LIST_LENGTH * DIV_SIZE; - return zxerr_ok; + MEMZERO(zip32_seed, sizeof(zip32_seed)); + *replylen = DIV_LIST_LENGTH * DIV_SIZE; + return zxerr_ok; } typedef struct { - union { - struct { - uint8_t diversifier[DIV_SIZE]; - uint8_t pkd[PKD_SIZE]; - }; - struct { - uint8_t address_raw[ADDR_LEN_SAPLING]; - char address_bech32[100]; - }; - struct { - uint8_t dummy[ADDR_LEN_SAPLING]; - uint8_t startindex[DIV_INDEX_SIZE]; + union { + struct { + uint8_t diversifier[DIV_SIZE]; + uint8_t pkd[PKD_SIZE]; + }; + struct { + uint8_t address_raw[ADDR_LEN_SAPLING]; + char address_bech32[100]; + }; + struct { + uint8_t dummy[ADDR_LEN_SAPLING]; + uint8_t startindex[DIV_INDEX_SIZE]; + }; }; - }; } tmp_buf_addr_s; // handleGetAddrSaplingDiv -zxerr_t crypto_fillAddress_with_diversifier_sapling(uint8_t *buffer, - uint16_t bufferLen, - uint32_t p, uint8_t *div, - uint16_t *replyLen) { - if (bufferLen < sizeof(tmp_buf_addr_s)) { - return zxerr_unknown; - } - - MEMZERO(buffer, bufferLen); +zxerr_t crypto_fillAddress_with_diversifier_sapling( + uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint8_t *div, uint16_t *replyLen) { + if (bufferLen < sizeof(tmp_buf_addr_s)) { + return zxerr_unknown; + } - zemu_log_stack("crypto_fillAddress_with_div_sapling"); + MEMZERO(buffer, bufferLen); - tmp_buf_addr_s *const out = (tmp_buf_addr_s *)buffer; + zemu_log_stack("crypto_fillAddress_with_div_sapling"); - uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; + tmp_buf_addr_s *const out = (tmp_buf_addr_s *)buffer; - // Initialize diversifier - MEMCPY(out->diversifier, div, DIV_SIZE); - if (!is_valid_diversifier(out->diversifier)) { - return zxerr_unknown; - } + uint8_t zip32_seed[ZIP32_SEED_SIZE] = {0}; - // Temporarily get sk from Ed25519 - if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { - MEMZERO(zip32_seed, sizeof(zip32_seed)); - *replyLen = 0; - return zxerr_unknown; - } - CHECK_APP_CANARY() + // Initialize diversifier + MEMCPY(out->diversifier, div, DIV_SIZE); + if (!is_valid_diversifier(out->diversifier)) { + return zxerr_unknown; + } - // Initialize pkd - get_pkd(zip32_seed, p, out->diversifier, out->pkd); - CHECK_APP_CANARY() + // Temporarily get sk from Ed25519 + if (crypto_fillSaplingSeed(zip32_seed) != zxerr_ok) { + MEMZERO(zip32_seed, sizeof(zip32_seed)); + *replyLen = 0; + return zxerr_unknown; + } + CHECK_APP_CANARY() - MEMZERO(zip32_seed, sizeof(zip32_seed)); + // Initialize pkd + get_pkd(zip32_seed, p, out->diversifier, out->pkd); + CHECK_APP_CANARY() - // To simplify the code and avoid making copies, read the 'address_raw' variable. - // This variable completely overlaps with the 'diversifier' and 'pkd' fields. - // Therefore, using 'address_raw' is equivalent to have [diversifier(11) | pkd(32)] - if (bech32EncodeFromBytes(out->address_bech32, - sizeof_field(tmp_buf_addr_s, address_bech32), - BECH32_HRP, out->address_raw, - sizeof_field(tmp_buf_addr_s, address_raw), 1, - BECH32_ENCODING_BECH32) != zxerr_ok) { + MEMZERO(zip32_seed, sizeof(zip32_seed)); - MEMZERO(out, bufferLen); - *replyLen = 0; - return zxerr_unknown; - } + // To simplify the code and avoid making copies, read the 'address_raw' variable. + // This variable completely overlaps with the 'diversifier' and 'pkd' fields. + // Therefore, using 'address_raw' is equivalent to have [diversifier(11) | pkd(32)] + if (bech32EncodeFromBytes(out->address_bech32, sizeof_field(tmp_buf_addr_s, address_bech32), BECH32_HRP, + out->address_raw, sizeof_field(tmp_buf_addr_s, address_raw), 1, + BECH32_ENCODING_BECH32) != zxerr_ok) { + MEMZERO(out, bufferLen); + *replyLen = 0; + return zxerr_unknown; + } - CHECK_APP_CANARY() - *replyLen = sizeof_field(tmp_buf_addr_s, address_raw) + - strlen((const char *)out->address_bech32); - return zxerr_ok; + CHECK_APP_CANARY() + *replyLen = sizeof_field(tmp_buf_addr_s, address_raw) + strlen((const char *)out->address_bech32); + return zxerr_ok; } // handleGetAddrSapling -zxerr_t crypto_fillAddress_sapling(uint8_t *buffer, uint16_t bufferLen, - uint32_t p, uint16_t *replyLen) { +zxerr_t crypto_fillAddress_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen) { if (bufferLen < sizeof(tmp_buf_addr_s)) { return zxerr_unknown; } @@ -1624,18 +1505,15 @@ zxerr_t crypto_fillAddress_sapling(uint8_t *buffer, uint16_t bufferLen, CHECK_APP_CANARY() MEMZERO(zip32_seed, sizeof(zip32_seed)); - if (bech32EncodeFromBytes(out->address_bech32, - sizeof_field(tmp_buf_addr_s, address_bech32), - BECH32_HRP, out->address_raw, - sizeof_field(tmp_buf_addr_s, address_raw), 1, - BECH32_ENCODING_BECH32) != zxerr_ok) { + if (bech32EncodeFromBytes(out->address_bech32, sizeof_field(tmp_buf_addr_s, address_bech32), BECH32_HRP, + out->address_raw, sizeof_field(tmp_buf_addr_s, address_raw), 1, + BECH32_ENCODING_BECH32) != zxerr_ok) { MEMZERO(out, bufferLen); *replyLen = 0; return zxerr_unknown; } CHECK_APP_CANARY() - *replyLen = sizeof_field(tmp_buf_addr_s, address_raw) + - strlen((const char *)out->address_bech32); + *replyLen = sizeof_field(tmp_buf_addr_s, address_raw) + strlen((const char *)out->address_bech32); return zxerr_ok; } diff --git a/app/src/crypto.h b/app/src/crypto.h index 210e40c1..018d8b4e 100644 --- a/app/src/crypto.h +++ b/app/src/crypto.h @@ -20,99 +20,67 @@ extern "C" { #endif -#include "coin.h" -#include "zxerror.h" #include #include #include +#include "coin.h" +#include "zxerror.h" + extern uint32_t hdPath[HDPATH_LEN_DEFAULT]; extern address_kind_e addressKind; zxerr_t crypto_fillSaplingSeed(uint8_t *sk); -zxerr_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t bufferLen, - uint16_t *replyLen); - -zxerr_t crypto_fillAddress_sapling(uint8_t *buffer, uint16_t bufferLen, - uint32_t p, uint16_t *replyLen); -zxerr_t crypto_fillAddress_with_diversifier_sapling(uint8_t *buffer, - uint16_t bufferLen, - uint32_t p, uint8_t *div, - uint16_t *replyLen); -zxerr_t crypto_diversifier_with_startindex(uint8_t *buffer, uint32_t p, - const uint8_t *startindex, - uint16_t *replylen); - -zxerr_t crypto_ivk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, - uint16_t *replyLen); -zxerr_t crypto_ovk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, - uint16_t *replyLen); -zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, - uint16_t *replyLen); -zxerr_t crypto_nullifier_sapling(uint8_t *buffer, uint16_t bufferLen, - uint64_t notepos, uint8_t *cm, - uint16_t *replyLen); - -zxerr_t crypto_hash_messagebuffer(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, uint16_t txdataLen); - -zxerr_t crypto_checkspend_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *spenddata, - uint16_t spenddatalen, - const uint8_t tx_version); - -zxerr_t crypto_checkoutput_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *outputdata, - const uint16_t outputdatalen, - const uint8_t tx_version); - -zxerr_t crypto_checkencryptions_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *outputdata); - -uint16_t crypto_key_exchange(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint16_t txdatalen); -zxerr_t crypto_extracttx_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen); - -zxerr_t crypto_extract_spend_proofkeyandrnd(uint8_t *buffer, - uint16_t bufferLen); - -zxerr_t crypto_extract_output_rnd(uint8_t *buffer, uint16_t bufferLen, - uint16_t *replyLen); - -zxerr_t crypto_signspends_sapling(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *signdata, uint16_t signdatalen, - const uint8_t tx_version); +zxerr_t crypto_fillAddress_secp256k1(uint8_t *buffer, uint16_t bufferLen, uint16_t *replyLen); + +zxerr_t crypto_fillAddress_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen); +zxerr_t crypto_fillAddress_with_diversifier_sapling( + uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint8_t *div, uint16_t *replyLen); +zxerr_t crypto_diversifier_with_startindex(uint8_t *buffer, uint32_t p, const uint8_t *startindex, uint16_t *replylen); + +zxerr_t crypto_ivk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen); +zxerr_t crypto_ovk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen); +zxerr_t crypto_fvk_sapling(uint8_t *buffer, uint16_t bufferLen, uint32_t p, uint16_t *replyLen); +zxerr_t crypto_nullifier_sapling(uint8_t *buffer, uint16_t bufferLen, uint64_t notepos, uint8_t *cm, uint16_t *replyLen); + +zxerr_t crypto_hash_messagebuffer(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, uint16_t txdataLen); + +zxerr_t crypto_checkspend_sapling( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *spenddata, uint16_t spenddatalen, const uint8_t tx_version); + +zxerr_t crypto_checkoutput_sapling( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *outputdata, const uint16_t outputdatalen, const uint8_t tx_version); + +zxerr_t crypto_checkencryptions_sapling(uint8_t *buffer, uint16_t bufferLen, const uint8_t *outputdata); + +uint16_t crypto_key_exchange(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen); +zxerr_t crypto_extracttx_sapling(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen); + +zxerr_t crypto_extract_spend_proofkeyandrnd(uint8_t *buffer, uint16_t bufferLen); + +zxerr_t crypto_extract_output_rnd(uint8_t *buffer, uint16_t bufferLen, uint16_t *replyLen); + +zxerr_t crypto_signspends_sapling( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *signdata, uint16_t signdatalen, const uint8_t tx_version); zxerr_t crypto_extract_spend_signature(uint8_t *buffer, uint16_t bufferLen); -zxerr_t crypto_check_prevouts(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint8_t tx_version); +zxerr_t crypto_check_prevouts(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version); -zxerr_t crypto_check_sequence(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint8_t tx_version); +zxerr_t crypto_check_sequence(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version); -zxerr_t crypto_check_outputs(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, const uint16_t txdatalen, - const uint8_t tx_version); +zxerr_t crypto_check_outputs( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version); -zxerr_t crypto_check_joinsplits(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint8_t tx_version); +zxerr_t crypto_check_joinsplits(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version); -zxerr_t crypto_check_valuebalance(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint8_t tx_version); +zxerr_t crypto_check_valuebalance(uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint8_t tx_version); -zxerr_t crypto_sign_and_check_transparent(uint8_t *buffer, uint16_t bufferLen, - const uint8_t *txdata, - const uint16_t txdatalen, - const uint8_t tx_version); -zxerr_t crypto_extract_transparent_signature(uint8_t *buffer, - uint16_t bufferLen); +zxerr_t crypto_sign_and_check_transparent( + uint8_t *buffer, uint16_t bufferLen, const uint8_t *txdata, const uint16_t txdatalen, const uint8_t tx_version); +zxerr_t crypto_extract_transparent_signature(uint8_t *buffer, uint16_t bufferLen); #ifdef __cplusplus } #endif diff --git a/app/src/index_NU5.h b/app/src/index_NU5.h index c770cfbd..2d6f52a4 100644 --- a/app/src/index_NU5.h +++ b/app/src/index_NU5.h @@ -16,20 +16,20 @@ #include -#define NU5_LENGTH_HASH_DATA 220 +#define NU5_LENGTH_HASH_DATA 220 -#define NU5_INDEX_HASH_VERSION 0 -#define NU5_INDEX_HASH_VERSION_GROUP_ID 4 +#define NU5_INDEX_HASH_VERSION 0 +#define NU5_INDEX_HASH_VERSION_GROUP_ID 4 #define NU5_INDEX_HASH_CONSENSUS_BRANCH_ID 8 -#define NU5_INDEX_HASH_LOCK_TIME 12 -#define NU5_INDEX_EXPIRY_HEIGHT 16 +#define NU5_INDEX_HASH_LOCK_TIME 12 +#define NU5_INDEX_EXPIRY_HEIGHT 16 -#define NU5_INDEX_HASH_PREVOUTSHASH 20 // 32 bytes -#define NU5_INDEX_HASH_SEQUENCEHASH 52 // 32 bytes -#define NU5_INDEX_HASH_OUTPUTSHASH 84 // 32 bytes -#define NU5_INDEX_HASH_SHIELDEDSPENDHASH 116 // 32 bytes -#define NU5_INDEX_HASH_SHIELDEDOUTPUTHASH 148 // 32 bytes -#define NU5_INDEX_HASH_VALUEBALANCE 180 // 64 bit -#define NU5_INDEX_HASH_ORCHARDHASH 188 // of length 32 +#define NU5_INDEX_HASH_PREVOUTSHASH 20 // 32 bytes +#define NU5_INDEX_HASH_SEQUENCEHASH 52 // 32 bytes +#define NU5_INDEX_HASH_OUTPUTSHASH 84 // 32 bytes +#define NU5_INDEX_HASH_SHIELDEDSPENDHASH 116 // 32 bytes +#define NU5_INDEX_HASH_SHIELDEDOUTPUTHASH 148 // 32 bytes +#define NU5_INDEX_HASH_VALUEBALANCE 180 // 64 bit +#define NU5_INDEX_HASH_ORCHARDHASH 188 // of length 32 -#define NU5_VALUEBALANCE_SIZE 8 // 64 bit +#define NU5_VALUEBALANCE_SIZE 8 // 64 bit diff --git a/app/src/index_sapling.c b/app/src/index_sapling.c index 415260fb..0886f6d9 100644 --- a/app/src/index_sapling.c +++ b/app/src/index_sapling.c @@ -15,20 +15,29 @@ ********************************************************************************/ #include "index_sapling.h" + #include "nvdata.h" -uint16_t length_t_in_data() { return t_inlist_len() * T_IN_TX_LEN; }; +uint16_t length_t_in_data() { + return t_inlist_len() * T_IN_TX_LEN; +}; -uint16_t length_spend_old_data() { return spendlist_len() * SPEND_OLD_TX_LEN; } +uint16_t length_spend_old_data() { + return spendlist_len() * SPEND_OLD_TX_LEN; +} uint16_t length_spenddata() { - return spendlist_len() * (SPEND_TX_LEN + SPEND_OLD_TX_LEN); + return spendlist_len() * (SPEND_TX_LEN + SPEND_OLD_TX_LEN); }; -uint16_t length_outputdata() { return outputlist_len() * OUTPUT_TX_LEN; }; +uint16_t length_outputdata() { + return outputlist_len() * OUTPUT_TX_LEN; +}; -uint16_t length_spend_new_data() { return spendlist_len() * SPEND_TX_LEN; }; +uint16_t length_spend_new_data() { + return spendlist_len() * SPEND_TX_LEN; +}; uint16_t start_sighashdata() { - return length_t_in_data() + length_spenddata() + length_outputdata(); + return length_t_in_data() + length_spenddata() + length_outputdata(); }; diff --git a/app/src/index_sapling.h b/app/src/index_sapling.h index 0f53f1c4..6eba3212 100644 --- a/app/src/index_sapling.h +++ b/app/src/index_sapling.h @@ -16,69 +16,66 @@ #include -#define T_IN_INPUT_LEN 54 // fixme: maybe add more options to HDPATH -#define T_OUT_INPUT_LEN 34 -#define SPEND_INPUT_LEN 55 -#define OUTPUT_INPUT_LEN 85 - -#define INDEX_INPUT_TIN_PATH 0 -#define INDEX_INPUT_TIN_SCRIPT 20 -#define INDEX_INPUT_TIN_VALUE 46 - -#define INDEX_INPUT_TOUT_ADDR 0 -#define INDEX_INPUT_TOUT_VALUE 26 - -#define INDEX_INPUT_SPENDPOS 0 -#define INDEX_INPUT_INPUTDIV 4 -#define INDEX_INPUT_INPUTPKD 15 -#define INDEX_INPUT_INPUTVALUE 47 - -#define INDEX_INPUT_OUTPUTDIV 0 -#define INDEX_INPUT_OUTPUTPKD 11 -#define INDEX_INPUT_OUTPUTVALUE 43 -#define INDEX_INPUT_OUTPUTMEMO 51 -#define INDEX_INPUT_OUTPUTOVK 52 - -#define SPEND_EXTRACT_LEN 128 -#define OUTPUT_EXTRACT_LEN 64 - -#define T_IN_TX_LEN \ - 74 // size of tx_in encoded as in bitcoin. The same across all tx versions -#define SPEND_OLD_TX_LEN 40 -#define SPEND_TX_LEN \ - 320 // cv (32) + anchor (32) + nullifier (32) + rk (32) + zkproof (192) -#define OUTPUT_TX_LEN 948 - -#define INDEX_TIN_PREVOUT 0 -#define INDEX_TIN_SCRIPT 36 -#define INDEX_TIN_VALUE 62 -#define INDEX_TIN_SEQ 70 - -#define INDEX_SPEND_OLD_RCM 0 -#define INDEX_SPEND_OLD_NOTEPOS 32 - -#define INDEX_SPEND_VALUECMT 0 -#define INDEX_SPEND_ANCHOR 32 -#define INDEX_SPEND_NF 64 -#define INDEX_SPEND_RK 96 - -#define INDEX_OUTPUT_VALUECMT 0 -#define INDEX_OUTPUT_NOTECMT 32 -#define INDEX_OUTPUT_EPK 64 -#define INDEX_OUTPUT_ENC 96 -#define INDEX_OUTPUT_ENC_MEMO 96 + 52 // contents of the encrypted memo field -#define INDEX_OUTPUT_ENC_AEAD_TAG \ - 96 + 564 // contents of the encrypted memo field -#define INDEX_OUTPUT_OUT 676 - -#define SAPLING_LENGTH_HASH_DATA 220 -#define SAPLING_INDEX_HASH_PREVOUTSHASH 8 -#define SAPLING_INDEX_HASH_SEQUENCEHASH 40 -#define SAPLING_INDEX_HASH_OUTPUTSHASH 72 -#define SAPLING_INDEX_HASH_JOINSPLITSHASH 104 -#define SAPLING_INDEX_HASH_SHIELDEDSPENDHASH 136 +#define T_IN_INPUT_LEN 54 // fixme: maybe add more options to HDPATH +#define T_OUT_INPUT_LEN 34 +#define SPEND_INPUT_LEN 55 +#define OUTPUT_INPUT_LEN 85 + +#define INDEX_INPUT_TIN_PATH 0 +#define INDEX_INPUT_TIN_SCRIPT 20 +#define INDEX_INPUT_TIN_VALUE 46 + +#define INDEX_INPUT_TOUT_ADDR 0 +#define INDEX_INPUT_TOUT_VALUE 26 + +#define INDEX_INPUT_SPENDPOS 0 +#define INDEX_INPUT_INPUTDIV 4 +#define INDEX_INPUT_INPUTPKD 15 +#define INDEX_INPUT_INPUTVALUE 47 + +#define INDEX_INPUT_OUTPUTDIV 0 +#define INDEX_INPUT_OUTPUTPKD 11 +#define INDEX_INPUT_OUTPUTVALUE 43 +#define INDEX_INPUT_OUTPUTMEMO 51 +#define INDEX_INPUT_OUTPUTOVK 52 + +#define SPEND_EXTRACT_LEN 128 +#define OUTPUT_EXTRACT_LEN 64 + +#define T_IN_TX_LEN 74 // size of tx_in encoded as in bitcoin. The same across all tx versions +#define SPEND_OLD_TX_LEN 40 +#define SPEND_TX_LEN 320 // cv (32) + anchor (32) + nullifier (32) + rk (32) + zkproof (192) +#define OUTPUT_TX_LEN 948 + +#define INDEX_TIN_PREVOUT 0 +#define INDEX_TIN_SCRIPT 36 +#define INDEX_TIN_VALUE 62 +#define INDEX_TIN_SEQ 70 + +#define INDEX_SPEND_OLD_RCM 0 +#define INDEX_SPEND_OLD_NOTEPOS 32 + +#define INDEX_SPEND_VALUECMT 0 +#define INDEX_SPEND_ANCHOR 32 +#define INDEX_SPEND_NF 64 +#define INDEX_SPEND_RK 96 + +#define INDEX_OUTPUT_VALUECMT 0 +#define INDEX_OUTPUT_NOTECMT 32 +#define INDEX_OUTPUT_EPK 64 +#define INDEX_OUTPUT_ENC 96 +#define INDEX_OUTPUT_ENC_MEMO 96 + 52 // contents of the encrypted memo field +#define INDEX_OUTPUT_ENC_AEAD_TAG 96 + 564 // contents of the encrypted memo field +#define INDEX_OUTPUT_OUT 676 + +#define SAPLING_LENGTH_HASH_DATA 220 +#define SAPLING_INDEX_HASH_PREVOUTSHASH 8 +#define SAPLING_INDEX_HASH_SEQUENCEHASH 40 +#define SAPLING_INDEX_HASH_OUTPUTSHASH 72 +#define SAPLING_INDEX_HASH_JOINSPLITSHASH 104 +#define SAPLING_INDEX_HASH_SHIELDEDSPENDHASH 136 #define SAPLING_INDEX_HASH_SHIELDEDOUTPUTHASH 168 -#define SAPLING_INDEX_HASH_VALUEBALANCE 208 +#define SAPLING_INDEX_HASH_VALUEBALANCE 208 uint16_t length_t_in_data(); diff --git a/app/src/jubjub.c b/app/src/jubjub.c index 36ea389f..f7e4bc07 100644 --- a/app/src/jubjub.c +++ b/app/src/jubjub.c @@ -15,370 +15,346 @@ ********************************************************************************/ #include "jubjub.h" -#include "cx.h" + #include #include -#define CONVERT_CX_ZX(CALL) \ - return CALL == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; - -unsigned char const JUBJUB_FR_MODULUS_BYTES[JUBJUB_SCALAR_BYTES] = { - 14, 125, 180, 234, 101, 51, 175, 169, 6, 103, 59, - 1, 1, 52, 59, 0, 166, 104, 32, 147, 204, 200, - 16, 130, 208, 151, 14, 94, 214, 247, 44, 183}; - -unsigned char const JUBJUB_FQ_MODULUS_BYTES[JUBJUB_FIELD_BYTES] = { - 0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, 0x33, 0x39, 0xd8, - 0x08, 0x09, 0xa1, 0xd8, 0x05, 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, - 0x5b, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01}; - -const jubjub_fq JUBJUB_FQ_ZERO = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -const jubjub_fq JUBJUB_FQ_ONE = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; - -const jubjub_fq JUBJUB_FQ_EDWARDS_D = {42, 147, 24, 231, 75, 250, 43, 72, - 245, 253, 146, 7, 230, 189, 127, 212, - 41, 45, 127, 109, 55, 87, 157, 38, - 1, 6, 95, 214, 214, 52, 62, 177}; - -const jubjub_fq JUBJUB_FQ_EDWARDS_2D = { - 85, 38, 49, 206, 151, 244, 86, 145, 235, 251, 36, 15, 205, 122, 255, 168, - 82, 90, 254, 218, 110, 175, 58, 76, 2, 12, 191, 173, 172, 104, 125, 98}; - -const jubjub_fq JUBJUB_FQ_SQRT_T = { - 0, 0, 0, 0, 57, 246, 211, 169, 148, 206, 190, 164, 25, 156, 236, 4, - 4, 208, 236, 2, 169, 222, 210, 1, 127, 255, 45, 255, 127, 255, 255, 255}; -const jubjub_fq JUBJUB_FQ_ROOT_OF_UNITY = { - 22, 162, 161, 158, 223, 232, 31, 32, 208, 155, 104, 25, 34, 200, 19, 180, - 182, 54, 131, 80, 140, 34, 128, 185, 56, 41, 151, 31, 67, 159, 13, 43}; +#include "cx.h" + +#define CONVERT_CX_ZX(CALL) return CALL == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; + +unsigned char const JUBJUB_FR_MODULUS_BYTES[JUBJUB_SCALAR_BYTES] = {14, 125, 180, 234, 101, 51, 175, 169, 6, 103, 59, + 1, 1, 52, 59, 0, 166, 104, 32, 147, 204, 200, + 16, 130, 208, 151, 14, 94, 214, 247, 44, 183}; + +unsigned char const JUBJUB_FQ_MODULUS_BYTES[JUBJUB_FIELD_BYTES] = {0x73, 0xed, 0xa7, 0x53, 0x29, 0x9d, 0x7d, 0x48, + 0x33, 0x39, 0xd8, 0x08, 0x09, 0xa1, 0xd8, 0x05, + 0x53, 0xbd, 0xa4, 0x02, 0xff, 0xfe, 0x5b, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01}; + +const jubjub_fq JUBJUB_FQ_ZERO = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +const jubjub_fq JUBJUB_FQ_ONE = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}; + +const jubjub_fq JUBJUB_FQ_EDWARDS_D = {42, 147, 24, 231, 75, 250, 43, 72, 245, 253, 146, 7, 230, 189, 127, 212, + 41, 45, 127, 109, 55, 87, 157, 38, 1, 6, 95, 214, 214, 52, 62, 177}; + +const jubjub_fq JUBJUB_FQ_EDWARDS_2D = {85, 38, 49, 206, 151, 244, 86, 145, 235, 251, 36, 15, 205, 122, 255, 168, + 82, 90, 254, 218, 110, 175, 58, 76, 2, 12, 191, 173, 172, 104, 125, 98}; + +const jubjub_fq JUBJUB_FQ_SQRT_T = {0, 0, 0, 0, 57, 246, 211, 169, 148, 206, 190, 164, 25, 156, 236, 4, + 4, 208, 236, 2, 169, 222, 210, 1, 127, 255, 45, 255, 127, 255, 255, 255}; +const jubjub_fq JUBJUB_FQ_ROOT_OF_UNITY = {22, 162, 161, 158, 223, 232, 31, 32, 208, 155, 104, 25, 34, 200, 19, 180, + 182, 54, 131, 80, 140, 34, 128, 185, 56, 41, 151, 31, 67, 159, 13, 43}; const jubjub_extendedpoint JUBJUB_GEN = { - .U = {9, 38, 212, 243, 32, 89, 199, 18, 212, 24, 167, - 255, 38, 117, 59, 106, 213, 185, 167, 211, 239, 142, - 40, 39, 71, 191, 70, 146, 10, 149, 167, 83}, - .V = {87, 161, 1, 158, 109, 233, 182, 117, 83, 187, 55, - 208, 194, 28, 253, 5, 109, 101, 103, 77, 206, 219, - 221, 188, 48, 86, 50, 173, 170, 242, 181, 48}, - .Z = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - .T1 = {9, 38, 212, 243, 32, 89, 199, 18, 212, 24, 167, - 255, 38, 117, 59, 106, 213, 185, 167, 211, 239, 142, - 40, 39, 71, 191, 70, 146, 10, 149, 167, 83}, - .T2 = {87, 161, 1, 158, 109, 233, 182, 117, 83, 187, 55, - 208, 194, 28, 253, 5, 109, 101, 103, 77, 206, 219, - 221, 188, 48, 86, 50, 173, 170, 242, 181, 48}, + .U = {9, 38, 212, 243, 32, 89, 199, 18, 212, 24, 167, 255, 38, 117, 59, 106, + 213, 185, 167, 211, 239, 142, 40, 39, 71, 191, 70, 146, 10, 149, 167, 83}, + .V = {87, 161, 1, 158, 109, 233, 182, 117, 83, 187, 55, 208, 194, 28, 253, 5, + 109, 101, 103, 77, 206, 219, 221, 188, 48, 86, 50, 173, 170, 242, 181, 48}, + .Z = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .T1 = {9, 38, 212, 243, 32, 89, 199, 18, 212, 24, 167, 255, 38, 117, 59, 106, + 213, 185, 167, 211, 239, 142, 40, 39, 71, 191, 70, 146, 10, 149, 167, 83}, + .T2 = {87, 161, 1, 158, 109, 233, 182, 117, 83, 187, 55, 208, 194, 28, 253, 5, + 109, 101, 103, 77, 206, 219, 221, 188, 48, 86, 50, 173, 170, 242, 181, 48}, }; const jubjub_extendedpoint JUBJUB_ID = { - .U = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - .V = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - .Z = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, - .T1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, - .T2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .U = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .V = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .Z = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, + .T1 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + .T2 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; void u8_cmov(uint8_t *r, uint8_t a, uint8_t bit) { - uint8_t b = bit & 0x01; - uint8_t mask = (uint8_t)(-(int8_t)b); - uint8_t h, x; - h = *r; - x = h ^ a; - x &= mask; - *r = *r ^ x; + uint8_t b = bit & 0x01; + uint8_t mask = (uint8_t)(-(int8_t)b); + uint8_t h, x; + h = *r; + x = h ^ a; + x &= mask; + *r = *r ^ x; } zxerr_t jubjub_field_frombytes(jubjub_fq r, const uint8_t *s) { - MEMZERO(r, sizeof(jubjub_fq)); - MEMCPY(r, s, sizeof(jubjub_fq)); - CONVERT_CX_ZX(cx_math_modm_no_throw(r, JUBJUB_FIELD_BYTES, JUBJUB_FQ_MODULUS_BYTES, - JUBJUB_FIELD_BYTES)); + MEMZERO(r, sizeof(jubjub_fq)); + MEMCPY(r, s, sizeof(jubjub_fq)); + CONVERT_CX_ZX(cx_math_modm_no_throw(r, JUBJUB_FIELD_BYTES, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } int jubjub_field_iszero(const jubjub_fq r) { - return cx_math_is_zero(r, JUBJUB_FIELD_BYTES); + return cx_math_is_zero(r, JUBJUB_FIELD_BYTES); } __Z_INLINE uint8_t jubjub_field_is_equal(const jubjub_fq a, const jubjub_fq b) { - return (MEMCMP(a, b, sizeof(jubjub_fq)) == 0) & 0x01; + return (MEMCMP(a, b, sizeof(jubjub_fq)) == 0) & 0x01; } void jubjub_field_one(jubjub_fq r) { - MEMZERO(r, sizeof(jubjub_fq)); - MEMCPY(r, JUBJUB_FQ_ONE, sizeof(jubjub_fq)); + MEMZERO(r, sizeof(jubjub_fq)); + MEMCPY(r, JUBJUB_FQ_ONE, sizeof(jubjub_fq)); } void jubjub_field_copy(jubjub_fq r, const jubjub_fq a) { - MEMZERO(r, sizeof(jubjub_fq)); - MEMCPY(r, a, sizeof(jubjub_fq)); + MEMZERO(r, sizeof(jubjub_fq)); + MEMCPY(r, a, sizeof(jubjub_fq)); } static zxerr_t jubjub_field_mult(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { - CONVERT_CX_ZX(cx_math_multm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_multm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_add(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { - CONVERT_CX_ZX(cx_math_addm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_addm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_sub(jubjub_fq r, const jubjub_fq a, const jubjub_fq b) { - CONVERT_CX_ZX(cx_math_subm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_subm_no_throw(r, a, b, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_inverse(jubjub_fq r, jubjub_fq a) { - CONVERT_CX_ZX(cx_math_invprimem_no_throw(r, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_invprimem_no_throw(r, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_square(jubjub_fq r, jubjub_fq a) { - CONVERT_CX_ZX(cx_math_multm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_multm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_double(jubjub_fq r, jubjub_fq a) { - CONVERT_CX_ZX(cx_math_addm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_addm_no_throw(r, a, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_pow_t(jubjub_fq r, const jubjub_fq a) { - CONVERT_CX_ZX(cx_math_powm_no_throw(r, a, JUBJUB_FQ_SQRT_T, JUBJUB_FIELD_BYTES, - JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX( + cx_math_powm_no_throw(r, a, JUBJUB_FQ_SQRT_T, JUBJUB_FIELD_BYTES, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } static zxerr_t jubjub_field_negate(jubjub_fq r, const jubjub_fq a) { - CONVERT_CX_ZX(cx_math_subm_no_throw(r, JUBJUB_FQ_ZERO, a, JUBJUB_FQ_MODULUS_BYTES, - JUBJUB_FIELD_BYTES)); + CONVERT_CX_ZX(cx_math_subm_no_throw(r, JUBJUB_FQ_ZERO, a, JUBJUB_FQ_MODULUS_BYTES, JUBJUB_FIELD_BYTES)); } void jubjub_field_cmov(jubjub_fq r, const jubjub_fq a, uint8_t bit) { - uint8_t b = bit & 0x01; - uint8_t mask = (uint8_t)(-(int8_t)b); - jubjub_fq h, x; - for (int i = 0; i < JUBJUB_FIELD_BYTES; i++) { - h[i] = r[i]; - x[i] = h[i] ^ a[i]; - x[i] &= mask; - r[i] = r[i] ^ x[i]; - } + uint8_t b = bit & 0x01; + uint8_t mask = (uint8_t)(-(int8_t)b); + jubjub_fq h, x; + for (int i = 0; i < JUBJUB_FIELD_BYTES; i++) { + h[i] = r[i]; + x[i] = h[i] ^ a[i]; + x[i] &= mask; + r[i] = r[i] ^ x[i]; + } } zxerr_t jubjub_field_sqrt(jubjub_fq r, const jubjub_fq a) { - jubjub_fq w, x, b, z; - CHECK_ZXERR(jubjub_field_pow_t(w, a)); - - uint8_t v = 32; - CHECK_ZXERR(jubjub_field_mult(x, a, w)); - CHECK_ZXERR(jubjub_field_mult(b, x, w)); - jubjub_field_copy(z, JUBJUB_FQ_ROOT_OF_UNITY); - jubjub_fq tmp; - - for (uint8_t max_v = 32; max_v >= 1; max_v--) { - uint8_t k = 1; - CHECK_ZXERR(jubjub_field_square(tmp, b)); - uint8_t j_less_than_v = 1; - for (uint8_t j = 2; j < max_v; j++) { - uint8_t tmp_is_one = jubjub_field_is_equal(tmp, JUBJUB_FQ_ONE); - jubjub_fq squared; - jubjub_field_copy(squared, z); - jubjub_field_cmov(squared, tmp, !tmp_is_one); - CHECK_ZXERR(jubjub_field_square(squared, squared)); - jubjub_field_cmov(tmp, squared, !tmp_is_one); - jubjub_fq new_z; - jubjub_field_copy(new_z, squared); - jubjub_field_cmov(new_z, z, !tmp_is_one); - j_less_than_v &= !(j == v); - u8_cmov(&k, j, !tmp_is_one); - jubjub_field_cmov(z, new_z, j_less_than_v); + jubjub_fq w, x, b, z; + CHECK_ZXERR(jubjub_field_pow_t(w, a)); + + uint8_t v = 32; + CHECK_ZXERR(jubjub_field_mult(x, a, w)); + CHECK_ZXERR(jubjub_field_mult(b, x, w)); + jubjub_field_copy(z, JUBJUB_FQ_ROOT_OF_UNITY); + jubjub_fq tmp; + + for (uint8_t max_v = 32; max_v >= 1; max_v--) { + uint8_t k = 1; + CHECK_ZXERR(jubjub_field_square(tmp, b)); + uint8_t j_less_than_v = 1; + for (uint8_t j = 2; j < max_v; j++) { + uint8_t tmp_is_one = jubjub_field_is_equal(tmp, JUBJUB_FQ_ONE); + jubjub_fq squared; + jubjub_field_copy(squared, z); + jubjub_field_cmov(squared, tmp, !tmp_is_one); + CHECK_ZXERR(jubjub_field_square(squared, squared)); + jubjub_field_cmov(tmp, squared, !tmp_is_one); + jubjub_fq new_z; + jubjub_field_copy(new_z, squared); + jubjub_field_cmov(new_z, z, !tmp_is_one); + j_less_than_v &= !(j == v); + u8_cmov(&k, j, !tmp_is_one); + jubjub_field_cmov(z, new_z, j_less_than_v); + } + + jubjub_fq result; + CHECK_ZXERR(jubjub_field_mult(result, x, z)); + uint8_t b_is_one = jubjub_field_is_equal(b, JUBJUB_FQ_ONE); + + jubjub_field_cmov(x, result, !b_is_one); + CHECK_ZXERR(jubjub_field_square(z, z)); + CHECK_ZXERR(jubjub_field_mult(b, b, z)); + v = k; } - jubjub_fq result; - CHECK_ZXERR(jubjub_field_mult(result, x, z)); - uint8_t b_is_one = jubjub_field_is_equal(b, JUBJUB_FQ_ONE); + CHECK_ZXERR(jubjub_field_square(w, x)); + uint8_t correct = jubjub_field_is_equal(w, a); - jubjub_field_cmov(x, result, !b_is_one); - CHECK_ZXERR(jubjub_field_square(z, z)); - CHECK_ZXERR(jubjub_field_mult(b, b, z)); - v = k; - } - - CHECK_ZXERR(jubjub_field_square(w, x)); - uint8_t correct = jubjub_field_is_equal(w, a); - - if (!correct) { - return zxerr_unknown; - } + if (!correct) { + return zxerr_unknown; + } - jubjub_field_copy(r, x); - return zxerr_ok; + jubjub_field_copy(r, x); + return zxerr_ok; } -static void jubjub_extendedpoint_cmov(jubjub_extendedpoint *r, jubjub_extendedpoint *p, - unsigned int bit) { - jubjub_field_cmov(r->U, p->U, bit); - jubjub_field_cmov(r->V, p->V, bit); - jubjub_field_cmov(r->Z, p->Z, bit); - jubjub_field_cmov(r->T1, p->T1, bit); - jubjub_field_cmov(r->T1, p->T2, bit); +static void jubjub_extendedpoint_cmov(jubjub_extendedpoint *r, jubjub_extendedpoint *p, unsigned int bit) { + jubjub_field_cmov(r->U, p->U, bit); + jubjub_field_cmov(r->V, p->V, bit); + jubjub_field_cmov(r->Z, p->Z, bit); + jubjub_field_cmov(r->T1, p->T1, bit); + jubjub_field_cmov(r->T1, p->T2, bit); } static zxerr_t jubjub_extendedpoint_add(jubjub_extendedpoint *r, const jubjub_extendedpoint *p) { - if (r == NULL || p == NULL) { - return zxerr_no_data; - } + if (r == NULL || p == NULL) { + return zxerr_no_data; + } - jubjub_fq v_minus_u, v_plus_u, t2d; + jubjub_fq v_minus_u, v_plus_u, t2d; - CHECK_ZXERR(jubjub_field_add(v_plus_u, p->V, p->U)); - CHECK_ZXERR(jubjub_field_sub(v_minus_u, p->V, p->U)); - CHECK_ZXERR(jubjub_field_mult(t2d, p->T1, p->T2)); - CHECK_ZXERR(jubjub_field_mult(t2d, t2d, JUBJUB_FQ_EDWARDS_2D)); + CHECK_ZXERR(jubjub_field_add(v_plus_u, p->V, p->U)); + CHECK_ZXERR(jubjub_field_sub(v_minus_u, p->V, p->U)); + CHECK_ZXERR(jubjub_field_mult(t2d, p->T1, p->T2)); + CHECK_ZXERR(jubjub_field_mult(t2d, t2d, JUBJUB_FQ_EDWARDS_2D)); - jubjub_fq a, b, c, d; + jubjub_fq a, b, c, d; - CHECK_ZXERR(jubjub_field_sub(a, r->V, r->U)); - CHECK_ZXERR(jubjub_field_mult(a, a, v_minus_u)); + CHECK_ZXERR(jubjub_field_sub(a, r->V, r->U)); + CHECK_ZXERR(jubjub_field_mult(a, a, v_minus_u)); - CHECK_ZXERR(jubjub_field_add(b, r->V, r->U)); - CHECK_ZXERR(jubjub_field_mult(b, b, v_plus_u)); + CHECK_ZXERR(jubjub_field_add(b, r->V, r->U)); + CHECK_ZXERR(jubjub_field_mult(b, b, v_plus_u)); - CHECK_ZXERR(jubjub_field_mult(c, r->T1, r->T2)); - CHECK_ZXERR(jubjub_field_mult(c, c, t2d)); + CHECK_ZXERR(jubjub_field_mult(c, r->T1, r->T2)); + CHECK_ZXERR(jubjub_field_mult(c, c, t2d)); - CHECK_ZXERR(jubjub_field_mult(d, r->Z, p->Z)); - CHECK_ZXERR(jubjub_field_double(d, d)); + CHECK_ZXERR(jubjub_field_mult(d, r->Z, p->Z)); + CHECK_ZXERR(jubjub_field_double(d, d)); - // completed point - jubjub_fq u, v, z, t; - CHECK_ZXERR(jubjub_field_sub(u, b, a)); - CHECK_ZXERR(jubjub_field_add(v, b, a)); - CHECK_ZXERR(jubjub_field_add(z, d, c)); - CHECK_ZXERR(jubjub_field_sub(t, d, c)); + // completed point + jubjub_fq u, v, z, t; + CHECK_ZXERR(jubjub_field_sub(u, b, a)); + CHECK_ZXERR(jubjub_field_add(v, b, a)); + CHECK_ZXERR(jubjub_field_add(z, d, c)); + CHECK_ZXERR(jubjub_field_sub(t, d, c)); - // completed point to extended - CHECK_ZXERR(jubjub_field_mult(r->U, u, t)); - CHECK_ZXERR(jubjub_field_mult(r->V, v, z)); - CHECK_ZXERR(jubjub_field_mult(r->Z, t, z)); - jubjub_field_copy(r->T1, u); - jubjub_field_copy(r->T2, v); + // completed point to extended + CHECK_ZXERR(jubjub_field_mult(r->U, u, t)); + CHECK_ZXERR(jubjub_field_mult(r->V, v, z)); + CHECK_ZXERR(jubjub_field_mult(r->Z, t, z)); + jubjub_field_copy(r->T1, u); + jubjub_field_copy(r->T2, v); - return zxerr_ok; + return zxerr_ok; } -static zxerr_t jubjub_extendedpoint_double(jubjub_extendedpoint *r, - jubjub_extendedpoint *p) { - - jubjub_fq uu, vv; - jubjub_fq zz2, uv2; - jubjub_fq vv_plus_uu, vv_minus_uu; +static zxerr_t jubjub_extendedpoint_double(jubjub_extendedpoint *r, jubjub_extendedpoint *p) { + jubjub_fq uu, vv; + jubjub_fq zz2, uv2; + jubjub_fq vv_plus_uu, vv_minus_uu; - CHECK_ZXERR(jubjub_field_square(uu, p->U)); - CHECK_ZXERR(jubjub_field_square(vv, p->V)); + CHECK_ZXERR(jubjub_field_square(uu, p->U)); + CHECK_ZXERR(jubjub_field_square(vv, p->V)); - CHECK_ZXERR(jubjub_field_square(zz2, p->Z)); - CHECK_ZXERR(jubjub_field_double(zz2, zz2)); + CHECK_ZXERR(jubjub_field_square(zz2, p->Z)); + CHECK_ZXERR(jubjub_field_double(zz2, zz2)); - CHECK_ZXERR(jubjub_field_add(uv2, p->U, p->V)); - CHECK_ZXERR(jubjub_field_square(uv2, uv2)); + CHECK_ZXERR(jubjub_field_add(uv2, p->U, p->V)); + CHECK_ZXERR(jubjub_field_square(uv2, uv2)); - CHECK_ZXERR(jubjub_field_add(vv_plus_uu, vv, uu)); - CHECK_ZXERR(jubjub_field_sub(vv_minus_uu, vv, uu)); + CHECK_ZXERR(jubjub_field_add(vv_plus_uu, vv, uu)); + CHECK_ZXERR(jubjub_field_sub(vv_minus_uu, vv, uu)); - // completed point - jubjub_fq u, v, z, t; - CHECK_ZXERR(jubjub_field_sub(u, uv2, vv_plus_uu)); - jubjub_field_copy(v, vv_plus_uu); - jubjub_field_copy(z, vv_minus_uu); - CHECK_ZXERR(jubjub_field_sub(t, zz2, vv_minus_uu)); + // completed point + jubjub_fq u, v, z, t; + CHECK_ZXERR(jubjub_field_sub(u, uv2, vv_plus_uu)); + jubjub_field_copy(v, vv_plus_uu); + jubjub_field_copy(z, vv_minus_uu); + CHECK_ZXERR(jubjub_field_sub(t, zz2, vv_minus_uu)); - // completed point to extended - CHECK_ZXERR(jubjub_field_mult(r->U, u, t)); - CHECK_ZXERR(jubjub_field_mult(r->V, v, z)); - CHECK_ZXERR(jubjub_field_mult(r->Z, t, z)); - jubjub_field_copy(r->T1, u); - jubjub_field_copy(r->T2, v); + // completed point to extended + CHECK_ZXERR(jubjub_field_mult(r->U, u, t)); + CHECK_ZXERR(jubjub_field_mult(r->V, v, z)); + CHECK_ZXERR(jubjub_field_mult(r->Z, t, z)); + jubjub_field_copy(r->T1, u); + jubjub_field_copy(r->T2, v); - return zxerr_ok; + return zxerr_ok; } -zxerr_t jubjub_extendedpoint_scalarmult(jubjub_extendedpoint *r, - jubjub_fr scalar) { - jubjub_extendedpoint p, dummy; - MEMCPY(&p, &JUBJUB_ID, sizeof(jubjub_extendedpoint)); - // skip the first 4 bits as they are always 0 - for (int i = 4; i < 8 * JUBJUB_SCALAR_BYTES; i++) { - uint8_t di = (scalar[i / 8] >> (7 - (i % 8))) & 0x01; - CHECK_ZXERR(jubjub_extendedpoint_double(&p, &p)); - MEMCPY(&dummy, &p, sizeof(jubjub_extendedpoint)); - CHECK_ZXERR(jubjub_extendedpoint_add(&dummy, r)); - jubjub_extendedpoint_cmov(&p, &dummy, di); - } - MEMCPY(r, &p, sizeof(jubjub_extendedpoint)); - - return zxerr_ok; +zxerr_t jubjub_extendedpoint_scalarmult(jubjub_extendedpoint *r, jubjub_fr scalar) { + jubjub_extendedpoint p, dummy; + MEMCPY(&p, &JUBJUB_ID, sizeof(jubjub_extendedpoint)); + // skip the first 4 bits as they are always 0 + for (int i = 4; i < 8 * JUBJUB_SCALAR_BYTES; i++) { + uint8_t di = (scalar[i / 8] >> (7 - (i % 8))) & 0x01; + CHECK_ZXERR(jubjub_extendedpoint_double(&p, &p)); + MEMCPY(&dummy, &p, sizeof(jubjub_extendedpoint)); + CHECK_ZXERR(jubjub_extendedpoint_add(&dummy, r)); + jubjub_extendedpoint_cmov(&p, &dummy, di); + } + MEMCPY(r, &p, sizeof(jubjub_extendedpoint)); + + return zxerr_ok; } zxerr_t jubjub_extendedpoint_tobytes(uint8_t *s, jubjub_extendedpoint *p) { + jubjub_fq x, y, zinv; + CHECK_ZXERR(jubjub_field_inverse(zinv, p->Z)); + CHECK_ZXERR(jubjub_field_mult(x, p->U, zinv)); + CHECK_ZXERR(jubjub_field_mult(y, p->V, zinv)); - jubjub_fq x, y, zinv; - CHECK_ZXERR(jubjub_field_inverse(zinv, p->Z)); - CHECK_ZXERR(jubjub_field_mult(x, p->U, zinv)); - CHECK_ZXERR(jubjub_field_mult(y, p->V, zinv)); + MEMCPY(s, y, sizeof(jubjub_fq)); + s[0] |= (x[31] << 7); + SWAP_ENDIAN_BYTES(&s[0]); - MEMCPY(s, y, sizeof(jubjub_fq)); - s[0] |= (x[31] << 7); - SWAP_ENDIAN_BYTES(&s[0]); - - return zxerr_ok; + return zxerr_ok; } zxerr_t jubjub_extendedpoint_frombytes(jubjub_extendedpoint *p, uint8_t *s) { - uint8_t b[JUBJUB_FIELD_BYTES] = {0}; - MEMCPY(b, s, JUBJUB_FIELD_BYTES); - SWAP_ENDIAN_BYTES(&b[0]); - - uint8_t sign = b[0] >> 7; - b[0] &= 0x7f; - - jubjub_fq v, v2, v3, u; - - CHECK_ZXERR(jubjub_field_frombytes(v, b)); - CHECK_ZXERR(jubjub_field_square(v2, v)); - jubjub_field_copy(v3, v2); - CHECK_ZXERR(jubjub_field_mult(v2, v2, JUBJUB_FQ_EDWARDS_D)); - CHECK_ZXERR(jubjub_field_add(v2, v2, JUBJUB_FQ_ONE)); - - if (jubjub_field_iszero(v2)) { - return zxerr_unknown; - } - - CHECK_ZXERR(jubjub_field_inverse(v2, v2)); - CHECK_ZXERR(jubjub_field_sub(v3, v3, JUBJUB_FQ_ONE)); - CHECK_ZXERR(jubjub_field_mult(v3, v3, v2)); - CHECK_ZXERR(jubjub_field_sqrt(u, v3)); - - uint8_t flip_sign = (u[JUBJUB_FIELD_BYTES - 1] ^ sign) & 1; - jubjub_fq u_neg; - CHECK_ZXERR(jubjub_field_negate(u_neg, u)); - jubjub_field_cmov(u, u_neg, flip_sign); - - jubjub_field_copy(p->U, u); - jubjub_field_copy(p->V, v); - jubjub_field_copy(p->Z, JUBJUB_FQ_ONE); - jubjub_field_copy(p->T1, u); - jubjub_field_copy(p->T2, v); - - return zxerr_ok; + uint8_t b[JUBJUB_FIELD_BYTES] = {0}; + MEMCPY(b, s, JUBJUB_FIELD_BYTES); + SWAP_ENDIAN_BYTES(&b[0]); + + uint8_t sign = b[0] >> 7; + b[0] &= 0x7f; + + jubjub_fq v, v2, v3, u; + + CHECK_ZXERR(jubjub_field_frombytes(v, b)); + CHECK_ZXERR(jubjub_field_square(v2, v)); + jubjub_field_copy(v3, v2); + CHECK_ZXERR(jubjub_field_mult(v2, v2, JUBJUB_FQ_EDWARDS_D)); + CHECK_ZXERR(jubjub_field_add(v2, v2, JUBJUB_FQ_ONE)); + + if (jubjub_field_iszero(v2)) { + return zxerr_unknown; + } + + CHECK_ZXERR(jubjub_field_inverse(v2, v2)); + CHECK_ZXERR(jubjub_field_sub(v3, v3, JUBJUB_FQ_ONE)); + CHECK_ZXERR(jubjub_field_mult(v3, v3, v2)); + CHECK_ZXERR(jubjub_field_sqrt(u, v3)); + + uint8_t flip_sign = (u[JUBJUB_FIELD_BYTES - 1] ^ sign) & 1; + jubjub_fq u_neg; + CHECK_ZXERR(jubjub_field_negate(u_neg, u)); + jubjub_field_cmov(u, u_neg, flip_sign); + + jubjub_field_copy(p->U, u); + jubjub_field_copy(p->V, v); + jubjub_field_copy(p->Z, JUBJUB_FQ_ONE); + jubjub_field_copy(p->T1, u); + jubjub_field_copy(p->T2, v); + + return zxerr_ok; } diff --git a/app/src/jubjub.h b/app/src/jubjub.h index be4f41bd..d6023bcf 100644 --- a/app/src/jubjub.h +++ b/app/src/jubjub.h @@ -13,47 +13,47 @@ * See the License for the specific language governing permissions and * limitations under the License. ********************************************************************************/ -#include #include +#include #define JUBJUB_SCALAR_BYTES 32 -#define JUBJUB_FIELD_BYTES 32 +#define JUBJUB_FIELD_BYTES 32 typedef unsigned char jubjub_fr[JUBJUB_SCALAR_BYTES]; typedef unsigned char jubjub_fq[JUBJUB_FIELD_BYTES]; typedef struct { - jubjub_fq U; - jubjub_fq V; - jubjub_fq Z; - jubjub_fq T1; - jubjub_fq T2; + jubjub_fq U; + jubjub_fq V; + jubjub_fq Z; + jubjub_fq T1; + jubjub_fq T2; } jubjub_extendedpoint; extern const jubjub_extendedpoint JUBJUB_GEN; -#define SWAP_BYTES(x, y, tmp) \ - { \ - tmp = x; \ - x = y; \ - y = tmp; \ - } +#define SWAP_BYTES(x, y, tmp) \ + { \ + tmp = x; \ + x = y; \ + y = tmp; \ + } -#define SWAP_ENDIAN_U64(x, tmp) \ - { \ - SWAP_BYTES(*x, *(x + 7), tmp); \ - SWAP_BYTES(*(x + 1), *(x + 6), tmp); \ - SWAP_BYTES(*(x + 2), *(x + 5), tmp); \ - SWAP_BYTES(*(x + 3), *(x + 4), tmp); \ - } +#define SWAP_ENDIAN_U64(x, tmp) \ + { \ + SWAP_BYTES(*x, *(x + 7), tmp); \ + SWAP_BYTES(*(x + 1), *(x + 6), tmp); \ + SWAP_BYTES(*(x + 2), *(x + 5), tmp); \ + SWAP_BYTES(*(x + 3), *(x + 4), tmp); \ + } -#define SWAP_ENDIAN_BYTES(x) \ - { \ - uint8_t tmp = 0; \ - for (int i = 0; i < 32 / 2; i++) { \ - SWAP_BYTES(*(x + i), *(x + (32 - 1 - i)), tmp); \ - } \ - } +#define SWAP_ENDIAN_BYTES(x) \ + { \ + uint8_t tmp = 0; \ + for (int i = 0; i < 32 / 2; i++) { \ + SWAP_BYTES(*(x + i), *(x + (32 - 1 - i)), tmp); \ + } \ + } zxerr_t jubjub_extendedpoint_tobytes(uint8_t *s, jubjub_extendedpoint *p); diff --git a/app/src/key.c b/app/src/key.c index 815454ed..dc3adc57 100644 --- a/app/src/key.c +++ b/app/src/key.c @@ -14,6 +14,8 @@ * limitations under the License. ********************************************************************************/ +#include + #include "actions.h" #include "app_mode.h" #include "coin.h" @@ -21,67 +23,70 @@ #include "zxerror.h" #include "zxformat.h" #include "zxmacros.h" -#include zxerr_t key_getNumItems(uint8_t *num_items) { - zemu_log_stack("key_getNumItems"); - *num_items = 1; - if (app_mode_expert()) { - *num_items = 2; - } - return zxerr_ok; + zemu_log_stack("key_getNumItems"); + *num_items = 1; + if (app_mode_expert()) { + *num_items = 2; + } + return zxerr_ok; } -zxerr_t key_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, - char *outVal, uint16_t outValLen, uint8_t pageIdx, +zxerr_t key_getItem(int8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outVal, + uint16_t outValLen, + uint8_t pageIdx, uint8_t *pageCount) { - snprintf(outKey, outKeyLen, "?"); - snprintf(outVal, outValLen, "?"); + snprintf(outKey, outKeyLen, "?"); + snprintf(outVal, outValLen, "?"); - zemu_log_stack("key_getItem"); - switch (displayIdx) { - case 0: { - zemu_log_stack("case 0"); - char tmpBuffer[100]; - MEMZERO(tmpBuffer, sizeof(tmpBuffer)); - switch (key_state.kind) { - case key_ovk: - snprintf(outKey, outKeyLen, "Send OVK?"); - array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32); - pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); - return zxerr_ok; - case key_ivk: - snprintf(outKey, outKeyLen, "Send IVK?"); - array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32); - pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); - return zxerr_ok; - case key_fvk: - snprintf(outKey, outKeyLen, "Send FVK?\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?"); - array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32); - pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); - return zxerr_ok; - default: - return zxerr_unknown; - } - } - case 1: { - if (!app_mode_expert()) { - return zxerr_no_data; - } + zemu_log_stack("key_getItem"); + switch (displayIdx) { + case 0: { + zemu_log_stack("case 0"); + char tmpBuffer[100]; + MEMZERO(tmpBuffer, sizeof(tmpBuffer)); + switch (key_state.kind) { + case key_ovk: + snprintf(outKey, outKeyLen, "Send OVK?"); + array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32); + pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); + return zxerr_ok; + case key_ivk: + snprintf(outKey, outKeyLen, "Send IVK?"); + array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32); + pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); + return zxerr_ok; + case key_fvk: + snprintf(outKey, outKeyLen, "Send FVK?\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?"); + array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), G_io_apdu_buffer, 32); + pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); + return zxerr_ok; + default: + return zxerr_unknown; + } + } + case 1: { + if (!app_mode_expert()) { + return zxerr_no_data; + } - snprintf(outKey, outKeyLen, "Your Path"); - char buffer[300]; - bip32_to_str(buffer, sizeof(buffer), hdPath, HDPATH_LEN_DEFAULT); - pageString(outVal, outValLen, buffer, pageIdx, pageCount); - return zxerr_ok; - } - default: - return zxerr_no_data; - } + snprintf(outKey, outKeyLen, "Your Path"); + char buffer[300]; + bip32_to_str(buffer, sizeof(buffer), hdPath, HDPATH_LEN_DEFAULT); + pageString(outVal, outValLen, buffer, pageIdx, pageCount); + return zxerr_ok; + } + default: + return zxerr_no_data; + } } diff --git a/app/src/key.h b/app/src/key.h index cb1460e7..0c8ff2b6 100644 --- a/app/src/key.h +++ b/app/src/key.h @@ -28,8 +28,12 @@ extern "C" { zxerr_t key_getNumItems(uint8_t *num_items); /// Gets an specific item from the address view (including paging) -zxerr_t key_getItem(int8_t displayIdx, char *outKey, uint16_t outKeyLen, - char *outValue, uint16_t outValueLen, uint8_t pageIdx, +zxerr_t key_getItem(int8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outValue, + uint16_t outValueLen, + uint8_t pageIdx, uint8_t *pageCount); #ifdef __cplusplus diff --git a/app/src/nvdata.c b/app/src/nvdata.c index 16e5144d..f4fc3534 100644 --- a/app/src/nvdata.c +++ b/app/src/nvdata.c @@ -15,6 +15,7 @@ ********************************************************************************/ #include "nvdata.h" + #include "app_main.h" #include "coin.h" #include "constants.h" @@ -34,10 +35,8 @@ spendlist_t NV_CONST N_spendlist_impl __attribute__((aligned(64))); outputlist_t NV_CONST N_outputlist_impl __attribute__((aligned(64))); #define N_outputlist (*(NV_VOLATILE outputlist_t *)PIC(&N_outputlist_impl)) -transaction_info_t NV_CONST N_transaction_info_impl - __attribute__((aligned(64))); -#define N_transactioninfo \ - (*(NV_VOLATILE transaction_info_t *)PIC(&N_transaction_info_impl)) +transaction_info_t NV_CONST N_transaction_info_impl __attribute__((aligned(64))); +#define N_transactioninfo (*(NV_VOLATILE transaction_info_t *)PIC(&N_transaction_info_impl)) transaction_header_t transaction_header; @@ -47,333 +46,334 @@ transaction_header_t transaction_header; ////////////////////////////////////////////////////////////// zxerr_t t_inlist_append_item(uint32_t *p, uint8_t *script, uint64_t v) { - zemu_log_stack("let's append"); - if (transaction_header.t_in_len >= T_IN_LIST_SIZE) { - return zxerr_unknown; - } + zemu_log_stack("let's append"); + if (transaction_header.t_in_len >= T_IN_LIST_SIZE) { + return zxerr_unknown; + } - transaction_header.total_value += v; + transaction_header.total_value += v; - t_input_item_t newitem; - MEMCPY(newitem.path, (uint8_t *)p, PATH_SIZE * sizeof(uint32_t)); - MEMCPY(newitem.script, script, SCRIPT_SIZE); - newitem.value = v; + t_input_item_t newitem; + MEMCPY(newitem.path, (uint8_t *)p, PATH_SIZE * sizeof(uint32_t)); + MEMCPY(newitem.script, script, SCRIPT_SIZE); + newitem.value = v; - MEMCPY_NV((void *)&N_t_inlist.items[transaction_header.t_in_len], &newitem, - sizeof(t_input_item_t)); + MEMCPY_NV((void *)&N_t_inlist.items[transaction_header.t_in_len], &newitem, sizeof(t_input_item_t)); - transaction_header.t_in_len += 1; - zemu_log_stack("appended"); - return zxerr_ok; + transaction_header.t_in_len += 1; + zemu_log_stack("appended"); + return zxerr_ok; } t_input_item_t *t_inlist_retrieve_item(uint8_t i) { - if (transaction_header.t_in_len < i) { - return NULL; - } else { - return (t_input_item_t *)&N_t_inlist.items[i]; - } + if (transaction_header.t_in_len < i) { + return NULL; + } else { + return (t_input_item_t *)&N_t_inlist.items[i]; + } } zxerr_t t_outlist_append_item(uint8_t *addr, uint64_t v) { - if (transaction_header.t_out_len >= T_OUT_LIST_SIZE) { - return zxerr_unknown; - } + if (transaction_header.t_out_len >= T_OUT_LIST_SIZE) { + return zxerr_unknown; + } - transaction_header.total_value -= v; + transaction_header.total_value -= v; - t_output_item_t newitem = {0}; - MEMCPY(newitem.address, addr, SCRIPT_SIZE); - newitem.value = v; + t_output_item_t newitem = {0}; + MEMCPY(newitem.address, addr, SCRIPT_SIZE); + newitem.value = v; - MEMCPY_NV((void *)&N_t_outlist.items[transaction_header.t_out_len], &newitem, - sizeof(t_output_item_t)); + MEMCPY_NV((void *)&N_t_outlist.items[transaction_header.t_out_len], &newitem, sizeof(t_output_item_t)); - transaction_header.t_out_len += 1; - return zxerr_ok; + transaction_header.t_out_len += 1; + return zxerr_ok; } t_output_item_t *t_outlist_retrieve_item(uint8_t i) { - if (transaction_header.t_out_len < i) { - return NULL; - } else { - return (t_output_item_t *)&N_t_outlist.items[i]; - } + if (transaction_header.t_out_len < i) { + return NULL; + } else { + return (t_output_item_t *)&N_t_outlist.items[i]; + } } -uint8_t t_inlist_len() { return transaction_header.t_in_len; } +uint8_t t_inlist_len() { + return transaction_header.t_in_len; +} // Returns the list of all transparent input amounts. uint64_t t_inlist_retrieve_item_amount(uint8_t i) { - return N_t_inlist.items[i].value; + return N_t_inlist.items[i].value; } void t_inlist_retrieve_item_script(uint8_t i, uint8_t *output) { - MEMCPY(output, (const void *)N_t_inlist.items[i].script, SCRIPT_SIZE); + MEMCPY(output, (const void *)N_t_inlist.items[i].script, SCRIPT_SIZE); } -uint8_t t_outlist_len() { return transaction_header.t_out_len; } +uint8_t t_outlist_len() { + return transaction_header.t_out_len; +} bool transparent_signatures_more_extract() { - return transaction_header.t_sign_index > 0; + return transaction_header.t_sign_index > 0; } zxerr_t transparent_signatures_append(uint8_t *signature) { - if (transaction_header.t_sign_index >= transaction_header.t_in_len) { - return zxerr_unknown; - } - MEMCPY_NV((void *)&N_transactioninfo - .transparent_signatures[transaction_header.t_sign_index], - signature, SIGNATURE_SIZE); - transaction_header.t_sign_index++; - return zxerr_ok; + if (transaction_header.t_sign_index >= transaction_header.t_in_len) { + return zxerr_unknown; + } + MEMCPY_NV((void *)&N_transactioninfo.transparent_signatures[transaction_header.t_sign_index], signature, SIGNATURE_SIZE); + transaction_header.t_sign_index++; + return zxerr_ok; } zxerr_t get_next_transparent_signature(uint8_t *result) { - const uint8_t index = transaction_header.t_in_len - transaction_header.t_sign_index; - if (index >= transaction_header.t_in_len) { - return zxerr_unknown; - } - MEMCPY(result, (void *)&N_transactioninfo.transparent_signatures[index], SIGNATURE_SIZE); - transaction_header.t_sign_index--; - if (!transparent_signatures_more_extract() && - !spend_signatures_more_extract()) { - transaction_reset(); - view_idle_show(0, NULL); - } - return zxerr_ok; + const uint8_t index = transaction_header.t_in_len - transaction_header.t_sign_index; + if (index >= transaction_header.t_in_len) { + return zxerr_unknown; + } + MEMCPY(result, (void *)&N_transactioninfo.transparent_signatures[index], SIGNATURE_SIZE); + transaction_header.t_sign_index--; + if (!transparent_signatures_more_extract() && !spend_signatures_more_extract()) { + transaction_reset(); + view_idle_show(0, NULL); + } + return zxerr_ok; } bool spend_signatures_more_extract() { - return transaction_header.spends_sign_index > 0; + return transaction_header.spends_sign_index > 0; } zxerr_t spend_signatures_append(uint8_t *signature) { - if (transaction_header.spends_sign_index >= - transaction_header.spendlist_len) { - return zxerr_unknown; - } + if (transaction_header.spends_sign_index >= transaction_header.spendlist_len) { + return zxerr_unknown; + } - MEMCPY_NV((void *)&N_transactioninfo - .spend_signatures[transaction_header.spends_sign_index], - signature, SIGNATURE_SIZE); - transaction_header.spends_sign_index++; - return zxerr_ok; + MEMCPY_NV((void *)&N_transactioninfo.spend_signatures[transaction_header.spends_sign_index], signature, SIGNATURE_SIZE); + transaction_header.spends_sign_index++; + return zxerr_ok; } zxerr_t get_next_spend_signature(uint8_t *result) { - const uint8_t index = transaction_header.spendlist_len - transaction_header.spends_sign_index; - if (index >= transaction_header.spendlist_len) { - return zxerr_unknown; - } - MEMCPY(result, (void *)&N_transactioninfo.spend_signatures[index], SIGNATURE_SIZE); - transaction_header.spends_sign_index--; - if (!transparent_signatures_more_extract() && - !spend_signatures_more_extract()) { - transaction_reset(); - view_idle_show(0, NULL); - } - return zxerr_ok; + const uint8_t index = transaction_header.spendlist_len - transaction_header.spends_sign_index; + if (index >= transaction_header.spendlist_len) { + return zxerr_unknown; + } + MEMCPY(result, (void *)&N_transactioninfo.spend_signatures[index], SIGNATURE_SIZE); + transaction_header.spends_sign_index--; + if (!transparent_signatures_more_extract() && !spend_signatures_more_extract()) { + transaction_reset(); + view_idle_show(0, NULL); + } + return zxerr_ok; } void transaction_reset() { - MEMZERO(&transaction_header, sizeof(transaction_header_t)); - zeroize_flashstorage(); + MEMZERO(&transaction_header, sizeof(transaction_header_t)); + zeroize_flashstorage(); } -bool spendlist_is_active() { return transaction_header.spendlist_len > 0; } +bool spendlist_is_active() { + return transaction_header.spendlist_len > 0; +} -zxerr_t spendlist_append_item(uint32_t p, uint64_t v, uint8_t *div, - uint8_t *pkd, uint8_t *rcm, uint8_t *alpha) { - if (transaction_header.spendlist_len >= SPEND_LIST_SIZE) { - return zxerr_unknown; - } +zxerr_t spendlist_append_item(uint32_t p, uint64_t v, uint8_t *div, uint8_t *pkd, uint8_t *rcm, uint8_t *alpha) { + if (transaction_header.spendlist_len >= SPEND_LIST_SIZE) { + return zxerr_unknown; + } - transaction_header.sapling_value += v; - transaction_header.total_value += v; - uint32_t path = p | 0x80000000; + transaction_header.sapling_value += v; + transaction_header.total_value += v; + uint32_t path = p | 0x80000000; - spend_item_t newitem; - newitem.path = path; - newitem.value = v; - MEMCPY(newitem.div, div, DIV_SIZE); - MEMCPY(newitem.pkd, pkd, PKD_SIZE); - MEMCPY(newitem.rcmvalue, rcm, RCM_SIZE); - MEMCPY(newitem.alpha, alpha, ALPHA_SIZE); + spend_item_t newitem; + newitem.path = path; + newitem.value = v; + MEMCPY(newitem.div, div, DIV_SIZE); + MEMCPY(newitem.pkd, pkd, PKD_SIZE); + MEMCPY(newitem.rcmvalue, rcm, RCM_SIZE); + MEMCPY(newitem.alpha, alpha, ALPHA_SIZE); - MEMCPY_NV((void *)&N_spendlist.items[transaction_header.spendlist_len], - &newitem, sizeof(spend_item_t)); + MEMCPY_NV((void *)&N_spendlist.items[transaction_header.spendlist_len], &newitem, sizeof(spend_item_t)); - transaction_header.spendlist_len += 1; - return zxerr_ok; + transaction_header.spendlist_len += 1; + return zxerr_ok; } spend_item_t *spendlist_retrieve_item(uint8_t i) { - if (transaction_header.spendlist_len < i) { - return NULL; - } else { - return (spend_item_t *)&N_spendlist.items[i]; - } + if (transaction_header.spendlist_len < i) { + return NULL; + } else { + return (spend_item_t *)&N_spendlist.items[i]; + } } spend_item_t *spendlist_extract_next() { - if (transaction_header.spendlist_len <= - transaction_header.spenddata_extract_index) { - return NULL; - } else { - spend_item_t *result = - (spend_item_t *)&N_spendlist - .items[transaction_header.spenddata_extract_index]; - transaction_header.spenddata_extract_index += 1; - return result; - } + if (transaction_header.spendlist_len <= transaction_header.spenddata_extract_index) { + return NULL; + } else { + spend_item_t *result = (spend_item_t *)&N_spendlist.items[transaction_header.spenddata_extract_index]; + transaction_header.spenddata_extract_index += 1; + return result; + } } bool spendlist_more_extract() { - return transaction_header.spendlist_len > - transaction_header.spenddata_extract_index; + return transaction_header.spendlist_len > transaction_header.spenddata_extract_index; } -uint8_t spendlist_len() { return transaction_header.spendlist_len; } - -bool outputlist_is_active() { return transaction_header.outputlist_len > 0; } - -zxerr_t outputlist_append_item(uint8_t *d, uint8_t *pkd, uint64_t v, - uint8_t memotype, uint8_t *ovk, uint8_t *rcmv, - uint8_t *rseed) { - if (transaction_header.outputlist_len >= OUTPUT_LIST_SIZE) { - return zxerr_unknown; - } - transaction_header.sapling_value -= v; - transaction_header.total_value -= v; +uint8_t spendlist_len() { + return transaction_header.spendlist_len; +} - output_item_t newitem = {0}; - newitem.value = v; - MEMCPY(newitem.rcmvalue, rcmv, RCM_V_SIZE); - MEMCPY(newitem.rseed, rseed, RSEED_SIZE); - MEMCPY(newitem.div, d, DIV_SIZE); - MEMCPY(newitem.pkd, pkd, PKD_SIZE); - MEMCPY(newitem.ovk, ovk, OVK_SET_SIZE); - newitem.memotype = memotype; - MEMCPY_NV((void *)&N_outputlist.items[transaction_header.outputlist_len], - &newitem, sizeof(output_item_t)); +bool outputlist_is_active() { + return transaction_header.outputlist_len > 0; +} - transaction_header.outputlist_len += 1; - return zxerr_ok; +zxerr_t outputlist_append_item( + uint8_t *d, uint8_t *pkd, uint64_t v, uint8_t memotype, uint8_t *ovk, uint8_t *rcmv, uint8_t *rseed) { + if (transaction_header.outputlist_len >= OUTPUT_LIST_SIZE) { + return zxerr_unknown; + } + transaction_header.sapling_value -= v; + transaction_header.total_value -= v; + + output_item_t newitem = {0}; + newitem.value = v; + MEMCPY(newitem.rcmvalue, rcmv, RCM_V_SIZE); + MEMCPY(newitem.rseed, rseed, RSEED_SIZE); + MEMCPY(newitem.div, d, DIV_SIZE); + MEMCPY(newitem.pkd, pkd, PKD_SIZE); + MEMCPY(newitem.ovk, ovk, OVK_SET_SIZE); + newitem.memotype = memotype; + MEMCPY_NV((void *)&N_outputlist.items[transaction_header.outputlist_len], &newitem, sizeof(output_item_t)); + + transaction_header.outputlist_len += 1; + return zxerr_ok; } output_item_t *outputlist_retrieve_item(uint8_t i) { - if (transaction_header.outputlist_len <= i) { - return NULL; - } else { - return (output_item_t *)&N_outputlist.items[i]; - } + if (transaction_header.outputlist_len <= i) { + return NULL; + } else { + return (output_item_t *)&N_outputlist.items[i]; + } } output_item_t *outputlist_extract_next() { - if (transaction_header.outputlist_len <= - transaction_header.outputdata_extract_index) { - return NULL; - } else { - output_item_t *result = - (output_item_t *)&N_outputlist - .items[transaction_header.outputdata_extract_index]; - transaction_header.outputdata_extract_index += 1; - return result; - } + if (transaction_header.outputlist_len <= transaction_header.outputdata_extract_index) { + return NULL; + } else { + output_item_t *result = (output_item_t *)&N_outputlist.items[transaction_header.outputdata_extract_index]; + transaction_header.outputdata_extract_index += 1; + return result; + } } bool outputlist_more_extract() { - return transaction_header.outputlist_len > - transaction_header.outputdata_extract_index; + return transaction_header.outputlist_len > transaction_header.outputdata_extract_index; } -uint8_t outputlist_len() { return transaction_header.outputlist_len; } +uint8_t outputlist_len() { + return transaction_header.outputlist_len; +} // valueBalance is not the total value, but the // net value of Sapling Spend transfers minus Output transfers. // i.e. the contents of the Sapling value pool -int64_t get_valuebalance() { return transaction_header.sapling_value; } -uint64_t get_totalvalue() { return transaction_header.total_value; } -uint8_t get_state() { return transaction_header.state; } +int64_t get_valuebalance() { + return transaction_header.sapling_value; +} +uint64_t get_totalvalue() { + return transaction_header.total_value; +} +uint8_t get_state() { + return transaction_header.state; +} -void set_state(uint8_t state) { transaction_header.state = state; } +void set_state(uint8_t state) { + transaction_header.state = state; +} -void state_reset() { transaction_header.state = STATE_INITIAL; } +void state_reset() { + transaction_header.state = STATE_INITIAL; +} void zeroize_tin_data() { - uint32_t p[PATH_SIZE]; - uint8_t s[SCRIPT_SIZE]; - uint64_t v = 0; - MEMZERO(p, sizeof(p)); - MEMZERO(s, sizeof(s)); - transaction_header.t_in_len = 0; - for (int i = 0; i < T_IN_LIST_SIZE; i++) { - t_inlist_append_item(p, s, v); - } - transaction_header.t_in_len = 0; + uint32_t p[PATH_SIZE]; + uint8_t s[SCRIPT_SIZE]; + uint64_t v = 0; + MEMZERO(p, sizeof(p)); + MEMZERO(s, sizeof(s)); + transaction_header.t_in_len = 0; + for (int i = 0; i < T_IN_LIST_SIZE; i++) { + t_inlist_append_item(p, s, v); + } + transaction_header.t_in_len = 0; } void zeroize_tout_data() { - uint8_t s[SCRIPT_SIZE]; - uint64_t v = 0; - MEMZERO(s, sizeof(s)); - transaction_header.t_out_len = 0; - for (int i = 0; i < T_OUT_LIST_SIZE; i++) { - t_outlist_append_item(s, v); - } - transaction_header.t_out_len = 0; + uint8_t s[SCRIPT_SIZE]; + uint64_t v = 0; + MEMZERO(s, sizeof(s)); + transaction_header.t_out_len = 0; + for (int i = 0; i < T_OUT_LIST_SIZE; i++) { + t_outlist_append_item(s, v); + } + transaction_header.t_out_len = 0; } void zeroize_spend_data() { - uint32_t p = 0; - uint64_t v = 0; - uint8_t div[DIV_SIZE] = {0}; - uint8_t pkd[PKD_SIZE] = {0}; - uint8_t rcm[RCM_SIZE] = {0}; - uint8_t alpha[ALPHA_SIZE] = {0}; - transaction_header.spendlist_len = 0; - for (int i = 0; i < SPEND_LIST_SIZE; i++) { - spendlist_append_item(p, v, div, pkd, rcm, alpha); - } - transaction_header.spendlist_len = 0; + uint32_t p = 0; + uint64_t v = 0; + uint8_t div[DIV_SIZE] = {0}; + uint8_t pkd[PKD_SIZE] = {0}; + uint8_t rcm[RCM_SIZE] = {0}; + uint8_t alpha[ALPHA_SIZE] = {0}; + transaction_header.spendlist_len = 0; + for (int i = 0; i < SPEND_LIST_SIZE; i++) { + spendlist_append_item(p, v, div, pkd, rcm, alpha); + } + transaction_header.spendlist_len = 0; } void zeroize_output_data() { - uint64_t v = 0; - uint8_t div[DIV_SIZE] = {0}; - uint8_t pkd[PKD_SIZE] = {0}; - uint8_t ovk[OVK_SIZE] = {0}; - uint8_t rcmv[RCM_V_SIZE] = {0}; - uint8_t rseed[RSEED_SIZE] = {0}; - uint8_t memotype = 0x00; - transaction_header.outputlist_len = 0; - for (int i = 0; i < OUTPUT_LIST_SIZE; i++) { - outputlist_append_item(div, pkd, v, memotype, ovk, rcmv, rseed); - } - transaction_header.outputlist_len = 0; + uint64_t v = 0; + uint8_t div[DIV_SIZE] = {0}; + uint8_t pkd[PKD_SIZE] = {0}; + uint8_t ovk[OVK_SIZE] = {0}; + uint8_t rcmv[RCM_V_SIZE] = {0}; + uint8_t rseed[RSEED_SIZE] = {0}; + uint8_t memotype = 0x00; + transaction_header.outputlist_len = 0; + for (int i = 0; i < OUTPUT_LIST_SIZE; i++) { + outputlist_append_item(div, pkd, v, memotype, ovk, rcmv, rseed); + } + transaction_header.outputlist_len = 0; } void zeroize_signatures() { - uint8_t sig[SIGNATURE_SIZE] = {0}; - - transaction_header.t_sign_index = 0; - for (int i = 0; i < T_IN_LIST_SIZE; i++) { - transparent_signatures_append(sig); - } - transaction_header.t_sign_index = 0; - - transaction_header.spends_sign_index = 0; - for (int i = 0; i < T_IN_LIST_SIZE; i++) { - spend_signatures_append(sig); - } - transaction_header.spends_sign_index = 0; + uint8_t sig[SIGNATURE_SIZE] = {0}; + + transaction_header.t_sign_index = 0; + for (int i = 0; i < T_IN_LIST_SIZE; i++) { + transparent_signatures_append(sig); + } + transaction_header.t_sign_index = 0; + + transaction_header.spends_sign_index = 0; + for (int i = 0; i < T_IN_LIST_SIZE; i++) { + spend_signatures_append(sig); + } + transaction_header.spends_sign_index = 0; } void zeroize_flashstorage() { - zeroize_tin_data(); - zeroize_tout_data(); - zeroize_spend_data(); - zeroize_output_data(); - zeroize_signatures(); + zeroize_tin_data(); + zeroize_tout_data(); + zeroize_spend_data(); + zeroize_output_data(); + zeroize_signatures(); } diff --git a/app/src/nvdata.h b/app/src/nvdata.h index c89f92b2..e9badb5d 100644 --- a/app/src/nvdata.h +++ b/app/src/nvdata.h @@ -15,75 +15,76 @@ ********************************************************************************/ #pragma once +#include + #include "coin.h" #include "constants.h" #include "zxerror.h" #include "zxmacros.h" -#include typedef struct { - uint32_t path[PATH_SIZE]; - uint8_t script[SCRIPT_SIZE]; - uint64_t value; + uint32_t path[PATH_SIZE]; + uint8_t script[SCRIPT_SIZE]; + uint64_t value; } t_input_item_t; typedef struct { - uint8_t address[SCRIPT_SIZE]; - uint64_t value; + uint8_t address[SCRIPT_SIZE]; + uint64_t value; } t_output_item_t; typedef struct { - t_input_item_t items[T_IN_LIST_SIZE]; + t_input_item_t items[T_IN_LIST_SIZE]; } t_inlist_t; typedef struct { - t_output_item_t items[T_OUT_LIST_SIZE]; + t_output_item_t items[T_OUT_LIST_SIZE]; } t_outlist_t; typedef struct { - uint32_t path; - uint64_t value; - uint8_t div[DIV_SIZE]; - uint8_t pkd[PKD_SIZE]; - uint8_t rcmvalue[RCM_SIZE]; - uint8_t alpha[ALPHA_SIZE]; + uint32_t path; + uint64_t value; + uint8_t div[DIV_SIZE]; + uint8_t pkd[PKD_SIZE]; + uint8_t rcmvalue[RCM_SIZE]; + uint8_t alpha[ALPHA_SIZE]; } spend_item_t; typedef struct { - uint64_t total_value; - int64_t sapling_value; - uint8_t state; - uint8_t t_in_len; - uint8_t t_out_len; - uint8_t spendlist_len; - uint8_t outputlist_len; - uint8_t spenddata_extract_index; - uint8_t outputdata_extract_index; - uint8_t spends_sign_index; - uint8_t t_sign_index; + uint64_t total_value; + int64_t sapling_value; + uint8_t state; + uint8_t t_in_len; + uint8_t t_out_len; + uint8_t spendlist_len; + uint8_t outputlist_len; + uint8_t spenddata_extract_index; + uint8_t outputdata_extract_index; + uint8_t spends_sign_index; + uint8_t t_sign_index; } transaction_header_t; typedef struct { - spend_item_t items[SPEND_LIST_SIZE]; + spend_item_t items[SPEND_LIST_SIZE]; } spendlist_t; typedef struct { - uint8_t div[DIV_SIZE]; - uint8_t pkd[PKD_SIZE]; - uint64_t value; - uint8_t memotype; - uint8_t rcmvalue[RCM_V_SIZE]; - uint8_t rseed[RSEED_SIZE]; - uint8_t ovk[OVK_SET_SIZE]; + uint8_t div[DIV_SIZE]; + uint8_t pkd[PKD_SIZE]; + uint64_t value; + uint8_t memotype; + uint8_t rcmvalue[RCM_V_SIZE]; + uint8_t rseed[RSEED_SIZE]; + uint8_t ovk[OVK_SET_SIZE]; } output_item_t; typedef struct { - output_item_t items[SPEND_LIST_SIZE]; + output_item_t items[SPEND_LIST_SIZE]; } outputlist_t; typedef struct { - uint8_t transparent_signatures[T_IN_LIST_SIZE][64]; - uint8_t spend_signatures[SPEND_LIST_SIZE][64]; + uint8_t transparent_signatures[T_IN_LIST_SIZE][64]; + uint8_t spend_signatures[SPEND_LIST_SIZE][64]; } transaction_info_t; #ifdef __cplusplus @@ -99,13 +100,13 @@ void state_reset(); void set_state(uint8_t state); -#define STATE_INITIAL 0 -#define STATE_PROCESSED_INPUTS 1 +#define STATE_INITIAL 0 +#define STATE_PROCESSED_INPUTS 1 #define STATE_PROCESSED_SPEND_EXTRACTIONS 2 -#define STATE_PROCESSED_ALL_EXTRACTIONS 3 -#define STATE_CHECKING_ALL_TXDATA 4 -#define STATE_VERIFIED_ALL_TXDATA 5 -#define STATE_SIGNED_TX 6 +#define STATE_PROCESSED_ALL_EXTRACTIONS 3 +#define STATE_CHECKING_ALL_TXDATA 4 +#define STATE_VERIFIED_ALL_TXDATA 5 +#define STATE_SIGNED_TX 6 // metadata flash api int64_t get_valuebalance(); @@ -147,8 +148,7 @@ uint8_t t_outlist_len(); // spendlist flashstorage API bool spendlist_is_active(); -zxerr_t spendlist_append_item(uint32_t p, uint64_t v, uint8_t *div, - uint8_t *pkd, uint8_t *rcm, uint8_t *alpha); +zxerr_t spendlist_append_item(uint32_t p, uint64_t v, uint8_t *div, uint8_t *pkd, uint8_t *rcm, uint8_t *alpha); uint8_t spendlist_len(); @@ -163,9 +163,8 @@ bool spendlist_more_extract(); // outputlist flashstorage API bool outputlist_is_active(); -zxerr_t outputlist_append_item(uint8_t *d, uint8_t *pkd, uint64_t v, - uint8_t memotype, uint8_t *ovk, uint8_t *rcmv, - uint8_t *rseed); +zxerr_t outputlist_append_item( + uint8_t *d, uint8_t *pkd, uint64_t v, uint8_t memotype, uint8_t *ovk, uint8_t *rcmv, uint8_t *rseed); uint8_t outputlist_len(); diff --git a/app/src/parser.c b/app/src/parser.c index 2f4711b4..2b954763 100644 --- a/app/src/parser.c +++ b/app/src/parser.c @@ -15,416 +15,391 @@ ********************************************************************************/ #include "parser.h" -#include "app_mode.h" -#include "parser_common.h" -#include "parser_impl.h" + +#include #include #include #include +#include "app_mode.h" #include "base58.h" #include "bech32.h" #include "coin.h" #include "nvdata.h" +#include "parser_common.h" +#include "parser_impl.h" #include "parser_txdef.h" #include "rslib.h" #include "view.h" -#include #define DEFAULT_MEMOTYPE 0xf6 typedef enum { - type_tin = 0, - type_tout = 1, - type_sspend = 2, - type_sout = 3, - type_txfee = 4, + type_tin = 0, + type_tout = 1, + type_sspend = 2, + type_sout = 3, + type_txfee = 4, } sapling_parser_type_e; typedef struct { - sapling_parser_type_e type; - uint8_t index; + sapling_parser_type_e type; + uint8_t index; } parser_sapling_t; -parser_error_t parser_sapling_path_with_div(const uint8_t *data, size_t dataLen, - parser_addr_div_t *prs) { - if (dataLen != 15) { - return parser_context_unexpected_size; - } - parser_context_t pars_ctx; - parser_error_t pars_err; - pars_ctx.offset = 0; - pars_ctx.buffer = data; - pars_ctx.bufferLen = 4; - uint32_t p = 0; - pars_err = _readUInt32(&pars_ctx, &p); - if (pars_err != parser_ok) { - return pars_err; - } - prs->path = p | 0x80000000; - memcpy(prs->div, data + 4, DIV_SIZE); - return parser_ok; +parser_error_t parser_sapling_path_with_div(const uint8_t *data, size_t dataLen, parser_addr_div_t *prs) { + if (dataLen != 15) { + return parser_context_unexpected_size; + } + parser_context_t pars_ctx; + parser_error_t pars_err; + pars_ctx.offset = 0; + pars_ctx.buffer = data; + pars_ctx.bufferLen = 4; + uint32_t p = 0; + pars_err = _readUInt32(&pars_ctx, &p); + if (pars_err != parser_ok) { + return pars_err; + } + prs->path = p | 0x80000000; + memcpy(prs->div, data + 4, DIV_SIZE); + return parser_ok; } -parser_error_t parser_sapling_path(const uint8_t *data, size_t dataLen, - uint32_t *p) { - if (dataLen < 4) { - return parser_context_unexpected_size; - } - parser_context_t pars_ctx; - parser_error_t pars_err; - pars_ctx.offset = 0; - pars_ctx.buffer = data; - pars_ctx.bufferLen = 4; - pars_err = _readUInt32(&pars_ctx, p); - if (pars_err != parser_ok) { - return pars_err; - } - *p |= 0x80000000; - return parser_ok; +parser_error_t parser_sapling_path(const uint8_t *data, size_t dataLen, uint32_t *p) { + if (dataLen < 4) { + return parser_context_unexpected_size; + } + parser_context_t pars_ctx; + parser_error_t pars_err; + pars_ctx.offset = 0; + pars_ctx.buffer = data; + pars_ctx.bufferLen = 4; + pars_err = _readUInt32(&pars_ctx, p); + if (pars_err != parser_ok) { + return pars_err; + } + *p |= 0x80000000; + return parser_ok; } void view_tx_state() { #if !defined(TARGET_STAX) - uint8_t state = get_state(); - switch (state) { - case STATE_PROCESSED_INPUTS: - case STATE_PROCESSED_SPEND_EXTRACTIONS: { - view_message_show("Zcash", "Step [1/5]"); - break; - } - - case STATE_PROCESSED_ALL_EXTRACTIONS: { - view_message_show("Zcash", "Step [2/5]"); - break; - } - - case STATE_CHECKING_ALL_TXDATA: { - view_message_show("Zcash", "Step [3/5]"); - break; - } - - case STATE_VERIFIED_ALL_TXDATA: { - view_message_show("Zcash", "Step [4/5]"); - break; - } - - case STATE_SIGNED_TX: { - view_message_show("Zcash", "Step [5/5]"); - break; - } - - default: { - view_idle_show(0, NULL); - } - } - UX_WAIT_DISPLAYED(); + uint8_t state = get_state(); + switch (state) { + case STATE_PROCESSED_INPUTS: + case STATE_PROCESSED_SPEND_EXTRACTIONS: { + view_message_show("Zcash", "Step [1/5]"); + break; + } + + case STATE_PROCESSED_ALL_EXTRACTIONS: { + view_message_show("Zcash", "Step [2/5]"); + break; + } + + case STATE_CHECKING_ALL_TXDATA: { + view_message_show("Zcash", "Step [3/5]"); + break; + } + + case STATE_VERIFIED_ALL_TXDATA: { + view_message_show("Zcash", "Step [4/5]"); + break; + } + + case STATE_SIGNED_TX: { + view_message_show("Zcash", "Step [5/5]"); + break; + } + + default: { + view_idle_show(0, NULL); + } + } + UX_WAIT_DISPLAYED(); #endif - return; + return; } -parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, - size_t dataLen) { - CHECK_PARSER_ERR(parser_init(ctx, data, dataLen)) +parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, size_t dataLen) { + CHECK_PARSER_ERR(parser_init(ctx, data, dataLen)) - return parser_ok; + return parser_ok; } parser_error_t parser_validate() { - // Iterate through all items to check that all can be shown and are valid - uint8_t numItems = 0; - CHECK_PARSER_ERR(parser_getNumItems(&numItems)) + // Iterate through all items to check that all can be shown and are valid + uint8_t numItems = 0; + CHECK_PARSER_ERR(parser_getNumItems(&numItems)) - char tmpKey[30]; - char tmpVal[30]; + char tmpKey[30]; + char tmpVal[30]; - for (uint8_t idx = 0; idx < numItems; idx++) { - uint8_t pageCount = 0; - CHECK_PARSER_ERR(parser_getItem(idx, tmpKey, sizeof(tmpKey), tmpVal, - sizeof(tmpVal), 0, &pageCount)) - } + for (uint8_t idx = 0; idx < numItems; idx++) { + uint8_t pageCount = 0; + CHECK_PARSER_ERR(parser_getItem(idx, tmpKey, sizeof(tmpKey), tmpVal, sizeof(tmpVal), 0, &pageCount)) + } - return parser_ok; + return parser_ok; } -parser_error_t parser_sapling_display_value(uint64_t value, char *outVal, - uint16_t outValLen, uint8_t pageIdx, - uint8_t *pageCount) { - char tmpBuffer[100]; - fpuint64_to_str(tmpBuffer, sizeof(tmpBuffer), value, 8); - pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); - return parser_ok; +parser_error_t parser_sapling_display_value( + uint64_t value, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { + char tmpBuffer[100]; + fpuint64_to_str(tmpBuffer, sizeof(tmpBuffer), value, 8); + pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); + return parser_ok; } -parser_error_t parser_sapling_display_address_t(const uint8_t *addr, - char *outVal, - uint16_t outValLen, - uint8_t pageIdx, - uint8_t *pageCount) { - MEMZERO(outVal, outValLen); +parser_error_t parser_sapling_display_address_t( + const uint8_t *addr, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { + MEMZERO(outVal, outValLen); - uint8_t address[VERSION_SIZE + CX_RIPEMD160_SIZE + CX_SHA256_SIZE]; - address[0] = VERSION_P2PKH >> 8; - address[1] = VERSION_P2PKH & 0xFF; - MEMCPY(address + VERSION_SIZE, addr + 4, CX_RIPEMD160_SIZE); + uint8_t address[VERSION_SIZE + CX_RIPEMD160_SIZE + CX_SHA256_SIZE]; + address[0] = VERSION_P2PKH >> 8; + address[1] = VERSION_P2PKH & 0xFF; + MEMCPY(address + VERSION_SIZE, addr + 4, CX_RIPEMD160_SIZE); - cx_hash_sha256(address, VERSION_SIZE + CX_RIPEMD160_SIZE, - address + VERSION_SIZE + CX_RIPEMD160_SIZE, CX_SHA256_SIZE); + cx_hash_sha256(address, VERSION_SIZE + CX_RIPEMD160_SIZE, address + VERSION_SIZE + CX_RIPEMD160_SIZE, CX_SHA256_SIZE); - cx_hash_sha256(address + VERSION_SIZE + CX_RIPEMD160_SIZE, CX_SHA256_SIZE, - address + VERSION_SIZE + CX_RIPEMD160_SIZE, CX_SHA256_SIZE); + cx_hash_sha256(address + VERSION_SIZE + CX_RIPEMD160_SIZE, CX_SHA256_SIZE, address + VERSION_SIZE + CX_RIPEMD160_SIZE, + CX_SHA256_SIZE); - uint8_t tmpBuffer[60]; - size_t outLen = sizeof(tmpBuffer); + uint8_t tmpBuffer[60]; + size_t outLen = sizeof(tmpBuffer); - int err = - encode_base58(address, VERSION_SIZE + CX_RIPEMD160_SIZE + CHECKSUM_SIZE, - tmpBuffer, &outLen); - if (err != 0) { - return parser_unexpected_error; - } - - pageString(outVal, outValLen, (char *)tmpBuffer, pageIdx, pageCount); - return parser_ok; -} + int err = encode_base58(address, VERSION_SIZE + CX_RIPEMD160_SIZE + CHECKSUM_SIZE, tmpBuffer, &outLen); + if (err != 0) { + return parser_unexpected_error; + } -parser_error_t parser_sapling_display_address_s(uint8_t *div, uint8_t *pkd, - char *outVal, - uint16_t outValLen, - uint8_t pageIdx, - uint8_t *pageCount) { - - uint8_t address[DIV_SIZE + PKD_SIZE]; - MEMCPY(address, div, DIV_SIZE); - MEMCPY(address + DIV_SIZE, pkd, PKD_SIZE); - char tmpBuffer[100]; - bech32EncodeFromBytes(tmpBuffer, sizeof(tmpBuffer), BECH32_HRP, address, - sizeof(address), 1, BECH32_ENCODING_BECH32); - pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); - return parser_ok; + pageString(outVal, outValLen, (char *)tmpBuffer, pageIdx, pageCount); + return parser_ok; } -parser_error_t parser_sapling_getTypes(const uint16_t displayIdx, - parser_sapling_t *prs) { - uint16_t index = displayIdx; - - if (index < t_inlist_len() * NUM_ITEMS_TIN && t_inlist_len() > 0) { - prs->type = type_tin; - prs->index = index; +parser_error_t parser_sapling_display_address_s( + uint8_t *div, uint8_t *pkd, char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) { + uint8_t address[DIV_SIZE + PKD_SIZE]; + MEMCPY(address, div, DIV_SIZE); + MEMCPY(address + DIV_SIZE, pkd, PKD_SIZE); + char tmpBuffer[100]; + bech32EncodeFromBytes(tmpBuffer, sizeof(tmpBuffer), BECH32_HRP, address, sizeof(address), 1, BECH32_ENCODING_BECH32); + pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); return parser_ok; - } - index -= t_inlist_len() * NUM_ITEMS_TIN; - if (index < t_outlist_len() * NUM_ITEMS_TOUT && t_outlist_len() > 0) { - prs->type = type_tout; - prs->index = index; - return parser_ok; - } - index -= t_outlist_len() * NUM_ITEMS_TOUT; - if (index < spendlist_len() * NUM_ITEMS_SSPEND && spendlist_len() > 0) { - prs->type = type_sspend; - prs->index = index; - return parser_ok; - } - index -= spendlist_len() * NUM_ITEMS_SSPEND; - if (index < outputlist_len() * NUM_ITEMS_SOUT && outputlist_len() > 0) { - prs->type = type_sout; - prs->index = index; - return parser_ok; - } - prs->type = type_txfee; - return parser_ok; } -parser_error_t parser_getNumItems(uint8_t *num_items) { - *num_items = t_inlist_len() * NUM_ITEMS_TIN + - t_outlist_len() * NUM_ITEMS_TOUT + - spendlist_len() * NUM_ITEMS_SSPEND + - outputlist_len() * NUM_ITEMS_SOUT + NUM_ITEMS_CONST; +parser_error_t parser_sapling_getTypes(const uint16_t displayIdx, parser_sapling_t *prs) { + uint16_t index = displayIdx; - return parser_ok; -} - -parser_error_t parser_getItem(uint8_t displayIdx, char *outKey, - uint16_t outKeyLen, char *outVal, - uint16_t outValLen, uint8_t pageIdx, - uint8_t *pageCount) { - MEMZERO(outKey, outKeyLen); - MEMZERO(outVal, outValLen); - snprintf(outKey, outKeyLen, "?"); - snprintf(outVal, outValLen, "?"); - *pageCount = 1; - - uint8_t numItems; - CHECK_PARSER_ERR(parser_getNumItems(&numItems)) - CHECK_APP_CANARY() - - if (displayIdx >= numItems) { - return parser_no_data; - } - - parser_sapling_t prs; - MEMZERO(&prs, sizeof(parser_sapling_t)); - CHECK_PARSER_ERR(parser_sapling_getTypes(displayIdx, &prs)); - - switch (prs.type) { - case type_tin: { - uint8_t itemnum = prs.index / NUM_ITEMS_TIN; - const t_input_item_t *item = t_inlist_retrieve_item(itemnum); - uint8_t itemtype = prs.index % NUM_ITEMS_TIN; - - switch (itemtype) { - case 0: { - snprintf(outKey, outKeyLen, "T-in addr"); - return parser_sapling_display_address_t(item->script, outVal, outValLen, - pageIdx, pageCount); + if (index < t_inlist_len() * NUM_ITEMS_TIN && t_inlist_len() > 0) { + prs->type = type_tin; + prs->index = index; + return parser_ok; } - case 1: { - snprintf(outKey, outKeyLen, "T-in (ZEC)"); - return parser_sapling_display_value(item->value, outVal, outValLen, - pageIdx, pageCount); + index -= t_inlist_len() * NUM_ITEMS_TIN; + if (index < t_outlist_len() * NUM_ITEMS_TOUT && t_outlist_len() > 0) { + prs->type = type_tout; + prs->index = index; + return parser_ok; } + index -= t_outlist_len() * NUM_ITEMS_TOUT; + if (index < spendlist_len() * NUM_ITEMS_SSPEND && spendlist_len() > 0) { + prs->type = type_sspend; + prs->index = index; + return parser_ok; } - } - - case type_tout: { - uint8_t itemnum = prs.index / NUM_ITEMS_TOUT; - t_output_item_t *item = t_outlist_retrieve_item(itemnum); - uint8_t itemtype = prs.index % NUM_ITEMS_TOUT; - switch (itemtype) { - case 0: { - snprintf(outKey, outKeyLen, "T-out addr"); - return parser_sapling_display_address_t(item->address, outVal, outValLen, - pageIdx, pageCount); + index -= spendlist_len() * NUM_ITEMS_SSPEND; + if (index < outputlist_len() * NUM_ITEMS_SOUT && outputlist_len() > 0) { + prs->type = type_sout; + prs->index = index; + return parser_ok; } - case 1: { - snprintf(outKey, outKeyLen, "T-out (ZEC)"); - return parser_sapling_display_value(item->value, outVal, outValLen, - pageIdx, pageCount); - } - } - } - case type_sspend: { - uint8_t itemnum = prs.index / NUM_ITEMS_SSPEND; - spend_item_t *item = spendlist_retrieve_item(itemnum); - uint8_t itemtype = prs.index % NUM_ITEMS_SSPEND; - switch (itemtype) { - case 0: { - snprintf(outKey, outKeyLen, "S-in addr"); - return parser_sapling_display_address_s(item->div, item->pkd, outVal, - outValLen, pageIdx, pageCount); - } - case 1: { - snprintf(outKey, outKeyLen, "S-in (ZEC)"); - return parser_sapling_display_value(item->value, outVal, outValLen, - pageIdx, pageCount); - } - } - } + prs->type = type_txfee; + return parser_ok; +} - case type_sout: { +parser_error_t parser_getNumItems(uint8_t *num_items) { + *num_items = t_inlist_len() * NUM_ITEMS_TIN + t_outlist_len() * NUM_ITEMS_TOUT + spendlist_len() * NUM_ITEMS_SSPEND + + outputlist_len() * NUM_ITEMS_SOUT + NUM_ITEMS_CONST; - uint8_t itemnum = prs.index / NUM_ITEMS_SOUT; - output_item_t *item = outputlist_retrieve_item(itemnum); - if (item == NULL) { - return parser_unexpected_error; - } + return parser_ok; +} - uint8_t itemtype = prs.index % NUM_ITEMS_SOUT; - switch (itemtype) { - case 0: { - snprintf(outKey, outKeyLen, "S-out addr"); - return parser_sapling_display_address_s(item->div, item->pkd, outVal, - outValLen, pageIdx, pageCount); - } - case 1: { - snprintf(outKey, outKeyLen, "S-out (ZEC)"); - return parser_sapling_display_value(item->value, outVal, outValLen, - pageIdx, pageCount); - } - case 2: { - snprintf(outKey, outKeyLen, "S-out Memotype"); - if (item->memotype == DEFAULT_MEMOTYPE) { - snprintf(outVal, outValLen, "Default"); - } else { - snprintf(outVal, outValLen, "Custom"); - } - return parser_ok; +parser_error_t parser_getItem(uint8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outVal, + uint16_t outValLen, + uint8_t pageIdx, + uint8_t *pageCount) { + MEMZERO(outKey, outKeyLen); + MEMZERO(outVal, outValLen); + snprintf(outKey, outKeyLen, "?"); + snprintf(outVal, outValLen, "?"); + *pageCount = 1; + + uint8_t numItems; + CHECK_PARSER_ERR(parser_getNumItems(&numItems)) + CHECK_APP_CANARY() + + if (displayIdx >= numItems) { + return parser_no_data; } - case 3: { - snprintf(outKey, outKeyLen, "S-out OVK"); - if (item->ovk[0] == 0x01) { - char tmpBuffer[100] = {0}; - array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), item->ovk + 1, OVK_SIZE); - pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); - } else { - snprintf(outVal, outValLen, "None"); - } - return parser_ok; + parser_sapling_t prs; + MEMZERO(&prs, sizeof(parser_sapling_t)); + CHECK_PARSER_ERR(parser_sapling_getTypes(displayIdx, &prs)); + + switch (prs.type) { + case type_tin: { + uint8_t itemnum = prs.index / NUM_ITEMS_TIN; + const t_input_item_t *item = t_inlist_retrieve_item(itemnum); + uint8_t itemtype = prs.index % NUM_ITEMS_TIN; + + switch (itemtype) { + case 0: { + snprintf(outKey, outKeyLen, "T-in addr"); + return parser_sapling_display_address_t(item->script, outVal, outValLen, pageIdx, pageCount); + } + case 1: { + snprintf(outKey, outKeyLen, "T-in (ZEC)"); + return parser_sapling_display_value(item->value, outVal, outValLen, pageIdx, pageCount); + } + } + } + + case type_tout: { + uint8_t itemnum = prs.index / NUM_ITEMS_TOUT; + t_output_item_t *item = t_outlist_retrieve_item(itemnum); + uint8_t itemtype = prs.index % NUM_ITEMS_TOUT; + switch (itemtype) { + case 0: { + snprintf(outKey, outKeyLen, "T-out addr"); + return parser_sapling_display_address_t(item->address, outVal, outValLen, pageIdx, pageCount); + } + case 1: { + snprintf(outKey, outKeyLen, "T-out (ZEC)"); + return parser_sapling_display_value(item->value, outVal, outValLen, pageIdx, pageCount); + } + } + } + case type_sspend: { + uint8_t itemnum = prs.index / NUM_ITEMS_SSPEND; + spend_item_t *item = spendlist_retrieve_item(itemnum); + uint8_t itemtype = prs.index % NUM_ITEMS_SSPEND; + switch (itemtype) { + case 0: { + snprintf(outKey, outKeyLen, "S-in addr"); + return parser_sapling_display_address_s(item->div, item->pkd, outVal, outValLen, pageIdx, pageCount); + } + case 1: { + snprintf(outKey, outKeyLen, "S-in (ZEC)"); + return parser_sapling_display_value(item->value, outVal, outValLen, pageIdx, pageCount); + } + } + } + + case type_sout: { + uint8_t itemnum = prs.index / NUM_ITEMS_SOUT; + output_item_t *item = outputlist_retrieve_item(itemnum); + if (item == NULL) { + return parser_unexpected_error; + } + + uint8_t itemtype = prs.index % NUM_ITEMS_SOUT; + switch (itemtype) { + case 0: { + snprintf(outKey, outKeyLen, "S-out addr"); + return parser_sapling_display_address_s(item->div, item->pkd, outVal, outValLen, pageIdx, pageCount); + } + case 1: { + snprintf(outKey, outKeyLen, "S-out (ZEC)"); + return parser_sapling_display_value(item->value, outVal, outValLen, pageIdx, pageCount); + } + case 2: { + snprintf(outKey, outKeyLen, "S-out Memotype"); + if (item->memotype == DEFAULT_MEMOTYPE) { + snprintf(outVal, outValLen, "Default"); + } else { + snprintf(outVal, outValLen, "Custom"); + } + return parser_ok; + } + + case 3: { + snprintf(outKey, outKeyLen, "S-out OVK"); + if (item->ovk[0] == 0x01) { + char tmpBuffer[100] = {0}; + array_to_hexstr(tmpBuffer, sizeof(tmpBuffer), item->ovk + 1, OVK_SIZE); + pageString(outVal, outValLen, tmpBuffer, pageIdx, pageCount); + } else { + snprintf(outVal, outValLen, "None"); + } + return parser_ok; + } + } + } + + case type_txfee: { + snprintf(outKey, outKeyLen, "Fee"); + return parser_sapling_display_value(get_totalvalue(), outVal, outValLen, pageIdx, pageCount); + } + + default: { + return parser_no_data; + } } - } - } - - case type_txfee: { - snprintf(outKey, outKeyLen, "Fee"); - return parser_sapling_display_value(get_totalvalue(), outVal, outValLen, - pageIdx, pageCount); - } - - default: { - return parser_no_data; - } - } - return parser_ok; + return parser_ok; } const char *parser_getErrorDescription(parser_error_t err) { - switch (err) { - // General errors - case parser_ok: - return "No error"; - case parser_no_data: - return "No more data"; - case parser_init_context_empty: - return "Initialized empty context"; - case parser_display_idx_out_of_range: - return "display_idx_out_of_range"; - case parser_display_page_out_of_range: - return "display_page_out_of_range"; - case parser_unexpected_error: - return "Unexpected internal error"; - case parser_no_memory_for_state: - return "No enough memory for parser state"; - /////////// Context specific - case parser_context_mismatch: - return "context prefix is invalid"; - case parser_context_unexpected_size: - return "context unexpected size"; - case parser_context_invalid_chars: - return "context invalid chars"; - // Required fields error - // Coin specific - case parser_invalid_output_script: - return "Invalid output script"; - case parser_unexpected_type: - return "Unexpected data type"; - case parser_unexpected_method: - return "Unexpected method"; - case parser_unexpected_buffer_end: - return "Unexpected buffer end"; - case parser_unexpected_value: - return "Unexpected value"; - case parser_unexpected_number_items: - return "Unexpected number of items"; - case parser_unexpected_characters: - return "Unexpected characters"; - case parser_unexpected_field: - return "Unexpected field"; - case parser_value_out_of_range: - return "Value out of range"; - case parser_invalid_address: - return "Invalid address format"; - default: - return "Unrecognized error code"; - } + switch (err) { + // General errors + case parser_ok: + return "No error"; + case parser_no_data: + return "No more data"; + case parser_init_context_empty: + return "Initialized empty context"; + case parser_display_idx_out_of_range: + return "display_idx_out_of_range"; + case parser_display_page_out_of_range: + return "display_page_out_of_range"; + case parser_unexpected_error: + return "Unexpected internal error"; + case parser_no_memory_for_state: + return "No enough memory for parser state"; + /////////// Context specific + case parser_context_mismatch: + return "context prefix is invalid"; + case parser_context_unexpected_size: + return "context unexpected size"; + case parser_context_invalid_chars: + return "context invalid chars"; + // Required fields error + // Coin specific + case parser_invalid_output_script: + return "Invalid output script"; + case parser_unexpected_type: + return "Unexpected data type"; + case parser_unexpected_method: + return "Unexpected method"; + case parser_unexpected_buffer_end: + return "Unexpected buffer end"; + case parser_unexpected_value: + return "Unexpected value"; + case parser_unexpected_number_items: + return "Unexpected number of items"; + case parser_unexpected_characters: + return "Unexpected characters"; + case parser_unexpected_field: + return "Unexpected field"; + case parser_value_out_of_range: + return "Value out of range"; + case parser_invalid_address: + return "Invalid address format"; + default: + return "Unrecognized error code"; + } } diff --git a/app/src/parser.h b/app/src/parser.h index 0814d290..65bd398c 100644 --- a/app/src/parser.h +++ b/app/src/parser.h @@ -25,29 +25,26 @@ extern "C" { #include "parser_common.h" #include "parser_txdef.h" -#define NUM_ITEMS_TIN 2 // address, value -#define NUM_ITEMS_TOUT 2 // address, value -#define NUM_ITEMS_SSPEND 2 // address, value -#define NUM_ITEMS_SOUT 4 // address, value, memotype, OVK? -#define NUM_ITEMS_CONST 1 // txfee +#define NUM_ITEMS_TIN 2 // address, value +#define NUM_ITEMS_TOUT 2 // address, value +#define NUM_ITEMS_SSPEND 2 // address, value +#define NUM_ITEMS_SOUT 4 // address, value, memotype, OVK? +#define NUM_ITEMS_CONST 1 // txfee typedef struct { - uint32_t path; - uint8_t div[11]; + uint32_t path; + uint8_t div[11]; } parser_addr_div_t; -parser_error_t parser_sapling_path_with_div(const uint8_t *data, size_t dataLen, - parser_addr_div_t *prs); -parser_error_t parser_sapling_path(const uint8_t *data, size_t dataLen, - uint32_t *p); +parser_error_t parser_sapling_path_with_div(const uint8_t *data, size_t dataLen, parser_addr_div_t *prs); +parser_error_t parser_sapling_path(const uint8_t *data, size_t dataLen, uint32_t *p); void view_tx_state(); const char *parser_getErrorDescription(parser_error_t err); //// parses a tx buffer -parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, - size_t dataLen); +parser_error_t parser_parse(parser_context_t *ctx, const uint8_t *data, size_t dataLen); //// verifies tx fields parser_error_t parser_validate(); @@ -56,9 +53,12 @@ parser_error_t parser_validate(); parser_error_t parser_getNumItems(uint8_t *num_items); // retrieves a readable output for each field / page -parser_error_t parser_getItem(uint8_t displayIdx, char *outKey, - uint16_t outKeyLen, char *outValue, - uint16_t outValueLen, uint8_t pageIdx, +parser_error_t parser_getItem(uint8_t displayIdx, + char *outKey, + uint16_t outKeyLen, + char *outValue, + uint16_t outValueLen, + uint8_t pageIdx, uint8_t *pageCount); void parser_resetState(); diff --git a/app/src/parser_common.h b/app/src/parser_common.h index c750abcf..7f76453c 100644 --- a/app/src/parser_common.h +++ b/app/src/parser_common.h @@ -19,62 +19,62 @@ extern "C" { #endif -#include "parser_txdef.h" #include #include -#define CHECK_PARSER_ERR(__CALL) \ - { \ - parser_error_t __err = __CALL; \ - CHECK_APP_CANARY() \ - if (__err != parser_ok) \ - return __err; \ - } +#include "parser_txdef.h" + +#define CHECK_PARSER_ERR(__CALL) \ + { \ + parser_error_t __err = __CALL; \ + CHECK_APP_CANARY() \ + if (__err != parser_ok) return __err; \ + } typedef enum { - // Generic errors - parser_ok = 0, - parser_no_data, - parser_init_context_empty, - parser_display_idx_out_of_range, - parser_display_page_out_of_range, - parser_unexpected_error, - parser_no_memory_for_state, - // Context related errors - parser_context_mismatch, - parser_context_unexpected_size, - parser_context_invalid_chars, - parser_context_unknown_prefix, - // Required fields - //////////////////////// - // Coin specific - parser_invalid_output_script, - parser_unexpected_type, - parser_unexpected_method, - parser_not_allowed, - parser_not_supported, - parser_unexpected_buffer_end, - parser_unexpected_value, - parser_unexpected_number_items, - parser_unexpected_characters, - parser_unexpected_field, - parser_value_out_of_range, - parser_invalid_address, - parser_value_too_many_bytes, - parser_unexpected_module, - parser_unexpected_callIndex, - parser_unexpected_unparsed_bytes, - parser_print_not_supported, - parser_tx_nesting_not_supported, - parser_tx_nesting_limit_reached, - parser_tx_call_vec_too_large, + // Generic errors + parser_ok = 0, + parser_no_data, + parser_init_context_empty, + parser_display_idx_out_of_range, + parser_display_page_out_of_range, + parser_unexpected_error, + parser_no_memory_for_state, + // Context related errors + parser_context_mismatch, + parser_context_unexpected_size, + parser_context_invalid_chars, + parser_context_unknown_prefix, + // Required fields + //////////////////////// + // Coin specific + parser_invalid_output_script, + parser_unexpected_type, + parser_unexpected_method, + parser_not_allowed, + parser_not_supported, + parser_unexpected_buffer_end, + parser_unexpected_value, + parser_unexpected_number_items, + parser_unexpected_characters, + parser_unexpected_field, + parser_value_out_of_range, + parser_invalid_address, + parser_value_too_many_bytes, + parser_unexpected_module, + parser_unexpected_callIndex, + parser_unexpected_unparsed_bytes, + parser_print_not_supported, + parser_tx_nesting_not_supported, + parser_tx_nesting_limit_reached, + parser_tx_call_vec_too_large, } parser_error_t; typedef struct { - const uint8_t *buffer; - uint16_t bufferLen; - uint16_t offset; - parser_tx_t *tx_obj; + const uint8_t *buffer; + uint16_t bufferLen; + uint16_t offset; + parser_tx_t *tx_obj; } parser_context_t; #ifdef __cplusplus diff --git a/app/src/parser_impl.c b/app/src/parser_impl.c index 4a010155..6af4d2b8 100644 --- a/app/src/parser_impl.c +++ b/app/src/parser_impl.c @@ -15,80 +15,80 @@ ********************************************************************************/ #include "parser_impl.h" + +#include + #include "coin.h" #include "crypto.h" #include "parser_txdef.h" #include "zxformat.h" -#include -parser_error_t parser_init_context(parser_context_t *ctx, const uint8_t *buffer, - uint16_t bufferSize) { - ctx->offset = 0; - ctx->buffer = NULL; - ctx->bufferLen = 0; +parser_error_t parser_init_context(parser_context_t *ctx, const uint8_t *buffer, uint16_t bufferSize) { + ctx->offset = 0; + ctx->buffer = NULL; + ctx->bufferLen = 0; - if (bufferSize == 0 || buffer == NULL) { - // Not available, use defaults - return parser_init_context_empty; - } + if (bufferSize == 0 || buffer == NULL) { + // Not available, use defaults + return parser_init_context_empty; + } - ctx->buffer = buffer; - ctx->bufferLen = bufferSize; + ctx->buffer = buffer; + ctx->bufferLen = bufferSize; - ZEMU_LOGF(100, "init_context %d bytes", bufferSize); + ZEMU_LOGF(100, "init_context %d bytes", bufferSize); - return parser_ok; + return parser_ok; } -parser_error_t parser_init(parser_context_t *ctx, const uint8_t *buffer, - uint16_t bufferSize) { - CHECK_PARSER_ERR(parser_init_context(ctx, buffer, bufferSize)) - return parser_ok; +parser_error_t parser_init(parser_context_t *ctx, const uint8_t *buffer, uint16_t bufferSize) { + CHECK_PARSER_ERR(parser_init_context(ctx, buffer, bufferSize)) + return parser_ok; } const char *parser_getErrorDescription(parser_error_t err) { - switch (err) { - // General errors - case parser_ok: - return "No error"; - case parser_no_data: - return "No more data"; - case parser_init_context_empty: - return "Initialized empty context"; - case parser_display_idx_out_of_range: - return "display_idx_out_of_range"; - case parser_display_page_out_of_range: - return "display_page_out_of_range"; - // Coin specific - case parser_not_allowed: - return "Not allowed"; - case parser_not_supported: - return "Not supported"; - case parser_unexpected_buffer_end: - return "Unexpected buffer end"; - case parser_unexpected_value: - return "Unexpected value"; - case parser_value_out_of_range: - return "Value out of range"; - case parser_value_too_many_bytes: - return "Value too many bytes"; - case parser_unexpected_module: - return "Unexpected module"; - case parser_unexpected_callIndex: - return "Unexpected call index"; - case parser_unexpected_unparsed_bytes: - return "Unexpected unparsed bytes"; - case parser_print_not_supported: - return "Value cannot be printed"; - case parser_tx_nesting_not_supported: - return "Call nesting not supported"; - case parser_tx_nesting_limit_reached: - return "Max nested calls reached"; - case parser_tx_call_vec_too_large: - return "Call vector exceeds limit"; - default: - return "Unrecognized error code"; - } + switch (err) { + // General errors + case parser_ok: + return "No error"; + case parser_no_data: + return "No more data"; + case parser_init_context_empty: + return "Initialized empty context"; + case parser_display_idx_out_of_range: + return "display_idx_out_of_range"; + case parser_display_page_out_of_range: + return "display_page_out_of_range"; + // Coin specific + case parser_not_allowed: + return "Not allowed"; + case parser_not_supported: + return "Not supported"; + case parser_unexpected_buffer_end: + return "Unexpected buffer end"; + case parser_unexpected_value: + return "Unexpected value"; + case parser_value_out_of_range: + return "Value out of range"; + case parser_value_too_many_bytes: + return "Value too many bytes"; + case parser_unexpected_module: + return "Unexpected module"; + case parser_unexpected_callIndex: + return "Unexpected call index"; + case parser_unexpected_unparsed_bytes: + return "Unexpected unparsed bytes"; + case parser_print_not_supported: + return "Value cannot be printed"; + case parser_tx_nesting_not_supported: + return "Call nesting not supported"; + case parser_tx_nesting_limit_reached: + return "Max nested calls reached"; + case parser_tx_call_vec_too_large: + return "Call vector exceeds limit"; + default: + return "Unrecognized error code"; + } } GEN_DEF_READFIX_UNSIGNED(8) diff --git a/app/src/parser_impl.h b/app/src/parser_impl.h index e19339d9..1ffe86d7 100644 --- a/app/src/parser_impl.h +++ b/app/src/parser_impl.h @@ -15,10 +15,11 @@ ********************************************************************************/ #pragma once +#include + #include "parser_common.h" #include "parser_txdef.h" #include "zxtypes.h" -#include #ifdef __cplusplus extern "C" { @@ -29,83 +30,72 @@ extern "C" { #include // Checks that there are at least SIZE bytes available in the buffer -#define CTX_CHECK_AVAIL(CTX, SIZE) \ - if ((CTX) == NULL || ((CTX)->offset + SIZE) > (CTX)->bufferLen) { \ - return parser_unexpected_buffer_end; \ - } +#define CTX_CHECK_AVAIL(CTX, SIZE) \ + if ((CTX) == NULL || ((CTX)->offset + SIZE) > (CTX)->bufferLen) { \ + return parser_unexpected_buffer_end; \ + } -#define CTX_CHECK_AND_ADVANCE(CTX, SIZE) \ - CTX_CHECK_AVAIL((CTX), (SIZE)) \ - (CTX)->offset += (SIZE); +#define CTX_CHECK_AND_ADVANCE(CTX, SIZE) \ + CTX_CHECK_AVAIL((CTX), (SIZE)) \ + (CTX)->offset += (SIZE); // Checks function input is valid -#define CHECK_INPUT() \ - if (v == NULL) { \ - return parser_no_data; \ - } \ - CTX_CHECK_AVAIL(c, \ - 1) // Checks that there is something available in the buffer - -#define CLEAN_AND_CHECK() \ - MEMZERO(outValue, outValueLen); \ - if (v == NULL) { \ - *pageCount = 0; \ - return parser_no_data; \ - } - -#define GEN_DEF_READARRAY(SIZE) \ - v->_ptr = c->buffer + c->offset; \ - CTX_CHECK_AND_ADVANCE(c, SIZE) \ - return parser_ok; - -#define GEN_DEF_TOSTRING_ARRAY(SIZE) \ - CLEAN_AND_CHECK(); \ - if (v->_ptr == NULL || outValueLen == 0) \ - return parser_unexpected_buffer_end; \ - const uint16_t outLenNormalized = (outValueLen - 1) / 2; \ - *pageCount = SIZE / outLenNormalized; \ - if (SIZE % outLenNormalized != 0) \ - *pageCount += 1; \ - const uint16_t pageOffset = pageIdx * outLenNormalized; \ - uint16_t loopmax = outLenNormalized; \ - if (loopmax > SIZE - pageOffset) \ - loopmax = SIZE - pageOffset; \ - for (uint16_t i = 0; i < loopmax; i++) { \ - const uint16_t offset = i << 1u; \ - const uint8_t *c = v->_ptr + pageOffset; \ - snprintf(outValue + offset, outValueLen - offset, "%02x", c[i]); \ - } \ - return parser_ok; - -#define GEN_DEC_READFIX_UNSIGNED(BITS) \ - parser_error_t _readUInt##BITS(parser_context_t *ctx, uint##BITS##_t *value) -#define GEN_DEF_READFIX_UNSIGNED(BITS) \ - parser_error_t _readUInt##BITS(parser_context_t *ctx, \ - uint##BITS##_t *value) { \ - if (value == NULL) \ - return parser_no_data; \ - *value = 0u; \ - for (uint8_t i = 0u; i < (BITS##u >> 3u); i++, ctx->offset++) { \ - if (ctx->offset >= ctx->bufferLen) \ - return parser_unexpected_buffer_end; \ - *value += (uint##BITS##_t) * (ctx->buffer + ctx->offset) << (8u * i); \ - } \ - return parser_ok; \ - } -#define GEN_DEC_READFIX_SIGNED(BITS) \ - parser_error_t _readInt##BITS(parser_context_t *ctx, int##BITS##_t *value) -#define GEN_DEF_READFIX_SIGNED(BITS) \ - parser_error_t _readInt##BITS(parser_context_t *ctx, int##BITS##_t *value) { \ - if (value == NULL) \ - return parser_no_data; \ - *value = 0; \ - for (int8_t i = 0; i < (BITS >> 3); i++, ctx->offset++) { \ - if (ctx->offset >= ctx->bufferLen) \ - return parser_unexpected_buffer_end; \ - *value += (int##BITS##_t) * (ctx->buffer + ctx->offset) << (8 * i); \ - } \ - return parser_ok; \ - } +#define CHECK_INPUT() \ + if (v == NULL) { \ + return parser_no_data; \ + } \ + CTX_CHECK_AVAIL(c, 1) // Checks that there is something available in the buffer + +#define CLEAN_AND_CHECK() \ + MEMZERO(outValue, outValueLen); \ + if (v == NULL) { \ + *pageCount = 0; \ + return parser_no_data; \ + } + +#define GEN_DEF_READARRAY(SIZE) \ + v->_ptr = c->buffer + c->offset; \ + CTX_CHECK_AND_ADVANCE(c, SIZE) \ + return parser_ok; + +#define GEN_DEF_TOSTRING_ARRAY(SIZE) \ + CLEAN_AND_CHECK(); \ + if (v->_ptr == NULL || outValueLen == 0) return parser_unexpected_buffer_end; \ + const uint16_t outLenNormalized = (outValueLen - 1) / 2; \ + *pageCount = SIZE / outLenNormalized; \ + if (SIZE % outLenNormalized != 0) *pageCount += 1; \ + const uint16_t pageOffset = pageIdx * outLenNormalized; \ + uint16_t loopmax = outLenNormalized; \ + if (loopmax > SIZE - pageOffset) loopmax = SIZE - pageOffset; \ + for (uint16_t i = 0; i < loopmax; i++) { \ + const uint16_t offset = i << 1u; \ + const uint8_t *c = v->_ptr + pageOffset; \ + snprintf(outValue + offset, outValueLen - offset, "%02x", c[i]); \ + } \ + return parser_ok; + +#define GEN_DEC_READFIX_UNSIGNED(BITS) parser_error_t _readUInt##BITS(parser_context_t *ctx, uint##BITS##_t *value) +#define GEN_DEF_READFIX_UNSIGNED(BITS) \ + parser_error_t _readUInt##BITS(parser_context_t *ctx, uint##BITS##_t *value) { \ + if (value == NULL) return parser_no_data; \ + *value = 0u; \ + for (uint8_t i = 0u; i < (BITS##u >> 3u); i++, ctx->offset++) { \ + if (ctx->offset >= ctx->bufferLen) return parser_unexpected_buffer_end; \ + *value += (uint##BITS##_t) * (ctx->buffer + ctx->offset) << (8u * i); \ + } \ + return parser_ok; \ + } +#define GEN_DEC_READFIX_SIGNED(BITS) parser_error_t _readInt##BITS(parser_context_t *ctx, int##BITS##_t *value) +#define GEN_DEF_READFIX_SIGNED(BITS) \ + parser_error_t _readInt##BITS(parser_context_t *ctx, int##BITS##_t *value) { \ + if (value == NULL) return parser_no_data; \ + *value = 0; \ + for (int8_t i = 0; i < (BITS >> 3); i++, ctx->offset++) { \ + if (ctx->offset >= ctx->bufferLen) return parser_unexpected_buffer_end; \ + *value += (int##BITS##_t) * (ctx->buffer + ctx->offset) << (8 * i); \ + } \ + return parser_ok; \ + } GEN_DEC_READFIX_UNSIGNED(8); @@ -117,8 +107,7 @@ GEN_DEC_READFIX_UNSIGNED(64); GEN_DEC_READFIX_SIGNED(64); -parser_error_t parser_init(parser_context_t *ctx, const uint8_t *buffer, - uint16_t bufferSize); +parser_error_t parser_init(parser_context_t *ctx, const uint8_t *buffer, uint16_t bufferSize); #ifdef __cplusplus } diff --git a/app/src/parser_txdef.h b/app/src/parser_txdef.h index f5cce9cc..fa82a43b 100644 --- a/app/src/parser_txdef.h +++ b/app/src/parser_txdef.h @@ -26,8 +26,8 @@ extern "C" { #include typedef struct { - uint8_t *state; - uint16_t len; + uint8_t *state; + uint16_t len; } parser_tx_t; #ifdef __cplusplus diff --git a/app/src/sighash.c b/app/src/sighash.c index 1e048f30..b995c204 100644 --- a/app/src/sighash.c +++ b/app/src/sighash.c @@ -15,13 +15,15 @@ ********************************************************************************/ #include "sighash.h" + +#include +#include + #include "cx.h" #include "index_sapling.h" #include "nvdata.h" #include "os.h" #include "txid.h" -#include -#include #include "zcash_utils.h" const uint8_t PERSONALIZATION_SIZE = 16; @@ -32,207 +34,214 @@ const uint8_t ZCASH_OUTPUTS_HASH_PERSONALIZATION[] = "ZcashOutputsHash"; const uint8_t CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION[] = "ZcashSSpendsHash"; const uint8_t CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION[] = "ZcashSOutputHash"; -const uint8_t CONSENSUS_BRANCH_ID_SAPLING[4] = {0xBB, 0x09, 0xB8, 0x76}; // sapling -const uint8_t CONSENSUS_BRANCH_ID_ORCHARD[4] = {0xB4, 0xD0, 0xD6, 0xC2}; // orchard +const uint8_t CONSENSUS_BRANCH_ID_SAPLING[4] = {0xBB, 0x09, 0xB8, 0x76}; // sapling +const uint8_t CONSENSUS_BRANCH_ID_ORCHARD[4] = {0xB4, 0xD0, 0xD6, 0xC2}; // orchard zxerr_t sapling_transparent_prevouts_hash(const uint8_t *input, uint8_t *output) { - const uint8_t n = t_inlist_len(); + const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0,(uint8_t *)ZCASH_PREVOUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_PREVOUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - return zxerr_ok; - } + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } - const uint8_t *data = input + INDEX_TIN_PREVOUT; - for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - if (cx_hash_no_throw(&ctx.header, 0, data, 36, NULL, 0) != CX_OK) { - return zxerr_invalid_crypto_settings; + const uint8_t *data = input + INDEX_TIN_PREVOUT; + for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { + if (cx_hash_no_throw(&ctx.header, 0, data, 36, NULL, 0) != CX_OK) { + return zxerr_invalid_crypto_settings; + } + io_seproxyhal_io_heartbeat(); } - io_seproxyhal_io_heartbeat(); - } - const cx_err_t error = cx_hash_no_throw(&ctx.header, CX_LAST, data, 36, output, HASH_SIZE); + const cx_err_t error = cx_hash_no_throw(&ctx.header, CX_LAST, data, 36, output, HASH_SIZE); - return error == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; + return error == CX_OK ? zxerr_ok : zxerr_invalid_crypto_settings; } zxerr_t sapling_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { - const uint8_t n = t_inlist_len(); + const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SEQUENCE_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SEQUENCE_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - return zxerr_ok; - } + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } - const uint8_t *data = input + INDEX_TIN_SEQ; - for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, 4, NULL, 0)); - io_seproxyhal_io_heartbeat(); - } - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, 4, output, HASH_SIZE)); + const uint8_t *data = input + INDEX_TIN_SEQ; + for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, 4, NULL, 0)); + io_seproxyhal_io_heartbeat(); + } + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, 4, output, HASH_SIZE)); - return zxerr_ok; + return zxerr_ok; } zxerr_t v4_transparent_outputs_hash(uint8_t *output) { - const uint8_t n = t_outlist_len(); + const uint8_t n = t_outlist_len(); - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - return zxerr_ok; - } + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } - uint8_t data[34] = {0}; - uint8_t i = 0; - for (; i < n - 1; i++) { + uint8_t data[34] = {0}; + uint8_t i = 0; + for (; i < n - 1; i++) { + t_output_item_t *item = t_outlist_retrieve_item(i); + MEMCPY(data, (uint8_t *)&(item->value), 8); + MEMCPY(data + 8, item->address, SCRIPT_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0)); + io_seproxyhal_io_heartbeat(); + } t_output_item_t *item = t_outlist_retrieve_item(i); MEMCPY(data, (uint8_t *)&(item->value), 8); MEMCPY(data + 8, item->address, SCRIPT_SIZE); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0)); - io_seproxyhal_io_heartbeat(); - } - t_output_item_t *item = t_outlist_retrieve_item(i); - MEMCPY(data, (uint8_t *)&(item->value), 8); - MEMCPY(data + 8, item->address, SCRIPT_SIZE); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE)); - return zxerr_ok; + return zxerr_ok; } -zxerr_t shielded_output_hash(const uint8_t *input, uint16_t inputlen, - uint8_t *output) { - if (inputlen == 0) { - MEMZERO(output, HASH_SIZE); - return zxerr_no_data; - } - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0,(uint8_t *)CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); - - return zxerr_ok; +zxerr_t shielded_output_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output) { + if (inputlen == 0) { + MEMZERO(output, HASH_SIZE); + return zxerr_no_data; + } + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)CTX_ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); + + return zxerr_ok; } -zxerr_t shielded_spend_hash(const uint8_t *input, uint16_t inputlen, - uint8_t *output) { - if (inputlen == 0) { - MEMZERO(output, HASH_SIZE); - return zxerr_no_data; - } +zxerr_t shielded_spend_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output) { + if (inputlen == 0) { + MEMZERO(output, HASH_SIZE); + return zxerr_no_data; + } - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0,(uint8_t *)CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION, 16)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)CTX_ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION, 16)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); - return zxerr_ok; + return zxerr_ok; } static zxerr_t signature_hash_v4(const uint8_t *input, uint16_t inputlen, uint8_t *output) { - zemu_log_stack("signature_hash_v4"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } + zemu_log_stack("signature_hash_v4"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } - cx_blake2b_t ctx = {0}; + cx_blake2b_t ctx = {0}; - uint8_t personalization[16] = "ZcashSigHash"; - MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); + uint8_t personalization[16] = "ZcashSigHash"; + MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, input, inputlen, output, HASH_SIZE)); - return zxerr_ok; + return zxerr_ok; } -static zxerr_t signature_hash_v5(const uint8_t *input, uint8_t *start_signdata, - uint8_t index, signable_input type, - uint8_t *output) { - zemu_log_stack("signature_hash_v5"); - if (input == NULL || start_signdata == NULL || output == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - - uint8_t personalization[16] = "ZcashTxHash_"; - MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); - - uint8_t header_digest[32] = {0}; - uint8_t transparent_digest[32] = {0}; - uint8_t sapling_digest[32] = {0}; - uint8_t orchard_digest[32] = {0}; - - CHECK_ZXERR(hash_header_txid_data(start_signdata, header_digest)); - io_seproxyhal_io_heartbeat(); - CHECK_ZXERR(transparent_sig_digest(input, start_signdata, index, type, transparent_digest)); - io_seproxyhal_io_heartbeat(); - CHECK_ZXERR(hash_sapling_txid_data(start_signdata, sapling_digest)); - io_seproxyhal_io_heartbeat(); - CHECK_ZXERR(hash_empty_orchard_txid_data(orchard_digest)); - io_seproxyhal_io_heartbeat(); - - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, header_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, transparent_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, sapling_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, orchard_digest, HASH_SIZE, output, HASH_SIZE)); - io_seproxyhal_io_heartbeat(); - - return zxerr_ok; +static zxerr_t signature_hash_v5( + const uint8_t *input, uint8_t *start_signdata, uint8_t index, signable_input type, uint8_t *output) { + zemu_log_stack("signature_hash_v5"); + if (input == NULL || start_signdata == NULL || output == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + + uint8_t personalization[16] = "ZcashTxHash_"; + MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); + + uint8_t header_digest[32] = {0}; + uint8_t transparent_digest[32] = {0}; + uint8_t sapling_digest[32] = {0}; + uint8_t orchard_digest[32] = {0}; + + CHECK_ZXERR(hash_header_txid_data(start_signdata, header_digest)); + io_seproxyhal_io_heartbeat(); + CHECK_ZXERR(transparent_sig_digest(input, start_signdata, index, type, transparent_digest)); + io_seproxyhal_io_heartbeat(); + CHECK_ZXERR(hash_sapling_txid_data(start_signdata, sapling_digest)); + io_seproxyhal_io_heartbeat(); + CHECK_ZXERR(hash_empty_orchard_txid_data(orchard_digest)); + io_seproxyhal_io_heartbeat(); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, header_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, transparent_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, sapling_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, orchard_digest, HASH_SIZE, output, HASH_SIZE)); + io_seproxyhal_io_heartbeat(); + + return zxerr_ok; } -zxerr_t signature_hash(const uint8_t *txdata, uint8_t *start_signdata, - uint16_t inputlen, const uint8_t tx_version, uint8_t *output) { - if (txdata == NULL || start_signdata == NULL || output == NULL) { - return zxerr_no_data; - } +zxerr_t signature_hash( + const uint8_t *txdata, uint8_t *start_signdata, uint16_t inputlen, const uint8_t tx_version, uint8_t *output) { + if (txdata == NULL || start_signdata == NULL || output == NULL) { + return zxerr_no_data; + } - if (tx_version == TX_VERSION_SAPLING) { - return signature_hash_v4(start_signdata, inputlen, output); - } else if (tx_version == TX_VERSION_NU5) { - return signature_hash_v5(txdata, start_signdata, 0, shielded, output); - } + if (tx_version == TX_VERSION_SAPLING) { + return signature_hash_v4(start_signdata, inputlen, output); + } else if (tx_version == TX_VERSION_NU5) { + return signature_hash_v5(txdata, start_signdata, 0, shielded, output); + } - return zxerr_unknown; + return zxerr_unknown; } -static zxerr_t signature_script_hash_v4(const uint8_t *input, uint16_t inputlen, - uint8_t *script, uint16_t scriptlen, uint8_t *output) { - if (input == NULL || script == NULL || output == NULL) { - return zxerr_no_data; - } +static zxerr_t signature_script_hash_v4( + const uint8_t *input, uint16_t inputlen, uint8_t *script, uint16_t scriptlen, uint8_t *output) { + if (input == NULL || script == NULL || output == NULL) { + return zxerr_no_data; + } - cx_blake2b_t ctx = {0}; - uint8_t personalization[16] = "ZcashSigHash"; - MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); + cx_blake2b_t ctx = {0}; + uint8_t personalization[16] = "ZcashSigHash"; + MEMCPY(personalization + 12, CONSENSUS_BRANCH_ID_ORCHARD, 4); - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, input, inputlen, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, script, scriptlen, output, HASH_SIZE)); - io_seproxyhal_io_heartbeat(); + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)personalization, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, input, inputlen, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, script, scriptlen, output, HASH_SIZE)); + io_seproxyhal_io_heartbeat(); - return zxerr_ok; + return zxerr_ok; } -zxerr_t signature_script_hash(const uint8_t *input, uint8_t *start_signdata, uint16_t inputlen, - uint8_t *script, uint16_t scriptlen, uint8_t index, - const uint8_t tx_version, uint8_t *output) { - if (input == NULL || start_signdata == NULL || script == NULL || output == NULL) { - return zxerr_no_data; - } +zxerr_t signature_script_hash(const uint8_t *input, + uint8_t *start_signdata, + uint16_t inputlen, + uint8_t *script, + uint16_t scriptlen, + uint8_t index, + const uint8_t tx_version, + uint8_t *output) { + if (input == NULL || start_signdata == NULL || script == NULL || output == NULL) { + return zxerr_no_data; + } - if (tx_version == TX_VERSION_SAPLING) { - return signature_script_hash_v4(start_signdata, inputlen, script, scriptlen,output); - } else if (tx_version == TX_VERSION_NU5) { - return signature_hash_v5(input, start_signdata, index, transparent, output); - } + if (tx_version == TX_VERSION_SAPLING) { + return signature_script_hash_v4(start_signdata, inputlen, script, scriptlen, output); + } else if (tx_version == TX_VERSION_NU5) { + return signature_hash_v5(input, start_signdata, index, transparent, output); + } - return zxerr_unknown; + return zxerr_unknown; } diff --git a/app/src/sighash.h b/app/src/sighash.h index 892ff262..0e38088b 100644 --- a/app/src/sighash.h +++ b/app/src/sighash.h @@ -17,11 +17,12 @@ #pragma once #include + #include "zxerror.h" typedef enum { - transparent = 0, - shielded = 1, + transparent = 0, + shielded = 1, } signable_input; zxerr_t sapling_transparent_prevouts_hash(const uint8_t *input, uint8_t *output); @@ -30,17 +31,18 @@ zxerr_t sapling_transparent_sequence_hash(const uint8_t *input, uint8_t *output) zxerr_t v4_transparent_outputs_hash(uint8_t *output); -zxerr_t shielded_output_hash(const uint8_t *input, uint16_t inputlen, - uint8_t *output); +zxerr_t shielded_output_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output); -zxerr_t shielded_spend_hash(const uint8_t *input, uint16_t inputlen, - uint8_t *output); +zxerr_t shielded_spend_hash(const uint8_t *input, uint16_t inputlen, uint8_t *output); -zxerr_t signature_hash(const uint8_t *txdata, uint8_t *start_signdata, - uint16_t inputlen, const uint8_t tx_version, - uint8_t *output); +zxerr_t signature_hash( + const uint8_t *txdata, uint8_t *start_signdata, uint16_t inputlen, const uint8_t tx_version, uint8_t *output); -zxerr_t signature_script_hash(const uint8_t *input, uint8_t *start_signdata, - uint16_t inputlen, uint8_t *script, - uint16_t scriptlen, uint8_t index, - const uint8_t tx_version, uint8_t *output); +zxerr_t signature_script_hash(const uint8_t *input, + uint8_t *start_signdata, + uint16_t inputlen, + uint8_t *script, + uint16_t scriptlen, + uint8_t index, + const uint8_t tx_version, + uint8_t *output); diff --git a/app/src/txid.c b/app/src/txid.c index 6cf61246..21e0535b 100644 --- a/app/src/txid.c +++ b/app/src/txid.c @@ -1,3 +1,7 @@ +#include +#include +#include + #include "constants.h" #include "cx.h" #include "index_NU5.h" @@ -5,86 +9,85 @@ #include "nvdata.h" #include "os.h" #include "sighash.h" -#include -#include -#include #include "zcash_utils.h" #define PERSONALIZATION_SIZE 16 // TxId level 1 node personalization -#define ZCASH_HEADERS_HASH_PERSONALIZATION "ZTxIdHeadersHash" +#define ZCASH_HEADERS_HASH_PERSONALIZATION "ZTxIdHeadersHash" #define ZCASH_TRANSPARENT_HASH_PERSONALIZATION "ZTxIdTranspaHash" -#define ZCASH_SAPLING_HASH_PERSONALIZATION "ZTxIdSaplingHash" -#define ZCASH_ORCHARD_HASH_PERSONALIZATION "ZTxIdOrchardHash" +#define ZCASH_SAPLING_HASH_PERSONALIZATION "ZTxIdSaplingHash" +#define ZCASH_ORCHARD_HASH_PERSONALIZATION "ZTxIdOrchardHash" // TxId transparent level 2 node personalization #define ZCASH_PREVOUTS_HASH_PERSONALIZATION "ZTxIdPrevoutHash" #define ZCASH_SEQUENCE_HASH_PERSONALIZATION "ZTxIdSequencHash" -#define ZCASH_OUTPUTS_HASH_PERSONALIZATION "ZTxIdOutputsHash" +#define ZCASH_OUTPUTS_HASH_PERSONALIZATION "ZTxIdOutputsHash" // TxId sapling level 2 node personalization -#define ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION "ZTxIdSSpendsHash" -#define ZCASH_SAPLING_SPENDS_COMPACT_HASH_PERSONALIZATION "ZTxIdSSpendCHash" -#define ZCASH_SAPLING_SPENDS_NONCOMPACT_HASH_PERSONALIZATION "ZTxIdSSpendNHash" +#define ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION "ZTxIdSSpendsHash" +#define ZCASH_SAPLING_SPENDS_COMPACT_HASH_PERSONALIZATION "ZTxIdSSpendCHash" +#define ZCASH_SAPLING_SPENDS_NONCOMPACT_HASH_PERSONALIZATION "ZTxIdSSpendNHash" -#define ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION "ZTxIdSOutputHash" -#define ZCASH_SAPLING_OUTPUTS_COMPACT_HASH_PERSONALIZATION "ZTxIdSOutC__Hash" -#define ZCASH_SAPLING_OUTPUTS_MEMOS_HASH_PERSONALIZATION "ZTxIdSOutM__Hash" +#define ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION "ZTxIdSOutputHash" +#define ZCASH_SAPLING_OUTPUTS_COMPACT_HASH_PERSONALIZATION "ZTxIdSOutC__Hash" +#define ZCASH_SAPLING_OUTPUTS_MEMOS_HASH_PERSONALIZATION "ZTxIdSOutM__Hash" #define ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION "ZTxIdSOutN__Hash" -#define ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION "Zcash___TxInHash" -#define ZCASH_TRANSPARENT_AMOUNTS_HASH_PERSONALIZATION "ZTxTrAmountsHash" -#define ZCASH_TRANSPARENT_SCRIPTS_HASH_PERSONALIZATION "ZTxTrScriptsHash" +#define ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION "Zcash___TxInHash" +#define ZCASH_TRANSPARENT_AMOUNTS_HASH_PERSONALIZATION "ZTxTrAmountsHash" +#define ZCASH_TRANSPARENT_SCRIPTS_HASH_PERSONALIZATION "ZTxTrScriptsHash" -#define SIGHASH_ALL 0x01 +#define SIGHASH_ALL 0x01 zxerr_t nu5_transparent_prevouts_hash(const uint8_t *input, uint8_t *output) { - zemu_log_stack("nu5_transparent_prevouts_hash\n"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } - - const uint8_t n = t_inlist_len(); - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_PREVOUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + zemu_log_stack("nu5_transparent_prevouts_hash\n"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + + const uint8_t n = t_inlist_len(); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_PREVOUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } + + const uint8_t *data = input + INDEX_TIN_PREVOUT; + for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, PREVOUT_SIZE, NULL, 0)); + io_seproxyhal_io_heartbeat(); + } + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, PREVOUT_SIZE, output, HASH_SIZE)); return zxerr_ok; - } - - const uint8_t *data = input + INDEX_TIN_PREVOUT; - for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, PREVOUT_SIZE, NULL, 0)); - io_seproxyhal_io_heartbeat(); - } - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, PREVOUT_SIZE, output, HASH_SIZE)); - return zxerr_ok; } zxerr_t nu5_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { - zemu_log_stack("nu5_transparent_sequence_hash"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } - const uint8_t n = t_inlist_len(); - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SEQUENCE_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + zemu_log_stack("nu5_transparent_sequence_hash"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + const uint8_t n = t_inlist_len(); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SEQUENCE_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } + + const uint8_t *data = input + INDEX_TIN_SEQ; + for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, SEQUENCE_SIZE, NULL, 0)); + io_seproxyhal_io_heartbeat(); + } + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, SEQUENCE_SIZE, output, HASH_SIZE)); return zxerr_ok; - } - - const uint8_t *data = input + INDEX_TIN_SEQ; - for (uint8_t i = 0; i < n - 1; i++, data += T_IN_TX_LEN) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, SEQUENCE_SIZE, NULL, 0)); - io_seproxyhal_io_heartbeat(); - } - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, SEQUENCE_SIZE, output, HASH_SIZE)); - return zxerr_ok; } /// Sequentially append the full serialized value of each transparent output @@ -92,35 +95,36 @@ zxerr_t nu5_transparent_sequence_hash(const uint8_t *input, uint8_t *output) { /// In the case that no outputs are provided, this produces a default /// hash from just the personalization string. zxerr_t nu5_transparent_outputs_hash(uint8_t *output) { - if (output == NULL) { - return zxerr_no_data; - } + if (output == NULL) { + return zxerr_no_data; + } + + const uint8_t n = t_outlist_len(); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } + + uint8_t data[T_OUTPUT_SIZE] = {0}; + uint8_t i = 0; + for (; i < n - 1; i++) { + t_output_item_t *item = t_outlist_retrieve_item(i); + MEMCPY(data, (uint8_t *)&(item->value), 8); + MEMCPY(data + 8, item->address, SCRIPT_SIZE); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0)); + } - const uint8_t n = t_outlist_len(); - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - return zxerr_ok; - } - - uint8_t data[T_OUTPUT_SIZE] = {0}; - uint8_t i = 0; - for (; i < n - 1; i++) { t_output_item_t *item = t_outlist_retrieve_item(i); MEMCPY(data, (uint8_t *)&(item->value), 8); MEMCPY(data + 8, item->address, SCRIPT_SIZE); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, data, sizeof(data), NULL, 0)); - } - - t_output_item_t *item = t_outlist_retrieve_item(i); - MEMCPY(data, (uint8_t *)&(item->value), 8); - MEMCPY(data + 8, item->address, SCRIPT_SIZE); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, data, sizeof(data), output, HASH_SIZE)); - return zxerr_ok; + return zxerr_ok; } /// Implements [ZIP 244 section @@ -135,55 +139,58 @@ zxerr_t nu5_transparent_outputs_hash(uint8_t *output) { /// Then, hash these together personalized by /// ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION zxerr_t nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output) { - zemu_log_stack("nu5_hash_sapling_spends"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } - - const uint8_t n = spendlist_len(); - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - return zxerr_ok; - } - cx_blake2b_t ch_ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_SPENDS_COMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - cx_blake2b_t nh_ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_SPENDS_NONCOMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - const uint8_t *nullifier_data = input + INDEX_SPEND_NF; - const uint8_t *cv_data = input + INDEX_SPEND_VALUECMT; - const uint8_t *anchor_data = input + INDEX_SPEND_ANCHOR; - const uint8_t *rk_data = input + INDEX_SPEND_RK; - - for (uint8_t i = 0; i < n - 1; i++, nullifier_data += SPEND_TX_LEN, - cv_data += SPEND_TX_LEN, - anchor_data += SPEND_TX_LEN, - rk_data += SPEND_TX_LEN) { - // build the hash of nullifiers separately for compact blocks. - CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, nullifier_data, NULLIFIER_SIZE, NULL,0)); - - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL,0)); + zemu_log_stack("nu5_hash_sapling_spends"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + + const uint8_t n = spendlist_len(); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SAPLING_SPENDS_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); + + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } + cx_blake2b_t ch_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, + (uint8_t *)ZCASH_SAPLING_SPENDS_COMPACT_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); + + cx_blake2b_t nh_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, + (uint8_t *)ZCASH_SAPLING_SPENDS_NONCOMPACT_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); + + const uint8_t *nullifier_data = input + INDEX_SPEND_NF; + const uint8_t *cv_data = input + INDEX_SPEND_VALUECMT; + const uint8_t *anchor_data = input + INDEX_SPEND_ANCHOR; + const uint8_t *rk_data = input + INDEX_SPEND_RK; + + for (uint8_t i = 0; i < n - 1; i++, nullifier_data += SPEND_TX_LEN, cv_data += SPEND_TX_LEN, anchor_data += SPEND_TX_LEN, + rk_data += SPEND_TX_LEN) { + // build the hash of nullifiers separately for compact blocks. + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, nullifier_data, NULLIFIER_SIZE, NULL, 0)); + + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, rk_data, RK_SIZE, NULL, 0)); + } + + uint8_t ch_out[HASH_SIZE] = {0}; + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, CX_LAST, nullifier_data, NULLIFIER_SIZE, (uint8_t *)ch_out, HASH_SIZE)); + + uint8_t nh_out[HASH_SIZE] = {0}; + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL, 0)); CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, rk_data, RK_SIZE, NULL, 0)); - } + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, CX_LAST, rk_data, RK_SIZE, (uint8_t *)nh_out, HASH_SIZE)); - uint8_t ch_out[HASH_SIZE] = {0}; - CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, CX_LAST, nullifier_data, NULLIFIER_SIZE,(uint8_t *)ch_out, HASH_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, (uint8_t *)ch_out, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, (uint8_t *)nh_out, HASH_SIZE, output, HASH_SIZE)); - uint8_t nh_out[HASH_SIZE] = {0}; - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv_data, VALUE_COMMITMENT_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, anchor_data, ANCHOR_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, CX_LAST, rk_data, RK_SIZE, (uint8_t *)nh_out,HASH_SIZE)); - - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, (uint8_t *)ch_out, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, (uint8_t *)nh_out, HASH_SIZE, output,HASH_SIZE)); - - return zxerr_ok; + return zxerr_ok; } /// Implements [ZIP 244 section @@ -200,247 +207,259 @@ zxerr_t nu5_hash_sapling_spends(const uint8_t *input, uint8_t *output) { /// Then, hash these together personalized with /// ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION zxerr_t nu5_hash_sapling_outputs(const uint8_t *input, uint8_t *output) { - zemu_log_stack("nu5_hash_sapling_outputs"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } + zemu_log_stack("nu5_hash_sapling_outputs"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } - const uint8_t n = outputlist_len(); + const uint8_t n = outputlist_len(); - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SAPLING_OUTPUTS_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); - if (n == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - return zxerr_ok; - } + if (n == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } + + cx_blake2b_t ch_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, + (uint8_t *)ZCASH_SAPLING_OUTPUTS_COMPACT_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); - cx_blake2b_t ch_ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ch_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_COMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t mh_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&mh_ctx, 256, NULL, 0, (uint8_t *)ZCASH_SAPLING_OUTPUTS_MEMOS_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); - cx_blake2b_t mh_ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&mh_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_MEMOS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t nh_ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, + (uint8_t *)ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); - cx_blake2b_t nh_ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&nh_ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_OUTPUTS_NONCOMPACT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + const uint8_t *cmu = input + INDEX_OUTPUT_NOTECMT; + const uint8_t *ephemeral_key = input + INDEX_OUTPUT_EPK; + const uint8_t *enc_ciphertext = input + INDEX_OUTPUT_ENC; - const uint8_t *cmu = input + INDEX_OUTPUT_NOTECMT; - const uint8_t *ephemeral_key = input + INDEX_OUTPUT_EPK; - const uint8_t *enc_ciphertext = input + INDEX_OUTPUT_ENC; + const uint8_t *enc_ciphertext_memo = input + INDEX_OUTPUT_ENC_MEMO; - const uint8_t *enc_ciphertext_memo = input + INDEX_OUTPUT_ENC_MEMO; + const uint8_t *cv = input + INDEX_OUTPUT_VALUECMT; + const uint8_t *enc_ciphertext_aead_tag = input + INDEX_OUTPUT_ENC_AEAD_TAG; + const uint8_t *out_ciphertext = input + INDEX_OUTPUT_OUT; - const uint8_t *cv = input + INDEX_OUTPUT_VALUECMT; - const uint8_t *enc_ciphertext_aead_tag = input + INDEX_OUTPUT_ENC_AEAD_TAG; - const uint8_t *out_ciphertext = input + INDEX_OUTPUT_OUT; + for (uint8_t i = 0; i < n - 1; i++, cmu += OUTPUT_TX_LEN, ephemeral_key += OUTPUT_TX_LEN, + enc_ciphertext += OUTPUT_TX_LEN, enc_ciphertext_memo += OUTPUT_TX_LEN, cv += OUTPUT_TX_LEN, + enc_ciphertext_aead_tag += OUTPUT_TX_LEN, out_ciphertext += OUTPUT_TX_LEN) { + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, enc_ciphertext, 52, NULL, 0)); - for (uint8_t i = 0; i < n - 1; i++, cmu += OUTPUT_TX_LEN, ephemeral_key += OUTPUT_TX_LEN, - enc_ciphertext += OUTPUT_TX_LEN, enc_ciphertext_memo += OUTPUT_TX_LEN, - cv += OUTPUT_TX_LEN, enc_ciphertext_aead_tag += OUTPUT_TX_LEN, - out_ciphertext += OUTPUT_TX_LEN) { + CHECK_CX_OK(cx_hash_no_throw(&mh_ctx.header, 0, enc_ciphertext_memo, OUTPUT_ENC_MEMO_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag, OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, out_ciphertext, OUTPUT_OUT_SIZE, NULL, 0)); + } + + uint8_t ch_out[HASH_SIZE] = {0}; CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0)); CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, enc_ciphertext, 52, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, CX_LAST, enc_ciphertext, 52, ch_out, HASH_SIZE)); - CHECK_CX_OK(cx_hash_no_throw(&mh_ctx.header, 0, enc_ciphertext_memo,OUTPUT_ENC_MEMO_SIZE, NULL, 0)); + uint8_t mh_out[HASH_SIZE] = {0}; + CHECK_CX_OK( + cx_hash_no_throw(&mh_ctx.header, CX_LAST, enc_ciphertext_memo, OUTPUT_ENC_MEMO_SIZE, (uint8_t *)mh_out, HASH_SIZE)); + uint8_t nh_out[HASH_SIZE] = {0}; CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag,OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, out_ciphertext, OUTPUT_OUT_SIZE, NULL,0)); - } - - uint8_t ch_out[HASH_SIZE] = {0}; - CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, cmu, NOTE_COMMITMENT_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, 0, ephemeral_key, EPK_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ch_ctx.header, CX_LAST, enc_ciphertext, 52, ch_out,HASH_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag, OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, CX_LAST, out_ciphertext, OUTPUT_OUT_SIZE, nh_out, HASH_SIZE)); - uint8_t mh_out[HASH_SIZE] = {0}; - CHECK_CX_OK(cx_hash_no_throw(&mh_ctx.header, CX_LAST, enc_ciphertext_memo,OUTPUT_ENC_MEMO_SIZE, (uint8_t *)mh_out, HASH_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, ch_out, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, mh_out, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, nh_out, HASH_SIZE, output, HASH_SIZE)); - uint8_t nh_out[HASH_SIZE] = {0}; - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, cv, VALUE_COMMITMENT_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, 0, enc_ciphertext_aead_tag,OUTPUT_ENC_AEAD_TAG_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&nh_ctx.header, CX_LAST, out_ciphertext, OUTPUT_OUT_SIZE,nh_out, HASH_SIZE)); - - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, ch_out, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, mh_out, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, nh_out, HASH_SIZE, output, HASH_SIZE)); - - return zxerr_ok; + return zxerr_ok; } /// The txid commits to the hash of all transparent outputs. The /// prevout and sequence_hash components of txid zxerr_t hash_header_txid_data(const uint8_t *input, uint8_t *output) { - zemu_log_stack("hash_header_txid_data"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_HEADERS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - const uint8_t *version = input + NU5_INDEX_HASH_VERSION; - const uint8_t *version_group_id = input + NU5_INDEX_HASH_VERSION_GROUP_ID; - const uint8_t *consensus_branch_id = input + NU5_INDEX_HASH_CONSENSUS_BRANCH_ID; - const uint8_t *lock_time = input + NU5_INDEX_HASH_LOCK_TIME; - const uint8_t *expiry_height = input + NU5_INDEX_EXPIRY_HEIGHT; - - if (cx_hash_no_throw(&ctx.header, 0, version, 4, NULL, 0) != CX_OK || - cx_hash_no_throw(&ctx.header, 0, version_group_id, 4, NULL, 0) != CX_OK || - cx_hash_no_throw(&ctx.header, 0, consensus_branch_id, 4, NULL, 0) != CX_OK || - cx_hash_no_throw(&ctx.header, 0, lock_time, 4, NULL, 0) != CX_OK || - cx_hash_no_throw(&ctx.header, CX_LAST, expiry_height, 4, output, HASH_SIZE) != CX_OK) { - - return zxerr_invalid_crypto_settings; - } - - return zxerr_ok; + zemu_log_stack("hash_header_txid_data"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_HEADERS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + const uint8_t *version = input + NU5_INDEX_HASH_VERSION; + const uint8_t *version_group_id = input + NU5_INDEX_HASH_VERSION_GROUP_ID; + const uint8_t *consensus_branch_id = input + NU5_INDEX_HASH_CONSENSUS_BRANCH_ID; + const uint8_t *lock_time = input + NU5_INDEX_HASH_LOCK_TIME; + const uint8_t *expiry_height = input + NU5_INDEX_EXPIRY_HEIGHT; + + if (cx_hash_no_throw(&ctx.header, 0, version, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, version_group_id, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, consensus_branch_id, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, lock_time, 4, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, CX_LAST, expiry_height, 4, output, HASH_SIZE) != CX_OK) { + return zxerr_invalid_crypto_settings; + } + + return zxerr_ok; } zxerr_t hash_transparent_txid_data(const uint8_t *input, uint8_t *output) { - zemu_log_stack("hash_transparent_txid_data"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } + zemu_log_stack("hash_transparent_txid_data"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_TRANSPARENT_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); - if ((t_inlist_len() + t_outlist_len()) == 0) { - return cx_hash_no_throw(&ctx.header, CX_LAST, NULL, 0, output, HASH_SIZE) == CX_OK ? zxerr_ok : zxerr_unknown; - } + if ((t_inlist_len() + t_outlist_len()) == 0) { + return cx_hash_no_throw(&ctx.header, CX_LAST, NULL, 0, output, HASH_SIZE) == CX_OK ? zxerr_ok : zxerr_unknown; + } - const uint8_t *prevout_digest = input + NU5_INDEX_HASH_PREVOUTSHASH; - const uint8_t *sequence_digest = input + NU5_INDEX_HASH_SEQUENCEHASH; - const uint8_t *outputs_digest = input + NU5_INDEX_HASH_OUTPUTSHASH; + const uint8_t *prevout_digest = input + NU5_INDEX_HASH_PREVOUTSHASH; + const uint8_t *sequence_digest = input + NU5_INDEX_HASH_SEQUENCEHASH; + const uint8_t *outputs_digest = input + NU5_INDEX_HASH_OUTPUTSHASH; - if (cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0) != CX_OK || - cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0) != CX_OK || - cx_hash_no_throw(&ctx.header, CX_LAST, outputs_digest, HASH_SIZE, output,HASH_SIZE) != CX_OK) { + if (cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0) != CX_OK || + cx_hash_no_throw(&ctx.header, CX_LAST, outputs_digest, HASH_SIZE, output, HASH_SIZE) != CX_OK) { + return zxerr_unknown; + } - return zxerr_unknown; - } - - return zxerr_ok; + return zxerr_ok; } -zxerr_t transparent_sig_digest(const uint8_t *input, uint8_t *start_signdata, - uint8_t index, signable_input type, uint8_t *output) { - zemu_log_stack("transparent_sig_digest"); - if (input == NULL || start_signdata == NULL || output == NULL) { - return zxerr_no_data; - } - - if (t_inlist_len() == 0) { - return hash_transparent_txid_data(start_signdata, output); - } - - // the following implies that flag_anyonecanpay = flag_single = flag_none = false - uint8_t hash_type = SIGHASH_ALL; - const uint8_t *prevout_digest = start_signdata + NU5_INDEX_HASH_PREVOUTSHASH; - - // compute amounts digest - cx_blake2b_t ctx_amounts = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_amounts, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_AMOUNTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - uint64_t amount = 0; - uint8_t amounts_digest[HASH_SIZE] = {0}; - for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { - amount = t_inlist_retrieve_item_amount(i); - CHECK_CX_OK(cx_hash_no_throw(&ctx_amounts.header, 0, (uint8_t *)&amount,sizeof(uint64_t), NULL, 0)); - } - - // t_inlist_len will be >0 - amount = t_inlist_retrieve_item_amount(t_inlist_len() - 1); - CHECK_CX_OK(cx_hash_no_throw(&ctx_amounts.header, CX_LAST, (uint8_t *)&amount, sizeof(uint64_t), amounts_digest, HASH_SIZE)); - - cx_blake2b_t ctx_scripts = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_scripts, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_SCRIPTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - uint8_t scripts[SCRIPT_SIZE] = {0}; - uint8_t scripts_digest[HASH_SIZE] = {0}; - for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { - t_inlist_retrieve_item_script(i, scripts); - CHECK_CX_OK(cx_hash_no_throw(&ctx_scripts.header, 0, scripts, sizeof(scripts), NULL,0)); - MEMZERO(scripts, SCRIPT_SIZE); - } - t_inlist_retrieve_item_script(t_inlist_len() - 1, scripts); - CHECK_CX_OK(cx_hash_no_throw(&ctx_scripts.header, CX_LAST, scripts, SCRIPT_SIZE,scripts_digest, HASH_SIZE)); - - const uint8_t *sequence_digest = start_signdata + NU5_INDEX_HASH_SEQUENCEHASH; - const uint8_t *outputs_digest = start_signdata + NU5_INDEX_HASH_OUTPUTSHASH; - - cx_blake2b_t ctx_txin_sig_digest = {0}; - uint8_t txin_sig_digest[HASH_SIZE] = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_txin_sig_digest, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - if (type == transparent) { - const t_input_item_t *item = t_inlist_retrieve_item(index); +zxerr_t transparent_sig_digest( + const uint8_t *input, uint8_t *start_signdata, uint8_t index, signable_input type, uint8_t *output) { + zemu_log_stack("transparent_sig_digest"); + if (input == NULL || start_signdata == NULL || output == NULL) { + return zxerr_no_data; + } + + if (t_inlist_len() == 0) { + return hash_transparent_txid_data(start_signdata, output); + } + + // the following implies that flag_anyonecanpay = flag_single = flag_none = false + uint8_t hash_type = SIGHASH_ALL; + const uint8_t *prevout_digest = start_signdata + NU5_INDEX_HASH_PREVOUTSHASH; + + // compute amounts digest + cx_blake2b_t ctx_amounts = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_amounts, 256, NULL, 0, + (uint8_t *)ZCASH_TRANSPARENT_AMOUNTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + uint64_t amount = 0; + uint8_t amounts_digest[HASH_SIZE] = {0}; + for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { + amount = t_inlist_retrieve_item_amount(i); + CHECK_CX_OK(cx_hash_no_throw(&ctx_amounts.header, 0, (uint8_t *)&amount, sizeof(uint64_t), NULL, 0)); + } + + // t_inlist_len will be >0 + amount = t_inlist_retrieve_item_amount(t_inlist_len() - 1); + CHECK_CX_OK( + cx_hash_no_throw(&ctx_amounts.header, CX_LAST, (uint8_t *)&amount, sizeof(uint64_t), amounts_digest, HASH_SIZE)); + + cx_blake2b_t ctx_scripts = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_scripts, 256, NULL, 0, + (uint8_t *)ZCASH_TRANSPARENT_SCRIPTS_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + uint8_t scripts[SCRIPT_SIZE] = {0}; + uint8_t scripts_digest[HASH_SIZE] = {0}; + for (uint8_t i = 0; i < t_inlist_len() - 1; ++i) { + t_inlist_retrieve_item_script(i, scripts); + CHECK_CX_OK(cx_hash_no_throw(&ctx_scripts.header, 0, scripts, sizeof(scripts), NULL, 0)); + MEMZERO(scripts, SCRIPT_SIZE); + } + t_inlist_retrieve_item_script(t_inlist_len() - 1, scripts); + CHECK_CX_OK(cx_hash_no_throw(&ctx_scripts.header, CX_LAST, scripts, SCRIPT_SIZE, scripts_digest, HASH_SIZE)); + + const uint8_t *sequence_digest = start_signdata + NU5_INDEX_HASH_SEQUENCEHASH; + const uint8_t *outputs_digest = start_signdata + NU5_INDEX_HASH_OUTPUTSHASH; + + cx_blake2b_t ctx_txin_sig_digest = {0}; + uint8_t txin_sig_digest[HASH_SIZE] = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx_txin_sig_digest, 256, NULL, 0, + (uint8_t *)ZCASH_TRANSPARENT_INPUT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (type == transparent) { + const t_input_item_t *item = t_inlist_retrieve_item(index); + + const uint8_t *prevout_data = input + index * T_IN_TX_LEN + INDEX_TIN_PREVOUT; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, prevout_data, PREVOUT_SIZE, NULL, 0)); + + uint64_t value = item->value; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, (uint8_t *)&value, sizeof(uint64_t), NULL, 0)); + + const uint8_t *script = item->script; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, script, SCRIPT_SIZE, NULL, 0)); + + const uint8_t *sequence_data = input + index * T_IN_TX_LEN + INDEX_TIN_SEQ; + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, sequence_data, SEQUENCE_SIZE, NULL, 0)); + } + + CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, CX_LAST, NULL, 0, txin_sig_digest, HASH_SIZE)); + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_TRANSPARENT_HASH_PERSONALIZATION, + PERSONALIZATION_SIZE)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, &hash_type, sizeof(uint8_t), NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, amounts_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, scripts_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, outputs_digest, HASH_SIZE, NULL, 0)); + + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, txin_sig_digest, HASH_SIZE, output, HASH_SIZE)); - const uint8_t *prevout_data = input + index * T_IN_TX_LEN + INDEX_TIN_PREVOUT; - CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, prevout_data,PREVOUT_SIZE, NULL, 0)); - - uint64_t value = item->value; - CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, (uint8_t *)&value,sizeof(uint64_t), NULL, 0)); - - const uint8_t *script = item->script; - CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, script, SCRIPT_SIZE,NULL, 0)); - - const uint8_t *sequence_data = input + index * T_IN_TX_LEN + INDEX_TIN_SEQ; - CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, 0, sequence_data, SEQUENCE_SIZE, NULL, 0)); - } - - CHECK_CX_OK(cx_hash_no_throw(&ctx_txin_sig_digest.header, CX_LAST, NULL, 0, txin_sig_digest, HASH_SIZE)); - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_TRANSPARENT_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, &hash_type, sizeof(uint8_t), NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, prevout_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, amounts_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, scripts_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, sequence_digest, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, outputs_digest, HASH_SIZE, NULL, 0)); - - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, txin_sig_digest, HASH_SIZE, output,HASH_SIZE)); - - return zxerr_ok; + return zxerr_ok; } zxerr_t hash_sapling_txid_data(const uint8_t *input, uint8_t *output) { - zemu_log_stack("hash_sapling_txid_data"); - if (input == NULL || output == NULL) { - return zxerr_no_data; - } - - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_SAPLING_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + zemu_log_stack("hash_sapling_txid_data"); + if (input == NULL || output == NULL) { + return zxerr_no_data; + } + + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_SAPLING_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + + if (spendlist_len() + outputlist_len() == 0) { + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + return zxerr_ok; + } + + const uint8_t *hash_sapling_spends = input + NU5_INDEX_HASH_SHIELDEDSPENDHASH; + const uint8_t *hash_sapling_outputs = input + NU5_INDEX_HASH_SHIELDEDOUTPUTHASH; + const uint8_t *value_balance = input + NU5_INDEX_HASH_VALUEBALANCE; + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, hash_sapling_spends, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, hash_sapling_outputs, HASH_SIZE, NULL, 0)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, value_balance, NU5_VALUEBALANCE_SIZE, output, HASH_SIZE)); - if (spendlist_len() + outputlist_len() == 0) { - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); return zxerr_ok; - } - - const uint8_t *hash_sapling_spends = input + NU5_INDEX_HASH_SHIELDEDSPENDHASH; - const uint8_t *hash_sapling_outputs = input + NU5_INDEX_HASH_SHIELDEDOUTPUTHASH; - const uint8_t *value_balance = input + NU5_INDEX_HASH_VALUEBALANCE; - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, hash_sapling_spends, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, 0, hash_sapling_outputs, HASH_SIZE, NULL, 0)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, value_balance, NU5_VALUEBALANCE_SIZE,output, HASH_SIZE)); - - return zxerr_ok; } zxerr_t hash_empty_orchard_txid_data(uint8_t *output) { - if (output == NULL) { - return zxerr_no_data; - } - cx_blake2b_t ctx = {0}; - CHECK_CX_OK(cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t*)ZCASH_ORCHARD_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); - CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); - - return zxerr_ok; + if (output == NULL) { + return zxerr_no_data; + } + cx_blake2b_t ctx = {0}; + CHECK_CX_OK( + cx_blake2b_init2_no_throw(&ctx, 256, NULL, 0, (uint8_t *)ZCASH_ORCHARD_HASH_PERSONALIZATION, PERSONALIZATION_SIZE)); + CHECK_CX_OK(cx_hash_no_throw(&ctx.header, CX_LAST, 0, 0, output, HASH_SIZE)); + + return zxerr_ok; } diff --git a/app/src/txid.h b/app/src/txid.h index 27bd9ed4..f6f7a91e 100644 --- a/app/src/txid.h +++ b/app/src/txid.h @@ -18,8 +18,8 @@ #include -#include "zxerror.h" #include "sighash.h" +#include "zxerror.h" zxerr_t nu5_transparent_prevouts_hash(const uint8_t *input, uint8_t *output); @@ -35,9 +35,8 @@ zxerr_t hash_header_txid_data(const uint8_t *input, uint8_t *output); zxerr_t hash_transparent_txid_data(const uint8_t *input, uint8_t *output); -zxerr_t transparent_sig_digest(const uint8_t *input, uint8_t *start_signdata, - uint8_t index, signable_input type, - uint8_t *output); +zxerr_t transparent_sig_digest( + const uint8_t *input, uint8_t *start_signdata, uint8_t index, signable_input type, uint8_t *output); zxerr_t hash_sapling_txid_data(const uint8_t *input, uint8_t *output); diff --git a/app/src/zcash_utils.h b/app/src/zcash_utils.h index 9392dd2f..5e63a1c2 100644 --- a/app/src/zcash_utils.h +++ b/app/src/zcash_utils.h @@ -1,5 +1,5 @@ /******************************************************************************* -* (c) 2018 -2023 Zondax AG + * (c) 2018 -2023 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,15 +22,13 @@ extern "C" { #include "cx.h" #include "zxerror.h" - -#define CHECK_CX_OK(CALL) \ -do { \ -cx_err_t __cx_err = CALL; \ -if (__cx_err != CX_OK) { \ -return zxerr_unknown; \ -} \ -} while (0) - +#define CHECK_CX_OK(CALL) \ + do { \ + cx_err_t __cx_err = CALL; \ + if (__cx_err != CX_OK) { \ + return zxerr_unknown; \ + } \ + } while (0) #ifdef __cplusplus } diff --git a/app/src/zip-0317.c b/app/src/zip-0317.c index 492d1b93..b9efac75 100644 --- a/app/src/zip-0317.c +++ b/app/src/zip-0317.c @@ -1,39 +1,32 @@ #include "zip-0317.h" -#define DIV_CEIL(x, y) ((x + (y - 1)) / y) +#define DIV_CEIL(x, y) ((x + (y - 1)) / y) -#define MARGINAL_FEE 5000 -#define GRACE_ACTIONS 2 -#define P2PKH_STANDARD_INPUT_SIZE 150 +#define MARGINAL_FEE 5000 +#define GRACE_ACTIONS 2 +#define P2PKH_STANDARD_INPUT_SIZE 150 #define P2PKH_STANDARD_OUTPUT_SIZE 34 -uint64_t zip_0317_fee_raw(uint64_t tx_in_total_size, uint64_t tx_out_total_size, - uint64_t n_join_split, uint64_t n_spends_sapling, +uint64_t zip_0317_fee_raw(uint64_t tx_in_total_size, + uint64_t tx_out_total_size, + uint64_t n_join_split, + uint64_t n_spends_sapling, uint64_t n_outputs_sapling, uint64_t n_actions_orchard) { + uint64_t tin_actions = DIV_CEIL(tx_in_total_size, P2PKH_STANDARD_INPUT_SIZE); + uint64_t tout_actions = DIV_CEIL(tx_out_total_size, P2PKH_STANDARD_OUTPUT_SIZE); - uint64_t tin_actions = DIV_CEIL(tx_in_total_size, P2PKH_STANDARD_INPUT_SIZE); - uint64_t tout_actions = - DIV_CEIL(tx_out_total_size, P2PKH_STANDARD_OUTPUT_SIZE); + uint64_t transparent_actions = (tin_actions > tout_actions) ? tin_actions : tout_actions; + uint64_t sapling_actions = (n_spends_sapling > n_outputs_sapling) ? n_spends_sapling : n_outputs_sapling; + uint64_t joinsplit_actions = 2 * n_join_split; + uint64_t orchard_actions = n_actions_orchard; - uint64_t transparent_actions = - (tin_actions > tout_actions) ? tin_actions : tout_actions; - uint64_t sapling_actions = (n_spends_sapling > n_outputs_sapling) - ? n_spends_sapling - : n_outputs_sapling; - uint64_t joinsplit_actions = 2 * n_join_split; - uint64_t orchard_actions = n_actions_orchard; + uint64_t logical_actions = transparent_actions + sapling_actions + joinsplit_actions + orchard_actions; - uint64_t logical_actions = transparent_actions + sapling_actions + - joinsplit_actions + orchard_actions; - - return MARGINAL_FEE * - ((GRACE_ACTIONS > logical_actions) ? GRACE_ACTIONS : logical_actions); + return MARGINAL_FEE * ((GRACE_ACTIONS > logical_actions) ? GRACE_ACTIONS : logical_actions); } -uint64_t zip_0317(uint64_t n_tin, uint64_t n_tout, uint64_t n_sapling_spends, - uint64_t n_sapling_outs) { - return zip_0317_fee_raw(n_tin * P2PKH_STANDARD_INPUT_SIZE, - n_tout * P2PKH_STANDARD_OUTPUT_SIZE, 0, - n_sapling_spends, n_sapling_outs, 0); +uint64_t zip_0317(uint64_t n_tin, uint64_t n_tout, uint64_t n_sapling_spends, uint64_t n_sapling_outs) { + return zip_0317_fee_raw(n_tin * P2PKH_STANDARD_INPUT_SIZE, n_tout * P2PKH_STANDARD_OUTPUT_SIZE, 0, n_sapling_spends, + n_sapling_outs, 0); } diff --git a/app/src/zip-0317.h b/app/src/zip-0317.h index 3e4dd257..a4862f96 100644 --- a/app/src/zip-0317.h +++ b/app/src/zip-0317.h @@ -22,8 +22,7 @@ extern "C" { #endif -uint64_t zip_0317(uint64_t n_tin, uint64_t n_tout, uint64_t n_sapling_spends, - uint64_t n_sapling_outs); +uint64_t zip_0317(uint64_t n_tin, uint64_t n_tout, uint64_t n_sapling_spends, uint64_t n_sapling_outs); #ifdef __cplusplus } diff --git a/tests_zemu/tests/txs_advanced.test.ts b/tests_zemu/tests/txs_advanced.test.ts index 2123fbe9..32b255b0 100644 --- a/tests_zemu/tests/txs_advanced.test.ts +++ b/tests_zemu/tests/txs_advanced.test.ts @@ -1085,8 +1085,8 @@ describe('End to end transactions', function () { const req5 = await app.extractOutputData() console.log(req5) - await expect(app.extractSpendSignature()).rejects.toThrow("Data is invalid"); - await expect(app.extractTransparentSig()).rejects.toThrow("Data is invalid"); + await expect(app.extractSpendSignature()).rejects.toThrow('Data is invalid') + await expect(app.extractTransparentSig()).rejects.toThrow('Data is invalid') await takeLastSnapshot(testname, last_index, sim) } finally { @@ -1102,7 +1102,7 @@ describe('Failing transactions', function () { await sim.start({ ...defaultOptions, model: m.name }) const app = new ZCashApp(sim.getTransport()) - await expect(app.extractSpendData()).rejects.toThrow("Data is invalid"); + await expect(app.extractSpendData()).rejects.toThrow('Data is invalid') } finally { await sim.close() } @@ -1133,7 +1133,7 @@ describe('Failing transactions', function () { expect(req.txdata.length).toEqual(64) - await expect(app.extractOutputData()).rejects.toThrow("Data is invalid"); + await expect(app.extractOutputData()).rejects.toThrow('Data is invalid') } finally { await sim.close() } @@ -1327,9 +1327,8 @@ describe('Failing transactions', function () { // Below are the failing extractions - - await expect(app.extractSpendSignature()).rejects.toThrow("Data is invalid"); - await expect(app.extractTransparentSig()).rejects.toThrow("Data is invalid"); + await expect(app.extractSpendSignature()).rejects.toThrow('Data is invalid') + await expect(app.extractTransparentSig()).rejects.toThrow('Data is invalid') } finally { await sim.close() } @@ -1690,8 +1689,7 @@ describe('Failing transactions', function () { // For this, it uses the input from inittx to verify. // If all checks are ok, the ledger signs the transaction. - - await expect(app.checkAndSign(ledgerblob_txdata, tx_version)).rejects.toThrow("Unknown Return Code: 0x6997"); + await expect(app.checkAndSign(ledgerblob_txdata, tx_version)).rejects.toThrow('Unknown Return Code: 0x6997') } finally { await sim.close() } @@ -1717,9 +1715,7 @@ describe('Failing transactions', function () { // If confirmed, the ledger also computes the randomness needed for : // - The shielded spends // - the shielded outputs - const reqinit = - - await expect(app.initNewTx(ledgerblob_initdata)).rejects.toThrow("Unknown Return Code: 0x6989"); + const reqinit = await expect(app.initNewTx(ledgerblob_initdata)).rejects.toThrow('Unknown Return Code: 0x6989') } finally { await sim.close() } @@ -1753,14 +1749,14 @@ describe('Failing transactions', function () { // We do not wait here (on purpose) as the exception will be thrown the moment compareSnapshotsAndReject finishes. // We execute the tx on the device, progress screens with compareSnapshotsAndReject, and the moment it rejects the tx, // the exception will raise. - expect(app.initNewTx(ledgerblob_initdata)).rejects.toThrow("Transaction rejected"); + expect(app.initNewTx(ledgerblob_initdata)).rejects.toThrow('Transaction rejected') await sim.waitUntilScreenIsNot(sim.getMainMenuSnapshot()) await sim.compareSnapshotsAndReject('.', `${m.prefix.toLowerCase()}-ext-data-after-tx-reject`) // Try to extract data after a rejection of a transaction - await expect(app.extractSpendData()).rejects.toThrow("Data is invalid"); - await expect(app.extractOutputData()).rejects.toThrow("Data is invalid"); + await expect(app.extractSpendData()).rejects.toThrow('Data is invalid') + await expect(app.extractOutputData()).rejects.toThrow('Data is invalid') } finally { await sim.close() } @@ -1897,7 +1893,7 @@ describe('Failing transactions', function () { const ledgerblob_txdata = builder.build(SPEND_PATH, OUTPUT_PATH, bad_tx_version) - await expect(app.checkAndSign(ledgerblob_txdata, bad_tx_version)).rejects.toThrow("Unknown Return Code: 0x69A2"); + await expect(app.checkAndSign(ledgerblob_txdata, bad_tx_version)).rejects.toThrow('Unknown Return Code: 0x69A2') } finally { await sim.close() }