ec.c (ecptxl_1): Preparatory reformatting.
[catacomb-python] / t / t-ec.py
CommitLineData
553d59fe
MW
1### -*- mode: python, coding: utf-8 -*-
2###
3### Testing elliptic curve functionality
4###
5### (c) 2019 Straylight/Edgeware
6###
7
8###----- Licensing notice ---------------------------------------------------
9###
10### This file is part of the Python interface to Catacomb.
11###
12### Catacomb/Python is free software: you can redistribute it and/or
13### modify it under the terms of the GNU General Public License as
14### published by the Free Software Foundation; either version 2 of the
15### License, or (at your option) any later version.
16###
17### Catacomb/Python is distributed in the hope that it will be useful, but
18### WITHOUT ANY WARRANTY; without even the implied warranty of
19### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20### General Public License for more details.
21###
22### You should have received a copy of the GNU General Public License
23### along with Catacomb/Python. If not, write to the Free Software
24### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25### USA.
26
27###--------------------------------------------------------------------------
28### Imported modules.
29
30import catacomb as C
31import unittest as U
32import testutils as T
33
34k = C.PrimeField(19)
35E = k.ec(-3, 6)
36P = E(0) # order 26
37
38kk = C.BinPolyField(0x13)
39EE = kk.ec(1, 8)
40PP = EE(8) # order 20
41
42###--------------------------------------------------------------------------
43class TestCurvelessPoints (U.TestCase):
44 """Test handling of points without an explicit curve."""
45
46 def test(me):
47
48 ## Construction.
49 O = C.ECPt(); me.assertFalse(O)
50 P = C.ECPt(12345, 67890); me.assertTrue(P)
51 Q = C.ECPt(23456, 78901); me.assertTrue(Q); me.assertNotEqual(P, Q)
52 R = C.ECPt(O); me.assertFalse(R); me.assertEqual(O, R); me.assertNotEqual(P, R)
53 R = C.ECPt(None); me.assertFalse(R); me.assertEqual(O, R)
54 me.assertEqual(C.ECPt("12345, 67890"), P)
55 me.assertEqual(C.ECPt((12345, 67890)), P)
56 me.assertRaises(TypeError, C.ECPt, ())
57 me.assertRaises(TypeError, C.ECPt, (1234,))
58 me.assertRaises(TypeError, C.ECPt, (1, 2, 3, 4))
59 me.assertRaises(ValueError, C.ECPt, "12345")
60 me.assertRaises(ValueError, C.ECPt, "12345,")
61 me.assertRaises(ValueError, C.ECPt, "12345, xyzzy")
941a3483 62 me.assertRaises(ValueError, C.ECPt, "12345, 67890!??")
7f5eb608 63 me.assertRaises(ValueError, C.ECPt, (1, 2, 3))
553d59fe
MW
64 me.assertRaises(TypeError, C.ECPt, 1, 2, 3)
65 me.assertRaises(TypeError, C.ECPt, 1234)
66 me.assertRaises(TypeError, C.ECPt, object())
67 me.assertRaises(TypeError, C.ECPt, 1, None)
68 #me.assertRaises(TypeError, C.ECPt, (1, None))
69
70 ## Arithmetic shouldn't work.
71 me.assertRaises(TypeError, T.neg, P)
72 me.assertRaises(TypeError, T.add, P, Q)
73
74 ## Attributes. We only have raw integer access.
75 me.assertTrue(P.point is P)
76 me.assertEqual(P.ix, 12345)
77 me.assertEqual(P.iy, 67890)
78 me.assertEqual(P.tobuf(), C.bytes("000230390003010932"))
79 me.assertRaises(AttributeError, lambda: P.curve)
80 me.assertRaises(AttributeError, lambda: P.x)
81 me.assertRaises(AttributeError, lambda: P.y)
82 me.assertRaises(AttributeError, lambda: P._x)
83 me.assertRaises(AttributeError, lambda: P._y)
84 me.assertRaises(AttributeError, lambda: P._z)
85
86 ## Encoding and decoding.
87 P = C.ECPt(254, 291)
88 me.assertEqual(O.tobuf(), C.bytes("0000"))
89 me.assertEqual(C.ECPt(0, 0).tobuf(), C.bytes("000100000100"))
90 me.assertEqual(P.tobuf(), C.bytes("0001fe00020123"))
91 me.assertEqual(C.ECPt.frombuf(C.bytes("0001fe000201233f")),
92 (P, C.bytes("3f")))
93 me.assertRaises(ValueError, C.ECPt.frombuf, C.bytes("0001fe000201"))
94
95 ## String conversion and parsing.
96 me.assertEqual(C.ECPt.parse("254, 291)"), (P, ")"))
97 me.assertRaises(ValueError, C.ECPt.parse, "(254, 291")
98
99###--------------------------------------------------------------------------
100class TestCurves (T.GenericTestMixin):
101 """Test elliptic curves."""
102
103 def test_compare(me):
104 me.assertEqual(E, E)
105 E1 = k.ec(-3, 6)
106 me.assertFalse(E is E1)
107 me.assertEqual(E, E1)
108 me.assertNotEqual(E, EE)
109 me.assertNotEqual(E, [])
110
111 def _test_curve(me, einfo, checkfail = False):
112
113 ## Some useful values.
114 E = einfo.curve
115 P = einfo.G
116 O = E()
117 n = einfo.r
118 h = einfo.h
119 k = E.field
120 me.assertTrue(n.primep()); l = C.NicePrimeField(n)
121
122 ## Check that things are basically sane.
123 me.assertFalse(O)
124 me.assertTrue(P)
125 me.assertTrue(n)
126 nP = n*P; me.assertFalse(nP); me.assertEqual(nP, O)
127
128 ## Check point construction.
129 me.assertEqual(type(P.ix), C.MP)
130 me.assertEqual(type(P.iy), C.MP)
131 me.assertTrue(isinstance(P.x, C.FE))
132 me.assertTrue(isinstance(P.y, C.FE))
133 me.assertTrue(isinstance(P._x, C.FE))
134 me.assertTrue(isinstance(P._y, C.FE))
135 if isinstance(E, C.ECPrimeProjCurve) or isinstance(E, C.ECBinProjCurve):
136 me.assertTrue(isinstance(P._z, C.FE))
137 else:
138 me.assertEqual(P._z, None)
139 me.assertEqual(E(None), O)
140 me.assertEqual(E(P.x, P.y), P)
141 me.assertEqual(E((P.x, P.y)), P)
142 me.assertEqual(E(P._x, P._y, P._z), P)
143 me.assertEqual(E((P._x, P._y, P._z)), P)
144 Q = E(P.point); me.assertEqual(type(Q), E); me.assertEqual(Q, P)
145 me.assertEqual(E("%s, %s" % (P.ix, P.iy)), P)
146 me.assertRaises(ValueError, E, "1234")
147 me.assertRaises(ValueError, E, "1234,")
941a3483 148 me.assertRaises(ValueError, E, "1234, 5678?")
553d59fe
MW
149 me.assertRaises(TypeError, E, 1, None)
150 Q = E(P.ix); me.assertTrue(Q == P or Q == -P)
151 for i in T.range(128):
152 x = P.ix + i
153 try: E(x)
154 except ValueError: badx = x; break
155 else:
156 me.fail("no off-curve point found")
157
158 ## Attributes.
159 me.assertEqual(P.ix, P.point.ix)
160 me.assertEqual(P.iy, P.point.iy)
161 me.assertEqual(P.x, k(P.point.ix))
162 me.assertEqual(P.y, k(P.point.iy))
163 R = 6*P
164 if isinstance(E, C.ECPrimeProjCurve) or isinstance(E, C.ECBinProjCurve):
165 me.assertEqual(P._z, k.one)
166 me.assertEqual(R._x, R.x*R._z**2)
167 me.assertEqual(R._y, R.y*R._z**3)
168 me.assertNotEqual(R._z, k.one)
169 else:
170 me.assertEqual(P._z, None)
171 me.assertEqual(R._x, R.x)
172 me.assertEqual(R._y, R.y)
173 me.assertEqual(R._z, None)
174 me.assertEqual(R.curve, E)
175
176 ## Arithmetic.
177 Q = 17*P
178 me.assertEqual(Q, P*17)
179 me.assertEqual(-Q, (n - 17)*P)
180 me.assertEqual(Q + R, 23*P)
181 me.assertEqual(Q + R.point, 23*P)
182 me.assertRaises(TypeError, T.add, Q.point, R.point)
6311e4f7 183 me.assertRaises(TypeError, T.mul, kk(1), Q)
553d59fe 184 me.assertEqual(Q - R, 11*P)
dc55f697
MW
185 me.assertEqual(l(17)*P, Q)
186 me.assertEqual(P*l(17), Q)
553d59fe
MW
187
188 ## Ordering.
189 me.assertTrue(P == P)
190 me.assertTrue(P != Q)
191 me.assertRaises(TypeError, T.lt, P, Q)
192 me.assertRaises(TypeError, T.le, P, Q)
193 me.assertRaises(TypeError, T.ge, P, Q)
194 me.assertRaises(TypeError, T.gt, P, Q)
195
196 ## Encoding.
197 Z0 = C.ByteString.zero(0)
198 Z1 = C.ByteString.zero(1)
199 me.assertEqual(O.ec2osp(), Z1)
200 me.assertEqual(E.os2ecp(Z1), (O, Z0))
d0cc556a
MW
201 t = C.WriteBuffer() \
202 .putu8(0x04) \
203 .put(P.ix.storeb(k.noctets)) \
204 .put(P.iy.storeb(k.noctets)) \
205 .contents
553d59fe 206 me.assertEqual(P.ec2osp(), t)
d0cc556a 207 me.assertEqual(C.WriteBuffer().putecptraw(P).contents, t)
a375f639 208 me.assertEqual(C.WriteBuffer().ec2osp(P).contents, t)
553d59fe
MW
209 me.assertEqual(E.os2ecp(t), (P, Z0))
210 me.assertEqual(C.ReadBuffer(t).getecptraw(E), P)
a375f639 211 me.assertEqual(C.ReadBuffer(t).os2ecp(E), P)
553d59fe
MW
212 if isinstance(k, C.PrimeField): ybit = int(P.iy&1)
213 else:
214 try: ybit = int((P.y/P.x).value&C.GF(1))
215 except ZeroDivisionError: ybit = 0
d0cc556a
MW
216 t = C.WriteBuffer() \
217 .putu8(0x02 | ybit) \
218 .put(P.ix.storeb(k.noctets)) \
219 .contents
553d59fe 220 me.assertEqual(P.ec2osp(C.EC_LSB), t)
a375f639 221 me.assertEqual(C.WriteBuffer().ec2osp(P, C.EC_LSB).contents, t)
553d59fe 222 me.assertEqual(E.os2ecp(t, C.EC_LSB), (P, Z0))
a375f639 223 me.assertEqual(C.ReadBuffer(t).os2ecp(E, C.EC_LSB), P)
553d59fe
MW
224
225 ## Curve methods.
226 Q = E.find(P.x); me.assertTrue(Q == P or Q == -P)
227 Q = E.find(P.ix); me.assertTrue(Q == P or Q == -P)
228 me.assertRaises(ValueError, E.find, badx)
229 for i in T.range(128):
230 if E.rand() != P: break
231 else:
232 me.fail("random point always gives me P")
233 for i in T.range(128):
234 R = E.rand(C.LCRand(i))
235 if R != P: break
236 else:
237 me.fail("random point always gives me P")
238 me.assertEqual(R, E.rand(C.LCRand(i)))
239 me.assertEqual(E.parse("%s, %s!xyzzy" % (P.ix, P.iy)), (P, "!xyzzy"))
240
241 ## Simultaneous multiplication.
242 Q, R, S = 5*P, 7*P, 11*P
243 me.assertEqual(E.mmul([Q, 9, R, 8, S, 5]), 156*P)
244 me.assertEqual(E.mmul(Q, 9, R, 8, S, 5), 156*P)
245
246 ## Test other curve info things while we're here.
247 if not checkfail: einfo.check()
248 else: me.assertRaises(ValueError, einfo.check)
249
250 def test_tinycurves(me):
251 me._test_curve(C.ECInfo(E, 2*P, 13, 2), checkfail = True)
252 ei, _ = C.ECInfo.parse("binpoly: 0x13; bin: 0x01, 0x08; 0x02, 0x0c: 5*4")
253 me._test_curve(ei, checkfail = True)
254
255TestCurves.generate_testcases((name, C.eccurves[name]) for name in
256 ["nist-p256", "nist-k233", "nist-b163", "nist-b283n"])
257
258###----- That's all, folks --------------------------------------------------
259
260if __name__ == "__main__": U.main()