示例#1
0
文件: lwe.py 项目: bopopescu/sage-5
    def __init__(self, N, delta=0.01, m=None):
        """
        Construct a Ring-LWE oracle in dimension ``n=phi(N)`` where
        the modulus ``q`` and the ``stddev`` of the noise is chosen as in
        [LP11]_.

        INPUT:

        - ``N`` - index of cyclotomic polynomial (integer > 0, must be power of 2)
        - ``delta`` - error probability per symbol (default: 0.01)
        - ``m`` - number of allowed samples or ``None`` in which case ``3*n`` is
          used (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import RingLindnerPeikert
            sage: RingLindnerPeikert(N=16)
            RingLWE(16, 1031, DiscreteGaussianPolynomialSamplerRejection(8, 2.803372, 53, 4), x^8 + 1, 'noise', 24)
        """
        n = euler_phi(N)
        if m is None:
            m = 3 * n
        # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40
        #  i.e c>=1 such that 2*n*log(c)+n*(1-c**2) + 40*log(2) == 0
        c = 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 [LP11]_
        q = next_prime(floor(2**round(log(256 / s_t_bound, 2))))
        # Gaussian parameter as defined in [LP11]_
        s = sqrt(s_t_bound * floor(q / 4))
        # Transform s into stddev
        stddev = s / sqrt(2 * pi.n())
        D = DiscreteGaussianPolynomialSampler(n, stddev)
        RingLWE.__init__(self,
                         N=N,
                         q=q,
                         D=D,
                         poly=None,
                         secret_dist='noise',
                         m=m)
示例#2
0
文件: lwe.py 项目: bopopescu/sage-5
    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
        [LP11]_.

        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 [LP11]_ (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import LindnerPeikert
            sage: LindnerPeikert(n=20)
            LWE(20, 2053, DiscreteGaussianSamplerRejection(3.600954, 53, 4), '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 = 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 [LP11]_
        q = next_prime(floor(2**round(log(256 / s_t_bound, 2))))
        # Gaussian parameter as defined in [LP11]_
        s = sqrt(s_t_bound * floor(q / 4))
        # Transform s into stddev
        stddev = s / sqrt(2 * pi.n())
        D = DiscreteGaussianSampler(stddev)
        LWE.__init__(self, n=n, q=q, D=D, secret_dist='noise', m=m)
示例#3
0
文件: lwe.py 项目: sagemath/sage
    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)
示例#4
0
def random_polygon_2d(num_vertices, **kwargs):
    r"""Generate a random polygon (2d) obtained by uniform sampling over the unit circle.

    INPUT:

    * ``num_vertices`` - the number of vertices of the generated polyhedron.

    * ``base_ring`` - (default: ``QQ``). The ring passed to the constructor of Polyhedron. 
    alid options are ``QQ`` and ``RDF``.

    * ``scale`` - (default: 1). The scale factor; each vertex is chosen randomly from the unit circle, 
    and then multiplied by scale.

    OUTPUT:

    A random polygon (object of type Polyhedron), whose vertices belong to a circle
    of radius ``scale``.

    NOTES:

    - If ``RDF`` is chosen as ``base_ring``, sometimes there are exceptions related 
    to numerical errors, and show up as ``'FrozenSet'`` exceptions. This occurs 
    particularly frequently for a large number of vertices (more than 30).
    """
    from sage.functions.log import exp
    from sage.symbolic.constants import pi
    from sage.symbolic.all import I

    base_ring = kwargs['base_ring'] if 'base_ring' in kwargs else QQ

    scale = kwargs['scale'] if 'scale' in kwargs else 1

    angles = [
        random.uniform(0, 2 * pi.n(digits=5)) for i in range(num_vertices)
    ]
    vert = [[
        scale * exp(I * angles[i]).real(), scale * exp(I * angles[i]).imag()
    ] for i in range(num_vertices)]

    return Polyhedron(vertices=vert, base_ring=base_ring)
示例#5
0
    def __init__(self, n, secret_dist='uniform', m=None):
        """
        Construct LWE instance parameterised by security paramter ``n`` where
        the modulus ``q`` and the ``stddev`` of the noise are chosen as in
        [Reg09]_.

        INPUT:

        - ``n`` - security paramter (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: Regev(n=20)
            LWE(20, 401, DiscreteGaussianSamplerRejection(1.915069, 401, 4), 'uniform', None)
        """
        q = ZZ(next_prime(n**2))
        s = RR(1 / (RR(n).sqrt() * log(n, 2)**2) * q)
        D = DiscreteGaussianSampler(s / sqrt(2 * pi.n()), q)
        LWE.__init__(self, n=n, q=q, D=D, secret_dist=secret_dist, m=m)
示例#6
0
文件: lwe.py 项目: sagemath/sage
    def __init__(self, N, delta=0.01, m=None):
        """
        Construct a Ring-LWE oracle in dimension ``n=phi(N)`` where
        the modulus ``q`` and the ``stddev`` of the noise is chosen as in
        [LP2011]_.

        INPUT:

        - ``N`` - index of cyclotomic polynomial (integer > 0, must be power of 2)
        - ``delta`` - error probability per symbol (default: 0.01)
        - ``m`` - number of allowed samples or ``None`` in which case ``3*n`` is
          used (default: ``None``)

        EXAMPLES::

            sage: from sage.crypto.lwe import RingLindnerPeikert
            sage: RingLindnerPeikert(N=16)
            RingLWE(16, 1031, Discrete Gaussian sampler for polynomials of degree < 8 with σ=2.803372 in each component, x^8 + 1, 'noise', 24)
        """
        n = euler_phi(N)
        if m is None:
            m = 3*n
        # Find c>=1 such that c*exp((1-c**2)/2))**(2*n) == 2**-40
        #  i.e c>=1 such that 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 = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, stddev)
        RingLWE.__init__(self, N=N, q=q, D=D, poly=None, secret_dist='noise', m=m)
示例#7
0
文件: lwe.py 项目: sagemath/sage
    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)
示例#8
0
# Fundamental constants in SI units
c = constants.c
G = constants.G

# Astronomical constants in SI units
pc = constants.parsec
yr = constants.year
au = constants.au

# Sun
solar_mass_kg = 1.98848e30  # Particle Data Group, PRD 98, 030001 (2018); http://pdg.lbl.gov/
solar_mass_m = G * solar_mass_kg / c**2
solar_mass_s = solar_mass_m / c
solar_eq_radius_m = 6.957e8  # IAU Resolution B3; arXiv:1510.07674
solar_mean_density_SI = solar_mass_kg / (4 * pi.n() / 3 * solar_eq_radius_m**3)
# aliases:
Msol = solar_mass_kg
Msol_m = solar_mass_m
Msol_s = solar_mass_s

# Earth
Earth_mass_kg = 5.9724e24  # Particle Data Group, PRD 98, 030001 (2018); http://pdg.lbl.gov/
Earth_mass_m = G * Earth_mass_kg / c**2
Earth_mass_s = Earth_mass_m / c
Earth_mass_sol = Earth_mass_kg / solar_mass_kg
Earth_eq_radius_m = 6.3781e6  # IAU Resolution B3; arXiv:1510.07674
Earth_mean_density_SI = Earth_mass_kg / (4 * pi.n() / 3 * Earth_eq_radius_m**3)
Earth_mean_density_sol = Earth_mean_density_SI / solar_mean_density_SI

# Jupiter
def compute_flowpipe(A=None, X0=None, B=None, U=None, **kwargs):
    r"""Implements LGG reachability algorithm for the linear continuous system dx/dx = Ax + Bu.

    INPUTS:

    * ``A`` -- coefficient matrix of the system

    * ``X0`` -- initial set

    * ``B`` -- transformation of the input

    * ``U`` -- input set

    * ``time_step`` -- (default = 1e-2) time step

    * ``initial_time`` -- (default = 0) the initial time

    * ``time_horizon`` -- (default = 1) the final time

    * ``number_of_time_steps`` -- (default = ceil(T/tau)) number of time steps

    * "directions" -- (default: random, and a box) dictionary

    * ``solver`` -- LP solver. Valid options are:
        * 'GLPK' (default).
        * 'Gurobi'

    * ``base_ring`` -- base ring where polyhedral computations are performed
        Valid options are:
        * QQ - (default) rational field
        * RDF - real double field

    OUTPUTS:

    * ``flowpipe``

    """

    # ################
    # Parse input    #
    # ################
    if A is None:
        raise ValueError('System matrix A is missing.')
    else:
        if 'sage.matrix' in str(type(A)):
            n = A.ncols()
        elif type(A) == np.ndarray:
            n = A.shape[0]

    base_ring = kwargs['base_ring'] if 'base_ring' in kwargs else QQ

    if X0 is None:
        raise ValueError('Initial state X0 is missing.')
    elif 'sage.geometry.polyhedron' not in str(type(X0)) and type(X0) == list:
        # If X0 is not some type of polyhedron, set an initial point
        X0 = Polyhedron(vertices = [X0], base_ring = base_ring)
    elif 'sage.geometry.polyhedron' not in str(type(X0)) and X0.is_vector():
        X0 = Polyhedron(vertices = [X0], base_ring = base_ring)
    elif 'sage.geometry.polyhedron' in str(type(X0)):
        # ensure that all input sets are on the same ring
        # not sure about this
        if 1==0:
            if X0.base_ring() != base_ring:
                [F, g] = polyhedron_to_Hrep(X0)
                X0 = polyhedron_from_Hrep(F, g, base_ring=base_ring)
    else:
        raise ValueError('Initial state X0 not understood')

    if B is None:
        # the system is homogeneous: dx/dt = Ax
        got_homogeneous = True
    else:
        got_homogeneous = False
        if U is None:
            raise ValueError('Input range U is missing.')

    tau = kwargs['time_step'] if 'time_step' in kwargs else 1e-2

    t0 = kwargs['initial_time'] if 'initial_time' in kwargs else 0

    T = kwargs['time_horizon'] if 'time_horizon' in kwargs else 1

    global N
    N = kwargs['number_of_time_steps'] if 'number_of_time_steps' in kwargs else ceil(T/tau)

    directions = kwargs['directions'] if 'directions' in kwargs else {'select':'box'}

    global solver
    solver = kwargs['solver'] if 'solver' in kwargs else 'GLPK'

    global verbose
    verbose = kwargs['verbose'] if 'verbose' in kwargs else 0

    # this involves the convex hull of X0 and a Minkowski sum
    #first_element_evaluation = kwargs['first_element_evaluation'] if 'first_element_evaluation' in kwargs else 'approximate'

    # #######################################################
    # Generate template directions                          #
    # #######################################################
    if directions['select'] == 'box':

        if n==2:
            theta = [0,pi/2,pi,3*pi/2] # box
            dList = [vector(RR,[cos(t), sin(t)]) for t in theta]

        else: # directions of hypercube
            dList = []
            dList += [-identity_matrix(n).column(i) for i in range(n)]
            dList += [identity_matrix(n).column(i) for i in range(n)]

    elif directions['select'] == 'oct':

        if n != 2:
            raise NotImplementedError('Directions select octagon not implemented for n other than 2. Try box.')

        theta = [i*pi/4 for i in range(8)] # octagon
        dList = [vector(RR,[cos(t), sin(t)]) for t in theta]

    elif directions['select'] == 'random':

        order = directions['order'] if 'order' in directions else 12

        if n == 2:
            theta = [random.uniform(0, 2*pi.n(digits=5)) for i in range(order)]
            dList = [vector(RR,[cos(theta[i]), sin(theta[i])]) for i in range(order)]
        else:
            raise NotImplementedError('Directions select random not implemented for n greater than 2. Try box.')

    elif directions['select'] == 'custom':

        dList = directions['dList']

    else:

        raise TypeError('Template directions not understood.')


    # transform directions to numpy array, and get number of directions
    dArray = np.array(dList)
    k = len(dArray)

    global Phi_tau, expX0, alpha_tau_B

    if got_homogeneous: # dx/dx = Ax

        # #######################################################
        # Compute first element of the approximating sequence   #
        # #######################################################

        # compute matrix exponential exp(A*tau)
        Phi_tau = expm(np.multiply(A, tau))

        # compute exp(tau*A)X0
        expX0 = Phi_tau * X0

        # compute the bloating factor
        Ainfty = A.norm(Infinity)
        RX0 = radius(X0)

        unitBall = BoxInfty(center = zero_vector(n), radius = 1, base_ring = base_ring)
        alpha_tau = (exp(tau*Ainfty) - 1 - tau*Ainfty)*(RX0)
        alpha_tau_B = (alpha_tau*np.identity(n)) * unitBall

        # now we have that:
        # Omega0 = X0.convex_hull(expX0.Minkowski_sum(alpha_tau_B))

        # compute the first element of the approximating sequence, Omega_0
        #if first_element_evaluation == 'exact':
        #    Omega0 = X0.convex_hull(expX0.Minkowski_sum(alpha_tau_B))

        #elif first_element_evaluation == 'approximate': # NOT TESTED!!!
            #Omega0_A = dArray
        #    Omega0_b = np.zeros(k)

        #    for i, d in enumerate(dArray):
        # rho_X0_d = supp_fun_polyhedron(X0, d, solver=solver, verbose=verbose)
        #        rho_expX0_d = supp_fun_polyhedron(expX0, d, solver=solver, verbose=verbose)
        #        rho_alpha_tau_B_d = supp_fun_polyhedron(alpha_tau_B, d, solver=solver, verbose=verbose)
        #        Omega0_b[i] = max(rho_X0_d, rho_expX0_d + rho_alpha_tau_B_d);

        #    Omega0 = PolyhedronFromHSpaceRep(dArray, Omega0_b);

        #W_tau = Polyhedron(vertices = [], ambient_dim=n)
        # since W_tau = [], supp_fun_polyhedron returns 0

        # ################################################
        # Build the sequence of approximations Omega_i   #
        # ################################################

        Omega_i_Family_SF = [_Omega_i_supports_hom(d, X0) for d in dArray]


    else: # dx/dx = Ax + Bu

        global tau_V, beta_tau_B

        # compute range of the input under B, V = BU
        V = B * U

        # compute matrix exponential exp(A*tau)
        Phi_tau = expm(np.multiply(A, tau))

        # compute exp(tau*A)X0
        expX0 = Phi_tau * X0

        # compute the initial over-approximation
        tau_V = (tau*np.identity(n)) * V

        # compute the bloating factor
        Ainfty = A.norm(Infinity)
        RX0 = radius(X0)
        RV = radius(V)

        unitBall = BoxInfty(center = zero_vector(n), radius = 1, base_ring = base_ring)
        alpha_tau = (exp(tau*Ainfty) - 1 - tau*Ainfty)*(RX0 + RV/Ainfty)
        alpha_tau_B = (alpha_tau*np.identity(n)) * unitBall

        # compute the first element of the approximating sequence, Omega_0
        #aux = expX0.Minkowski_sum(tau_V)
        #Omega0 = X0.convex_hull(aux.Minkowski_sum(alpha_tau_B))

        beta_tau = (exp(tau*Ainfty) - 1 - tau*Ainfty)*(RV/Ainfty)
        beta_tau_B = (beta_tau*np.identity(n)) * unitBall

        #W_tau = tau_V.Minkowski_sum(beta_tau_B)

        # ################################################
        # Build the sequence of approximations Omega_i   #
        # ################################################

        Omega_i_Family_SF = [_Omega_i_supports_inhom(d, X0) for d in dArray]


    # ################################################
    # Build the approximating polyhedra              #
    # ################################################

    # each polytope is built using the support functions over-approximation
    Omega_i_Poly = list()

    # This loop can be vectorized (?)
    for i in range(N):    # we have N polytopes

        # for each one, use all directions
        A = matrix(base_ring, k, n);
        b = vector(base_ring, k)

        for j in range(k): #run over directions
            s_fun = Omega_i_Family_SF[j][i]
            A.set_row(j, dList[j])
            b[j] = s_fun

        Omega_i_Poly.append( polyhedron_from_Hrep(A, b, base_ring = base_ring) )

    return Omega_i_Poly