@@ -20,6 +20,10 @@ use num_bigint::{BigInt, BigUint};
2020//use num_traits::ToPrimitive;
2121use serde_json:: Value ;
2222
23+ /// Threshold above which transaction data is streamed in chunks.
24+ /// Transactions with data larger than this use streaming mode.
25+ const STREAMING_THRESHOLD : usize = 6144 ;
26+
2327impl < R : Runtime > PairedBitBox < R > {
2428 async fn query_proto_eth (
2529 & self ,
@@ -478,6 +482,31 @@ impl<R: Runtime> PairedBitBox<R> {
478482 }
479483 }
480484
485+ /// Handles streaming of transaction data when in streaming mode.
486+ /// The device requests data chunks, and this method responds with the requested chunks.
487+ async fn handle_eth_data_streaming (
488+ & self ,
489+ data : & [ u8 ] ,
490+ mut response : pb:: eth_response:: Response ,
491+ ) -> Result < pb:: eth_response:: Response , Error > {
492+ while let pb:: eth_response:: Response :: DataRequestChunk ( chunk_req) = & response {
493+ let offset = chunk_req. offset as usize ;
494+ let length = chunk_req. length as usize ;
495+
496+ if offset + length > data. len ( ) {
497+ return Err ( Error :: UnexpectedResponse ) ;
498+ }
499+
500+ let chunk = data[ offset..offset + length] . to_vec ( ) ;
501+ response = self
502+ . query_proto_eth ( pb:: eth_request:: Request :: DataResponseChunk (
503+ pb:: EthSignDataResponseChunkRequest { chunk } ,
504+ ) )
505+ . await ?;
506+ }
507+ Ok ( response)
508+ }
509+
481510 /// Signs an Ethereum transaction. It returns a 65 byte signature (R, S, and 1 byte recID). The
482511 /// `tx` param can be constructed manually or parsed from a raw transaction using
483512 /// `raw_tx_slice.try_into()` (`rlp` feature required).
@@ -491,6 +520,11 @@ impl<R: Runtime> PairedBitBox<R> {
491520 // passing chainID instead of coin only since v9.10.0
492521 self . validate_version ( ">=9.10.0" ) ?;
493522
523+ let use_streaming = tx. data . len ( ) > STREAMING_THRESHOLD ;
524+ if use_streaming {
525+ self . validate_version ( ">=9.26.0" ) ?;
526+ }
527+
494528 let host_nonce = crate :: antiklepto:: gen_host_nonce ( ) ?;
495529 let request = pb:: eth_request:: Request :: Sign ( pb:: EthSignRequest {
496530 coin : 0 ,
@@ -500,14 +534,27 @@ impl<R: Runtime> PairedBitBox<R> {
500534 gas_limit : crate :: util:: remove_leading_zeroes ( & tx. gas_limit ) ,
501535 recipient : tx. recipient . to_vec ( ) ,
502536 value : crate :: util:: remove_leading_zeroes ( & tx. value ) ,
503- data : tx. data . clone ( ) ,
537+ data : if use_streaming {
538+ vec ! [ ]
539+ } else {
540+ tx. data . clone ( )
541+ } ,
504542 host_nonce_commitment : Some ( pb:: AntiKleptoHostNonceCommitment {
505543 commitment : crate :: antiklepto:: host_commit ( & host_nonce) . to_vec ( ) ,
506544 } ) ,
507545 chain_id,
508546 address_case : address_case. unwrap_or ( pb:: EthAddressCase :: Mixed ) . into ( ) ,
547+ data_length : if use_streaming {
548+ tx. data . len ( ) as u32
549+ } else {
550+ 0
551+ } ,
509552 } ) ;
510- let response = self . query_proto_eth ( request) . await ?;
553+
554+ let mut response = self . query_proto_eth ( request) . await ?;
555+ if use_streaming {
556+ response = self . handle_eth_data_streaming ( & tx. data , response) . await ?;
557+ }
511558 self . handle_antiklepto ( & response, host_nonce) . await
512559 }
513560
@@ -523,6 +570,11 @@ impl<R: Runtime> PairedBitBox<R> {
523570 // EIP1559 is suported from v9.16.0
524571 self . validate_version ( ">=9.16.0" ) ?;
525572
573+ let use_streaming = tx. data . len ( ) > STREAMING_THRESHOLD ;
574+ if use_streaming {
575+ self . validate_version ( ">=9.26.0" ) ?;
576+ }
577+
526578 let host_nonce = crate :: antiklepto:: gen_host_nonce ( ) ?;
527579 let request = pb:: eth_request:: Request :: SignEip1559 ( pb:: EthSignEip1559Request {
528580 chain_id : tx. chain_id ,
@@ -535,13 +587,26 @@ impl<R: Runtime> PairedBitBox<R> {
535587 gas_limit : crate :: util:: remove_leading_zeroes ( & tx. gas_limit ) ,
536588 recipient : tx. recipient . to_vec ( ) ,
537589 value : crate :: util:: remove_leading_zeroes ( & tx. value ) ,
538- data : tx. data . clone ( ) ,
590+ data : if use_streaming {
591+ vec ! [ ]
592+ } else {
593+ tx. data . clone ( )
594+ } ,
539595 host_nonce_commitment : Some ( pb:: AntiKleptoHostNonceCommitment {
540596 commitment : crate :: antiklepto:: host_commit ( & host_nonce) . to_vec ( ) ,
541597 } ) ,
542598 address_case : address_case. unwrap_or ( pb:: EthAddressCase :: Mixed ) . into ( ) ,
599+ data_length : if use_streaming {
600+ tx. data . len ( ) as u32
601+ } else {
602+ 0
603+ } ,
543604 } ) ;
544- let response = self . query_proto_eth ( request) . await ?;
605+
606+ let mut response = self . query_proto_eth ( request) . await ?;
607+ if use_streaming {
608+ response = self . handle_eth_data_streaming ( & tx. data , response) . await ?;
609+ }
545610 self . handle_antiklepto ( & response, host_nonce) . await
546611 }
547612
0 commit comments