Reference implementations of PQC
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

146 righe
4.7 KiB

  1. """
  2. Verify the metadata specified in the META.yml files.
  3. """
  4. import copy
  5. import itertools
  6. import pytest
  7. import helpers
  8. import pqclean
  9. @pytest.mark.parametrize(
  10. 'scheme',
  11. pqclean.Scheme.all_schemes(),
  12. ids=str,
  13. )
  14. @helpers.filtered_test
  15. def test_metadata(scheme):
  16. metadata = scheme.metadata()
  17. specification = EXPECTED_FIELDS.items()
  18. if scheme.type == 'kem':
  19. specification = itertools.chain(specification, KEM_FIELDS.items())
  20. elif scheme.type == 'sign':
  21. specification = itertools.chain(specification,
  22. SIGNATURE_FIELDS.items())
  23. else:
  24. assert False, "Wrong type of metadata"
  25. check_spec(copy.deepcopy(metadata), specification)
  26. implementation_names_in_yaml = set(
  27. i['name'] for i in metadata['implementations'])
  28. if len(implementation_names_in_yaml) != len(metadata['implementations']):
  29. raise AssertionError("Implementations in YAML file are not distinct")
  30. implementations_on_disk = set(i.name for i in scheme.implementations)
  31. if implementation_names_in_yaml != implementations_on_disk:
  32. raise AssertionError("Implementations in YAML file {} and "
  33. "implementations on disk {} do not match"
  34. .format(implementation_names_in_yaml,
  35. implementations_on_disk))
  36. EXPECTED_FIELDS = {
  37. 'name': {'type': str},
  38. 'type': {'type': str},
  39. 'claimed-nist-level': {'type': int, 'min': 1, 'max': 5},
  40. 'length-public-key': {'type': int, 'min': 1},
  41. 'length-secret-key': {'type': int, 'min': 1},
  42. 'nistkat-sha256': {'type': str, 'length': 64},
  43. 'principal-submitters': {'type': list, 'elements': {'type': str}},
  44. 'auxiliary-submitters': {
  45. 'type': list, 'elements': {'type': str}, 'optional': True},
  46. 'implementations': {
  47. 'type': list,
  48. 'elements': {
  49. 'type': dict,
  50. 'spec': {
  51. 'name': {'type': str},
  52. 'version': {'type': str},
  53. },
  54. },
  55. },
  56. }
  57. KEM_FIELDS = {
  58. 'claimed-security': {'type': str, 'values': ['IND-CPA', 'IND-CCA2']},
  59. 'length-ciphertext': {'type': int, 'min': 1},
  60. 'length-shared-secret': {'type': int, 'min': 1},
  61. }
  62. SIGNATURE_FIELDS = {
  63. 'length-signature': {'type': int, 'min': 1},
  64. 'testvectors-sha256': {'type': str, 'length': 64},
  65. }
  66. def check_spec(metadata, spec):
  67. for field, props in spec:
  68. if field not in metadata and 'optional' not in props:
  69. raise AssertionError("Field '{}' not present.".format(field))
  70. # validate element
  71. if field in metadata:
  72. check_element(field, metadata[field], props)
  73. # delete it to detect extras
  74. del metadata[field]
  75. # Done checking all specified fields, check if we have extras
  76. for field, value in metadata.items():
  77. raise AssertionError(
  78. "Unexpected item '{}' with value '{}'".format(field, value))
  79. def check_element(field, element, props):
  80. type_ = props['type']
  81. # Validate type of element
  82. type_(element)
  83. # Strs are valid lists otherwise
  84. if type_ == list and type(element) != list:
  85. raise ValueError("Field {} not a list".format(field))
  86. # lists are valid dicts otherwise
  87. if type_ == dict and type(element) != dict:
  88. raise ValueError("Field {} not a dict".format(field))
  89. if type_ == int:
  90. element = int(element)
  91. if 'min' in props:
  92. if element < props['min']:
  93. raise ValueError("Value of field '{}' is lower than minimum "
  94. "value {}".format(field, props['min']))
  95. if 'max' in props:
  96. if element > props['max']:
  97. raise ValueError("Value of field '{}' is larger than maximum"
  98. " value {}"
  99. .format(field, props['max']))
  100. if type_ == str:
  101. if 'length' in props:
  102. actual_len = len(element)
  103. if actual_len != props['length']:
  104. raise ValueError("Value of field '{}' should be length {}"
  105. " but was length {}"
  106. .format(field, props['length'], actual_len))
  107. if 'values' in props and element not in props['values']:
  108. raise ValueError("'{}' should be in {}"
  109. .format(element, props['values']))
  110. if type_ == list: # recursively check the elements
  111. for el in element:
  112. check_element('element of {}'.format(field), el, props['elements'])
  113. if type_ == dict:
  114. check_spec(element, props['spec'].items())
  115. if __name__ == '__main__':
  116. import sys
  117. pytest.main(sys.argv)