def noise_failure_prob(noise, q, n, w, reclen, g, cut):
    m = 2**w
    d = max(filter(lambda x: m*x*2 < q*(1. - 1./g), range(q)))
    print "d = ", d

    eps = sym_uniform(2**cut)
    noise_sqr = pdf_product(noise, noise, q)                       # noise_sqr = noise * noise
    noise_eps = pdf_product(noise, convolution(noise, eps, q), q)  # noise_eps = noise * (noise + eps)
    v1 = nfoldconvolution(n, noise_sqr, q) # v1 = n * (noise * noise)
    v2 = nfoldconvolution(n, noise_eps, q) # v2 = n * (noise * (noise + eps))
    vv = convolution(convolution(v1, v2, q), noise, q)  # vv = v1 + v2 + noise

    failure_pr = reclen * sum(map(lambda x: vv[x], filter(lambda x: min(x, q - x) > d, vv.keys())))

    return failure_pr
Beispiel #2
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)]
Beispiel #3
0
def parameters_to_TeX(p, nbar):
    """Formats parameters for use in TeX file.

    Args:
      p: A dictionary with entries for 'name', 'n', 'q', 'D', 'B', 'distr'
      nbar: Number of columns in exchanged matrices.

    Returns:
      LaTeX string.
    """
    name, n, q, dname, B, distr = p['name'], p['n'], p['q'], p['D'], p['B'], p[
        'distr']

    s = name.capitalize()
    s += " & \!\! {} \!\!".format(n)
    s += " & \!\! $2^{{{}}}$ \!\!".format(q)
    s += " & \!\! ${}$ \!\!".format(dname)

    agreed_bits = B * nbar * nbar
    s += " & ${}\cdot {}^2 = {}$".format(B, nbar, agreed_bits)
    if agreed_bits < 100:  # pad to equal length
        s += "\hphantom{0}"

    sym_distr = pdf_product(distr, {+1: .5, -1: .5})
    failure_prob = noise_failure_prob(sym_distr, 2**q, n, B, agreed_bits)
    s += " & $2^{{{:.1f}}}$".format(log(failure_prob, 2))

    bandwidth = nbar * q * 2 * n + nbar * nbar  # bandwidth in bits
    s += " & {:.2f} KB".format(bandwidth / 8000.)

    s += r" \\"

    return s
def parameters_to_TeX(p, nbar):
    """Formats parameters for use in TeX file.

    Args:
      p: A dictionary with entries for 'name', 'n', 'q', 'D', 'B', 'distr'
      nbar: Number of columns in exchanged matrices.

    Returns:
      LaTeX string.
    """
    name, n, q, dname, B, distr, g = p['name'], p['n'], p['q'], p['D'], p[
        'B'], p['distr'], p['g']

    s = name.capitalize()
    s += " n = {}".format(n)
    s += " q = $2^{{{}}}$".format(q)
    s += " distr = ${}$".format(dname)

    agreed_bits = B * nbar * nbar
    s += " ${}\cdot {}^2 = {}$".format(B, nbar, agreed_bits)

    sym_distr = pdf_product(distr, {+1: .5, -1: .5})
    failure_prob = noise_failure_prob(sym_distr, 2**q, n, B, agreed_bits, g,
                                      p['cut'])
    s += " err = $2^{{{:.1f}}}$".format(log(failure_prob, 2))

    bandwidth = nbar * q * 2 * n + nbar * nbar * ceil(log(
        g, 2))  # bandwidth in bits
    s += " & {:.2f} kB".format(bandwidth / 8000.)

    s += r" \\"

    return s
Beispiel #5
0
def parameters_to_tex(p):
    """Formats parameters for use in TeX file.

  Args:
    p: A dictionary with entries for 'name', 'n', 'q', 'D', 'B', 'distr'

  Returns:
    LaTeX string.
  """
    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)))

    name, n, q, b, distr, sigma, nbar, mbar, keylen = (p['name'], p['n'],
                                                       p['q'], p['B'],
                                                       p['distr'], p['sigma'],
                                                       p['n_bar'], p['m_bar'],
                                                       p['key_len'])

    s = name.capitalize()
    s += r' & \!\! {} \!\!'.format(n)
    s += r' & \!\! $2^{{{}}}$ \!\!'.format(q)
    sigma_str = r'{:.3f}'.format(sigma).rstrip('0.')
    s += r' &\quad ' + sigma_str
    s += r' &$[{}\dots {}]$'.format(-max(distr), max(distr))
    s += r' &\!\!{}\!\!'.format(b)

    s += r' & ${}\times {}$'.format(nbar, mbar)

    sym_distr = pdf_product(distr, {+1: .5, -1: .5})
    failure_prob = exact_failure_prob_pke(sym_distr, 2**q, n, b, keylen)
    if failure_prob == 0:
        s += r' & $0$ '
    else:
        s += r' & $2^{{{:.1f}}}$'.format(log(failure_prob) / log(2))

    ct_len = ((mbar * n + mbar * nbar) * q + keylen) // 8

    s += r' & {}'.format(ct_len)

    samples = n * (nbar + mbar) + nbar * mbar
    dg = dgauss(sigma)

    s += print_cost(svp_classical)
    # s += print_cost(svp_quantum)
    s += print_cost(svp_plausible)

    s += r' \\'

    return s
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
Beispiel #7
0
def main():
    d1 = {0: 44 / 128., 1: 61 / 128., 2: 20 / 128., 3: 3. / 128}
    sym_d1 = pdf_product(d1, {+1: .5, -1: .5})
    print "Parameters leading to deliberately large probability of failure (for testing purposes):"
    print "Distribution = D1,",
    print_failure_props(sym_d1, 10, 320, 1, 64)

    print "Recommended parameters:"
    d3 = {
        0: 603 / 2048.,
        1: 919 / 2048.,
        2: 406 / 2048.,
        3: 104 / 2048.,
        4: 15 / 2048.,
        5: 1 / 2048.
    }
    sym_d3 = pdf_product(d3, {+1: .5, -1: .5})
    print "Distribution = D3,",
    print_failure_props(sym_d3, 15, 752, 4, 256)

    print "Parameters similar to recommended, distribution is different:"
    dg175 = dgauss(sqrt(1.75))
    print "Distribution = rounded Gaussian with sigma^2 = 1.75,",
    print_failure_props(dg175, 15, 752, 4, 256)
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 
Beispiel #9
0
def exact_failure_prob_pke(noise, q, n, w, reclen):
    """Computes the probability of failure of PKE (exactly).

  Args:
    noise: The noise distribution as a dictionary.
    q: Modulus.
    n: Vector length.
    w: Number of extracted bits per coordinate.
    reclen: Number of bits to be extracted.

  Returns:
    The probability of failure.
  """
    def pr_rec_failure_pke(x):
        # Probability of failing to recover from an error of magnitude x.
        #        0% if -B/2 <= x < B/2
        #        100% if x >= B/2 or x < -B/2

        x = min(x, q - x)
        b = q / (2**w)
        if x >= b / 2:
            return 1.
        elif x < -b / 2:
            return 1.
        else:
            return 0

    noise_sqr = pdf_product(noise, noise, q)

    v = nfoldconvolution(2 * n, noise_sqr, q)

    v = convolution(v, noise, q)  # v = 2n * (noise^2) + noise

    exact_pr = {x: p * pr_rec_failure_pke(x) for (x, p) in v.iteritems()}

    r1r2 = (reclen + w - 1) / w

    failure_pr = r1r2 * sum(exact_pr.itervalues())

    return failure_pr
Beispiel #10
0
def noise_failure_prob(noise, q, n, w, reclen):
    """Computes the failure probability of key agreement for given noise distribution.

    Args:
      noise: Noise distribution given as a dictionary.
      q: Modulus.
      n: Vector length.
      w: Number of extracted bits per coordinate.
      reclen: Number of coordinates to be reconciled.

    Returns:
      The probability of failure.
    """
    def pr_rec_failure(x):
        """ Probability of failing to recover from an error of magnitude x:
            0% if x <= B/4
            100% if x >= 3B/4
            and linear in-between
        """
        x = min(x, q - x)
        B = q / (2**w)
        if x < B / 4:
            return 0
        elif x > 3 * B / 4:
            return 1.
        else:
            return (x - B / 4.) / (2. * B / 4.)

    noise_sqr = pdf_product(noise, noise, q)

    v = nfoldconvolution(2 * n, noise_sqr, q)

    v = convolution(v, noise, q)  # v = 2n * (noise^2) + noise

    exact_pr = {x: p * pr_rec_failure(x) for (x, p) in v.iteritems()}

    failure_pr = reclen * sum(exact_pr.itervalues())

    return failure_pr
Beispiel #11
0
def approximate_and_compute_failure_pr(qlog, n, sigma, m_bar, n_bar, agree_bits, w):
  samples = 2 * (m_bar + n_bar) * n + m_bar * n_bar
  _, d, a = approximate_dgauss(sigma, samples, 149, None, 16, quiet=True)
  sym_distr = pdf_product(d, {+1: .5, -1: .5})
  return exact_failure_prob_pke(sym_distr, 2 ** qlog, n, w, agree_bits)