chiark / gitweb /
t/: Add a test suite.
[catacomb-python] / t / t-group.py
diff --git a/t/t-group.py b/t/t-group.py
new file mode 100644 (file)
index 0000000..203ca16
--- /dev/null
@@ -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()