diff --git a/core/.changelog.d/2510.added b/core/.changelog.d/2510.added
new file mode 100644
index 00000000000..4b3fa0852ae
--- /dev/null
+++ b/core/.changelog.d/2510.added
@@ -0,0 +1 @@
+Add Zcash Rust primitives
diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index 96ffec17d1c..a8f5a8cc3bd 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -12,6 +12,7 @@ FEATURE_FLAGS = {
"RDI": True,
"SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot)
"SYSTEM_VIEW": False,
+ "ZCASH_SHIELDED": False,
}
CCFLAGS_MOD = ''
@@ -202,6 +203,10 @@ if UI2:
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorui2.c',
]
+if FEATURE_FLAGS["ZCASH_SHIELDED"]:
+ SOURCE_MOD += [
+ 'embed/extmod/rustmods/modtrezorzcashprimitives.c'
+ ]
# modutime
SOURCE_MOD += [
@@ -678,7 +683,7 @@ if FROZEN:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/zcash_v4.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Zcash*.py'))
- source_mpy = env.FrozenModule(source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY)
+ source_mpy = env.FrozenModule(source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY, zcash_shielded=FEATURE_FLAGS['ZCASH_SHIELDED'])
source_mpyc = env.FrozenCFile(
target='frozen_mpy.c', source=source_mpy, qstr_header=qstr_preprocessed)
@@ -720,6 +725,8 @@ def cargo_build():
features.append('ui')
if PYOPT == '0':
features.append('ui_debug')
+ if FEATURE_FLAGS["ZCASH_SHIELDED"]:
+ features.append("zcash_shielded")
cargo_opts = [
f'--target={RUST_TARGET}',
diff --git a/core/SConscript.unix b/core/SConscript.unix
index d129adcd8b2..edcbaf2d440 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -10,6 +10,7 @@ UI2 = ARGUMENTS.get('UI2', '0') == '1' or TREZOR_MODEL in ('1', 'R')
FEATURE_FLAGS = {
"SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot)
+ "ZCASH_SHIELDED": EVERYTHING,
}
CCFLAGS_MOD = ''
@@ -202,6 +203,10 @@ if UI2:
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorui2.c',
]
+if FEATURE_FLAGS["ZCASH_SHIELDED"]:
+ SOURCE_MOD += [
+ 'embed/extmod/rustmods/modtrezorzcashprimitives.c'
+ ]
# modutime
SOURCE_MOD += [
@@ -634,7 +639,7 @@ if FROZEN:
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'apps/bitcoin/sign_tx/zcash_v4.py'))
SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/enums/Zcash*.py'))
- source_mpy = env.FrozenModule(source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY)
+ source_mpy = env.FrozenModule(source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY, zcash_shielded=FEATURE_FLAGS['ZCASH_SHIELDED'])
source_mpyc = env.FrozenCFile(
target='frozen_mpy.c', source=source_mpy, qstr_header=qstr_preprocessed)
@@ -674,6 +679,8 @@ def cargo_build():
features.append('ui')
if PYOPT == '0':
features.append('debug')
+ if FEATURE_FLAGS["ZCASH_SHIELDED"]:
+ features.append('zcash_shielded')
return f'cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}"'
diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils.c b/core/embed/extmod/modtrezorutils/modtrezorutils.c
index 40212557798..1656d144da8 100644
--- a/core/embed/extmod/modtrezorutils/modtrezorutils.c
+++ b/core/embed/extmod/modtrezorutils/modtrezorutils.c
@@ -243,6 +243,7 @@ STATIC mp_obj_str_t mod_trezorutils_revision_obj = {
/// MODEL: str
/// EMULATOR: bool
/// BITCOIN_ONLY: bool
+/// ZCASH_SHIELDED: bool
STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorutils)},
@@ -283,6 +284,11 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else
{MP_ROM_QSTR(MP_QSTR_BITCOIN_ONLY), mp_const_false},
#endif
+#ifdef ZCASH_SHIELDED
+ {MP_ROM_QSTR(MP_QSTR_ZCASH_SHIELDED), mp_const_true},
+#elif TREZOR_EMULATOR
+ {MP_ROM_QSTR(MP_QSTR_ZCASH_SHIELDED), mp_const_false},
+#endif
};
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorutils_globals,
diff --git a/core/embed/extmod/rustmods/modtrezorzcashprimitives.c b/core/embed/extmod/rustmods/modtrezorzcashprimitives.c
new file mode 100644
index 00000000000..030e7b20755
--- /dev/null
+++ b/core/embed/extmod/rustmods/modtrezorzcashprimitives.c
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "py/runtime.h"
+
+#include "librust.h"
+
+#if MICROPY_PY_TREZORPALLAS
+MP_REGISTER_MODULE(MP_QSTR_trezorpallas, mp_module_trezorpallas,
+ MICROPY_PY_TREZORPALLAS);
+#endif // MICROPY_PY_TREZORPALLAS
+
+#if MICROPY_PY_TREZORPOSEIDON
+MP_REGISTER_MODULE(MP_QSTR_trezorposeidon, mp_module_trezorposeidon,
+ MICROPY_PY_TREZORPOSEIDON);
+#endif // MICROPY_PY_TREZORPOSEIDON
diff --git a/core/embed/firmware/mpconfigport.h b/core/embed/firmware/mpconfigport.h
index c123c91a0d8..49546040837 100644
--- a/core/embed/firmware/mpconfigport.h
+++ b/core/embed/firmware/mpconfigport.h
@@ -160,6 +160,8 @@
#define MICROPY_PY_TREZORUTILS (1)
#define MICROPY_PY_TREZORPROTO (1)
#define MICROPY_PY_TREZORUI2 (1)
+#define MICROPY_PY_TREZORPALLAS (1)
+#define MICROPY_PY_TREZORPOSEIDON (1)
#ifdef SYSTEM_VIEW
#define MP_PLAT_PRINT_STRN(str, len) segger_print(str, len)
diff --git a/core/embed/rust/Cargo.lock b/core/embed/rust/Cargo.lock
index abcb1132b21..5e548950e14 100644
--- a/core/embed/rust/Cargo.lock
+++ b/core/embed/rust/Cargo.lock
@@ -27,6 +27,13 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+[[package]]
+name = "blake2b_simd"
+version = "1.0.0"
+dependencies = [
+ "cty",
+]
+
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -81,12 +88,33 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+[[package]]
+name = "ff"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e"
+dependencies = [
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+[[package]]
+name = "group"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "hash32"
version = "0.2.1"
@@ -166,6 +194,19 @@ dependencies = [
"minimal-lexical",
]
+[[package]]
+name = "pasta_curves"
+version = "0.4.0"
+source = "git+https://github.com/jarys/pasta_curves?rev=a4f755013aad344982383c9f5af362697d928325#a4f755013aad344982383c9f5af362697d928325"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "rand",
+ "static_assertions",
+ "subtle",
+]
+
[[package]]
name = "peeking_take_while"
version = "0.1.2"
@@ -190,6 +231,21 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+
[[package]]
name = "regex"
version = "1.5.6"
@@ -238,16 +294,30 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
[[package]]
name = "trezor_lib"
version = "0.1.0"
dependencies = [
"bindgen",
+ "blake2b_simd",
"cc",
"cstr_core",
"cty",
"glob",
"heapless",
+ "pasta_curves",
]
[[package]]
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index 1f6cdd4b572..e5410fc5a22 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -8,6 +8,9 @@ build = "build.rs"
[features]
default = ["model_tt"]
bitcoin_only = []
+zcash_shielded = [
+ "micropython", "pasta_curves", "blake2b_simd",
+]
model_tt = ["touch"]
model_t1 = ["buttons"]
model_tr = ["buttons"]
@@ -19,7 +22,7 @@ buttons = []
touch = []
clippy = []
debug = ["ui_debug"]
-test = ["cc", "glob", "micropython", "protobuf", "ui", "ui_debug"]
+test = ["cc", "glob", "micropython", "protobuf", "ui", "ui_debug", "zcash_shielded"]
[lib]
crate-type = ["staticlib"]
@@ -53,6 +56,16 @@ default_features = false
version = "0.2.4"
default_features = false
+[dependencies.blake2b_simd]
+optional = true
+version = "1"
+default_features = false
+
+[dependencies.pasta_curves]
+optional = true
+version = "0.4.0"
+default-features = false
+
# Build dependencies
[build-dependencies.bindgen]
@@ -69,3 +82,10 @@ version = "1.0.69"
[build-dependencies.glob]
optional = true
version = "0.3.0"
+
+[patch.crates-io.blake2b_simd]
+path = "./blake2b_hal"
+
+[patch.crates-io.pasta_curves]
+git = "https://github.com/jarys/pasta_curves"
+rev = "a4f755013aad344982383c9f5af362697d928325"
diff --git a/core/embed/rust/blake2b_hal/Cargo.lock b/core/embed/rust/blake2b_hal/Cargo.lock
new file mode 100644
index 00000000000..0c911cdda91
--- /dev/null
+++ b/core/embed/rust/blake2b_hal/Cargo.lock
@@ -0,0 +1,16 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "blake2b_simd"
+version = "0.1.0"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
diff --git a/core/embed/rust/blake2b_hal/Cargo.toml b/core/embed/rust/blake2b_hal/Cargo.toml
new file mode 100644
index 00000000000..be430975af0
--- /dev/null
+++ b/core/embed/rust/blake2b_hal/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "blake2b_simd"
+version = "1.0.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+cty = "0.2.2"
diff --git a/core/embed/rust/blake2b_hal/src/ffi.rs b/core/embed/rust/blake2b_hal/src/ffi.rs
new file mode 100644
index 00000000000..d1e720e6a50
--- /dev/null
+++ b/core/embed/rust/blake2b_hal/src/ffi.rs
@@ -0,0 +1,43 @@
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __blake2b_state {
+ pub h: [u64; 8usize],
+ pub t: [u64; 2usize],
+ pub f: [u64; 2usize],
+ pub buf: [u8; 128usize],
+ pub buflen: usize,
+ pub outlen: usize,
+ pub last_node: u8,
+}
+#[allow(non_camel_case_types)]
+pub type blake2b_state = __blake2b_state;
+extern "C" {
+ pub fn blake2b_Init(S: *mut blake2b_state, outlen: usize) -> cty::c_int;
+}
+extern "C" {
+ pub fn blake2b_InitKey(
+ S: *mut blake2b_state,
+ outlen: usize,
+ key: *const cty::c_void,
+ keylen: usize,
+ ) -> cty::c_int;
+}
+extern "C" {
+ pub fn blake2b_InitPersonal(
+ S: *mut blake2b_state,
+ outlen: usize,
+ personal: *const cty::c_void,
+ personal_len: usize,
+ ) -> cty::c_int;
+}
+extern "C" {
+ pub fn blake2b_Update(
+ S: *mut blake2b_state,
+ pin: *const cty::c_void,
+ inlen: usize,
+ ) -> cty::c_int;
+}
+extern "C" {
+ pub fn blake2b_Final(S: *mut blake2b_state, out: *mut cty::c_void, outlen: usize)
+ -> cty::c_int;
+}
diff --git a/core/embed/rust/blake2b_hal/src/lib.rs b/core/embed/rust/blake2b_hal/src/lib.rs
new file mode 100644
index 00000000000..3654afc020f
--- /dev/null
+++ b/core/embed/rust/blake2b_hal/src/lib.rs
@@ -0,0 +1,144 @@
+//! This crate is a wrapper of blake2b.c.
+//! Purpose of this crate is to replace blake2_simd crate
+//! required by some Rust dependencies.
+
+#![no_std]
+
+use cty::c_void;
+
+mod ffi;
+
+pub const BLOCKBYTES: usize = 128;
+pub const KEYBYTES: usize = 64;
+pub const OUTBYTES: usize = 64;
+pub const PERSONALBYTES: usize = 16;
+pub const SALTBYTES: usize = 16;
+
+#[derive(Clone, Copy)]
+pub struct Hash {
+ bytes: [u8; OUTBYTES],
+ len: u8,
+}
+
+impl Hash {
+ pub fn as_bytes(&self) -> &[u8] {
+ &self.bytes[..self.len as usize]
+ }
+
+ #[inline]
+ pub fn as_array(&self) -> &[u8; OUTBYTES] {
+ &self.bytes
+ }
+}
+
+#[derive(Clone, Copy)]
+pub struct Params<'a, 'b> {
+ key: Option<&'a [u8]>,
+ personal: Option<&'b [u8]>,
+ outlen: usize,
+}
+
+impl<'a, 'b> Params<'a, 'b> {
+ pub fn new() -> Self {
+ Params {
+ key: None,
+ personal: None,
+ outlen: OUTBYTES,
+ }
+ }
+
+ pub fn hash_length(&mut self, length: usize) -> &mut Self {
+ self.outlen = length;
+ self
+ }
+
+ pub fn key(&mut self, key: &'a [u8]) -> &mut Self {
+ self.key = Some(key);
+ self
+ }
+
+ pub fn personal(&mut self, personal: &'b [u8]) -> &mut Self {
+ self.personal = Some(personal);
+ self
+ }
+
+ pub fn to_state(self) -> State {
+ assert!(self.key.is_none() || self.personal.is_none());
+ let mut ctx = ffi::__blake2b_state {
+ h: [0u64; 8usize],
+ t: [0u64; 2usize],
+ f: [0u64; 2usize],
+ buf: [0u8; 128usize],
+ buflen: 0usize,
+ outlen: 0usize,
+ last_node: 0u8,
+ };
+ let res = unsafe {
+ match (self.key, self.personal) {
+ (None, None) => ffi::blake2b_Init(&mut ctx, self.outlen),
+ (Some(key), None) => ffi::blake2b_InitKey(
+ &mut ctx,
+ self.outlen,
+ key.as_ptr() as *const c_void,
+ key.len(),
+ ),
+ (None, Some(personal)) => ffi::blake2b_InitPersonal(
+ &mut ctx,
+ self.outlen,
+ personal.as_ptr() as *const c_void,
+ personal.len(),
+ ),
+ (Some(_), Some(_)) => {
+ panic!("Using key and personalization simultaniously not implemented.")
+ }
+ }
+ };
+ if res < 0 {
+ panic!("Blake2b initialization failed.")
+ }
+ State { ctx }
+ }
+
+ pub fn hash(self, data: &[u8]) -> Hash {
+ self.to_state().update(data).finalize()
+ }
+}
+
+#[derive(Clone)]
+pub struct State {
+ ctx: ffi::blake2b_state,
+}
+
+impl State {
+ pub fn new() -> Self {
+ Params::new().to_state()
+ }
+
+ pub fn update(&mut self, data: &[u8]) -> &mut Self {
+ unsafe {
+ ffi::blake2b_Update(&mut self.ctx, data.as_ptr() as *const c_void, data.len());
+ }
+ self
+ }
+
+ pub fn finalize(&self) -> Hash {
+ // Method `finalize` takes imutable reference to the self
+ // to mirror `blake2b_simd` API.
+ let mut bytes = [0u8; OUTBYTES];
+ let ptr = bytes.as_mut_ptr() as *mut c_void;
+ // clone `ctx` to get a mutable reference required by `ffi::blake2b_Final`
+ let mut ctx = self.ctx.clone();
+ let res = unsafe { ffi::blake2b_Final(&mut ctx, ptr, OUTBYTES) };
+ if res < 0 {
+ panic!("Blake2b hash finalization failed.")
+ }
+ Hash {
+ bytes,
+ len: self.ctx.outlen as u8,
+ }
+ }
+}
+
+pub fn blake2b(data: &[u8]) -> Hash {
+ State::new().update(data).finalize()
+}
diff --git a/core/embed/rust/librust.h b/core/embed/rust/librust.h
index a3d943e2029..3969d09cc77 100644
--- a/core/embed/rust/librust.h
+++ b/core/embed/rust/librust.h
@@ -17,3 +17,8 @@ extern mp_obj_module_t mp_module_trezorui2;
#ifdef TREZOR_EMULATOR
mp_obj_t ui_debug_layout_type();
#endif
+
+#ifdef ZCASH_SHIELDED
+extern mp_obj_module_t mp_module_trezorpallas;
+extern mp_obj_module_t mp_module_trezorposeidon;
+#endif
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 81c22d3c666..8004ff7a1c7 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -68,4 +68,30 @@ static void _librust_qstrs(void) {
MP_QSTR_total_amount;
MP_QSTR_total_fee_new;
MP_QSTR_user_fee_change;
+
+ // pallas
+ MP_QSTR_trezorpallas;
+ MP_QSTR_Fp;
+ MP_QSTR_Scalar;
+ MP_QSTR_Point;
+ MP_QSTR_to_bytes;
+ MP_QSTR_extract;
+ MP_QSTR_is_identity;
+ MP_QSTR_to_base;
+ MP_QSTR_to_scalar;
+ MP_QSTR_group_hash;
+ MP_QSTR_scalar_from_i64;
+ MP_QSTR_generators;
+ MP_QSTR_SPENDING_KEY_BASE;
+ MP_QSTR_NULLIFIER_K_BASE;
+ MP_QSTR_VALUE_COMMITMENT_VALUE_BASE;
+ MP_QSTR_VALUE_COMMITMENT_RANDOMNESS_BASE;
+ MP_QSTR_NOTE_COMMITMENT_BASE;
+ MP_QSTR_NOTE_COMMITMENT_Q;
+ MP_QSTR_IVK_COMMITMENT_BASE;
+ MP_QSTR_IVK_COMMITMENT_Q;
+
+ // poseidon
+ MP_QSTR_trezorposeidon;
+ MP_QSTR_poseidon;
}
diff --git a/core/embed/rust/src/error.rs b/core/embed/rust/src/error.rs
index 13e278603a5..6e9910fba77 100644
--- a/core/embed/rust/src/error.rs
+++ b/core/embed/rust/src/error.rs
@@ -1,4 +1,5 @@
use core::{
+ array::TryFromSliceError,
convert::{Infallible, TryInto},
num::TryFromIntError,
};
@@ -83,3 +84,9 @@ impl From for Error {
Self::OutOfRange
}
}
+
+impl From for Error {
+ fn from(_e: TryFromSliceError) -> Error {
+ Error::OutOfRange
+ }
+}
diff --git a/core/embed/rust/src/lib.rs b/core/embed/rust/src/lib.rs
index 2f63df12b4d..5346b97d07c 100644
--- a/core/embed/rust/src/lib.rs
+++ b/core/embed/rust/src/lib.rs
@@ -17,6 +17,9 @@ mod time;
#[cfg(feature = "ui_debug")]
mod trace;
+#[cfg(feature = "zcash_shielded")]
+mod zcash_primitives;
+
#[cfg(feature = "ui")]
#[macro_use]
pub mod ui;
diff --git a/core/embed/rust/src/micropython/macros.rs b/core/embed/rust/src/micropython/macros.rs
index 557666c8e00..71406d1db28 100644
--- a/core/embed/rust/src/micropython/macros.rs
+++ b/core/embed/rust/src/micropython/macros.rs
@@ -121,7 +121,10 @@ macro_rules! obj_type {
(name: $name:expr,
$(locals: $locals:expr,)?
$(attr_fn: $attr_fn:ident,)?
+ $(make_new_fn: $make_new_fn:expr,)?
$(call_fn: $call_fn:ident,)?
+ $(unary_op_fn: $unary_op_fn:ident,)?
+ $(binary_op_fn: $binary_op_fn:ident,)?
) => {{
#[allow(unused_unsafe)]
unsafe {
@@ -134,11 +137,26 @@ macro_rules! obj_type {
let mut attr: ffi::mp_attr_fun_t = None;
$(attr = Some($attr_fn);)?
+ #[allow(unused_mut)]
+ #[allow(unused_assignments)]
+ let mut make_new: ffi::mp_make_new_fun_t = None;
+ $(make_new = Some($make_new_fn);)?
+
#[allow(unused_mut)]
#[allow(unused_assignments)]
let mut call: ffi::mp_call_fun_t = None;
$(call = Some($call_fn);)?
+ #[allow(unused_mut)]
+ #[allow(unused_assignments)]
+ let mut unary_op: ffi::mp_unary_op_fun_t = None;
+ $(unary_op = Some($unary_op_fn);)?
+
+ #[allow(unused_mut)]
+ #[allow(unused_assignments)]
+ let mut binary_op: ffi::mp_binary_op_fun_t = None;
+ $(binary_op = Some($binary_op_fn);)?
+
// TODO: This is safe only if we pass in `Dict` with fixed `Map` (created by
// `Map::fixed()`, usually through `obj_map!`), because only then will
// MicroPython treat `locals_dict` as immutable, and make the mutable cast safe.
@@ -154,10 +172,10 @@ macro_rules! obj_type {
flags: 0,
name,
print: None,
- make_new: None,
+ make_new,
call,
- unary_op: None,
- binary_op: None,
+ unary_op,
+ binary_op,
attr,
subscr: None,
getiter: None,
diff --git a/core/embed/rust/src/micropython/mod.rs b/core/embed/rust/src/micropython/mod.rs
index 0ebe3afae68..dbf5048dea7 100644
--- a/core/embed/rust/src/micropython/mod.rs
+++ b/core/embed/rust/src/micropython/mod.rs
@@ -18,6 +18,8 @@ pub mod runtime;
pub mod time;
pub mod typ;
pub mod util;
+#[cfg(feature = "zcash_shielded")]
+pub mod wrap;
#[cfg(test)]
pub mod testutil;
diff --git a/core/embed/rust/src/micropython/obj.rs b/core/embed/rust/src/micropython/obj.rs
index 1b0a09d7209..6e2cd633ce9 100644
--- a/core/embed/rust/src/micropython/obj.rs
+++ b/core/embed/rust/src/micropython/obj.rs
@@ -2,7 +2,7 @@ use core::convert::{TryFrom, TryInto};
use cstr_core::CStr;
-use crate::error::Error;
+use crate::{error::Error, micropython::buffer::Buffer};
use super::{ffi, runtime::catch_exception};
@@ -382,6 +382,23 @@ impl TryFrom for usize {
}
}
+impl TryFrom<[u8; N]> for Obj {
+ type Error = Error;
+
+ fn try_from(array: [u8; N]) -> Result {
+ Ok((&array[..]).try_into()?)
+ }
+}
+
+impl TryFrom for [u8; N] {
+ type Error = Error;
+
+ fn try_from(obj: Obj) -> Result<[u8; N], Error> {
+ let buffer: Buffer = obj.try_into()?;
+ Ok(buffer.as_ref().try_into()?)
+ }
+}
+
impl From