@@ -103,6 +103,28 @@ fn eip1559_sighash(tx: &EIP1559Transaction) -> [u8; 32] {
103103 keccak256 ( & prefixed)
104104}
105105
106+ fn eip712_sighash ( primary_type : & str , data_type : & str , data : & [ u8 ] ) -> [ u8 ; 32 ] {
107+ let domain_type_hash = keccak256 ( b"EIP712Domain(string name)" ) ;
108+ let name_hash = keccak256 ( b"Test" ) ;
109+ let mut domain_input = Vec :: new ( ) ;
110+ domain_input. extend_from_slice ( & domain_type_hash) ;
111+ domain_input. extend_from_slice ( & name_hash) ;
112+ let domain_separator = keccak256 ( & domain_input) ;
113+
114+ let type_hash = keccak256 ( format ! ( "{primary_type}({data_type} data)" ) . as_bytes ( ) ) ;
115+ let data_hash = keccak256 ( data) ;
116+ let mut struct_input = Vec :: new ( ) ;
117+ struct_input. extend_from_slice ( & type_hash) ;
118+ struct_input. extend_from_slice ( & data_hash) ;
119+ let struct_hash = keccak256 ( & struct_input) ;
120+
121+ let mut sig_input = Vec :: new ( ) ;
122+ sig_input. extend_from_slice ( b"\x19 \x01 " ) ;
123+ sig_input. extend_from_slice ( & domain_separator) ;
124+ sig_input. extend_from_slice ( & struct_hash) ;
125+ keccak256 ( & sig_input)
126+ }
127+
106128fn verify_eth_signature ( sighash : & [ u8 ; 32 ] , signature : & [ u8 ; 65 ] ) {
107129 let secp = secp256k1:: Secp256k1 :: new ( ) ;
108130 let path: bitcoin:: bip32:: DerivationPath = "m/44'/60'/0'/0/0" . parse ( ) . unwrap ( ) ;
@@ -312,3 +334,87 @@ async fn test_eth_sign_typed_message_antiklepto_disabled() {
312334 } )
313335 . await
314336}
337+
338+ #[ tokio:: test]
339+ async fn test_eth_sign_typed_message_streaming_bytes ( ) {
340+ test_initialized_simulators ( async |paired_bitbox| {
341+ if !semver:: VersionReq :: parse ( ">=9.26.0" )
342+ . unwrap ( )
343+ . matches ( paired_bitbox. version ( ) )
344+ {
345+ return ;
346+ }
347+
348+ let large_bytes_hex = "aa" . repeat ( 10000 ) ;
349+ let msg = format ! (
350+ r#"{{
351+ "types": {{
352+ "EIP712Domain": [
353+ {{ "name": "name", "type": "string" }}
354+ ],
355+ "Msg": [
356+ {{ "name": "data", "type": "bytes" }}
357+ ]
358+ }},
359+ "primaryType": "Msg",
360+ "domain": {{
361+ "name": "Test"
362+ }},
363+ "message": {{
364+ "data": "0x{large_bytes_hex}"
365+ }}
366+ }}"#
367+ ) ;
368+
369+ let signature = paired_bitbox
370+ . eth_sign_typed_message ( 1 , & "m/44'/60'/0'/0/0" . try_into ( ) . unwrap ( ) , & msg, false )
371+ . await
372+ . unwrap ( ) ;
373+ assert_eq ! ( signature. len( ) , 65 ) ;
374+ let sighash = eip712_sighash ( "Msg" , "bytes" , & vec ! [ 0xaa ; 10000 ] ) ;
375+ verify_eth_signature ( & sighash, & signature) ;
376+ } )
377+ . await
378+ }
379+
380+ #[ tokio:: test]
381+ async fn test_eth_sign_typed_message_streaming_string ( ) {
382+ test_initialized_simulators ( async |paired_bitbox| {
383+ if !semver:: VersionReq :: parse ( ">=9.26.0" )
384+ . unwrap ( )
385+ . matches ( paired_bitbox. version ( ) )
386+ {
387+ return ;
388+ }
389+
390+ let large_string = "a" . repeat ( 10000 ) ;
391+ let msg = format ! (
392+ r#"{{
393+ "types": {{
394+ "EIP712Domain": [
395+ {{ "name": "name", "type": "string" }}
396+ ],
397+ "Msg": [
398+ {{ "name": "data", "type": "string" }}
399+ ]
400+ }},
401+ "primaryType": "Msg",
402+ "domain": {{
403+ "name": "Test"
404+ }},
405+ "message": {{
406+ "data": "{large_string}"
407+ }}
408+ }}"#
409+ ) ;
410+
411+ let signature = paired_bitbox
412+ . eth_sign_typed_message ( 1 , & "m/44'/60'/0'/0/0" . try_into ( ) . unwrap ( ) , & msg, false )
413+ . await
414+ . unwrap ( ) ;
415+ assert_eq ! ( signature. len( ) , 65 ) ;
416+ let sighash = eip712_sighash ( "Msg" , "string" , "a" . repeat ( 10000 ) . as_bytes ( ) ) ;
417+ verify_eth_signature ( & sighash, & signature) ;
418+ } )
419+ . await
420+ }
0 commit comments