mp.c: Tighten up the `MP' and `GF' implicit conversions.
[catacomb-python] / t / t-convert.py
CommitLineData
ffad1322
MW
1### -*- mode: python, coding: utf-8 -*-
2###
3### Testing implicit conversions
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 sys as SYS
32import unittest as U
33import testutils as T
34
35###--------------------------------------------------------------------------
36class TestConvert (U.TestCase):
37 """Test implicit conversions between various mathematical types."""
38
39 def test(me):
40
41 k = C.PrimeField(17)
42 E = k.ec(-3, 4)
43 P = E(1) # order 15
44 kk = C.BinPolyField(0x13)
45 EE = kk.ec(1, 2)
46 PP = E(9) # order 16
47
48 ## `MP' asymmetric operations.
49 me.assertEqual(pow(C.MP(5), 2), 25)
50 me.assertEqual(pow(5, C.MP(2)), 25)
51 me.assertEqual(pow(C.MP(5), 2, 7), 4)
52 me.assertEqual(pow(5, C.MP(2), 7), 4)
53 me.assertEqual(pow(5, 2, C.MP(7)), 4)
7032ee7c 54 for bad in [C.GF, k, kk, str, float, lambda x: [x]]:
ffad1322
MW
55 me.assertRaises(TypeError, pow, C.MP(5), bad(2))
56 me.assertRaises(TypeError, pow, C.MP(5), bad(2), 7)
d472b9a1 57 if not (T.PY2 and T.DEBUGP):
ffad1322
MW
58 ## Debug builds of Python 2 crash here, and it's not our fault. Run
59 ##
60 ## $ python2.7-dbg -c 'pow(long(5), 2, [7])'
61 ##
62 ## to confirm. The `[7]' causes coercion to occur. The first and
63 ## second operands are coerced first, and successfully replaced by
64 ## the results: the first operand (in this case) is unchanged, but
65 ## has its refcount bumped, and the second operand is replaced by the
66 ## result of coercion, which now has a refcount of 1. Then the first
67 ## and third operands are coerced, which fails. Python decrements
68 ## the refcounts of the results of the first coercion, so the second
69 ## operand is now freed and, in debug builds, clobbered. Python then
70 ## tries to format an error message, quoting the types of the
71 ## operands, but one of them has been lost.
72 me.assertRaises(TypeError, pow, C.MP(5), 2, bad(7))
73 me.assertRaises(TypeError, T.lsl, C.MP(5), bad(2))
74
75 ## `GF' asymmetric operations.
76 me.assertEqual(pow(C.GF(0x5), 2), C.GF(0x11))
77 me.assertEqual(pow(C.GF(0x5), C.MP(2)), C.GF(0x11))
78 me.assertEqual(pow(C.GF(5), 2, C.GF(0x13)), C.GF(0x2))
7032ee7c 79 for bad in [k, kk, str, float, lambda x: [x]]:
ffad1322
MW
80 me.assertRaises(TypeError, pow, C.GF(5), bad(2))
81 me.assertRaises(TypeError, T.lsl, C.GF(5), bad(2))
7032ee7c 82 for bad in [int, C.MP, k, kk, str, float, lambda x: [x]]:
ffad1322
MW
83 me.assertRaises(TypeError, pow, bad(5), C.GF(2))
84 me.assertRaises(TypeError, pow, bad(5), C.GF(2), bad(7))
85 me.assertRaises(TypeError, pow, bad(5), bad(2), C.GF(7))
86 me.assertRaises(TypeError, pow, C.GF(5), bad(2), bad(7))
d472b9a1 87 if not (T.PY2 and T.DEBUGP):
ffad1322
MW
88 ## Python bug: see above.
89 me.assertRaises(TypeError, pow, C.GF(5), 2, bad(7))
90
91 ## `MP' and `GF'.
92 me.assertEqual(C.MP(5), 5)
93 me.assertEqual(5, C.MP(5))
7032ee7c
MW
94 me.assertNotEqual(C.GF(5), 5)
95 me.assertNotEqual(5, C.GF(5))
a70a5a80
MW
96 me.assertNotEqual(C.MP(5), C.GF(5))
97 me.assertNotEqual(C.GF(5), C.MP(5))
ffad1322
MW
98
99 me.assertEqual(C.MP(5) + 3, 8)
100 me.assertEqual(3 + C.MP(5), 8)
7032ee7c
MW
101 me.assertRaises(TypeError, T.add, C.GF(5), 3)
102 me.assertRaises(TypeError, T.add, 3, C.GF(5))
ffad1322
MW
103 me.assertRaises(TypeError, T.add, C.MP(5), C.GF(3))
104 me.assertRaises(TypeError, T.add, C.GF(3), C.MP(5))
7032ee7c 105 if T.PY3: me.assertRaises(TypeError, T.le, C.MP(4), C.GF(5))
ffad1322
MW
106
107 ## Field elements.
108 me.assertEqual(k(3) + 4, 7)
109 me.assertEqual(4 + k(3), 7)
110 me.assertEqual(k(3) + C.MP(4), 7)
111 me.assertEqual(C.MP(4) + k(3), 7)
112 me.assertEqual(k(3) + 4, 7)
113 me.assertEqual(C.GF(7) + kk(3), C.GF(4))
114 me.assertEqual(kk(3) + C.GF(7), C.GF(4))
115
4dc1425b 116 me.assertRaises(TypeError, T.add, k(3), 3.0)
7032ee7c 117 me.assertRaises(TypeError, T.add, k(3), "3")
ffad1322
MW
118 me.assertRaises(TypeError, T.add, k(3), kk(3))
119 me.assertRaises(TypeError, T.add, kk(3), k(3))
4dc1425b
MW
120 me.assertRaises(TypeError, T.add, k(3), C.GF(7))
121 me.assertRaises(TypeError, T.add, C.GF(7), k(3))
7032ee7c 122 me.assertRaises(TypeError, T.add, kk(3), 7)
4dc1425b 123 me.assertRaises(TypeError, T.add, kk(3), 7.0)
7032ee7c
MW
124 me.assertRaises(TypeError, T.add, kk(3), "7")
125 me.assertRaises(TypeError, T.add, 7, kk(3))
4dc1425b
MW
126 me.assertRaises(TypeError, T.add, kk(3), C.MP(7))
127 me.assertRaises(TypeError, T.add, C.MP(7), kk(3))
ffad1322
MW
128
129###----- That's all, folks --------------------------------------------------
130
131if __name__ == "__main__": U.main()