def key_gen(cls, seed=None): """Generate a new public/secret key pair :param cls: Kyber class, inherit and change constants to change defaults :param seed: seed used for random sampling if provided .. note :: Resembles Algorithm 1 of the Kyber paper. """ n, q, eta, k, D = cls.n, cls.q, cls.eta, cls.k, cls.D if seed is not None: set_random_seed(seed) R, x = PolynomialRing(ZZ, "x").objgen() Rq = PolynomialRing(GF(q), "x") f = R(cls.f) A = matrix(Rq, k, k, [Rq.random_element(degree=n - 1) for _ in range(k * k)]) s = vector(R, k, [R([(D(eta)) for _ in range(n)]) for _ in range(k)]) e = vector(R, k, [R([(D(eta)) for _ in range(n)]) for _ in range(k)]) t = (A * s + e) % f # NOTE ignoring compression return (A, t), s
def test_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, ref_mul=lambda f, g: f._mul_generic(g), base_ring_random_elt_args=[], numtests=10, verbose=False): """ Test univariate karatsuba multiplication against other multiplication algorithms. EXAMPLES: First check that random tests are reproducible:: sage: import sage.rings.tests sage: sage.rings.tests.test_karatsuba_multiplication(ZZ, 6, 5, verbose=True, seed=42) test_karatsuba_multiplication: ring=Univariate Polynomial Ring in x over Integer Ring, threshold=2 (2*x^6 - x^5 - x^4 - 3*x^3 + 4*x^2 + 4*x + 1)*(4*x^4 + x^3 - 2*x^2 - 20*x + 3) (16*x^2)*(x^2 - 41*x + 1) (-x + 1)*(x^2 + 2*x + 8) (-x^6 - x^4 - 8*x^3 - x^2 - 4*x + 3)*(-x^3 - x^2) (2*x^2 + x + 1)*(x^4 - x^3 + 3*x^2 - x) (-x^3 + x^2 + x + 1)*(4*x^2 + 76*x - 1) (6*x + 1)*(-5*x - 1) (-x^3 + 4*x^2 + x)*(-x^5 + 3*x^4 - 2*x + 5) (-x^5 + 4*x^4 + x^3 + 21*x^2 + x)*(14*x^3) (2*x + 1)*(12*x^3 - 12) Test Karatsuba multiplication of polynomials of small degree over some common rings:: sage: for C in [QQ, ZZ[I], ZZ[I, sqrt(2)], GF(49, 'a'), MatrixSpace(GF(17), 3)]: ....: sage.rings.tests.test_karatsuba_multiplication(C, 10, 10) Zero-tests over ``QQbar`` are currently very slow, so we test only very small examples:: sage.rings.tests.test_karatsuba_multiplication(QQbar, 3, 3, numtests=2) Larger degrees (over ``ZZ``, using FLINT):: sage: sage.rings.tests.test_karatsuba_multiplication(ZZ, 1000, 1000, ref_mul=lambda f,g: f*g, base_ring_random_elt_args=[1000]) Some more aggressive tests:: sage: for C in [QQ, ZZ[I], ZZ[I, sqrt(2)], GF(49, 'a'), MatrixSpace(GF(17), 3)]: ....: sage.rings.tests.test_karatsuba_multiplication(C, 10, 10) # long time sage: sage.rings.tests.test_karatsuba_multiplication(ZZ, 10000, 10000, ref_mul=lambda f,g: f*g, base_ring_random_elt_args=[100000]) """ from sage.all import randint, PolynomialRing threshold = randint(0, min(maxdeg1,maxdeg2)) R = PolynomialRing(base_ring, 'x') if verbose: print "test_karatsuba_multiplication: ring={}, threshold={}".format(R, threshold) for i in range(numtests): f = R.random_element(randint(0, maxdeg1), *base_ring_random_elt_args) g = R.random_element(randint(0, maxdeg2), *base_ring_random_elt_args) if verbose: print " ({})*({})".format(f, g) if ref_mul(f, g) - f._mul_karatsuba(g, threshold) != 0: raise ValueError("Multiplication failed") return
def test_nose(cls=Kyber, l=None, t=128, seed=0xdeadbeef, proof=False, worst_case=True): """ Test correctness of the Sneeze/Snort gadget for normal form MLWE parameters. TESTS:: sage: test_nose(MiniKyber) sage: test_nose(MiniPseudoLima, seed=1, worst_case=False) sage: test_nose(MiniKyber, l = Nose.prec(MiniKyber)-1) Traceback (most recent call last): ... AssertionError sage: test_nose(MiniPseudoLima, l = Nose.prec(MiniPseudoLima)-1, seed=1, worst_case=False) Traceback (most recent call last): ... AssertionError .. note :: An ``AssertionError`` if final key does not match original. """ if seed is not None: set_random_seed(seed) R, x = PolynomialRing(ZZ, "x").objgen() D = BinomialDistribution # TODO ce n, q, eta, k, f = cls.n, cls.q, cls.eta, cls.k, R(cls.f) Rq = PolynomialRing(GF(q), "x") if not l: l = Nose.prec(cls) l = ceil(l) for _ in range(t): if worst_case: a = vector(Rq, k, [[q // 2 + randint(0, 1) for _ in range(n)] for i in range(k)]) # noqa s = vector(R, k, [[((-1)**randint(0, 1)) * eta for _ in range(n)] for i in range(k)]) e = R([((-1)**randint(0, 1)) * eta for _ in range(n)]) else: a = vector(Rq, k, [Rq.random_element(degree=n - 1) for i in range(k)]) s = vector(R, k, [[D(eta) for _ in range(n)] for i in range(k)]) e = R([D(eta) for _ in range(n)]) b = (a * s + e) % f bb = Rq(Nose.muladd(cls, a, s, e, l=l)) assert (b == bb)
digits = 150 prec = ceil(log(10) / log(2) * digits) SetPariPrec(digits + 50) PariIntNumInit(3) power = 6 threshold = 2**(prec * .5) ncurves = 8 #i = 8 needs more precision for i in range(ncurves): print "i = %s of %s" % (i + 1, ncurves) smoothQ = False ZT = PolynomialRing(ZZ, "T") T = ZT.gen() while not smoothQ: g = ZT.random_element(degree=6) # ZT([-4, 12, 0, -20, 0, 8, 1])# dg = g.derivative() smoothQ = gcd(g, dg) == 1 print "C: y^2 = %s" % g verbose = False prec = ceil(log(10) / log(2) * digits) iaj = InvertAJglobal(g, prec, verbose) CCap = iaj.C Pic = iaj.Pic y0 = 0 while y0 == 0: x0 = 1 #ZZ.random_element() y0 = sqrt(g(x0)) print "\tPi = (%s, -/+%s)" % (x0, y0) P0, P1 = vector(CCap, (x0, y0)), vector(CCap, (x0, -y0))