Fork of the official github repository of the framework Leaky-LWE-Estimator, a Sage Toolkit to attack and estimate the hardness of LWE with Side Information. https://github.com/lducas/leaky-LWE-Estimator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

exploiting_SCA_from_Bos_et_al.sage 9.4KB

  1. load("../framework/instance_gen.sage")
  2. demo = False
  3. """ Example
  4. Uncomment the following to get an example
  5. of the detailed computation (without redundancy)
  6. """
  7. demo = True
  8. logging("--- Demonstration mode (no averaging) ---")
  9. for params in ['CCS1', 'CCS2', 'CCS3', 'CCS4', 'NIST1', 'NIST2']:
  10. logging("Set of parameters: " + params)
  11. if params == 'NIST1':
  12. # NIST1 FRODOKEM-640
  13. n = 640
  14. m = 640
  15. q = 2**15
  16. frodo_distribution = [9288, 8720, 7216, 5264, 3384,
  17. 1918, 958, 422, 164, 56, 17, 4, 1]
  18. D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
  19. load("Frodo_Single_data/simulation_distribution_NIST1.sage")
  20. load("Frodo_Single_data/aposteriori_distribution_NIST1.sage")
  21. elif params == 'NIST2':
  22. # NIST2 FRODOKEM-976
  23. n = 976
  24. m = 976
  25. q = 65536
  26. frodo_distribution = [11278, 10277, 7774, 4882, 2545, 1101,
  27. 396, 118, 29, 6, 1]
  28. D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
  29. load("Frodo_Single_data/simulation_distribution_NIST2.sage")
  30. load("Frodo_Single_data/aposteriori_distribution_NIST2.sage")
  31. elif params == 'CCS1':
  32. n = 352
  33. m = 352
  34. q = 2 ** 11
  35. frodo_distribution = [22528, 15616, 5120, 768]
  36. D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
  37. load("Frodo_Single_data/simulation_distribution_CCS1.sage")
  38. load("Frodo_Single_data/aposteriori_distribution_CCS1.sage")
  39. elif params == 'CCS2':
  40. n = 592
  41. m = 592
  42. q = 2 ** 12
  43. frodo_distribution = [25120, 15840, 3968, 384, 16]
  44. D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
  45. load("Frodo_Single_data/simulation_distribution_CCS2.sage")
  46. load("Frodo_Single_data/aposteriori_distribution_CCS2.sage")
  47. elif params == 'CCS3':
  48. n = 752
  49. m = 752
  50. q = 2 ** 15
  51. frodo_distribution = [19296, 14704, 6496, 1664, 240, 16]
  52. D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
  53. load("Frodo_Single_data/simulation_distribution_CCS3.sage")
  54. load("Frodo_Single_data/aposteriori_distribution_CCS3.sage")
  55. elif params == 'CCS4':
  56. n = 864
  57. m = 864
  58. q = 2 ** 15
  59. frodo_distribution = [19304, 14700, 6490, 1659, 245, 21, 1]
  60. D_s = get_distribution_from_table(frodo_distribution, 2 ** 16)
  61. load("Frodo_Single_data/simulation_distribution_CCS4.sage")
  62. load("Frodo_Single_data/aposteriori_distribution_CCS4.sage")
  63. """ Original Security """
  64. A, b, dbdd = initialize_from_LWE_instance(DBDD_predict_diag,
  65. n,
  66. q, m, D_s, D_s, verbosity=0)
  67. dbdd.integrate_q_vectors(q, indices=range(n, n + m))
  68. (beta, _) = dbdd.estimate_attack()
  69. logging("Attack without hints: %3.2f bikz" % beta, style="HEADER")
  70. """ Refined Side channel attack """
  71. def simu_measured(secret):
  72. """
  73. This fonction simulates the information gained by
  74. Bos et al attack. The simulation is based on a
  75. distribution obtained with a large amount of data
  76. for Bos et al suite (in Matlab).
  77. :secret: an integer being the secret value
  78. :measurement: an integer that represents the output
  79. of Bos et al attack.
  80. """
  81. secret = recenter(secret)
  82. distrib_of_guesses = renormalize_dist(Dguess[secret])
  83. measurement = draw_from_distribution(distrib_of_guesses)
  84. return measurement
  85. def ordered_indices(sorted_guesses, measured):
  86. """
  87. Necessary for the bruteforce attack, this function
  88. sorts the indices of the coefficients
  89. of the secret with decreasing likelihood.
  90. :sorted_guess: the best guesses in order of likelihood
  91. :measured: the measurement for each coefficient
  92. :orderered_coefficients: the indices of the coefficients
  93. ordered according to Probability[secret[i] = measured[i]]
  94. """
  95. orderered_coefficients = []
  96. for x in sorted_guesses:
  97. for i in range(len(measured)):
  98. meas = measured[i]
  99. if meas == x:
  100. orderered_coefficients += [i]
  101. return orderered_coefficients
  102. def estimate_SCA(report_every, dbdd, measured, max_guesses):
  103. """
  104. This function evaluates the security loss after Bos et al attack
  105. :report_every: an integer that give the frequency of
  106. logging (None for no logging)
  107. :dbdd: instance of the class DBDD
  108. :measured: table representing the (simulated) information
  109. given by Bos et al attack
  110. :max_guesses: integer for upperbounding the number of guesses
  111. """
  112. Id = identity_matrix(n + m)
  113. for i in range(n):
  114. v = vec(Id[i])
  115. if report_every is not None and ((i % report_every == 0) or (i == n - 1)) :
  116. verbose = 2
  117. else:
  118. verbose = 0
  119. dbdd.verbosity = verbose
  120. if verbose == 2:
  121. logging("[...%d]" % report_every, newline=False)
  122. if variance_aposteriori[measured[i]] is not None and variance_aposteriori[measured[i]] != 0:
  123. dbdd.integrate_approx_hint(v,
  124. center_aposteriori[measured[i]],
  125. variance_aposteriori[measured[i]],
  126. aposteriori=True, estimate=verbose)
  127. elif variance_aposteriori[measured[i]] is not None and variance_aposteriori[measured[i]] == 0 :
  128. dbdd.integrate_perfect_hint(v, center_aposteriori[measured[i]],
  129. estimate=verbose)
  130. if report_every is not None:
  131. dbdd.integrate_q_vectors(q, indices=range(n, n + m), report_every=report_every)
  132. else:
  133. dbdd.integrate_q_vectors(q, indices=range(n, n + m))
  134. (beta, _) = dbdd.estimate_attack()
  135. if report_every is not None:
  136. logging(" Hybrid attack estimation ", style="HEADER")
  137. sorted_guesses = sorted(proba_best_guess_correct.items(),
  138. key=lambda kv: - kv[1])
  139. sorted_guesses = [sorted_guesses[i][0] for i in range(len(sorted_guesses))
  140. if sorted_guesses[i][1] != 1.]
  141. proba_success = 1.
  142. dbdd.verbosity = 0
  143. guesses = 0
  144. j = 0
  145. for i in ordered_indices(sorted_guesses, measured):
  146. j += 1
  147. if (guesses <= max_guesses):
  148. v = vec(Id[i])
  149. if dbdd.integrate_perfect_hint(v, _):
  150. guesses += 1
  151. proba_success *= proba_best_guess_correct[measured[i]]
  152. if report_every is not None and (j % report_every == 0):
  153. logging("[...%d]" % report_every, newline=False)
  154. dbdd.integrate_q_vectors(q, indices=range(n, n + m))
  155. logging("dim=%3d \t delta=%.6f \t beta=%3.2f \t guesses=%4d" %
  156. (dbdd.dim(), dbdd.delta, dbdd.beta, guesses),
  157. style="VALUE", newline=False)
  158. logging("Proba success = %s" % proba_success, style="VALUE",
  159. newline=True)
  160. return beta, dbdd.beta, proba_success
  161. if demo:
  162. A, b, dbdd = initialize_from_LWE_instance(DBDD_predict_diag,
  163. n,
  164. q, m, D_s, D_s, verbosity=2)
  165. measured = [simu_measured(dbdd.u[0, i]) for i in range(n)]
  166. estimate_SCA(50, dbdd, measured, 200)
  167. else:
  168. """ Averaging
  169. The following averages the measures to get accurate data
  170. for the paper. The averaging mode is quite long.
  171. """
  172. nb_tests_per_params = 100
  173. # Chosen values for the number of guesses
  174. if params == 'CCS1':
  175. max_guesses = 100
  176. elif params == 'CCS2':
  177. max_guesses = 350
  178. elif params == 'CCS3':
  179. max_guesses = 300
  180. elif params == 'CCS4':
  181. max_guesses = 150
  182. elif params == 'NIST1':
  183. max_guesses = 50
  184. elif params == 'NIST2':
  185. max_guesses = 100
  186. beta = 0
  187. beta_hybrid = 0
  188. proba_success = 0
  189. for i in range(nb_tests_per_params):
  190. A, b, dbdd = initialize_from_LWE_instance(DBDD_predict_diag,
  191. n,
  192. q, m, D_s, D_s, verbosity=0)
  193. measured = [simu_measured(dbdd.u[0, i]) for i in range(n)]
  194. b, b_hybrid, p_success = estimate_SCA(None, dbdd,
  195. measured, max_guesses)
  196. beta += b
  197. beta_hybrid += b_hybrid
  198. proba_success += p_success
  199. beta /= nb_tests_per_params
  200. beta_hybrid /= nb_tests_per_params
  201. proba_success /= nb_tests_per_params
  202. logging("Attack with hints: %3.2f bikz" % beta, style="HEADER")
  203. logging("Attack with hints and guess: %3.2f bikz"% beta_hybrid, style="HEADER")
  204. logging("Number of guesses: %4d" % max_guesses, style="HEADER")
  205. logging("Success probability: %3.2f" %proba_success, style="HEADER")