test_crypto.c (23830B)
1 /* 2 This file is part of TALER 3 (C) 2015, 2020-2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 /** 18 * @file util/test_crypto.c 19 * @brief Tests for Taler-specific crypto logic 20 * @author Christian Grothoff <christian@grothoff.org> 21 */ 22 #include "taler/taler_util.h" 23 24 25 /** 26 * Test high-level link encryption/decryption API. 27 * 28 * @return 0 on success 29 */ 30 static int 31 test_high_level (void) 32 { 33 struct TALER_CoinSpendPrivateKeyP coin_priv; 34 struct TALER_CoinSpendPublicKeyP coin_pub; 35 struct TALER_TransferPrivateKeyP trans_priv; 36 struct TALER_TransferPublicKeyP trans_pub; 37 struct TALER_TransferSecretP secret; 38 struct TALER_TransferSecretP secret2; 39 union GNUNET_CRYPTO_BlindingSecretP bks1; 40 union GNUNET_CRYPTO_BlindingSecretP bks2; 41 struct TALER_CoinSpendPrivateKeyP coin_priv1; 42 struct TALER_CoinSpendPrivateKeyP coin_priv2; 43 struct TALER_PlanchetMasterSecretP ps1; 44 struct TALER_PlanchetMasterSecretP ps2; 45 struct GNUNET_CRYPTO_BlindingInputValues bi = { 46 .cipher = GNUNET_CRYPTO_BSA_RSA 47 }; 48 struct TALER_ExchangeBlindingValues alg1 = { 49 .blinding_inputs = &bi 50 }; 51 struct TALER_ExchangeBlindingValues alg2 = { 52 .blinding_inputs = &bi 53 }; 54 55 GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv); 56 GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv, 57 &coin_pub.eddsa_pub); 58 GNUNET_CRYPTO_ecdhe_key_create (&trans_priv.ecdhe_priv); 59 GNUNET_CRYPTO_ecdhe_key_get_public (&trans_priv.ecdhe_priv, 60 &trans_pub.ecdhe_pub); 61 TALER_link_derive_transfer_secret (&coin_priv, 62 &trans_priv, 63 &secret); 64 TALER_link_reveal_transfer_secret (&trans_priv, 65 &coin_pub, 66 &secret2); 67 GNUNET_assert (0 == 68 GNUNET_memcmp (&secret, 69 &secret2)); 70 TALER_link_recover_transfer_secret (&trans_pub, 71 &coin_priv, 72 &secret2); 73 GNUNET_assert (0 == 74 GNUNET_memcmp (&secret, 75 &secret2)); 76 TALER_transfer_secret_to_planchet_secret (&secret, 77 0, 78 &ps1); 79 TALER_planchet_setup_coin_priv (&ps1, 80 &alg1, 81 &coin_priv1); 82 TALER_planchet_blinding_secret_create (&ps1, 83 &alg1, 84 &bks1); 85 TALER_transfer_secret_to_planchet_secret (&secret, 86 1, 87 &ps2); 88 TALER_planchet_setup_coin_priv (&ps2, 89 &alg2, 90 &coin_priv2); 91 TALER_planchet_blinding_secret_create (&ps2, 92 &alg2, 93 &bks2); 94 GNUNET_assert (0 != 95 GNUNET_memcmp (&ps1, 96 &ps2)); 97 GNUNET_assert (0 != 98 GNUNET_memcmp (&coin_priv1, 99 &coin_priv2)); 100 GNUNET_assert (0 != 101 GNUNET_memcmp (&bks1, 102 &bks2)); 103 return 0; 104 } 105 106 107 static struct TALER_AgeMask age_mask = { 108 .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12 109 | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21 110 }; 111 112 /** 113 * Test the basic planchet functionality of creating a fresh planchet 114 * and extracting the respective signature. 115 * 116 * @return 0 on success 117 */ 118 static int 119 test_planchets_rsa (uint8_t age) 120 { 121 struct TALER_PlanchetMasterSecretP ps; 122 struct TALER_CoinSpendPrivateKeyP coin_priv; 123 union GNUNET_CRYPTO_BlindingSecretP bks; 124 struct TALER_DenominationPrivateKey dk_priv; 125 struct TALER_DenominationPublicKey dk_pub; 126 const struct TALER_ExchangeBlindingValues *alg_values; 127 struct TALER_PlanchetDetail pd; 128 struct TALER_BlindedDenominationSignature blind_sig; 129 struct TALER_FreshCoin coin; 130 struct TALER_CoinPubHashP c_hash; 131 struct TALER_AgeCommitmentHashP *ach = NULL; 132 struct TALER_AgeCommitmentHashP ah = {0}; 133 134 alg_values = TALER_denom_ewv_rsa_singleton (); 135 if (0 < age) 136 { 137 struct TALER_AgeCommitmentProof acp; 138 struct GNUNET_HashCode seed; 139 140 GNUNET_CRYPTO_random_block (&seed, 141 sizeof(seed)); 142 TALER_age_restriction_commit (&age_mask, 143 age, 144 &seed, 145 &acp); 146 TALER_age_commitment_hash (&acp.commitment, 147 &ah); 148 ach = &ah; 149 TALER_age_commitment_proof_free (&acp); 150 } 151 152 GNUNET_CRYPTO_random_block (&ps, 153 sizeof (ps)); 154 GNUNET_log_skip (1, GNUNET_YES); 155 GNUNET_assert (GNUNET_SYSERR == 156 TALER_denom_priv_create (&dk_priv, 157 &dk_pub, 158 GNUNET_CRYPTO_BSA_INVALID)); 159 GNUNET_log_skip (1, GNUNET_YES); 160 GNUNET_assert (GNUNET_SYSERR == 161 TALER_denom_priv_create (&dk_priv, 162 &dk_pub, 163 42)); 164 165 GNUNET_assert (GNUNET_OK == 166 TALER_denom_priv_create (&dk_priv, 167 &dk_pub, 168 GNUNET_CRYPTO_BSA_RSA, 169 1024)); 170 TALER_planchet_setup_coin_priv (&ps, 171 alg_values, 172 &coin_priv); 173 TALER_planchet_blinding_secret_create (&ps, 174 alg_values, 175 &bks); 176 GNUNET_assert (GNUNET_OK == 177 TALER_planchet_prepare (&dk_pub, 178 alg_values, 179 &bks, 180 NULL, 181 &coin_priv, 182 ach, 183 &c_hash, 184 &pd)); 185 GNUNET_assert (GNUNET_OK == 186 TALER_denom_sign_blinded (&blind_sig, 187 &dk_priv, 188 false, 189 &pd.blinded_planchet)); 190 TALER_planchet_detail_free (&pd); 191 GNUNET_assert (GNUNET_OK == 192 TALER_planchet_to_coin (&dk_pub, 193 &blind_sig, 194 &bks, 195 &coin_priv, 196 ach, 197 &c_hash, 198 alg_values, 199 &coin)); 200 TALER_blinded_denom_sig_free (&blind_sig); 201 TALER_denom_sig_free (&coin.sig); 202 TALER_denom_priv_free (&dk_priv); 203 TALER_denom_pub_free (&dk_pub); 204 return 0; 205 } 206 207 208 /** 209 * Test the basic planchet functionality of creating a fresh planchet with CS denomination 210 * and extracting the respective signature. 211 * 212 * @return 0 on success 213 */ 214 static int 215 test_planchets_cs (uint8_t age) 216 { 217 struct TALER_WithdrawMasterSeedP seed; 218 struct TALER_BlindingMasterSeedP blinding_seed; 219 struct TALER_PlanchetMasterSecretP ps; 220 struct TALER_CoinSpendPrivateKeyP coin_priv; 221 union GNUNET_CRYPTO_BlindingSecretP bks; 222 struct TALER_DenominationPrivateKey dk_priv; 223 struct TALER_DenominationPublicKey dk_pub; 224 struct TALER_PlanchetDetail pd; 225 struct TALER_CoinPubHashP c_hash; 226 union GNUNET_CRYPTO_BlindSessionNonce nonce; 227 struct TALER_BlindedDenominationSignature blind_sig; 228 struct TALER_FreshCoin coin; 229 struct TALER_ExchangeBlindingValues alg_values; 230 struct TALER_AgeCommitmentHashP *ach = NULL; 231 struct TALER_AgeCommitmentHashP ah = {0}; 232 const uint32_t coin_offset = 0; 233 234 if (0 < age) 235 { 236 struct TALER_AgeCommitmentProof acp; 237 struct GNUNET_HashCode seed; 238 239 GNUNET_CRYPTO_random_block (&seed, 240 sizeof(seed)); 241 TALER_age_restriction_commit (&age_mask, 242 age, 243 &seed, 244 &acp); 245 TALER_age_commitment_hash (&acp.commitment, 246 &ah); 247 ach = &ah; 248 TALER_age_commitment_proof_free (&acp); 249 } 250 251 TALER_withdraw_master_seed_setup_random (&seed); 252 TALER_withdraw_expand_secrets (1, 253 &seed, 254 &ps); 255 TALER_cs_withdraw_seed_to_blinding_seed (&seed, 256 &blinding_seed); 257 GNUNET_assert (GNUNET_OK == 258 TALER_denom_priv_create (&dk_priv, 259 &dk_pub, 260 GNUNET_CRYPTO_BSA_CS)); 261 TALER_cs_derive_only_cs_blind_nonces_from_seed ( 262 &blinding_seed, 263 false, 264 1, 265 &coin_offset, 266 &nonce); 267 // FIXME: define Taler abstraction for this: 268 alg_values.blinding_inputs 269 = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key, 270 &nonce, 271 "rw"); 272 TALER_denom_pub_hash (&dk_pub, 273 &pd.denom_pub_hash); 274 TALER_planchet_setup_coin_priv (&ps, 275 &alg_values, 276 &coin_priv); 277 TALER_planchet_blinding_secret_create (&ps, 278 &alg_values, 279 &bks); 280 GNUNET_assert (GNUNET_OK == 281 TALER_planchet_prepare (&dk_pub, 282 &alg_values, 283 &bks, 284 &nonce, 285 &coin_priv, 286 ach, 287 &c_hash, 288 &pd)); 289 GNUNET_assert (GNUNET_OK == 290 TALER_denom_sign_blinded (&blind_sig, 291 &dk_priv, 292 false, 293 &pd.blinded_planchet)); 294 GNUNET_assert (GNUNET_OK == 295 TALER_planchet_to_coin (&dk_pub, 296 &blind_sig, 297 &bks, 298 &coin_priv, 299 ach, 300 &c_hash, 301 &alg_values, 302 &coin)); 303 TALER_blinded_denom_sig_free (&blind_sig); 304 TALER_denom_sig_free (&coin.sig); 305 TALER_denom_priv_free (&dk_priv); 306 TALER_denom_pub_free (&dk_pub); 307 return 0; 308 } 309 310 311 /** 312 * Test the basic planchet functionality of creating a fresh planchet 313 * and extracting the respective signature. 314 * Calls test_planchets_rsa and test_planchets_cs 315 * 316 * @return 0 on success 317 */ 318 static int 319 test_planchets (uint8_t age) 320 { 321 if (0 != test_planchets_rsa (age)) 322 return -1; 323 return test_planchets_cs (age); 324 } 325 326 327 static int 328 test_exchange_sigs (void) 329 { 330 const struct TALER_FullPayto pt = { 331 .full_payto 332 = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC" 333 }; 334 const struct TALER_FullPayto pto = { 335 .full_payto 336 = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH" 337 }; 338 struct TALER_MasterPrivateKeyP priv; 339 struct TALER_MasterPublicKeyP pub; 340 struct TALER_MasterSignatureP sig; 341 json_t *rest; 342 343 GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); 344 rest = json_array (); 345 GNUNET_assert (NULL != rest); 346 TALER_exchange_wire_signature_make (pt, 347 NULL, 348 "https://example.com/", 349 NULL, 350 rest, 351 rest, 352 &priv, 353 &sig); 354 GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, 355 &pub.eddsa_pub); 356 if (GNUNET_OK != 357 TALER_exchange_wire_signature_check (pt, 358 NULL, 359 "https://example.com/", 360 NULL, 361 rest, 362 rest, 363 &pub, 364 &sig)) 365 { 366 GNUNET_break (0); 367 return 1; 368 } 369 if (GNUNET_OK == 370 TALER_exchange_wire_signature_check ( 371 pto, 372 NULL, 373 "https://example.com/", 374 NULL, 375 rest, 376 rest, 377 &pub, 378 &sig)) 379 { 380 GNUNET_break (0); 381 return 1; 382 } 383 if (GNUNET_OK == 384 TALER_exchange_wire_signature_check ( 385 pt, 386 "http://example.com/", 387 NULL, 388 NULL, 389 rest, 390 rest, 391 &pub, 392 &sig)) 393 { 394 GNUNET_break (0); 395 return 1; 396 } 397 json_decref (rest); 398 return 0; 399 } 400 401 402 /** 403 * Private key used by #test_sign_cb(). 404 */ 405 static struct TALER_ExchangePrivateKeyP test_exchange_priv; 406 407 408 /** 409 * Sign @a purpose with #test_exchange_priv, standing in for 410 * the exchange's signing helper. 411 * 412 * @param purpose message to sign 413 * @param[out] pub set to the public key of #test_exchange_priv 414 * @param[out] sig set to the signature 415 * @return #TALER_EC_NONE 416 */ 417 static enum TALER_ErrorCode 418 test_sign_cb (const struct GNUNET_CRYPTO_SignaturePurpose *purpose, 419 struct TALER_ExchangePublicKeyP *pub, 420 struct TALER_ExchangeSignatureP *sig) 421 { 422 GNUNET_CRYPTO_eddsa_key_get_public (&test_exchange_priv.eddsa_priv, 423 &pub->eddsa_pub); 424 GNUNET_CRYPTO_eddsa_sign_ (&test_exchange_priv.eddsa_priv, 425 purpose, 426 &sig->eddsa_signature); 427 return TALER_EC_NONE; 428 } 429 430 431 /** 432 * Test the batch recoup confirmation signatures and the hash 433 * over the recouped coins they cover. 434 * 435 * @return 0 on success 436 */ 437 static int 438 test_recoup_batch_sigs (void) 439 { 440 struct TALER_RecoupedCoin recoups[3]; 441 struct TALER_RecoupedCoin swapped[3]; 442 struct GNUNET_HashCode h_recoups; 443 struct GNUNET_HashCode h_swapped; 444 struct TALER_Amount total; 445 struct TALER_ReservePublicKeyP reserve_pub; 446 struct TALER_HashBlindedPlanchetsP planchets_h; 447 struct TALER_CoinSpendPublicKeyP old_coin_pub; 448 struct TALER_RefreshCommitmentP rc; 449 struct GNUNET_TIME_Timestamp ts; 450 struct TALER_ExchangePublicKeyP pub; 451 struct TALER_ExchangeSignatureP sig; 452 453 GNUNET_CRYPTO_eddsa_key_create (&test_exchange_priv.eddsa_priv); 454 GNUNET_assert (GNUNET_OK == 455 TALER_amount_set_zero ("EUR", 456 &total)); 457 for (unsigned int i = 0; i < 3; i++) 458 { 459 GNUNET_CRYPTO_random_block (&recoups[i].coin_pub, 460 sizeof (recoups[i].coin_pub)); 461 GNUNET_assert (GNUNET_OK == 462 TALER_string_to_amount ("EUR:1.5", 463 &recoups[i].amount)); 464 GNUNET_assert (0 <= 465 TALER_amount_add (&total, 466 &total, 467 &recoups[i].amount)); 468 } 469 GNUNET_CRYPTO_random_block (&reserve_pub, 470 sizeof (reserve_pub)); 471 GNUNET_CRYPTO_random_block (&planchets_h, 472 sizeof (planchets_h)); 473 GNUNET_CRYPTO_random_block (&old_coin_pub, 474 sizeof (old_coin_pub)); 475 GNUNET_CRYPTO_random_block (&rc, 476 sizeof (rc)); 477 ts = GNUNET_TIME_timestamp_get (); 478 479 /* the hash must depend on the order of the coins */ 480 TALER_recoup_batch_hash (3, 481 recoups, 482 &h_recoups); 483 swapped[0] = recoups[1]; 484 swapped[1] = recoups[0]; 485 swapped[2] = recoups[2]; 486 TALER_recoup_batch_hash (3, 487 swapped, 488 &h_swapped); 489 if (0 == 490 GNUNET_memcmp (&h_recoups, 491 &h_swapped)) 492 { 493 GNUNET_break (0); 494 return 1; 495 } 496 497 /* withdraw batch confirmation */ 498 if (TALER_EC_NONE != 499 TALER_exchange_online_confirm_recoup_withdraw_batch_sign ( 500 &test_sign_cb, 501 ts, 502 &reserve_pub, 503 &planchets_h, 504 &total, 505 &h_recoups, 506 &pub, 507 &sig)) 508 { 509 GNUNET_break (0); 510 return 1; 511 } 512 if (GNUNET_OK != 513 TALER_exchange_online_confirm_recoup_withdraw_batch_verify ( 514 ts, 515 &reserve_pub, 516 &planchets_h, 517 &total, 518 &h_recoups, 519 &pub, 520 &sig)) 521 { 522 GNUNET_break (0); 523 return 1; 524 } 525 if (GNUNET_OK == 526 TALER_exchange_online_confirm_recoup_withdraw_batch_verify ( 527 ts, 528 &reserve_pub, 529 &planchets_h, 530 &total, 531 &h_swapped, 532 &pub, 533 &sig)) 534 { 535 GNUNET_break (0); 536 return 1; 537 } 538 if (GNUNET_OK == 539 TALER_exchange_online_confirm_recoup_withdraw_batch_verify ( 540 ts, 541 &reserve_pub, 542 &planchets_h, 543 &recoups[0].amount, 544 &h_recoups, 545 &pub, 546 &sig)) 547 { 548 GNUNET_break (0); 549 return 1; 550 } 551 552 /* refresh batch confirmation */ 553 if (TALER_EC_NONE != 554 TALER_exchange_online_confirm_recoup_refresh_batch_sign ( 555 &test_sign_cb, 556 ts, 557 &old_coin_pub, 558 &rc, 559 &total, 560 &h_recoups, 561 &pub, 562 &sig)) 563 { 564 GNUNET_break (0); 565 return 1; 566 } 567 if (GNUNET_OK != 568 TALER_exchange_online_confirm_recoup_refresh_batch_verify ( 569 ts, 570 &old_coin_pub, 571 &rc, 572 &total, 573 &h_recoups, 574 &pub, 575 &sig)) 576 { 577 GNUNET_break (0); 578 return 1; 579 } 580 if (GNUNET_OK == 581 TALER_exchange_online_confirm_recoup_refresh_batch_verify ( 582 GNUNET_TIME_timestamp_get (), 583 &old_coin_pub, 584 &rc, 585 &total, 586 &h_recoups, 587 &pub, 588 &sig)) 589 { 590 /* only fails if the clock did not advance; tolerate that */ 591 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 592 "timestamp did not change, skipping negative check\n"); 593 } 594 return 0; 595 } 596 597 598 static int 599 test_merchant_sigs (void) 600 { 601 const struct TALER_FullPayto pt = { 602 .full_payto 603 = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC" 604 }; 605 const struct TALER_FullPayto pto = { 606 .full_payto 607 = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH" 608 }; 609 struct TALER_WireSaltP salt; 610 struct TALER_MerchantPrivateKeyP priv; 611 struct TALER_MerchantPublicKeyP pub; 612 struct TALER_MerchantSignatureP sig; 613 614 GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); 615 memset (&salt, 616 42, 617 sizeof (salt)); 618 TALER_merchant_wire_signature_make (pt, 619 &salt, 620 &priv, 621 &sig); 622 GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, 623 &pub.eddsa_pub); 624 if (GNUNET_OK != 625 TALER_merchant_wire_signature_check (pt, 626 &salt, 627 &pub, 628 &sig)) 629 { 630 GNUNET_break (0); 631 return 1; 632 } 633 if (GNUNET_OK == 634 TALER_merchant_wire_signature_check ( 635 pto, 636 &salt, 637 &pub, 638 &sig)) 639 { 640 GNUNET_break (0); 641 return 1; 642 } 643 memset (&salt, 644 43, 645 sizeof (salt)); 646 if (GNUNET_OK == 647 TALER_merchant_wire_signature_check (pt, 648 &salt, 649 &pub, 650 &sig)) 651 { 652 GNUNET_break (0); 653 return 1; 654 } 655 return 0; 656 } 657 658 659 static int 660 test_contracts (void) 661 { 662 struct TALER_ContractDiffiePrivateP cpriv; 663 struct TALER_PurseContractPublicKeyP purse_pub; 664 struct TALER_PurseContractPrivateKeyP purse_priv; 665 void *econtract; 666 size_t econtract_size; 667 struct TALER_PurseMergePrivateKeyP mpriv_in; 668 struct TALER_PurseMergePrivateKeyP mpriv_out; 669 json_t *c; 670 671 GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv); 672 GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv); 673 GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv, 674 &purse_pub.eddsa_pub); 675 memset (&mpriv_in, 676 42, 677 sizeof (mpriv_in)); 678 c = json_pack ("{s:s}", "test", "value"); 679 GNUNET_assert (NULL != c); 680 TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub, 681 &cpriv, 682 &mpriv_in, 683 c, 684 &econtract, 685 &econtract_size); 686 json_decref (c); 687 c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv, 688 &purse_pub, 689 econtract, 690 econtract_size, 691 &mpriv_out); 692 GNUNET_free (econtract); 693 if (NULL == c) 694 return 1; 695 json_decref (c); 696 if (0 != GNUNET_memcmp (&mpriv_in, 697 &mpriv_out)) 698 return 1; 699 return 0; 700 } 701 702 703 static int 704 test_attributes (void) 705 { 706 struct TALER_AttributeEncryptionKeyP key; 707 void *eattr; 708 size_t eattr_size; 709 json_t *c; 710 711 GNUNET_CRYPTO_random_block (&key, 712 sizeof (key)); 713 c = json_pack ("{s:s}", "test", "value"); 714 GNUNET_assert (NULL != c); 715 TALER_CRYPTO_kyc_attributes_encrypt (&key, 716 c, 717 &eattr, 718 &eattr_size); 719 json_decref (c); 720 c = TALER_CRYPTO_kyc_attributes_decrypt (&key, 721 eattr, 722 eattr_size); 723 GNUNET_free (eattr); 724 if (NULL == c) 725 { 726 GNUNET_break (0); 727 return 1; 728 } 729 GNUNET_assert (0 == 730 strcmp ("value", 731 json_string_value (json_object_get (c, 732 "test")))); 733 json_decref (c); 734 return 0; 735 } 736 737 738 int 739 main (int argc, 740 const char *const argv[]) 741 { 742 (void) argc; 743 (void) argv; 744 GNUNET_log_setup ("test-crypto", 745 "WARNING", 746 NULL); 747 if (0 != test_high_level ()) 748 return 1; 749 if (0 != test_planchets (0)) 750 return 2; 751 if (0 != test_planchets (13)) 752 return 3; 753 if (0 != test_exchange_sigs ()) 754 return 4; 755 if (0 != test_recoup_batch_sigs ()) 756 return 9; 757 if (0 != test_merchant_sigs ()) 758 return 5; 759 if (0 != test_contracts ()) 760 return 6; 761 if (0 != test_attributes ()) 762 return 7; 763 return 0; 764 } 765 766 767 /* end of test_crypto.c */