math/f25519.[ch]: More field operations.
[catacomb] / utils / qfarith-test
1 #! /usr/bin/python
2
3 from sys import argv
4 import catacomb as C
5
6 TESTS = {}
7 NTEST = 20
8
9 def test(arg):
10 def reg(fn, name):
11 TESTS[name] = fn
12 return fn
13 if isinstance(arg, str): return lambda fn: reg(fn, arg)
14 else: return reg(arg, arg.__name__.replace('_', '-'))
15
16 FIELDS = {}
17
18 class FieldElt (object):
19 def __init__(me, k, n):
20 me.k = k
21 me.v = (C.MP(n)%k.p).storel(k.len)
22 def __str__(me): return hex(me.v)
23 @property
24 def n(me): return C.MP.loadl(me.v)
25 def __pos__(me): return FieldElt(me.k, me.n)
26 def __neg__(me): return FieldElt(me.k, -me.n)
27 def __nonzero__(me): return me.n != 0
28 def __add__(me, you): return FieldElt(me.k, me.n + me.k(you).n)
29 def __radd__(me, you): return FieldElt(me.k, me.k(you).n + me.n)
30 def __sub__(me, you): return FieldElt(me.k, me.n - me.k(you).n)
31 def __rsub__(me, you): return FieldElt(me.k, me.k(you).n - me.n)
32 def __mul__(me, you): return FieldElt(me.k, me.n*me.k(you).n)
33 def __rmul__(me, you): return FieldElt(me.k, me.k(you).n*me.n)
34 def __div__(me, you): return FieldElt(me.k, me.n*me.k(you).inv().n)
35 def __rdiv__(me, you): return FieldElt(me.k, me.k(you).n*me.inv().n)
36 def inv(me): return FieldElt(me.k, me.k.p.modinv(me.n))
37 def sqrt(me): return FieldElt(me.k, me.k.p.modsqrt(me.n))
38 @classmethod
39 def rand(cls, k):
40 me = cls(k, 0)
41 me.v = C.rand.block(k. len)
42 return me
43
44 class Field (object):
45 def __init__(me, p, len = None):
46 me.p = C.MP(p)
47 me.len = len is None and me.p.noctets or len
48 @classmethod
49 def register(cls, name, *args, **kw):
50 FIELDS[name] = cls(*args, **kw)
51 def rand(me): return FieldElt.rand(me)
52 def __call__(me, n):
53 if isinstance(n, FieldElt):
54 assert n.k is me
55 return n
56 else:
57 return FieldElt(me, n)
58
59 Field.register('f25519', C.MP(0).setbit(255) - 19)
60
61 def binop(k, op):
62 x = k.rand(); y = k.rand()
63 print ' %s\n %s\n %s;' % (x, y, op(x, y))
64
65 def unop(k, op):
66 x = k.rand()
67 print ' %s\n %s;' % (x, op(x))
68
69 @test
70 def add(k): binop(k, lambda x, y: x + y)
71
72 @test
73 def sub(k): binop(k, lambda x, y: x - y)
74
75 @test
76 def neg(k): unop(k, lambda x: -x)
77
78 @test
79 def mul(k): binop(k, lambda x, y: x*y)
80
81 @test
82 def sqr(k): unop(k, lambda x: x*x)
83
84 @test
85 def inv(k): unop(k, lambda x: x and x.inv() or k(0))
86
87 @test
88 def quosqrt(k):
89 x = k.rand(); y = k.rand()
90 yy = +y
91 u = yy and x/y or k(0)
92 try: zz = u.sqrt()
93 except ValueError: print ' %s\n %s\n "" "";' % (x, y)
94 else: print ' %s\n %s\n %s\n %s;' % (x, y, zz, -zz)
95
96 @test
97 def mulconst(k):
98 x = k.rand()
99 a = C.rand.range(1 << 20) - (1 << 19)
100 print ' %s %d\n %s;' % (x, a, a*x)
101
102 def mask(): return C.rand.range(2)*0xffffffff
103
104 @test
105 def pick2(k):
106 x = k.rand(); y = k.rand(); m = mask()
107 print ' %s\n %s\n 0x%08x\n %s;' % (x, y, m, +(m and x or y))
108
109 @test
110 def condneg(k):
111 x = k.rand(); m = mask()
112 print ' %s\n 0x%08x\n %s;' % (x, m, x*(m and -1 or +1))
113
114 @test
115 def pickn(k):
116 n = C.rand.range(31) + 1
117 v = [k.rand() for i in xrange(n)]
118 i = C.rand.range(n)
119 print ' "%s"\n %d\n %s;' % ('\n '.join(map(str, v)), i, +v[i])
120
121 @test
122 def condswap(k):
123 x = k.rand(); y = k.rand(); m = mask()
124 xx, yy = m and (+y, +x) or (+x, +y)
125 print ' %s\n %s\n 0x%08x\n %s\n %s;' % (x, y, m, xx, yy)
126
127 @test
128 def sub_mulc_add_sub_mul(k):
129 u = k.rand(); v = k.rand(); w = k.rand(); x = k.rand(); y = k.rand();
130 a = C.rand.range(1 << 20) - (1 << 19)
131 print ' %s\n %s %d\n %s\n %s\n %s\n %s;' % \
132 (u, v, a, w, x, y, ((u - v)*a + w)*(x - y))
133
134 k = FIELDS[argv[1]]
135 for t in argv[2:]:
136 print '%s {' % t
137 for i in xrange(NTEST): TESTS[t](k)
138 print '}'