Merge branch '1.2.x' into 1.3.x
[catacomb-python] / t / t-rand.py
diff --git a/t/t-rand.py b/t/t-rand.py
new file mode 100644 (file)
index 0000000..d8d7b00
--- /dev/null
@@ -0,0 +1,165 @@
+### -*-python-*-
+###
+### Testing random-generator 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 TestRandomGenerator (U.TestCase):
+
+  def check_rand(me, rng):
+
+    for i in T.range(50):
+      x = rng.byte()
+      me.assertEqual(type(x), int)
+      me.assertTrue(0 <= x < 256)
+
+    x = rng.word()
+    me.assertTrue(0 <= x <= 0xffffffff)
+
+    for i in T.range(50):
+      x = rng.range(10)
+      me.assertEqual(type(x), int)
+      me.assertTrue(0 <= x < 10)
+    x = rng.range(T.MAXFIXNUM + 1)
+    me.assertEqual(type(x), C.MP)
+
+    for i in T.range(50):
+      x = rng.mp(123, 7)
+      me.assertEqual(type(x), C.MP)
+      me.assertEqual(x.nbits, 123)
+      me.assertEqual(x&7, 7)
+    me.assertRaises((OverflowError, ValueError), rng.mp, 128, -1)
+    me.assertRaises((OverflowError, ValueError), rng.mp, 128, C.MPW_MAX + 1)
+
+    x = rng.block(17)
+    me.assertEqual(type(x), C.ByteString)
+    me.assertEqual(len(x), 17)
+
+  def test_lcrand(me):
+    rng = C.LCRand(0)
+    me.assertFalse(rng.cryptop)
+    w0 = rng.word()
+    rng.seedint(0)
+    me.assertEqual(rng.word(), w0)
+
+  def test_firand(me):
+    rng = C.FibRand(0)
+    me.assertFalse(rng.cryptop)
+    w0 = rng.word()
+    rng.seedint(0)
+    me.assertEqual(rng.word(), w0)
+
+  def test_truerand(me):
+    rng = C.TrueRand()
+    me.assertTrue(rng.cryptop)
+    me.check_rand(rng)
+    rng.key(T.span(23))
+    rng.seed(256)
+    me.assertRaises(ValueError, rng.seed, C.RAND_IBITS + 1)
+    rng.seedint(-314)
+    rng.seedword(0x12345678)
+    rng.seedrand(T.detrand("seed-truerand"))
+    rng.seedblock(T.span(123))
+    rng.add(T.span(123), 978)
+    rng.gate()
+    rng.stretch()
+    rng.timer()
+    me.check_rand(rng)
+
+  def test_cryptorand(me):
+    for r, kw in [("rijndael-counter", {}),
+                  ("rc4", {}),
+                  ("xchacha20", { "nonce": T.span(24) }),
+                  ("seal", { "i": 12345678 }),
+                  ("shake128", { "func": T.bin("TEST"),
+                                 "perso": T.bin("Catacomb/Python test") }),
+                  ("kmac256", { "perso": T.bin("Catacomb/Python test") })]:
+      rcls = C.gccrands[r]
+      rng = rcls(T.span(rcls.keysz.default), **kw)
+      me.assertTrue(rng.cryptop)
+
+  def test_sslrand(me):
+    rng = C.SSLRand(T.span(16), T.span(32), C.md5, C.sha)
+    me.check_rand(rng)
+  def test_tlsdx(me):
+    rng = C.TLSDataExpansion(T.span(16), T.span(32), C.sha256_hmac)
+    me.check_rand(rng)
+  def test_tlsprf(me):
+    rng = C.TLSPRF(T.span(16), T.span(32), C.md5_hmac, C.sha_hmac)
+    me.check_rand(rng)
+
+  def test_dsarand(me):
+    seed = T.span(16)
+    n = C.MP.loadb(seed)
+    rng = C.DSARand(seed)
+    me.check_rand(rng)
+    me.assertEqual(rng.seed, (n + 153 + 3).storeb(16))
+
+  def test_bbs(me):
+    ev = T.EventRecorder()
+    drng = T.detrand("bbs")
+    rngpriv = C.BBSPriv.generate(1536, event = ev, rng = drng)
+    me.assertEqual(rngpriv.n.nbits, 1536)
+    me.assertEqual(rngpriv.p&3, 3)
+    me.assertEqual(rngpriv.q&3, 3)
+    me.assertTrue(rngpriv.p.primep())
+    me.assertTrue(rngpriv.q.primep())
+    me.assertEqual(rngpriv.n, rngpriv.p*rngpriv.q)
+    me.assertEqual(ev.events,
+                   "[p [s]:F10/P7/D]"
+                   "[p [t]:F2/P7/D]"
+                   "[p [r]:F7/P7/D]"
+                   "[p:F6/P3/D]"
+                   "[q [s]:P7/D]"
+                   "[q [t]:F33/P7/D]"
+                   "[q [r]:F33/P7/D]"
+                   "[q:F55/P3/D]")
+
+    x0 = drng.range(rngpriv.n)
+    rngpriv.seedmp(x0)
+    rng = C.BlumBlumShub(rngpriv.n, x0)
+    me.check_rand(rngpriv)
+    me.check_rand(rng)
+    me.assertEqual(rngpriv.x, rng.x)
+
+    msg = T.span(123)
+    rng.wrap()
+    ct = rng.mask(msg)
+    rng.wrap()
+
+    rngpriv.x = rng.x
+    nsteps = (123*8 + 7)//(rng.stepsz)
+    rngpriv.rew(nsteps + 1)
+    me.assertEqual(rngpriv.mask(ct), msg)
+
+###----- That's all, folks --------------------------------------------------
+
+if __name__ == "__main__": U.main()