77//! Based on: Basu, A. (2026). "Tool Receipts, Not Zero-Knowledge Proofs:
88//! Practical Hallucination Detection for AI Agents." arXiv:2603.10060
99
10- use base64:: engine:: general_purpose:: URL_SAFE_NO_PAD ;
1110use base64:: Engine ;
11+ use base64:: engine:: general_purpose:: URL_SAFE_NO_PAD ;
1212use hmac:: { Hmac , Mac } ;
1313use sha2:: Sha256 ;
1414
@@ -132,16 +132,16 @@ mod tests {
132132
133133 #[ test]
134134 fn receipt_generation_deterministic ( ) {
135- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
136- let r1 = gen . generate ( "shell" , & test_args ( ) , "Mon Mar 27" , 1_711_547_700 ) ;
137- let r2 = gen . generate ( "shell" , & test_args ( ) , "Mon Mar 27" , 1_711_547_700 ) ;
135+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
136+ let r1 = receipt_gen . generate ( "shell" , & test_args ( ) , "Mon Mar 27" , 1_711_547_700 ) ;
137+ let r2 = receipt_gen . generate ( "shell" , & test_args ( ) , "Mon Mar 27" , 1_711_547_700 ) ;
138138 assert_eq ! ( r1, r2) ;
139139 }
140140
141141 #[ test]
142142 fn receipt_format_parseable ( ) {
143- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
144- let receipt = gen . generate ( "shell" , & test_args ( ) , "output" , 1_711_547_700 ) ;
143+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
144+ let receipt = receipt_gen . generate ( "shell" , & test_args ( ) , "output" , 1_711_547_700 ) ;
145145 assert ! ( receipt. starts_with( "zc-receipt-1711547700-" ) ) ;
146146 let ( ts, hash) = parse_receipt ( & receipt) . unwrap ( ) ;
147147 assert_eq ! ( ts, 1_711_547_700 ) ;
@@ -150,89 +150,89 @@ mod tests {
150150
151151 #[ test]
152152 fn receipt_verification_succeeds ( ) {
153- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
153+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
154154 let args = test_args ( ) ;
155- let receipt = gen . generate ( "shell" , & args, "output" , 1_711_547_700 ) ;
156- assert ! ( gen . verify( & receipt, "shell" , & args, "output" ) ) ;
155+ let receipt = receipt_gen . generate ( "shell" , & args, "output" , 1_711_547_700 ) ;
156+ assert ! ( receipt_gen . verify( & receipt, "shell" , & args, "output" ) ) ;
157157 }
158158
159159 #[ test]
160160 fn receipt_verification_fails_tampered_result ( ) {
161- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
161+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
162162 let args = test_args ( ) ;
163- let receipt = gen . generate ( "shell" , & args, "real output" , 1_711_547_700 ) ;
164- assert ! ( !gen . verify( & receipt, "shell" , & args, "fake output" ) ) ;
163+ let receipt = receipt_gen . generate ( "shell" , & args, "real output" , 1_711_547_700 ) ;
164+ assert ! ( !receipt_gen . verify( & receipt, "shell" , & args, "fake output" ) ) ;
165165 }
166166
167167 #[ test]
168168 fn receipt_verification_fails_tampered_name ( ) {
169- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
169+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
170170 let args = test_args ( ) ;
171- let receipt = gen . generate ( "shell" , & args, "output" , 1_711_547_700 ) ;
172- assert ! ( !gen . verify( & receipt, "web_search" , & args, "output" ) ) ;
171+ let receipt = receipt_gen . generate ( "shell" , & args, "output" , 1_711_547_700 ) ;
172+ assert ! ( !receipt_gen . verify( & receipt, "web_search" , & args, "output" ) ) ;
173173 }
174174
175175 #[ test]
176176 fn receipt_verification_fails_wrong_key ( ) {
177- let gen1 = ReceiptGenerator :: with_key ( vec ! [ 1u8 ; 32 ] ) ;
178- let gen2 = ReceiptGenerator :: with_key ( vec ! [ 2u8 ; 32 ] ) ;
177+ let receipt_gen1 = ReceiptGenerator :: with_key ( vec ! [ 1u8 ; 32 ] ) ;
178+ let receipt_gen2 = ReceiptGenerator :: with_key ( vec ! [ 2u8 ; 32 ] ) ;
179179 let args = test_args ( ) ;
180- let receipt = gen1 . generate ( "shell" , & args, "output" , 1_711_547_700 ) ;
181- assert ! ( !gen2 . verify( & receipt, "shell" , & args, "output" ) ) ;
180+ let receipt = receipt_gen1 . generate ( "shell" , & args, "output" , 1_711_547_700 ) ;
181+ assert ! ( !receipt_gen2 . verify( & receipt, "shell" , & args, "output" ) ) ;
182182 }
183183
184184 #[ test]
185185 fn fabricated_receipt_fails_verification ( ) {
186- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
186+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
187187 let args = test_args ( ) ;
188188 let fake = "zc-receipt-1_711_547_700-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ;
189- assert ! ( !gen . verify( fake, "shell" , & args, "output" ) ) ;
189+ assert ! ( !receipt_gen . verify( fake, "shell" , & args, "output" ) ) ;
190190 }
191191
192192 #[ test]
193193 fn malformed_receipt_fails_verification ( ) {
194- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
194+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
195195 let args = test_args ( ) ;
196- assert ! ( !gen . verify( "not-a-receipt" , "shell" , & args, "output" ) ) ;
197- assert ! ( !gen . verify( "zc-receipt-" , "shell" , & args, "output" ) ) ;
198- assert ! ( !gen . verify( "zc-receipt-abc-hash" , "shell" , & args, "output" ) ) ;
199- assert ! ( !gen . verify( "zc-receipt-123-" , "shell" , & args, "output" ) ) ;
196+ assert ! ( !receipt_gen . verify( "not-a-receipt" , "shell" , & args, "output" ) ) ;
197+ assert ! ( !receipt_gen . verify( "zc-receipt-" , "shell" , & args, "output" ) ) ;
198+ assert ! ( !receipt_gen . verify( "zc-receipt-abc-hash" , "shell" , & args, "output" ) ) ;
199+ assert ! ( !receipt_gen . verify( "zc-receipt-123-" , "shell" , & args, "output" ) ) ;
200200 }
201201
202202 #[ test]
203203 fn receipt_from_different_tool_fails ( ) {
204- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
204+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
205205 let args_a = serde_json:: json!( { "query" : "rust" } ) ;
206206 let args_b = serde_json:: json!( { "path" : "/tmp" } ) ;
207- let receipt = gen . generate ( "web_search" , & args_a, "results" , 1_711_547_700 ) ;
208- assert ! ( !gen . verify( & receipt, "file_read" , & args_b, "results" ) ) ;
207+ let receipt = receipt_gen . generate ( "web_search" , & args_a, "results" , 1_711_547_700 ) ;
208+ assert ! ( !receipt_gen . verify( & receipt, "file_read" , & args_b, "results" ) ) ;
209209 }
210210
211211 #[ test]
212212 fn receipt_with_modified_args_fails ( ) {
213- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
213+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
214214 let args_real = serde_json:: json!( { "command" : "date" } ) ;
215215 let args_fake = serde_json:: json!( { "command" : "rm -rf /" } ) ;
216- let receipt = gen . generate ( "shell" , & args_real, "Mon Mar 27" , 1_711_547_700 ) ;
217- assert ! ( !gen . verify( & receipt, "shell" , & args_fake, "Mon Mar 27" ) ) ;
216+ let receipt = receipt_gen . generate ( "shell" , & args_real, "Mon Mar 27" , 1_711_547_700 ) ;
217+ assert ! ( !receipt_gen . verify( & receipt, "shell" , & args_fake, "Mon Mar 27" ) ) ;
218218 }
219219
220220 #[ test]
221221 fn generate_now_produces_valid_receipt ( ) {
222- let gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
222+ let receipt_gen = ReceiptGenerator :: with_key ( test_key ( ) ) ;
223223 let args = test_args ( ) ;
224- let receipt = gen . generate_now ( "shell" , & args, "output" ) ;
224+ let receipt = receipt_gen . generate_now ( "shell" , & args, "output" ) ;
225225 assert ! ( receipt. starts_with( "zc-receipt-" ) ) ;
226- assert ! ( gen . verify( & receipt, "shell" , & args, "output" ) ) ;
226+ assert ! ( receipt_gen . verify( & receipt, "shell" , & args, "output" ) ) ;
227227 }
228228
229229 #[ test]
230230 fn new_generates_random_key ( ) {
231- let gen1 = ReceiptGenerator :: new ( ) ;
232- let gen2 = ReceiptGenerator :: new ( ) ;
231+ let receipt_gen1 = ReceiptGenerator :: new ( ) ;
232+ let receipt_gen2 = ReceiptGenerator :: new ( ) ;
233233 let args = test_args ( ) ;
234- let r1 = gen1 . generate ( "shell" , & args, "out" , 100 ) ;
235- let r2 = gen2 . generate ( "shell" , & args, "out" , 100 ) ;
234+ let r1 = receipt_gen1 . generate ( "shell" , & args, "out" , 100 ) ;
235+ let r2 = receipt_gen2 . generate ( "shell" , & args, "out" , 100 ) ;
236236 // Different keys → different receipts (probabilistically)
237237 assert_ne ! ( r1, r2) ;
238238 }
0 commit comments