aboutsummaryrefslogtreecommitdiff
path: root/tests/test-ecdsa.py
blob: 4c14d9f910653fbacbb2befb384007289f4c10da (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# Test vectors from "Suite B Implementer's Guide to FIPS 186-3".
#
# e is given in decimal, all other values are hex, because that's how
# these were given in the paper

p256_d    = 0x70a12c2db16845ed56ff68cfc21a472b3f04d7d6851bf6349f2d7d5b3452b38a
p256_Qx   = 0x8101ece47464a6ead70cf69a6e2bd3d88691a3262d22cba4f7635eaff26680a8
p256_Qy   = 0xd8a12ba61d599235f67d9cb4d58f1783d3ca43e78f0a5abaa624079936c0c3a9
p256_k    = 0x580ec00d856434334cef3f71ecaed4965b12ae37fa47055b1965c7b134ee45d0
p256_kinv = 0x6a664fa115356d33f16331b54c4e7ce967965386c7dcbf2904604d0c132b4a74
p256_Rx   = 0x7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c
p256_Ry   = 0x8b81e3e977597110c7cf2633435b2294b72642987defd3d4007e1cfc5df84541
p256_r    = p256_Rx
p256_M    = 0x54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67
p256_H    = 0x7c3e883ddc8bd688f96eac5e9324222c8f30f9d6bb59e9c5f020bd39ba2b8377
p256_e    = 56197278047627432394583341962843287937266210957576322469816113796290471232375
p256_s    = 0x7d1ff961980f961bdaa3233b6209f4013317d3e3f9e1493592dbeaa1af2bc367
p256_w    = 0xd69be75f67ee5394cabb6c286f3610cf62d722cba9eea70faee770a6b2ed72dc
p256_u1   = 0xbb252401d6fb322bb747184cf2ac52bf8d54b95a1515062a2f6141f2e2092ed8
p256_u2   = 0xaae7d1c7f2c232dfc641948af3dba141d4de8634e571cf84c486301b510cfc04
p256_v    = 0x7214bc9647160bbd39ff2f80533f5dc6ddd70ddf86bb815661e805d5d4e6f27c

p384_d    = 0xc838b85253ef8dc7394fa5808a5183981c7deef5a69ba8f4f2117ffea39cfcd90e95f6cbc854abacab701d50c1f3cf24
p384_Qx   = 0x1fbac8eebd0cbf35640b39efe0808dd774debff20a2a329e91713baf7d7f3c3e81546d883730bee7e48678f857b02ca0
p384_Qy   = 0xeb213103bd68ce343365a8a4c3d4555fa385f5330203bdd76ffad1f3affb95751c132007e1b240353cb0a4cf1693bdf9
p384_k    = 0xdc6b44036989a196e39d1cdac000812f4bdd8b2db41bb33af51372585ebd1db63f0ce8275aa1fd45e2d2a735f8749359
p384_kinv = 0x7436f03088e65c37ba8e7b33887fbc87757514d611f7d1fbdf6d2104a297ad318cdbf7404e4ba37e599666df37b8d8be
p384_Rx   = 0xa0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856
p384_Ry   = 0x855649409815bb91424eaca5fd76c97375d575d1422ec53d343bd33b847fdf0c11569685b528ab25493015428d7cf72b
p384_r    = p384_Rx
p384_M    = 0x54686973206973206f6e6c7920612074657374206d6573736167652e204974206973203438206279746573206c6f6e67
p384_H    = 0xb9210c9d7e20897ab86597266a9d5077e8db1b06f7220ed6ee75bd8b45db37891f8ba5550304004159f4453dc5b3f5a1
p384_e    = 28493976155450475404302482243066463769180620629462008675793884393889401828800663731864240088367206094074919580333473
p384_s    = 0x20ab3f45b74f10b6e11f96a2c8eb694d206b9dda86d3c7e331c26b22c987b7537726577667adadf168ebbe803794a402
p384_w    = 0x1798845cd0a6cea5327c501a71a4baf2f7be882cfbc303750a7c861af8fe8225467a257f5bf91a4aaa5a79a8637d218a
p384_u1   = 0x6ce25649d42d223e020c11140fe772326612bb11b686d35ee98ed4550e0635d9dd3a2afbca0cf2c4baedcd23313b189e
p384_u2   = 0xf3b240751d5d8ed394a4b5bf8e2a4c0e1e21aa51f2620a08b8c55a2bc334c9689923162648f06e5f4659fc526d9c1fd6
p384_v    = 0xa0c27ec893092dea1e1bd2ccfed3cf945c8134ed0c9f81311a0f4a05942db8dbed8dd59f267471d5462aa14fe72de856

from textwrap                   import TextWrapper
from binascii                   import hexlify, unhexlify
from os.path                    import basename
from sys                        import argv
from pyasn1.type.univ           import Sequence, Choice, Integer, OctetString, ObjectIdentifier, BitString
from pyasn1.type.namedtype      import NamedTypes, NamedType, OptionalNamedType
from pyasn1.type.namedval       import NamedValues
from pyasn1.type.tag            import Tag, tagClassContext, tagFormatSimple
from pyasn1.type.constraint     import SingleValueConstraint
from pyasn1.codec.der.encoder   import encode as DER_Encode
from pyasn1.codec.der.decoder   import decode as DER_Decode

wrapper = TextWrapper(width = 78, initial_indent = " " * 2, subsequent_indent = " " * 2)

def long_to_bytes(number, order):
  #
  # This is just plain nasty.
  #
  s = "{:x}".format(number)
  s = ("0" * (order/8 - len(s))) + s
  return unhexlify(s)

def bytes_to_bits(b):
  #
  # This, on the other hand, is not just plain nasty, this is fancy nasty.
  # This is nasty with raisins in it.
  #
  s = bin(int(hexlify(b), 16))[2:]
  if len(s) % 8:
    s = ("0" * (8 - len(s) % 8)) + s
  return tuple(int(i) for i in s)

###

def encode_sig(r, s, order):
  return long_to_bytes(r, order) + long_to_bytes(s, order)

p256_sig = encode_sig(p256_r, p256_s, 256)
p384_sig = encode_sig(p384_r, p384_s, 384)

###

class ECPrivateKey(Sequence):
  componentType = NamedTypes(
    NamedType("version", Integer(namedValues = NamedValues(("ecPrivkeyVer1", 1))
                                 ).subtype(subtypeSpec = Integer.subtypeSpec + SingleValueConstraint(1))),
    NamedType("privateKey", OctetString()),
    OptionalNamedType("parameters", ObjectIdentifier().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 0))),
    OptionalNamedType("publicKey", BitString().subtype(explicitTag = Tag(tagClassContext, tagFormatSimple, 1))))

def encode_key(d, Qx, Qy, order, oid):
  private_key = long_to_bytes(d, order)
  public_key  = bytes_to_bits(chr(0x04) + long_to_bytes(Qx, order) + long_to_bytes(Qy, order))
  parameters = oid
  key = ECPrivateKey()
  key["version"]    = 1
  key["privateKey"] = private_key
  key["parameters"] = parameters
  key["publicKey"]  = public_key
  return DER_Encode(key)

p256_key = encode_key(p256_d, p256_Qx, p256_Qy, 256, "1.2.840.10045.3.1.7")
p384_key = encode_key(p384_d, p384_Qx, p384_Qy, 384, "1.3.132.0.34")

###

print("/*")
print(" * ECDSA test data.")
print(" * File automatically generated by", basename(argv[0]))
print(" */")

curves = ("p256", "p384")
vars   = set()

for name in dir():
  head, sep, tail = name.partition("_")
  if head in curves:
    vars.add(tail)

vars = sorted(vars)

for curve in curves:
  order = int(curve[1:])
  for var in vars:
    name = curve + "_" + var
    value = globals().get(name, None)
    if isinstance(value, int):
      value = long_to_bytes(value, order)
    if value is not None:
      value = hexlify(value).decode("ascii")
      print()
      print("static const uint8_t {}[] = {{ /* {:d} bytes */".format(name, len(value)))
      print(wrapper.fill(", ".join("0x" + value[i : i + 2] for i in range(0, len(value), 2))))
      print("};")

print()
print("typedef struct {")
print("  hal_curve_name_t curve;")
for var in vars:
  print("  const uint8_t *{0:>8}; size_t {0:>8}_len;".format(var))
print("} ecdsa_tc_t;")
print()
print("static const ecdsa_tc_t ecdsa_tc[] = {")
for curve in curves:
  print("  {{ HAL_CURVE_{},".format(curve.upper()))
  for var in vars:
    name = curve + "_" + var
    if name in globals():
      print("    {:<14} sizeof({}),".format(name + ",", name))
    else:
      print("    {:<14} 0,".format("NULL,"))
  print("  },")
print("};")