示例#1
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 main():
    print "RLWE with OKCN, AKCN"

    bandwith = lambda q, n, g : (ceil(log(q, 2)) * n * 2 + ceil(log(g, 2)) * n + 256)*1. / 8

    q, n, m = 12289, 1024, 2
    reclen = n; 
    noise = sym_binomial(32)
    noise_sqr = pdf_product(noise, noise, q)  
    v = nfoldconvolution(2*n, noise_sqr, q)
    v = convolution(v, noise, q)  # v = 2*n * (noise * noise) + noise

    print getVariance(v, q), 2.*n*getVariance(noise, q)**2 + getVariance(noise, q)

    g = 2**2
    d = okcn_get_d(q, n, m, g)
    failure_pr = sum(map(lambda x: v[x], filter(lambda x: min(x, q - x) > d, v.keys())))
    print "OKCN q = {}, n = {}, m = {}, g = {}, d = {}, bandwith = {}".format(q, n, m, g, d, bandwith(q, n, g))
    print "per bit pr of failure = 2^{:.2f}".format(log(failure_pr, 2))
    print 

    g = 2**3
    d = okcn_get_d(q, n, m, g)
    failure_pr = sum(map(lambda x: v[x], filter(lambda x: min(x, q - x) > d, v.keys())))
    print "OKCN q = {}, n = {}, m = {}, g = {}, d = {}, bandwith = {}".format(q, n, m, g, d, bandwith(q, n, g))
    print "per bit pr of failure = 2^{:.2f}".format(log(failure_pr, 2))
    print 

    g = 2**4
    d = okcn_get_d(q, n, m, g)
    failure_pr = sum(map(lambda x: v[x], filter(lambda x: min(x, q - x) > d, v.keys())))
    print "OKCN q = {}, n = {}, m = {}, g = {}, d = {}, bandwith = {}".format(q, n, m, g, d, bandwith(q, n, g))
    print "per bit pr of failure = 2^{:.2f}".format(log(failure_pr, 2))
    print 

    g = 2**4
    d = akcn_get_d(q, n, m, g)
    failure_pr = sum(map(lambda x: v[x], filter(lambda x: min(x, q - x) > d, v.keys())))
    print "AKCN q = {}, n = {}, m = {}, g = {}, d = {}, bandwith = {}".format(q, n, m, g, d, bandwith(q, n, g))
    print "per bit pr of failure = 2^{:.2f}".format(log(failure_pr, 2))
    print 

    g = 2**6
    d = akcn_get_d(q, n, m, g)
    failure_pr = sum(map(lambda x: v[x], filter(lambda x: min(x, q - x) > d, v.keys())))
    print "AKCN q = {}, n = {}, m = {}, g = {}, d = {}, bandwith = {}".format(q, n, m, g, d, bandwith(q, n, g))
    print "per bit pr of failure = 2^{:.2f}".format(log(failure_pr, 2))
    print 
示例#3
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]
示例#4
0
def minimize_bandwidth(classical_lb,
                       quantum_lb,
                       plausible_lb,
                       ubits,
                       binomials_only=False,
                       reduce_to_LWE=True,
                       agree_bits=256):
    """Searches the parameter space to minimize bandwidth. Prints to stdout.

    Args:
        classical_lb: A lower bound on classical security (None if undefined).
        quantum_lb: A lower bound on quantum security (None if undefined).
        plausible_lb: A conservative lower bound on security (None if undefined).
        ubits: The bound on the number of uniform bits required for sampling.
        binomials_only: If True, considers only binomial distributions.
        reduce_to_LWE: If True, uses reduction to rounded-Gaussian LWE.
        agree_bits: Target key length.
    """
    def check_costs(cost_cl, cost_pq, cost_pp):
        """Checks whether the costs satisfy lower bounds.

        Returns:
            True if lower bounds are satisfied.
        """
        return ((classical_lb is None or cost_cl >= classical_lb)
                and (quantum_lb is None or cost_pq >= quantum_lb)
                and (plausible_lb is None or cost_pp >= plausible_lb))

    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)
        ]

    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 print_intermediate_result(opt_d, qlog, n, w, sigma, bandwidth,
                                  heuristic_pr_failure, actual_pr_failure,
                                  costs_gauss, costs_opt):

        print distr_to_str(nonnegative_half(opt_d))
        print "q = 2**{}, n = {}, w = {}, sigma^2 = {:.2f}:".format(
            qlog, n, w, sigma**2),
        print "bandwidth = {:.2f} KB,".format(bandwidth / (8. * 1000)),

        print(
            "heuristic Pr of failure = {:.1f}, "
            "actual Pr of failure = {:.1f},".format(
                log(heuristic_pr_failure, 2), log(actual_pr_failure, 2))),

        formatted_costs = ", ".join("{:.1f}".format(c) for c in costs_gauss
                                    if not isinf(c))
        print "security = [{}],".format(formatted_costs),

        if reduce_to_LWE or not binomials_only:
            formatted_costs_opt = ", ".join("{:.1f}".format(c)
                                            for c in costs_opt if not isinf(c))
            print "security after reduction = [{}],".format(
                formatted_costs_opt),

        if binomials_only:
            bits = int(round(4 * sigma**2)) + 1
        else:
            bits = bits_needed_to_sample(opt_d)
        print "distribution on [{}, {}], {} bits to sample".format(
            min(opt_d.iterkeys()), max(opt_d.iterkeys()), bits)

        print "Parameters for print_tables.py: 'sigma': sqrt({:.2f}), 'n': {}, 'q': {}, 'B': {}, 'bits': {}, 'base': {:.0f}".format(
            sigma**2, n, qlog, w, bits, min(costs_gauss))

    # Main body of minimize_bandwidth starts here.

    attacks = [svp_classical]
    if quantum_lb is not None:
        attacks.append(svp_quantum)
    if plausible_lb is not None:
        attacks.append(svp_plausible)

    qlog_list = range(10, 16)  # Enumerate moduli in the range 2^10..2^15.
    # Enumerate n in the range 256..900.
    n_list = [n for n in xrange(256, 900, 16)]
    # The number of bits to extract; can range between 1 and be as large as
    # the modulus.
    w_list = range(1, 1 + max(qlog_list))
    # Feasible values for the variance.
    v_list = (1., 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 2.)

    min_bandwidth_bits = 8 * 30000  # bandwidth in bits

    for qlog in qlog_list:
        print "q = 2**{}".format(qlog)
        for n in n_list:
            prev_k = None  # number of columns already considered
            for w in w_list:
                # number of coordinates needed to achieve agree_bits
                required_coordinates = (agree_bits + w - 1) / w
                # number of columns
                k = int(ceil(sqrt(required_coordinates)))
                if k == prev_k:
                    # Nothing to do: w is larger than before but the number
                    # of columns is the same.
                    continue
                prev_k = k

                max_m = n + k
                bandwidth = k * qlog * 2 * n + required_coordinates
                if bandwidth > min_bandwidth_bits:
                    continue

                for v in v_list:
                    if binomials_only and fmod(2 * v, 1.0) != 0:
                        continue

                    sigma = sqrt(v)

                    # Quick-and-dirty check on the probability of failure
                    heuristic_pr_failure = heuristic_failure_prob_upper(
                        2**qlog, n, sigma, w, agree_bits)
                    if heuristic_pr_failure > 2**-20:  # very loose bound
                        continue

                    samples = 2 * k * n + required_coordinates

                    costs_gauss = estimate_cost(2**qlog, n, max_m, sigma,
                                                attacks)

                    # Checking upper bounds on costs, before trying to find an optimal
                    # approximation.
                    if not check_costs(*costs_gauss):
                        continue

                    if binomials_only:
                        if reduce_to_LWE:
                            [opt_d, cost_cl_opt, cost_pq_opt, cost_pp_opt
                             ] = find_binomial_cost(int(round(2 * v)), samples,
                                                    *costs_gauss)
                        else:
                            # no reduction
                            [cost_cl_opt, cost_pq_opt,
                             cost_pp_opt] = costs_gauss
                            opt_d = sym_binomial(2 * int(round(2 * v)))
                    else:
                        [opt_d, cost_cl_opt, cost_pq_opt,
                         cost_pp_opt] = find_opt_distr(sigma, samples, ubits,
                                                       *costs_gauss)

                    costs_opt = [cost_cl_opt, cost_pq_opt, cost_pp_opt]

                    if reduce_to_LWE and not check_costs(*costs_opt):
                        continue

                    actual_pr_failure = noise_failure_prob(
                        opt_d, 2**qlog, n, w, required_coordinates)
                    if actual_pr_failure > _PROB_FAILURE_CUTOFF:
                        continue

                    min_bandwidth_bits = bandwidth
                    print_intermediate_result(opt_d, qlog, n, w, sigma,
                                              bandwidth, heuristic_pr_failure,
                                              actual_pr_failure, costs_gauss,
                                              costs_opt)

    return
示例#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:
        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]