mldsa_wycheproof_parse.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env python
  2. # Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License 2.0 (the "License"). You may not use
  5. # this file except in compliance with the License. You can obtain a copy
  6. # in the file LICENSE in the source distribution or at
  7. # https://www.openssl.org/source/license.html
  8. # A python program written to parse (version 1) of the WYCHEPROOF test vectors for
  9. # ML_DSA. The 6 files that can be processed by this utility can be downloaded
  10. # from
  11. # https://github.com/C2SP/wycheproof/blob/8e7fa6f87e6993d7b613cf48b46512a32df8084a/testvectors_v1/mldsa_*_standard_*_test.json")
  12. # and output from this utility to
  13. # test/recipes/30-test_evp_data/evppkey_ml_dsa_44_wycheproof_sign.txt
  14. # test/recipes/30-test_evp_data/evppkey_ml_dsa_65_wycheproof_sign.txt
  15. # test/recipes/30-test_evp_data/evppkey_ml_dsa_87_wycheproof_sign.txt
  16. # test/recipes/30-test_evp_data/evppkey_ml_dsa_44_wycheproof_verify.txt
  17. # test/recipes/30-test_evp_data/evppkey_ml_dsa_65_wycheproof_verify.txt
  18. # test/recipes/30-test_evp_data/evppkey_ml_dsa_87_wycheproof_verify.txt
  19. #
  20. # e.g. python3 ./test/mldsa_wycheproof_parse.py -alg ML-DSA-44 ./wycheproof/testvectors_v1/mldsa_44_standard_sign_test.json > test/recipes/30-test_evp_data/evppkey_ml_dsa_44_wycheproof_sign.txt
  21. import json
  22. import argparse
  23. import datetime
  24. from _ast import Or
  25. def print_label(label, value):
  26. print(label + " = " + value)
  27. def print_hexlabel(label, tag, value):
  28. print(label + " = hex" + tag + ":" + value)
  29. def parse_ml_dsa_sig_gen(alg, groups):
  30. grpId = 1
  31. for grp in groups:
  32. keyOnly = False
  33. first = True
  34. name = alg.replace('-', '_')
  35. keyname = name + "_" + str(grpId)
  36. grpId += 1
  37. for tst in grp['tests']:
  38. if first:
  39. first = False
  40. if 'flags' in tst:
  41. if 'IncorrectPrivateKeyLength' in tst['flags'] or 'InvalidPrivateKey' in tst['flags']:
  42. keyOnly = True
  43. if not keyOnly:
  44. print("")
  45. print_label("PrivateKeyRaw", keyname + ":" + alg + ":" + grp['privateKey'])
  46. testname = name + "_" + str(tst['tcId'])
  47. print("\n# " + str(tst['tcId']) + " " + tst['comment'])
  48. print_label("FIPSversion", ">=3.5.0")
  49. if keyOnly:
  50. print_label("KeyFromData", alg)
  51. print_hexlabel("Ctrl", "priv", grp['privateKey'])
  52. print_label("Result", "KEY_FROMDATA_ERROR")
  53. else:
  54. print_label("Sign-Message", alg + ":" + keyname)
  55. print_label("Input", tst['msg'])
  56. print_label("Output", tst['sig'])
  57. if 'ctx' in tst:
  58. print_hexlabel("Ctrl", "context-string", tst['ctx'])
  59. print_label("Ctrl", "message-encoding:1")
  60. print_label("Ctrl", "deterministic:1")
  61. if tst['result'] == "invalid":
  62. print_label("Result", "PKEY_CTRL_ERROR")
  63. def parse_ml_dsa_sig_ver(alg, groups):
  64. grpId = 1
  65. for grp in groups:
  66. keyOnly = False
  67. first = True
  68. name = alg.replace('-', '_')
  69. keyname = name + "_" + str(grpId)
  70. grpId += 1
  71. for tst in grp['tests']:
  72. if first:
  73. first = False
  74. if 'flags' in tst:
  75. if 'IncorrectPublicKeyLength' in tst['flags'] or 'InvalidPublicKey' in tst['flags']:
  76. keyOnly = True
  77. if not keyOnly:
  78. print("")
  79. print_label("PublicKeyRaw", keyname + ":" + alg + ":" + grp['publicKey'])
  80. testname = name + "_" + str(tst['tcId'])
  81. print("\n# " + str(tst['tcId']) + " " + tst['comment'])
  82. print_label("FIPSversion", ">=3.5.0")
  83. if keyOnly:
  84. print_label("KeyFromData", alg)
  85. print_hexlabel("Ctrl", "pub", grp['publicKey'])
  86. print_label("Result", "KEY_FROMDATA_ERROR")
  87. else:
  88. print_label("Verify-Message-Public", alg + ":" + keyname)
  89. print_label("Input", tst['msg'])
  90. print_label("Output", tst['sig'])
  91. if 'ctx' in tst:
  92. print_hexlabel("Ctrl", "context-string", tst['ctx'])
  93. print_label("Ctrl", "message-encoding:1")
  94. print_label("Ctrl", "deterministic:1")
  95. if tst['result'] == "invalid":
  96. if 'InvalidContext' in tst['flags']:
  97. print_label("Result", "PKEY_CTRL_ERROR")
  98. else:
  99. print_label("Result", "VERIFY_ERROR")
  100. parser = argparse.ArgumentParser(description="")
  101. parser.add_argument('filename', type=str)
  102. parser.add_argument('-alg', type=str)
  103. args = parser.parse_args()
  104. # Open and read the JSON file
  105. with open(args.filename, 'r') as file:
  106. data = json.load(file)
  107. year = datetime.date.today().year
  108. version = data['generatorVersion']
  109. algorithm = data['algorithm']
  110. mode = data['testGroups'][0]['type']
  111. print("# Copyright " + str(year) + " The OpenSSL Project Authors. All Rights Reserved.")
  112. print("#")
  113. print("# Licensed under the Apache License 2.0 (the \"License\"). You may not use")
  114. print("# this file except in compliance with the License. You can obtain a copy")
  115. print("# in the file LICENSE in the source distribution or at")
  116. print("# https://www.openssl.org/source/license.html\n")
  117. print("# Wycheproof test data for " + algorithm + " " + mode + " generated from")
  118. print("# https://github.com/C2SP/wycheproof/blob/8e7fa6f87e6993d7b613cf48b46512a32df8084a/testvectors_v1/mldsa_*_standard_*_test.json")
  119. print("# [version " + str(version) + "]")
  120. if algorithm == "ML-DSA":
  121. if mode == 'MlDsaSign':
  122. parse_ml_dsa_sig_gen(args.alg, data['testGroups'])
  123. elif mode == 'MlDsaVerify':
  124. parse_ml_dsa_sig_ver(args.alg, data['testGroups'])
  125. else:
  126. print("Unsupported mode " + mode)
  127. else:
  128. print("Unsupported algorithm " + algorithm)