Coverage for tests/ledger/hsm2dongle_cmds/test_hsm2dongle_sign_auth_segwit.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-07-10 13:43 +0000

1# The MIT License (MIT) 

2# 

3# Copyright (c) 2021 RSK Labs Ltd 

4# 

5# Permission is hereby granted, free of charge, to any person obtaining a copy of 

6# this software and associated documentation files (the "Software"), to deal in 

7# the Software without restriction, including without limitation the rights to 

8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 

9# of the Software, and to permit persons to whom the Software is furnished to do 

10# so, subject to the following conditions: 

11# 

12# The above copyright notice and this permission notice shall be included in all 

13# copies or substantial portions of the Software. 

14# 

15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 

16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 

18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 

19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 

20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 

21# SOFTWARE. 

22 

23from unittest.mock import Mock, patch, call 

24from parameterized import parameterized 

25from tests.ledger.test_hsm2dongle import TestHSM2DongleBase, HSM2DongleTestMode 

26from ledger.hsm2dongle import ( 

27 HSM2DongleError, 

28 SighashComputationMode, 

29) 

30from ledgerblue.commException import CommException 

31 

32import logging 

33 

34logging.disable(logging.CRITICAL) 

35 

36 

37class TestHSM2DongleSignAuthorizedSegwit(TestHSM2DongleBase): 

38 def setUp(self): 

39 super().setUp() 

40 

41 self.SEGWIT_SPEC = { 

42 "exchanges": [ 

43 "q-path >02 01 11223344 D2040000", 

44 "a-tx0 <02 02 0C", 

45 "q-tx0 >02 02 0F000000 01 0E00 AABBCCDDEE", 

46 "a-tx1 <02 02 03", 

47 "q-tx1 >02 02 FF7788", 

48 "a-tx2 <02 02 05", 

49 "q-tx2 >02 02 0522446688", 

50 "a-tx3 <02 02 09", 

51 "q-tx3 >02 02 AA 992C0A0000000000", 

52 "a-rc0 <02 04 04", 

53 "q-rc0 >02 04 00112233", 

54 "a-rc1 <02 04 06", 

55 "q-rc1 >02 04 445566778899", 

56 "a-mp0 <02 08 04", 

57 "q-mp0 >02 08 03 03 3344", 

58 "a-mp1 <02 08 03", 

59 "q-mp1 >02 08 55 02 66", 

60 "a-mp2 <02 08 07", 

61 "q-mp2 >02 08 77 05 aabbccddee", 

62 "a-sig <02 81 AABBCCDD", 

63 ], 

64 "mode": SighashComputationMode.SEGWIT, 

65 "tx": "aabbccddeeff7788", 

66 "input": 1234, 

67 "ws": "22446688aa", 

68 "ov": 666777, 

69 "receipt": "00112233445566778899", 

70 "mp": ["334455", "6677", "aabbccddee"], 

71 } 

72 

73 @patch("ledger.hsm2dongle.HSM2DongleSignature") 

74 def test_ok(self, HSM2DongleSignatureMock): 

75 key_id = Mock(**{"to_binary.return_value": bytes.fromhex("11223344")}) 

76 spec = self.process_sign_auth_spec({**self.SEGWIT_SPEC, "keyid": key_id}) 

77 HSM2DongleSignatureMock.return_value = "the-signature" 

78 

79 self.assertEqual( 

80 (True, "the-signature"), 

81 self.do_sign_auth(spec) 

82 ) 

83 self.assert_exchange(spec["requests"]) 

84 self.assertEqual( 

85 [call(bytes.fromhex("aabbccdd"))], 

86 HSM2DongleSignatureMock.call_args_list, 

87 ) 

88 

89 def test_long_witness_script_length(self): 

90 exchanges = [ 

91 "q-path >02 01 11223344 D2040000", 

92 "a-tx0 <02 02 0C", 

93 "q-tx0 >02 02 0F000000 01 0D01 AABBCCDDEE", 

94 "a-tx1 <02 02 03", 

95 "q-tx1 >02 02 FF7788", 

96 "a-tx2 <02 02 08", 

97 "q-tx2 >02 02 FD0201 0001020304", 

98 "a-tx3 <FF", 

99 ] 

100 key_id = Mock(**{"to_binary.return_value": bytes.fromhex("11223344")}) 

101 spec = self.process_sign_auth_spec({ 

102 **self.SEGWIT_SPEC, "exchanges": exchanges, 

103 "keyid": key_id, "ws": self.buf(258).hex() 

104 }, stop="a-tx3", replace=CommException("forced-stop", 0xFFFF) 

105 ) 

106 

107 with self.assertRaises(HSM2DongleError): 

108 self.do_sign_auth(spec) 

109 self.assert_exchange(spec["requests"]) 

110 

111 @parameterized.expand([ 

112 ("input", "a-tx1", 0x6A88, -2), 

113 ("tx_hash_mismatch", "a-tx3", 0x6A8D, -2), 

114 ("tx_version", "a-tx2", 0x6A8E, -2), 

115 ("invalid_sighash_computation_mode", "a-tx3", 0x6A97, -2), 

116 ("invalid_extradata_size", "a-tx1", 0x6A98, -2), 

117 ("unknown", "a-tx2", 0x6AFF, -10), 

118 ("unexpected", "a-tx3", [0, 0, 0xFF], -10), 

119 ]) 

120 def test_btctx_invalid(self, _, stop, device_error, expected_response): 

121 if type(device_error) == int: 

122 last_response = CommException("msg", device_error) 

123 else: 

124 last_response = bytes(device_error) 

125 

126 key_id = Mock(**{"to_binary.return_value": bytes.fromhex("11223344")}) 

127 spec = self.process_sign_auth_spec( 

128 {**self.SEGWIT_SPEC, "keyid": key_id}, 

129 stop=stop, 

130 replace=last_response 

131 ) 

132 

133 self.assertEqual( 

134 (False, expected_response), 

135 self.do_sign_auth(spec) 

136 ) 

137 self.assert_exchange(spec["requests"]) 

138 

139 def test_btctx_unexpected_error_exc(self): 

140 key_id = Mock(**{"to_binary.return_value": bytes.fromhex("11223344")}) 

141 spec = self.process_sign_auth_spec( 

142 {**self.SEGWIT_SPEC, "keyid": key_id}, 

143 stop="a-tx2", 

144 replace=CommException("", 0xFF) 

145 ) 

146 

147 with self.assertRaises(HSM2DongleError): 

148 self.do_sign_auth(spec) 

149 self.assert_exchange(spec["requests"]) 

150 

151 

152class TestHSM2DongleSGXSignAuthorizedSegwit(TestHSM2DongleSignAuthorizedSegwit): 

153 def get_test_mode(self): 

154 return HSM2DongleTestMode.SGX