X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb-python/blobdiff_plain/e91150b266bbd768905258166601fdf333d3d987..553d59fec08fd9102b21fd0dc83ba708862a6090:/t/t-group.py diff --git a/t/t-group.py b/t/t-group.py new file mode 100644 index 0000000..203ca16 --- /dev/null +++ b/t/t-group.py @@ -0,0 +1,255 @@ +### -*-python-*- +### +### Testing cyclic-group functionality +### +### (c) 2019 Straylight/Edgeware +### + +###----- Licensing notice --------------------------------------------------- +### +### This file is part of the Python interface to Catacomb. +### +### Catacomb/Python is free software: you can redistribute it and/or +### modify it under the terms of the GNU General Public License as +### published by the Free Software Foundation; either version 2 of the +### License, or (at your option) any later version. +### +### Catacomb/Python is distributed in the hope that it will be useful, but +### WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +### General Public License for more details. +### +### You should have received a copy of the GNU General Public License +### along with Catacomb/Python. If not, write to the Free Software +### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +### USA. + +###-------------------------------------------------------------------------- +### Imported modules. + +import catacomb as C +import unittest as U +import testutils as T + +###-------------------------------------------------------------------------- +class TestGroups (T.GenericTestMixin): + """Test cyclic groups.""" + + def _test_group(me, G): + + ## Some initial values. + id = G.i + g = G.g + x = g**2014319630 + y = g**721326623 + + ## Check that they're all different. + v = [id, g, x, y] + for i in T.range(len(v)): + for j in T.range(len(v)): + if i == j: me.assertEqual(v[i], v[j]) + else: me.assertNotEqual(v[i], v[j]) + + ## Basic arithmetic. Knowing the answers is too hard. For now, just + ## check that the field laws hold. + t = x*y; me.assertEqual(t/x, y); me.assertEqual(t/y, x) + me.assertEqual(x*x.inv(), id) + me.assertEqual(x.sqr(), x*x) + me.assertEqual(x/x, id) + + ## Exponentiation. + me.assertEqual(x**G.r, id) + me.assertEqual(G.mexp((x, 5), (y, 7)), g**15120884511) + + ## Comparisons. We've already done equality and inequality, and nothing + ## else should work. + me.assertRaises(TypeError, T.lt, x, y) + me.assertRaises(TypeError, T.le, x, y) + me.assertRaises(TypeError, T.ge, x, y) + me.assertRaises(TypeError, T.gt, x, y) + + if isinstance(G, C.ECGroup): + + ## Properties. + me.assertEqual(G.noctets, 2*G.info.curve.field.noctets + 1) + me.assertEqual(G.nbits, 2*G.info.curve.field.nbits) + + ## Conversion to integer. + i = y.toint(); me.assertEqual(type(i), C.MP) + t = G(i); me.assertTrue(t == y or t == y.inv()) + + ## Conversion to elliptic curve. + Q = y.toec() + me.assertTrue(isinstance(Q, C.ECPtCurve)) + me.assertEqual(G(Q), y) + + ## Encoding. + t = y.tobuf() + me.assertEqual(t, Q.tobuf()) + me.assertEqual(G.frombuf(t)[0], y) + me.assertEqual(id.tobuf(), C.ByteString.zero(2)) + t = y.toraw() + me.assertEqual(t, Q.ec2osp()) + me.assertEqual(G.fromraw(t)[0], y) + me.assertEqual(id.toraw(), C.ByteString.zero(1)) + + else: + + ## Properties. + me.assertEqual(G.noctets, G.info.p.noctets) + if isinstance(G.info, C.BinDHInfo): + me.assertEqual(G.nbits, G.info.p.degree) + else: + me.assertEqual(G.nbits, G.info.p.nbits) + + ## Conversion to integer. + i = y.toint(); me.assertEqual(type(i), C.MP) + me.assertTrue(G(i) == y) + + ## Conversion to elliptic curve. + me.assertRaises(TypeError, G.toec, x) + + ## Encoding. + t = y.tobuf() + me.assertEqual(t, C.ByteString(C.WriteBuffer().putmp(i))) + me.assertEqual(G.frombuf(t)[0], y) + me.assertEqual(id.tobuf(), C.bytes("000101")) + t = y.toraw() + me.assertEqual(t, i.storeb(G.noctets)) + me.assertEqual(G.fromraw(t)[0], y) + me.assertEqual(id.toraw(), + C.ByteString(C.WriteBuffer().zero(G.noctets - 1).putu8(1))) + + ## String conversion. + ystr = str(y) + me.assertEqual(G.fromstring(ystr), (y, "")) + + ## Checking operations. + me.assertRaises(ValueError, id.check) + x.check() + y.check() + G.checkgroup() + + def test_dhinfo(me): + dhinfo = C.DHInfo.parse("127, 7, 2") + me.assertEqual(dhinfo.p, 127) + me.assertEqual(dhinfo.r, 7) + me.assertEqual(dhinfo.g, 2) + dhinfo.group().checkgroup() + + def test_bindhinfo(me): + bindhinfo = C.BinDHInfo.parse("0x805, 89, 0x22") + me.assertEqual(bindhinfo.p, C.GF(0x805)) + me.assertEqual(bindhinfo.r, 89) + me.assertEqual(bindhinfo.g, C.GF(0x22)) + bindhinfo.group().checkgroup() + + def test_parse(me): + + G = C.Group.parse("prime 127, 7, 2") + me.assertEqual(G.info.p, 127) + me.assertEqual(G.r, 7) + me.assertEqual(G.info.g, 2) + G.checkgroup() + + G = C.Group.parse("bin 0x805, 89, 0x22") + me.assertEqual(G.info.p, C.GF(0x805)) + me.assertEqual(G.r, 89) + me.assertEqual(G.info.g, C.GF(0x22)) + G.checkgroup() + + def test_gen_schnorr(me): + ev = T.EventRecorder() + dhinfo = C.DHInfo.generate(512, 64, event = ev, + rng = T.detrand("schnorr")) + me.assertEqual(dhinfo.p.nbits, 512) + me.assertEqual(dhinfo.r.nbits, 64) + me.assertTrue(dhinfo.p.primep()) + me.assertTrue(dhinfo.r.primep()) + me.assertEqual(dhinfo.p%dhinfo.r, 1) + me._test_group(dhinfo.group()) + me.assertEqual(ev.events, "[q:F4/P26/D][p:F5/P5/D][g:D]") + + def test_gen_limlee(me): + ev = T.EventRecorder() + dhinfo, ff = C.DHInfo.genlimlee(512, 64, event = ev, ievent = ev, + rng = T.detrand("limlee")) + me.assertEqual(dhinfo.p.nbits, 512) + me.assertEqual(dhinfo.r.nbits, 64) + me.assertTrue(dhinfo.p.primep()) + me.assertTrue(dhinfo.r.primep()) + for f in ff: + me.assertTrue(f.primep()) + me.assertTrue(f.nbits >= 64) + me.assertEqual(C.MPMul().factor(2).factor(ff).done() + 1, dhinfo.p) + me._test_group(dhinfo.group()) + me.assertEqual(ev.events, + "[p:" + "[p_0:F8/P26/D]" + "[p_1:P26/D]" + "[p_2:F4/P26/D]" + "[p_3:P26/D]" + "[p_4:F1/P26/D]" + "[p_5:F1/P26/D]" + "[p_6:P26/D]" + "[p*_7:P26/D]" + "[p_8:F1/P26/D]" + "[p_9:F1/P26/D]" + "[p*_10:P26/D]" + "[p_11:F6/P26/D]" + "[p_12:P26/D]" + "[p_13:P26/D]" + "[p_14:F4/P26/D]" + "[p_15:F1/P26/D]" + "[p_16:F1/P26/D]" + "[p_17:F1/P26/D]" + "[p_18:F6/P26/D]" + "[p_19:F1/P26/D]" + "[p_20:F3/P26/D]" + "[p_21:P26/D]" + "[p_22:F2/P26/D]" + "[p_23:F4/P26/D]" + "[p_24:F7/P26/D]" + "[p_25:F2/P26/D]" + "[p_26:F9/P26/D]" + "[p_27:F4/P26/D]" + "[p*_28:F11/P26/D]" + "[p*_29:F4/P26/D]" + "[p*_30:F1/P26/D]" + "[p*_31:F6/P26/D]" + "[p*_32:F4/P26/D]" + "[p*_33:F3/P26/D]" + "[p*_34:P26/D]" + "[p*_35:F3/P26/D]" + "[p*_36:F1/P26/D]" + "[p*_37:F1/P26/D]" + "[p*_38:F4/P26/D]" + "[p*_39:P26/D]" + "[p*_40:P26/D]" + "[p*_41:F2/P26/D]" + "[p*_42:F1/P26/D]" + "F22/P5/D]" + "[g:D]") + + def test_gen_kcdsa(me): + ev = T.EventRecorder() + dhinfo, h = C.DHInfo.genkcdsa(512, 64, event = ev, + rng = T.detrand("kcdsa")) + me.assertEqual(dhinfo.p.nbits, 512) + me.assertEqual(dhinfo.r.nbits, 64) + me.assertTrue(dhinfo.p.primep()) + me.assertTrue(dhinfo.r.primep()) + me.assertTrue(h.primep()) + me.assertEqual(2*h*dhinfo.r + 1, dhinfo.p) + me._test_group(dhinfo.group()) + me.assertEqual(ev.events, "[v:F23/P6/D][p:F86/P26/D][g:D]") + +TestGroups.generate_testcases((name, map[name].group()) for name, map in + [("nist-p256", C.eccurves), + ("nist-b283", C.eccurves), + ("catacomb-ll-128-512", C.primegroups), + ("p1363-64", C.bingroups)]) + +###----- That's all, folks -------------------------------------------------- + +if __name__ == "__main__": U.main()