您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

135 行
4.1 KiB

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