1
1
use ledger_device_sdk:: io:: ApduHeader ;
2
- use utils:: { buffer:: Buffer , decode:: StreamingDecoder , deserialize_path, types:: UnsignedTx } ;
2
+ use utils:: {
3
+ buffer:: Buffer , decode:: StreamingDecoder , deserialize_path, types:: UnsignedTx , PATH_LENGTH ,
4
+ } ;
3
5
4
6
use crate :: ledger_sdk_stub:: nvm:: { NVMData , NVM , NVM_DATA_SIZE } ;
5
7
use crate :: ledger_sdk_stub:: swapping_buffer:: { SwappingBuffer , RAM_SIZE } ;
@@ -12,6 +14,7 @@ use crate::{
12
14
error_code:: ErrorCode ,
13
15
} ;
14
16
17
+ // The NVM data is used for SwappingBuffer to store temporary data in case RAM is not enough
15
18
#[ link_section = ".nvm_data" ]
16
19
static mut DATA : NVMData < NVM < NVM_DATA_SIZE > > = NVMData :: new ( NVM :: zeroed ( ) ) ;
17
20
@@ -22,6 +25,9 @@ enum DecodeStep {
22
25
Complete ,
23
26
}
24
27
28
+ // The context for signing a transaction
29
+ // It keeps track of the current step, the transaction decoder, the path, and the device address
30
+ // A streaming decoder is used to decode the transaction in chunks so that it can handle large transactions
25
31
pub struct SignTxContext {
26
32
pub path : [ u32 ; 5 ] ,
27
33
tx_decoder : StreamingDecoder < UnsignedTx > ,
@@ -34,7 +40,7 @@ pub struct SignTxContext {
34
40
impl SignTxContext {
35
41
pub fn new ( ) -> Self {
36
42
SignTxContext {
37
- path : [ 0 ; 5 ] ,
43
+ path : [ 0 ; PATH_LENGTH ] ,
38
44
tx_decoder : StreamingDecoder :: default ( ) ,
39
45
current_step : DecodeStep :: Init ,
40
46
hasher : Blake2bHasher :: new ( ) ,
@@ -43,6 +49,7 @@ impl SignTxContext {
43
49
}
44
50
}
45
51
52
+ // Initialize the context with the path
46
53
pub fn init ( & mut self , data : & [ u8 ] ) -> Result < ( ) , ErrorCode > {
47
54
deserialize_path ( data, & mut self . path , ErrorCode :: HDPathDecodingFailed ) ?;
48
55
@@ -58,11 +65,13 @@ impl SignTxContext {
58
65
self . current_step == DecodeStep :: Complete
59
66
}
60
67
68
+ // Get the transaction ID by finalizing the hash
61
69
pub fn get_tx_id ( & mut self ) -> Result < [ u8 ; BLAKE2B_HASH_SIZE ] , ErrorCode > {
62
70
assert ! ( self . is_complete( ) ) ;
63
71
self . hasher . finalize ( )
64
72
}
65
73
74
+ // Sign the transaction by signing the transaction ID
66
75
pub fn sign_tx ( & mut self ) -> Result < ( [ u8 ; 72 ] , u32 , u32 ) , ErrorCode > {
67
76
let tx_id = self . get_tx_id ( ) ?;
68
77
sign_hash ( & self . path , & tx_id)
@@ -75,6 +84,7 @@ impl SignTxContext {
75
84
) -> Result < ( ) , ErrorCode > {
76
85
while !buffer. is_empty ( ) {
77
86
match self . tx_decoder . step ( buffer) {
87
+ // New transaction details are available
78
88
Ok ( true ) => {
79
89
tx_reviewer. review_tx_details (
80
90
& self . tx_decoder . inner ,
@@ -90,42 +100,51 @@ impl SignTxContext {
90
100
self . tx_decoder . reset_stage ( ) ;
91
101
}
92
102
}
103
+ // No new transaction details are available
93
104
Ok ( false ) => return Ok ( ( ) ) ,
94
105
Err ( _) => return Err ( ErrorCode :: TxDecodingFailed ) ,
95
106
}
96
107
}
97
108
Ok ( ( ) )
98
109
}
99
110
100
- fn decode_tx ( & mut self , data : & [ u8 ] , tx_reviewer : & mut TxReviewer ) -> Result < ( ) , ErrorCode > {
101
- if data. len ( ) > ( u8:: MAX as usize ) {
111
+ // Decode a transaction chunk
112
+ fn decode_tx (
113
+ & mut self ,
114
+ tx_chunk : & [ u8 ] ,
115
+ tx_reviewer : & mut TxReviewer ,
116
+ ) -> Result < ( ) , ErrorCode > {
117
+ if tx_chunk. len ( ) > ( u8:: MAX as usize ) {
102
118
return Err ( ErrorCode :: BadLen ) ;
103
119
}
104
- let mut buffer = Buffer :: new ( data , & mut self . temp_data ) ;
120
+ let mut buffer = Buffer :: new ( tx_chunk , & mut self . temp_data ) ;
105
121
let result = self . _decode_tx ( & mut buffer, tx_reviewer) ;
106
- self . hasher . update ( data ) ?;
122
+ self . hasher . update ( tx_chunk ) ?;
107
123
result
108
124
}
109
125
126
+ // Handle a transaction data chunk
110
127
pub fn handle_data (
111
128
& mut self ,
112
129
apdu_header : & ApduHeader ,
113
- tx_data : & [ u8 ] ,
130
+ tx_data_chunk : & [ u8 ] ,
114
131
tx_reviewer : & mut TxReviewer ,
115
132
) -> Result < ( ) , ErrorCode > {
116
133
match self . current_step {
117
134
DecodeStep :: Complete => Err ( ErrorCode :: InternalError ) ,
118
135
DecodeStep :: Init => {
136
+ // The first chunk of the transaction
119
137
if apdu_header. p1 == 0 {
120
138
self . current_step = DecodeStep :: DecodingTx ;
121
- self . decode_tx ( tx_data , tx_reviewer)
139
+ self . decode_tx ( tx_data_chunk , tx_reviewer)
122
140
} else {
123
141
Err ( ErrorCode :: BadP1P2 )
124
142
}
125
143
}
126
144
DecodeStep :: DecodingTx => {
145
+ // The subsequent chunks of the transaction
127
146
if apdu_header. p1 == 1 {
128
- self . decode_tx ( tx_data , tx_reviewer)
147
+ self . decode_tx ( tx_data_chunk , tx_reviewer)
129
148
} else {
130
149
Err ( ErrorCode :: BadP1P2 )
131
150
}
0 commit comments