chiark / gitweb /
ec.c: Reject strings with trailing junk in the curve-point constructor.
[catacomb-python] / t / t-ec.py
CommitLineData
ffad1322
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")
55114a87 62 me.assertRaises(ValueError, C.ECPt, "12345, 67890!??")
ffad1322
MW
63 me.assertRaises(TypeError, C.ECPt, (1, 2, 3))
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,")
55114a87 148 me.assertRaises(ValueError, E, "1234, 5678?")
ffad1322
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)
f3e22904 183 me.assertRaises(TypeError, T.mul, kk(1), Q)
ffad1322 184 me.assertEqual(Q - R, 11*P)
3317491a
MW
185 me.assertEqual(l(17)*P, Q)
186 me.assertEqual(P*l(17), Q)
ffad1322
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))
ac5a6ec0
MW
201 t = C.WriteBuffer() \
202 .putu8(0x04) \
203 .put(P.ix.storeb(k.noctets)) \
204 .put(P.iy.storeb(k.noctets)) \
205 .contents
ffad1322 206 me.assertEqual(P.ec2osp(), t)
ac5a6ec0 207 me.assertEqual(C.WriteBuffer().putecptraw(P).contents, t)
04d6d312 208 me.assertEqual(C.WriteBuffer().ec2osp(P).contents, t)
ffad1322
MW
209 me.assertEqual(E.os2ecp(t), (P, Z0))
210 me.assertEqual(C.ReadBuffer(t).getecptraw(E), P)
04d6d312 211 me.assertEqual(C.ReadBuffer(t).os2ecp(E), P)
ffad1322
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
ac5a6ec0
MW
216 t = C.WriteBuffer() \
217 .putu8(0x02 | ybit) \
218 .put(P.ix.storeb(k.noctets)) \
219 .contents
ffad1322 220 me.assertEqual(P.ec2osp(C.EC_LSB), t)
04d6d312 221 me.assertEqual(C.WriteBuffer().ec2osp(P, C.EC_LSB).contents, t)
ffad1322 222 me.assertEqual(E.os2ecp(t, C.EC_LSB), (P, Z0))
04d6d312 223 me.assertEqual(C.ReadBuffer(t).os2ecp(E, C.EC_LSB), P)
ffad1322
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()