Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

135 linhas
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()