def time_search_loop(p): y = random_vector(F, n) g = random_matrix(F, p, n).rows() scalars = [[Fstar[randint(0, q - 2)] for i in range(p)] for s in range(100)] before = process_time() for m in scalars: e = y - sum(m[i] * g[i] for i in range(p)) return (process_time() - before) / 100.
def random_deformation(self, epsilon=None): """ Return a random deformation INPUT: - ``epsilon`` -- a number in the base ring. OUTPUT: A new filtered vector space where the generators of the subspaces are moved by ``epsilon`` times a random vector. EXAMPLES:: sage: gens = identity_matrix(3).rows() sage: F = FilteredVectorSpace(gens, {0:[0,1,2], 2:[0]}); F QQ^3 >= QQ^1 >= QQ^1 >= 0 sage: F.get_degree(2) Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [1 0 0] sage: G = F.random_deformation(1/50); G QQ^3 >= QQ^1 >= QQ^1 >= 0 sage: D = G.get_degree(2) sage: D.degree() 3 sage: v = D.basis_matrix()[0] sage: v[0] 1 sage: while F.random_deformation(1/50).get_degree(2).matrix() == matrix([1, 0, 0]): ....: pass """ from sage.modules.free_module_element import random_vector R = self.base_ring() if epsilon is None: epsilon = R.one() filtration = dict() for deg, filt in self._filt[1:]: generators = [ v + epsilon * random_vector(R, self.rank()) for v in filt.echelonized_basis() ] filtration[deg] = generators return FilteredVectorSpace(filtration, base_ring=R, check=True)
def random_deformation(self, epsilon=None): """ Return a random deformation INPUT: - ``epsilon`` -- a number in the base ring. OUTPUT: A new filtered vector space where the generators of the subspaces are moved by ``epsilon`` times a random vector. EXAMPLES:: sage: gens = identity_matrix(3).rows() sage: F = FilteredVectorSpace(gens, {0:[0,1,2], 2:[0]}); F QQ^3 >= QQ^1 >= QQ^1 >= 0 sage: F.get_degree(2) Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [1 0 0] sage: G = F.random_deformation(1/50); G QQ^3 >= QQ^1 >= QQ^1 >= 0 sage: G.get_degree(2) Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [ 1 -15/304 0] """ from sage.modules.free_module_element import random_vector R = self.base_ring() if epsilon is None: epsilon = R.one() filtration = dict() for deg, filt in self._filt[1:]: generators = [v + epsilon * random_vector(R, self.rank()) for v in filt.echelonized_basis()] filtration[deg] = generators return FilteredVectorSpace(filtration, base_ring=R, check=True)
def __init__(self, n, q, D, secret_dist='uniform', m=None): r""" Construct an LWE oracle in dimension ``n`` over a ring of order ``q`` with noise distribution ``D``. INPUT: - ``n`` - dimension (integer > 0) - ``q`` - modulus typically > n (integer > 0) - ``D`` - an error distribution such as an instance of :class:`DiscreteGaussianDistributionIntegerSampler` or :class:`UniformSampler` - ``secret_dist`` - distribution of the secret (default: 'uniform'); one of - "uniform" - secret follows the uniform distribution in `\Zmod{q}` - "noise" - secret follows the noise distribution - ``(lb,ub)`` - the secret is chosen uniformly from ``[lb,...,ub]`` including both endpoints - ``m`` - number of allowed samples or ``None`` if no such limit exists (default: ``None``) EXAMPLES: First, we construct a noise distribution with standard deviation 3.0:: sage: from sage.stats.distributions.discrete_gaussian_integer import DiscreteGaussianDistributionIntegerSampler sage: D = DiscreteGaussianDistributionIntegerSampler(3.0) Next, we construct our oracle:: sage: from sage.crypto.lwe import LWE sage: lwe = LWE(n=20, q=next_prime(400), D=D); lwe LWE(20, 401, Discrete Gaussian sampler over the Integers with sigma = 3.000000 and c = 0, 'uniform', None) and sample 1000 samples:: sage: L = [lwe() for _ in range(1000)] To test the oracle, we use the internal secret to evaluate the samples in the secret:: sage: S = [ZZ(a.dot_product(lwe._LWE__s) - c) for (a,c) in L] However, while Sage represents finite field elements between 0 and q-1 we rely on a balanced representation of those elements here. Hence, we fix the representation and recover the correct standard deviation of the noise:: sage: sqrt(variance([e if e <= 200 else e-401 for e in S]).n()) 3.0... If ``m`` is not ``None`` the number of available samples is restricted:: sage: from sage.crypto.lwe import LWE sage: lwe = LWE(n=20, q=next_prime(400), D=D, m=30) sage: _ = [lwe() for _ in range(30)] sage: lwe() # 31 Traceback (most recent call last): ... IndexError: Number of available samples exhausted. """ self.n = ZZ(n) self.m = m self.__i = 0 self.K = IntegerModRing(q) self.FM = FreeModule(self.K, n) self.D = D self.secret_dist = secret_dist if secret_dist == 'uniform': self.__s = random_vector(self.K, self.n) elif secret_dist == 'noise': self.__s = vector(self.K, self.n, [self.D() for _ in range(n)]) else: try: lb, ub = map(ZZ, secret_dist) self.__s = vector(self.K, self.n, [randint(lb,ub) for _ in range(n)]) except (IndexError, TypeError): raise TypeError("Parameter secret_dist=%s not understood."%(secret_dist))
def __init__(self, n, q, D, secret_dist='uniform', m=None): """ Construct an LWE oracle in dimension ``n`` over a ring of order ``q`` with noise distribution ``D``. INPUT: - ``n`` - dimension (integer > 0) - ``q`` - modulus typically > n (integer > 0) - ``D`` - an error distribution such as an instance of :class:`DiscreteGaussianSamplerRejection` or :class:`UniformSampler` - ``secret_dist`` - distribution of the secret (default: 'uniform'); one of - "uniform" - secret follows the uniform distribution in `\Zmod{q}` - "noise" - secret follows the noise distribution - ``(lb,ub)`` - the secret is chosen uniformly from ``[lb,...,ub]`` including both endpoints - ``m`` - number of allowed samples or ``None`` if no such limit exists (default: ``None``) EXAMPLE: First, we construct a noise distribution with standard deviation 3.0:: sage: from sage.crypto.lwe import DiscreteGaussianSampler sage: D = DiscreteGaussianSampler(3.0) Next, we construct our oracle:: sage: from sage.crypto.lwe import LWE sage: lwe = LWE(n=20, q=next_prime(400), D=D); lwe LWE(20, 401, DiscreteGaussianSamplerRejection(3.000000, 53, 4), 'uniform', None) and sample 1000 samples:: sage: L = [lwe() for _ in range(1000)] To test the oracle, we use the internal secret to evaluate the samples in the secret:: sage: S = [ZZ(a.dot_product(lwe._LWE__s) - c) for (a,c) in L] However, while Sage represents finite field elements between 0 and q-1 we rely on a balanced representation of those elements here. Hence, we fix the representation and recover the correct standard deviation of the noise:: sage: sqrt(variance([e if e <= 200 else e-401 for e in S]).n()) 3.0... If ``m`` is not ``None`` the number of available samples is restricted:: sage: from sage.crypto.lwe import LWE sage: lwe = LWE(n=20, q=next_prime(400), D=D, m=30) sage: _ = [lwe() for _ in range(30)] sage: lwe() # 31 Traceback (most recent call last): ... IndexError: Number of available samples exhausted. """ self.n = ZZ(n) self.m = m self.__i = 0 self.K = IntegerModRing(q) self.FM = FreeModule(self.K, n) self.D = D self.secret_dist = secret_dist if secret_dist == 'uniform': self.__s = random_vector(self.K, self.n) elif secret_dist == 'noise': self.__s = vector(self.K, self.n, [self.D() for _ in range(n)]) else: try: lb, ub = map(ZZ, secret_dist) self.__s = vector(self.K, self.n, [randint(lb, ub) for _ in range(n)]) except (IndexError, TypeError): raise TypeError("Parameter secret_dist=%s not understood." % (secret_dist))