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..73fbd91e29b 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -202,6 +202,10 @@ if UI2:
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorui2.c',
]
+if EVERYTHING:
+ SOURCE_MOD += [
+ 'embed/extmod/rustmods/modtrezorzcashprimitives.c'
+ ]
# modutime
SOURCE_MOD += [
diff --git a/core/SConscript.unix b/core/SConscript.unix
index d129adcd8b2..056322f6c0f 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -202,6 +202,10 @@ if UI2:
SOURCE_MOD += [
'embed/extmod/rustmods/modtrezorui2.c',
]
+if EVERYTHING:
+ SOURCE_MOD += [
+ 'embed/extmod/rustmods/modtrezorzcashprimitives.c'
+ ]
# modutime
SOURCE_MOD += [
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..da284724673 100644
--- a/core/embed/rust/Cargo.lock
+++ b/core/embed/rust/Cargo.lock
@@ -27,6 +27,36 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
+[[package]]
+name = "blake2b_simd"
+version = "1.0.0"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "bls12_381"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62250ece575fa9b22068b3a8d59586f01d426dd7785522efd97632959e71c986"
+dependencies = [
+ "ff",
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "byteorder"
version = "1.4.3"
@@ -81,12 +111,39 @@ 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 = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
[[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"
@@ -107,6 +164,20 @@ dependencies = [
"stable_deref_trait",
]
+[[package]]
+name = "jubjub"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a575df5f985fe1cd5b2b05664ff6accfc46559032b954529fd225a2168d27b0f"
+dependencies = [
+ "bitvec",
+ "bls12_381",
+ "ff",
+ "group",
+ "rand_core",
+ "subtle",
+]
+
[[package]]
name = "lazy_static"
version = "1.4.0"
@@ -166,6 +237,19 @@ dependencies = [
"minimal-lexical",
]
+[[package]]
+name = "pasta_curves"
+version = "0.4.0"
+source = "git+https://github.com/jarys/pasta_curves?branch=unboxed-hashtocurve-and-uninline#a4f755013aad344982383c9f5af362697d928325"
+dependencies = [
+ "blake2b_simd",
+ "ff",
+ "group",
+ "rand",
+ "static_assertions",
+ "subtle",
+]
+
[[package]]
name = "peeking_take_while"
version = "0.1.2"
@@ -190,6 +274,40 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
+[[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 = "reddsa"
+version = "0.3.0"
+source = "git+https://github.com/jarys/reddsa?branch=fix-alloc-feature#e9b04401b8899df47972ff553ee057f632b5de0d"
+dependencies = [
+ "blake2b_simd",
+ "byteorder",
+ "group",
+ "jubjub",
+ "pasta_curves",
+ "rand_core",
+]
+
[[package]]
name = "regex"
version = "1.5.6"
@@ -238,16 +356,41 @@ 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 = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
[[package]]
name = "trezor_lib"
version = "0.1.0"
dependencies = [
"bindgen",
+ "bitvec",
+ "blake2b_simd",
"cc",
"cstr_core",
"cty",
+ "ff",
"glob",
+ "group",
"heapless",
+ "pasta_curves",
+ "rand_core",
+ "reddsa",
]
[[package]]
@@ -277,3 +420,12 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "wyz"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
+dependencies = [
+ "tap",
+]
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index 1f6cdd4b572..47abdbec9a1 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -53,6 +53,34 @@ default_features = false
version = "0.2.4"
default_features = false
+[dependencies.ff]
+version = "0.12"
+default-features = false
+
+[dependencies.group]
+version = "0.12"
+default-features = false
+
+[dependencies.bitvec]
+version = "1"
+default-features = false
+
+[dependencies.rand_core]
+version = "0.6.3"
+default_features = false
+
+[dependencies.blake2b_simd]
+version = "1"
+default_features = false
+
+[dependencies.pasta_curves]
+version = "0.4.0"
+default-features = false
+
+[dependencies.reddsa]
+version = "0.3.0"
+default_features = false
+
# Build dependencies
[build-dependencies.bindgen]
@@ -69,3 +97,14 @@ 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"
+branch = "unboxed-hashtocurve-and-uninline"
+
+[patch.crates-io.reddsa]
+git = "https://github.com/jarys/reddsa"
+branch = "fix-alloc-feature"
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..be3274cd81f
--- /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: 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..afddae48c82 100644
--- a/core/embed/rust/librust.h
+++ b/core/embed/rust/librust.h
@@ -17,3 +17,7 @@ extern mp_obj_module_t mp_module_trezorui2;
#ifdef TREZOR_EMULATOR
mp_obj_t ui_debug_layout_type();
#endif
+
+// Zcash
+extern mp_obj_module_t mp_module_trezorpallas;
+extern mp_obj_module_t mp_module_trezorposeidon;
diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h
index 81c22d3c666..6314713a9f7 100644
--- a/core/embed/rust/librust_qstr.h
+++ b/core/embed/rust/librust_qstr.h
@@ -68,4 +68,24 @@ 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_is_not_zero;
+ MP_QSTR_sign_spend_auth;
+ MP_QSTR_sign_binding;
+
+ // 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..93f3a1e78e6 100644
--- a/core/embed/rust/src/lib.rs
+++ b/core/embed/rust/src/lib.rs
@@ -17,6 +17,8 @@ mod time;
#[cfg(feature = "ui_debug")]
mod trace;
+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..ca717cca21c 100644
--- a/core/embed/rust/src/micropython/mod.rs
+++ b/core/embed/rust/src/micropython/mod.rs
@@ -18,6 +18,7 @@ pub mod runtime;
pub mod time;
pub mod typ;
pub mod util;
+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