|  | #!/usr/bin/sage -python
# -*- coding: latin-1 -*-
load("../framework/instance_gen.sage")
for params in ['CCS1']:
    logging("Set of parameters: " + params)
    if params == 'challenge':
        n = 296
        m = n + 4
        q = 2**12
        frodo_distribution = []
        D_s = {-1: RR(1 / 3), 0: RR(1 / 3), 1: RR(1 / 3)}
    elif params == 'NIST1':
        # NIST1 FRODOKEM-640
        n = 640
        m = 640
        q = 2**15
        frodo_distribution = [9288, 8720, 7216, 5264, 3384,
                                1918, 958, 422, 164, 56, 17, 4, 1]
        D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
        load("Frodo_Single_data/simulation_distribution_NIST1.sage")
        load("Frodo_Single_data/aposteriori_distribution_NIST1.sage")
    elif params == 'NIST2':
        # NIST2 FRODOKEM-976
        n = 976
        m = 976
        q = 65536
        frodo_distribution = [11278, 10277, 7774, 4882, 2545, 1101,
                                 396, 118, 29, 6, 1]
        D_s = get_distribution_from_table(frodo_distribution, 2 ** 16) 
        load("Frodo_Single_data/simulation_distribution_NIST2.sage")
        load("Frodo_Single_data/aposteriori_distribution_NIST2.sage")
    elif params == 'CCS1':
        n = 352
        m = 352
        q = 2 ** 11
        frodo_distribution = [22528, 15616, 5120, 768]
        D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
        load("Frodo_Single_data/simulation_distribution_CCS1.sage")
        load("Frodo_Single_data/aposteriori_distribution_CCS1.sage")
    elif params == 'CCS2':
        n = 592
        m = 592
        q = 2 ** 12
        frodo_distribution = [25120, 15840, 3968, 384, 16]
        D_s = get_distribution_from_table(frodo_distribution, 2 ** 16) 
        load("Frodo_Single_data/simulation_distribution_CCS2.sage")
        load("Frodo_Single_data/aposteriori_distribution_CCS2.sage")
    elif params == 'CCS3':
        n = 752
        m = 752
        q = 2 ** 15
        frodo_distribution = [19296, 14704, 6496, 1664, 240, 16]
        D_s = get_distribution_from_table(frodo_distribution, 2 ** 16) 
        load("Frodo_Single_data/simulation_distribution_CCS3.sage")
        load("Frodo_Single_data/aposteriori_distribution_CCS3.sage")
    elif params == 'CCS4':
        n = 864
        m = 864
        q = 2 ** 15
        frodo_distribution = [19304, 14700, 6490, 1659, 245, 21, 1]
        D_s = get_distribution_from_table(frodo_distribution, 2 ** 16) 
        load("Frodo_Single_data/simulation_distribution_CCS4.sage")
        load("Frodo_Single_data/aposteriori_distribution_CCS4.sage")
    """  Original Security   """
    A, b, dbdd = initialize_from_LWE_instance(DBDD_predict_diag,
                                               n,
                                               q, m, D_s, D_s, verbosity=0)
    dbdd.integrate_q_vectors(q, indices=range(n, n + m))
    (beta, _) = dbdd.estimate_attack()
    logging("Attack without hints:  %3.2f bikz" % beta, style="HEADER")
    """  Refined Side channel attack  """
    def simu_measured(secret):
        """ 
        This fonction simulates the information gained by
        Bos et al attack. The simulation is based on a
        distribution obtained with a large amount of data
        for Bos et al suite (in Matlab).
        :secret: an integer being the secret value
        :measurement: an integer that represents the output
        of Bos et al attack.
        """
        secret = recenter(secret)
        distrib_of_guesses = renormalize_dist(Dguess[secret])
        measurement = draw_from_distribution(distrib_of_guesses)
        return measurement
    def ordered_indices(sorted_guesses, measured):
            """
            Necessary for the bruteforce attack, this function
            sorts the indices of the coefficients
            of the secret with decreasing likelihood.
            :sorted_guess: the best guesses in order of likelihood
            :measured: the measurement for each coefficient
            :orderered_coefficients: the indices of the coefficients
            ordered according to Probability[secret[i] = measured[i]]
            """
            orderered_coefficients = []
            for x in sorted_guesses:
                for i in range(len(measured)):
                    meas = measured[i]
                    if meas == x:
                        orderered_coefficients += [i]
            return orderered_coefficients
    def estimate_SCA(report_every, dbdd, measured, max_guesses):
        """ 
        This function evaluates the security loss after Bos et al attack
        :report_every: an integer that give the frequency of
        logging (None for no logging)
        :dbdd: instance of the class DBDD
        :measured: table representing the (simulated) information
        given by Bos et al attack
        :max_guesses: integer for upperbounding the number of guesses
        """
        Id = identity_matrix(n + m)
        for i in range(n):
            v = vec(Id[i])
            if report_every is not None and ((i % report_every == 0) or (i == n - 1)) :
                verbose = 2 
            else:
                verbose = 0
            dbdd.verbosity = verbose
            if verbose == 2:
                logging("[...%d]" % report_every, newline=False)
            if variance_aposteriori[measured[i]] is not None and variance_aposteriori[measured[i]] != 0:
                dbdd.integrate_approx_hint(v,
                                           center_aposteriori[measured[i]],
                                           variance_aposteriori[measured[i]],
                                           aposteriori=True, estimate=verbose)
            elif variance_aposteriori[measured[i]] is not None and variance_aposteriori[measured[i]] == 0 :
                dbdd.integrate_perfect_hint(v, center_aposteriori[measured[i]],
                                            estimate=verbose)
        if report_every is not None:
            dbdd.integrate_q_vectors(q, indices=range(n, n + m), report_every=report_every)
        else:
            dbdd.integrate_q_vectors(q, indices=range(n, n + m))
        (beta, _) = dbdd.estimate_attack()
        if report_every is not None:
            logging("     Hybrid attack estimation     ", style="HEADER")
        sorted_guesses = sorted(proba_best_guess_correct.items(),
                                key=lambda kv: - kv[1])
        sorted_guesses = [sorted_guesses[i][0] for i in range(len(sorted_guesses))
                          if sorted_guesses[i][1] != 1.]
        proba_success = 1.
        dbdd.verbosity = 0
        guesses = 0
        j = 0
        for i in ordered_indices(sorted_guesses, measured):
            j += 1
            if (guesses <= max_guesses):
                v = vec(Id[i])
                if dbdd.integrate_perfect_hint(v, _):
                    guesses += 1
                    proba_success *= proba_best_guess_correct[measured[i]]
                if report_every is not None and (j % report_every == 0):
                    logging("[...%d]" % report_every, newline=False)
                    dbdd.integrate_q_vectors(q, indices=range(n, n + m))
                    logging("dim=%3d \t delta=%.6f \t beta=%3.2f \t guesses=%4d" %
                            (dbdd.dim(), dbdd.delta, dbdd.beta, guesses),
                            style="VALUE", newline=False)
                    logging("Proba success = %s" % proba_success, style="VALUE",
                            newline=True)
        dbdd.attack()
        return beta, dbdd.beta, proba_success
    """  Example
    Uncomment the following to get the detailed computation
    """
    A, b, dbdd = initialize_from_LWE_instance(DBDD,
                                                  n,
                                                  q, m, D_s, D_s, verbosity=2)
    measured = [simu_measured(dbdd.u[0, i]) for i in range(n)]
    estimate_SCA(50, dbdd, measured, 200)
 |