/ src / secp256k1 / tools / tests_wycheproof_generate_ecdsa.py
tests_wycheproof_generate_ecdsa.py
  1  #!/usr/bin/env python3
  2  # Copyright (c) 2023 Random "Randy" Lattice and Sean Andersen
  3  # Distributed under the MIT software license, see the accompanying
  4  # file COPYING or https://www.opensource.org/licenses/mit-license.php.
  5  '''
  6  Generate a C file with ECDSA testvectors from the Wycheproof project.
  7  '''
  8  
  9  import json
 10  import sys
 11  
 12  from wycheproof_utils import to_c_array
 13  
 14  filename_input = sys.argv[1]
 15  
 16  with open(filename_input) as f:
 17      doc = json.load(f)
 18  
 19  num_groups = len(doc['testGroups'])
 20  
 21  
 22  num_vectors = 0
 23  offset_msg_running, offset_pk_running, offset_sig = 0, 0, 0
 24  out = ""
 25  messages = ""
 26  signatures = ""
 27  public_keys = ""
 28  cache_msgs = {}
 29  cache_public_keys = {}
 30  
 31  for i in range(num_groups):
 32      group = doc['testGroups'][i]
 33      num_tests = len(group['tests'])
 34      public_key = group['publicKey']
 35      for j in range(num_tests):
 36          test_vector = group['tests'][j]
 37          # // 2 to convert hex to byte length
 38          sig_size = len(test_vector['sig']) // 2
 39          msg_size = len(test_vector['msg']) // 2
 40  
 41          if test_vector['result'] == "invalid":
 42              expected_verify = 0
 43          elif test_vector['result'] == "valid":
 44              expected_verify = 1
 45          else:
 46              raise ValueError("invalid result field")
 47  
 48          if num_vectors != 0 and sig_size != 0:
 49              signatures += ",\n  "
 50  
 51          new_msg = False
 52          msg = to_c_array(test_vector['msg'])
 53          msg_offset = offset_msg_running
 54          # check for repeated msg
 55          if msg not in cache_msgs:
 56              if num_vectors != 0 and msg_size != 0:
 57                  messages += ",\n  "
 58              cache_msgs[msg] = offset_msg_running
 59              messages += msg
 60              new_msg = True
 61          else:
 62              msg_offset = cache_msgs[msg]
 63  
 64          new_pk = False
 65          pk = to_c_array(public_key['uncompressed'])
 66          pk_offset = offset_pk_running
 67          # check for repeated pk
 68          if pk not in cache_public_keys:
 69              if num_vectors != 0:
 70                  public_keys += ",\n  "
 71              cache_public_keys[pk] = offset_pk_running
 72              public_keys += pk
 73              new_pk = True
 74          else:
 75              pk_offset = cache_public_keys[pk]
 76  
 77          signatures += to_c_array(test_vector['sig'])
 78  
 79          out += "  /" + "* tcId: " + str(test_vector['tcId']) + ". " + test_vector['comment'] + " *" + "/\n"
 80          out += f"  {{{pk_offset}, {msg_offset}, {msg_size}, {offset_sig}, {sig_size}, {expected_verify} }},\n"
 81          if new_msg:
 82              offset_msg_running += msg_size
 83          if new_pk:
 84              offset_pk_running += 65
 85          offset_sig += sig_size
 86          num_vectors += 1
 87  
 88  struct_definition = """
 89  typedef struct {
 90      size_t pk_offset;
 91      size_t msg_offset;
 92      size_t msg_len;
 93      size_t sig_offset;
 94      size_t sig_len;
 95      int expected_verify;
 96  } wycheproof_ecdsa_testvector;
 97  """
 98  
 99  
100  print("/* Note: this file was autogenerated using tests_wycheproof_generate_ecdsa.py. Do not edit. */")
101  print(f"#define SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS ({num_vectors})")
102  
103  print(struct_definition)
104  
105  print("static const unsigned char wycheproof_ecdsa_messages[]    = { " + messages + "};\n")
106  print("static const unsigned char wycheproof_ecdsa_public_keys[] = { " + public_keys + "};\n")
107  print("static const unsigned char wycheproof_ecdsa_signatures[]  = { " + signatures + "};\n")
108  
109  print("static const wycheproof_ecdsa_testvector testvectors[SECP256K1_ECDSA_WYCHEPROOF_NUMBER_TESTVECTORS] = {")
110  print(out)
111  print("};")