1 ### -*- mode: python, coding: utf-8 -*-
3 ### Testing elliptic curve functionality
5 ### (c) 2019 Straylight/Edgeware
8 ###----- Licensing notice ---------------------------------------------------
10 ### This file is part of the Python interface to Catacomb.
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.
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.
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,
27 ###--------------------------------------------------------------------------
38 kk
= C
.BinPolyField(0x13)
42 ###--------------------------------------------------------------------------
43 class TestCurvelessPoints (U
.TestCase
):
44 """Test handling of points without an explicit curve."""
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")
62 me
.assertRaises(TypeError, C
.ECPt
, (1, 2, 3))
63 me
.assertRaises(TypeError, C
.ECPt
, 1, 2, 3)
64 me
.assertRaises(TypeError, C
.ECPt
, 1234)
65 me
.assertRaises(TypeError, C
.ECPt
, object())
66 me
.assertRaises(TypeError, C
.ECPt
, 1, None)
67 #me.assertRaises(TypeError, C.ECPt, (1, None))
69 ## Arithmetic shouldn't work.
70 me
.assertRaises(TypeError, T
.neg
, P
)
71 me
.assertRaises(TypeError, T
.add
, P
, Q
)
73 ## Attributes. We only have raw integer access.
74 me
.assertTrue(P
.point
is P
)
75 me
.assertEqual(P
.ix
, 12345)
76 me
.assertEqual(P
.iy
, 67890)
77 me
.assertEqual(P
.tobuf(), C
.bytes("000230390003010932"))
78 me
.assertRaises(AttributeError, lambda: P
.curve
)
79 me
.assertRaises(AttributeError, lambda: P
.x
)
80 me
.assertRaises(AttributeError, lambda: P
.y
)
81 me
.assertRaises(AttributeError, lambda: P
._x
)
82 me
.assertRaises(AttributeError, lambda: P
._y
)
83 me
.assertRaises(AttributeError, lambda: P
._z
)
85 ## Encoding and decoding.
87 me
.assertEqual(O
.tobuf(), C
.bytes("0000"))
88 me
.assertEqual(C
.ECPt(0, 0).tobuf(), C
.bytes("000100000100"))
89 me
.assertEqual(P
.tobuf(), C
.bytes("0001fe00020123"))
90 me
.assertEqual(C
.ECPt
.frombuf(C
.bytes("0001fe000201233f")),
92 me
.assertRaises(ValueError, C
.ECPt
.frombuf
, C
.bytes("0001fe000201"))
94 ## String conversion and parsing.
95 me
.assertEqual(C
.ECPt
.parse("254, 291)"), (P
, ")"))
96 me
.assertRaises(ValueError, C
.ECPt
.parse
, "(254, 291")
98 ###--------------------------------------------------------------------------
99 class TestCurves (T
.GenericTestMixin
):
100 """Test elliptic curves."""
102 def test_compare(me
):
105 me
.assertFalse(E
is E1
)
106 me
.assertEqual(E
, E1
)
107 me
.assertNotEqual(E
, EE
)
108 me
.assertNotEqual(E
, [])
110 def _test_curve(me
, einfo
, checkfail
= False):
112 ## Some useful values.
119 me
.assertTrue(n
.primep()); l
= C
.NicePrimeField(n
)
121 ## Check that things are basically sane.
125 nP
= n
*P
; me
.assertFalse(nP
); me
.assertEqual(nP
, O
)
127 ## Check point construction.
128 me
.assertEqual(type(P
.ix
), C
.MP
)
129 me
.assertEqual(type(P
.iy
), C
.MP
)
130 me
.assertTrue(isinstance(P
.x
, C
.FE
))
131 me
.assertTrue(isinstance(P
.y
, C
.FE
))
132 me
.assertTrue(isinstance(P
._x
, C
.FE
))
133 me
.assertTrue(isinstance(P
._y
, C
.FE
))
134 if isinstance(E
, C
.ECPrimeProjCurve
) or isinstance(E
, C
.ECBinProjCurve
):
135 me
.assertTrue(isinstance(P
._z
, C
.FE
))
137 me
.assertEqual(P
._z
, None)
138 me
.assertEqual(E(None), O
)
139 me
.assertEqual(E(P
.x
, P
.y
), P
)
140 me
.assertEqual(E((P
.x
, P
.y
)), P
)
141 me
.assertEqual(E(P
._x
, P
._y
, P
._z
), P
)
142 me
.assertEqual(E((P
._x
, P
._y
, P
._z
)), P
)
143 Q
= E(P
.point
); me
.assertEqual(type(Q
), E
); me
.assertEqual(Q
, P
)
144 me
.assertEqual(E("%s, %s" %
(P
.ix
, P
.iy
)), P
)
145 me
.assertRaises(ValueError, E
, "1234")
146 me
.assertRaises(ValueError, E
, "1234,")
147 me
.assertRaises(TypeError, E
, 1, None)
148 Q
= E(P
.ix
); me
.assertTrue(Q
== P
or Q
== -P
)
149 for i
in T
.range(128):
152 except ValueError: badx
= x
; break
154 me
.fail("no off-curve point found")
157 me
.assertEqual(P
.ix
, P
.point
.ix
)
158 me
.assertEqual(P
.iy
, P
.point
.iy
)
159 me
.assertEqual(P
.x
, k(P
.point
.ix
))
160 me
.assertEqual(P
.y
, k(P
.point
.iy
))
162 if isinstance(E
, C
.ECPrimeProjCurve
) or isinstance(E
, C
.ECBinProjCurve
):
163 me
.assertEqual(P
._z
, k
.one
)
164 me
.assertEqual(R
._x
, R
.x
*R
._z
**2)
165 me
.assertEqual(R
._y
, R
.y
*R
._z
**3)
166 me
.assertNotEqual(R
._z
, k
.one
)
168 me
.assertEqual(P
._z
, None)
169 me
.assertEqual(R
._x
, R
.x
)
170 me
.assertEqual(R
._y
, R
.y
)
171 me
.assertEqual(R
._z
, None)
172 me
.assertEqual(R
.curve
, E
)
176 me
.assertEqual(Q
, P
*17)
177 me
.assertEqual(-Q
, (n
- 17)*P
)
178 me
.assertEqual(Q
+ R
, 23*P
)
179 me
.assertEqual(Q
+ R
.point
, 23*P
)
180 me
.assertRaises(TypeError, T
.add
, Q
.point
, R
.point
)
181 me
.assertEqual(Q
- R
, 11*P
)
182 me
.assertEqual(P
*l(17), Q
)
185 me
.assertTrue(P
== P
)
186 me
.assertTrue(P
!= Q
)
187 me
.assertRaises(TypeError, T
.lt
, P
, Q
)
188 me
.assertRaises(TypeError, T
.le
, P
, Q
)
189 me
.assertRaises(TypeError, T
.ge
, P
, Q
)
190 me
.assertRaises(TypeError, T
.gt
, P
, Q
)
193 Z0
= C
.ByteString
.zero(0)
194 Z1
= C
.ByteString
.zero(1)
195 me
.assertEqual(O
.ec2osp(), Z1
)
196 me
.assertEqual(E
.os2ecp(Z1
), (O
, Z0
))
197 t
= C
.WriteBuffer() \
199 .put(P
.ix
.storeb(k
.noctets
)) \
200 .put(P
.iy
.storeb(k
.noctets
)) \
202 me
.assertEqual(P
.ec2osp(), t
)
203 me
.assertEqual(C
.WriteBuffer().putecptraw(P
).contents
, t
)
204 me
.assertEqual(C
.WriteBuffer().ec2osp(P
).contents
, t
)
205 me
.assertEqual(E
.os2ecp(t
), (P
, Z0
))
206 me
.assertEqual(C
.ReadBuffer(t
).getecptraw(E
), P
)
207 me
.assertEqual(C
.ReadBuffer(t
).os2ecp(E
), P
)
208 if isinstance(k
, C
.PrimeField
): ybit
= int(P
.iy
&1)
210 try: ybit
= int((P
.y
/P
.x
).value
&C
.GF(1))
211 except ZeroDivisionError: ybit
= 0
212 t
= C
.WriteBuffer() \
213 .putu8(0x02 | ybit
) \
214 .put(P
.ix
.storeb(k
.noctets
)) \
216 me
.assertEqual(P
.ec2osp(C
.EC_LSB
), t
)
217 me
.assertEqual(C
.WriteBuffer().ec2osp(P
, C
.EC_LSB
).contents
, t
)
218 me
.assertEqual(E
.os2ecp(t
, C
.EC_LSB
), (P
, Z0
))
219 me
.assertEqual(C
.ReadBuffer(t
).os2ecp(E
, C
.EC_LSB
), P
)
222 Q
= E
.find(P
.x
); me
.assertTrue(Q
== P
or Q
== -P
)
223 Q
= E
.find(P
.ix
); me
.assertTrue(Q
== P
or Q
== -P
)
224 me
.assertRaises(ValueError, E
.find
, badx
)
225 for i
in T
.range(128):
226 if E
.rand() != P
: break
228 me
.fail("random point always gives me P")
229 for i
in T
.range(128):
230 R
= E
.rand(C
.LCRand(i
))
233 me
.fail("random point always gives me P")
234 me
.assertEqual(R
, E
.rand(C
.LCRand(i
)))
235 me
.assertEqual(E
.parse("%s, %s!xyzzy" %
(P
.ix
, P
.iy
)), (P
, "!xyzzy"))
237 ## Simultaneous multiplication.
238 Q
, R
, S
= 5*P
, 7*P
, 11*P
239 me
.assertEqual(E
.mmul([Q
, 9, R
, 8, S
, 5]), 156*P
)
240 me
.assertEqual(E
.mmul(Q
, 9, R
, 8, S
, 5), 156*P
)
242 ## Test other curve info things while we're here.
243 if not checkfail
: einfo
.check()
244 else: me
.assertRaises(ValueError, einfo
.check
)
246 def test_tinycurves(me
):
247 me
._test_curve(C
.ECInfo(E
, 2*P
, 13, 2), checkfail
= True)
248 ei
, _
= C
.ECInfo
.parse("binpoly: 0x13; bin: 0x01, 0x08; 0x02, 0x0c: 5*4")
249 me
._test_curve(ei
, checkfail
= True)
251 TestCurves
.generate_testcases((name
, C
.eccurves
[name
]) for name
in
252 ["nist-p256", "nist-k233", "nist-b163", "nist-b283n"])
254 ###----- That's all, folks --------------------------------------------------
256 if __name__
== "__main__": U
.main()