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