xref: /freebsd/crypto/libecc/scripts/expand_libecc.py (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1*f0865ec9SKyle Evans#/*
2*f0865ec9SKyle Evans# *  Copyright (C) 2017 - This file is part of libecc project
3*f0865ec9SKyle Evans# *
4*f0865ec9SKyle Evans# *  Authors:
5*f0865ec9SKyle Evans# *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans# *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans# *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8*f0865ec9SKyle Evans# *
9*f0865ec9SKyle Evans# *  Contributors:
10*f0865ec9SKyle Evans# *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11*f0865ec9SKyle Evans# *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12*f0865ec9SKyle Evans# *
13*f0865ec9SKyle Evans# *  This software is licensed under a dual BSD and GPL v2 license.
14*f0865ec9SKyle Evans# *  See LICENSE file at the root folder of the project.
15*f0865ec9SKyle Evans# */
16*f0865ec9SKyle Evans#! /usr/bin/env python
17*f0865ec9SKyle Evans
18*f0865ec9SKyle Evansimport random, sys, re, math, os, getopt, glob, copy, hashlib, binascii, string, signal, base64
19*f0865ec9SKyle Evans
20*f0865ec9SKyle Evans# External dependecy for SHA-3
21*f0865ec9SKyle Evans# It is an independent module, since hashlib has no support
22*f0865ec9SKyle Evans# for SHA-3 functions for now
23*f0865ec9SKyle Evansimport sha3
24*f0865ec9SKyle Evans
25*f0865ec9SKyle Evans# Handle Python 2/3 issues
26*f0865ec9SKyle Evansdef is_python_2():
27*f0865ec9SKyle Evans    if sys.version_info[0] < 3:
28*f0865ec9SKyle Evans        return True
29*f0865ec9SKyle Evans    else:
30*f0865ec9SKyle Evans        return False
31*f0865ec9SKyle Evans
32*f0865ec9SKyle Evans### Ctrl-C handler
33*f0865ec9SKyle Evansdef handler(signal, frame):
34*f0865ec9SKyle Evans    print("\nSIGINT caught: exiting ...")
35*f0865ec9SKyle Evans    exit(0)
36*f0865ec9SKyle Evans
37*f0865ec9SKyle Evans# Helper to ask the user for something
38*f0865ec9SKyle Evansdef get_user_input(prompt):
39*f0865ec9SKyle Evans    # Handle the Python 2/3 issue
40*f0865ec9SKyle Evans    if is_python_2() == False:
41*f0865ec9SKyle Evans        return input(prompt)
42*f0865ec9SKyle Evans    else:
43*f0865ec9SKyle Evans        return raw_input(prompt)
44*f0865ec9SKyle Evans
45*f0865ec9SKyle Evans##########################################################
46*f0865ec9SKyle Evans#### Math helpers
47*f0865ec9SKyle Evansdef egcd(b, n):
48*f0865ec9SKyle Evans    x0, x1, y0, y1 = 1, 0, 0, 1
49*f0865ec9SKyle Evans    while n != 0:
50*f0865ec9SKyle Evans        q, b, n = b // n, n, b % n
51*f0865ec9SKyle Evans        x0, x1 = x1, x0 - q * x1
52*f0865ec9SKyle Evans        y0, y1 = y1, y0 - q * y1
53*f0865ec9SKyle Evans    return  b, x0, y0
54*f0865ec9SKyle Evans
55*f0865ec9SKyle Evansdef modinv(a, m):
56*f0865ec9SKyle Evans    g, x, y = egcd(a, m)
57*f0865ec9SKyle Evans    if g != 1:
58*f0865ec9SKyle Evans        raise Exception("Error: modular inverse does not exist")
59*f0865ec9SKyle Evans    else:
60*f0865ec9SKyle Evans        return x % m
61*f0865ec9SKyle Evans
62*f0865ec9SKyle Evansdef compute_monty_coef(prime, pbitlen, wlen):
63*f0865ec9SKyle Evans    """
64*f0865ec9SKyle Evans    Compute montgomery coeff r, r^2 and mpinv. pbitlen is the size
65*f0865ec9SKyle Evans    of p in bits. It is expected to be a multiple of word
66*f0865ec9SKyle Evans    bit size.
67*f0865ec9SKyle Evans    """
68*f0865ec9SKyle Evans    r = (1 << int(pbitlen)) % prime
69*f0865ec9SKyle Evans    r_square = (1 << (2 * int(pbitlen))) % prime
70*f0865ec9SKyle Evans    mpinv = 2**wlen - (modinv(prime, 2**wlen))
71*f0865ec9SKyle Evans    return r, r_square, mpinv
72*f0865ec9SKyle Evans
73*f0865ec9SKyle Evansdef compute_div_coef(prime, pbitlen, wlen):
74*f0865ec9SKyle Evans    """
75*f0865ec9SKyle Evans    Compute division coeffs p_normalized, p_shift and p_reciprocal.
76*f0865ec9SKyle Evans    """
77*f0865ec9SKyle Evans    tmp = prime
78*f0865ec9SKyle Evans    cnt = 0
79*f0865ec9SKyle Evans    while tmp != 0:
80*f0865ec9SKyle Evans        tmp = tmp >> 1
81*f0865ec9SKyle Evans        cnt += 1
82*f0865ec9SKyle Evans    pshift = int(pbitlen - cnt)
83*f0865ec9SKyle Evans    primenorm = prime << pshift
84*f0865ec9SKyle Evans    B = 2**wlen
85*f0865ec9SKyle Evans    prec = B**3 // ((primenorm >> int(pbitlen - 2*wlen)) + 1) - B
86*f0865ec9SKyle Evans    return pshift, primenorm, prec
87*f0865ec9SKyle Evans
88*f0865ec9SKyle Evansdef is_probprime(n):
89*f0865ec9SKyle Evans    # ensure n is odd
90*f0865ec9SKyle Evans    if n % 2 == 0:
91*f0865ec9SKyle Evans        return False
92*f0865ec9SKyle Evans    # write n-1 as 2**s * d
93*f0865ec9SKyle Evans    # repeatedly try to divide n-1 by 2
94*f0865ec9SKyle Evans    s = 0
95*f0865ec9SKyle Evans    d = n-1
96*f0865ec9SKyle Evans    while True:
97*f0865ec9SKyle Evans        quotient, remainder = divmod(d, 2)
98*f0865ec9SKyle Evans        if remainder == 1:
99*f0865ec9SKyle Evans            break
100*f0865ec9SKyle Evans        s += 1
101*f0865ec9SKyle Evans        d = quotient
102*f0865ec9SKyle Evans    assert(2**s * d == n-1)
103*f0865ec9SKyle Evans    # test the base a to see whether it is a witness for the compositeness of n
104*f0865ec9SKyle Evans    def try_composite(a):
105*f0865ec9SKyle Evans        if pow(a, d, n) == 1:
106*f0865ec9SKyle Evans            return False
107*f0865ec9SKyle Evans        for i in range(s):
108*f0865ec9SKyle Evans            if pow(a, 2**i * d, n) == n-1:
109*f0865ec9SKyle Evans                return False
110*f0865ec9SKyle Evans        return True # n is definitely composite
111*f0865ec9SKyle Evans    for i in range(5):
112*f0865ec9SKyle Evans        a = random.randrange(2, n)
113*f0865ec9SKyle Evans        if try_composite(a):
114*f0865ec9SKyle Evans            return False
115*f0865ec9SKyle Evans    return True # no base tested showed n as composite
116*f0865ec9SKyle Evans
117*f0865ec9SKyle Evansdef legendre_symbol(a, p):
118*f0865ec9SKyle Evans    ls = pow(a, (p - 1) // 2, p)
119*f0865ec9SKyle Evans    return -1 if ls == p - 1 else ls
120*f0865ec9SKyle Evans
121*f0865ec9SKyle Evans# Tonelli-Shanks algorithm to find square roots
122*f0865ec9SKyle Evans# over prime fields
123*f0865ec9SKyle Evansdef mod_sqrt(a, p):
124*f0865ec9SKyle Evans    # Square root of 0 is 0
125*f0865ec9SKyle Evans    if a == 0:
126*f0865ec9SKyle Evans        return 0
127*f0865ec9SKyle Evans    # Simple cases
128*f0865ec9SKyle Evans    if legendre_symbol(a, p) != 1:
129*f0865ec9SKyle Evans        # No square residue
130*f0865ec9SKyle Evans        return None
131*f0865ec9SKyle Evans    elif p == 2:
132*f0865ec9SKyle Evans        return a
133*f0865ec9SKyle Evans    elif p % 4 == 3:
134*f0865ec9SKyle Evans        return pow(a, (p + 1) // 4, p)
135*f0865ec9SKyle Evans    s = p - 1
136*f0865ec9SKyle Evans    e = 0
137*f0865ec9SKyle Evans    while s % 2 == 0:
138*f0865ec9SKyle Evans        s = s // 2
139*f0865ec9SKyle Evans        e += 1
140*f0865ec9SKyle Evans    n = 2
141*f0865ec9SKyle Evans    while legendre_symbol(n, p) != -1:
142*f0865ec9SKyle Evans        n += 1
143*f0865ec9SKyle Evans    x = pow(a, (s + 1) // 2, p)
144*f0865ec9SKyle Evans    b = pow(a, s, p)
145*f0865ec9SKyle Evans    g = pow(n, s, p)
146*f0865ec9SKyle Evans    r = e
147*f0865ec9SKyle Evans    while True:
148*f0865ec9SKyle Evans        t = b
149*f0865ec9SKyle Evans        m = 0
150*f0865ec9SKyle Evans        if is_python_2():
151*f0865ec9SKyle Evans            for m in xrange(r):
152*f0865ec9SKyle Evans                if t == 1:
153*f0865ec9SKyle Evans                    break
154*f0865ec9SKyle Evans                t = pow(t, 2, p)
155*f0865ec9SKyle Evans        else:
156*f0865ec9SKyle Evans            for m in range(r):
157*f0865ec9SKyle Evans                if t == 1:
158*f0865ec9SKyle Evans                    break
159*f0865ec9SKyle Evans                t = pow(t, 2, p)
160*f0865ec9SKyle Evans        if m == 0:
161*f0865ec9SKyle Evans            return x
162*f0865ec9SKyle Evans        gs = pow(g, 2 ** (r - m - 1), p)
163*f0865ec9SKyle Evans        g = (gs * gs) % p
164*f0865ec9SKyle Evans        x = (x * gs) % p
165*f0865ec9SKyle Evans        b = (b * g) % p
166*f0865ec9SKyle Evans        r = m
167*f0865ec9SKyle Evans
168*f0865ec9SKyle Evans##########################################################
169*f0865ec9SKyle Evans### Math elliptic curves basic blocks
170*f0865ec9SKyle Evans
171*f0865ec9SKyle Evans# WARNING: these blocks are only here for testing purpose and
172*f0865ec9SKyle Evans# are not intended to be used in a security oriented library!
173*f0865ec9SKyle Evans# This explains the usage of naive affine coordinates fomulas
174*f0865ec9SKyle Evansclass Curve(object):
175*f0865ec9SKyle Evans    def __init__(self, a, b, prime, order, cofactor, gx, gy, npoints, name, oid):
176*f0865ec9SKyle Evans        self.a = a
177*f0865ec9SKyle Evans        self.b = b
178*f0865ec9SKyle Evans        self.p = prime
179*f0865ec9SKyle Evans        self.q = order
180*f0865ec9SKyle Evans        self.c = cofactor
181*f0865ec9SKyle Evans        self.gx = gx
182*f0865ec9SKyle Evans        self.gy = gy
183*f0865ec9SKyle Evans        self.n = npoints
184*f0865ec9SKyle Evans        self.name = name
185*f0865ec9SKyle Evans        self.oid = oid
186*f0865ec9SKyle Evans    # Equality testing
187*f0865ec9SKyle Evans    def __eq__(self, other):
188*f0865ec9SKyle Evans        return self.__dict__ == other.__dict__
189*f0865ec9SKyle Evans    # Deep copy is implemented using the ~X operator
190*f0865ec9SKyle Evans    def __invert__(self):
191*f0865ec9SKyle Evans        return copy.deepcopy(self)
192*f0865ec9SKyle Evans
193*f0865ec9SKyle Evans
194*f0865ec9SKyle Evansclass Point(object):
195*f0865ec9SKyle Evans    # Affine coordinates (x, y), infinity point is (None, None)
196*f0865ec9SKyle Evans    def __init__(self, curve, x, y):
197*f0865ec9SKyle Evans        self.curve = curve
198*f0865ec9SKyle Evans        if x != None:
199*f0865ec9SKyle Evans            self.x = (x % curve.p)
200*f0865ec9SKyle Evans        else:
201*f0865ec9SKyle Evans            self.x = None
202*f0865ec9SKyle Evans        if y != None:
203*f0865ec9SKyle Evans            self.y = (y % curve.p)
204*f0865ec9SKyle Evans        else:
205*f0865ec9SKyle Evans            self.y = None
206*f0865ec9SKyle Evans        # Check that the point is indeed on the curve
207*f0865ec9SKyle Evans        if (x != None):
208*f0865ec9SKyle Evans            if (pow(y, 2, curve.p) != ((pow(x, 3, curve.p) + (curve.a * x) + curve.b ) % curve.p)):
209*f0865ec9SKyle Evans                raise Exception("Error: point is not on curve!")
210*f0865ec9SKyle Evans    # Addition
211*f0865ec9SKyle Evans    def __add__(self, Q):
212*f0865ec9SKyle Evans        x1 = self.x
213*f0865ec9SKyle Evans        y1 = self.y
214*f0865ec9SKyle Evans        x2 = Q.x
215*f0865ec9SKyle Evans        y2 = Q.y
216*f0865ec9SKyle Evans        curve = self.curve
217*f0865ec9SKyle Evans        # Check that we are on the same curve
218*f0865ec9SKyle Evans        if Q.curve != curve:
219*f0865ec9SKyle Evans            raise Exception("Point add error: two point don't have the same curve")
220*f0865ec9SKyle Evans        # If Q is infinity point, return ourself
221*f0865ec9SKyle Evans        if Q.x == None:
222*f0865ec9SKyle Evans            return Point(self.curve, self.x, self.y)
223*f0865ec9SKyle Evans        # If we are the infinity point return Q
224*f0865ec9SKyle Evans        if self.x == None:
225*f0865ec9SKyle Evans            return Q
226*f0865ec9SKyle Evans        # Infinity point or Doubling
227*f0865ec9SKyle Evans        if (x1 == x2):
228*f0865ec9SKyle Evans            if (((y1 + y2) % curve.p) == 0):
229*f0865ec9SKyle Evans                # Return infinity point
230*f0865ec9SKyle Evans                return Point(self.curve, None, None)
231*f0865ec9SKyle Evans            else:
232*f0865ec9SKyle Evans                # Doubling
233*f0865ec9SKyle Evans                L = ((3*pow(x1, 2, curve.p) + curve.a) * modinv(2*y1, curve.p)) % curve.p
234*f0865ec9SKyle Evans        # Addition
235*f0865ec9SKyle Evans        else:
236*f0865ec9SKyle Evans            L = ((y2 - y1) * modinv((x2 - x1) % curve.p, curve.p)) % curve.p
237*f0865ec9SKyle Evans        resx = (pow(L, 2, curve.p) - x1 - x2) % curve.p
238*f0865ec9SKyle Evans        resy = ((L * (x1 - resx)) - y1) % curve.p
239*f0865ec9SKyle Evans        # Return the point
240*f0865ec9SKyle Evans        return Point(self.curve, resx, resy)
241*f0865ec9SKyle Evans    # Negation
242*f0865ec9SKyle Evans    def __neg__(self):
243*f0865ec9SKyle Evans        if (self.x == None):
244*f0865ec9SKyle Evans            return Point(self.curve, None, None)
245*f0865ec9SKyle Evans        else:
246*f0865ec9SKyle Evans            return Point(self.curve, self.x, -self.y)
247*f0865ec9SKyle Evans    # Subtraction
248*f0865ec9SKyle Evans    def __sub__(self, other):
249*f0865ec9SKyle Evans        return self + (-other)
250*f0865ec9SKyle Evans    # Scalar mul
251*f0865ec9SKyle Evans    def __rmul__(self, scalar):
252*f0865ec9SKyle Evans        # Implement simple double and add algorithm
253*f0865ec9SKyle Evans        P = self
254*f0865ec9SKyle Evans        Q = Point(P.curve, None, None)
255*f0865ec9SKyle Evans        for i in range(getbitlen(scalar), 0, -1):
256*f0865ec9SKyle Evans            Q = Q + Q
257*f0865ec9SKyle Evans            if (scalar >> (i-1)) & 0x1 == 0x1:
258*f0865ec9SKyle Evans                Q = Q + P
259*f0865ec9SKyle Evans        return Q
260*f0865ec9SKyle Evans    # Equality testing
261*f0865ec9SKyle Evans    def __eq__(self, other):
262*f0865ec9SKyle Evans        return self.__dict__ == other.__dict__
263*f0865ec9SKyle Evans    # Deep copy is implemented using the ~X operator
264*f0865ec9SKyle Evans    def __invert__(self):
265*f0865ec9SKyle Evans        return copy.deepcopy(self)
266*f0865ec9SKyle Evans    def __str__(self):
267*f0865ec9SKyle Evans        if self.x == None:
268*f0865ec9SKyle Evans            return "Inf"
269*f0865ec9SKyle Evans        else:
270*f0865ec9SKyle Evans            return ("(x = %s, y = %s)" % (hex(self.x), hex(self.y)))
271*f0865ec9SKyle Evans
272*f0865ec9SKyle Evans##########################################################
273*f0865ec9SKyle Evans### Private and public keys structures
274*f0865ec9SKyle Evansclass PrivKey(object):
275*f0865ec9SKyle Evans    def __init__(self, curve, x):
276*f0865ec9SKyle Evans        self.curve = curve
277*f0865ec9SKyle Evans        self.x = x
278*f0865ec9SKyle Evans
279*f0865ec9SKyle Evansclass PubKey(object):
280*f0865ec9SKyle Evans    def __init__(self, curve, Y):
281*f0865ec9SKyle Evans        # Sanity check
282*f0865ec9SKyle Evans        if Y.curve != curve:
283*f0865ec9SKyle Evans            raise Exception("Error: curve and point curve differ in public key!")
284*f0865ec9SKyle Evans        self.curve = curve
285*f0865ec9SKyle Evans        self.Y = Y
286*f0865ec9SKyle Evans
287*f0865ec9SKyle Evansclass KeyPair(object):
288*f0865ec9SKyle Evans    def __init__(self, pubkey, privkey):
289*f0865ec9SKyle Evans        self.pubkey = pubkey
290*f0865ec9SKyle Evans        self.privkey = privkey
291*f0865ec9SKyle Evans
292*f0865ec9SKyle Evans
293*f0865ec9SKyle Evansdef fromprivkey(privkey, is_eckcdsa=False):
294*f0865ec9SKyle Evans    curve = privkey.curve
295*f0865ec9SKyle Evans    q = curve.q
296*f0865ec9SKyle Evans    gx = curve.gx
297*f0865ec9SKyle Evans    gy = curve.gy
298*f0865ec9SKyle Evans    G = Point(curve, gx, gy)
299*f0865ec9SKyle Evans    if is_eckcdsa == False:
300*f0865ec9SKyle Evans        return PubKey(curve, privkey.x * G)
301*f0865ec9SKyle Evans    else:
302*f0865ec9SKyle Evans        return PubKey(curve, modinv(privkey.x, q) * G)
303*f0865ec9SKyle Evans
304*f0865ec9SKyle Evansdef genKeyPair(curve, is_eckcdsa=False):
305*f0865ec9SKyle Evans    p = curve.p
306*f0865ec9SKyle Evans    q = curve.q
307*f0865ec9SKyle Evans    gx = curve.gx
308*f0865ec9SKyle Evans    gy = curve.gy
309*f0865ec9SKyle Evans    G = Point(curve, gx, gy)
310*f0865ec9SKyle Evans    OK = False
311*f0865ec9SKyle Evans    while OK == False:
312*f0865ec9SKyle Evans        x = getrandomint(q)
313*f0865ec9SKyle Evans        if x == 0:
314*f0865ec9SKyle Evans            continue
315*f0865ec9SKyle Evans        OK = True
316*f0865ec9SKyle Evans    privkey = PrivKey(curve, x)
317*f0865ec9SKyle Evans    pubkey = fromprivkey(privkey, is_eckcdsa)
318*f0865ec9SKyle Evans    return KeyPair(pubkey, privkey)
319*f0865ec9SKyle Evans
320*f0865ec9SKyle Evans##########################################################
321*f0865ec9SKyle Evans### Signature algorithms helpers
322*f0865ec9SKyle Evansdef getrandomint(modulo):
323*f0865ec9SKyle Evans    return random.randrange(0, modulo+1)
324*f0865ec9SKyle Evans
325*f0865ec9SKyle Evansdef getbitlen(bint):
326*f0865ec9SKyle Evans    """
327*f0865ec9SKyle Evans    Returns the number of bits encoding an integer
328*f0865ec9SKyle Evans    """
329*f0865ec9SKyle Evans    if bint == None:
330*f0865ec9SKyle Evans        return 0
331*f0865ec9SKyle Evans    if bint == 0:
332*f0865ec9SKyle Evans        # Zero is encoded on one bit
333*f0865ec9SKyle Evans        return 1
334*f0865ec9SKyle Evans    else:
335*f0865ec9SKyle Evans        return int(bint).bit_length()
336*f0865ec9SKyle Evans
337*f0865ec9SKyle Evansdef getbytelen(bint):
338*f0865ec9SKyle Evans    """
339*f0865ec9SKyle Evans    Returns the number of bytes encoding an integer
340*f0865ec9SKyle Evans    """
341*f0865ec9SKyle Evans    bitsize = getbitlen(bint)
342*f0865ec9SKyle Evans    bytesize = int(bitsize // 8)
343*f0865ec9SKyle Evans    if bitsize % 8 != 0:
344*f0865ec9SKyle Evans        bytesize += 1
345*f0865ec9SKyle Evans    return bytesize
346*f0865ec9SKyle Evans
347*f0865ec9SKyle Evansdef stringtoint(bitstring):
348*f0865ec9SKyle Evans    acc = 0
349*f0865ec9SKyle Evans    size = len(bitstring)
350*f0865ec9SKyle Evans    for i in range(0, size):
351*f0865ec9SKyle Evans        acc = acc + (ord(bitstring[i]) * (2**(8*(size - 1 - i))))
352*f0865ec9SKyle Evans    return acc
353*f0865ec9SKyle Evans
354*f0865ec9SKyle Evansdef inttostring(a):
355*f0865ec9SKyle Evans    size = int(getbytelen(a))
356*f0865ec9SKyle Evans    outstr = ""
357*f0865ec9SKyle Evans    for i in range(0, size):
358*f0865ec9SKyle Evans        outstr = outstr + chr((a >> (8*(size - 1 - i))) & 0xFF)
359*f0865ec9SKyle Evans    return outstr
360*f0865ec9SKyle Evans
361*f0865ec9SKyle Evansdef expand(bitstring, bitlen, direction):
362*f0865ec9SKyle Evans    bytelen = int(math.ceil(bitlen / 8.))
363*f0865ec9SKyle Evans    if len(bitstring) >= bytelen:
364*f0865ec9SKyle Evans        return bitstring
365*f0865ec9SKyle Evans    else:
366*f0865ec9SKyle Evans        if direction == "LEFT":
367*f0865ec9SKyle Evans            return ((bytelen-len(bitstring))*"\x00") + bitstring
368*f0865ec9SKyle Evans        elif direction == "RIGHT":
369*f0865ec9SKyle Evans            return bitstring + ((bytelen-len(bitstring))*"\x00")
370*f0865ec9SKyle Evans        else:
371*f0865ec9SKyle Evans            raise Exception("Error: unknown direction "+direction+" in expand")
372*f0865ec9SKyle Evans
373*f0865ec9SKyle Evansdef truncate(bitstring, bitlen, keep):
374*f0865ec9SKyle Evans    """
375*f0865ec9SKyle Evans    Takes a bit string and truncates it to keep the left
376*f0865ec9SKyle Evans    most or the right most bits
377*f0865ec9SKyle Evans    """
378*f0865ec9SKyle Evans    strbitlen = 8*len(bitstring)
379*f0865ec9SKyle Evans    # Check if truncation is needed
380*f0865ec9SKyle Evans    if strbitlen > bitlen:
381*f0865ec9SKyle Evans        if keep == "LEFT":
382*f0865ec9SKyle Evans            return expand(inttostring(stringtoint(bitstring) >> int(strbitlen - bitlen)), bitlen, "LEFT")
383*f0865ec9SKyle Evans        elif keep == "RIGHT":
384*f0865ec9SKyle Evans            mask = (2**bitlen)-1
385*f0865ec9SKyle Evans            return expand(inttostring(stringtoint(bitstring) & mask), bitlen, "LEFT")
386*f0865ec9SKyle Evans        else:
387*f0865ec9SKyle Evans            raise Exception("Error: unknown direction "+keep+" in truncate")
388*f0865ec9SKyle Evans    else:
389*f0865ec9SKyle Evans        # No need to truncate!
390*f0865ec9SKyle Evans        return bitstring
391*f0865ec9SKyle Evans
392*f0865ec9SKyle Evans##########################################################
393*f0865ec9SKyle Evans### Hash algorithms
394*f0865ec9SKyle Evansdef sha224(message):
395*f0865ec9SKyle Evans    ctx = hashlib.sha224()
396*f0865ec9SKyle Evans    if(is_python_2() == True):
397*f0865ec9SKyle Evans        ctx.update(message)
398*f0865ec9SKyle Evans        digest = ctx.digest()
399*f0865ec9SKyle Evans    else:
400*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
401*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
402*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
403*f0865ec9SKyle Evans
404*f0865ec9SKyle Evansdef sha256(message):
405*f0865ec9SKyle Evans    ctx = hashlib.sha256()
406*f0865ec9SKyle Evans    if(is_python_2() == True):
407*f0865ec9SKyle Evans        ctx.update(message)
408*f0865ec9SKyle Evans        digest = ctx.digest()
409*f0865ec9SKyle Evans    else:
410*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
411*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
412*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
413*f0865ec9SKyle Evans
414*f0865ec9SKyle Evansdef sha384(message):
415*f0865ec9SKyle Evans    ctx = hashlib.sha384()
416*f0865ec9SKyle Evans    if(is_python_2() == True):
417*f0865ec9SKyle Evans        ctx.update(message)
418*f0865ec9SKyle Evans        digest = ctx.digest()
419*f0865ec9SKyle Evans    else:
420*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
421*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
422*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
423*f0865ec9SKyle Evans
424*f0865ec9SKyle Evansdef sha512(message):
425*f0865ec9SKyle Evans    ctx = hashlib.sha512()
426*f0865ec9SKyle Evans    if(is_python_2() == True):
427*f0865ec9SKyle Evans        ctx.update(message)
428*f0865ec9SKyle Evans        digest = ctx.digest()
429*f0865ec9SKyle Evans    else:
430*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
431*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
432*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
433*f0865ec9SKyle Evans
434*f0865ec9SKyle Evansdef sha3_224(message):
435*f0865ec9SKyle Evans    ctx = sha3.Sha3_ctx(224)
436*f0865ec9SKyle Evans    if(is_python_2() == True):
437*f0865ec9SKyle Evans        ctx.update(message)
438*f0865ec9SKyle Evans        digest = ctx.digest()
439*f0865ec9SKyle Evans    else:
440*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
441*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
442*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
443*f0865ec9SKyle Evans
444*f0865ec9SKyle Evansdef sha3_256(message):
445*f0865ec9SKyle Evans    ctx = sha3.Sha3_ctx(256)
446*f0865ec9SKyle Evans    if(is_python_2() == True):
447*f0865ec9SKyle Evans        ctx.update(message)
448*f0865ec9SKyle Evans        digest = ctx.digest()
449*f0865ec9SKyle Evans    else:
450*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
451*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
452*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
453*f0865ec9SKyle Evans
454*f0865ec9SKyle Evansdef sha3_384(message):
455*f0865ec9SKyle Evans    ctx = sha3.Sha3_ctx(384)
456*f0865ec9SKyle Evans    if(is_python_2() == True):
457*f0865ec9SKyle Evans        ctx.update(message)
458*f0865ec9SKyle Evans        digest = ctx.digest()
459*f0865ec9SKyle Evans    else:
460*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
461*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
462*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
463*f0865ec9SKyle Evans
464*f0865ec9SKyle Evansdef sha3_512(message):
465*f0865ec9SKyle Evans    ctx = sha3.Sha3_ctx(512)
466*f0865ec9SKyle Evans    if(is_python_2() == True):
467*f0865ec9SKyle Evans        ctx.update(message)
468*f0865ec9SKyle Evans        digest = ctx.digest()
469*f0865ec9SKyle Evans    else:
470*f0865ec9SKyle Evans        ctx.update(message.encode('latin-1'))
471*f0865ec9SKyle Evans        digest = ctx.digest().decode('latin-1')
472*f0865ec9SKyle Evans    return (digest, ctx.digest_size, ctx.block_size)
473*f0865ec9SKyle Evans
474*f0865ec9SKyle Evans##########################################################
475*f0865ec9SKyle Evans### Signature algorithms
476*f0865ec9SKyle Evans
477*f0865ec9SKyle Evans# *| IUF  - ECDSA signature
478*f0865ec9SKyle Evans# *|
479*f0865ec9SKyle Evans# *|  UF  1. Compute h = H(m)
480*f0865ec9SKyle Evans# *|   F  2. If |h| > bitlen(q), set h to bitlen(q)
481*f0865ec9SKyle Evans# *|         leftmost (most significant) bits of h
482*f0865ec9SKyle Evans# *|   F  3. e = OS2I(h) mod q
483*f0865ec9SKyle Evans# *|   F  4. Get a random value k in ]0,q[
484*f0865ec9SKyle Evans# *|   F  5. Compute W = (W_x,W_y) = kG
485*f0865ec9SKyle Evans# *|   F  6. Compute r = W_x mod q
486*f0865ec9SKyle Evans# *|   F  7. If r is 0, restart the process at step 4.
487*f0865ec9SKyle Evans# *|   F  8. If e == rx, restart the process at step 4.
488*f0865ec9SKyle Evans# *|   F  9. Compute s = k^-1 * (xr + e) mod q
489*f0865ec9SKyle Evans# *|   F 10. If s is 0, restart the process at step 4.
490*f0865ec9SKyle Evans# *|   F 11. Return (r,s)
491*f0865ec9SKyle Evansdef ecdsa_sign(hashfunc, keypair, message, k=None):
492*f0865ec9SKyle Evans    privkey = keypair.privkey
493*f0865ec9SKyle Evans    # Get important parameters from the curve
494*f0865ec9SKyle Evans    p = privkey.curve.p
495*f0865ec9SKyle Evans    q = privkey.curve.q
496*f0865ec9SKyle Evans    gx = privkey.curve.gx
497*f0865ec9SKyle Evans    gy = privkey.curve.gy
498*f0865ec9SKyle Evans    G = Point(privkey.curve, gx, gy)
499*f0865ec9SKyle Evans    q_limit_len = getbitlen(q)
500*f0865ec9SKyle Evans    # Compute the hash
501*f0865ec9SKyle Evans    (h, _, _) = hashfunc(message)
502*f0865ec9SKyle Evans    # Truncate hash value
503*f0865ec9SKyle Evans    h = truncate(h, q_limit_len, "LEFT")
504*f0865ec9SKyle Evans    # Convert the hash value to an int
505*f0865ec9SKyle Evans    e = stringtoint(h) % q
506*f0865ec9SKyle Evans    OK = False
507*f0865ec9SKyle Evans    while OK == False:
508*f0865ec9SKyle Evans        if k == None:
509*f0865ec9SKyle Evans            k = getrandomint(q)
510*f0865ec9SKyle Evans        if k == 0:
511*f0865ec9SKyle Evans            continue
512*f0865ec9SKyle Evans        W = k * G
513*f0865ec9SKyle Evans        r = W.x % q
514*f0865ec9SKyle Evans        if r == 0:
515*f0865ec9SKyle Evans            continue
516*f0865ec9SKyle Evans        if e == r * privkey.x:
517*f0865ec9SKyle Evans            continue
518*f0865ec9SKyle Evans        s = (modinv(k, q) * ((privkey.x * r) + e)) % q
519*f0865ec9SKyle Evans        if s == 0:
520*f0865ec9SKyle Evans            continue
521*f0865ec9SKyle Evans        OK = True
522*f0865ec9SKyle Evans    return ((expand(inttostring(r), 8*getbytelen(q), "LEFT") + expand(inttostring(s), 8*getbytelen(q), "LEFT")), k)
523*f0865ec9SKyle Evans
524*f0865ec9SKyle Evans# *| IUF  - ECDSA verification
525*f0865ec9SKyle Evans# *|
526*f0865ec9SKyle Evans# *| I    1. Reject the signature if r or s is 0.
527*f0865ec9SKyle Evans# *|  UF  2. Compute h = H(m)
528*f0865ec9SKyle Evans# *|   F  3. If |h| > bitlen(q), set h to bitlen(q)
529*f0865ec9SKyle Evans# *|         leftmost (most significant) bits of h
530*f0865ec9SKyle Evans# *|   F  4. Compute e = OS2I(h) mod q
531*f0865ec9SKyle Evans# *|   F  5. Compute u = (s^-1)e mod q
532*f0865ec9SKyle Evans# *|   F  6. Compute v = (s^-1)r mod q
533*f0865ec9SKyle Evans# *|   F  7. Compute W' = uG + vY
534*f0865ec9SKyle Evans# *|   F  8. If W' is the point at infinity, reject the signature.
535*f0865ec9SKyle Evans# *|   F  9. Compute r' = W'_x mod q
536*f0865ec9SKyle Evans# *|   F 10. Accept the signature if and only if r equals r'
537*f0865ec9SKyle Evansdef ecdsa_verify(hashfunc, keypair, message, sig):
538*f0865ec9SKyle Evans    pubkey = keypair.pubkey
539*f0865ec9SKyle Evans    # Get important parameters from the curve
540*f0865ec9SKyle Evans    p = pubkey.curve.p
541*f0865ec9SKyle Evans    q = pubkey.curve.q
542*f0865ec9SKyle Evans    gx = pubkey.curve.gx
543*f0865ec9SKyle Evans    gy = pubkey.curve.gy
544*f0865ec9SKyle Evans    q_limit_len = getbitlen(q)
545*f0865ec9SKyle Evans    G = Point(pubkey.curve, gx, gy)
546*f0865ec9SKyle Evans    # Extract r and s
547*f0865ec9SKyle Evans    if len(sig) != 2*getbytelen(q):
548*f0865ec9SKyle Evans        raise Exception("ECDSA verify: bad signature length!")
549*f0865ec9SKyle Evans    r = stringtoint(sig[0:int(len(sig)/2)])
550*f0865ec9SKyle Evans    s = stringtoint(sig[int(len(sig)/2):])
551*f0865ec9SKyle Evans    if r == 0 or s == 0:
552*f0865ec9SKyle Evans        return False
553*f0865ec9SKyle Evans    # Compute the hash
554*f0865ec9SKyle Evans    (h, _, _) = hashfunc(message)
555*f0865ec9SKyle Evans    # Truncate hash value
556*f0865ec9SKyle Evans    h = truncate(h, q_limit_len, "LEFT")
557*f0865ec9SKyle Evans    # Convert the hash value to an int
558*f0865ec9SKyle Evans    e = stringtoint(h) % q
559*f0865ec9SKyle Evans    u = (modinv(s, q) * e) % q
560*f0865ec9SKyle Evans    v = (modinv(s, q) * r) % q
561*f0865ec9SKyle Evans    W_ = (u * G) + (v * pubkey.Y)
562*f0865ec9SKyle Evans    if W_.x == None:
563*f0865ec9SKyle Evans        return False
564*f0865ec9SKyle Evans    r_ = W_.x % q
565*f0865ec9SKyle Evans    if r == r_:
566*f0865ec9SKyle Evans        return True
567*f0865ec9SKyle Evans    else:
568*f0865ec9SKyle Evans        return False
569*f0865ec9SKyle Evans
570*f0865ec9SKyle Evansdef eckcdsa_genKeyPair(curve):
571*f0865ec9SKyle Evans    return genKeyPair(curve, True)
572*f0865ec9SKyle Evans
573*f0865ec9SKyle Evans# *| IUF  - ECKCDSA signature
574*f0865ec9SKyle Evans# *|
575*f0865ec9SKyle Evans# *| IUF  1. Compute h = H(z||m)
576*f0865ec9SKyle Evans# *|   F  2. If hsize > bitlen(q), set h to bitlen(q)
577*f0865ec9SKyle Evans# *|         rightmost (less significant) bits of h.
578*f0865ec9SKyle Evans# *|   F  3. Get a random value k in ]0,q[
579*f0865ec9SKyle Evans# *|   F  4. Compute W = (W_x,W_y) = kG
580*f0865ec9SKyle Evans# *|   F  5. Compute r = h(FE2OS(W_x)).
581*f0865ec9SKyle Evans# *|   F  6. If hsize > bitlen(q), set r to bitlen(q)
582*f0865ec9SKyle Evans# *|         rightmost (less significant) bits of r.
583*f0865ec9SKyle Evans# *|   F  7. Compute e = OS2I(r XOR h) mod q
584*f0865ec9SKyle Evans# *|   F  8. Compute s = x(k - e) mod q
585*f0865ec9SKyle Evans# *|   F  9. if s == 0, restart at step 3.
586*f0865ec9SKyle Evans# *|   F 10. return (r,s)
587*f0865ec9SKyle Evansdef eckcdsa_sign(hashfunc, keypair, message, k=None):
588*f0865ec9SKyle Evans    privkey = keypair.privkey
589*f0865ec9SKyle Evans    # Get important parameters from the curve
590*f0865ec9SKyle Evans    p = privkey.curve.p
591*f0865ec9SKyle Evans    q = privkey.curve.q
592*f0865ec9SKyle Evans    gx = privkey.curve.gx
593*f0865ec9SKyle Evans    gy = privkey.curve.gy
594*f0865ec9SKyle Evans    G = Point(privkey.curve, gx, gy)
595*f0865ec9SKyle Evans    q_limit_len = getbitlen(q)
596*f0865ec9SKyle Evans    # Compute the certificate data
597*f0865ec9SKyle Evans    (_, _, hblocksize) = hashfunc("")
598*f0865ec9SKyle Evans    z = expand(inttostring(keypair.pubkey.Y.x), 8*getbytelen(p), "LEFT")
599*f0865ec9SKyle Evans    z = z + expand(inttostring(keypair.pubkey.Y.y), 8*getbytelen(p), "LEFT")
600*f0865ec9SKyle Evans    if len(z) > hblocksize:
601*f0865ec9SKyle Evans        # Truncate
602*f0865ec9SKyle Evans        z = truncate(z, 8*hblocksize, "LEFT")
603*f0865ec9SKyle Evans    else:
604*f0865ec9SKyle Evans        # Expand
605*f0865ec9SKyle Evans        z = expand(z, 8*hblocksize, "RIGHT")
606*f0865ec9SKyle Evans    # Compute the hash
607*f0865ec9SKyle Evans    (h, _, _) = hashfunc(z + message)
608*f0865ec9SKyle Evans    # Truncate hash value
609*f0865ec9SKyle Evans    h = truncate(h, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT")
610*f0865ec9SKyle Evans    OK = False
611*f0865ec9SKyle Evans    while OK == False:
612*f0865ec9SKyle Evans        if k == None:
613*f0865ec9SKyle Evans            k = getrandomint(q)
614*f0865ec9SKyle Evans        if k == 0:
615*f0865ec9SKyle Evans            continue
616*f0865ec9SKyle Evans        W = k * G
617*f0865ec9SKyle Evans        (r, _, _) = hashfunc(expand(inttostring(W.x), 8*getbytelen(p), "LEFT"))
618*f0865ec9SKyle Evans        r = truncate(r, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT")
619*f0865ec9SKyle Evans        e = (stringtoint(r) ^ stringtoint(h)) % q
620*f0865ec9SKyle Evans        s = (privkey.x * (k - e)) % q
621*f0865ec9SKyle Evans        if s == 0:
622*f0865ec9SKyle Evans            continue
623*f0865ec9SKyle Evans        OK = True
624*f0865ec9SKyle Evans    return (r + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k)
625*f0865ec9SKyle Evans
626*f0865ec9SKyle Evans# *| IUF - ECKCDSA verification
627*f0865ec9SKyle Evans# *|
628*f0865ec9SKyle Evans# *| I   1. Check the length of r:
629*f0865ec9SKyle Evans# *|         - if hsize > bitlen(q), r must be of
630*f0865ec9SKyle Evans# *|           length bitlen(q)
631*f0865ec9SKyle Evans# *|         - if hsize <= bitlen(q), r must be of
632*f0865ec9SKyle Evans# *|           length hsize
633*f0865ec9SKyle Evans# *| I   2. Check that s is in ]0,q[
634*f0865ec9SKyle Evans# *| IUF 3. Compute h = H(z||m)
635*f0865ec9SKyle Evans# *|   F 4. If hsize > bitlen(q), set h to bitlen(q)
636*f0865ec9SKyle Evans# *|        rightmost (less significant) bits of h.
637*f0865ec9SKyle Evans# *|   F 5. Compute e = OS2I(r XOR h) mod q
638*f0865ec9SKyle Evans# *|   F 6. Compute W' = sY + eG, where Y is the public key
639*f0865ec9SKyle Evans# *|   F 7. Compute r' = h(FE2OS(W'x))
640*f0865ec9SKyle Evans# *|   F 8. If hsize > bitlen(q), set r' to bitlen(q)
641*f0865ec9SKyle Evans# *|        rightmost (less significant) bits of r'.
642*f0865ec9SKyle Evans# *|   F 9. Check if r == r'
643*f0865ec9SKyle Evansdef eckcdsa_verify(hashfunc, keypair, message, sig):
644*f0865ec9SKyle Evans    pubkey = keypair.pubkey
645*f0865ec9SKyle Evans    # Get important parameters from the curve
646*f0865ec9SKyle Evans    p = pubkey.curve.p
647*f0865ec9SKyle Evans    q = pubkey.curve.q
648*f0865ec9SKyle Evans    gx = pubkey.curve.gx
649*f0865ec9SKyle Evans    gy = pubkey.curve.gy
650*f0865ec9SKyle Evans    G = Point(pubkey.curve, gx, gy)
651*f0865ec9SKyle Evans    q_limit_len = getbitlen(q)
652*f0865ec9SKyle Evans    (_, hsize, hblocksize) = hashfunc("")
653*f0865ec9SKyle Evans    # Extract r and s
654*f0865ec9SKyle Evans    if (8*hsize) > q_limit_len:
655*f0865ec9SKyle Evans        r_len = int(math.ceil(q_limit_len / 8.))
656*f0865ec9SKyle Evans    else:
657*f0865ec9SKyle Evans        r_len = hsize
658*f0865ec9SKyle Evans    r = stringtoint(sig[0:int(r_len)])
659*f0865ec9SKyle Evans    s = stringtoint(sig[int(r_len):])
660*f0865ec9SKyle Evans    if (s >= q) or (s < 0):
661*f0865ec9SKyle Evans        return False
662*f0865ec9SKyle Evans    # Compute the certificate data
663*f0865ec9SKyle Evans    z = expand(inttostring(keypair.pubkey.Y.x), 8*getbytelen(p), "LEFT")
664*f0865ec9SKyle Evans    z = z + expand(inttostring(keypair.pubkey.Y.y), 8*getbytelen(p), "LEFT")
665*f0865ec9SKyle Evans    if len(z) > hblocksize:
666*f0865ec9SKyle Evans        # Truncate
667*f0865ec9SKyle Evans        z = truncate(z, 8*hblocksize, "LEFT")
668*f0865ec9SKyle Evans    else:
669*f0865ec9SKyle Evans        # Expand
670*f0865ec9SKyle Evans        z = expand(z, 8*hblocksize, "RIGHT")
671*f0865ec9SKyle Evans    # Compute the hash
672*f0865ec9SKyle Evans    (h, _, _) = hashfunc(z + message)
673*f0865ec9SKyle Evans    # Truncate hash value
674*f0865ec9SKyle Evans    h = truncate(h, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT")
675*f0865ec9SKyle Evans    e = (r ^ stringtoint(h)) % q
676*f0865ec9SKyle Evans    W_ = (s * pubkey.Y) + (e * G)
677*f0865ec9SKyle Evans    (h, _, _) = hashfunc(expand(inttostring(W_.x), 8*getbytelen(p), "LEFT"))
678*f0865ec9SKyle Evans    r_ = truncate(h, 8 * int(math.ceil(q_limit_len / 8)), "RIGHT")
679*f0865ec9SKyle Evans    if stringtoint(r_) == r:
680*f0865ec9SKyle Evans        return True
681*f0865ec9SKyle Evans    else:
682*f0865ec9SKyle Evans        return False
683*f0865ec9SKyle Evans
684*f0865ec9SKyle Evans# *| IUF - ECFSDSA signature
685*f0865ec9SKyle Evans# *|
686*f0865ec9SKyle Evans# *| I   1. Get a random value k in ]0,q[
687*f0865ec9SKyle Evans# *| I   2. Compute W = (W_x,W_y) = kG
688*f0865ec9SKyle Evans# *| I   3. Compute r = FE2OS(W_x)||FE2OS(W_y)
689*f0865ec9SKyle Evans# *| I   4. If r is an all zero string, restart the process at step 1.
690*f0865ec9SKyle Evans# *| IUF 5. Compute h = H(r||m)
691*f0865ec9SKyle Evans# *|   F 6. Compute e = OS2I(h) mod q
692*f0865ec9SKyle Evans# *|   F 7. Compute s = (k + ex) mod q
693*f0865ec9SKyle Evans# *|   F 8. If s is 0, restart the process at step 1 (see c. below)
694*f0865ec9SKyle Evans# *|   F 9. Return (r,s)
695*f0865ec9SKyle Evansdef ecfsdsa_sign(hashfunc, keypair, message, k=None):
696*f0865ec9SKyle Evans    privkey = keypair.privkey
697*f0865ec9SKyle Evans    # Get important parameters from the curve
698*f0865ec9SKyle Evans    p = privkey.curve.p
699*f0865ec9SKyle Evans    q = privkey.curve.q
700*f0865ec9SKyle Evans    gx = privkey.curve.gx
701*f0865ec9SKyle Evans    gy = privkey.curve.gy
702*f0865ec9SKyle Evans    G = Point(privkey.curve, gx, gy)
703*f0865ec9SKyle Evans    OK = False
704*f0865ec9SKyle Evans    while OK == False:
705*f0865ec9SKyle Evans        if k == None:
706*f0865ec9SKyle Evans            k = getrandomint(q)
707*f0865ec9SKyle Evans        if k == 0:
708*f0865ec9SKyle Evans            continue
709*f0865ec9SKyle Evans        W = k * G
710*f0865ec9SKyle Evans        r = expand(inttostring(W.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W.y), 8*getbytelen(p), "LEFT")
711*f0865ec9SKyle Evans        if stringtoint(r) == 0:
712*f0865ec9SKyle Evans            continue
713*f0865ec9SKyle Evans        (h, _, _) = hashfunc(r + message)
714*f0865ec9SKyle Evans        e = stringtoint(h) % q
715*f0865ec9SKyle Evans        s = (k + e * privkey.x) % q
716*f0865ec9SKyle Evans        if s == 0:
717*f0865ec9SKyle Evans            continue
718*f0865ec9SKyle Evans        OK = True
719*f0865ec9SKyle Evans    return (r + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k)
720*f0865ec9SKyle Evans
721*f0865ec9SKyle Evans
722*f0865ec9SKyle Evans# *| IUF - ECFSDSA verification
723*f0865ec9SKyle Evans# *|
724*f0865ec9SKyle Evans# *| I   1. Reject the signature if r is not a valid point on the curve.
725*f0865ec9SKyle Evans# *| I   2. Reject the signature if s is not in ]0,q[
726*f0865ec9SKyle Evans# *| IUF 3. Compute h = H(r||m)
727*f0865ec9SKyle Evans# *|   F 4. Convert h to an integer and then compute e = -h mod q
728*f0865ec9SKyle Evans# *|   F 5. compute W' = sG + eY, where Y is the public key
729*f0865ec9SKyle Evans# *|   F 6. Compute r' = FE2OS(W'_x)||FE2OS(W'_y)
730*f0865ec9SKyle Evans# *|   F 7. Accept the signature if and only if r equals r'
731*f0865ec9SKyle Evansdef ecfsdsa_verify(hashfunc, keypair, message, sig):
732*f0865ec9SKyle Evans    pubkey = keypair.pubkey
733*f0865ec9SKyle Evans    # Get important parameters from the curve
734*f0865ec9SKyle Evans    p = pubkey.curve.p
735*f0865ec9SKyle Evans    q = pubkey.curve.q
736*f0865ec9SKyle Evans    gx = pubkey.curve.gx
737*f0865ec9SKyle Evans    gy = pubkey.curve.gy
738*f0865ec9SKyle Evans    G = Point(pubkey.curve, gx, gy)
739*f0865ec9SKyle Evans    # Extract coordinates from r and s from signature
740*f0865ec9SKyle Evans    if len(sig) != (2*getbytelen(p)) + getbytelen(q):
741*f0865ec9SKyle Evans        raise Exception("ECFSDSA verify: bad signature length!")
742*f0865ec9SKyle Evans    wx = sig[:int(getbytelen(p))]
743*f0865ec9SKyle Evans    wy = sig[int(getbytelen(p)):int(2*getbytelen(p))]
744*f0865ec9SKyle Evans    r = wx + wy
745*f0865ec9SKyle Evans    s = stringtoint(sig[int(2*getbytelen(p)):int((2*getbytelen(p))+getbytelen(q))])
746*f0865ec9SKyle Evans    # Check r is on the curve
747*f0865ec9SKyle Evans    W = Point(pubkey.curve, stringtoint(wx), stringtoint(wy))
748*f0865ec9SKyle Evans    # Check s is in ]0,q[
749*f0865ec9SKyle Evans    if s == 0 or s > q:
750*f0865ec9SKyle Evans        raise Exception("ECFSDSA verify: s not in ]0,q[")
751*f0865ec9SKyle Evans    (h, _, _) = hashfunc(r + message)
752*f0865ec9SKyle Evans    e = (-stringtoint(h)) % q
753*f0865ec9SKyle Evans    W_ = s * G + e * pubkey.Y
754*f0865ec9SKyle Evans    r_ = expand(inttostring(W_.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W_.y), 8*getbytelen(p), "LEFT")
755*f0865ec9SKyle Evans    if r == r_:
756*f0865ec9SKyle Evans        return True
757*f0865ec9SKyle Evans    else:
758*f0865ec9SKyle Evans        return False
759*f0865ec9SKyle Evans
760*f0865ec9SKyle Evans
761*f0865ec9SKyle Evans# NOTE: ISO/IEC 14888-3 standard seems to diverge from the existing implementations
762*f0865ec9SKyle Evans# of ECRDSA when treating the message hash, and from the examples of certificates provided
763*f0865ec9SKyle Evans# in RFC 7091 and draft-deremin-rfc4491-bis. While in ISO/IEC 14888-3 it is explicitely asked
764*f0865ec9SKyle Evans# to proceed with the hash of the message as big endian, the RFCs derived from the Russian
765*f0865ec9SKyle Evans# standard expect the hash value to be treated as little endian when importing it as an integer
766*f0865ec9SKyle Evans# (this discrepancy is exhibited and confirmed by test vectors present in ISO/IEC 14888-3, and
767*f0865ec9SKyle Evans# by X.509 certificates present in the RFCs). This seems (to be confirmed) to be a discrepancy of
768*f0865ec9SKyle Evans# ISO/IEC 14888-3 algorithm description that must be fixed there.
769*f0865ec9SKyle Evans#
770*f0865ec9SKyle Evans# In order to be conservative, libecc uses the Russian standard behavior as expected to be in line with
771*f0865ec9SKyle Evans# other implemetations, but keeps the ISO/IEC 14888-3 behavior if forced/asked by the user using
772*f0865ec9SKyle Evans# the USE_ISO14888_3_ECRDSA toggle. This allows to keep backward compatibility with previous versions of the
773*f0865ec9SKyle Evans# library if needed.
774*f0865ec9SKyle Evans
775*f0865ec9SKyle Evans# *| IUF - ECRDSA signature
776*f0865ec9SKyle Evans# *|
777*f0865ec9SKyle Evans# *|  UF  1. Compute h = H(m)
778*f0865ec9SKyle Evans# *|   F  2. Get a random value k in ]0,q[
779*f0865ec9SKyle Evans# *|   F  3. Compute W = (W_x,W_y) = kG
780*f0865ec9SKyle Evans# *|   F  4. Compute r = W_x mod q
781*f0865ec9SKyle Evans# *|   F  5. If r is 0, restart the process at step 2.
782*f0865ec9SKyle Evans# *|   F  6. Compute e = OS2I(h) mod q. If e is 0, set e to 1.
783*f0865ec9SKyle Evans# *|         NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated.
784*f0865ec9SKyle Evans# *|         e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h
785*f0865ec9SKyle Evans# *|         is reversed for RFCs.
786*f0865ec9SKyle Evans# *|   F  7. Compute s = (rx + ke) mod q
787*f0865ec9SKyle Evans# *|   F  8. If s is 0, restart the process at step 2.
788*f0865ec9SKyle Evans# *|   F 11. Return (r,s)
789*f0865ec9SKyle Evansdef ecrdsa_sign(hashfunc, keypair, message, k=None, use_iso14888_divergence=False):
790*f0865ec9SKyle Evans    privkey = keypair.privkey
791*f0865ec9SKyle Evans    # Get important parameters from the curve
792*f0865ec9SKyle Evans    p = privkey.curve.p
793*f0865ec9SKyle Evans    q = privkey.curve.q
794*f0865ec9SKyle Evans    gx = privkey.curve.gx
795*f0865ec9SKyle Evans    gy = privkey.curve.gy
796*f0865ec9SKyle Evans    G = Point(privkey.curve, gx, gy)
797*f0865ec9SKyle Evans    (h, _, _) = hashfunc(message)
798*f0865ec9SKyle Evans    if use_iso14888_divergence == False:
799*f0865ec9SKyle Evans        # Reverse the endianness for Russian standard RFC ECRDSA (contrary to ISO/IEC 14888-3 case)
800*f0865ec9SKyle Evans        h = h[::-1]
801*f0865ec9SKyle Evans    OK = False
802*f0865ec9SKyle Evans    while OK == False:
803*f0865ec9SKyle Evans        if k == None:
804*f0865ec9SKyle Evans            k = getrandomint(q)
805*f0865ec9SKyle Evans        if k == 0:
806*f0865ec9SKyle Evans            continue
807*f0865ec9SKyle Evans        W = k * G
808*f0865ec9SKyle Evans        r = W.x % q
809*f0865ec9SKyle Evans        if r == 0:
810*f0865ec9SKyle Evans            continue
811*f0865ec9SKyle Evans        e = stringtoint(h) % q
812*f0865ec9SKyle Evans        if e == 0:
813*f0865ec9SKyle Evans            e = 1
814*f0865ec9SKyle Evans        s = ((r * privkey.x) + (k * e)) % q
815*f0865ec9SKyle Evans        if s == 0:
816*f0865ec9SKyle Evans            continue
817*f0865ec9SKyle Evans        OK = True
818*f0865ec9SKyle Evans    return (expand(inttostring(r), 8*getbytelen(q), "LEFT") + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k)
819*f0865ec9SKyle Evans
820*f0865ec9SKyle Evans# *| IUF - ECRDSA verification
821*f0865ec9SKyle Evans# *|
822*f0865ec9SKyle Evans# *|  UF 1. Check that r and s are both in ]0,q[
823*f0865ec9SKyle Evans# *|   F 2. Compute h = H(m)
824*f0865ec9SKyle Evans# *|   F 3. Compute e = OS2I(h)^-1 mod q
825*f0865ec9SKyle Evans# *|         NOTE: here, ISO/IEC 14888-3 and RFCs differ in the way e treated.
826*f0865ec9SKyle Evans# *|         e = OS2I(h) for ISO/IEC 14888-3, or e = OS2I(reversed(h)) when endianness of h
827*f0865ec9SKyle Evans# *|         is reversed for RFCs.
828*f0865ec9SKyle Evans# *|   F 4. Compute u = es mod q
829*f0865ec9SKyle Evans# *|   F 4. Compute v = -er mod q
830*f0865ec9SKyle Evans# *|   F 5. Compute W' = uG + vY = (W'_x, W'_y)
831*f0865ec9SKyle Evans# *|   F 6. Let's now compute r' = W'_x mod q
832*f0865ec9SKyle Evans# *|   F 7. Check r and r' are the same
833*f0865ec9SKyle Evansdef ecrdsa_verify(hashfunc, keypair, message, sig, use_iso14888_divergence=False):
834*f0865ec9SKyle Evans    pubkey = keypair.pubkey
835*f0865ec9SKyle Evans    # Get important parameters from the curve
836*f0865ec9SKyle Evans    p = pubkey.curve.p
837*f0865ec9SKyle Evans    q = pubkey.curve.q
838*f0865ec9SKyle Evans    gx = pubkey.curve.gx
839*f0865ec9SKyle Evans    gy = pubkey.curve.gy
840*f0865ec9SKyle Evans    G = Point(pubkey.curve, gx, gy)
841*f0865ec9SKyle Evans    # Extract coordinates from r and s from signature
842*f0865ec9SKyle Evans    if len(sig) != 2*getbytelen(q):
843*f0865ec9SKyle Evans        raise Exception("ECRDSA verify: bad signature length!")
844*f0865ec9SKyle Evans    r = stringtoint(sig[:int(getbytelen(q))])
845*f0865ec9SKyle Evans    s = stringtoint(sig[int(getbytelen(q)):int(2*getbytelen(q))])
846*f0865ec9SKyle Evans    if r == 0 or r > q:
847*f0865ec9SKyle Evans        raise Exception("ECRDSA verify: r not in ]0,q[")
848*f0865ec9SKyle Evans    if s == 0 or s > q:
849*f0865ec9SKyle Evans        raise Exception("ECRDSA verify: s not in ]0,q[")
850*f0865ec9SKyle Evans    (h, _, _) = hashfunc(message)
851*f0865ec9SKyle Evans    if use_iso14888_divergence == False:
852*f0865ec9SKyle Evans        # Reverse the endianness for Russian standard RFC ECRDSA (contrary to ISO/IEC 14888-3 case)
853*f0865ec9SKyle Evans        h = h[::-1]
854*f0865ec9SKyle Evans    e = modinv(stringtoint(h) % q, q)
855*f0865ec9SKyle Evans    u = (e * s) % q
856*f0865ec9SKyle Evans    v = (-e * r) % q
857*f0865ec9SKyle Evans    W_ = u * G + v * pubkey.Y
858*f0865ec9SKyle Evans    r_ = W_.x % q
859*f0865ec9SKyle Evans    if r == r_:
860*f0865ec9SKyle Evans        return True
861*f0865ec9SKyle Evans    else:
862*f0865ec9SKyle Evans        return False
863*f0865ec9SKyle Evans
864*f0865ec9SKyle Evans
865*f0865ec9SKyle Evans# *| IUF - ECGDSA signature
866*f0865ec9SKyle Evans# *|
867*f0865ec9SKyle Evans# *|  UF 1. Compute h = H(m). If |h| > bitlen(q), set h to bitlen(q)
868*f0865ec9SKyle Evans# *|         leftmost (most significant) bits of h
869*f0865ec9SKyle Evans# *|   F 2. Convert e = - OS2I(h) mod q
870*f0865ec9SKyle Evans# *|   F 3. Get a random value k in ]0,q[
871*f0865ec9SKyle Evans# *|   F 4. Compute W = (W_x,W_y) = kG
872*f0865ec9SKyle Evans# *|   F 5. Compute r = W_x mod q
873*f0865ec9SKyle Evans# *|   F 6. If r is 0, restart the process at step 4.
874*f0865ec9SKyle Evans# *|   F 7. Compute s = x(kr + e) mod q
875*f0865ec9SKyle Evans# *|   F 8. If s is 0, restart the process at step 4.
876*f0865ec9SKyle Evans# *|   F 9. Return (r,s)
877*f0865ec9SKyle Evansdef ecgdsa_sign(hashfunc, keypair, message, k=None):
878*f0865ec9SKyle Evans    privkey = keypair.privkey
879*f0865ec9SKyle Evans    # Get important parameters from the curve
880*f0865ec9SKyle Evans    p = privkey.curve.p
881*f0865ec9SKyle Evans    q = privkey.curve.q
882*f0865ec9SKyle Evans    gx = privkey.curve.gx
883*f0865ec9SKyle Evans    gy = privkey.curve.gy
884*f0865ec9SKyle Evans    G = Point(privkey.curve, gx, gy)
885*f0865ec9SKyle Evans    (h, _, _) = hashfunc(message)
886*f0865ec9SKyle Evans    q_limit_len = getbitlen(q)
887*f0865ec9SKyle Evans    # Truncate hash value
888*f0865ec9SKyle Evans    h = truncate(h, q_limit_len, "LEFT")
889*f0865ec9SKyle Evans    e = (-stringtoint(h)) % q
890*f0865ec9SKyle Evans    OK = False
891*f0865ec9SKyle Evans    while OK == False:
892*f0865ec9SKyle Evans        if k == None:
893*f0865ec9SKyle Evans            k = getrandomint(q)
894*f0865ec9SKyle Evans        if k == 0:
895*f0865ec9SKyle Evans            continue
896*f0865ec9SKyle Evans        W = k * G
897*f0865ec9SKyle Evans        r = W.x % q
898*f0865ec9SKyle Evans        if r == 0:
899*f0865ec9SKyle Evans            continue
900*f0865ec9SKyle Evans        s = (privkey.x * ((k * r) + e)) % q
901*f0865ec9SKyle Evans        if s == 0:
902*f0865ec9SKyle Evans            continue
903*f0865ec9SKyle Evans        OK = True
904*f0865ec9SKyle Evans    return (expand(inttostring(r), 8*getbytelen(q), "LEFT") + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k)
905*f0865ec9SKyle Evans
906*f0865ec9SKyle Evans# *| IUF - ECGDSA verification
907*f0865ec9SKyle Evans# *|
908*f0865ec9SKyle Evans# *| I   1. Reject the signature if r or s is 0.
909*f0865ec9SKyle Evans# *|  UF 2. Compute h = H(m). If |h| > bitlen(q), set h to bitlen(q)
910*f0865ec9SKyle Evans# *|         leftmost (most significant) bits of h
911*f0865ec9SKyle Evans# *|   F 3. Compute e = OS2I(h) mod q
912*f0865ec9SKyle Evans# *|   F 4. Compute u = ((r^-1)e mod q)
913*f0865ec9SKyle Evans# *|   F 5. Compute v = ((r^-1)s mod q)
914*f0865ec9SKyle Evans# *|   F 6. Compute W' = uG + vY
915*f0865ec9SKyle Evans# *|   F 7. Compute r' = W'_x mod q
916*f0865ec9SKyle Evans# *|   F 8. Accept the signature if and only if r equals r'
917*f0865ec9SKyle Evansdef ecgdsa_verify(hashfunc, keypair, message, sig):
918*f0865ec9SKyle Evans    pubkey = keypair.pubkey
919*f0865ec9SKyle Evans    # Get important parameters from the curve
920*f0865ec9SKyle Evans    p = pubkey.curve.p
921*f0865ec9SKyle Evans    q = pubkey.curve.q
922*f0865ec9SKyle Evans    gx = pubkey.curve.gx
923*f0865ec9SKyle Evans    gy = pubkey.curve.gy
924*f0865ec9SKyle Evans    G = Point(pubkey.curve, gx, gy)
925*f0865ec9SKyle Evans    # Extract coordinates from r and s from signature
926*f0865ec9SKyle Evans    if len(sig) != 2*getbytelen(q):
927*f0865ec9SKyle Evans        raise Exception("ECGDSA verify: bad signature length!")
928*f0865ec9SKyle Evans    r = stringtoint(sig[:int(getbytelen(q))])
929*f0865ec9SKyle Evans    s = stringtoint(sig[int(getbytelen(q)):int(2*getbytelen(q))])
930*f0865ec9SKyle Evans    if r == 0 or r > q:
931*f0865ec9SKyle Evans        raise Exception("ECGDSA verify: r not in ]0,q[")
932*f0865ec9SKyle Evans    if s == 0 or s > q:
933*f0865ec9SKyle Evans        raise Exception("ECGDSA verify: s not in ]0,q[")
934*f0865ec9SKyle Evans    (h, _, _) = hashfunc(message)
935*f0865ec9SKyle Evans    q_limit_len = getbitlen(q)
936*f0865ec9SKyle Evans    # Truncate hash value
937*f0865ec9SKyle Evans    h = truncate(h, q_limit_len, "LEFT")
938*f0865ec9SKyle Evans    e = stringtoint(h) % q
939*f0865ec9SKyle Evans    r_inv = modinv(r, q)
940*f0865ec9SKyle Evans    u = (r_inv * e) % q
941*f0865ec9SKyle Evans    v = (r_inv * s) % q
942*f0865ec9SKyle Evans    W_ = u * G + v * pubkey.Y
943*f0865ec9SKyle Evans    r_ = W_.x % q
944*f0865ec9SKyle Evans    if r == r_:
945*f0865ec9SKyle Evans        return True
946*f0865ec9SKyle Evans    else:
947*f0865ec9SKyle Evans        return False
948*f0865ec9SKyle Evans
949*f0865ec9SKyle Evans# *| IUF - ECSDSA/ECOSDSA signature
950*f0865ec9SKyle Evans# *|
951*f0865ec9SKyle Evans# *| I   1. Get a random value k in ]0, q[
952*f0865ec9SKyle Evans# *| I   2. Compute W = kG = (Wx, Wy)
953*f0865ec9SKyle Evans# *| IUF 3. Compute r = H(Wx [|| Wy] || m)
954*f0865ec9SKyle Evans# *|        - In the normal version (ECSDSA), r = h(Wx || Wy || m).
955*f0865ec9SKyle Evans# *|        - In the optimized version (ECOSDSA), r = h(Wx || m).
956*f0865ec9SKyle Evans# *|   F 4. Compute e = OS2I(r) mod q
957*f0865ec9SKyle Evans# *|   F 5. if e == 0, restart at step 1.
958*f0865ec9SKyle Evans# *|   F 6. Compute s = (k + ex) mod q.
959*f0865ec9SKyle Evans# *|   F 7. if s == 0, restart at step 1.
960*f0865ec9SKyle Evans# *|   F 8. Return (r, s)
961*f0865ec9SKyle Evansdef ecsdsa_common_sign(hashfunc, keypair, message, optimized, k=None):
962*f0865ec9SKyle Evans    privkey = keypair.privkey
963*f0865ec9SKyle Evans    # Get important parameters from the curve
964*f0865ec9SKyle Evans    p = privkey.curve.p
965*f0865ec9SKyle Evans    q = privkey.curve.q
966*f0865ec9SKyle Evans    gx = privkey.curve.gx
967*f0865ec9SKyle Evans    gy = privkey.curve.gy
968*f0865ec9SKyle Evans    G = Point(privkey.curve, gx, gy)
969*f0865ec9SKyle Evans    OK = False
970*f0865ec9SKyle Evans    while OK == False:
971*f0865ec9SKyle Evans        if k == None:
972*f0865ec9SKyle Evans            k = getrandomint(q)
973*f0865ec9SKyle Evans        if k == 0:
974*f0865ec9SKyle Evans            continue
975*f0865ec9SKyle Evans        W = k * G
976*f0865ec9SKyle Evans        if optimized == False:
977*f0865ec9SKyle Evans            (r, _, _) = hashfunc(expand(inttostring(W.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W.y), 8*getbytelen(p), "LEFT") + message)
978*f0865ec9SKyle Evans        else:
979*f0865ec9SKyle Evans            (r, _, _) = hashfunc(expand(inttostring(W.x), 8*getbytelen(p), "LEFT") + message)
980*f0865ec9SKyle Evans        e = stringtoint(r) % q
981*f0865ec9SKyle Evans        if e == 0:
982*f0865ec9SKyle Evans            continue
983*f0865ec9SKyle Evans        s = (k + (e * privkey.x)) % q
984*f0865ec9SKyle Evans        if s == 0:
985*f0865ec9SKyle Evans            continue
986*f0865ec9SKyle Evans        OK = True
987*f0865ec9SKyle Evans    return (r + expand(inttostring(s), 8*getbytelen(q), "LEFT"), k)
988*f0865ec9SKyle Evans
989*f0865ec9SKyle Evansdef ecsdsa_sign(hashfunc, keypair, message, k=None):
990*f0865ec9SKyle Evans    return ecsdsa_common_sign(hashfunc, keypair, message, False, k)
991*f0865ec9SKyle Evans
992*f0865ec9SKyle Evansdef ecosdsa_sign(hashfunc, keypair, message, k=None):
993*f0865ec9SKyle Evans    return ecsdsa_common_sign(hashfunc, keypair, message, True, k)
994*f0865ec9SKyle Evans
995*f0865ec9SKyle Evans# *| IUF - ECSDSA/ECOSDSA verification
996*f0865ec9SKyle Evans# *|
997*f0865ec9SKyle Evans# *| I   1. if s is not in ]0,q[, reject the signature.x
998*f0865ec9SKyle Evans# *| I   2. Compute e = -r mod q
999*f0865ec9SKyle Evans# *| I   3. If e == 0, reject the signature.
1000*f0865ec9SKyle Evans# *| I   4. Compute W' = sG + eY
1001*f0865ec9SKyle Evans# *| IUF 5. Compute r' = H(W'x [|| W'y] || m)
1002*f0865ec9SKyle Evans# *|        - In the normal version (ECSDSA), r = h(W'x || W'y || m).
1003*f0865ec9SKyle Evans# *|        - In the optimized version (ECOSDSA), r = h(W'x || m).
1004*f0865ec9SKyle Evans# *|   F 6. Accept the signature if and only if r and r' are the same
1005*f0865ec9SKyle Evansdef ecsdsa_common_verify(hashfunc, keypair, message, sig, optimized):
1006*f0865ec9SKyle Evans    pubkey = keypair.pubkey
1007*f0865ec9SKyle Evans    # Get important parameters from the curve
1008*f0865ec9SKyle Evans    p = pubkey.curve.p
1009*f0865ec9SKyle Evans    q = pubkey.curve.q
1010*f0865ec9SKyle Evans    gx = pubkey.curve.gx
1011*f0865ec9SKyle Evans    gy = pubkey.curve.gy
1012*f0865ec9SKyle Evans    G = Point(pubkey.curve, gx, gy)
1013*f0865ec9SKyle Evans    (_, hlen, _) = hashfunc("")
1014*f0865ec9SKyle Evans    # Extract coordinates from r and s from signature
1015*f0865ec9SKyle Evans    if len(sig) != hlen + getbytelen(q):
1016*f0865ec9SKyle Evans        raise Exception("EC[O]SDSA verify: bad signature length!")
1017*f0865ec9SKyle Evans    r = stringtoint(sig[:int(hlen)])
1018*f0865ec9SKyle Evans    s = stringtoint(sig[int(hlen):int(hlen+getbytelen(q))])
1019*f0865ec9SKyle Evans    if s == 0 or s > q:
1020*f0865ec9SKyle Evans        raise Exception("EC[O]DSA verify: s not in ]0,q[")
1021*f0865ec9SKyle Evans    e = (-r) % q
1022*f0865ec9SKyle Evans    if e == 0:
1023*f0865ec9SKyle Evans        raise Exception("EC[O]DSA verify: e is null")
1024*f0865ec9SKyle Evans    W_ = s * G + e * pubkey.Y
1025*f0865ec9SKyle Evans    if optimized == False:
1026*f0865ec9SKyle Evans        (r_, _, _) = hashfunc(expand(inttostring(W_.x), 8*getbytelen(p), "LEFT") + expand(inttostring(W_.y), 8*getbytelen(p), "LEFT") + message)
1027*f0865ec9SKyle Evans    else:
1028*f0865ec9SKyle Evans        (r_, _, _) = hashfunc(expand(inttostring(W_.x), 8*getbytelen(p), "LEFT") + message)
1029*f0865ec9SKyle Evans    if sig[:int(hlen)] == r_:
1030*f0865ec9SKyle Evans        return True
1031*f0865ec9SKyle Evans    else:
1032*f0865ec9SKyle Evans        return False
1033*f0865ec9SKyle Evans
1034*f0865ec9SKyle Evansdef ecsdsa_verify(hashfunc, keypair, message, sig):
1035*f0865ec9SKyle Evans    return ecsdsa_common_verify(hashfunc, keypair, message, sig, False)
1036*f0865ec9SKyle Evans
1037*f0865ec9SKyle Evansdef ecosdsa_verify(hashfunc, keypair, message, sig):
1038*f0865ec9SKyle Evans    return ecsdsa_common_verify(hashfunc, keypair, message, sig, True)
1039*f0865ec9SKyle Evans
1040*f0865ec9SKyle Evans
1041*f0865ec9SKyle Evans##########################################################
1042*f0865ec9SKyle Evans### Generate self-tests for all the algorithms
1043*f0865ec9SKyle Evans
1044*f0865ec9SKyle Evansall_hash_funcs = [ (sha224, "SHA224"), (sha256, "SHA256"), (sha384, "SHA384"), (sha512, "SHA512"), (sha3_224, "SHA3_224"), (sha3_256, "SHA3_256"), (sha3_384, "SHA3_384"), (sha3_512, "SHA3_512") ]
1045*f0865ec9SKyle Evans
1046*f0865ec9SKyle Evansall_sig_algs = [ (ecdsa_sign, ecdsa_verify, genKeyPair, "ECDSA"),
1047*f0865ec9SKyle Evans         (eckcdsa_sign, eckcdsa_verify, eckcdsa_genKeyPair, "ECKCDSA"),
1048*f0865ec9SKyle Evans         (ecfsdsa_sign, ecfsdsa_verify, genKeyPair, "ECFSDSA"),
1049*f0865ec9SKyle Evans         (ecrdsa_sign, ecrdsa_verify, genKeyPair, "ECRDSA"),
1050*f0865ec9SKyle Evans         (ecgdsa_sign, ecgdsa_verify, eckcdsa_genKeyPair, "ECGDSA"),
1051*f0865ec9SKyle Evans         (ecsdsa_sign, ecsdsa_verify, genKeyPair, "ECSDSA"),
1052*f0865ec9SKyle Evans         (ecosdsa_sign, ecosdsa_verify, genKeyPair, "ECOSDSA"), ]
1053*f0865ec9SKyle Evans
1054*f0865ec9SKyle Evans
1055*f0865ec9SKyle Evanscurr_test = 0
1056*f0865ec9SKyle Evansdef pretty_print_curr_test(num_test, total_gen_tests):
1057*f0865ec9SKyle Evans    num_decimal = int(math.log10(total_gen_tests))+1
1058*f0865ec9SKyle Evans    format_buf = "%0"+str(num_decimal)+"d/%0"+str(num_decimal)+"d"
1059*f0865ec9SKyle Evans    sys.stdout.write('\b'*((2*num_decimal)+1))
1060*f0865ec9SKyle Evans    sys.stdout.flush()
1061*f0865ec9SKyle Evans    sys.stdout.write(format_buf % (num_test, total_gen_tests))
1062*f0865ec9SKyle Evans    if num_test == total_gen_tests:
1063*f0865ec9SKyle Evans        print("")
1064*f0865ec9SKyle Evans    return
1065*f0865ec9SKyle Evans
1066*f0865ec9SKyle Evansdef gen_self_test(curve, hashfunc, sig_alg_sign, sig_alg_verify, sig_alg_genkeypair, num, hashfunc_name, sig_alg_name, total_gen_tests):
1067*f0865ec9SKyle Evans    global curr_test
1068*f0865ec9SKyle Evans    curr_test = curr_test + 1
1069*f0865ec9SKyle Evans    if num != 0:
1070*f0865ec9SKyle Evans        pretty_print_curr_test(curr_test, total_gen_tests)
1071*f0865ec9SKyle Evans    output_list = []
1072*f0865ec9SKyle Evans    for test_num in range(0, num):
1073*f0865ec9SKyle Evans        out_vectors = ""
1074*f0865ec9SKyle Evans        # Generate a random key pair
1075*f0865ec9SKyle Evans        keypair = sig_alg_genkeypair(curve)
1076*f0865ec9SKyle Evans        # Generate a random message with a random size
1077*f0865ec9SKyle Evans        size = getrandomint(256)
1078*f0865ec9SKyle Evans        if is_python_2():
1079*f0865ec9SKyle Evans            message = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(size)])
1080*f0865ec9SKyle Evans        else:
1081*f0865ec9SKyle Evans            message = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(size)])
1082*f0865ec9SKyle Evans        test_name = sig_alg_name + "_" + hashfunc_name + "_" + curve.name.upper() + "_" + str(test_num)
1083*f0865ec9SKyle Evans        # Sign the message
1084*f0865ec9SKyle Evans        (sig, k) = sig_alg_sign(hashfunc, keypair, message)
1085*f0865ec9SKyle Evans        # Check that everything is OK with a verify
1086*f0865ec9SKyle Evans        if sig_alg_verify(hashfunc, keypair, message, sig) != True:
1087*f0865ec9SKyle Evans            raise Exception("Error during self test generation: sig verify failed! "+test_name+ "   /  msg="+message+"   /   sig="+binascii.hexlify(sig)+"    /    k="+hex(k)+"   /   privkey.x="+hex(keypair.privkey.x))
1088*f0865ec9SKyle Evans        if sig_alg_name == "ECRDSA":
1089*f0865ec9SKyle Evans            out_vectors += "#ifndef USE_ISO14888_3_ECRDSA\n"
1090*f0865ec9SKyle Evans        # Now generate the test vector
1091*f0865ec9SKyle Evans        out_vectors += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"\n"
1092*f0865ec9SKyle Evans        out_vectors += "#ifdef WITH_CURVE_"+curve.name.upper()+"\n"
1093*f0865ec9SKyle Evans        out_vectors += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"\n"
1094*f0865ec9SKyle Evans        out_vectors += "/* "+test_name+" known test vectors */\n"
1095*f0865ec9SKyle Evans        out_vectors += "static int "+test_name+"_test_vectors_get_random(nn_t out, nn_src_t q)\n{\n"
1096*f0865ec9SKyle Evans        # k_buf MUST be exported padded to the length of q
1097*f0865ec9SKyle Evans        out_vectors += "\tconst u8 k_buf[] = "+bigint_to_C_array(k, getbytelen(curve.q))
1098*f0865ec9SKyle Evans        out_vectors += "\tint ret, cmp;\n\tret = nn_init_from_buf(out, k_buf, sizeof(k_buf)); EG(ret, err);\n\tret = nn_cmp(out, q, &cmp); EG(ret, err);\n\tret = (cmp >= 0) ? -1 : 0;\nerr:\n\treturn ret;\n}\n"
1099*f0865ec9SKyle Evans        out_vectors += "static const u8 "+test_name+"_test_vectors_priv_key[] = \n"+bigint_to_C_array(keypair.privkey.x, getbytelen(keypair.privkey.x))
1100*f0865ec9SKyle Evans        out_vectors += "static const u8 "+test_name+"_test_vectors_expected_sig[] = \n"+bigint_to_C_array(stringtoint(sig), len(sig))
1101*f0865ec9SKyle Evans        out_vectors += "static const ec_test_case "+test_name+"_test_case = {\n"
1102*f0865ec9SKyle Evans        out_vectors += "\t.name = \""+test_name+"\",\n"
1103*f0865ec9SKyle Evans        out_vectors += "\t.ec_str_p = &"+curve.name+"_str_params,\n"
1104*f0865ec9SKyle Evans        out_vectors += "\t.priv_key = "+test_name+"_test_vectors_priv_key,\n"
1105*f0865ec9SKyle Evans        out_vectors += "\t.priv_key_len = sizeof("+test_name+"_test_vectors_priv_key),\n"
1106*f0865ec9SKyle Evans        out_vectors += "\t.nn_random = "+test_name+"_test_vectors_get_random,\n"
1107*f0865ec9SKyle Evans        out_vectors += "\t.hash_type = "+hashfunc_name+",\n"
1108*f0865ec9SKyle Evans        out_vectors += "\t.msg = \""+message+"\",\n"
1109*f0865ec9SKyle Evans        out_vectors += "\t.msglen = "+str(len(message))+",\n"
1110*f0865ec9SKyle Evans        out_vectors += "\t.sig_type = "+sig_alg_name+",\n"
1111*f0865ec9SKyle Evans        out_vectors += "\t.exp_sig = "+test_name+"_test_vectors_expected_sig,\n"
1112*f0865ec9SKyle Evans        out_vectors += "\t.exp_siglen = sizeof("+test_name+"_test_vectors_expected_sig),\n};\n"
1113*f0865ec9SKyle Evans        out_vectors += "#endif /* WITH_HASH_"+hashfunc_name+" */\n"
1114*f0865ec9SKyle Evans        out_vectors += "#endif /* WITH_CURVE_"+curve.name+" */\n"
1115*f0865ec9SKyle Evans        out_vectors += "#endif /* WITH_SIG_"+sig_alg_name+" */\n"
1116*f0865ec9SKyle Evans        if sig_alg_name == "ECRDSA":
1117*f0865ec9SKyle Evans            out_vectors += "#endif /* !USE_ISO14888_3_ECRDSA */\n"
1118*f0865ec9SKyle Evans        out_name = ""
1119*f0865ec9SKyle Evans        if sig_alg_name == "ECRDSA":
1120*f0865ec9SKyle Evans            out_name += "#ifndef USE_ISO14888_3_ECRDSA"+"/* For "+test_name+" */\n"
1121*f0865ec9SKyle Evans        out_name += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"/* For "+test_name+" */\n"
1122*f0865ec9SKyle Evans        out_name += "#ifdef WITH_CURVE_"+curve.name.upper()+"/* For "+test_name+" */\n"
1123*f0865ec9SKyle Evans        out_name += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"/* For "+test_name+" */\n"
1124*f0865ec9SKyle Evans        out_name += "\t&"+test_name+"_test_case,\n"
1125*f0865ec9SKyle Evans        out_name += "#endif /* WITH_HASH_"+hashfunc_name+" for "+test_name+" */\n"
1126*f0865ec9SKyle Evans        out_name += "#endif /* WITH_CURVE_"+curve.name+" for "+test_name+" */\n"
1127*f0865ec9SKyle Evans        out_name += "#endif /* WITH_SIG_"+sig_alg_name+" for "+test_name+" */"
1128*f0865ec9SKyle Evans        if sig_alg_name == "ECRDSA":
1129*f0865ec9SKyle Evans            out_name += "\n#endif /* !USE_ISO14888_3_ECRDSA */"+"/* For "+test_name+" */"
1130*f0865ec9SKyle Evans        output_list.append((out_name, out_vectors))
1131*f0865ec9SKyle Evans        # In the specific case of ECRDSA, we also generate an ISO/IEC compatible test vector
1132*f0865ec9SKyle Evans        if sig_alg_name == "ECRDSA":
1133*f0865ec9SKyle Evans            out_vectors = ""
1134*f0865ec9SKyle Evans            (sig, k) = sig_alg_sign(hashfunc, keypair, message, use_iso14888_divergence=True)
1135*f0865ec9SKyle Evans            # Check that everything is OK with a verify
1136*f0865ec9SKyle Evans            if sig_alg_verify(hashfunc, keypair, message, sig, use_iso14888_divergence=True) != True:
1137*f0865ec9SKyle Evans                raise Exception("Error during self test generation: sig verify failed! "+test_name+ "   /  msg="+message+"   /   sig="+binascii.hexlify(sig)+"    /    k="+hex(k)+"   /   privkey.x="+hex(keypair.privkey.x))
1138*f0865ec9SKyle Evans            out_vectors += "#ifdef USE_ISO14888_3_ECRDSA\n"
1139*f0865ec9SKyle Evans            # Now generate the test vector
1140*f0865ec9SKyle Evans            out_vectors += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"\n"
1141*f0865ec9SKyle Evans            out_vectors += "#ifdef WITH_CURVE_"+curve.name.upper()+"\n"
1142*f0865ec9SKyle Evans            out_vectors += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"\n"
1143*f0865ec9SKyle Evans            out_vectors += "/* "+test_name+" known test vectors */\n"
1144*f0865ec9SKyle Evans            out_vectors += "static int "+test_name+"_test_vectors_get_random(nn_t out, nn_src_t q)\n{\n"
1145*f0865ec9SKyle Evans            # k_buf MUST be exported padded to the length of q
1146*f0865ec9SKyle Evans            out_vectors += "\tconst u8 k_buf[] = "+bigint_to_C_array(k, getbytelen(curve.q))
1147*f0865ec9SKyle Evans            out_vectors += "\tint ret, cmp;\n\tret = nn_init_from_buf(out, k_buf, sizeof(k_buf)); EG(ret, err);\n\tret = nn_cmp(out, q, &cmp); EG(ret, err);\n\tret = (cmp >= 0) ? -1 : 0;\nerr:\n\treturn ret;\n}\n"
1148*f0865ec9SKyle Evans            out_vectors += "static const u8 "+test_name+"_test_vectors_priv_key[] = \n"+bigint_to_C_array(keypair.privkey.x, getbytelen(keypair.privkey.x))
1149*f0865ec9SKyle Evans            out_vectors += "static const u8 "+test_name+"_test_vectors_expected_sig[] = \n"+bigint_to_C_array(stringtoint(sig), len(sig))
1150*f0865ec9SKyle Evans            out_vectors += "static const ec_test_case "+test_name+"_test_case = {\n"
1151*f0865ec9SKyle Evans            out_vectors += "\t.name = \""+test_name+"\",\n"
1152*f0865ec9SKyle Evans            out_vectors += "\t.ec_str_p = &"+curve.name+"_str_params,\n"
1153*f0865ec9SKyle Evans            out_vectors += "\t.priv_key = "+test_name+"_test_vectors_priv_key,\n"
1154*f0865ec9SKyle Evans            out_vectors += "\t.priv_key_len = sizeof("+test_name+"_test_vectors_priv_key),\n"
1155*f0865ec9SKyle Evans            out_vectors += "\t.nn_random = "+test_name+"_test_vectors_get_random,\n"
1156*f0865ec9SKyle Evans            out_vectors += "\t.hash_type = "+hashfunc_name+",\n"
1157*f0865ec9SKyle Evans            out_vectors += "\t.msg = \""+message+"\",\n"
1158*f0865ec9SKyle Evans            out_vectors += "\t.msglen = "+str(len(message))+",\n"
1159*f0865ec9SKyle Evans            out_vectors += "\t.sig_type = "+sig_alg_name+",\n"
1160*f0865ec9SKyle Evans            out_vectors += "\t.exp_sig = "+test_name+"_test_vectors_expected_sig,\n"
1161*f0865ec9SKyle Evans            out_vectors += "\t.exp_siglen = sizeof("+test_name+"_test_vectors_expected_sig),\n};\n"
1162*f0865ec9SKyle Evans            out_vectors += "#endif /* WITH_HASH_"+hashfunc_name+" */\n"
1163*f0865ec9SKyle Evans            out_vectors += "#endif /* WITH_CURVE_"+curve.name+" */\n"
1164*f0865ec9SKyle Evans            out_vectors += "#endif /* WITH_SIG_"+sig_alg_name+" */\n"
1165*f0865ec9SKyle Evans            out_vectors += "#endif /* USE_ISO14888_3_ECRDSA */\n"
1166*f0865ec9SKyle Evans            out_name = ""
1167*f0865ec9SKyle Evans            out_name += "#ifdef USE_ISO14888_3_ECRDSA"+"/* For "+test_name+" */\n"
1168*f0865ec9SKyle Evans            out_name += "#ifdef WITH_HASH_"+hashfunc_name.upper()+"/* For "+test_name+" */\n"
1169*f0865ec9SKyle Evans            out_name += "#ifdef WITH_CURVE_"+curve.name.upper()+"/* For "+test_name+" */\n"
1170*f0865ec9SKyle Evans            out_name += "#ifdef WITH_SIG_"+sig_alg_name.upper()+"/* For "+test_name+" */\n"
1171*f0865ec9SKyle Evans            out_name += "\t&"+test_name+"_test_case,\n"
1172*f0865ec9SKyle Evans            out_name += "#endif /* WITH_HASH_"+hashfunc_name+" for "+test_name+" */\n"
1173*f0865ec9SKyle Evans            out_name += "#endif /* WITH_CURVE_"+curve.name+" for "+test_name+" */\n"
1174*f0865ec9SKyle Evans            out_name += "#endif /* WITH_SIG_"+sig_alg_name+" for "+test_name+" */\n"
1175*f0865ec9SKyle Evans            out_name += "#endif /* USE_ISO14888_3_ECRDSA */"+"/* For "+test_name+" */"
1176*f0865ec9SKyle Evans            output_list.append((out_name, out_vectors))
1177*f0865ec9SKyle Evans
1178*f0865ec9SKyle Evans    return output_list
1179*f0865ec9SKyle Evans
1180*f0865ec9SKyle Evansdef gen_self_tests(curve, num):
1181*f0865ec9SKyle Evans    global curr_test
1182*f0865ec9SKyle Evans    curr_test = 0
1183*f0865ec9SKyle Evans    total_gen_tests = len(all_hash_funcs) * len(all_sig_algs)
1184*f0865ec9SKyle Evans    vectors = [[ gen_self_test(curve, hashf, sign, verify, genkp, num, hash_name, sig_alg_name, total_gen_tests)
1185*f0865ec9SKyle Evans               for (hashf, hash_name) in all_hash_funcs ] for (sign, verify, genkp, sig_alg_name) in all_sig_algs ]
1186*f0865ec9SKyle Evans    return vectors
1187*f0865ec9SKyle Evans
1188*f0865ec9SKyle Evans##########################################################
1189*f0865ec9SKyle Evans### ASN.1 stuff
1190*f0865ec9SKyle Evansdef parse_DER_extract_size(derbuf):
1191*f0865ec9SKyle Evans    # Extract the size
1192*f0865ec9SKyle Evans    if ord(derbuf[0]) & 0x80 != 0:
1193*f0865ec9SKyle Evans        encoding_len_bytes = ord(derbuf[0]) & ~0x80
1194*f0865ec9SKyle Evans        # Skip
1195*f0865ec9SKyle Evans        base = 1
1196*f0865ec9SKyle Evans    else:
1197*f0865ec9SKyle Evans        encoding_len_bytes = 1
1198*f0865ec9SKyle Evans        base = 0
1199*f0865ec9SKyle Evans    if len(derbuf) < encoding_len_bytes+1:
1200*f0865ec9SKyle Evans        return (False, 0, 0)
1201*f0865ec9SKyle Evans    else:
1202*f0865ec9SKyle Evans        length = stringtoint(derbuf[base:base+encoding_len_bytes])
1203*f0865ec9SKyle Evans        if len(derbuf) < length+encoding_len_bytes:
1204*f0865ec9SKyle Evans            return (False, 0, 0)
1205*f0865ec9SKyle Evans        else:
1206*f0865ec9SKyle Evans            return (True, encoding_len_bytes+base, length)
1207*f0865ec9SKyle Evans
1208*f0865ec9SKyle Evansdef extract_DER_object(derbuf, object_tag):
1209*f0865ec9SKyle Evans    # Check type
1210*f0865ec9SKyle Evans    if ord(derbuf[0]) != object_tag:
1211*f0865ec9SKyle Evans        # Not the type we expect ...
1212*f0865ec9SKyle Evans        return (False, 0, "")
1213*f0865ec9SKyle Evans    else:
1214*f0865ec9SKyle Evans        derbuf = derbuf[1:]
1215*f0865ec9SKyle Evans        # Extract the size
1216*f0865ec9SKyle Evans        (check, encoding_len, size) = parse_DER_extract_size(derbuf)
1217*f0865ec9SKyle Evans        if check == False:
1218*f0865ec9SKyle Evans            return (False, 0, "")
1219*f0865ec9SKyle Evans        else:
1220*f0865ec9SKyle Evans            if len(derbuf) < encoding_len + size:
1221*f0865ec9SKyle Evans                return (False, 0, "")
1222*f0865ec9SKyle Evans            else:
1223*f0865ec9SKyle Evans                return (True, size+encoding_len+1, derbuf[encoding_len:encoding_len+size])
1224*f0865ec9SKyle Evans
1225*f0865ec9SKyle Evansdef extract_DER_sequence(derbuf):
1226*f0865ec9SKyle Evans    return extract_DER_object(derbuf, 0x30)
1227*f0865ec9SKyle Evans
1228*f0865ec9SKyle Evansdef extract_DER_integer(derbuf):
1229*f0865ec9SKyle Evans    return extract_DER_object(derbuf, 0x02)
1230*f0865ec9SKyle Evans
1231*f0865ec9SKyle Evansdef extract_DER_octetstring(derbuf):
1232*f0865ec9SKyle Evans    return extract_DER_object(derbuf, 0x04)
1233*f0865ec9SKyle Evans
1234*f0865ec9SKyle Evansdef extract_DER_bitstring(derbuf):
1235*f0865ec9SKyle Evans    return extract_DER_object(derbuf, 0x03)
1236*f0865ec9SKyle Evans
1237*f0865ec9SKyle Evansdef extract_DER_oid(derbuf):
1238*f0865ec9SKyle Evans    return extract_DER_object(derbuf, 0x06)
1239*f0865ec9SKyle Evans
1240*f0865ec9SKyle Evans# See ECParameters sequence in RFC 3279
1241*f0865ec9SKyle Evansdef parse_DER_ECParameters(derbuf):
1242*f0865ec9SKyle Evans    # XXX: this is a very ugly way of extracting the information
1243*f0865ec9SKyle Evans    # regarding an EC curve, but since the ASN.1 structure is quite
1244*f0865ec9SKyle Evans    # "static", this might be sufficient without embedding a full
1245*f0865ec9SKyle Evans    # ASN.1 parser ...
1246*f0865ec9SKyle Evans    # Default return (a, b, prime, order, cofactor, gx, gy)
1247*f0865ec9SKyle Evans    default_ret = (0, 0, 0, 0, 0, 0, 0)
1248*f0865ec9SKyle Evans    # Get ECParameters wrapping sequence
1249*f0865ec9SKyle Evans    (check, size_ECParameters, ECParameters) = extract_DER_sequence(derbuf)
1250*f0865ec9SKyle Evans    if check == False:
1251*f0865ec9SKyle Evans        return (False, default_ret)
1252*f0865ec9SKyle Evans    # Get integer
1253*f0865ec9SKyle Evans    (check, size_ECPVer, ECPVer) = extract_DER_integer(ECParameters)
1254*f0865ec9SKyle Evans    if check == False:
1255*f0865ec9SKyle Evans        return (False, default_ret)
1256*f0865ec9SKyle Evans    # Get sequence
1257*f0865ec9SKyle Evans    (check, size_FieldID, FieldID) = extract_DER_sequence(ECParameters[size_ECPVer:])
1258*f0865ec9SKyle Evans    if check == False:
1259*f0865ec9SKyle Evans        return (False, default_ret)
1260*f0865ec9SKyle Evans    # Get OID
1261*f0865ec9SKyle Evans    (check, size_Oid, Oid) = extract_DER_oid(FieldID)
1262*f0865ec9SKyle Evans    if check == False:
1263*f0865ec9SKyle Evans        return (False, default_ret)
1264*f0865ec9SKyle Evans    # Does the OID correspond to a prime field?
1265*f0865ec9SKyle Evans    if(Oid != "\x2A\x86\x48\xCE\x3D\x01\x01"):
1266*f0865ec9SKyle Evans        print("DER parse error: only prime fields are supported ...")
1267*f0865ec9SKyle Evans        return (False, default_ret)
1268*f0865ec9SKyle Evans    # Get prime p of prime field
1269*f0865ec9SKyle Evans    (check, size_P, P) = extract_DER_integer(FieldID[size_Oid:])
1270*f0865ec9SKyle Evans    if check == False:
1271*f0865ec9SKyle Evans        return (False, default_ret)
1272*f0865ec9SKyle Evans    # Get curve (sequence)
1273*f0865ec9SKyle Evans    (check, size_Curve, Curve) = extract_DER_sequence(ECParameters[size_ECPVer+size_FieldID:])
1274*f0865ec9SKyle Evans    if check == False:
1275*f0865ec9SKyle Evans        return (False, default_ret)
1276*f0865ec9SKyle Evans    # Get A in curve
1277*f0865ec9SKyle Evans    (check, size_A, A) = extract_DER_octetstring(Curve)
1278*f0865ec9SKyle Evans    if check == False:
1279*f0865ec9SKyle Evans        return (False, default_ret)
1280*f0865ec9SKyle Evans    # Get B in curve
1281*f0865ec9SKyle Evans    (check, size_B, B) = extract_DER_octetstring(Curve[size_A:])
1282*f0865ec9SKyle Evans    if check == False:
1283*f0865ec9SKyle Evans        return (False, default_ret)
1284*f0865ec9SKyle Evans    # Get ECPoint
1285*f0865ec9SKyle Evans    (check, size_ECPoint, ECPoint) = extract_DER_octetstring(ECParameters[size_ECPVer+size_FieldID+size_Curve:])
1286*f0865ec9SKyle Evans    if check == False:
1287*f0865ec9SKyle Evans        return (False, default_ret)
1288*f0865ec9SKyle Evans    # Get Order
1289*f0865ec9SKyle Evans    (check, size_Order, Order) = extract_DER_integer(ECParameters[size_ECPVer+size_FieldID+size_Curve+size_ECPoint:])
1290*f0865ec9SKyle Evans    if check == False:
1291*f0865ec9SKyle Evans        return (False, default_ret)
1292*f0865ec9SKyle Evans    # Get Cofactor
1293*f0865ec9SKyle Evans    (check, size_Cofactor, Cofactor) = extract_DER_integer(ECParameters[size_ECPVer+size_FieldID+size_Curve+size_ECPoint+size_Order:])
1294*f0865ec9SKyle Evans    if check == False:
1295*f0865ec9SKyle Evans        return (False, default_ret)
1296*f0865ec9SKyle Evans    # If we end up here, everything is OK, we can extract all our elements
1297*f0865ec9SKyle Evans    prime = stringtoint(P)
1298*f0865ec9SKyle Evans    a = stringtoint(A)
1299*f0865ec9SKyle Evans    b = stringtoint(B)
1300*f0865ec9SKyle Evans    order = stringtoint(Order)
1301*f0865ec9SKyle Evans    cofactor = stringtoint(Cofactor)
1302*f0865ec9SKyle Evans    # Extract Gx and Gy, see X9.62-1998
1303*f0865ec9SKyle Evans    if len(ECPoint) < 1:
1304*f0865ec9SKyle Evans        return (False, default_ret)
1305*f0865ec9SKyle Evans    ECPoint_type = ord(ECPoint[0])
1306*f0865ec9SKyle Evans    if (ECPoint_type == 0x04) or (ECPoint_type == 0x06) or (ECPoint_type == 0x07):
1307*f0865ec9SKyle Evans        # Uncompressed and hybrid points
1308*f0865ec9SKyle Evans        if len(ECPoint[1:]) % 2 != 0:
1309*f0865ec9SKyle Evans            return (False, default_ret)
1310*f0865ec9SKyle Evans        ECPoint = ECPoint[1:]
1311*f0865ec9SKyle Evans        gx = stringtoint(ECPoint[:int(len(ECPoint)/2)])
1312*f0865ec9SKyle Evans        gy = stringtoint(ECPoint[int(len(ECPoint)/2):])
1313*f0865ec9SKyle Evans    elif (ECPoint_type == 0x02) or (ECPoint_type == 0x03):
1314*f0865ec9SKyle Evans        # Compressed point: uncompress it, see X9.62-1998 section 4.2.1
1315*f0865ec9SKyle Evans        ECPoint = ECPoint[1:]
1316*f0865ec9SKyle Evans        gx = stringtoint(ECPoint)
1317*f0865ec9SKyle Evans        alpha = (pow(gx, 3, prime) + (a * gx) + b) % prime
1318*f0865ec9SKyle Evans        beta = mod_sqrt(alpha, prime)
1319*f0865ec9SKyle Evans        if (beta == None) or ((beta == 0) and (alpha != 0)):
1320*f0865ec9SKyle Evans            return (False, 0)
1321*f0865ec9SKyle Evans        if (beta & 0x1) == (ECPoint_type & 0x1):
1322*f0865ec9SKyle Evans            gy = beta
1323*f0865ec9SKyle Evans        else:
1324*f0865ec9SKyle Evans            gy = prime - beta
1325*f0865ec9SKyle Evans    else:
1326*f0865ec9SKyle Evans        print("DER parse error: hybrid points are unsupported!")
1327*f0865ec9SKyle Evans        return (False, default_ret)
1328*f0865ec9SKyle Evans    return (True, (a, b, prime, order, cofactor, gx, gy))
1329*f0865ec9SKyle Evans
1330*f0865ec9SKyle Evans##########################################################
1331*f0865ec9SKyle Evans### Text and format helpers
1332*f0865ec9SKyle Evansdef bigint_to_C_array(bint, size):
1333*f0865ec9SKyle Evans    """
1334*f0865ec9SKyle Evans    Format a python big int to a C hex array
1335*f0865ec9SKyle Evans    """
1336*f0865ec9SKyle Evans    hexstr = format(int(bint), 'x')
1337*f0865ec9SKyle Evans    # Left pad to the size!
1338*f0865ec9SKyle Evans    hexstr = ("0"*int((2*size)-len(hexstr)))+hexstr
1339*f0865ec9SKyle Evans    hexstr = ("0"*(len(hexstr) % 2))+hexstr
1340*f0865ec9SKyle Evans    out_str = "{\n"
1341*f0865ec9SKyle Evans    for i in range(0, len(hexstr) - 1, 2):
1342*f0865ec9SKyle Evans        if (i%16 == 0):
1343*f0865ec9SKyle Evans            if(i!=0):
1344*f0865ec9SKyle Evans                out_str += "\n"
1345*f0865ec9SKyle Evans            out_str += "\t"
1346*f0865ec9SKyle Evans        out_str += "0x"+hexstr[i:i+2]+", "
1347*f0865ec9SKyle Evans    out_str += "\n};\n"
1348*f0865ec9SKyle Evans    return out_str
1349*f0865ec9SKyle Evans
1350*f0865ec9SKyle Evansdef check_in_file(fname, pat):
1351*f0865ec9SKyle Evans    # See if the pattern is in the file.
1352*f0865ec9SKyle Evans    with open(fname) as f:
1353*f0865ec9SKyle Evans        if not any(re.search(pat, line) for line in f):
1354*f0865ec9SKyle Evans            return False # pattern does not occur in file so we are done.
1355*f0865ec9SKyle Evans        else:
1356*f0865ec9SKyle Evans            return True
1357*f0865ec9SKyle Evans
1358*f0865ec9SKyle Evansdef num_patterns_in_file(fname, pat):
1359*f0865ec9SKyle Evans    num_pat = 0
1360*f0865ec9SKyle Evans    with open(fname) as f:
1361*f0865ec9SKyle Evans        for line in f:
1362*f0865ec9SKyle Evans            if re.search(pat, line):
1363*f0865ec9SKyle Evans                num_pat = num_pat+1
1364*f0865ec9SKyle Evans    return num_pat
1365*f0865ec9SKyle Evans
1366*f0865ec9SKyle Evansdef file_replace_pattern(fname, pat, s_after):
1367*f0865ec9SKyle Evans    # first, see if the pattern is even in the file.
1368*f0865ec9SKyle Evans    with open(fname) as f:
1369*f0865ec9SKyle Evans        if not any(re.search(pat, line) for line in f):
1370*f0865ec9SKyle Evans            return # pattern does not occur in file so we are done.
1371*f0865ec9SKyle Evans
1372*f0865ec9SKyle Evans    # pattern is in the file, so perform replace operation.
1373*f0865ec9SKyle Evans    with open(fname) as f:
1374*f0865ec9SKyle Evans        out_fname = fname + ".tmp"
1375*f0865ec9SKyle Evans        out = open(out_fname, "w")
1376*f0865ec9SKyle Evans        for line in f:
1377*f0865ec9SKyle Evans            out.write(re.sub(pat, s_after, line))
1378*f0865ec9SKyle Evans        out.close()
1379*f0865ec9SKyle Evans        os.rename(out_fname, fname)
1380*f0865ec9SKyle Evans
1381*f0865ec9SKyle Evansdef file_remove_pattern(fname, pat):
1382*f0865ec9SKyle Evans    # first, see if the pattern is even in the file.
1383*f0865ec9SKyle Evans    with open(fname) as f:
1384*f0865ec9SKyle Evans        if not any(re.search(pat, line) for line in f):
1385*f0865ec9SKyle Evans            return # pattern does not occur in file so we are done.
1386*f0865ec9SKyle Evans
1387*f0865ec9SKyle Evans    # pattern is in the file, so perform remove operation.
1388*f0865ec9SKyle Evans    with open(fname) as f:
1389*f0865ec9SKyle Evans        out_fname = fname + ".tmp"
1390*f0865ec9SKyle Evans        out = open(out_fname, "w")
1391*f0865ec9SKyle Evans        for line in f:
1392*f0865ec9SKyle Evans            if not re.search(pat, line):
1393*f0865ec9SKyle Evans                out.write(line)
1394*f0865ec9SKyle Evans        out.close()
1395*f0865ec9SKyle Evans
1396*f0865ec9SKyle Evans    if os.path.exists(fname):
1397*f0865ec9SKyle Evans        remove_file(fname)
1398*f0865ec9SKyle Evans    os.rename(out_fname, fname)
1399*f0865ec9SKyle Evans
1400*f0865ec9SKyle Evansdef remove_file(fname):
1401*f0865ec9SKyle Evans    # Remove file
1402*f0865ec9SKyle Evans    os.remove(fname)
1403*f0865ec9SKyle Evans
1404*f0865ec9SKyle Evansdef remove_files_pattern(fpattern):
1405*f0865ec9SKyle Evans    [remove_file(x) for x in glob.glob(fpattern)]
1406*f0865ec9SKyle Evans
1407*f0865ec9SKyle Evansdef buffer_remove_pattern(buff, pat):
1408*f0865ec9SKyle Evans    if is_python_2() == False:
1409*f0865ec9SKyle Evans        buff = buff.decode('latin-1')
1410*f0865ec9SKyle Evans    if re.search(pat, buff) == None:
1411*f0865ec9SKyle Evans        return (False, buff) # pattern does not occur in file so we are done.
1412*f0865ec9SKyle Evans    # Remove the pattern
1413*f0865ec9SKyle Evans    buff = re.sub(pat, "", buff)
1414*f0865ec9SKyle Evans    return (True, buff)
1415*f0865ec9SKyle Evans
1416*f0865ec9SKyle Evansdef is_base64(s):
1417*f0865ec9SKyle Evans    s = ''.join([s.strip() for s in s.split("\n")])
1418*f0865ec9SKyle Evans    try:
1419*f0865ec9SKyle Evans        enc = base64.b64encode(base64.b64decode(s)).strip()
1420*f0865ec9SKyle Evans        if type(enc) is bytes:
1421*f0865ec9SKyle Evans            return enc == s.encode('latin-1')
1422*f0865ec9SKyle Evans        else:
1423*f0865ec9SKyle Evans            return enc == s
1424*f0865ec9SKyle Evans    except TypeError:
1425*f0865ec9SKyle Evans        return False
1426*f0865ec9SKyle Evans
1427*f0865ec9SKyle Evans### Curve helpers
1428*f0865ec9SKyle Evansdef export_curve_int(curvename, intname, bigint, size):
1429*f0865ec9SKyle Evans    if bigint == None:
1430*f0865ec9SKyle Evans        out  = "static const u8 "+curvename+"_"+intname+"[] = {\n\t0x00,\n};\n"
1431*f0865ec9SKyle Evans        out += "TO_EC_STR_PARAM_FIXED_SIZE("+curvename+"_"+intname+", 0);\n\n"
1432*f0865ec9SKyle Evans    else:
1433*f0865ec9SKyle Evans        out  = "static const u8 "+curvename+"_"+intname+"[] = "+bigint_to_C_array(bigint, size)+"\n"
1434*f0865ec9SKyle Evans        out += "TO_EC_STR_PARAM("+curvename+"_"+intname+");\n\n"
1435*f0865ec9SKyle Evans    return out
1436*f0865ec9SKyle Evans
1437*f0865ec9SKyle Evansdef export_curve_string(curvename, stringname, stringvalue):
1438*f0865ec9SKyle Evans    out  = "static const u8 "+curvename+"_"+stringname+"[] = \""+stringvalue+"\";\n"
1439*f0865ec9SKyle Evans    out += "TO_EC_STR_PARAM("+curvename+"_"+stringname+");\n\n"
1440*f0865ec9SKyle Evans    return out
1441*f0865ec9SKyle Evans
1442*f0865ec9SKyle Evansdef export_curve_struct(curvename, paramname, paramnamestr):
1443*f0865ec9SKyle Evans    return "\t."+paramname+" = &"+curvename+"_"+paramnamestr+"_str_param, \n"
1444*f0865ec9SKyle Evans
1445*f0865ec9SKyle Evansdef curve_params(name, prime, pbitlen, a, b, gx, gy, order, cofactor, oid, alpha_montgomery, gamma_montgomery, alpha_edwards):
1446*f0865ec9SKyle Evans    """
1447*f0865ec9SKyle Evans    Take as input some elliptic curve parameters and generate the
1448*f0865ec9SKyle Evans    C parameters in a string
1449*f0865ec9SKyle Evans    """
1450*f0865ec9SKyle Evans    bytesize = int(pbitlen / 8)
1451*f0865ec9SKyle Evans    if pbitlen % 8 != 0:
1452*f0865ec9SKyle Evans        bytesize += 1
1453*f0865ec9SKyle Evans    # Compute the rounded word size for each word size
1454*f0865ec9SKyle Evans    if bytesize % 8 != 0:
1455*f0865ec9SKyle Evans        wordsbitsize64 = 8*((int(bytesize/8)+1)*8)
1456*f0865ec9SKyle Evans    else:
1457*f0865ec9SKyle Evans        wordsbitsize64 = 8*bytesize
1458*f0865ec9SKyle Evans    if bytesize % 4 != 0:
1459*f0865ec9SKyle Evans        wordsbitsize32 = 8*((int(bytesize/4)+1)*4)
1460*f0865ec9SKyle Evans    else:
1461*f0865ec9SKyle Evans        wordsbitsize32 = 8*bytesize
1462*f0865ec9SKyle Evans    if bytesize % 2 != 0:
1463*f0865ec9SKyle Evans        wordsbitsize16 = 8*((int(bytesize/2)+1)*2)
1464*f0865ec9SKyle Evans    else:
1465*f0865ec9SKyle Evans        wordsbitsize16 = 8*bytesize
1466*f0865ec9SKyle Evans    # Compute some parameters
1467*f0865ec9SKyle Evans    (r64, r_square64, mpinv64) = compute_monty_coef(prime, wordsbitsize64, 64)
1468*f0865ec9SKyle Evans    (r32, r_square32, mpinv32) = compute_monty_coef(prime, wordsbitsize32, 32)
1469*f0865ec9SKyle Evans    (r16, r_square16, mpinv16) = compute_monty_coef(prime, wordsbitsize16, 16)
1470*f0865ec9SKyle Evans    # Compute p_reciprocal for each word size
1471*f0865ec9SKyle Evans    (pshift64, primenorm64, p_reciprocal64) = compute_div_coef(prime, wordsbitsize64, 64)
1472*f0865ec9SKyle Evans    (pshift32, primenorm32, p_reciprocal32) = compute_div_coef(prime, wordsbitsize32, 32)
1473*f0865ec9SKyle Evans    (pshift16, primenorm16, p_reciprocal16) = compute_div_coef(prime, wordsbitsize16, 16)
1474*f0865ec9SKyle Evans    # Compute the number of points on the curve
1475*f0865ec9SKyle Evans    npoints = order * cofactor
1476*f0865ec9SKyle Evans
1477*f0865ec9SKyle Evans    # Now output the parameters
1478*f0865ec9SKyle Evans    ec_params_string =  "#include <libecc/lib_ecc_config.h>\n"
1479*f0865ec9SKyle Evans    ec_params_string += "#ifdef WITH_CURVE_"+name.upper()+"\n\n"
1480*f0865ec9SKyle Evans    ec_params_string += "#ifndef __EC_PARAMS_"+name.upper()+"_H__\n"
1481*f0865ec9SKyle Evans    ec_params_string += "#define __EC_PARAMS_"+name.upper()+"_H__\n"
1482*f0865ec9SKyle Evans    ec_params_string += "#include <libecc/curves/known/ec_params_external.h>\n"
1483*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p", prime, bytesize)
1484*f0865ec9SKyle Evans
1485*f0865ec9SKyle Evans    ec_params_string += "#define CURVE_"+name.upper()+"_P_BITLEN "+str(pbitlen)+"\n"
1486*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_bitlen", pbitlen, getbytelen(pbitlen))
1487*f0865ec9SKyle Evans
1488*f0865ec9SKyle Evans    ec_params_string += "#if (WORD_BYTES == 8)     /* 64-bit words */\n"
1489*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "r", r64, getbytelen(r64))
1490*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "r_square", r_square64, getbytelen(r_square64))
1491*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "mpinv", mpinv64, getbytelen(mpinv64))
1492*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_shift", pshift64, getbytelen(pshift64))
1493*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_normalized", primenorm64, getbytelen(primenorm64))
1494*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_reciprocal", p_reciprocal64, getbytelen(p_reciprocal64))
1495*f0865ec9SKyle Evans    ec_params_string += "#elif (WORD_BYTES == 4)   /* 32-bit words */\n"
1496*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "r", r32, getbytelen(r32))
1497*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "r_square", r_square32, getbytelen(r_square32))
1498*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "mpinv", mpinv32, getbytelen(mpinv32))
1499*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_shift", pshift32, getbytelen(pshift32))
1500*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_normalized", primenorm32, getbytelen(primenorm32))
1501*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_reciprocal", p_reciprocal32, getbytelen(p_reciprocal32))
1502*f0865ec9SKyle Evans    ec_params_string += "#elif (WORD_BYTES == 2)   /* 16-bit words */\n"
1503*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "r", r16, getbytelen(r16))
1504*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "r_square", r_square16, getbytelen(r_square16))
1505*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "mpinv", mpinv16, getbytelen(mpinv16))
1506*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_shift", pshift16, getbytelen(pshift16))
1507*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_normalized", primenorm16, getbytelen(primenorm16))
1508*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "p_reciprocal", p_reciprocal16, getbytelen(p_reciprocal16))
1509*f0865ec9SKyle Evans    ec_params_string += "#else                     /* unknown word size */\n"
1510*f0865ec9SKyle Evans    ec_params_string += "#error \"Unsupported word size\"\n"
1511*f0865ec9SKyle Evans    ec_params_string += "#endif\n\n"
1512*f0865ec9SKyle Evans
1513*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "a", a, bytesize)
1514*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "b", b, bytesize)
1515*f0865ec9SKyle Evans
1516*f0865ec9SKyle Evans    curve_order_bitlen = getbitlen(npoints)
1517*f0865ec9SKyle Evans    ec_params_string += "#define CURVE_"+name.upper()+"_CURVE_ORDER_BITLEN "+str(curve_order_bitlen)+"\n"
1518*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "curve_order", npoints, getbytelen(npoints))
1519*f0865ec9SKyle Evans
1520*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "gx", gx, bytesize)
1521*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "gy", gy, bytesize)
1522*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "gz", 0x01, bytesize)
1523*f0865ec9SKyle Evans
1524*f0865ec9SKyle Evans    qbitlen = getbitlen(order)
1525*f0865ec9SKyle Evans
1526*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "gen_order", order, getbytelen(order))
1527*f0865ec9SKyle Evans    ec_params_string += "#define CURVE_"+name.upper()+"_Q_BITLEN "+str(qbitlen)+"\n"
1528*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "gen_order_bitlen", qbitlen, getbytelen(qbitlen))
1529*f0865ec9SKyle Evans
1530*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "cofactor", cofactor, getbytelen(cofactor))
1531*f0865ec9SKyle Evans
1532*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "alpha_montgomery", alpha_montgomery, getbytelen(alpha_montgomery))
1533*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "gamma_montgomery", gamma_montgomery, getbytelen(gamma_montgomery))
1534*f0865ec9SKyle Evans    ec_params_string += export_curve_int(name, "alpha_edwards", alpha_edwards, getbytelen(alpha_edwards))
1535*f0865ec9SKyle Evans
1536*f0865ec9SKyle Evans    ec_params_string += export_curve_string(name, "name", name.upper());
1537*f0865ec9SKyle Evans
1538*f0865ec9SKyle Evans    if oid == None:
1539*f0865ec9SKyle Evans        oid = ""
1540*f0865ec9SKyle Evans    ec_params_string += export_curve_string(name, "oid", oid);
1541*f0865ec9SKyle Evans
1542*f0865ec9SKyle Evans    ec_params_string += "static const ec_str_params "+name+"_str_params = {\n"+\
1543*f0865ec9SKyle Evans    export_curve_struct(name, "p", "p") +\
1544*f0865ec9SKyle Evans    export_curve_struct(name, "p_bitlen", "p_bitlen") +\
1545*f0865ec9SKyle Evans    export_curve_struct(name, "r", "r") +\
1546*f0865ec9SKyle Evans    export_curve_struct(name, "r_square", "r_square") +\
1547*f0865ec9SKyle Evans    export_curve_struct(name, "mpinv", "mpinv") +\
1548*f0865ec9SKyle Evans    export_curve_struct(name, "p_shift", "p_shift") +\
1549*f0865ec9SKyle Evans    export_curve_struct(name, "p_normalized", "p_normalized") +\
1550*f0865ec9SKyle Evans    export_curve_struct(name, "p_reciprocal", "p_reciprocal") +\
1551*f0865ec9SKyle Evans    export_curve_struct(name, "a", "a") +\
1552*f0865ec9SKyle Evans    export_curve_struct(name, "b", "b") +\
1553*f0865ec9SKyle Evans    export_curve_struct(name, "curve_order", "curve_order") +\
1554*f0865ec9SKyle Evans    export_curve_struct(name, "gx", "gx") +\
1555*f0865ec9SKyle Evans    export_curve_struct(name, "gy", "gy") +\
1556*f0865ec9SKyle Evans    export_curve_struct(name, "gz", "gz") +\
1557*f0865ec9SKyle Evans    export_curve_struct(name, "gen_order", "gen_order") +\
1558*f0865ec9SKyle Evans    export_curve_struct(name, "gen_order_bitlen", "gen_order_bitlen") +\
1559*f0865ec9SKyle Evans    export_curve_struct(name, "cofactor", "cofactor") +\
1560*f0865ec9SKyle Evans    export_curve_struct(name, "alpha_montgomery", "alpha_montgomery") +\
1561*f0865ec9SKyle Evans    export_curve_struct(name, "gamma_montgomery", "gamma_montgomery") +\
1562*f0865ec9SKyle Evans    export_curve_struct(name, "alpha_edwards", "alpha_edwards") +\
1563*f0865ec9SKyle Evans    export_curve_struct(name, "oid", "oid") +\
1564*f0865ec9SKyle Evans    export_curve_struct(name, "name", "name")
1565*f0865ec9SKyle Evans    ec_params_string += "};\n\n"
1566*f0865ec9SKyle Evans
1567*f0865ec9SKyle Evans    ec_params_string += "/*\n"+\
1568*f0865ec9SKyle Evans    " * Compute max bit length of all curves for p and q\n"+\
1569*f0865ec9SKyle Evans    " */\n"+\
1570*f0865ec9SKyle Evans    "#ifndef CURVES_MAX_P_BIT_LEN\n"+\
1571*f0865ec9SKyle Evans    "#define CURVES_MAX_P_BIT_LEN    0\n"+\
1572*f0865ec9SKyle Evans    "#endif\n"+\
1573*f0865ec9SKyle Evans    "#if (CURVES_MAX_P_BIT_LEN < CURVE_"+name.upper()+"_P_BITLEN)\n"+\
1574*f0865ec9SKyle Evans    "#undef CURVES_MAX_P_BIT_LEN\n"+\
1575*f0865ec9SKyle Evans    "#define CURVES_MAX_P_BIT_LEN CURVE_"+name.upper()+"_P_BITLEN\n"+\
1576*f0865ec9SKyle Evans    "#endif\n"+\
1577*f0865ec9SKyle Evans    "#ifndef CURVES_MAX_Q_BIT_LEN\n"+\
1578*f0865ec9SKyle Evans    "#define CURVES_MAX_Q_BIT_LEN    0\n"+\
1579*f0865ec9SKyle Evans    "#endif\n"+\
1580*f0865ec9SKyle Evans    "#if (CURVES_MAX_Q_BIT_LEN < CURVE_"+name.upper()+"_Q_BITLEN)\n"+\
1581*f0865ec9SKyle Evans    "#undef CURVES_MAX_Q_BIT_LEN\n"+\
1582*f0865ec9SKyle Evans    "#define CURVES_MAX_Q_BIT_LEN CURVE_"+name.upper()+"_Q_BITLEN\n"+\
1583*f0865ec9SKyle Evans    "#endif\n"+\
1584*f0865ec9SKyle Evans    "#ifndef CURVES_MAX_CURVE_ORDER_BIT_LEN\n"+\
1585*f0865ec9SKyle Evans    "#define CURVES_MAX_CURVE_ORDER_BIT_LEN    0\n"+\
1586*f0865ec9SKyle Evans    "#endif\n"+\
1587*f0865ec9SKyle Evans    "#if (CURVES_MAX_CURVE_ORDER_BIT_LEN < CURVE_"+name.upper()+"_CURVE_ORDER_BITLEN)\n"+\
1588*f0865ec9SKyle Evans    "#undef CURVES_MAX_CURVE_ORDER_BIT_LEN\n"+\
1589*f0865ec9SKyle Evans    "#define CURVES_MAX_CURVE_ORDER_BIT_LEN CURVE_"+name.upper()+"_CURVE_ORDER_BITLEN\n"+\
1590*f0865ec9SKyle Evans    "#endif\n\n"
1591*f0865ec9SKyle Evans
1592*f0865ec9SKyle Evans    ec_params_string += "/*\n"+\
1593*f0865ec9SKyle Evans    " * Compute and adapt max name and oid length\n"+\
1594*f0865ec9SKyle Evans    " */\n"+\
1595*f0865ec9SKyle Evans    "#ifndef MAX_CURVE_OID_LEN\n"+\
1596*f0865ec9SKyle Evans    "#define MAX_CURVE_OID_LEN 0\n"+\
1597*f0865ec9SKyle Evans    "#endif\n"+\
1598*f0865ec9SKyle Evans    "#ifndef MAX_CURVE_NAME_LEN\n"+\
1599*f0865ec9SKyle Evans    "#define MAX_CURVE_NAME_LEN 0\n"+\
1600*f0865ec9SKyle Evans    "#endif\n"+\
1601*f0865ec9SKyle Evans    "#if (MAX_CURVE_OID_LEN < "+str(len(oid)+1)+")\n"+\
1602*f0865ec9SKyle Evans    "#undef MAX_CURVE_OID_LEN\n"+\
1603*f0865ec9SKyle Evans    "#define MAX_CURVE_OID_LEN "+str(len(oid)+1)+"\n"+\
1604*f0865ec9SKyle Evans    "#endif\n"+\
1605*f0865ec9SKyle Evans    "#if (MAX_CURVE_NAME_LEN < "+str(len(name.upper())+1)+")\n"+\
1606*f0865ec9SKyle Evans    "#undef MAX_CURVE_NAME_LEN\n"+\
1607*f0865ec9SKyle Evans    "#define MAX_CURVE_NAME_LEN "+str(len(name.upper())+1)+"\n"+\
1608*f0865ec9SKyle Evans    "#endif\n\n"
1609*f0865ec9SKyle Evans
1610*f0865ec9SKyle Evans    ec_params_string += "#endif /* __EC_PARAMS_"+name.upper()+"_H__ */\n\n"+"#endif /* WITH_CURVE_"+name.upper()+" */\n"
1611*f0865ec9SKyle Evans
1612*f0865ec9SKyle Evans    return ec_params_string
1613*f0865ec9SKyle Evans
1614*f0865ec9SKyle Evansdef usage():
1615*f0865ec9SKyle Evans    print("This script is intented to *statically* expand the ECC library with user defined curves.")
1616*f0865ec9SKyle Evans    print("By statically we mean that the source code of libecc is expanded with new curves parameters through")
1617*f0865ec9SKyle Evans    print("automatic code generation filling place holders in the existing code base of the library. Though the")
1618*f0865ec9SKyle Evans    print("choice of static code generation versus dynamic curves import (such as what OpenSSL does) might be")
1619*f0865ec9SKyle Evans    print("argued, this choice has been driven by simplicity and security design decisions: we want libecc to have")
1620*f0865ec9SKyle Evans    print("all its parameters (such as memory consumption) set at compile time and statically adapted to the curves.")
1621*f0865ec9SKyle Evans    print("Since libecc only supports curves over prime fields, the script can only add this kind of curves.")
1622*f0865ec9SKyle Evans    print("This script implements elliptic curves and ISO signature algorithms from scratch over Python's multi-precision")
1623*f0865ec9SKyle Evans    print("big numbers library. Addition and doubling over curves use naive formulas. Please DO NOT use the functions of this")
1624*f0865ec9SKyle Evans    print("script for production code: they are not securely implemented and are very inefficient. Their only purpose is to expand")
1625*f0865ec9SKyle Evans    print("libecc and produce test vectors.")
1626*f0865ec9SKyle Evans    print("")
1627*f0865ec9SKyle Evans    print("In order to add a curve, there are two ways:")
1628*f0865ec9SKyle Evans    print("Adding a user defined curve with explicit parameters:")
1629*f0865ec9SKyle Evans    print("-----------------------------------------------------")
1630*f0865ec9SKyle Evans    print(sys.argv[0]+" --name=\"YOURCURVENAME\" --prime=... --order=... --a=... --b=... --gx=... --gy=... --cofactor=... --oid=THEOID")
1631*f0865ec9SKyle Evans    print("\t> name: name of the curve in the form of a string")
1632*f0865ec9SKyle Evans    print("\t> prime: prime number representing the curve prime field")
1633*f0865ec9SKyle Evans    print("\t> order: prime number representing the generator order")
1634*f0865ec9SKyle Evans    print("\t> cofactor: cofactor of the curve")
1635*f0865ec9SKyle Evans    print("\t> a: 'a' coefficient of the short Weierstrass equation of the curve")
1636*f0865ec9SKyle Evans    print("\t> b: 'b' coefficient of the short Weierstrass equation of the curve")
1637*f0865ec9SKyle Evans    print("\t> gx: x coordinate of the generator G")
1638*f0865ec9SKyle Evans    print("\t> gy: y coordinate of the generator G")
1639*f0865ec9SKyle Evans    print("\t> oid: optional OID of the curve")
1640*f0865ec9SKyle Evans    print("  Notes:")
1641*f0865ec9SKyle Evans    print("  ******")
1642*f0865ec9SKyle Evans    print("\t1) These elements are verified to indeed satisfy the curve equation.")
1643*f0865ec9SKyle Evans    print("\t2) All the numbers can be given either in decimal or hexadecimal format with a prepending '0x'.")
1644*f0865ec9SKyle Evans    print("\t3) The script automatically generates all the necessary files for the curve to be included in the library." )
1645*f0865ec9SKyle Evans    print("\tYou will find the new curve definition in the usual 'lib_ecc_config.h' file (one can activate it or not at compile time).")
1646*f0865ec9SKyle Evans    print("")
1647*f0865ec9SKyle Evans    print("Adding a user defined curve through RFC3279 ASN.1 parameters:")
1648*f0865ec9SKyle Evans    print("-------------------------------------------------------------")
1649*f0865ec9SKyle Evans    print(sys.argv[0]+" --name=\"YOURCURVENAME\" --ECfile=... --oid=THEOID")
1650*f0865ec9SKyle Evans    print("\t> ECfile: the DER or PEM encoded file containing the curve parameters (see RFC3279)")
1651*f0865ec9SKyle Evans    print("  Notes:")
1652*f0865ec9SKyle Evans    print("\tCurve parameters encoded in DER or PEM format can be generated with tools like OpenSSL (among others). As an illustrative example,")
1653*f0865ec9SKyle Evans    print("\tone can list all the supported curves under OpenSSL with:")
1654*f0865ec9SKyle Evans    print("\t  $ openssl ecparam -list_curves")
1655*f0865ec9SKyle Evans    print("\tOnly the listed so called \"prime\" curves are supported. Then, one can extract an explicit curve representation in ASN.1")
1656*f0865ec9SKyle Evans    print("\tas defined in RFC3279, for example for BRAINPOOLP320R1:")
1657*f0865ec9SKyle Evans    print("\t  $ openssl ecparam -param_enc explicit -outform DER -name brainpoolP320r1 -out brainpoolP320r1.der")
1658*f0865ec9SKyle Evans    print("")
1659*f0865ec9SKyle Evans    print("Removing user defined curves:")
1660*f0865ec9SKyle Evans    print("-----------------------------")
1661*f0865ec9SKyle Evans    print("\t*All the user defined curves can be removed with the --remove-all toggle.")
1662*f0865ec9SKyle Evans    print("\t*A specific named user define curve can be removed with the --remove toggle: in this case the --name option is used to ")
1663*f0865ec9SKyle Evans    print("\tlocate which named curve must be deleted.")
1664*f0865ec9SKyle Evans    print("")
1665*f0865ec9SKyle Evans    print("Test vectors:")
1666*f0865ec9SKyle Evans    print("-------------")
1667*f0865ec9SKyle Evans    print("\tTest vectors can be automatically generated and added to the library self tests when providing the --add-test-vectors=X toggle.")
1668*f0865ec9SKyle Evans    print("\tIn this case, X test vectors will be generated for *each* (curve, sign algorithm, hash algorithm) 3-uplet (beware of combinatorial")
1669*f0865ec9SKyle Evans    print("\tissues when X is big!). These tests are transparently added and compiled with the self tests.")
1670*f0865ec9SKyle Evans    return
1671*f0865ec9SKyle Evans
1672*f0865ec9SKyle Evansdef get_int(instring):
1673*f0865ec9SKyle Evans    if len(instring) == 0:
1674*f0865ec9SKyle Evans        return 0
1675*f0865ec9SKyle Evans    if len(instring) >= 2:
1676*f0865ec9SKyle Evans        if instring[:2] == "0x":
1677*f0865ec9SKyle Evans            return int(instring, 16)
1678*f0865ec9SKyle Evans    return int(instring)
1679*f0865ec9SKyle Evans
1680*f0865ec9SKyle Evansdef parse_cmd_line(args):
1681*f0865ec9SKyle Evans    """
1682*f0865ec9SKyle Evans    Get elliptic curve parameters from command line
1683*f0865ec9SKyle Evans    """
1684*f0865ec9SKyle Evans    name = oid = prime = a = b = gx = gy = g = order = cofactor = ECfile = remove = remove_all = add_test_vectors = None
1685*f0865ec9SKyle Evans    alpha_montgomery = gamma_montgomery = alpha_edwards = None
1686*f0865ec9SKyle Evans    try:
1687*f0865ec9SKyle Evans        opts, args = getopt.getopt(sys.argv[1:], ":h", ["help", "remove", "remove-all", "name=", "prime=", "a=", "b=", "generator=", "gx=", "gy=", "order=", "cofactor=", "alpha_montgomery=","gamma_montgomery=", "alpha_edwards=", "ECfile=", "oid=", "add-test-vectors="])
1688*f0865ec9SKyle Evans    except getopt.GetoptError as err:
1689*f0865ec9SKyle Evans        # print help information and exit:
1690*f0865ec9SKyle Evans        print(err) # will print something like "option -a not recognized"
1691*f0865ec9SKyle Evans        usage()
1692*f0865ec9SKyle Evans        return False
1693*f0865ec9SKyle Evans    for o, arg in opts:
1694*f0865ec9SKyle Evans        if o in ("-h", "--help"):
1695*f0865ec9SKyle Evans            usage()
1696*f0865ec9SKyle Evans            return True
1697*f0865ec9SKyle Evans        elif o in ("--name"):
1698*f0865ec9SKyle Evans            name = arg
1699*f0865ec9SKyle Evans            # Prepend the custom string before name to avoid any collision
1700*f0865ec9SKyle Evans            name = "user_defined_"+name
1701*f0865ec9SKyle Evans            # Replace any unwanted name char
1702*f0865ec9SKyle Evans            name = re.sub("\-", "_", name)
1703*f0865ec9SKyle Evans        elif o in ("--oid="):
1704*f0865ec9SKyle Evans            oid = arg
1705*f0865ec9SKyle Evans        elif o in ("--prime"):
1706*f0865ec9SKyle Evans            prime = get_int(arg.replace(' ', ''))
1707*f0865ec9SKyle Evans        elif o in ("--a"):
1708*f0865ec9SKyle Evans            a = get_int(arg.replace(' ', ''))
1709*f0865ec9SKyle Evans        elif o in ("--b"):
1710*f0865ec9SKyle Evans            b = get_int(arg.replace(' ', ''))
1711*f0865ec9SKyle Evans        elif o in ("--gx"):
1712*f0865ec9SKyle Evans            gx = get_int(arg.replace(' ', ''))
1713*f0865ec9SKyle Evans        elif o in ("--gy"):
1714*f0865ec9SKyle Evans            gy = get_int(arg.replace(' ', ''))
1715*f0865ec9SKyle Evans        elif o in ("--generator"):
1716*f0865ec9SKyle Evans            g = arg.replace(' ', '')
1717*f0865ec9SKyle Evans        elif o in ("--order"):
1718*f0865ec9SKyle Evans            order = get_int(arg.replace(' ', ''))
1719*f0865ec9SKyle Evans        elif o in ("--cofactor"):
1720*f0865ec9SKyle Evans            cofactor = get_int(arg.replace(' ', ''))
1721*f0865ec9SKyle Evans        elif o in ("--alpha_montgomery"):
1722*f0865ec9SKyle Evans            alpha_montgomery = get_int(arg.replace(' ', ''))
1723*f0865ec9SKyle Evans        elif o in ("--gamma_montgomery"):
1724*f0865ec9SKyle Evans            gamma_montgomery = get_int(arg.replace(' ', ''))
1725*f0865ec9SKyle Evans        elif o in ("--alpha_edwards"):
1726*f0865ec9SKyle Evans            alpha_edwards = get_int(arg.replace(' ', ''))
1727*f0865ec9SKyle Evans        elif o in ("--remove"):
1728*f0865ec9SKyle Evans            remove = True
1729*f0865ec9SKyle Evans        elif o in ("--remove-all"):
1730*f0865ec9SKyle Evans            remove_all = True
1731*f0865ec9SKyle Evans        elif o in ("--add-test-vectors"):
1732*f0865ec9SKyle Evans            add_test_vectors = get_int(arg.replace(' ', ''))
1733*f0865ec9SKyle Evans        elif o in ("--ECfile"):
1734*f0865ec9SKyle Evans            ECfile = arg
1735*f0865ec9SKyle Evans        else:
1736*f0865ec9SKyle Evans            print("unhandled option")
1737*f0865ec9SKyle Evans            usage()
1738*f0865ec9SKyle Evans            return False
1739*f0865ec9SKyle Evans
1740*f0865ec9SKyle Evans    # File paths
1741*f0865ec9SKyle Evans    script_path = os.path.abspath(os.path.dirname(sys.argv[0])) + "/"
1742*f0865ec9SKyle Evans    ec_params_path = script_path + "../include/libecc/curves/user_defined/"
1743*f0865ec9SKyle Evans    curves_list_path = script_path + "../include/libecc/curves/"
1744*f0865ec9SKyle Evans    lib_ecc_types_path = script_path + "../include/libecc/"
1745*f0865ec9SKyle Evans    lib_ecc_config_path = script_path + "../include/libecc/"
1746*f0865ec9SKyle Evans    ec_self_tests_path = script_path + "../src/tests/"
1747*f0865ec9SKyle Evans    meson_options_path = script_path + "../"
1748*f0865ec9SKyle Evans
1749*f0865ec9SKyle Evans    # If remove is True, we have been asked to remove already existing user defined curves
1750*f0865ec9SKyle Evans    if remove == True:
1751*f0865ec9SKyle Evans        if name == None:
1752*f0865ec9SKyle Evans            print("--remove option expects a curve name provided with --name")
1753*f0865ec9SKyle Evans            return False
1754*f0865ec9SKyle Evans        asked = ""
1755*f0865ec9SKyle Evans        while asked != "y" and asked != "n":
1756*f0865ec9SKyle Evans            asked = get_user_input("You asked to remove everything related to user defined "+name.replace("user_defined_", "")+" curve. Enter y to confirm, n to cancel [y/n]. ")
1757*f0865ec9SKyle Evans        if asked == "n":
1758*f0865ec9SKyle Evans            print("NOT removing curve "+name.replace("user_defined_", "")+" (cancelled).")
1759*f0865ec9SKyle Evans            return True
1760*f0865ec9SKyle Evans        # Remove any user defined stuff with given name
1761*f0865ec9SKyle Evans        print("Removing user defined curve "+name.replace("user_defined_", "")+" ...")
1762*f0865ec9SKyle Evans        if name == None:
1763*f0865ec9SKyle Evans            print("Error: you must provide a curve name with --remove")
1764*f0865ec9SKyle Evans            return False
1765*f0865ec9SKyle Evans        file_remove_pattern(curves_list_path + "curves_list.h", ".*"+name+".*")
1766*f0865ec9SKyle Evans        file_remove_pattern(curves_list_path + "curves_list.h", ".*"+name.upper()+".*")
1767*f0865ec9SKyle Evans        file_remove_pattern(lib_ecc_types_path + "lib_ecc_types.h", ".*"+name.upper()+".*")
1768*f0865ec9SKyle Evans        file_remove_pattern(lib_ecc_config_path + "lib_ecc_config.h", ".*"+name.upper()+".*")
1769*f0865ec9SKyle Evans        file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*"+name+".*")
1770*f0865ec9SKyle Evans        file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*"+name.upper()+".*")
1771*f0865ec9SKyle Evans        file_remove_pattern(meson_options_path + "meson.options", ".*"+name.lower()+".*")
1772*f0865ec9SKyle Evans        try:
1773*f0865ec9SKyle Evans            remove_file(ec_params_path + "ec_params_"+name+".h")
1774*f0865ec9SKyle Evans        except:
1775*f0865ec9SKyle Evans            print("Error: curve name "+name+" does not seem to be present in the sources!")
1776*f0865ec9SKyle Evans            return False
1777*f0865ec9SKyle Evans        try:
1778*f0865ec9SKyle Evans            remove_file(ec_self_tests_path + "ec_self_tests_core_"+name+".h")
1779*f0865ec9SKyle Evans        except:
1780*f0865ec9SKyle Evans            print("Warning: curve name "+name+" self tests do not seem to be present ...")
1781*f0865ec9SKyle Evans            return True
1782*f0865ec9SKyle Evans        return True
1783*f0865ec9SKyle Evans    if remove_all == True:
1784*f0865ec9SKyle Evans        asked = ""
1785*f0865ec9SKyle Evans        while asked != "y" and asked != "n":
1786*f0865ec9SKyle Evans            asked = get_user_input("You asked to remove everything related to ALL user defined curves. Enter y to confirm, n to cancel [y/n]. ")
1787*f0865ec9SKyle Evans        if asked == "n":
1788*f0865ec9SKyle Evans            print("NOT removing user defined curves (cancelled).")
1789*f0865ec9SKyle Evans            return True
1790*f0865ec9SKyle Evans        # Remove any user defined stuff with given name
1791*f0865ec9SKyle Evans        print("Removing ALL user defined curves ...")
1792*f0865ec9SKyle Evans        # Remove any user defined stuff (whatever name)
1793*f0865ec9SKyle Evans        file_remove_pattern(curves_list_path + "curves_list.h", ".*user_defined.*")
1794*f0865ec9SKyle Evans        file_remove_pattern(curves_list_path + "curves_list.h", ".*USER_DEFINED.*")
1795*f0865ec9SKyle Evans        file_remove_pattern(lib_ecc_types_path + "lib_ecc_types.h", ".*USER_DEFINED.*")
1796*f0865ec9SKyle Evans        file_remove_pattern(lib_ecc_config_path + "lib_ecc_config.h", ".*USER_DEFINED.*")
1797*f0865ec9SKyle Evans        file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*USER_DEFINED.*")
1798*f0865ec9SKyle Evans        file_remove_pattern(ec_self_tests_path + "ec_self_tests_core.h", ".*user_defined.*")
1799*f0865ec9SKyle Evans        file_remove_pattern(meson_options_path + "meson.options", ".*user_defined.*")
1800*f0865ec9SKyle Evans        remove_files_pattern(ec_params_path + "ec_params_user_defined_*.h")
1801*f0865ec9SKyle Evans        remove_files_pattern(ec_self_tests_path + "ec_self_tests_core_user_defined_*.h")
1802*f0865ec9SKyle Evans        return True
1803*f0865ec9SKyle Evans
1804*f0865ec9SKyle Evans    # If a g is provided, split it in two gx and gy
1805*f0865ec9SKyle Evans    if g != None:
1806*f0865ec9SKyle Evans        if (len(g)/2)%2 == 0:
1807*f0865ec9SKyle Evans            gx = get_int(g[:len(g)/2])
1808*f0865ec9SKyle Evans            gy = get_int(g[len(g)/2:])
1809*f0865ec9SKyle Evans        else:
1810*f0865ec9SKyle Evans            # This is probably a generator encapsulated in a bit string
1811*f0865ec9SKyle Evans            if g[0:2] != "04":
1812*f0865ec9SKyle Evans                print("Error: provided generator g is not conforming!")
1813*f0865ec9SKyle Evans                return False
1814*f0865ec9SKyle Evans            else:
1815*f0865ec9SKyle Evans                g = g[2:]
1816*f0865ec9SKyle Evans                gx = get_int(g[:len(g)/2])
1817*f0865ec9SKyle Evans                gy = get_int(g[len(g)/2:])
1818*f0865ec9SKyle Evans    if ECfile != None:
1819*f0865ec9SKyle Evans        # ASN.1 DER input incompatible with other options
1820*f0865ec9SKyle Evans        if (prime != None) or (a != None) or (b != None) or (gx != None) or (gy != None) or (order != None) or (cofactor != None):
1821*f0865ec9SKyle Evans            print("Error: option ECfile incompatible with explicit (prime, a, b, gx, gy, order, cofactor) options!")
1822*f0865ec9SKyle Evans            return False
1823*f0865ec9SKyle Evans        # We need at least a name
1824*f0865ec9SKyle Evans        if (name == None):
1825*f0865ec9SKyle Evans            print("Error: option ECfile needs a curve name!")
1826*f0865ec9SKyle Evans            return False
1827*f0865ec9SKyle Evans        # Open the file
1828*f0865ec9SKyle Evans        try:
1829*f0865ec9SKyle Evans            buf = open(ECfile, 'rb').read()
1830*f0865ec9SKyle Evans        except:
1831*f0865ec9SKyle Evans            print("Error: cannot open ECfile file "+ECfile)
1832*f0865ec9SKyle Evans            return False
1833*f0865ec9SKyle Evans        # Check if we have a PEM or a DER file
1834*f0865ec9SKyle Evans        (check, derbuf) = buffer_remove_pattern(buf, "-----.*-----")
1835*f0865ec9SKyle Evans        if (check == True):
1836*f0865ec9SKyle Evans            # This a PEM file, proceed with base64 decoding
1837*f0865ec9SKyle Evans            if(is_base64(derbuf) == False):
1838*f0865ec9SKyle Evans                print("Error: error when decoding ECfile file "+ECfile+" (seems to be PEM, but failed to decode)")
1839*f0865ec9SKyle Evans                return False
1840*f0865ec9SKyle Evans            derbuf = base64.b64decode(derbuf)
1841*f0865ec9SKyle Evans        (check, (a, b, prime, order, cofactor, gx, gy)) = parse_DER_ECParameters(derbuf)
1842*f0865ec9SKyle Evans        if (check == False):
1843*f0865ec9SKyle Evans            print("Error: error when parsing ECfile file "+ECfile+" (malformed or unsupported ASN.1)")
1844*f0865ec9SKyle Evans            return False
1845*f0865ec9SKyle Evans
1846*f0865ec9SKyle Evans    else:
1847*f0865ec9SKyle Evans        if (prime == None) or (a == None) or (b == None) or (gx == None) or (gy == None) or (order == None) or (cofactor == None) or (name == None):
1848*f0865ec9SKyle Evans            err_string = (prime == None)*"prime "+(a == None)*"a "+(b == None)*"b "+(gx == None)*"gx "+(gy == None)*"gy "+(order == None)*"order "+(cofactor == None)*"cofactor "+(name == None)*"name "
1849*f0865ec9SKyle Evans            print("Error: missing "+err_string+" in explicit curve definition (name, prime, a, b, gx, gy, order, cofactor)!")
1850*f0865ec9SKyle Evans            print("See the help with -h or --help")
1851*f0865ec9SKyle Evans            return False
1852*f0865ec9SKyle Evans
1853*f0865ec9SKyle Evans    # Some sanity checks here
1854*f0865ec9SKyle Evans    # Check that prime is indeed a prime
1855*f0865ec9SKyle Evans    if is_probprime(prime) == False:
1856*f0865ec9SKyle Evans        print("Error: given prime is *NOT* prime!")
1857*f0865ec9SKyle Evans        return False
1858*f0865ec9SKyle Evans    if is_probprime(order) == False:
1859*f0865ec9SKyle Evans        print("Error: given order is *NOT* prime!")
1860*f0865ec9SKyle Evans        return False
1861*f0865ec9SKyle Evans    if (a > prime) or (b > prime) or (gx > prime) or (gy > prime):
1862*f0865ec9SKyle Evans        err_string = (a > prime)*"a "+(b > prime)*"b "+(gx > prime)*"gx "+(gy > prime)*"gy "
1863*f0865ec9SKyle Evans        print("Error: "+err_string+"is > prime")
1864*f0865ec9SKyle Evans        return False
1865*f0865ec9SKyle Evans    # Check that the provided generator is on the curve
1866*f0865ec9SKyle Evans    if pow(gy, 2, prime) != ((pow(gx, 3, prime) + (a*gx) + b) % prime):
1867*f0865ec9SKyle Evans        print("Error: the given parameters (prime, a, b, gx, gy) do not verify the elliptic curve equation!")
1868*f0865ec9SKyle Evans        return False
1869*f0865ec9SKyle Evans
1870*f0865ec9SKyle Evans    # Check Montgomery and Edwards transfer coefficients
1871*f0865ec9SKyle Evans    if ((alpha_montgomery != None) and (gamma_montgomery == None)) or ((alpha_montgomery == None) and (gamma_montgomery != None)):
1872*f0865ec9SKyle Evans        print("Error: alpha_montgomery and gamma_montgomery must be both defined if used!")
1873*f0865ec9SKyle Evans        return False
1874*f0865ec9SKyle Evans    if (alpha_edwards != None):
1875*f0865ec9SKyle Evans        if (alpha_montgomery == None) or (gamma_montgomery == None):
1876*f0865ec9SKyle Evans            print("Error: alpha_edwards needs alpha_montgomery and gamma_montgomery to be both defined if used!")
1877*f0865ec9SKyle Evans            return False
1878*f0865ec9SKyle Evans
1879*f0865ec9SKyle Evans    # Now that we have our parameters, call the function to get bitlen
1880*f0865ec9SKyle Evans    pbitlen = getbitlen(prime)
1881*f0865ec9SKyle Evans    ec_params = curve_params(name, prime, pbitlen, a, b, gx, gy, order, cofactor, oid, alpha_montgomery, gamma_montgomery, alpha_edwards)
1882*f0865ec9SKyle Evans    # Check if there is a name collision somewhere
1883*f0865ec9SKyle Evans    if os.path.exists(ec_params_path + "ec_params_"+name+".h") == True :
1884*f0865ec9SKyle Evans        print("Error: file %s already exists!" % (ec_params_path + "ec_params_"+name+".h"))
1885*f0865ec9SKyle Evans        return False
1886*f0865ec9SKyle Evans    if (check_in_file(curves_list_path + "curves_list.h", "ec_params_"+name+"_str_params") == True) or (check_in_file(curves_list_path + "curves_list.h", "WITH_CURVE_"+name.upper()+"\n") == True) or (check_in_file(lib_ecc_types_path + "lib_ecc_types.h", "WITH_CURVE_"+name.upper()+"\n") == True):
1887*f0865ec9SKyle Evans        print("Error: name %s already exists in files" % ("ec_params_"+name))
1888*f0865ec9SKyle Evans        return False
1889*f0865ec9SKyle Evans    # Create a new file with the parameters
1890*f0865ec9SKyle Evans    if not os.path.exists(ec_params_path):
1891*f0865ec9SKyle Evans        # Create the "user_defined" folder if it does not exist
1892*f0865ec9SKyle Evans        os.mkdir(ec_params_path)
1893*f0865ec9SKyle Evans    f = open(ec_params_path + "ec_params_"+name+".h", 'w')
1894*f0865ec9SKyle Evans    f.write(ec_params)
1895*f0865ec9SKyle Evans    f.close()
1896*f0865ec9SKyle Evans    # Include the file in curves_list.h
1897*f0865ec9SKyle Evans    magic = "ADD curves header here"
1898*f0865ec9SKyle Evans    magic_re = "\/\* "+magic+" \*\/"
1899*f0865ec9SKyle Evans    magic_back = "/* "+magic+" */"
1900*f0865ec9SKyle Evans    file_replace_pattern(curves_list_path + "curves_list.h", magic_re, "#include <libecc/curves/user_defined/ec_params_"+name+".h>\n"+magic_back)
1901*f0865ec9SKyle Evans    # Add the curve mapping
1902*f0865ec9SKyle Evans    magic = "ADD curves mapping here"
1903*f0865ec9SKyle Evans    magic_re = "\/\* "+magic+" \*\/"
1904*f0865ec9SKyle Evans    magic_back = "/* "+magic+" */"
1905*f0865ec9SKyle Evans    file_replace_pattern(curves_list_path + "curves_list.h", magic_re, "#ifdef WITH_CURVE_"+name.upper()+"\n\t{ .type = "+name.upper()+", .params = &"+name+"_str_params },\n#endif /* WITH_CURVE_"+name.upper()+" */\n"+magic_back)
1906*f0865ec9SKyle Evans    # Add the new curve type in the enum
1907*f0865ec9SKyle Evans    # First we get the number of already defined curves so that we increment the enum counter
1908*f0865ec9SKyle Evans    num_with_curve = num_patterns_in_file(lib_ecc_types_path + "lib_ecc_types.h", "#ifdef WITH_CURVE_")
1909*f0865ec9SKyle Evans    magic = "ADD curves type here"
1910*f0865ec9SKyle Evans    magic_re = "\/\* "+magic+" \*\/"
1911*f0865ec9SKyle Evans    magic_back = "/* "+magic+" */"
1912*f0865ec9SKyle Evans    file_replace_pattern(lib_ecc_types_path + "lib_ecc_types.h", magic_re, "#ifdef WITH_CURVE_"+name.upper()+"\n\t"+name.upper()+" = "+str(num_with_curve+1)+",\n#endif /* WITH_CURVE_"+name.upper()+" */\n"+magic_back)
1913*f0865ec9SKyle Evans    # Add the new curve define in the config
1914*f0865ec9SKyle Evans    magic = "ADD curves define here"
1915*f0865ec9SKyle Evans    magic_re = "\/\* "+magic+" \*\/"
1916*f0865ec9SKyle Evans    magic_back = "/* "+magic+" */"
1917*f0865ec9SKyle Evans    file_replace_pattern(lib_ecc_config_path + "lib_ecc_config.h", magic_re, "#define WITH_CURVE_"+name.upper()+"\n"+magic_back)
1918*f0865ec9SKyle Evans    # Add the new curve meson option in the meson.options file
1919*f0865ec9SKyle Evans    magic = "ADD curves meson option here"
1920*f0865ec9SKyle Evans    magic_re = "# " + magic
1921*f0865ec9SKyle Evans    magic_back = "# " + magic
1922*f0865ec9SKyle Evans    file_replace_pattern(meson_options_path + "meson.options", magic_re, "\t'"+name.lower()+"',\n"+magic_back)
1923*f0865ec9SKyle Evans
1924*f0865ec9SKyle Evans    # Do we need to add some test vectors?
1925*f0865ec9SKyle Evans    if add_test_vectors != None:
1926*f0865ec9SKyle Evans        print("Test vectors generation asked: this can take some time! Please wait ...")
1927*f0865ec9SKyle Evans        # Create curve
1928*f0865ec9SKyle Evans        c = Curve(a, b, prime, order, cofactor, gx, gy, cofactor * order, name, oid)
1929*f0865ec9SKyle Evans        # Generate key pair for the algorithm
1930*f0865ec9SKyle Evans        vectors = gen_self_tests(c, add_test_vectors)
1931*f0865ec9SKyle Evans        # Iterate through all the tests
1932*f0865ec9SKyle Evans        f = open(ec_self_tests_path + "ec_self_tests_core_"+name+".h", 'w')
1933*f0865ec9SKyle Evans        for l in vectors:
1934*f0865ec9SKyle Evans            for v in l:
1935*f0865ec9SKyle Evans                for case in v:
1936*f0865ec9SKyle Evans                    (case_name, case_vector) = case
1937*f0865ec9SKyle Evans                    # Add the new test case
1938*f0865ec9SKyle Evans                    magic = "ADD curve test case here"
1939*f0865ec9SKyle Evans                    magic_re = "\/\* "+magic+" \*\/"
1940*f0865ec9SKyle Evans                    magic_back = "/* "+magic+" */"
1941*f0865ec9SKyle Evans                    file_replace_pattern(ec_self_tests_path + "ec_self_tests_core.h", magic_re, case_name+"\n"+magic_back)
1942*f0865ec9SKyle Evans                    # Create/Increment the header file
1943*f0865ec9SKyle Evans                    f.write(case_vector)
1944*f0865ec9SKyle Evans        f.close()
1945*f0865ec9SKyle Evans        # Add the new test cases header
1946*f0865ec9SKyle Evans        magic = "ADD curve test vectors header here"
1947*f0865ec9SKyle Evans        magic_re = "\/\* "+magic+" \*\/"
1948*f0865ec9SKyle Evans        magic_back = "/* "+magic+" */"
1949*f0865ec9SKyle Evans        file_replace_pattern(ec_self_tests_path + "ec_self_tests_core.h", magic_re, "#include \"ec_self_tests_core_"+name+".h\"\n"+magic_back)
1950*f0865ec9SKyle Evans    return True
1951*f0865ec9SKyle Evans
1952*f0865ec9SKyle Evans
1953*f0865ec9SKyle Evans#### Main
1954*f0865ec9SKyle Evansif __name__ == "__main__":
1955*f0865ec9SKyle Evans    signal.signal(signal.SIGINT, handler)
1956*f0865ec9SKyle Evans    parse_cmd_line(sys.argv[1:])
1957