-
Notifications
You must be signed in to change notification settings - Fork 33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP]Feat/zcash #1366
[WIP]Feat/zcash #1366
Conversation
Latest protocol is updated in the code base. |
The purpose of I think we'd want to include Sapling components even if it isn't supported for Keystone, because it is needed for other applications of PCZTs. |
9cda39e
to
90596a9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably not going to work in light mode, because the Zashi logo and name are in white.
13f57a2
to
a809fdc
Compare
515890a
to
ea142af
Compare
6453e73
to
011282a
Compare
7e801ad
to
387adfe
Compare
// TODO: Determine how to correctly map error codes from the underlying hardware | ||
// into the `getrandom` custom error code space `Error::CUSTOM_START..=u32::MAX`. | ||
if ret != 0 { | ||
let error = NonZeroU32::new(Error::CUSTOM_START.saturating_add_signed(ret)).unwrap(); | ||
return Err(Error::from(error)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This TODO still needs addressing by someone with access to the TRNG documentation, in particular to confirm that ret
will never be negative. (Also to confirm that ret = 0
means success, but I think that's the case as otherwise this function would have been consistently returning an error.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just checked the ret
is asserted in the SE driver level so the error code should always be SUCCESS_CODE(0) here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed as of d41a8f2. This is not a full review or audit of the PR, just what I had time to look over.
@@ -45,6 +46,12 @@ typedef struct { | |||
char walletName[WALLET_NAME_MAX_LEN + 1]; | |||
} AccountInfo_t; | |||
|
|||
typedef struct { | |||
uint8_t accountIndex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This currently puts an upper limit of 256 accounts (2^8, vs the total possible 2^31), which is fine for now (given that only account 0 is supported at present) assuming that this cache struct can be altered later.
@@ -7,6 +7,7 @@ | |||
#include "stdio.h" | |||
|
|||
#define WALLET_NAME_MAX_LEN 16 | |||
#define ZCASH_UFVK_MAX_LEN 384 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Keystone device is generating the UFVKs, so the limit here only needs to encompass the data those UFVKs will contain:
- Orchard: 96 bytes (+ 2 for TLV overhead)
- Transparent: 65 bytes (+ 2 for TLV overhead)
- HRP padding: 16 bytes
- Total: 181 bytes
- Bech32 encoding: 6 + (181*8/5) + 6 = 302 characters
A limit of 384 bytes leaves plenty of overhead for e.g. metadata.
#![feature(error_in_core)] | ||
extern crate alloc; | ||
|
||
pub mod pczt_ext; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is only used by rust/apps/zcash/src/pczt/sign.rs
, so if desired we could move this file there, and remove rust/zcash_vendor
entirely (moving its relevant imports into the other crates). Non-blocking, I might look at this refactor separately.
if path.len() == 3 | ||
&& path[0] == zip32::ChildIndex::hardened(32) | ||
&& path[1] == zip32::ChildIndex::hardened(coin_type) | ||
{ | ||
let account_id = zip32::AccountId::try_from(path[2].index() - (1 << 31)).expect("valid"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm adding an orchard::pczt::Zip32Derivation::extract_account_index
API in zcash/orchard#449 that can replace this in future.
if zip32_derivation.seed_fingerprint() == seed_fingerprint | ||
&& zip32_derivation.derivation_path() | ||
== &[ | ||
zip32::ChildIndex::hardened(32), | ||
zip32::ChildIndex::hardened(params.network_type().coin_type()), | ||
account_index.into(), | ||
] => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can in future be replaced by checking the output of Zip32Derivation::extract_account_index
once the firmware is upgraded to an orchard
release containing zcash/orchard#449.
.map_err(|e| { | ||
ZcashError::InvalidPczt(alloc::format!("invalid Orchard action cmx: {:?}", e)) | ||
})?; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user_address
field of the Orchard action output is currently checked in pczt::parse::parse_orchard_output
. We could instead move that check to here, given that action.output().recipient()
is confirmed to be present if verify_note_commitment
passes. Then all that parse_orchard_output
would be checking is that the decrypted note's recipient matches action.output().recipient()
(unless that is also moved here per the TODO below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant to note that I did later see the comment about CPU management being why this was done later. I'd be interested to know what specifically is the CPU bottleneck.
_ => Err(ZcashError::InvalidPczt( | ||
"transparent output script pubkey is not a public key hash".to_string(), | ||
)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is going to prevent users from sending Keystone-controlled funds to P2SH addresses, which should be fixed at some point (the PCZT format does allow it). The same checking should be applied to user_address
in that case as above, but instead that it matches Receiver::P2sh(hash)
.
_ => Err(ZcashError::InvalidPczt( | ||
"transparent input script pubkey is not a public key hash".to_string(), | ||
)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will prevent creation of transactions where one of the inputs is a P2PKH coin controlled by a Keystone device, and another input is a P2SH coin. It will also prevent users from manually constructing e.g. P2SH multi-sig addresses where one of the pubkeys is controlled by a Keystone device.
Unlike on the output side, I think this limitation is fine for now; Zashi doesn't support creating these kinds of transactions. But it might be something to consider for future firmware updates.
let total_transfer_value = format_zec_value((total_output_value - total_change_value) as f64); | ||
let fee_value = format_zec_value((total_input_value - total_output_value) as f64); | ||
|
||
let has_sapling = pczt.sapling().spends().len() > 0 || pczt.sapling().outputs().len() > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently total_transfer_value
will be completely incorrect if has_sapling = true
. It should at a minimum include the Sapling bundle's value_sum
in the calculation; that value is included in the sighash, and thus even if it hasn't been checked to match the individual Sapling spends and outputs, it can still be "trusted" (because any change to it by the online wallet would invalidate the signature).
rust/apps/zcash/src/pczt/parse.rs
Outdated
//decode as utf8. | ||
if first <= 0xF4 { | ||
let mut temp_memo = memo_bytes.to_vec(); | ||
temp_memo.reverse(); | ||
let mut result = vec![]; | ||
temp_memo.iter().for_each(|v| { | ||
if *v != 0 { | ||
result.push(*v); | ||
} | ||
}); | ||
result.reverse(); | ||
|
||
return Some(String::from_utf8(result).unwrap()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is subtly incorrect: rather than only stripping trailing nul
bytes from the memo bytes, it is stripping every nul
byte from the memo bytes. nul
is a valid byte in UTF-8 (as part of the NUL character).
If a NUL character cannot be included in rendered memo strings (if Keystone requires C-strings), then it should be replaced with an appropriate Unicode replacement character.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I aim to remove until the first non-zero value but implement a wrong one.
Keystone Zcash UR Registries
This protocol is based on the Uniform Resources. It describes the data schemas (UR Registries) used in Zcash integrations.
Introduction
Keystone's QR workflow involves two main steps: linking the wallet and signing data, broken down into three sub-steps:
Two UR Registries are needed for these steps, utilizing the Partially Created Zcash Transaction structure.
Zcash Accounts
Unified Full Viewing Key (UFVK)
UFVK is a standard account expression format in Zcash as per ZIP-316. It consists of:
This protocol focuses on the Transparent and Orchard components.
CDDL for Zcash Accounts
The specification uses CDDL and includes
crypto-hdkey
andcrypto-key-path
specs defined in https://github.com/BlockchainCommons/Research/blob/master/papers/bcr-2020-007-hdkey.md.zcash-ufvk
describes the UFVK of a Zcash account. Each seed has multiple accounts with different indexes. For index 0,zcash-ufvk
should contain a BIP32 extended public key with pathM/44'/133'/0'
(transparent) and an Orchard FVK with pathM_orchard/32'/133'/0'
(Orchard).CDDL for Zcash PCZT