def gen_instance(n, alpha, q, m, t=1):
    D = DiscreteGaussianDistributionIntegerSampler(alpha * q / sqrt(2 * pi))
    lwe = LWE(n, q, D)
    Ac = [lwe() for _ in range(m)]
    A = matrix([a_ for a_, c_ in Ac])
    c = vector(ZZ, [c_ for a_, c_ in Ac])
    B = A.T.echelon_form()
    e = (c - A * lwe._LWE__s).change_ring(ZZ)

    def bm(x):
        return ZZ(x) if ZZ(x) < q // 2 else ZZ(x) - q

    e = vector(map(bm, e))

    N = B.change_ring(ZZ)
    S = matrix(ZZ, m - n, n).augment(q * identity_matrix(ZZ, m - n))
    L = (N.stack(S)).augment(matrix(ZZ, m, 1))
    L = L.stack(matrix(c).augment(matrix(ZZ, 1, 1, [t])))
    return L, e
Пример #2
0
    def __init__(self, n, delta=0.01, m=None):
        """
        Construct LWE instance parameterised by security parameter ``n`` where
        the modulus ``q`` and the ``stddev`` of the noise is chosen as in
        [LP2011]_.

        INPUT:

        - ``n`` - security parameter (integer > 0)
        - ``delta`` - error probability per symbol (default: 0.01)
        - ``m`` - number of allowed samples or ``None`` in which case ``m=2*n +
          128`` as in [LP2011]_ (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import LindnerPeikert
            sage: LindnerPeikert(n=20)
            LWE(20, 2053, Discrete Gaussian sampler over the Integers with sigma = 3.600954 and c = 0, 'noise', 168)
        """
        if m is None:
            m = 2 * n + 128
        # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40
        #         (c*exp((1-c**2)/2))**(2*n) == 2**-40
        #    log((c*exp((1-c**2)/2))**(2*n)) == -40*log(2)
        #       (2*n)*log(c*exp((1-c**2)/2)) == -40*log(2)
        #  2*n*(log(c)+log(exp((1-c**2)/2))) == -40*log(2)
        #            2*n*(log(c)+(1-c**2)/2) == -40*log(2)
        #              2*n*log(c)+n*(1-c**2) == -40*log(2)
        #  2*n*log(c)+n*(1-c**2) + 40*log(2) == 0
        c = SR.var('c')
        c = find_root(2 * n * log(c) + n * (1 - c**2) + 40 * log(2) == 0, 1,
                      10)
        # Upper bound on s**2/t
        s_t_bound = (sqrt(2) * pi / c / sqrt(2 * n * log(2 / delta))).n()
        # Interpretation of "choose q just large enough to allow for a Gaussian parameter s>=8" in [LP2011]_
        q = next_prime(floor(2**round(log(256 / s_t_bound, 2))))
        # Gaussian parameter as defined in [LP2011]_
        s = sqrt(s_t_bound * floor(q / 4))
        # Transform s into stddev
        stddev = s / sqrt(2 * pi.n())
        D = DiscreteGaussianDistributionIntegerSampler(stddev)
        LWE.__init__(self, n=n, q=q, D=D, secret_dist='noise', m=m)
Пример #3
0
    def encrypt_lwe(self, m, t, n, q,
                    s):  # m : message, t: The parameter of BV11
        if t > q:
            print "t must be smaller than the modulus q.\n Please choose a new t"
            return 0
        if t <= m:
            print "*the first argument m* must be larger than (the second argument) t "
            return 0

    # Every time that we call the function encrypt_lwe, a new "a" and "e" is generated.
    # So, for the same message we have a different ciphertext.
    # That is, the encryption is probabilistic (and not determenistic)

        S = samples(
            1, n, lwe
        )  #  this is a function implemented in sagemath which returns a vector \bf{a} for lwe

        a = vector(ZZ,
                   S[0][0])  # the vector a, we transform it to a vector over Z

        D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma)
        e = int(D())
        ### TODO : YOU must allow e to take negative values
        ### Q : It is the same if we consider emod q instead of e<0 ?

        if e < 0:
            e = q - e

    # e maybe positve or zero or negative
        dot = int(
            a.dot_product(s) %
            q)  #dot is integer, this will be the *aux* polynomial in decrypt()

        dot_q = int((dot + t * e + m) % q)
        # this is the encryption of m, where m\in (-t/2,t/2), m!=-t/2,t/2
        # dot_q always is in {0,1,...,q-1}

        # if representation_modulo_t(dot_q - dot,t) == representation_modulo_t(t*e + m,t):
        #     print "ok"
        c = [a, dot_q]
        return c, a  #,e  # note that e does not send to Bob, onle c is sent to Bob
Пример #4
0
    def __init__(self, n, secret_dist='uniform', m=None):
        """
        Construct LWE instance parameterised by security parameter ``n`` where
        the modulus ``q`` and the ``stddev`` of the noise are chosen as in
        [Reg09]_.

        INPUT:

        - ``n`` - security parameter (integer > 0)
        - ``secret_dist`` - distribution of the secret. See documentation of :class:`LWE`
          for details (default='uniform')
        - ``m`` - number of allowed samples or ``None`` if no such limit exists
          (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import Regev
            sage: Regev(n=20)
            LWE(20, 401, Discrete Gaussian sampler over the Integers with sigma = 1.915069 and c = 401, 'uniform', None)
        """
        q = ZZ(next_prime(n**2))
        s = RR(1 / (RR(n).sqrt() * log(n, 2)**2) * q)
        D = DiscreteGaussianDistributionIntegerSampler(s / sqrt(2 * pi.n()), q)
        LWE.__init__(self, n=n, q=q, D=D, secret_dist=secret_dist, m=m)
Пример #5
0
q=2^54
d=1024
t=83
T=100
l=floor(log(q,T).n())
P.<x>=PolynomialRing(ZZ)
f=x^d+1
R.<X>=P.quotient(f)
Zq=Zmod(q)
Zt=Zmod(t)
Pq.<x>=PolynomialRing(Zq)
Pt.<x>=PolynomialRing(Zt)
sigma = 1.0
delta=floor(q/t)
from sage.stats.distributions.discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler
D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma)

def sample_e():
    return R([D() for _ in range(d)])
def sample_2():
    return R([randint(0,1) for _ in range(d)])
def sample_r():
    return R([randint(0,q-1) for _ in range(d)])

def rq(a):
    A=a.list()
    for i in range(len(A)):
        A[i]=A[i]%q
    return R(A)
def rt(a):
    A=a.list()
Пример #6
0
def discrete_gaussian_y(PP, m, n, sigma):
    D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma)
    return Matrix(PP.R, m, n,
                  lambda i, j: PP.R(list(D() for _ in range(PP.d))))
Пример #7
0
def discrete_gaussian_vector_y(PP, n, sigma):
    D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma)
    return list(PP.R(list(D() for _ in range(PP.d))) for j in range(n))
Пример #8
0
def attack(m, q, r=4, sigma=3.0, subfield_only=False):
    K = CyclotomicField(m, 'z')
    z = K.gen()
    OK = K.ring_of_integers()
    G = K.galois_group()

    n = euler_phi(m)
    mprime = m / r
    nprime = euler_phi(mprime)
    Gprime = [tau for tau in G if tau(z**r) == z**r]

    R = PolynomialRing(IntegerRing(), 'a')
    a = R.gen()
    phim = a**n + 1
    D = DiscreteGaussianDistributionIntegerSampler(sigma)

    print "sampling f,g"
    while True:
        f = sum([D() * z**i for i in range(n)])
        fx = sum([f[i] * a**i for i in range(n)])

        res = inverse(fx, phim, q)
        if res[0]:
            f_inv = sum([res[1][i] * z**i for i in range(n)])
            print "f_inv * f = %s (mod %d)" % ((f * f_inv).mod(q), q)
            break

    g = sum([D() * z**i for i in range(n)])
    print "done sampling f, g"

    #h = [g*f^{-1)]_q
    h = (g * f_inv).mod(q)

    lognorm_f = log(f.vector().norm(), 2)
    lognorm_g = log(g.vector().norm(), 2)

    print "f*h - g = %s" % (f * h - g).mod(q)
    print "log q = ", log(q, 2).n(precision)
    print "log |f| = %s, log |g| = %s" % (lognorm_f.n(precision),
                                          lognorm_g.n(precision))
    print "log |(f,g)| = ", log(
        sqrt(f.vector().norm()**2 + g.vector().norm()**2), 2).n(precision)

    print "begin computing N(f), N(g), N(h), Tr(h), fbar"
    fprime = norm(f, Gprime)
    gprime = norm(g, Gprime)
    hprime = norm(h, Gprime).mod(q)
    htr = trace(h, Gprime)
    fbar = prod([tau(f) for tau in Gprime[1:]])
    print "end computing N(f), N(g), N(h), Tr(h), fbar"

    lognorm_fp = log(fprime.vector().norm(), 2)
    lognorm_gp = log(gprime.vector().norm(), 2)

    print "%d * log |f| - log |f'| = %s" % (r, r * lognorm_f.n(precision) -
                                            lognorm_fp.n(precision))
    print "log |(f', g')| = ", log(
        sqrt(fprime.vector().norm()**2 + gprime.vector().norm()**2),
        2).n(precision)
    print "log |N(f), Tr(g fbar)| = ", log(
        sqrt(fprime.vector().norm()**2 +
             trace(g * fbar, Gprime).vector().norm()**2), 2).n(precision)

    #(fprime, gprime) lies in the lattice \Lambda_hprime^q
    print "f'*h' - g' = %s " % (hprime * fprime - gprime).mod(q)
    print "N(f) Tr(h) - Tr(g fbar) = %s" % (htr * fprime -
                                            trace(g * fbar, Gprime)).mod(q)

    if not subfield_only:
        ntru_full = NTRU(h, K, q)
        full_sv = ntru_full.shortest_vector()

        print "log |v| = %s" % log(full_sv.norm(), 2).n(precision)

    ntru_subfield = NTRU_subfield(hprime, q, nprime, r)
    ntru_trace_subfield = NTRU_subfield(htr, q, nprime, r)

    print "begin computing Shortest Vector of subfield lattice"
    norm_sv = ntru_subfield.shortest_vector()
    tr_sv = ntru_trace_subfield.shortest_vector()
    print "end computing Shortest Vector of subfield lattice"

    norm_xp = sum(
        [coerce(Integer, norm_sv[i]) * z**(r * i) for i in range(nprime)])
    tr_xp = sum(
        [coerce(Integer, tr_sv[i]) * z**(r * i) for i in range(nprime)])

    print "Norm map: log |(x',y')| = ", log(norm_sv.norm(), 2).n(precision)
    print "Trace map: log |(x', y')| = ", log(tr_sv.norm(), 2).n(precision)
    #test if xprime belongs to <fprime>
    mat = []
    for i in range(nprime):
        coordinate = (fprime * z**(r * i)).vector().list()
        mat.append([coordinate[r * j] for j in range(nprime)])
    FL = IntegerLattice(mat)
    print norm_sv[:nprime] in FL
    print tr_sv[:nprime] in FL

    norm_x = norm_xp
    norm_y = mod_q(norm_x * h, q)

    tr_x = tr_xp
    tr_y = mod_q(tr_x * h, q)

    print "Norm map: log |(x,y)| = ", log(
        sqrt(norm_x.vector().norm()**2 + norm_y.vector().norm()**2),
        2).n(precision)
    print "Trace map: log |(x,y)| = ", log(
        sqrt(tr_x.vector().norm()**2 + tr_y.vector().norm()**2),
        2).n(precision)
Пример #9
0
 def initialize_lwe(self, n, q, sigma):
     D = DiscreteGaussianDistributionIntegerSampler(sigma)
     lwe = LWE(n, q, D=D)
     secret_key = lwe._LWE__s
     return lwe, secret_key  # exports the object lwe and the corresponding secret key