@@ -6,19 +6,16 @@ use crate::{
6
6
error_code:: ErrorCode ,
7
7
public_key:: derive_pub_key,
8
8
sign_tx_context:: { check_blind_signing, SignTxContext } ,
9
- ui:: {
10
- review_address, sign_hash_ui,
11
- tx_reviewer:: { TxReviewer , TOKEN_METADATA_SIZE } ,
12
- } ,
9
+ ui:: { review_address, sign_hash_ui, tx_reviewer:: TxReviewer } ,
13
10
} ;
14
11
15
12
const MAX_TOKEN_SIZE : u8 = 5 ;
16
13
const PATH_LENGTH : usize = 20 ;
17
14
const HASH_LENGTH : usize = 32 ;
18
15
const PATH_HEX_LENGTH : usize = PATH_LENGTH * 2 ;
19
- const FIRST_FRAME_PREFIX_LENGTH : usize = PATH_LENGTH + 1 ; // path + 1 byte token size
20
16
const CALL_CONTRACT_FLAG : u8 = 0x01 ;
21
17
const SCRIPT_OFFSET : usize = 3 ; // the encoded script offset in the tx
18
+ pub const TOKEN_METADATA_SIZE : usize = 46 ;
22
19
23
20
#[ repr( u8 ) ]
24
21
pub enum Ins {
@@ -110,7 +107,13 @@ pub fn handle_apdu(
110
107
}
111
108
}
112
109
Ins :: SignTx => {
113
- let data = comm. get_data ( ) ?;
110
+ let data = match comm. get_data ( ) {
111
+ Ok ( data) => data,
112
+ Err ( code) => {
113
+ reset ( sign_tx_context, tx_reviewer) ;
114
+ return Err ( code. into ( ) ) ;
115
+ }
116
+ } ;
114
117
match handle_sign_tx ( apdu_header, data, sign_tx_context, tx_reviewer) {
115
118
Ok ( ( ) ) if !sign_tx_context. is_complete ( ) => {
116
119
return Ok ( ( ) ) ;
@@ -128,9 +131,11 @@ pub fn handle_apdu(
128
131
}
129
132
Err ( code) => Err ( code. into ( ) ) ,
130
133
} ;
134
+ reset ( sign_tx_context, tx_reviewer) ;
131
135
return result;
132
136
}
133
137
Err ( code) => {
138
+ reset ( sign_tx_context, tx_reviewer) ;
134
139
return Err ( code. into ( ) ) ;
135
140
}
136
141
}
@@ -139,55 +144,66 @@ pub fn handle_apdu(
139
144
Ok ( ( ) )
140
145
}
141
146
142
- // The transaction is split into multiple APDU commands
143
- // The first APDU command contains the path and token metadata
144
- // The subsequent APDU commands contain the transaction data
145
- // The transaction data is processed in chunks
147
+ // The transaction is split into multiple APDU commands, consisting of token metadata APDU and tx APDU commands
148
+ // We use `p1` and `p2` to distinguish between APDUs:
149
+ // * `p1` = 0 and `p2` = 0 indicates the first token metadata APDU frame
150
+ // * `p1` = 0 and `p2` = 1 indicates a new token metadata APDU frame
151
+ // * `p1` = 0 and `p2` = 2 indicates the remaining token proof APDU frame
152
+ // * `p1` = 1 and `p2` = 0 indicates the first tx APDU frame
153
+ // * `p1` = 1 and `p2` = 1 indicates subsequent tx APDU frames
146
154
fn handle_sign_tx (
147
155
apdu_header : & ApduHeader ,
148
156
data : & [ u8 ] ,
149
157
sign_tx_context : & mut SignTxContext ,
150
158
tx_reviewer : & mut TxReviewer ,
151
159
) -> Result < ( ) , ErrorCode > {
152
- match apdu_header. p1 {
153
- 0 if data. len ( ) < FIRST_FRAME_PREFIX_LENGTH => Err ( ErrorCode :: BadLen ) ,
154
- 0 => {
155
- // handle the path
156
- sign_tx_context. init ( & data[ ..PATH_LENGTH ] ) ?;
157
-
158
- // handle the token metadata
159
- let token_size = data[ FIRST_FRAME_PREFIX_LENGTH - 1 ] ;
160
- if token_size > MAX_TOKEN_SIZE {
161
- return Err ( ErrorCode :: InvalidTokenSize ) ;
160
+ match ( apdu_header. p1 , apdu_header. p2 ) {
161
+ ( 0 , 0 ) => {
162
+ // the first frame
163
+ if data. is_empty ( ) {
164
+ return Err ( ErrorCode :: BadLen ) ;
165
+ }
166
+ let token_size = data[ 0 ] ; // the first byte is the token size
167
+ check_token_size ( token_size) ?;
168
+ tx_reviewer. init ( token_size) ?;
169
+ if token_size == 0 {
170
+ return Ok ( ( ) ) ;
162
171
}
163
- let tx_data_index: usize =
164
- FIRST_FRAME_PREFIX_LENGTH + TOKEN_METADATA_SIZE * ( token_size as usize ) ;
165
- if data. len ( ) < tx_data_index + SCRIPT_OFFSET {
172
+ tx_reviewer. handle_token_metadata ( & data[ 1 ..] )
173
+ }
174
+ ( 0 , 1 ) => tx_reviewer. handle_token_metadata ( data) , // token metadata and proof frame
175
+ ( 0 , 2 ) => tx_reviewer. handle_token_proof ( data) , // the following token proof frame
176
+ ( 1 , 0 ) => {
177
+ // the first unsigned tx frame
178
+ if data. len ( ) < PATH_LENGTH + SCRIPT_OFFSET {
166
179
return Err ( ErrorCode :: BadLen ) ;
167
180
}
168
- let tx_data = & data[ tx_data_index ..] ;
181
+ let tx_data = & data[ PATH_LENGTH ..] ;
169
182
let is_tx_execute_script = tx_data[ SCRIPT_OFFSET - 1 ] == CALL_CONTRACT_FLAG ;
170
183
if is_tx_execute_script {
171
184
check_blind_signing ( ) ?;
172
185
}
173
- let token_metadata = & data [ FIRST_FRAME_PREFIX_LENGTH ..tx_data_index ] ;
174
- check_token_metadata ( token_size , token_metadata ) ? ;
175
- tx_reviewer . init ( is_tx_execute_script , token_metadata ) ?;
176
- sign_tx_context. handle_data ( apdu_header, tx_data, tx_reviewer)
186
+ tx_reviewer . set_tx_execute_script ( is_tx_execute_script ) ;
187
+
188
+ sign_tx_context . init ( & data [ .. PATH_LENGTH ] ) ?;
189
+ sign_tx_context. handle_tx_data ( apdu_header, tx_data, tx_reviewer)
177
190
}
178
- 1 => sign_tx_context. handle_data ( apdu_header, data, tx_reviewer) ,
191
+ ( 1 , 1 ) => sign_tx_context. handle_tx_data ( apdu_header, data, tx_reviewer) , // the following unsigned tx frame
179
192
_ => Err ( ErrorCode :: BadP1P2 ) ,
180
193
}
181
194
}
182
195
183
- // Check the token metadata version
184
- // The token metadata version should be 0 for now
185
- fn check_token_metadata ( token_size : u8 , token_metadata : & [ u8 ] ) -> Result < ( ) , ErrorCode > {
186
- for i in 0 ..token_size {
187
- let version_index = ( i as usize ) * TOKEN_METADATA_SIZE ;
188
- if token_metadata[ version_index] != 0 {
189
- return Err ( ErrorCode :: InvalidMetadataVersion ) ;
190
- }
196
+ #[ inline]
197
+ fn check_token_size ( size : u8 ) -> Result < ( ) , ErrorCode > {
198
+ if size > MAX_TOKEN_SIZE {
199
+ Err ( ErrorCode :: InvalidTokenSize )
200
+ } else {
201
+ Ok ( ( ) )
191
202
}
192
- Ok ( ( ) )
203
+ }
204
+
205
+ #[ inline]
206
+ fn reset ( sign_tx_context : & mut SignTxContext , tx_reviewer : & mut TxReviewer ) {
207
+ sign_tx_context. reset ( ) ;
208
+ tx_reviewer. reset ( ) ;
193
209
}
0 commit comments