Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 

147 рядки
4.7 KiB

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