mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-14 03:30:02 +00:00
feat(core): add Zcash Rust primitives
This commit is contained in:
parent
031bac4a9b
commit
6311675119
1
core/.changelog.d/2510.added
Normal file
1
core/.changelog.d/2510.added
Normal file
@ -0,0 +1 @@
|
||||
Add Zcash Rust primitives
|
@ -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}',
|
||||
|
@ -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)}"'
|
||||
|
||||
|
@ -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,
|
||||
|
32
core/embed/extmod/rustmods/modtrezorzcashprimitives.c
Normal file
32
core/embed/extmod/rustmods/modtrezorzcashprimitives.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -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)
|
||||
|
70
core/embed/rust/Cargo.lock
generated
70
core/embed/rust/Cargo.lock
generated
@ -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]]
|
||||
|
@ -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"
|
||||
|
16
core/embed/rust/blake2b_hal/Cargo.lock
generated
Normal file
16
core/embed/rust/blake2b_hal/Cargo.lock
generated
Normal file
@ -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"
|
9
core/embed/rust/blake2b_hal/Cargo.toml
Normal file
9
core/embed/rust/blake2b_hal/Cargo.toml
Normal file
@ -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"
|
43
core/embed/rust/blake2b_hal/src/ffi.rs
Normal file
43
core/embed/rust/blake2b_hal/src/ffi.rs
Normal file
@ -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;
|
||||
}
|
144
core/embed/rust/blake2b_hal/src/lib.rs
Normal file
144
core/embed/rust/blake2b_hal/src/lib.rs
Normal file
@ -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()
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use core::{
|
||||
array::TryFromSliceError,
|
||||
convert::{Infallible, TryInto},
|
||||
num::TryFromIntError,
|
||||
};
|
||||
@ -83,3 +84,9 @@ impl From<TryFromIntError> for Error {
|
||||
Self::OutOfRange
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TryFromSliceError> for Error {
|
||||
fn from(_e: TryFromSliceError) -> Error {
|
||||
Error::OutOfRange
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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<Obj> for usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> TryFrom<[u8; N]> for Obj {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(array: [u8; N]) -> Result<Obj, Error> {
|
||||
Ok((&array[..]).try_into()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> TryFrom<Obj> 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<T> From<Option<T>> for Obj
|
||||
where
|
||||
T: Into<Obj>,
|
||||
|
@ -22,6 +22,15 @@ impl Type {
|
||||
pub const fn as_base(&'static self) -> ObjBase {
|
||||
ObjBase { type_: self }
|
||||
}
|
||||
|
||||
/// Convert a "static const" Type to a MicroPython object.
|
||||
pub const fn as_obj(&'static self) -> Obj {
|
||||
// SAFETY:
|
||||
// - We are an object struct with a base and a type.
|
||||
// - 'static lifetime holds us in place.
|
||||
// - MicroPython is smart enough not to mutate `mp_obj_type_t` objects.
|
||||
unsafe { Obj::from_ptr(self as *const _ as *mut _) }
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: We are in a single-threaded environment.
|
||||
|
76
core/embed/rust/src/micropython/wrap.rs
Normal file
76
core/embed/rust/src/micropython/wrap.rs
Normal file
@ -0,0 +1,76 @@
|
||||
//! Tiny module for wrapping Rust structs into Python objects
|
||||
//!
|
||||
//! # Example:
|
||||
//! ```
|
||||
//! impl Wrappable for Foo {
|
||||
//! fn obj_type() -> &'static Type { ... }
|
||||
//! }
|
||||
//!
|
||||
//! fn bar(obj: Obj) -> Obj {
|
||||
//! let foo: Gc<Wrapped<Foo>> = obj.try_into()?;
|
||||
//! let foo: Foo = foo.deref().inner();
|
||||
//! let result: Foo = baz(foo);
|
||||
//! result.wrap()
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
micropython::{
|
||||
gc::Gc,
|
||||
obj::{Obj, ObjBase},
|
||||
typ::Type,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait Wrappable: Sized {
|
||||
fn obj_type() -> &'static Type;
|
||||
|
||||
fn alloc(inner: Self) -> Result<Gc<Wrapped<Self>>, Error> {
|
||||
Gc::new(Wrapped {
|
||||
base: Self::obj_type().as_base(),
|
||||
inner,
|
||||
})
|
||||
}
|
||||
|
||||
fn wrap(self) -> Result<Obj, Error> {
|
||||
let value: Gc<Wrapped<Self>> = Self::alloc(self)?;
|
||||
// SAFETY:
|
||||
// - `value` is GC-allocated.
|
||||
// - `value` is `repr(C)`.
|
||||
// - `value` has a `base` as the first field with the correct type.
|
||||
let obj = unsafe { Obj::from_ptr(Gc::into_raw(value).cast()) };
|
||||
Ok(obj)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Wrapped<T: Wrappable> {
|
||||
base: ObjBase,
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T: Wrappable> Wrapped<T> {
|
||||
pub fn inner(&self) -> &T {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn inner_mut(&mut self) -> &mut T {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Wrappable> TryFrom<Obj> for Gc<Wrapped<T>> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(obj: Obj) -> Result<Gc<Wrapped<T>>, Error> {
|
||||
if T::obj_type().is_type_of(obj) {
|
||||
// SAFETY: We assume that if `obj` is an object pointer with the correct type,
|
||||
// it is always GC-allocated.
|
||||
let this = unsafe { Gc::from_raw(obj.as_ptr().cast()) };
|
||||
Ok(this)
|
||||
} else {
|
||||
Err(Error::TypeError)
|
||||
}
|
||||
}
|
||||
}
|
62
core/embed/rust/src/trezorhal/blake2b_tests.rs
Normal file
62
core/embed/rust/src/trezorhal/blake2b_tests.rs
Normal file
@ -0,0 +1,62 @@
|
||||
//! Test are placed here to be executed by `make test_rust`.
|
||||
|
||||
use blake2b_simd::*;
|
||||
|
||||
const EMPTY_HASH: [u8; 64] = [
|
||||
120, 106, 2, 247, 66, 1, 89, 3, 198, 198, 253, 133, 37, 82, 210, 114, 145, 47, 71, 64, 225, 88,
|
||||
71, 97, 138, 134, 226, 23, 247, 31, 84, 25, 210, 94, 16, 49, 175, 238, 88, 83, 19, 137, 100,
|
||||
68, 147, 78, 176, 75, 144, 58, 104, 91, 20, 72, 183, 85, 213, 111, 112, 26, 254, 155, 226, 206,
|
||||
];
|
||||
const ABC_HASH: [u8; 64] = [
|
||||
186, 128, 165, 63, 152, 28, 77, 13, 106, 39, 151, 182, 159, 18, 246, 233, 76, 33, 47, 20, 104,
|
||||
90, 196, 183, 75, 18, 187, 111, 219, 255, 162, 209, 125, 135, 197, 57, 42, 171, 121, 45, 194,
|
||||
82, 213, 222, 69, 51, 204, 149, 24, 211, 138, 168, 219, 241, 146, 90, 185, 35, 134, 237, 212,
|
||||
0, 153, 35,
|
||||
];
|
||||
const ONE_BLOCK_HASH: [u8; 64] = [
|
||||
134, 89, 57, 225, 32, 230, 128, 84, 56, 71, 136, 65, 175, 183, 57, 174, 66, 80, 207, 55, 38,
|
||||
83, 7, 138, 6, 92, 220, 255, 252, 164, 202, 247, 152, 230, 212, 98, 182, 93, 101, 143, 193,
|
||||
101, 120, 38, 64, 237, 237, 112, 150, 52, 73, 174, 21, 0, 251, 15, 36, 152, 29, 119, 39, 226,
|
||||
44, 65,
|
||||
];
|
||||
const THOUSAND_HASH: [u8; 64] = [
|
||||
30, 228, 229, 30, 202, 181, 33, 10, 81, 143, 38, 21, 14, 136, 38, 39, 236, 131, 153, 103, 241,
|
||||
157, 118, 62, 21, 8, 177, 44, 254, 254, 209, 72, 88, 246, 161, 201, 209, 249, 105, 188, 34, 77,
|
||||
201, 68, 15, 90, 105, 85, 39, 126, 117, 91, 156, 81, 63, 155, 164, 66, 28, 94, 80, 200, 215,
|
||||
135,
|
||||
];
|
||||
|
||||
#[test]
|
||||
fn test_update_state() {
|
||||
let io = &[
|
||||
(&b""[..], EMPTY_HASH),
|
||||
(&b"abc"[..], ABC_HASH),
|
||||
(&[0; 128], ONE_BLOCK_HASH),
|
||||
(&[0; 1000], THOUSAND_HASH),
|
||||
];
|
||||
// Test each input all at once.
|
||||
for &(input, output) in io {
|
||||
let hash = blake2b(input);
|
||||
assert_eq!(hash.as_bytes(), &output, "hash mismatch");
|
||||
}
|
||||
// Now in two chunks. This is especially important for the ONE_BLOCK case,
|
||||
// because it would be a mistake for update() to call compress, even though
|
||||
// the buffer is full.
|
||||
for &(input, output) in io {
|
||||
let mut state = State::new();
|
||||
let split = input.len() / 2;
|
||||
state.update(&input[..split]);
|
||||
state.update(&input[split..]);
|
||||
let hash = state.finalize();
|
||||
assert_eq!(hash.as_bytes(), &output, "hash mismatch");
|
||||
}
|
||||
// Now one byte at a time.
|
||||
for &(input, output) in io {
|
||||
let mut state = State::new();
|
||||
for &b in input {
|
||||
state.update(&[b]);
|
||||
}
|
||||
let hash = state.finalize();
|
||||
assert_eq!(hash.as_bytes(), &output, "hash mismatch");
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
pub mod bip39;
|
||||
#[cfg(all(test, feature = "zcash_shielded"))]
|
||||
mod blake2b_tests;
|
||||
#[macro_use]
|
||||
#[allow(unused_macros)]
|
||||
pub mod common;
|
||||
|
2
core/embed/rust/src/zcash_primitives/mod.rs
Normal file
2
core/embed/rust/src/zcash_primitives/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod pallas;
|
||||
pub mod poseidon;
|
27
core/embed/rust/src/zcash_primitives/pallas/common.rs
Normal file
27
core/embed/rust/src/zcash_primitives/pallas/common.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use cstr_core::cstr;
|
||||
use pasta_curves::group::ff;
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
micropython::{map::Map, obj::Obj, typ::Type, util, wrap::Wrappable},
|
||||
};
|
||||
|
||||
pub unsafe extern "C" fn ff_from_bytes<F: Wrappable + ff::PrimeField<Repr = [u8; 32]>>(
|
||||
_type_: *const Type,
|
||||
n_args: usize,
|
||||
n_kw: usize,
|
||||
args: *const Obj,
|
||||
) -> Obj {
|
||||
let block = |args: &[Obj], _kwargs: &Map| {
|
||||
if args.len() != 1 {
|
||||
return Err(Error::TypeError);
|
||||
}
|
||||
let bytes: [u8; 32] = args[0].try_into()?;
|
||||
let elem = F::from_repr(bytes);
|
||||
match Option::<F>::from(elem) {
|
||||
Some(e) => e.wrap(),
|
||||
None => Err(Error::ValueError(cstr!("Conversion failed"))),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs_inline(n_args, n_kw, args, block) }
|
||||
}
|
63
core/embed/rust/src/zcash_primitives/pallas/fp.rs
Normal file
63
core/embed/rust/src/zcash_primitives/pallas/fp.rs
Normal file
@ -0,0 +1,63 @@
|
||||
use core::ops::Deref;
|
||||
use pasta_curves::{arithmetic::FieldExt, group::ff::PrimeField, Fp};
|
||||
|
||||
use crate::micropython::{
|
||||
ffi,
|
||||
gc::Gc,
|
||||
map::Map,
|
||||
obj::Obj,
|
||||
qstr::Qstr,
|
||||
typ::Type,
|
||||
util,
|
||||
wrap::{Wrappable, Wrapped},
|
||||
};
|
||||
|
||||
pub static FP_TYPE: Type = obj_type! {
|
||||
name: Qstr::MP_QSTR_Fp,
|
||||
locals: &obj_dict!(obj_map! {
|
||||
Qstr::MP_QSTR_to_bytes => obj_fn_1!(fp_to_bytes).as_obj(),
|
||||
}),
|
||||
make_new_fn: super::common::ff_from_bytes::<Fp>,
|
||||
binary_op_fn: fp_binary_op,
|
||||
};
|
||||
|
||||
impl Wrappable for Fp {
|
||||
fn obj_type() -> &'static Type {
|
||||
&FP_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn fp_to_bytes(self_in: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this: Gc<Wrapped<Fp>> = self_in.try_into()?;
|
||||
let bytes: [u8; 32] = this.deref().inner().to_repr();
|
||||
bytes.try_into()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn fp_binary_op(op: ffi::mp_binary_op_t, this: Obj, other: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Fp>>::try_from(this)?;
|
||||
let this = this.deref().inner();
|
||||
match op {
|
||||
ffi::mp_binary_op_t_MP_BINARY_OP_ADD => {
|
||||
let other = Gc::<Wrapped<Fp>>::try_from(other)?;
|
||||
let other = other.deref().inner();
|
||||
(this + other).wrap()
|
||||
}
|
||||
_ => Ok(Obj::const_null()),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn to_base(bytes: Obj) -> Obj {
|
||||
let block = || {
|
||||
let bytes: [u8; 64] = bytes.try_into()?;
|
||||
let elem = Fp::from_bytes_wide(&bytes);
|
||||
elem.wrap()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
155
core/embed/rust/src/zcash_primitives/pallas/generators.rs
Normal file
155
core/embed/rust/src/zcash_primitives/pallas/generators.rs
Normal file
@ -0,0 +1,155 @@
|
||||
//! Precomputed Orchard generators.
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
micropython::{ffi, obj::Obj, qstr::Qstr, typ::Type, util, wrap::Wrappable},
|
||||
};
|
||||
use pasta_curves::{
|
||||
arithmetic::CurveAffine,
|
||||
pallas::{Affine, Point},
|
||||
Fp,
|
||||
};
|
||||
|
||||
pub static GENERATORS_TYPE: Type = obj_type! {
|
||||
name: Qstr::MP_QSTR_generators,
|
||||
attr_fn: attr_fn,
|
||||
};
|
||||
|
||||
unsafe extern "C" fn attr_fn(_self_in: Obj, attr: ffi::qstr, dest: *mut Obj) {
|
||||
let block = || {
|
||||
let attr = Qstr::from_u16(attr as _);
|
||||
let (x, y) = get_by_name(attr)?;
|
||||
let affine_point: Affine = unwrap!(Option::from(Affine::from_xy(x, y)));
|
||||
let point: Point = affine_point.into();
|
||||
unsafe {
|
||||
if dest.read().is_null() {
|
||||
// Load attribute.
|
||||
dest.write(point.wrap()?);
|
||||
Ok(())
|
||||
} else {
|
||||
// Set attribute.
|
||||
Err(Error::TypeError)
|
||||
}
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_by_name(name: Qstr) -> Result<(Fp, Fp), Error> {
|
||||
match name {
|
||||
Qstr::MP_QSTR_SPENDING_KEY_BASE => Ok((
|
||||
Fp::from_raw([
|
||||
0x8d1a7284b875c963,
|
||||
0xc7f0ce37b70a10c,
|
||||
0x3b8d187c3e5f445f,
|
||||
0x375523b328f1d606,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x4ce33e817b0c3bc9,
|
||||
0xdfc914fec005bdd8,
|
||||
0x7b10bcfcfed624fb,
|
||||
0x1ad0357fdf1a66db,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_NULLIFIER_K_BASE => Ok((
|
||||
Fp::from_raw([
|
||||
0xd36f6aa7e447ca75,
|
||||
0x5e7eb192ccb5db9b,
|
||||
0x2e375571faf4c9cf,
|
||||
0x25e7aa169ca8198d,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x2db8dce21ae001cc,
|
||||
0x5fe0a49ec1c1b433,
|
||||
0x880473442008ff75,
|
||||
0x155c1f851b1a3384,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_VALUE_COMMITMENT_VALUE_BASE => Ok((
|
||||
Fp::from_raw([
|
||||
0x2aa7bd6e3af94367,
|
||||
0xfe04a37f2b5a7c8c,
|
||||
0xf7a86a704f9bb232,
|
||||
0x2f70597a8e3d0f42,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xa413c47eaf5af28e,
|
||||
0x1d9ea766a7ffe3db,
|
||||
0x1e917f63136d6c42,
|
||||
0x2d0e5169311919af,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_VALUE_COMMITMENT_RANDOMNESS_BASE => Ok((
|
||||
Fp::from_raw([
|
||||
0xec3c668883c5a91,
|
||||
0x406ed745ee90802f,
|
||||
0x4f66235bea8d2048,
|
||||
0x7f444550fa409bb,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xe2f46c8a772d9ca,
|
||||
0x279229f1f3928146,
|
||||
0x21562cc9e46fb7c2,
|
||||
0x24136777af26628c,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_NOTE_COMMITMENT_BASE => Ok((
|
||||
Fp::from_raw([
|
||||
0x2c022c480ffc6e13,
|
||||
0x239ec55cfc14a47c,
|
||||
0xcd239fab936f3df2,
|
||||
0x26b206c328a94533,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xc34153c622cf37e3,
|
||||
0x79c7c07823e0dcf6,
|
||||
0xa9541a2f2366e1c6,
|
||||
0x3cde564b686dc04c,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_NOTE_COMMITMENT_Q => Ok((
|
||||
Fp::from_raw([
|
||||
0x320eba0940a8745d,
|
||||
0xc5960f5afd46dd2a,
|
||||
0xf79ff2b479b0ed5d,
|
||||
0x178007a056fbcd0d,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x87270a5a7349ac63,
|
||||
0x8822128881db5e9e,
|
||||
0x4ebec2d96ef4c92c,
|
||||
0x32a058938ac67083,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_IVK_COMMITMENT_BASE => Ok((
|
||||
Fp::from_raw([
|
||||
0x9823486e5ff8a118,
|
||||
0x2957fe2d31aedc7,
|
||||
0x1634290a40808948,
|
||||
0x25a22ccd5070134e,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0x3fe793b3e37fdda9,
|
||||
0x6b4442fb1b58a6c7,
|
||||
0xc2c890c4284b5794,
|
||||
0x29cfd29966a2faeb,
|
||||
]),
|
||||
)),
|
||||
Qstr::MP_QSTR_IVK_COMMITMENT_Q => Ok((
|
||||
Fp::from_raw([
|
||||
0x6bcb2f92790f82f2,
|
||||
0x421bcc245128a232,
|
||||
0x7dcc81b85aa241fa,
|
||||
0x5bc0cf14aa9c811,
|
||||
]),
|
||||
Fp::from_raw([
|
||||
0xbe5ae5cecfaddebe,
|
||||
0x46c4351dc96da5f1,
|
||||
0xef59074620de054b,
|
||||
0x1b014cf6d41abee6,
|
||||
]),
|
||||
)),
|
||||
_ => Err(Error::AttributeError(name)),
|
||||
}
|
||||
}
|
88
core/embed/rust/src/zcash_primitives/pallas/mod.rs
Normal file
88
core/embed/rust/src/zcash_primitives/pallas/mod.rs
Normal file
@ -0,0 +1,88 @@
|
||||
use crate::micropython::{map::Map, module::Module, qstr::Qstr};
|
||||
|
||||
pub mod common;
|
||||
mod fp;
|
||||
mod generators;
|
||||
mod point;
|
||||
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:
|
||||
/// ...
|
||||
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:
|
||||
/// ...
|
||||
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:
|
||||
/// ...
|
||||
Qstr::MP_QSTR_group_hash => obj_fn_2!(point::group_hash).as_obj(),
|
||||
/// def scalar_from_i64(x: int) -> Scalar:
|
||||
/// """Converts integer to Scalar."""
|
||||
Qstr::MP_QSTR_scalar_from_i64 => obj_fn_1!(scalar::scalar_from_i64).as_obj(),
|
||||
/// class Fp:
|
||||
/// """Pallas base field."""
|
||||
///
|
||||
/// def __init__(self, repr: bytes) -> None:
|
||||
/// ...
|
||||
///
|
||||
/// def to_bytes(self) -> bytes:
|
||||
/// ...
|
||||
Qstr::MP_QSTR_Fp => (&fp::FP_TYPE).as_obj(),
|
||||
/// class Scalar:
|
||||
/// """Pallas scalar field."""
|
||||
///
|
||||
/// def __init__(self, repr: bytes) -> None:
|
||||
/// ...
|
||||
///
|
||||
/// def to_bytes(self) -> bytes:
|
||||
/// ...
|
||||
///
|
||||
/// def __mul__(self, other: Point) -> Point:
|
||||
/// ...
|
||||
///
|
||||
/// def __add__(self, other: Scalar) -> Scalar:
|
||||
/// ...
|
||||
///
|
||||
/// def __neg__(self) -> Point:
|
||||
/// ...
|
||||
///
|
||||
/// def __bool__(self) -> bool:
|
||||
/// ...
|
||||
Qstr::MP_QSTR_Scalar => (&scalar::SCALAR_TYPE).as_obj(),
|
||||
/// class Point:
|
||||
/// """Pallas point."""
|
||||
///
|
||||
/// def __init__(self, repr: bytes) -> None:
|
||||
/// ...
|
||||
///
|
||||
/// def to_bytes(self) -> bytes:
|
||||
/// ...
|
||||
///
|
||||
/// def extract(self) -> Fp:
|
||||
/// ...
|
||||
///
|
||||
/// def is_identity(self) -> bool:
|
||||
/// ...
|
||||
///
|
||||
/// def __add__(self, other: Point) -> Point:
|
||||
/// ...
|
||||
///
|
||||
/// def __neg__(self) -> Point:
|
||||
/// ...
|
||||
Qstr::MP_QSTR_Point => (&point::POINT_TYPE).as_obj(),
|
||||
/// class generators:
|
||||
/// SPENDING_KEY_BASE: Point
|
||||
/// NULLIFIER_K_BASE: Point
|
||||
/// VALUE_COMMITMENT_VALUE_BASE: Point
|
||||
/// VALUE_COMMITMENT_RANDOMNESS_BASE: Point
|
||||
/// NOTE_COMMITMENT_BASE: Point
|
||||
/// NOTE_COMMITMENT_Q: Point
|
||||
/// IVK_COMMITMENT_BASE: Point
|
||||
/// IVK_COMMITMENT_Q: Point
|
||||
Qstr::MP_QSTR_generators => (&generators::GENERATORS_TYPE).as_obj(),
|
||||
};
|
143
core/embed/rust/src/zcash_primitives/pallas/point.rs
Normal file
143
core/embed/rust/src/zcash_primitives/pallas/point.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use core::ops::Deref;
|
||||
use cstr_core::cstr;
|
||||
use pasta_curves::{
|
||||
arithmetic::{CurveAffine, CurveExt},
|
||||
group::{Curve, Group, GroupEncoding},
|
||||
pallas::Point,
|
||||
Fp,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
micropython::{
|
||||
buffer::{Buffer, StrBuffer},
|
||||
ffi,
|
||||
gc::Gc,
|
||||
map::Map,
|
||||
obj::Obj,
|
||||
qstr::Qstr,
|
||||
typ::Type,
|
||||
util,
|
||||
wrap::{Wrappable, Wrapped},
|
||||
},
|
||||
};
|
||||
|
||||
pub static POINT_TYPE: Type = obj_type! {
|
||||
name: Qstr::MP_QSTR_Point,
|
||||
locals: &obj_dict!(obj_map! {
|
||||
Qstr::MP_QSTR_extract => obj_fn_1!(point_extract).as_obj(),
|
||||
Qstr::MP_QSTR_to_bytes => obj_fn_1!(point_to_bytes).as_obj(),
|
||||
Qstr::MP_QSTR_is_identity => obj_fn_1!(point_is_identity).as_obj(),
|
||||
}),
|
||||
make_new_fn: point_from_bytes,
|
||||
unary_op_fn: point_unary_op,
|
||||
binary_op_fn: point_binary_op,
|
||||
};
|
||||
|
||||
impl Wrappable for Point {
|
||||
fn obj_type() -> &'static Type {
|
||||
&POINT_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn point_from_bytes(
|
||||
_type_: *const Type,
|
||||
n_args: usize,
|
||||
n_kw: usize,
|
||||
args: *const Obj,
|
||||
) -> Obj {
|
||||
let block = |args: &[Obj], _kwargs: &Map| {
|
||||
if args.len() != 1 {
|
||||
return Err(Error::TypeError);
|
||||
}
|
||||
let bytes: [u8; 32] = args[0].try_into()?;
|
||||
let point = Point::from_bytes(&bytes);
|
||||
match Option::<Point>::from(point) {
|
||||
Some(p) => p.wrap(),
|
||||
None => Err(Error::ValueError(cstr!("Conversion failed"))),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_with_args_and_kwargs_inline(n_args, n_kw, args, block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn point_unary_op(op: ffi::mp_unary_op_t, this: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Point>>::try_from(this)?;
|
||||
let this = this.deref().inner();
|
||||
match op {
|
||||
ffi::mp_unary_op_t_MP_UNARY_OP_NEGATIVE => (-this).wrap(),
|
||||
_ => Ok(Obj::const_null()),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn point_binary_op(op: ffi::mp_binary_op_t, this: Obj, other: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Point>>::try_from(this)?;
|
||||
let this = this.deref().inner();
|
||||
match op {
|
||||
ffi::mp_binary_op_t_MP_BINARY_OP_ADD => {
|
||||
let other = Gc::<Wrapped<Point>>::try_from(other)?;
|
||||
let other = other.deref().inner();
|
||||
(this + other).wrap()
|
||||
}
|
||||
ffi::mp_binary_op_t_MP_BINARY_OP_EQUAL => {
|
||||
let other = Gc::<Wrapped<Point>>::try_from(other)?;
|
||||
let other = other.deref().inner();
|
||||
Ok((this == other).into())
|
||||
}
|
||||
ffi::mp_binary_op_t_MP_BINARY_OP_NOT_EQUAL => {
|
||||
let other = Gc::<Wrapped<Point>>::try_from(other)?;
|
||||
let other = other.deref().inner();
|
||||
Ok((this != other).into())
|
||||
}
|
||||
_ => Ok(Obj::const_null()),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn point_extract(self_in: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Point>>::try_from(self_in)?;
|
||||
let elem = this
|
||||
.deref()
|
||||
.inner()
|
||||
.to_affine()
|
||||
.coordinates()
|
||||
.map(|c| *c.x())
|
||||
.unwrap_or_else(Fp::zero);
|
||||
elem.wrap()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn point_is_identity(self_in: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Point>>::try_from(self_in)?;
|
||||
let this = this.deref().inner();
|
||||
Ok((this == &Point::identity()).into())
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn point_to_bytes(self_in: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Point>>::try_from(self_in)?;
|
||||
let bytes: [u8; 32] = this.deref().inner().to_bytes();
|
||||
bytes.try_into()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn group_hash(domain: Obj, message: Obj) -> Obj {
|
||||
let block = || {
|
||||
let domain: StrBuffer = domain.try_into()?;
|
||||
let message: Buffer = message.try_into()?;
|
||||
let point = Point::hash_to_curve(domain.deref(), message.deref());
|
||||
point.wrap()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
100
core/embed/rust/src/zcash_primitives/pallas/scalar.rs
Normal file
100
core/embed/rust/src/zcash_primitives/pallas/scalar.rs
Normal file
@ -0,0 +1,100 @@
|
||||
use core::ops::Deref;
|
||||
|
||||
use pasta_curves::{
|
||||
arithmetic::FieldExt,
|
||||
group::ff::{Field, PrimeField},
|
||||
pallas::{Point, Scalar},
|
||||
};
|
||||
|
||||
use crate::micropython::{
|
||||
ffi,
|
||||
gc::Gc,
|
||||
map::Map,
|
||||
obj::Obj,
|
||||
qstr::Qstr,
|
||||
typ::Type,
|
||||
util,
|
||||
wrap::{Wrappable, Wrapped},
|
||||
};
|
||||
|
||||
pub static SCALAR_TYPE: Type = obj_type! {
|
||||
name: Qstr::MP_QSTR_Scalar,
|
||||
locals: &obj_dict!(obj_map! {
|
||||
Qstr::MP_QSTR_to_bytes => obj_fn_1!(scalar_to_bytes).as_obj(),
|
||||
}),
|
||||
make_new_fn: super::common::ff_from_bytes::<Scalar>,
|
||||
unary_op_fn: scalar_unary_op,
|
||||
binary_op_fn: scalar_binary_op,
|
||||
};
|
||||
|
||||
impl Wrappable for Scalar {
|
||||
fn obj_type() -> &'static Type {
|
||||
&SCALAR_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn scalar_binary_op(op: ffi::mp_binary_op_t, this: Obj, other: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Scalar>>::try_from(this)?;
|
||||
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()
|
||||
}
|
||||
ffi::mp_binary_op_t_MP_BINARY_OP_ADD => {
|
||||
let other = Gc::<Wrapped<Scalar>>::try_from(other)?;
|
||||
let other = other.deref().inner();
|
||||
(other + this).wrap()
|
||||
}
|
||||
_ => Ok(Obj::const_null()),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn scalar_unary_op(op: ffi::mp_unary_op_t, this: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Scalar>>::try_from(this)?;
|
||||
let this = this.deref().inner();
|
||||
match op {
|
||||
ffi::mp_unary_op_t_MP_UNARY_OP_NEGATIVE => (-this).wrap(),
|
||||
ffi::mp_unary_op_t_MP_UNARY_OP_BOOL => Ok(bool::from(!this.is_zero()).into()),
|
||||
_ => Ok(Obj::const_null()),
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn scalar_to_bytes(self_in: Obj) -> Obj {
|
||||
let block = || {
|
||||
let this = Gc::<Wrapped<Scalar>>::try_from(self_in)?;
|
||||
let bytes: [u8; 32] = this.deref().inner().to_repr();
|
||||
bytes.try_into()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn to_scalar(bytes: Obj) -> Obj {
|
||||
let block = || {
|
||||
let bytes: [u8; 64] = bytes.try_into()?;
|
||||
let elem = Scalar::from_bytes_wide(&bytes);
|
||||
elem.wrap()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn scalar_from_i64(n: Obj) -> Obj {
|
||||
let block = || {
|
||||
let n: i64 = n.try_into()?;
|
||||
if n >= 0 {
|
||||
Scalar::from(n as u64).wrap()
|
||||
} else {
|
||||
(-Scalar::from(-n as u64)).wrap()
|
||||
}
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
1350
core/embed/rust/src/zcash_primitives/poseidon/constants.rs
Normal file
1350
core/embed/rust/src/zcash_primitives/poseidon/constants.rs
Normal file
File diff suppressed because it is too large
Load Diff
113
core/embed/rust/src/zcash_primitives/poseidon/constants_gen.rs
Normal file
113
core/embed/rust/src/zcash_primitives/poseidon/constants_gen.rs
Normal file
@ -0,0 +1,113 @@
|
||||
//! Generates Poseidon round constants according to apendix F of article
|
||||
//!
|
||||
//! POSEIDON: A New Hash Function for Zero-Knowledge Proof Systems
|
||||
//! <https://eprint.iacr.org/2019/458>
|
||||
//!
|
||||
//! for paraments defined in
|
||||
//! <https://zips.z.cash/protocol/protocol.pdf#poseidonhash>
|
||||
|
||||
use core::cmp::Ordering;
|
||||
use pasta_curves::Fp;
|
||||
|
||||
/// Size of Pallas base field in little-endian
|
||||
const MODULUS: [u64; 4] = [
|
||||
0x992d30ed00000001,
|
||||
0x224698fc094cf91b,
|
||||
0x0000000000000000,
|
||||
0x4000000000000000,
|
||||
];
|
||||
|
||||
fn is_less_then_modulus(number: &[u64; 4]) -> bool {
|
||||
for i in (0..4).rev() {
|
||||
match number[i].cmp(&MODULUS[i]) {
|
||||
Ordering::Less => return true,
|
||||
Ordering::Greater => return false,
|
||||
Ordering::Equal => continue,
|
||||
};
|
||||
}
|
||||
false // numbers are equal
|
||||
}
|
||||
|
||||
// the newest bit is the lowest bit of `reg0`
|
||||
// the oldest bit is the highest bit of `reg2`
|
||||
pub struct ConstantsGenerator {
|
||||
reg0: u32,
|
||||
reg1: u32,
|
||||
reg2: u16,
|
||||
}
|
||||
|
||||
impl ConstantsGenerator {
|
||||
pub fn new() -> Self {
|
||||
// LSFR state is precomputed as follows:
|
||||
// 1. initialize LSFR according to the step 1
|
||||
// with parameters from the Zcash protocol paper §5.4.1.10
|
||||
// 2. drop first 160 bits according to the step 3
|
||||
// 3. convert the LSFR state from Fibonacci representation to Galois repr.
|
||||
ConstantsGenerator {
|
||||
reg0: 0x7858ff5e,
|
||||
reg1: 0xb8da546e,
|
||||
reg2: 0xfbfe,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns next LSFR bit
|
||||
fn next_bit(&mut self) -> u8 {
|
||||
// pop the oldest bit
|
||||
let new_bit = (self.reg2 >> 15) as u8;
|
||||
// shift register
|
||||
self.reg2 = (self.reg2 << 1) | (self.reg1 >> 31) as u16;
|
||||
self.reg1 = (self.reg1 << 1) | (self.reg0 >> 31);
|
||||
self.reg0 <<= 1;
|
||||
// add feedback
|
||||
if new_bit == 1 {
|
||||
// s_80 = s_62 + s_51 + s_38 + s_23 + s_13 + s_0
|
||||
self.reg0 ^= 0b00000000100000000010000000000001;
|
||||
self.reg1 ^= 0b01000000000010000000000001000000;
|
||||
}
|
||||
new_bit
|
||||
}
|
||||
|
||||
/// Filter bits according to the step 4
|
||||
fn next_filtered_bit(&mut self) -> u8 {
|
||||
loop {
|
||||
let b1 = self.next_bit();
|
||||
let b2 = self.next_bit();
|
||||
if b1 == 1 {
|
||||
break b2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next_digit(&mut self, n: usize) -> u64 {
|
||||
(0..n).fold(0u64, |acc, _| (acc << 1) + self.next_filtered_bit() as u64)
|
||||
}
|
||||
|
||||
fn next_field_element(&mut self) -> Fp {
|
||||
loop {
|
||||
// sample the number in the big-endian
|
||||
let mut digits = [
|
||||
self.next_digit(63),
|
||||
self.next_digit(64),
|
||||
self.next_digit(64),
|
||||
self.next_digit(64),
|
||||
];
|
||||
// then convert it to the little-endian
|
||||
digits.reverse();
|
||||
if is_less_then_modulus(&digits) {
|
||||
break Fp::from_raw(digits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ConstantsGenerator {
|
||||
type Item = [Fp; 3];
|
||||
|
||||
fn next(&mut self) -> Option<[Fp; 3]> {
|
||||
Some([
|
||||
self.next_field_element(),
|
||||
self.next_field_element(),
|
||||
self.next_field_element(),
|
||||
])
|
||||
}
|
||||
}
|
109
core/embed/rust/src/zcash_primitives/poseidon/mod.rs
Normal file
109
core/embed/rust/src/zcash_primitives/poseidon/mod.rs
Normal file
@ -0,0 +1,109 @@
|
||||
//! The Poseidon permutation lightweight implementation
|
||||
//! Poseidon specification: https://eprint.iacr.org/2019/458
|
||||
//! Orchard instantiation: https://zips.z.cash/protocol/protocol.pdf#poseidonhash
|
||||
|
||||
use core::{iter, ops::Deref};
|
||||
|
||||
use crate::micropython::{
|
||||
gc::Gc,
|
||||
map::Map,
|
||||
module::Module,
|
||||
obj::Obj,
|
||||
qstr::Qstr,
|
||||
util,
|
||||
wrap::{Wrappable, Wrapped},
|
||||
};
|
||||
use constants::MDS;
|
||||
use pasta_curves::{arithmetic::FieldExt, group::ff::Field, Fp};
|
||||
|
||||
mod constants;
|
||||
mod constants_gen;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
use constants_gen::ConstantsGenerator;
|
||||
|
||||
/// The type used to hold permutation state.
|
||||
type State = [Fp; 3];
|
||||
|
||||
#[inline]
|
||||
fn sbox(x: Fp) -> Fp {
|
||||
x.pow_vartime(&[5])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn full_round_sbox_layer(state: &mut State) {
|
||||
state[0] = sbox(state[0]);
|
||||
state[1] = sbox(state[1]);
|
||||
state[2] = sbox(state[2]);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn half_round_sbox_layer(state: &mut State) {
|
||||
state[0] = sbox(state[0]);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_round_constants(state: &mut State, rcs: &State) {
|
||||
state[0] += rcs[0];
|
||||
state[1] += rcs[1];
|
||||
state[2] += rcs[2];
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn apply_mds(state: &mut State) {
|
||||
let mut new_state = [Fp::zero(); 3];
|
||||
for i in 0..3 {
|
||||
for j in 0..3 {
|
||||
new_state[i] += MDS[i][j] * state[j];
|
||||
}
|
||||
}
|
||||
*state = new_state;
|
||||
}
|
||||
|
||||
/// Runs the Poseidon permutation on the given state.
|
||||
pub(crate) fn permute(state: &mut State) {
|
||||
let rounds = iter::empty()
|
||||
.chain(iter::repeat(true).take(4))
|
||||
.chain(iter::repeat(false).take(56))
|
||||
.chain(iter::repeat(true).take(4));
|
||||
|
||||
let round_constants = ConstantsGenerator::new();
|
||||
|
||||
for (is_full_round, rcs) in rounds.zip(round_constants) {
|
||||
add_round_constants(state, &rcs);
|
||||
if is_full_round {
|
||||
full_round_sbox_layer(state);
|
||||
} else {
|
||||
half_round_sbox_layer(state);
|
||||
}
|
||||
apply_mds(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// Poseidon hash
|
||||
pub fn hash(x: Fp, y: Fp) -> Fp {
|
||||
let mut state = [x, y, Fp::from_u128((2 as u128) << 64)];
|
||||
permute(&mut state);
|
||||
state[0]
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn poseidon_wrapper(nk: Obj, rho: Obj) -> Obj {
|
||||
let block = || {
|
||||
let nk: Gc<Wrapped<Fp>> = nk.try_into()?;
|
||||
let nk: Fp = nk.deref().inner().clone();
|
||||
let rho: Gc<Wrapped<Fp>> = rho.try_into()?;
|
||||
let rho: Fp = rho.deref().inner().clone();
|
||||
|
||||
hash(nk, rho).wrap()
|
||||
};
|
||||
unsafe { util::try_or_raise(block) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub static mp_module_trezorposeidon: Module = obj_module! {
|
||||
Qstr::MP_QSTR___name__ => Qstr::MP_QSTR_trezorposeidon.to_obj(),
|
||||
/// def poseidon(x: Fp, y: Fp) -> Fp:
|
||||
/// """Poseidon hash function."""
|
||||
Qstr::MP_QSTR_poseidon => obj_fn_2!(poseidon_wrapper).as_obj(),
|
||||
};
|
662
core/embed/rust/src/zcash_primitives/poseidon/tests.rs
Normal file
662
core/embed/rust/src/zcash_primitives/poseidon/tests.rs
Normal file
@ -0,0 +1,662 @@
|
||||
//! Test vectors for `OrchardNullifier`.
|
||||
|
||||
use super::*;
|
||||
use pasta_curves::group::ff::PrimeField;
|
||||
|
||||
#[test]
|
||||
fn permute_test_vectors() {
|
||||
for tv in PERMUTE_TEST_VECTORS.iter() {
|
||||
let mut state = [
|
||||
Fp::from_repr(tv.initial_state[0]).unwrap(),
|
||||
Fp::from_repr(tv.initial_state[1]).unwrap(),
|
||||
Fp::from_repr(tv.initial_state[2]).unwrap(),
|
||||
];
|
||||
|
||||
permute(&mut state);
|
||||
|
||||
for (expected, actual) in tv.final_state.iter().zip(state.iter()) {
|
||||
assert_eq!(&actual.to_repr(), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_test_vectors() {
|
||||
for tv in HASH_TEST_VECTORS.iter() {
|
||||
let x = Fp::from_repr(tv.input[0]).unwrap();
|
||||
let y = Fp::from_repr(tv.input[1]).unwrap();
|
||||
|
||||
let result = hash(x, y);
|
||||
|
||||
assert_eq!(result.to_repr(), tv.output);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constants_generator() {
|
||||
let gen = constants_gen::ConstantsGenerator::new();
|
||||
for (a, b) in constants::ROUND_CONSTANTS.into_iter().zip(gen) {
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PermuteTestVector {
|
||||
pub(crate) initial_state: [[u8; 32]; 3],
|
||||
pub(crate) final_state: [[u8; 32]; 3],
|
||||
}
|
||||
|
||||
pub(crate) struct HashTestVector {
|
||||
pub(crate) input: [[u8; 32]; 2],
|
||||
pub(crate) output: [u8; 32],
|
||||
}
|
||||
|
||||
pub(crate) static PERMUTE_TEST_VECTORS: [PermuteTestVector; 11] = [
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
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,
|
||||
],
|
||||
[
|
||||
0x01, 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,
|
||||
],
|
||||
[
|
||||
0x02, 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,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x56, 0xa4, 0xec, 0x4a, 0x02, 0xbc, 0xb1, 0xae, 0xa0, 0x42, 0xb6, 0xd0, 0x71, 0x9a,
|
||||
0xe6, 0xf7, 0x0f, 0x24, 0x66, 0xf9, 0x64, 0xb3, 0xef, 0x94, 0x53, 0xb4, 0x64, 0x0b,
|
||||
0xcd, 0x6a, 0x52, 0x2a,
|
||||
],
|
||||
[
|
||||
0x2a, 0xb8, 0xe5, 0x28, 0x96, 0x3e, 0x2a, 0x01, 0xfe, 0xda, 0xd9, 0xbe, 0x7f, 0x2e,
|
||||
0xd4, 0xdc, 0x12, 0x55, 0x3d, 0x34, 0xae, 0x7d, 0xff, 0x76, 0x30, 0xa4, 0x4a, 0x8b,
|
||||
0x56, 0xd1, 0xc5, 0x13,
|
||||
],
|
||||
[
|
||||
0xdd, 0x9d, 0x4e, 0xd3, 0xa1, 0x29, 0x90, 0x35, 0x7b, 0x2c, 0xa4, 0xbd, 0xe1, 0xdf,
|
||||
0xcf, 0xf7, 0x1a, 0x56, 0x84, 0x79, 0x59, 0xcd, 0x6f, 0x25, 0x44, 0x65, 0x97, 0xc6,
|
||||
0x68, 0xc8, 0x49, 0x0a,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, 0xac, 0x6b,
|
||||
0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, 0xaf, 0xfa, 0x2e, 0xf6,
|
||||
0xee, 0x69, 0x21, 0x08,
|
||||
],
|
||||
[
|
||||
0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, 0x98, 0x2b,
|
||||
0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, 0xb3, 0x53, 0x42, 0x01,
|
||||
0xcf, 0xb1, 0xcd, 0x0d,
|
||||
],
|
||||
[
|
||||
0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, 0x9b, 0xa9,
|
||||
0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, 0x4e,
|
||||
0x30, 0xa7, 0x35, 0x14,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0xd0, 0x6e, 0x2f, 0x83, 0x38, 0x92, 0x8a, 0x7e, 0xe7, 0x38, 0x0c, 0x77, 0x92, 0x80,
|
||||
0x87, 0xcd, 0xa2, 0xfd, 0x29, 0x61, 0xa1, 0x52, 0x69, 0x03, 0x7a, 0x22, 0xd6, 0xd1,
|
||||
0x20, 0xae, 0xdd, 0x21,
|
||||
],
|
||||
[
|
||||
0x29, 0x55, 0xa4, 0x5f, 0x41, 0x6f, 0x10, 0xd6, 0xbc, 0x79, 0xac, 0x94, 0xd0, 0xc0,
|
||||
0x69, 0xc9, 0x49, 0xe5, 0xf4, 0xbd, 0x09, 0x48, 0x1e, 0x1f, 0x36, 0x8c, 0xb9, 0xb8,
|
||||
0xee, 0x51, 0x14, 0x0d,
|
||||
],
|
||||
[
|
||||
0x0d, 0x83, 0x76, 0xbb, 0xe9, 0xd6, 0x5d, 0x2b, 0x1e, 0x13, 0x6f, 0xb7, 0xd9, 0x82,
|
||||
0xab, 0x87, 0xc5, 0x1c, 0x40, 0x30, 0x44, 0xbe, 0x5c, 0x79, 0x9d, 0x56, 0xbb, 0x68,
|
||||
0xac, 0xf9, 0x5b, 0x10,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, 0xed, 0x5a,
|
||||
0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, 0x4b, 0x69, 0x68, 0x91,
|
||||
0x2a, 0x63, 0x81, 0x0e,
|
||||
],
|
||||
[
|
||||
0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd,
|
||||
0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, 0x77, 0x08, 0x37, 0x56,
|
||||
0xd5, 0x9a, 0xf8, 0x0d,
|
||||
],
|
||||
[
|
||||
0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, 0xf0, 0xf0,
|
||||
0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, 0xe4, 0xe4, 0xc7, 0x63,
|
||||
0xcc, 0xb8, 0xf6, 0x36,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x0b, 0x77, 0xec, 0x53, 0x07, 0x14, 0x5a, 0x0c, 0x05, 0x2d, 0xc7, 0xa9, 0xd6, 0xf9,
|
||||
0x6a, 0xc3, 0x41, 0xae, 0x72, 0x64, 0x08, 0x32, 0xd5, 0x8e, 0x51, 0xeb, 0x92, 0xa4,
|
||||
0x17, 0x80, 0x17, 0x12,
|
||||
],
|
||||
[
|
||||
0x3b, 0x52, 0x3f, 0x44, 0xf0, 0x0e, 0x46, 0x3f, 0x8b, 0x0f, 0xd7, 0xd4, 0xfc, 0x0e,
|
||||
0x28, 0x0c, 0xdb, 0xde, 0xb9, 0x27, 0xf1, 0x81, 0x68, 0x07, 0x7b, 0xb3, 0x62, 0xf2,
|
||||
0x67, 0x5a, 0x2e, 0x18,
|
||||
],
|
||||
[
|
||||
0x95, 0x7a, 0x97, 0x06, 0xff, 0xcc, 0x35, 0x15, 0x64, 0xae, 0x80, 0x2a, 0x99, 0x11,
|
||||
0x31, 0x4c, 0x05, 0xe2, 0x3e, 0x22, 0xaf, 0xcf, 0x83, 0x40, 0x59, 0xdf, 0x80, 0xfa,
|
||||
0xc1, 0x05, 0x76, 0x26,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, 0x57, 0xef,
|
||||
0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, 0x1a, 0x38, 0xe0, 0x1d,
|
||||
0x94, 0x90, 0x3d, 0x3c,
|
||||
],
|
||||
[
|
||||
0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, 0x42, 0x98,
|
||||
0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b,
|
||||
0xe3, 0x4a, 0x98, 0x11,
|
||||
],
|
||||
[
|
||||
0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, 0x88, 0x39,
|
||||
0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d,
|
||||
0x32, 0x0d, 0xad, 0x16,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x67, 0x80, 0x08, 0x3f, 0x7f, 0x82, 0xcb, 0x42, 0x54, 0xe7, 0xb6, 0x6f, 0x4b, 0x83,
|
||||
0x84, 0x6a, 0xc9, 0x77, 0x3f, 0xb9, 0xc3, 0x9c, 0x6e, 0xc9, 0x81, 0x8b, 0x06, 0x22,
|
||||
0x23, 0x09, 0x55, 0x2a,
|
||||
],
|
||||
[
|
||||
0xa5, 0xf9, 0xa5, 0x7e, 0x2c, 0x40, 0xb1, 0x58, 0xd8, 0x16, 0x53, 0x43, 0xe6, 0x02,
|
||||
0x65, 0x2c, 0x3e, 0xfc, 0x0b, 0x64, 0xdd, 0xca, 0xee, 0xe5, 0xce, 0x3d, 0x95, 0x1f,
|
||||
0xd5, 0x9f, 0x50, 0x08,
|
||||
],
|
||||
[
|
||||
0xdc, 0xa4, 0x64, 0x36, 0x12, 0x7c, 0x47, 0x7e, 0x83, 0x95, 0x0f, 0xa0, 0x7c, 0xc6,
|
||||
0x8a, 0x56, 0x6e, 0x54, 0x18, 0x55, 0xad, 0xc2, 0x68, 0x52, 0x97, 0x87, 0x35, 0x24,
|
||||
0x88, 0x92, 0x1e, 0x3b,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, 0x34, 0x5b,
|
||||
0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, 0x76, 0xd3, 0x8d,
|
||||
0x47, 0xf1, 0xe1, 0x11,
|
||||
],
|
||||
[
|
||||
0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, 0x3f, 0xde,
|
||||
0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda,
|
||||
0xe6, 0x9c, 0xe8, 0x3c,
|
||||
],
|
||||
[
|
||||
0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, 0x20, 0x53,
|
||||
0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8,
|
||||
0xf7, 0x39, 0x3c, 0x14,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x89, 0x99, 0x8e, 0x5e, 0x0f, 0xa1, 0x95, 0x2a, 0x40, 0xb8, 0xb5, 0x2b, 0x62, 0xd9,
|
||||
0x45, 0x70, 0xa4, 0x9a, 0x7d, 0x91, 0xdd, 0x22, 0x6d, 0x69, 0x2b, 0xc9, 0xb1, 0xa6,
|
||||
0x13, 0xc9, 0x08, 0x30,
|
||||
],
|
||||
[
|
||||
0xd0, 0xee, 0x44, 0xd9, 0xa9, 0x0d, 0x90, 0x79, 0xef, 0xfb, 0x24, 0x86, 0xd3, 0xd8,
|
||||
0x4d, 0x1a, 0x18, 0x4e, 0xdf, 0x14, 0x97, 0x0b, 0xac, 0x36, 0xc7, 0x48, 0x04, 0xc7,
|
||||
0xff, 0xbe, 0xe5, 0x0b,
|
||||
],
|
||||
[
|
||||
0x04, 0x81, 0x45, 0xa6, 0x61, 0xce, 0x78, 0x7c, 0x7e, 0x12, 0x2a, 0xc6, 0x44, 0x7e,
|
||||
0x9b, 0xa3, 0x93, 0xd3, 0x67, 0xac, 0x05, 0x4f, 0xaa, 0xc5, 0xb7, 0xb5, 0xf7, 0x19,
|
||||
0x2b, 0x2f, 0xde, 0x21,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, 0x0f,
|
||||
0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, 0x73,
|
||||
0xf4, 0x68, 0xa0, 0x08,
|
||||
],
|
||||
[
|
||||
0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, 0xae, 0x25,
|
||||
0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, 0x88, 0x2d, 0x2b, 0x21,
|
||||
0x03, 0x59, 0x65, 0x15,
|
||||
],
|
||||
[
|
||||
0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, 0x91, 0xf4,
|
||||
0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d,
|
||||
0x99, 0x58, 0x9c, 0x0b,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0xce, 0x2d, 0x1f, 0x8d, 0x67, 0x7f, 0xfb, 0xfd, 0x73, 0xb2, 0x35, 0xe8, 0xc6, 0x87,
|
||||
0xfb, 0x42, 0x18, 0x7f, 0x78, 0x81, 0xc3, 0xce, 0x9c, 0x79, 0x4f, 0x2b, 0xd4, 0x61,
|
||||
0x40, 0xf7, 0xcc, 0x2a,
|
||||
],
|
||||
[
|
||||
0xaf, 0x82, 0x92, 0x39, 0xb6, 0xd5, 0x5d, 0x5f, 0x43, 0xec, 0x6f, 0x32, 0xb8, 0x4a,
|
||||
0x2a, 0x01, 0x1e, 0x64, 0xc5, 0x74, 0x73, 0x9f, 0x87, 0xcb, 0x47, 0xdc, 0x70, 0x23,
|
||||
0x83, 0xfa, 0x5a, 0x34,
|
||||
],
|
||||
[
|
||||
0x03, 0xd1, 0x08, 0x5b, 0x21, 0x4c, 0x69, 0xb8, 0xbf, 0xe8, 0x91, 0x02, 0xbd, 0x61,
|
||||
0x7e, 0xce, 0x0c, 0x54, 0x00, 0x17, 0x96, 0x40, 0x41, 0x05, 0xc5, 0x33, 0x30, 0xd2,
|
||||
0x49, 0x58, 0x1d, 0x0f,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, 0x20, 0x37,
|
||||
0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d,
|
||||
0xed, 0x42, 0x43, 0x1e,
|
||||
],
|
||||
[
|
||||
0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, 0x53, 0xd9,
|
||||
0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75, 0xa4, 0xa6,
|
||||
0xf2, 0x65, 0x72, 0x10,
|
||||
],
|
||||
[
|
||||
0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96, 0xbc,
|
||||
0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7,
|
||||
0x1a, 0x02, 0xaf, 0x11,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x5f, 0xcc, 0xd8, 0x7d, 0x2f, 0x66, 0x7b, 0x9e, 0xe3, 0x88, 0xf3, 0x4c, 0x1c, 0x71,
|
||||
0x06, 0x87, 0x12, 0x7b, 0xff, 0x5b, 0x02, 0x21, 0xfd, 0x8a, 0x52, 0x94, 0x88, 0x66,
|
||||
0x91, 0x57, 0x94, 0x2b,
|
||||
],
|
||||
[
|
||||
0x89, 0x62, 0xb5, 0x80, 0x30, 0xaa, 0x63, 0x52, 0xd9, 0x90, 0xf3, 0xb9, 0x00, 0x1c,
|
||||
0xcb, 0xe8, 0x8a, 0x56, 0x27, 0x58, 0x1b, 0xbf, 0xb9, 0x01, 0xac, 0x4a, 0x6a, 0xed,
|
||||
0xfa, 0xe5, 0xc6, 0x34,
|
||||
],
|
||||
[
|
||||
0x7c, 0x0b, 0x76, 0x59, 0xf2, 0x4c, 0x98, 0xaf, 0x31, 0x0e, 0x3e, 0x8d, 0x82, 0xb5,
|
||||
0xf3, 0x99, 0x43, 0x3c, 0xdd, 0xa5, 0x8f, 0x48, 0xd9, 0xef, 0x8d, 0xd0, 0xca, 0x86,
|
||||
0x42, 0x72, 0xda, 0x3f,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, 0x6f, 0x1e,
|
||||
0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee,
|
||||
0xcc, 0x40, 0xa9, 0x0d,
|
||||
],
|
||||
[
|
||||
0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, 0x61, 0xae,
|
||||
0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, 0xb7, 0xfa,
|
||||
0xe2, 0xdb, 0x58, 0x31,
|
||||
],
|
||||
[
|
||||
0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, 0xc1, 0x29,
|
||||
0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, 0xce, 0xcb, 0x8c, 0xb8,
|
||||
0xa5, 0xda, 0x01, 0x30,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x9e, 0xe1, 0xad, 0xdc, 0x6f, 0x64, 0xda, 0xb6, 0xac, 0xdc, 0xea, 0xec, 0xc1, 0xfb,
|
||||
0xbc, 0x8a, 0x32, 0x45, 0x8e, 0x49, 0xc1, 0x9e, 0x79, 0x85, 0x56, 0xc6, 0x4b, 0x59,
|
||||
0x8b, 0xa6, 0xff, 0x14,
|
||||
],
|
||||
[
|
||||
0x42, 0xcc, 0x10, 0x36, 0x4f, 0xd6, 0x59, 0xc3, 0xcc, 0x77, 0x25, 0x84, 0xdb, 0x91,
|
||||
0xc4, 0x9a, 0x38, 0x67, 0x2b, 0x69, 0x24, 0x93, 0xb9, 0x07, 0x5f, 0x16, 0x53, 0xca,
|
||||
0x1f, 0xae, 0x1c, 0x33,
|
||||
],
|
||||
[
|
||||
0xff, 0x41, 0xf3, 0x51, 0x80, 0x14, 0x56, 0xc4, 0x96, 0x0b, 0x39, 0x3a, 0xff, 0xa8,
|
||||
0x62, 0x13, 0xa7, 0xea, 0xc0, 0x6c, 0x66, 0x21, 0x3b, 0x45, 0xc3, 0xb5, 0x0e, 0xc6,
|
||||
0x48, 0xd6, 0x7d, 0x0d,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x71, 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, 0xd3, 0x90,
|
||||
0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, 0x4f, 0x5a, 0x53, 0x41,
|
||||
0xec, 0x5d, 0xd7, 0x15,
|
||||
],
|
||||
[
|
||||
0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, 0x21, 0x86,
|
||||
0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, 0x58, 0xcf, 0xb5, 0xcd,
|
||||
0x79, 0xf8, 0x80, 0x08,
|
||||
],
|
||||
[
|
||||
0xe2, 0x15, 0xdc, 0x7d, 0x96, 0x57, 0xba, 0xd3, 0xfb, 0x88, 0xb0, 0x1e, 0x99, 0x38,
|
||||
0x44, 0x54, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, 0x48, 0x9c, 0xe7, 0x57,
|
||||
0x45, 0x82, 0x4b, 0x37,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x63, 0x09, 0x15, 0xd7, 0xd8, 0x25, 0xeb, 0x74, 0x37, 0xb0, 0xe4, 0x6e, 0x37, 0x28,
|
||||
0x6a, 0x88, 0xb3, 0x89, 0xdc, 0x69, 0x85, 0x93, 0x07, 0x11, 0x6d, 0x34, 0x7b, 0x98,
|
||||
0xca, 0x14, 0x5c, 0x31,
|
||||
],
|
||||
[
|
||||
0xaa, 0x58, 0x1b, 0xae, 0xe9, 0x4f, 0xb5, 0x46, 0xa7, 0x61, 0xf1, 0x7a, 0x5d, 0x6e,
|
||||
0xaa, 0x70, 0x29, 0x52, 0x78, 0x42, 0xf3, 0x1c, 0x39, 0x87, 0xb8, 0x68, 0xed, 0x7d,
|
||||
0xaf, 0xfd, 0xb5, 0x34,
|
||||
],
|
||||
[
|
||||
0x7d, 0xc1, 0x17, 0xb3, 0x39, 0x1a, 0xab, 0x85, 0xde, 0x9f, 0x42, 0x4d, 0xb6, 0x65,
|
||||
0x1e, 0x00, 0x45, 0xab, 0x79, 0x98, 0xf2, 0x8e, 0x54, 0x10, 0x15, 0x35, 0x90, 0x61,
|
||||
0x99, 0xce, 0x1f, 0x1a,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, 0x40, 0x37,
|
||||
0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, 0xbd, 0x30, 0xf8, 0x37, 0x4a, 0xc1,
|
||||
0x33, 0x86, 0x79, 0x3f,
|
||||
],
|
||||
[
|
||||
0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, 0x6c, 0x00,
|
||||
0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, 0x47, 0x7a, 0x70, 0x96,
|
||||
0x49, 0xe9, 0x50, 0x06,
|
||||
],
|
||||
[
|
||||
0x04, 0x91, 0x39, 0x48, 0x25, 0x64, 0xf1, 0x85, 0xc7, 0x90, 0x0e, 0x83, 0xc7, 0x38,
|
||||
0x07, 0x0a, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, 0x3d, 0x9a, 0x69, 0xf5,
|
||||
0x33, 0x57, 0xd7, 0x36,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x6a, 0x5a, 0x19, 0x19, 0xa4, 0x49, 0xa5, 0xe0, 0x29, 0x71, 0x1f, 0x48, 0x8a, 0xdb,
|
||||
0xd6, 0xb0, 0x3e, 0x5c, 0x92, 0x7b, 0x6f, 0x9d, 0x9d, 0x35, 0xc5, 0xb3, 0xcc, 0xeb,
|
||||
0x76, 0x60, 0x52, 0x03,
|
||||
],
|
||||
[
|
||||
0x80, 0x47, 0x5b, 0x46, 0x89, 0x59, 0x61, 0x47, 0xab, 0x2a, 0xdf, 0x01, 0x73, 0xdb,
|
||||
0x28, 0x9b, 0x3a, 0x26, 0xa1, 0x04, 0x84, 0x21, 0x73, 0xe8, 0x8b, 0xdb, 0xfe, 0xc0,
|
||||
0x4a, 0x28, 0x67, 0x1b,
|
||||
],
|
||||
[
|
||||
0x1e, 0xf3, 0xc8, 0xd0, 0xf5, 0x44, 0x44, 0xf5, 0x55, 0xb1, 0x5f, 0x7b, 0xc9, 0xfa,
|
||||
0x4f, 0xfa, 0x0f, 0x56, 0x7c, 0x0f, 0x19, 0xac, 0x7d, 0x0f, 0xf9, 0x44, 0xfd, 0x36,
|
||||
0x42, 0x6e, 0x32, 0x3a,
|
||||
],
|
||||
],
|
||||
},
|
||||
PermuteTestVector {
|
||||
initial_state: [
|
||||
[
|
||||
0x7d, 0x4f, 0x5c, 0xcb, 0x01, 0x64, 0x3c, 0x31, 0xdb, 0x84, 0x5e, 0xec, 0xd5, 0xd6,
|
||||
0x3d, 0xc1, 0x6a, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, 0xf7, 0xf2, 0x44, 0xfc,
|
||||
0x71, 0x62, 0x69, 0x39,
|
||||
],
|
||||
[
|
||||
0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, 0x9e, 0x68,
|
||||
0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, 0x82, 0x81, 0x23, 0xd9, 0x78, 0x84, 0x80,
|
||||
0x6f, 0x15, 0xfa, 0x08,
|
||||
],
|
||||
[
|
||||
0xd9, 0x52, 0x75, 0x4a, 0x23, 0x64, 0xb6, 0x66, 0xff, 0xc3, 0x0f, 0xdb, 0x01, 0x47,
|
||||
0x86, 0xda, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, 0x10, 0xa8, 0x9d, 0x1a,
|
||||
0x70, 0x99, 0x21, 0x2d,
|
||||
],
|
||||
],
|
||||
final_state: [
|
||||
[
|
||||
0x1b, 0x4a, 0xc9, 0xbe, 0xf5, 0x6b, 0xdb, 0x6f, 0xb4, 0x2d, 0x3e, 0x3c, 0xd3, 0xa2,
|
||||
0xac, 0x70, 0xa4, 0xc4, 0x0c, 0x42, 0x5b, 0x0b, 0xd6, 0x67, 0x9c, 0xa5, 0x7b, 0x30,
|
||||
0x7e, 0xf1, 0xd4, 0x2f,
|
||||
],
|
||||
[
|
||||
0x1a, 0x2e, 0xf4, 0x11, 0x94, 0xaa, 0xa2, 0x34, 0x32, 0xe0, 0x86, 0xed, 0x8a, 0xdb,
|
||||
0xd1, 0xde, 0xec, 0x3c, 0x7c, 0xb3, 0x96, 0xde, 0x35, 0xba, 0xe9, 0x5a, 0xaf, 0x5a,
|
||||
0x08, 0xa0, 0xec, 0x36,
|
||||
],
|
||||
[
|
||||
0x68, 0xeb, 0x80, 0xc7, 0x3e, 0x2c, 0xcb, 0xde, 0xe1, 0xba, 0x71, 0x24, 0x77, 0x61,
|
||||
0xd5, 0xb5, 0xec, 0xc6, 0x20, 0xe6, 0xe4, 0x8e, 0x00, 0x3b, 0x02, 0x3d, 0x9f, 0x55,
|
||||
0x61, 0x66, 0x2f, 0x20,
|
||||
],
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
pub(crate) static HASH_TEST_VECTORS: [HashTestVector; 11] = [
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
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,
|
||||
],
|
||||
[
|
||||
0x01, 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,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x83, 0x58, 0xd7, 0x11, 0xa0, 0x32, 0x9d, 0x38, 0xbe, 0xcd, 0x54, 0xfb, 0xa7, 0xc2,
|
||||
0x83, 0xed, 0x3e, 0x08, 0x9a, 0x39, 0xc9, 0x1b, 0x6a, 0x9d, 0x10, 0xef, 0xb0, 0x2b,
|
||||
0xc3, 0xf1, 0x2f, 0x06,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, 0xac, 0x6b,
|
||||
0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, 0xaf, 0xfa, 0x2e, 0xf6,
|
||||
0xee, 0x69, 0x21, 0x08,
|
||||
],
|
||||
[
|
||||
0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, 0x98, 0x2b,
|
||||
0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, 0xb3, 0x53, 0x42, 0x01,
|
||||
0xcf, 0xb1, 0xcd, 0x0d,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xdb, 0x26, 0x75, 0xff, 0x3e, 0xf8, 0xfe, 0x30, 0xc4, 0xd5, 0xde, 0x61, 0xca, 0xc0,
|
||||
0x2a, 0x8e, 0xf1, 0xa0, 0x85, 0x23, 0xbe, 0x92, 0x39, 0x4b, 0x79, 0xd2, 0x67, 0x26,
|
||||
0x30, 0x3b, 0xe6, 0x03,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, 0x9b, 0xa9,
|
||||
0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, 0xa5, 0xe2, 0x9d, 0x4e,
|
||||
0x30, 0xa7, 0x35, 0x14,
|
||||
],
|
||||
[
|
||||
0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, 0xed, 0x5a,
|
||||
0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, 0x4b, 0x69, 0x68, 0x91,
|
||||
0x2a, 0x63, 0x81, 0x0e,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xf5, 0x12, 0x1d, 0x1e, 0x1d, 0x5c, 0xfe, 0x8d, 0xa8, 0x96, 0xac, 0x0f, 0x9c, 0x18,
|
||||
0x3d, 0x76, 0x00, 0x31, 0xf6, 0xef, 0x8c, 0x7a, 0x41, 0xe6, 0x5e, 0xb0, 0x07, 0xcd,
|
||||
0xdc, 0x1d, 0x14, 0x3d,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, 0xb5, 0xfd,
|
||||
0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, 0x77, 0x08, 0x37, 0x56,
|
||||
0xd5, 0x9a, 0xf8, 0x0d,
|
||||
],
|
||||
[
|
||||
0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, 0xf0, 0xf0,
|
||||
0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, 0xe4, 0xe4, 0xc7, 0x63,
|
||||
0xcc, 0xb8, 0xf6, 0x36,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xa4, 0x16, 0xa5, 0xe7, 0x13, 0x51, 0x36, 0xa0, 0x50, 0x56, 0x90, 0x00, 0x58, 0xfa,
|
||||
0x50, 0xbf, 0x18, 0x6a, 0xd7, 0x33, 0x90, 0xac, 0xe6, 0x32, 0x3d, 0x8d, 0x81, 0xaa,
|
||||
0x8a, 0xdb, 0xd4, 0x11,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, 0x57, 0xef,
|
||||
0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, 0x1a, 0x38, 0xe0, 0x1d,
|
||||
0x94, 0x90, 0x3d, 0x3c,
|
||||
],
|
||||
[
|
||||
0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, 0x42, 0x98,
|
||||
0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, 0x7e, 0xdc, 0xf0, 0x4b,
|
||||
0xe3, 0x4a, 0x98, 0x11,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x1a, 0xba, 0xf3, 0x06, 0xfe, 0xd0, 0x5f, 0xa8, 0x92, 0x84, 0x8c, 0x49, 0xf6, 0xba,
|
||||
0x10, 0x41, 0x63, 0x43, 0x3f, 0x3f, 0x63, 0x31, 0x08, 0xa1, 0x3b, 0xc1, 0x5b, 0x2a,
|
||||
0x1d, 0x55, 0xd4, 0x0c,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, 0x88, 0x39,
|
||||
0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, 0xb9, 0xda, 0x94, 0x8d,
|
||||
0x32, 0x0d, 0xad, 0x16,
|
||||
],
|
||||
[
|
||||
0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, 0x34, 0x5b,
|
||||
0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, 0x42, 0x76, 0xd3, 0x8d,
|
||||
0x47, 0xf1, 0xe1, 0x11,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x04, 0xa1, 0x8a, 0xeb, 0x59, 0x3f, 0x79, 0x0b, 0x76, 0xa3, 0x99, 0xb7, 0xc1, 0x52,
|
||||
0x8a, 0xcd, 0xed, 0xe9, 0x3b, 0x3b, 0x2c, 0x49, 0x6b, 0xd7, 0x1b, 0xd5, 0x87, 0xcb,
|
||||
0xd7, 0xcf, 0xdf, 0x35,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, 0x3f, 0xde,
|
||||
0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, 0x85, 0xed, 0xcb, 0xda,
|
||||
0xe6, 0x9c, 0xe8, 0x3c,
|
||||
],
|
||||
[
|
||||
0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, 0x20, 0x53,
|
||||
0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, 0x37, 0x83, 0x65, 0xc8,
|
||||
0xf7, 0x39, 0x3c, 0x14,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x11, 0x03, 0xcc, 0xdc, 0x00, 0xd0, 0xf3, 0x5f, 0x65, 0x83, 0x14, 0x11, 0x6b, 0xc2,
|
||||
0xbc, 0xd9, 0x43, 0x74, 0xa9, 0x1f, 0xf9, 0x87, 0x7e, 0x70, 0x66, 0x33, 0x29, 0x04,
|
||||
0x2b, 0xd2, 0xf6, 0x1f,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, 0x79, 0x0f,
|
||||
0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, 0x32, 0xb4, 0xf4, 0x73,
|
||||
0xf4, 0x68, 0xa0, 0x08,
|
||||
],
|
||||
[
|
||||
0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, 0xae, 0x25,
|
||||
0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, 0x88, 0x2d, 0x2b, 0x21,
|
||||
0x03, 0x59, 0x65, 0x15,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xf8, 0xf8, 0xc6, 0x5f, 0x43, 0x7c, 0x45, 0xbe, 0xac, 0x11, 0xeb, 0x7d, 0x9e, 0x47,
|
||||
0x58, 0x6d, 0x87, 0x9a, 0xfd, 0x6f, 0x93, 0x04, 0x35, 0xbe, 0x0c, 0x01, 0xd1, 0x9c,
|
||||
0x89, 0x5b, 0x8d, 0x10,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, 0x91, 0xf4,
|
||||
0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, 0x73, 0x1e, 0x98, 0x5d,
|
||||
0x99, 0x58, 0x9c, 0x0b,
|
||||
],
|
||||
[
|
||||
0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, 0x20, 0x37,
|
||||
0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, 0xeb, 0xbc, 0x86, 0x2d,
|
||||
0xed, 0x42, 0x43, 0x1e,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0x5a, 0xeb, 0x48, 0x96, 0x21, 0xb0, 0x2e, 0x8e, 0x69, 0x27, 0xb9, 0x4f, 0xd2, 0x9a,
|
||||
0x61, 0x01, 0x83, 0xdf, 0x7f, 0x42, 0x87, 0xe9, 0xcb, 0xf1, 0xcc, 0xc8, 0x81, 0xd7,
|
||||
0xd0, 0xb7, 0x38, 0x27,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, 0x53, 0xd9,
|
||||
0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, 0x6d, 0x75, 0xa4, 0xa6,
|
||||
0xf2, 0x65, 0x72, 0x10,
|
||||
],
|
||||
[
|
||||
0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, 0x96, 0xbc,
|
||||
0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, 0x12, 0x86, 0x3c, 0xe7,
|
||||
0x1a, 0x02, 0xaf, 0x11,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xb0, 0x14, 0x47, 0x20, 0xf5, 0xf2, 0xa2, 0x5d, 0x49, 0x2a, 0x50, 0x4e, 0xc0, 0x73,
|
||||
0x7f, 0x09, 0x7e, 0xd8, 0x52, 0x17, 0x4f, 0x55, 0xf5, 0x86, 0x30, 0x91, 0x30, 0x6c,
|
||||
0x1a, 0xf2, 0x00, 0x35,
|
||||
],
|
||||
},
|
||||
HashTestVector {
|
||||
input: [
|
||||
[
|
||||
0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, 0x6f, 0x1e,
|
||||
0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, 0x82, 0x85, 0x7d, 0xee,
|
||||
0xcc, 0x40, 0xa9, 0x0d,
|
||||
],
|
||||
[
|
||||
0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, 0x61, 0xae,
|
||||
0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, 0xb9, 0x27, 0xb7, 0xfa,
|
||||
0xe2, 0xdb, 0x58, 0x31,
|
||||
],
|
||||
],
|
||||
output: [
|
||||
0xbb, 0xbe, 0xb7, 0x42, 0xd6, 0xe7, 0xc0, 0x1a, 0xdb, 0xf4, 0xd3, 0x85, 0x5e, 0x35,
|
||||
0xfe, 0xc4, 0x62, 0x04, 0x30, 0x89, 0xc1, 0x8b, 0xa8, 0x02, 0x90, 0x64, 0x7b, 0xb0,
|
||||
0xe5, 0x81, 0xad, 0x11,
|
||||
],
|
||||
},
|
||||
];
|
@ -203,6 +203,8 @@ extern const struct _mp_print_t mp_stderr_print;
|
||||
#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)
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
|
79
core/mocks/generated/trezorpallas.pyi
Normal file
79
core/mocks/generated/trezorpallas.pyi
Normal file
@ -0,0 +1,79 @@
|
||||
from typing import *
|
||||
# https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
def to_base(x: bytes) -> Fp:
|
||||
...
|
||||
# https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
def to_scalar(x: bytes) -> Scalar:
|
||||
...
|
||||
# https://zips.z.cash/protocol/protocol.pdf#concretegrouphashpallasandvesta
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
def group_hash(domain: str, message: bytes) -> Point:
|
||||
...
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
def scalar_from_i64(x: int) -> Scalar:
|
||||
"""Converts integer to Scalar."""
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
class Fp:
|
||||
"""Pallas base field."""
|
||||
def __init__(self, repr: bytes) -> None:
|
||||
...
|
||||
def to_bytes(self) -> bytes:
|
||||
...
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
class Scalar:
|
||||
"""Pallas scalar field."""
|
||||
def __init__(self, repr: bytes) -> None:
|
||||
...
|
||||
def to_bytes(self) -> bytes:
|
||||
...
|
||||
def is_not_zero(self) -> bool:
|
||||
...
|
||||
def __mul__(self, other: Point) -> Point:
|
||||
...
|
||||
def __add__(self, other: Scalar) -> Scalar:
|
||||
...
|
||||
def __neg__(self) -> Point:
|
||||
...
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
class Point:
|
||||
"""Pallas point."""
|
||||
def __init__(self, repr: bytes) -> None:
|
||||
...
|
||||
def to_bytes(self) -> bytes:
|
||||
...
|
||||
def extract(self) -> Fp:
|
||||
...
|
||||
def is_identity(self) -> bool:
|
||||
...
|
||||
def __add__(self, other: Point) -> Point:
|
||||
...
|
||||
def __neg__(self) -> Point:
|
||||
...
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/pallas/mod.rs
|
||||
class generators:
|
||||
SPENDING_KEY_BASE: Point
|
||||
NULLIFIER_K_BASE: Point
|
||||
VALUE_COMMITMENT_VALUE_BASE: Point
|
||||
VALUE_COMMITMENT_RANDOMNESS_BASE: Point
|
||||
NOTE_COMMITMENT_BASE: Point
|
||||
NOTE_COMMITMENT_Q: Point
|
||||
IVK_COMMITMENT_BASE: Point
|
||||
IVK_COMMITMENT_Q: Point
|
6
core/mocks/generated/trezorposeidon.pyi
Normal file
6
core/mocks/generated/trezorposeidon.pyi
Normal file
@ -0,0 +1,6 @@
|
||||
from typing import *
|
||||
|
||||
|
||||
# rust/src/zcash_primitives/poseidon/mod.rs
|
||||
def poseidon(x: Fp, y: Fp) -> Fp:
|
||||
"""Poseidon hash function."""
|
@ -80,3 +80,4 @@ VERSION_PATCH: int
|
||||
MODEL: str
|
||||
EMULATOR: bool
|
||||
BITCOIN_ONLY: bool
|
||||
ZCASH_SHIELDED: bool
|
||||
|
@ -26,9 +26,12 @@ def generate(env):
|
||||
# replace "utils.BITCOIN_ONLY" with literal constant (True/False)
|
||||
# so the compiler can optimize out the things we don't want
|
||||
btc_only = env['bitcoin_only'] == '1'
|
||||
zcash_shielded = env['zcash_shielded'] == '1'
|
||||
interim = f"{target[:-4]}.i" # replace .mpy with .i
|
||||
sed_scripts = " ".join([
|
||||
rf"-e 's/utils\.BITCOIN_ONLY/{btc_only}/g'",
|
||||
rf"-e 's/utils\.ZCASH_SHIELDED/{zcash_shielded}/g'",
|
||||
rf"-e 's/^\s+ZCASH_SHIELDED/# \0/'",
|
||||
r"-e 's/if TYPE_CHECKING/if False/'",
|
||||
r"-e 's/import typing/# \0/'",
|
||||
r"-e '/from typing import (/,/^\s*)/ {s/^/# /}'",
|
||||
|
@ -81,6 +81,8 @@ trezor.crypto.der
|
||||
import trezor.crypto.der
|
||||
trezor.crypto.hashlib
|
||||
import trezor.crypto.hashlib
|
||||
trezor.crypto.pallas
|
||||
import trezor.crypto.pallas
|
||||
trezor.crypto.rlp
|
||||
import trezor.crypto.rlp
|
||||
trezor.crypto.scripts
|
||||
|
@ -10,3 +10,8 @@ from trezorcrypto import ( # noqa: F401
|
||||
sha256,
|
||||
sha512,
|
||||
)
|
||||
|
||||
from trezor import utils
|
||||
|
||||
if utils.ZCASH_SHIELDED:
|
||||
from trezorposeidon import poseidon # noqa: F401
|
||||
|
14
core/src/trezor/crypto/pallas.py
Normal file
14
core/src/trezor/crypto/pallas.py
Normal file
@ -0,0 +1,14 @@
|
||||
"""Curve for Zcash cryptography."""
|
||||
|
||||
from trezor import utils
|
||||
|
||||
if utils.ZCASH_SHIELDED:
|
||||
from trezorpallas import ( # noqa: F401
|
||||
Fp,
|
||||
Point,
|
||||
Scalar,
|
||||
group_hash,
|
||||
scalar_from_i64,
|
||||
to_base,
|
||||
to_scalar,
|
||||
)
|
@ -8,6 +8,7 @@ from trezorutils import ( # noqa: F401
|
||||
VERSION_MAJOR,
|
||||
VERSION_MINOR,
|
||||
VERSION_PATCH,
|
||||
ZCASH_SHIELDED,
|
||||
consteq,
|
||||
firmware_hash,
|
||||
firmware_vendor,
|
||||
|
Loading…
Reference in New Issue
Block a user