Example #1
0
def find_opt_distr(sigma, samples, ubits, cost_cl, cost_pq, cost_pp):
    """Finds an optimal distribution approximating rounded continuous Gaussian.

  Args:
    sigma: The standard deviation of the target (rounded) Gaussian.
    samples: The total number of samples drawn by both parties combined.
    ubits: The bound on the number of uniform bits required for sampling.
    cost_cl, cost_pq, cost_pp: Estimated costs of the rounded Gaussian.

  Returns:
    Four-tuple consisting of the distribution and the cost triplet.
  """
    cost_cl_opt, d, _ = approximate_dgauss(sigma,
                                           samples,
                                           cost_cl,
                                           None,
                                           ubits,
                                           quiet=True)

    sym_d = pdf_product(d, {+1: .5, -1: .5})

    dg = dgauss(sigma)

    _, cost_pq_opt = opt_renyi_bound(-cost_pq * log(2), sym_d, dg, samples)
    _, cost_pp_opt = opt_renyi_bound(-cost_pp * log(2), sym_d, dg, samples)

    return [sym_d, cost_cl_opt, -cost_pq_opt / log(2), -cost_pp_opt / log(2)]
Example #2
0
    def find_binomial_cost(sigma, samples, cost_cl, cost_pq, cost_pp):
        """Estimates the cost of replacing a rounded Gaussian with a binomial.

        Args:
            sigma: The standard deviation of the Gaussian.
            samples: The total number of samples drawn by Alice and Bob.
            cost_cl, cost_pq, cost_pp: Estimated costs of the rounded Gaussian.

        Returns:
            Four-tuple consisting of the distribution and the cost triplet.
        """

        dg = dgauss(sigma)
        # The binomial is defined as B(2*z, .5) - z.
        sb = sym_binomial(2 * sigma**2)

        _, cost_cl_binomial = opt_renyi_bound(-cost_cl * log(2), sb, dg,
                                              samples)
        _, cost_pq_binomial = opt_renyi_bound(-cost_pq * log(2), sb, dg,
                                              samples)
        _, cost_pp_binomial = opt_renyi_bound(-cost_pp * log(2), sb, dg,
                                              samples)

        return [
            sb, -cost_cl_binomial / log(2), -cost_pq_binomial / log(2),
            -cost_pp_binomial / log(2)
        ]
def security_to_TeX(p, nbar, print_sec=True):
    """Formats security estimates for use in TeX file.

    Args:
      p: A dictionary with entries for 'name', 'n', 'q', 'distr', 'sigma'
      nbar: Number of columns in exchanged matrices.
      print_sec: If true, output will include security estimates

    Returns:
      LaTeX string.
    """
    name, n, qlog, d, sigma = p['name'], p['n'], p['q'], p['distr'], p['sigma']

    samples = 2 * n * nbar + nbar**2
    q = 2**qlog
    ret = ""

    ret += r"\multirow{2}{*}{" + name.capitalize() + "} "

    for cost in [primal_cost, dual_cost]:
        m_pc, b_pc, cost_pc = optimize_attack(q, n, samples, sigma, cost, svp_classical, verbose=False)
        m_pq, b_pq, cost_pq = optimize_attack(q, n, samples, sigma, cost, svp_quantum, verbose=False)
        m_pp, b_pp, cost_pp = optimize_attack(q, n, samples, sigma, cost, svp_plausible, verbose=False)

        if cost == primal_cost:
            ret += "& Primal & "
        else:
            ret += "& Dual & "

        ret += "{} & {} &".format(m_pc, b_pc)

        if print_sec:
            sym_d = pdf_product(d, {+1: .5, -1: .5})
            dg = dgauss(sigma)

            _, cost_pc_reduced = opt_renyi_bound(-cost_pc * log(2), sym_d, dg, samples)
            _, cost_pq_reduced = opt_renyi_bound(-cost_pq * log(2), sym_d, dg, samples)
            _, cost_pp_reduced = opt_renyi_bound(-cost_pp * log(2), sym_d, dg, samples)

            ret += "{} & {} & {} & {} & {} & {} \\\\".format(
                int(cost_pc),
                int(cost_pq),
                int(cost_pp),
                int(-cost_pc_reduced / log(2)),
                int(-cost_pq_reduced / log(2)),
                int(-cost_pp_reduced / log(2)))  # always round down
        else:
            ret += "-- & -- & -- & -- & -- & -- \\\\"

        ret += "\n"
    return ret
Example #4
0
 def print_cost(attack_type):
     _, _, cost_pc = optimize_attack(
         2**q, n,
         max(nbar, mbar) + n, sigma, dual_cost, attack_type
     )  # Only compute the dual cost, since it is smaller than the primal cost.
     cost_pc -= log(nbar + mbar) / log(
         2
     )  # Take into account the hybrid argument over mbar + nbar instances.
     _, cost_pc_reduced = opt_renyi_bound(-cost_pc * log(2), sym_distr, dg,
                                          samples)
     return ' & {}'.format(int(-cost_pc_reduced / log(2)))
Example #5
0
def approximate_dgauss(sigma,
                       samples,
                       base_security,
                       max_table_len,
                       max_rand_bits,
                       suffix='',
                       quiet=True):
    """Approximates rounded Gaussian with a binomial and an optimal discrete distribution.

  Args:
    sigma: The standard deviation of the target Gaussian distribution.
    samples: Total number of samples per protocol run.
    base_security: The baseline security level, in bits (e.g., 150.34).
    max_table_len: Upper bound on the support of the distribution (can be
      None).
    max_rand_bits: Total number of uniformly random bits required for
      sampling.
    suffix: Suffix for printed out names.
    quiet: If quiet, suppress all output.

  Returns:
    (security bound, non-negative part of distribution, optimal Renyi order).
    """

    dg = dgauss(sigma)
    half_dg = nonnegative_half(dg)

    if not quiet:
        print(suffix)
        z = sigma**2 * 2
        if fmod(z, 1.) != 0:
            print('Skipping binomial')
        else:
            sb = sym_binomial(2 * int(z))
            opt_a_sb, opt_bound_sb = opt_renyi_bound(-base_security * log(2),
                                                     sb, dg, samples)

            print(
                'Sigma = {:.3f}: Binomial distribution z = {}, security = {:.2f}, a '
                '= {:.2f};').format(sigma, z, -opt_bound_sb / log(2), opt_a_sb)

    max_security = 0
    opt_r = None
    opt_d = {}
    opt_a = None

    for a in orders:
        for random_bits in range(
                1, max_rand_bits):  # reserve one bit for the sign
            d = round_distr_opt(half_dg,
                                2**-random_bits,
                                a,
                                max_table_len,
                                quiet=True)
            if d is not None:
                r = renyi(d, half_dg, a)
                security = -renyi_bound(-base_security * log(2), r * samples,
                                        a)
                if security > max_security:
                    max_security = security
                    opt_a = a
                    opt_d = d
                    opt_r = r

    if not quiet:
        if max_security == 0:
            print('Approximation is infeasible under given constraints')
        else:
            print('Security = {:.2f} a = {} Renyi divergence = {}'.format(
                max_security / log(2), opt_a, opt_r))
    return [max_security / log(2), opt_d, opt_a]
Example #6
0
def approximate_dgauss(sigma,
                       samples,
                       base_security,
                       max_table_len,
                       max_rand_bits,
                       suffix="",
                       quiet=True):
    """Approximates rounded Gaussian with a binomial and an optimal discrete distribution.

      Args:
        sigma: The standard deviation of the target Gaussian distribution.
        samples: Total number of samples per protocol run.
        base_security: The baseline security level, in bits (e.g., 150.34).
        max_table_len: Upper bound on the support of the distribution (can be None).
        max_rand_bits: Total number of uniformly random bits required for
          sampling.
        suffix: Suffix for printed out names.
        quiet: If quiet, suppress all output.

      Returns:
        Optimal rounded distribution (only the non-negative support), its security bound,
        and the order of Renyi divergence used to derive this bound.
    """

    dg = dgauss(sigma)
    half_dg = nonnegative_half(dg)

    if not quiet:
        print suffix
        z = sigma**2 * 2
        if fmod(z, 1.) != 0:
            print "Skipping binomial"
        else:
            sb = sym_binomial(2 * int(z))
            opt_a_sb, opt_bound_sb = opt_renyi_bound(-base_security * log(2),
                                                     sb, dg, samples)

            print(
                "Sigma = {:.3f}: Binomial distribution z = {}, security = {:.2f}, a = "
                "{:.2f};").format(sigma, z, -opt_bound_sb / log(2), opt_a_sb)

    # Constrain Renyi orders of interest to the following set for performance
    # and aesthetic reasons
    a_values = [
        1.5, 2., 5., 10., 15., 20., 25., 30., 40., 50., 75., 100., 200., 500.,
        float("inf")
    ]

    max_security = 0
    opt_r = None
    opt_d = {}
    opt_a = None

    for a in a_values:
        for random_bits in xrange(
                1, max_rand_bits):  # reserve one bit for the sign
            d = round_distr_opt(half_dg,
                                2**-random_bits,
                                a,
                                max_table_len,
                                quiet=True)
            if d is not None:
                r = renyi(d, half_dg, a)
                security = -renyi_bound(-base_security * log(2),
                                        log(r) * samples, a)
                if security > max_security:
                    max_security = security
                    opt_a = a
                    opt_d = d
                    opt_r = r

    if not quiet:
        if max_security == 0:
            print "Approximation is infeasible under given constraints"
        else:
            print "Security = {:.2f} a = {} Renyi divergence = {}".format(
                max_security / log(2), opt_a, opt_r)
    return [max_security / log(2), opt_d, opt_a]