Skip to content

Commit

Permalink
feat(core): add Zcash shielded payments
Browse files Browse the repository at this point in the history
  • Loading branch information
krnak committed Sep 20, 2022
1 parent 207d1a8 commit f544513
Show file tree
Hide file tree
Showing 61 changed files with 3,460 additions and 152 deletions.
1 change: 0 additions & 1 deletion common/protob/messages-binance.proto
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,3 @@ message BinanceSignedTx {
required bytes signature = 1;
required bytes public_key = 2;
}

22 changes: 21 additions & 1 deletion common/protob/messages-bitcoin.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ option (include_in_bitcoin_only) = true;

import "messages.proto";
import "messages-common.proto";
import "messages-zcash.proto";

/**
* Type of script which will be used for transaction input
Expand Down Expand Up @@ -197,6 +198,17 @@ message SignTx {
optional uint32 branch_id = 10; // only for Zcash, BRANCH_ID
optional AmountUnit amount_unit = 11 [default=BITCOIN]; // show amounts in
optional bool decred_staking_ticket = 12 [default=false]; // only for Decred, this is signing a ticket purchase
optional ZcashOrchardBundleInfo orchard = 13; // only for Zcash

/**
* Informations about shielded part of a Zcash transaction.
*/
message ZcashOrchardBundleInfo {
required uint32 inputs_count = 1; // number of Orchard inputs
required uint32 outputs_count = 2; // number of Orchard outputs
required bytes anchor = 3; // a root of Orchard Merkle tree
optional uint32 account = 7 [default = 0];
}
}

/**
Expand All @@ -211,6 +223,8 @@ message SignTx {
* @next TxAckPrevOutput
* @next TxAckPrevExtraData
* @next TxAckPaymentRequest
* @next ZcashOrchardInput
* @next ZcashOrchardOutput
*/
message TxRequest {
optional RequestType request_type = 1; // what should be filled in TxAck message?
Expand All @@ -228,6 +242,9 @@ message TxRequest {
TXORIGINPUT = 5;
TXORIGOUTPUT = 6;
TXPAYMENTREQ = 7;
TXORCHARDOUTPUT = 8;
TXORCHARDINPUT = 9;
NO_OP = 10;
}
/**
* Structure representing request details
Expand All @@ -245,6 +262,10 @@ message TxRequest {
optional uint32 signature_index = 1; // 'signature' field contains signed input of this index
optional bytes signature = 2; // signature of the signature_index input
optional bytes serialized_tx = 3; // part of serialized and signed transaction

optional uint32 signature_type = 4; // currently for Zcash only

optional bytes zcash_shielding_seed = 8; // for Zcash only
}
}

Expand Down Expand Up @@ -607,4 +628,3 @@ message AuthorizeCoinJoin {
optional InputScriptType script_type = 7 [default=SPENDADDRESS]; // used to distinguish between various address formats (non-segwit, segwit, etc.)
optional AmountUnit amount_unit = 8 [default=BITCOIN]; // show amounts in
}

100 changes: 100 additions & 0 deletions common/protob/messages-zcash.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
syntax = "proto2";
package hw.trezor.messages.zcash;

// Sugar for easier handling in Java
option java_package = "com.satoshilabs.trezor.lib.protobuf";
option java_outer_classname = "TrezorMessageZcash";


enum ZcashSignatureType {
reserved 1, 2, 4;
TRANSPARENT = 0;
// SAPLING_SPEND_AUTH = 1;
// SAPLING_BINDING = 2;
ORCHARD_SPEND_AUTH = 3;
// ORCHARD_BINDING = 4;
}

/**
* Request: Ask device for Orchard Full Viewing Key.
* @start
* @next Failure
* @next ZcashFullViewingKey
*/
message ZcashGetFullViewingKey {
optional string coin_name = 2 [default = "Zcash"];
repeated uint32 z_address_n = 3; // z-address ZIP 32 path
}

/**
* Response: Contains raw Orchard Full Viewing Key.
* @end
*/
message ZcashFullViewingKey {
required bytes fvk = 1;
}

/**
* Request: Ask device for Orchard Incoming Viewing Key.
* @start
* @next Failure
* @next ZcashIncomingViewingKey
*/
message ZcashGetIncomingViewingKey {
optional string coin_name = 1 [default = "Zcash"];
repeated uint32 z_address_n = 2; // z-address ZIP 32 path
}

/**
* Response: Contains raw Orchard Incoming Viewing Key.
* @end
*/
message ZcashIncomingViewingKey {
required bytes ivk = 1;
}

/**
* Request: Ask device for Unified Address.
* @start
* @next Failure
* @next ZcashAddress
*/
message ZcashGetAddress {
optional string coin_name = 1 [default = "Zcash"];
repeated uint32 t_address_n = 2; // t-address BIP 32 path (P2PKH)
repeated uint32 z_address_n = 3; // z-address ZIP 32 path (Orchard)
optional uint64 diversifier_index = 4 [default = 0]; // z-address diversifier index
optional bool show_display = 5 [default = false]; // Optionally show on display before sending the result
}

/**
* Response: Contains Zcash diversified payment address derived from device private seed
* @end
*/
message ZcashAddress {
optional string address = 1;
}

/**
* Request: Specify transaction Orchard input.
* @next TxRequest
*/
message ZcashOrchardInput {
required bytes recipient = 1;
required uint64 value = 2;
required bytes rho = 3;
required bytes rseed = 4;
}

/**
* Request: Specify transaction Orchard output.
* Let the `address` and `memo` fields empty for change outputs.
* @next TxRequest
*/
message ZcashOrchardOutput {
optional string address = 1; // for outgoing transfers
required uint64 amount = 2;
optional string memo = 3; // an optional message for a recepient
}

message ZcashAck {}
12 changes: 12 additions & 0 deletions common/protob/messages.proto
Original file line number Diff line number Diff line change
Expand Up @@ -357,4 +357,16 @@ enum MessageType {
MessageType_WebAuthnCredentials = 801 [(wire_out) = true];
MessageType_WebAuthnAddResidentCredential = 802 [(wire_in) = true];
MessageType_WebAuthnRemoveResidentCredential = 803 [(wire_in) = true];

// Zcash
MessageType_ZcashGetFullViewingKey = 893 [(wire_in) = true];
MessageType_ZcashFullViewingKey = 894 [(wire_out) = true];
MessageType_ZcashGetIncomingViewingKey = 895 [(wire_in) = true];
MessageType_ZcashIncomingViewingKey = 896[(wire_out) = true];
MessageType_ZcashGetAddress = 897 [(wire_in) = true];
MessageType_ZcashAddress = 898 [(wire_out) = true];
MessageType_ZcashOrchardBundleInfo = 899 [(wire_in) = true];
MessageType_ZcashOrchardInput = 900 [(wire_in) = true];
MessageType_ZcashOrchardOutput = 901 [(wire_in) = true];
MessageType_ZcashAck = 907 [(wire_in) = true];
}
3 changes: 2 additions & 1 deletion core/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ FIRMWARE_P1_MAXSIZE = 786432
FIRMWARE_P2_MAXSIZE = 917504
FIRMWARE_MAXSIZE = 1703936

CFLAGS += -DSCM_REVISION='\"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')\"'
#CFLAGS += -DSCM_REVISION='\"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')\"'
CFLAGS += -DSCM_REVISION='\"\x89\xfb\x6d\xa9\x11\x5e\x0b\x37\x4c\xea\x7f\x1c\xfa\xae\x2e\x20\x37\xdb\xdf\x92\"'

TESTPATH = $(CURDIR)/../tests

Expand Down
2 changes: 2 additions & 0 deletions core/SConscript.firmware
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,8 @@ if FROZEN:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Tezos*.py'))

SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/zcash/*.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/zcash/*/*.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/zcash/*/*/*.py'))

SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/webauthn/*.py'))

Expand Down
2 changes: 2 additions & 0 deletions core/SConscript.unix
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,8 @@ if FROZEN:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Tezos*.py'))

SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/zcash/*.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/zcash/*/*.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/zcash/*/*/*.py'))

SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/webauthn/*.py'))

Expand Down
4 changes: 2 additions & 2 deletions core/embed/firmware/memory_T.ld
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ SECTIONS {

.flash2 : ALIGN(512) {
build/firmware/frozen_mpy.o(.rodata*);
/*
build/firmware/vendor/secp256k1-zkp/src/secp256k1.o(.rodata*);
build/firmware/vendor/secp256k1-zkp/src/precomputed_ecmult.o(.rodata*);
build/firmware/vendor/secp256k1-zkp/src/precomputed_ecmult_gen.o(.rodata*);
build/firmware/vendor/secp256k1-zkp/src/precomputed_ecmult_gen.o(.rodata*); */
. = ALIGN(512);
} >FLASH2 AT>FLASH2

.flash : ALIGN(512) {
KEEP(*(.vector_table));
. = ALIGN(4);
Expand Down
40 changes: 21 additions & 19 deletions core/embed/rust/src/zcash_primitives/pallas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,14 @@ mod scalar;
#[no_mangle]
pub static mp_module_trezorpallas: Module = obj_module! {
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorpallas.to_obj(),
/// # https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
/// def to_base(x: bytes) -> Fp:
/// ...
/// """https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents"""
Qstr::MP_QSTR_to_base => obj_fn_1!(fp::to_base).as_obj(),
/// # https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
/// def to_scalar(x: bytes) -> Scalar:
/// ...
/// """https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents"""
Qstr::MP_QSTR_to_scalar => obj_fn_1!(scalar::to_scalar).as_obj(),
/// # https://zips.z.cash/protocol/protocol.pdf#concretegrouphashpallasandvesta
/// def group_hash(domain: str, message: bytes) -> Point:
/// ...
/// """https://zips.z.cash/protocol/protocol.pdf#concretegrouphashpallasandvesta"""
Qstr::MP_QSTR_group_hash => obj_fn_2!(point::group_hash).as_obj(),
/// def scalar_from_i64(x: int) -> Scalar:
/// """Converts integer to Scalar."""
Expand All @@ -32,46 +29,51 @@ pub static mp_module_trezorpallas: Module = obj_module! {
/// def to_bytes(self) -> bytes:
/// ...
Qstr::MP_QSTR_Fp => (&fp::FP_TYPE).as_obj(),
/// class Scalar:
/// """Pallas scalar field."""
/// class Point:
/// """Pallas point."""
///
/// def __init__(self, repr: bytes) -> None:
/// ...
///
/// def to_bytes(self) -> bytes:
/// ...
///
/// def is_not_zero(self) -> bool:
/// def extract(self) -> Fp:
/// ...
///
/// def __mul__(self, other: Point) -> Point:
/// def is_identity(self) -> bool:
/// ...
///
/// def __add__(self, other: Scalar) -> Scalar:
/// def __add__(self, other: Point) -> Point:
/// ...
///
/// def __neg__(self) -> Point:
/// ...
Qstr::MP_QSTR_Scalar => (&scalar::SCALAR_TYPE).as_obj(),
/// class Point:
/// """Pallas point."""
Qstr::MP_QSTR_Point => (&point::POINT_TYPE).as_obj(),
/// PointOrScalar = TypeVar("PointOrScalar", Point, Scalar)
///
/// class Scalar:
/// """Pallas scalar field."""
///
/// def __init__(self, repr: bytes) -> None:
/// ...
///
/// def to_bytes(self) -> bytes:
/// ...
///
/// def extract(self) -> Fp:
/// def is_not_zero(self) -> bool:
/// ...
///
/// def is_identity(self) -> bool:
/// def __mul__(self, other: PointOrScalar) -> PointOrScalar:
/// ...
/// # if isinstance(other, Point) then isinstance(result, Point)
/// # if isinstance(other, Scalar) then isinstance(result, Scalar)
/// return other # just for typechecker! inner implementation differs
///
/// def __add__(self, other: Point) -> Point:
/// def __add__(self, other: Scalar) -> Scalar:
/// ...
///
/// def __neg__(self) -> Point:
/// def __neg__(self) -> Scalar:
/// ...
Qstr::MP_QSTR_Point => (&point::POINT_TYPE).as_obj(),
Qstr::MP_QSTR_Scalar => (&scalar::SCALAR_TYPE).as_obj(),
};
13 changes: 10 additions & 3 deletions core/embed/rust/src/zcash_primitives/pallas/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,16 @@ unsafe extern "C" fn scalar_binary_op(op: ffi::mp_binary_op_t, this: Obj, other:
let this = this.deref().inner();
match op {
ffi::mp_binary_op_t_MP_BINARY_OP_MULTIPLY => {
let other = Gc::<Wrapped<Point>>::try_from(other)?;
let other = other.deref().inner();
(other * this).wrap()
let point = Gc::<Wrapped<Point>>::try_from(other);
if point.is_ok() {
let point = point.unwrap();
let point = point.deref().inner();
(point * this).wrap()
} else {
let scalar = Gc::<Wrapped<Scalar>>::try_from(other)?;
let scalar = scalar.deref().inner();
(this * scalar).wrap()
}
}
ffi::mp_binary_op_t_MP_BINARY_OP_ADD => {
let other = Gc::<Wrapped<Scalar>>::try_from(other)?;
Expand Down
Loading

0 comments on commit f544513

Please sign in to comment.