Example #1
0
def doit(logfile):

    lines = [l for l in CM.iread(logfile) if "Info:***" in l]

    rs = OrderedDict()
    for l in lines:
        name, nlocs, ninvs, ninps, ntime, nrand = l.split(',')
        name = name.split()[1].strip()
        nlocs = float(nlocs.split()[0].strip())
        ninvs = float(ninvs.split()[1].strip())
        ninps = float(ninps.split()[1].strip())
        ntime = float(ntime.split()[1].strip())

        print name, nlocs, ninvs, ninps, ntime
        if name not in rs:
            rs[name] = {'nlocs': [], 'ninvs': [], 'ninps': [], 'ntime': []}

        rs[name]['nlocs'].append(nlocs)
        rs[name]['ninvs'].append(ninvs)
        rs[name]['ninps'].append(ninps)
        rs[name]['ntime'].append(ntime)

    nruns = max(len(rs[name]['nlocs']) for name in rs)

    stats = {}
    for name in rs:
        stats[name] = {}
        for key in rs[name]:
            contents = rs[name][key]
            if len(contents) < nruns:
                maxv = max(contents)
                maxv = maxv * 100
                contents.extend([maxv] * (nruns - len(contents)))

            medianc = median(contents)
            meanc = mean(contents)
            lenc = len(contents)
            stats[name][key] = (medianc, meanc, lenc)

            print('{} {} median {} mean {} len {}'.format(
                name, key, medianc, meanc, lenc))

    for name in sorted(stats):
        invsd = stats[name]["ninvs"]
        timesd = stats[name]["ntime"]
        print name, invsd[0], timesd[0]

    return stats
Example #2
0
    def calibrate(self):
        r"""
        Run some test computations to estimate the optimal search size.

        Let `p` be the search size. We should simply choose `p` such that the
        average expected time is minimal. The algorithm succeeds when it chooses
        an information set with at least `k - p` correct positions, where `k` is
        the dimension of the code and `p` the search size. The expected number
        of trials we need before this occurs is:

        .. MATH::

            \binom{n}{k}/(\rho \sum_{i=0}^p \binom{n-\tau}{k-i} \binom{\tau}{i})

        Here `\rho` is the fraction of `k` subsets of indices which are
        information sets. If `T` is the average time for steps 1 and 2
        (including selecting `I` until an information set is found), while `P(i)`
        is the time for the body of the ``for``-loop in step 3 for `m` of weight
        `i`, then each information set trial takes roughly time `T +
        \sum_{i=0}^{p} P(i) \binom{k}{i} (q-1)^i`, where `\GF{q}` is the base
        field.

        The values `T` and `P` are here estimated by running a few test
        computations similar to those done by the decoding algorithm.
        We don't explicitly estimate `\rho`.

        OUTPUT: Does not output anything but sets private fields used by
        :meth:`sage.coding.information_set_decoder.InformationSetAlgorithm.parameters()`
        and
        :meth:`sage.coding.information_set_decoder.InformationSetAlgorithm.time_estimate()``.

        EXAMPLES::

            sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm
            sage: C = codes.GolayCode(GF(2))
            sage: A = LeeBrickellISDAlgorithm(C, (0,3)); A
            ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 3 errors
            sage: A.calibrate()
            sage: A.parameters() #random
            {'search_size': 1}
            sage: A.time_estimate() #random
            0.0008162108571427874

        If we specify the parameter at construction time, calibrate does not override this choice::

            sage: A = LeeBrickellISDAlgorithm(C, (0,3), search_size=2); A
            ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 3 errors
            sage: A.parameters()
            {'search_size': 2}
            sage: A.calibrate()
            sage: A.parameters()
            {'search_size': 2}
            sage: A.time_estimate() #random
            0.0008162108571427874
        """
        from sage.all import sample, mean, random_vector, random_matrix, randint
        import time
        C = self.code()
        G = C.generator_matrix()
        n, k = C.length(), C.dimension()
        tau = self.decoding_interval()[1]
        F = C.base_ring()
        q = F.cardinality()
        Fstar = F.list()[1:]

        def time_information_set_steps():
            before = time.clock()
            while True:
                I = sample(range(n), k)
                Gi = G.matrix_from_columns(I)
                try:
                    Gi_inv = Gi.inverse()
                except ZeroDivisionError:
                    continue
                return time.clock() - before

        def time_search_loop(p):
            y = random_vector(F, n)
            g = random_matrix(F, p, n).rows()
            scalars = [[Fstar[randint(0, q - 2)] for i in range(p)]
                       for s in range(100)]
            before = time.clock()
            for m in scalars:
                e = y - sum(m[i] * g[i] for i in range(p))
                errs = e.hamming_weight()
            return (time.clock() - before) / 100.

        T = mean([time_information_set_steps() for s in range(5)])
        P = [time_search_loop(p) for p in range(tau + 1)]

        def compute_estimate(p):
            iters = 1.* binomial(n, k)/ \
                sum( binomial(n-tau, k-i)*binomial(tau,i) for i in range(p+1) )
            estimate = iters*(T + \
                sum(P[pi] * (q-1)**pi * binomial(k, pi) for pi in range(p+1) ))
            return estimate

        if self._parameters_specified:
            self._time_estimate = compute_estimate(
                self._parameters['search_size'])
        else:
            self._calibrate_select(
                [compute_estimate(p) for p in range(tau + 1)])
Example #3
0
def log_mean(X):
    return log(mean([abs(x) for x in X]), 2)
Example #4
0
def log_mean(X):
    return log(mean([abs(x) for x in X]), 2)
Example #5
0
def estimate(nlen=256, m=85, klen=254, skip=None):
    """
    Estimate the cost of solving HNP for an ECDSA with biased nonces instance.

    :param nlen:
    :param m:
    :param klen:
    :param compute:
    :returns:
    :rtype:

    EXAMPLES::

        sage: estimate(256, m=85, klen=254)
        sage: estimate(160, m=85, klen=158)

    """
    from usvp import solvers

    if skip is None:
        skip = []

    ecdsa = ECDSA(nbits=nlen)
    klen_list = make_klen_list(klen, m)
    gh = ECDSASolver.ghf(m, ecdsa.n, klen_list, prec=nlen // 2)
    vol = ECDSASolver.volf(m, ecdsa.n, klen_list, prec=nlen // 2)
    target_norm = ECDSASolver.evf(m, max(klen_list), prec=nlen // 2)

    print(
        ("% {t:s} {h:s}, nlen: {nlen:3d}, m: {m:2d}, klen: {klen:.3f}").format(
            t=str(datetime.datetime.now()), h=socket.gethostname(), nlen=nlen, m=m, klen=float(mean(klen_list))
        )
    )

    print("     E[|b[0]|]: 2^{v:.2f}".format(v=float(RR(log(gh, 2)))))
    print("        E[|v|]: 2^{v:.2f}".format(v=float(RR(log(target_norm, 2)))))
    print("  E[v]/E[b[0]]: %.4f" % float(target_norm / gh))
    print("")

    for solver in solvers:
        if solver in skip:
            continue
        cost, params = solvers[solver].estimate((2 * log(vol), m + 1), target_norm ** 2)
        if cost is None:
            print(" {solver:20s} not applicable".format(solver=solver))
            continue
        else:
            print(
                " {solver:20s} cost: 2^{c:.1f} cycles ≈ {t:12.4f}h, aux data: {params}".format(
                    solver=solver, c=float(log(cost, 2)), t=cost / (2.0 * 10.0 ** 9 * 3600.0), params=params
                )
            )
Example #6
0
def benchmark(
    nlen=256,
    klen=128,
    m=2,
    e=0.0,
    tasks=8,
    algorithm=None,
    flavor="plain",
    d=None,
    jobs=1,
    parallelism=1,
    seed=None,
    solver_params=None,
):
    """

    :param nlen: number of bits in the ECDSA key
    :param klen: number of known bits of the key
    :param m: number of available samples
    :param e: fraction of errors
    :param tasks: number of experiments to run
    :param algorithm: algorithm to use, see ``usvp.solvers``
    :param flavor: higher-level strategy to use, see ``usvp.flavors``
    :param d: lattice dimension (default: `m+1`)
    :param jobs: number of experiments to run in parallel
    :param parallelism: parallelism to use per experiment
    :param seed: randomness seed

    """
    from usvp_prec_hack import usvp_pred_cut_n_sieve_solve
    from usvp import solvers

    if nlen > 384:
        logging.warning("% hotpatching with slower but more numerically stable `usvp_pred_cut_n_sieve_solve`.")
        solvers["sieve_pred"] = usvp_pred_cut_n_sieve_solve

    klen_list = make_klen_list(klen, m)

    tag = ZZ.random_element(x=0, y=2 ** 64)  # we tag all outputs for easier matching

    if seed is None:
        seed = ZZ.random_element(x=0, y=2 ** 64)

    logging.warning(
        (
            "% {t:s} {h:s} 0x{tag:016x} :: nlen: {nlen:3d}, m: {m:2d}, klen: {klen:.3f}, e: {e:.2f}, "
            "alg: {alg:s}, seed: 0x{seed:016x}, params: {params}"
        ).format(
            t=str(datetime.datetime.now()),
            h=socket.gethostname(),
            nlen=nlen,
            e=e,
            m=m,
            klen=float(mean(klen_list)),
            alg=str(algorithm),
            seed=seed,
            tag=tag,
            params=solver_params,
        )
    )

    pool = Pool(jobs)
    J = [
        ComputeKernelParams(
            i=i,
            nlen=nlen,
            m=m,
            e=e,
            klen_list=klen_list,
            seed=seed + i,
            algorithm=algorithm,
            flavor=flavor,
            d=d,
            threads=parallelism,
            params=solver_params,
            tag=tag,
        )
        for i in range(tasks)
    ]

    if jobs > 1:
        r = list(pool.imap_unordered(compute_kernel, J))
    else:
        r = list(map(compute_kernel, J))

    ecdsa = ECDSA(nbits=nlen)

    expected_target = ECDSASolver.evf(m, max(klen_list), prec=nlen // 2)
    expected_b0 = ECDSASolver.ghf(m, ecdsa.n, klen_list, prec=nlen // 2)

    successes = 0
    B0 = []
    eB0 = []
    work = []
    cputime = []
    walltime = []
    for key, res, targetvector_norm in r:
        successes += int(res.success)
        B0.append(float(targetvector_norm / res.b0))
        eB0.append(float(expected_target / res.b0))
        work.append(int(res.ntests))
        cputime.append(float(res.cputime))
        walltime.append(float(res.walltime))

    logging.warning(
        (
            "% {tm:s} {h:s} 0x{tag:016x} ::  sr: {sr:3.0f}%, v/b[0]: {b0ratio:.3f}, "
            "E|v|/|b[0]|: {eb0r:.3f}, E|v|/E|b[0]|: {eveb:.3f}, work: {wk:d}, "
            "t: {t:.1f}s, w: {w:.1f}s"
        ).format(
            tm=str(datetime.datetime.now()),
            h=socket.gethostname(),
            sr=100 * float(successes / tasks),
            b0ratio=median(B0),
            eb0r=median(eB0),
            eveb=float(expected_target / expected_b0),
            wk=int(median(work)),
            t=median(cputime),
            w=median(walltime),
            tag=tag,
        )
    )

    return r
    def calibrate(self):
        r"""
        Run some test computations to estimate the optimal search size.

        Let `p` be the search size. We should simply choose `p` such that the
        average expected time is minimal. The algorithm succeeds when it chooses
        an information set with at least `k - p` correct positions, where `k` is
        the dimension of the code and `p` the search size. The expected number
        of trials we need before this occurs is:

        .. MATH::

            \binom{n}{k}/(\rho \sum_{i=0}^p \binom{n-\tau}{k-i} \binom{\tau}{i})

        Here `\rho` is the fraction of `k` subsets of indices which are
        information sets. If `T` is the average time for steps 1 and 2
        (including selecting `I` until an information set is found), while `P(i)`
        is the time for the body of the ``for``-loop in step 3 for `m` of weight
        `i`, then each information set trial takes roughly time `T +
        \sum_{i=0}^{p} P(i) \binom{k}{i} (q-1)^i`, where `\GF{q}` is the base
        field.

        The values `T` and `P` are here estimated by running a few test
        computations similar to those done by the decoding algorithm.
        We don't explicitly estimate `\rho`.

        OUTPUT: Does not output anything but sets private fields used by
        :meth:`sage.coding.information_set_decoder.InformationSetAlgorithm.parameters()`
        and
        :meth:`sage.coding.information_set_decoder.InformationSetAlgorithm.time_estimate()``.

        EXAMPLES::

            sage: from sage.coding.information_set_decoder import LeeBrickellISDAlgorithm
            sage: C = codes.GolayCode(GF(2))
            sage: A = LeeBrickellISDAlgorithm(C, (0,3)); A
            ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 3 errors
            sage: A.calibrate()
            sage: A.parameters() #random
            {'search_size': 1}
            sage: A.time_estimate() #random
            0.0008162108571427874

        If we specify the parameter at construction time, calibrate does not override this choice::

            sage: A = LeeBrickellISDAlgorithm(C, (0,3), search_size=2); A
            ISD Algorithm (Lee-Brickell) for [24, 12, 8] Extended Golay code over GF(2) decoding up to 3 errors
            sage: A.parameters()
            {'search_size': 2}
            sage: A.calibrate()
            sage: A.parameters()
            {'search_size': 2}
            sage: A.time_estimate() #random
            0.0008162108571427874
        """
        from sage.all import sample, mean, random_vector, random_matrix, randint
        import time
        C = self.code()
        G = C.generator_matrix()
        n, k = C.length(), C.dimension()
        tau = self.decoding_interval()[1]
        F = C.base_ring()
        q = F.cardinality()
        Fstar = F.list()[1:]
        def time_information_set_steps():
            before = time.clock()
            while True:
                I = sample(range(n), k)
                Gi = G.matrix_from_columns(I)
                try:
                    Gi_inv = Gi.inverse()
                except ZeroDivisionError:
                    continue
                return time.clock() - before
        def time_search_loop(p):
            y = random_vector(F, n)
            g = random_matrix(F, p, n).rows()
            scalars = [  [ Fstar[randint(0,q-2)] for i in range(p) ]
                             for s in range(100) ]
            before = time.clock()
            for m in scalars:
                e = y - sum(m[i]*g[i] for i in range(p))
                errs = e.hamming_weight()
            return (time.clock() - before)/100.
        T = mean([ time_information_set_steps() for s in range(5) ])
        P = [ time_search_loop(p) for p in range(tau+1) ]

        def compute_estimate(p):
            iters = 1.* binomial(n, k)/ \
                sum( binomial(n-tau, k-i)*binomial(tau,i) for i in range(p+1) )
            estimate = iters*(T + \
                sum(P[pi] * (q-1)**pi * binomial(k, pi) for pi in range(p+1) ))
            return estimate

        if self._parameters_specified:
            self._time_estimate = compute_estimate(self._parameters['search_size'])
        else:
            self._calibrate_select([ compute_estimate(p) for p in range(tau+1) ])