def _element_constructor_(self, x): r""" Create an element in this group from ``x``. INPUT: - ``x`` -- a rational number TESTS:: sage: DiscreteValueGroup(0)(0) 0 sage: DiscreteValueGroup(0)(1) Traceback (most recent call last): ... ValueError: `1` is not in DiscreteValueGroup(0). sage: DiscreteValueGroup(1)(1) 1 sage: DiscreteValueGroup(1)(1/2) Traceback (most recent call last): ... ValueError: `1/2` is not in DiscreteValueGroup(1). """ from sage.misc.functional import coerce x = coerce(QQ, x) if x == 0 or (self._generator != 0 and x/self._generator in ZZ): return x raise ValueError("`{0}` is not in {1}.".format(x,self))
def _element_constructor_(self, x): r""" Create an element in this group from ``x``. INPUT: - ``x`` -- a rational number TESTS:: sage: DiscreteValueGroup(0)(0) 0 sage: DiscreteValueGroup(0)(1) Traceback (most recent call last): ... ValueError: `1` is not in DiscreteValueGroup(0). sage: DiscreteValueGroup(1)(1) 1 sage: DiscreteValueGroup(1)(1/2) Traceback (most recent call last): ... ValueError: `1/2` is not in DiscreteValueGroup(1). """ from sage.misc.functional import coerce x = coerce(QQ, x) if x == 0 or (self._generator != 0 and x / self._generator in ZZ): return x raise ValueError("`{0}` is not in {1}.".format(x, self))
def mod_q(elem, q): def half(a): if a < q / 2: return a else: return a - q z = elem.parent().gen() n = len(elem.list()) return sum([ half(Mod(coerce(Integer, elem[i]), q).lift()) * z**i for i in range(n) ])
def __classcall__(cls, generator, category=category): r""" Normalizes ``generator`` to a positive rational so that this is a unique parent. TESTS:: sage: DiscreteValueGroup(1) is DiscreteValueGroup(-1) True """ from sage.misc.functional import coerce generator = coerce(QQ, generator) generator = generator.abs() return super(DiscreteValueGroup, cls).__classcall__(cls, generator, category)
def _mul_(self, other, switch_sides=False): r""" Return the group generated by ``other`` times the generator of this group. INPUT: - ``other`` -- a rational number EXAMPLES:: sage: D = DiscreteValueGroup(1/2) sage: 1/2 * D DiscreteValueGroup(1/4) sage: D * (1/2) DiscreteValueGroup(1/4) sage: D * 0 DiscreteValueGroup(0) """ from sage.misc.functional import coerce other = coerce(QQ, other) return DiscreteValueGroup(self._generator*other, category=self.category())
def _mul_(self, other, switch_sides=False): r""" Return the group generated by ``other`` times the generator of this group. INPUT: - ``other`` -- a rational number EXAMPLES:: sage: D = DiscreteValueGroup(1/2) sage: 1/2 * D DiscreteValueGroup(1/4) sage: D * (1/2) DiscreteValueGroup(1/4) sage: D * 0 DiscreteValueGroup(0) """ from sage.misc.functional import coerce other = coerce(QQ, other) return DiscreteValueGroup(self._generator * other, category=self.category())
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)