Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subintent hash at device side #75

Open
wants to merge 53 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
88bbea9
Implement hash calculator for subintent (calculates intermediate hash…
siy Oct 1, 2024
c86b702
Hash calculator is working for the existing test vector.
siy Oct 2, 2024
4be4d1d
On-device hash calculation intermediate commit (hangs in the middle o…
siy Oct 14, 2024
fc436bc
Merge branch 'develop' into feature/subintent-hash-at-device-side
siy Oct 15, 2024
5dce883
Refactoring of SignMode uses
siy Oct 15, 2024
eb8b306
Add Secp256k1 for on-device signing
siy Oct 15, 2024
d15611d
Merge remote-tracking branch 'origin/develop' into feature/subintent-…
siy Oct 15, 2024
6bc5848
Fix calculation of hash for the subintents with child subintents
siy Oct 18, 2024
9d52ebd
Fix formatting
siy Oct 18, 2024
a4e1241
Fix compilation
siy Oct 21, 2024
281f4b8
Intermediate commit
siy Oct 24, 2024
2ee99be
Remove unused imports
siy Oct 24, 2024
b5324fd
Bump SDK version
siy Oct 24, 2024
55a1abf
Bump SDK version
siy Oct 24, 2024
9c6f30e
Suppress warnings
siy Oct 28, 2024
9a8c9f6
Intermediate commit
siy Oct 28, 2024
51f3bb6
Fix compilation warnings
siy Oct 28, 2024
d492709
Fix formatting
siy Oct 29, 2024
48b1f74
Bump SDK version, add some comments
siy Oct 29, 2024
7ebf756
Fix formatting
siy Oct 29, 2024
9c966ee
Address clippy issues
siy Oct 29, 2024
c782067
Add tests for simple-bigint module
siy Oct 29, 2024
fa07f8e
Merge branch 'audit-fixes/compilation-warnings' into feature/subinten…
siy Oct 29, 2024
27da62c
Cleanup compilation warnings
siy Oct 30, 2024
470780b
Make Clippy happy #1
siy Oct 30, 2024
3641a0c
Make Clippy happy #2
siy Oct 30, 2024
41c65bc
Make Clippy happy #3
siy Oct 30, 2024
5abb80b
Make Clippy happy #4
siy Oct 30, 2024
bbaf46f
Make Clippy happy #5
siy Oct 30, 2024
0668ff2
Make Clippy happy #6
siy Oct 30, 2024
b27a7b2
Update README with section about sideloading
CyonAlexRDX Oct 30, 2024
939c002
Cleanup ragger tests
siy Oct 30, 2024
0858f59
Merge pull request #83 from radixdlt/readme
CyonAlexRDX Oct 30, 2024
6ec1f4c
Merge branch 'audit-fixes/second-round-of-compilation-warnings' into …
siy Oct 31, 2024
9cac6bc
Add documentation to the sbor decoder and simple-bigint crates.
siy Oct 31, 2024
682d261
Merge remote-tracking branch 'origin/feature/subintent-hash-at-device…
siy Oct 31, 2024
5c17e0f
Bump SDK version
siy Oct 31, 2024
c89fb72
Update .gitignore
siy Oct 31, 2024
157e4a3
Merge branch 'develop' into feature/subintent-hash-at-device-side
siy Nov 1, 2024
8987be6
Fix formatting
siy Nov 1, 2024
339b94d
Fix compilation and tests
siy Nov 1, 2024
02b07af
Fix final hash calculation for the subintents; Fix settings menu; Bum…
siy Nov 1, 2024
3ef483d
Fix docs and tests; Minor refactorings; Reject early operations requi…
siy Nov 4, 2024
b7da2ec
Make Clippy happy
siy Nov 4, 2024
5fe86fe
Make Clippy happy
siy Nov 4, 2024
3c87fdf
Try to fix icon alignment.
siy Nov 4, 2024
96be00e
Add Ragger tests for un-device subintent hash calculation
siy Nov 4, 2024
aa6c9f0
Remaining screens for Nano S Plus and Nano X
siy Nov 4, 2024
a66808d
Remaining screens for Nano S Plus and Nano X
siy Nov 4, 2024
42d2918
update docs
matiasbzurovski Nov 5, 2024
73f1cd3
updates
matiasbzurovski Nov 5, 2024
af84512
Merge pull request #88 from radixdlt/mb/docs
matiasbzurovski Nov 5, 2024
eb58fab
merge
CyonAlexRDX Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sbor/src/bech32/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::bech32::network::NetworkId;
use crate::math::StaticVec;
use crate::type_info::ADDRESS_STATIC_LEN;

/// Reusable storage for various types of addresses. All addresses share same length.
/// For convenience in use with stream decoders, additional boolean flag is maintained.
#[derive(Copy, Clone, Debug)]
pub struct Address {
address: [u8; ADDRESS_STATIC_LEN as usize],
Expand Down
6 changes: 4 additions & 2 deletions sbor/src/decoder_error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Errors which could appear during decoding
/// Errors which could appear during decoding.
/// First parameter is the position in the stream where error was encountered.
/// Second parameter (where available) is the byte which caused the error.
#[derive(Copy, Clone, Debug)]
pub enum DecoderError {
UnknownType(usize, u8), // Unknown main type id
UnknownSubType(usize, u8), // Unknown sub type id (element, key, value)
UnknownSubType(usize, u8), // Unknown subtype id (element, key, value)
UnknownDiscriminator(usize, u8), // Unknown discriminator for OWN or NFL ID
InvalidLen(usize, u8), // Incorrectly encoded element length
InvalidState(usize), // Input caused decoder to reach invalid state
Expand Down
2 changes: 2 additions & 0 deletions sbor/src/digest/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const COPY_SIZE: usize = ADDRESS_STATIC_LEN as usize;
const COPY_FROM: usize = BLAKE2B_DIGEST_SIZE - COPY_SIZE;
const COPY_TO: usize = BLAKE2B_DIGEST_SIZE;

/// Value Object to represent a Blake2b digest.
/// Serves two purposes: 1 - preserves context and 2 - ensures automatic cleanup after use.
#[repr(C, packed)]
#[derive(Clone, Debug)]
pub struct Digest(pub [u8; BLAKE2B_DIGEST_SIZE]);
Expand Down
24 changes: 22 additions & 2 deletions sbor/src/digest/hash_calculator.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
/// Babylon uses quite non-traditional approach to hash calculation. Instead of hashing the whole transaction or subintent SBOR-encoded blob,
/// it hashes individual components of the transaction/subintent. Then final hash is calculated as a hash of hashes.
/// This approach introduces substantial complexity in case of the stream decoding and requires a state machine to handle the decoding process.
///
/// The general idea is to have two independent digesters - one for current element and one for final hash. Unfortunately, BLOBS require one more digester
/// because hash of the BLOB field is calculated as hash of hashes of individual BLOBs.
///
/// The subintent introduces additional complexity, as hashes for fields are calculated with initial (type) byte skipped
/// (see `radix-transactions/src/model/versioned.rs` in `radix-scrypto` repository for details of hash calculation)
///
/// Implementation basically consists of two decoders which share the same digesters for memory efficiency.
use core::result::Result;

use crate::digest::digest::Digest;
use crate::digest::digester::Digester;
use crate::sbor_decoder::SborEvent;

/// Working modes for the hash calculator
#[repr(u8)]
pub enum HashCalculatorMode {
Transaction,
PreAuth,
}

/// State machine phases for the transaction hash calculator
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
enum TxHashPhase {
Expand All @@ -25,6 +38,7 @@ enum TxHashPhase {
HashingError,
}

/// State machine phases for the subintent hash calculator
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u8)]
enum SiHashPhase {
Expand All @@ -43,6 +57,7 @@ enum SiHashPhase {
HashingError,
}

/// Internal state machine which controls the process of finalizing/merging hashes
#[derive(Copy, Clone, Debug)]
#[repr(u8)]
enum HashCommitPhase {
Expand Down Expand Up @@ -85,7 +100,7 @@ pub struct HashCalculator<T: Digester> {
mode: HashCalculatorMode,
}

// Transaction intent hash calculator
/// Transaction intent hash calculator implementation
impl<T: Digester> HashCalculator<T> {
fn tx_handle(&mut self, event: SborEvent) {
match event {
Expand Down Expand Up @@ -229,6 +244,7 @@ impl<T: Digester> HashCalculator<T> {
}
}

/// Subintent hash calculator implementation
impl<T: Digester> HashCalculator<T> {
fn si_handle(&mut self, event: SborEvent) {
match event {
Expand Down Expand Up @@ -367,6 +383,10 @@ impl<T: Digester> HashCalculator<T> {
match self.work_digester.finalize() {
Ok(digest) => match self.output_digester.update(digest.as_bytes()) {
Ok(_) => {
// Use it for debugging hash calculator: it prints the hash of each
// processed element. Note that si_test_data.rs contains these hashes as well,
// so you can compare (sorry, only visually for now) calculated hash with
// expected one and find which element is calculated incorrectly.
#[cfg(test)]
{
let blob = digest.as_bytes();
Expand Down Expand Up @@ -426,7 +446,7 @@ impl<T: Digester> HashCalculator<T> {
}
}

// Common part + externally visible API for both transaction and subintent hash calculators
/// Common part + externally visible API for both transaction and subintent hash calculators
impl<T: Digester> HashCalculator<T> {
const PAYLOAD_PREFIX: u8 = 0x54;
const V1_INTENT: u8 = 1;
Expand Down
2 changes: 1 addition & 1 deletion sbor/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Instructions recognized by instruction extractor
/// Instructions recognized by instruction extractor
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incorrect doc, there is an empty space between this doc and the type enum Instruction, the doc must go on top of #[repr()u8], without newline between. And every line in the doc must be ///

// Keep in sync with
// https://raw.githubusercontent.com/radixdlt/radixdlt-scrypto/develop/transaction/src/model/instruction.rs

Expand Down
6 changes: 4 additions & 2 deletions sbor/src/instruction_extractor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Process events received from decoder and extract data related to instructions

/// Process events received from SBOR decoder and extract data related to each instruction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incorrect doc, if this doc is for this file, then you should use //!, or put docs on top of types.

/// and its parameters.
/// Implemented as a state machine which "walks" through the transaction intent and when it reaches
/// the instructions it starts emitting relevant events.
use crate::instruction::{to_instruction, InstructionInfo};
use crate::sbor_decoder::SborEvent;
use crate::type_info::{to_type_info, TypeInfo, TYPE_ENUM, TYPE_NONE, TYPE_TUPLE};
Expand Down
1 change: 1 addition & 0 deletions sbor/src/math/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::static_vec::StaticVec;
#[derive(Copy, Clone, Debug)]
pub struct Decimal(BigInt<192>);

/// Ledger app-specific counterpart of the Scrypto Decimal type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incorrectly place doc, should go on top of derive on top of Decimal

impl Decimal {
pub const SIZE_IN_BYTES: usize = BigInt::<192>::NUM_BYTES;
pub const ZERO: Decimal = Decimal(BigInt::from_limbs([0, 0, 0, 0, 0, 0]));
Expand Down
3 changes: 3 additions & 0 deletions sbor/src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub use simple_bigint::bcd::BCD;
pub use simple_bigint::bigint::{BigInt, BigIntError};
pub use simple_bigint::ceil_div;

/// String formatting routine for Decimal and PreciseDecimal types.
/// It converts the underlying BigInt to BCD and then formats it by putting decimal dot where necessary
/// and stripping/adding leading/trailing zeros where necessary to achieve necessary output.
pub fn format_big_int<const N: usize, const SCALE: usize, const DISPLAY_WIDTH: usize>(
input: &BigInt<N>,
output: &mut StaticVec<u8, DISPLAY_WIDTH>,
Expand Down
1 change: 1 addition & 0 deletions sbor/src/math/precise_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::static_vec::StaticVec;
#[derive(Copy, Clone)]
pub struct PreciseDecimal(BigInt<256>);

/// Ledger app-specific counterpart of the Scrypto PreciseDecimal type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incorrectly place doc, should go on top of derive on top of PreciseDecimal

impl PreciseDecimal {
pub const SIZE_IN_BYTES: usize = BigInt::<256>::NUM_BYTES;
pub const SCALE: usize = 36;
Expand Down
8 changes: 4 additions & 4 deletions sbor/src/print/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ impl<T: Copy> ParameterPrinter<T> for ArrayParameterPrinter {
}
}

fn subcomponent_end(&self, state: &mut ParameterPrinterState<T>) {
state.print_text(b", ");
}

fn end(&self, state: &mut ParameterPrinterState<T>) {
state.print_byte(b')');
}

fn subcomponent_end(&self, state: &mut ParameterPrinterState<T>) {
state.print_text(b", ");
}
}
2 changes: 0 additions & 2 deletions sbor/src/print/decimals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use crate::math::{Decimal, PreciseDecimal};
use crate::print::parameter_printer::ParameterPrinter;
use crate::print::state::ParameterPrinterState;

// Decimal parameter printer
pub struct DecimalParameterPrinter {}

pub const DECIMAL_PARAMETER_PRINTER: DecimalParameterPrinter = DecimalParameterPrinter {};
Expand All @@ -22,7 +21,6 @@ impl<T: Copy> ParameterPrinter<T> for DecimalParameterPrinter {
}
}

// PreciseDecimal parameter printer
pub struct PreciseDecimalParameterPrinter {}

pub const PRECISE_DECIMAL_PARAMETER_PRINTER: PreciseDecimalParameterPrinter =
Expand Down
1 change: 1 addition & 0 deletions sbor/src/print/fanout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::instruction_extractor::{ExtractorEvent, InstructionHandler};
use crate::print::instruction_printer::InstructionPrinter;
use crate::print::tx_summary_detector::TxSummaryDetector;

/// Small adapter used to distribute events to multiple handlers.
pub struct Fanout<'a, T: Copy> {
printer: &'a mut InstructionPrinter<T>,
detector: &'a mut TxSummaryDetector,
Expand Down
2 changes: 2 additions & 0 deletions sbor/src/print/instruction_printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ impl<T: Copy> InstructionPrinter<T> {
}
}

/// This structure and its implementation are a workaround for Rust compiler for STM32 not
/// supporting dynamic traits (i.e. virtual methods).
struct Dispatcher;

// Workaround for not working vtables
Expand Down
11 changes: 7 additions & 4 deletions sbor/src/print/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::print::tty::TTY;
use crate::sbor_decoder::STACK_DEPTH;
use crate::static_vec::StaticVec;

/// Element of the parameter printer nesting stack.
#[repr(C, packed)]
#[derive(Copy, Clone, Debug)]
pub struct ValueState {
Expand Down Expand Up @@ -38,13 +39,15 @@ impl Default for ValueState {
}
}

/// The intermediate buffer size for the individual parameters.
#[cfg(target_os = "nanos")]
pub const PARAMETER_AREA_SIZE: usize = 96;
#[cfg(any(target_os = "nanox", target_os = "nanosplus"))]
pub const PARAMETER_AREA_SIZE: usize = 256;
#[cfg(not(any(target_os = "nanos", target_os = "nanox", target_os = "nanosplus")))]
pub const PARAMETER_AREA_SIZE: usize = 256;

/// The buffer size of the entire message to be displayed.
#[cfg(target_os = "nanos")]
pub const DISPLAY_SIZE: usize = 256; // Use smaller buffer for Nano S
#[cfg(any(target_os = "nanox", target_os = "nanosplus"))]
Expand All @@ -57,11 +60,11 @@ pub const TITLE_SIZE: usize = 32;
pub struct ParameterPrinterState<T: Copy> {
pub display: StaticVec<u8, { DISPLAY_SIZE }>,
pub data: StaticVec<u8, { PARAMETER_AREA_SIZE }>,
pub title: StaticVec<u8, { TITLE_SIZE }>,
pub title: StaticVec<u8, { TITLE_SIZE }>, // Intermediate buffer for formatting instruction titles (instruction number)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs must go op top of field, or are you "waiting" with that until last minute? just dont forget :)

pub stack: StaticVec<ValueState, { STACK_DEPTH as usize }>,
pub nesting_level: u8,
pub nesting_level: u8, // Active nesting level in the stack
pub network_id: NetworkId,
pub show_instructions: bool,
pub show_instructions: bool, // Whether to show instructions or not
tty: TTY<T>,
}

Expand All @@ -87,7 +90,7 @@ impl<T: Copy> ParameterPrinterState<T> {
nesting_level: 0,
network_id,
show_instructions: true,
tty: tty,
tty,
}
}

Expand Down
2 changes: 2 additions & 0 deletions sbor/src/print/tx_intent_type.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/// Transaction intent type as detected by the transaction summary detector.
/// So far only two types are recognized - Simple Transfer and others.
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum TxIntentType {
Expand Down
22 changes: 15 additions & 7 deletions sbor/src/print/tx_summary_detector.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/// Transaction summary detector is used to determine the type of the transaction intent and collect
/// information about fees.
/// Implementation consists of two independent state machines - one for detecting the intent type and
/// other to collect fee information. Both of them use information about decoded instructions
/// received from `InstructionExtractor`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incorrect doc, either use //! for documenting the whole file, or attach the doc to some specific type.

use crate::bech32::address::Address;
use crate::instruction::{Instruction, InstructionInfo};
use crate::instruction_extractor::ExtractorEvent;
Expand All @@ -7,7 +12,7 @@ use crate::sbor_decoder::SborEvent;
use crate::static_vec::StaticVec;
use crate::type_info::*;

// Lock_fee: CallMethod -> Address -> Name ("lock_fee") -> TupleLockFee -> (ValueLockFee) -> DoneLockFee
/// Transaction fee collector state machine phases.
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum FeePhase {
Expand All @@ -20,6 +25,7 @@ pub enum FeePhase {
ValueStart,
}

/// Transaction type detector state machine phases.
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum DecodingPhase {
Expand All @@ -46,10 +52,10 @@ pub enum DecodingPhase {
#[derive(Copy, Clone, Debug)]
pub struct TransferDetails {
pub fee: Option<Decimal>,
pub src_address: Address,
pub dst_address: Address,
pub res_address: Address,
pub amount: Decimal,
pub src_address: Address, // From ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't forget to fix doc for fields...

pub dst_address: Address, // To ...
pub res_address: Address, // Resource ...
pub amount: Decimal, // Amount ...
}

#[derive(Copy, Clone, Debug)]
Expand Down Expand Up @@ -132,14 +138,16 @@ impl DetectedTxType {
}
}

//Max of address length and decimal length
/// Size of temporary buffer for parameter data. It should be enough to store any parameter data
/// which we're going to use. So far we're operating with addresses, decimal numbers and fixed
/// method names. None of them exceeds 40 bytes.
const MAX_TX_DATA_SIZE: usize = 40;

pub struct TxSummaryDetector {
intent_type: TxIntentType,
decoding_phase: DecodingPhase,
fee_phase: FeePhase,
data: StaticVec<u8, { MAX_TX_DATA_SIZE }>,
data: StaticVec<u8, { MAX_TX_DATA_SIZE }>, // Temporary buffer for parameter data
fee: Decimal,
amount: Decimal,
src_address: Address,
Expand Down
Loading