@@ -70,10 +70,13 @@ void TestBIP324PacketVector(
7070 BOOST_CHECK (Span{mid_send_garbage} == cipher.GetSendGarbageTerminator ());
7171 BOOST_CHECK (Span{mid_recv_garbage} == cipher.GetReceiveGarbageTerminator ());
7272
73+ // Vector of encrypted empty messages, encrypted in order to seek to the right position.
74+ std::vector<std::vector<std::byte>> dummies (in_idx);
75+
7376 // Seek to the numbered packet.
7477 for (uint32_t i = 0 ; i < in_idx; ++i) {
75- std::vector<std::byte> dummy (cipher.EXPANSION );
76- cipher.Encrypt ({}, {}, false , dummy );
78+ dummies[i]. resize (cipher.EXPANSION );
79+ cipher.Encrypt ({}, {}, true , dummies[i] );
7780 }
7881
7982 // Construct contents and encrypt it.
@@ -93,9 +96,68 @@ void TestBIP324PacketVector(
9396 BOOST_CHECK (Span{out_ciphertext_endswith} == Span{ciphertext}.last (out_ciphertext_endswith.size ()));
9497 }
9598
96- // Note that we don't test decryption here, as the test vectors don't provide the other party's
97- // private key, so we cannot act like them. See the bip324_cipher_roundtrip fuzz test for a test
98- // that does cover decryption.
99+ for (unsigned error = 0 ; error <= 12 ; ++error) {
100+ // error selects a type of error introduced:
101+ // - error=0: no errors, decryption should be successful
102+ // - error=1: wrong side
103+ // - error=2..9: bit error in ciphertext
104+ // - error=10: bit error in aad
105+ // - error=11: extra 0x00 at end of aad
106+ // - error=12: message index wrong
107+
108+ // Instantiate self-decrypting BIP324 cipher.
109+ BIP324Cipher dec_cipher (key, ellswift_ours);
110+ BOOST_CHECK (!dec_cipher);
111+ BOOST_CHECK (dec_cipher.GetOurPubKey () == ellswift_ours);
112+ dec_cipher.Initialize (ellswift_theirs, (error == 1 ) ^ in_initiating, /* self_decrypt=*/ true );
113+ BOOST_CHECK (dec_cipher);
114+
115+ // Compare session variables.
116+ BOOST_CHECK ((Span{out_session_id} == dec_cipher.GetSessionID ()) == (error != 1 ));
117+ BOOST_CHECK ((Span{mid_send_garbage} == dec_cipher.GetSendGarbageTerminator ()) == (error != 1 ));
118+ BOOST_CHECK ((Span{mid_recv_garbage} == dec_cipher.GetReceiveGarbageTerminator ()) == (error != 1 ));
119+
120+ // Seek to the numbered packet.
121+ if (in_idx == 0 && error == 12 ) continue ;
122+ uint32_t dec_idx = in_idx ^ (error == 12 ? (1U << InsecureRandRange (16 )) : 0 );
123+ for (uint32_t i = 0 ; i < dec_idx; ++i) {
124+ unsigned use_idx = i < in_idx ? i : 0 ;
125+ bool dec_ignore{false };
126+ dec_cipher.DecryptLength (Span{dummies[use_idx]}.first (cipher.LENGTH_LEN ));
127+ dec_cipher.Decrypt (Span{dummies[use_idx]}.subspan (cipher.LENGTH_LEN ), {}, dec_ignore, {});
128+ }
129+
130+ // Construct copied (and possibly damaged) copy of ciphertext.
131+ // Decrypt length
132+ auto to_decrypt = ciphertext;
133+ if (error >= 2 && error <= 9 ) {
134+ to_decrypt[InsecureRandRange (to_decrypt.size ())] ^= std::byte (1U << InsecureRandRange (8 ));
135+ }
136+
137+ // Decrypt length and resize ciphertext to accomodate.
138+ uint32_t dec_len = dec_cipher.DecryptLength (MakeByteSpan (to_decrypt).first (cipher.LENGTH_LEN ));
139+ to_decrypt.resize (dec_len + cipher.EXPANSION );
140+
141+ // Construct copied (and possibly damaged) copy of aad.
142+ auto dec_aad = in_aad;
143+ if (error == 10 ) {
144+ if (in_aad.size () == 0 ) continue ;
145+ dec_aad[InsecureRandRange (dec_aad.size ())] ^= std::byte (1U << InsecureRandRange (8 ));
146+ }
147+ if (error == 11 ) dec_aad.push_back ({});
148+
149+ // Decrypt contents.
150+ std::vector<std::byte> decrypted (dec_len);
151+ bool dec_ignore{false };
152+ bool dec_ok = dec_cipher.Decrypt (Span{to_decrypt}.subspan (cipher.LENGTH_LEN ), dec_aad, dec_ignore, decrypted);
153+
154+ // Verify result.
155+ BOOST_CHECK (dec_ok == !error);
156+ if (dec_ok) {
157+ BOOST_CHECK (decrypted == contents);
158+ BOOST_CHECK (dec_ignore == in_ignore);
159+ }
160+ }
99161}
100162
101163} // namespace
0 commit comments