@@ -5,7 +5,9 @@ load("../framework/instance_gen.sage") | |||
Derr = build_centered_binomial_law(6) | |||
modulus = 11 | |||
saving_results = True | |||
results_filename = "results.csv" | |||
try: | |||
N_tests = int(sys.argv[1]) | |||
@@ -30,6 +32,13 @@ def randv(): | |||
vv += v(randint(qvec_donttouch, d - 1)) | |||
return vv | |||
def qrandv(): | |||
vv = randint(1, q-1) * v(randint(qvec_donttouch, d - 1)) | |||
vv -= randint(1, q-1) * v(randint(qvec_donttouch, d - 1)) | |||
vv += randint(1, q-1) * v(randint(qvec_donttouch, d - 1)) | |||
vv -= randint(1, q-1) * v(randint(qvec_donttouch, d - 1)) | |||
vv += randint(1, q-1) * v(randint(qvec_donttouch, d - 1)) | |||
return vv | |||
def one_experiment(id, aargs): | |||
(N_hints, T_hints) = aargs | |||
@@ -45,7 +54,6 @@ def one_experiment(id, aargs): | |||
verbosity=0) | |||
for j in range(N_hints): | |||
vv = randv() | |||
print(vv) | |||
if T_hints == "Perfect": | |||
dbdd.integrate_perfect_hint(vv, dbdd.leak(vv), estimate=False) | |||
dbdd_p.integrate_perfect_hint(vv, dbdd_p.leak(vv), estimate=False) | |||
@@ -62,6 +70,7 @@ def one_experiment(id, aargs): | |||
dbdd_p.integrate_modular_hint(vv, dbdd_p.leak(vv) % modulus, | |||
modulus, smooth=True, estimate=False) | |||
if T_hints == "Q-Modular": | |||
vv = qrandv() | |||
dbdd.integrate_q_modular_hint(vv, dbdd.leak(vv) % q, | |||
q, estimate=False) | |||
dbdd_p.integrate_q_modular_hint(vv, dbdd_p.leak(vv) % q, | |||
@@ -81,6 +90,10 @@ def get_stats(data, N_tests): | |||
avg = RR(sum(data)) / N_tests | |||
var = abs(RR(sum([r**2 for r in data])) / N_tests - avg**2) | |||
return (avg, var) | |||
def save_results(*args): | |||
with open(results_filename, 'a') as _file: | |||
_file.write(';'.join([str(arg) for arg in args])+'\n') | |||
def validation_prediction(N_tests, N_hints, T_hints): | |||
# Estimation | |||
@@ -96,11 +109,11 @@ def validation_prediction(N_tests, N_hints, T_hints): | |||
print("Time:", datetime.datetime.now() - ttt) | |||
if saving_results: | |||
with open('results.csv', 'a') as _file: | |||
_file.write(f'{T_hints};{N_hints};{N_tests};{datetime.datetime.now() - ttt};') | |||
_file.write(f'{beta_real};{beta_pred_full};{beta_pred_light};') | |||
_file.write(f'{vbeta_real};{vbeta_pred_full};{vbeta_pred_light};') | |||
_file.write(f'\n') | |||
save_results( | |||
T_hints, N_hints, N_tests, datetime.datetime.now() - ttt, | |||
beta_real, beta_pred_full, beta_pred_light, | |||
vbeta_real, vbeta_pred_full, vbeta_pred_light, | |||
) | |||
return beta_pred_full | |||
@@ -116,39 +129,25 @@ D_e = build_centered_binomial_law(40) | |||
d = m + n | |||
print("\n \n None") | |||
print("hints,\t real,\t pred_full, \t pred_light,") | |||
beta_pred = validation_prediction(N_tests, 0, "None") | |||
print("\n \n Perfect") | |||
print("hints,\t real,\t pred_full, \t pred_light,") | |||
for h in range(1, 100): | |||
beta_pred = validation_prediction(N_tests, h, "Perfect") # Line 0 | |||
if beta_pred < 3: | |||
break | |||
print("\n \n Modular") | |||
print("hints,\t real,\t pred_full, \t pred_light,") | |||
for h in range(2, 200, 2): | |||
beta_pred = validation_prediction(N_tests, h, "Modular") # Line 0 | |||
if beta_pred < 3: | |||
break | |||
print("\n \n Q-Modular") | |||
print("hints,\t real,\t pred_full, \t pred_light,") | |||
for h in range(1, 100): | |||
beta_pred = validation_prediction(N_tests, h, "Q-Modular") # Line 0 | |||
if beta_pred < 3: | |||
break | |||
print("\n \n Approx") | |||
print("hints,\t real,\t pred_full, \t pred_light,") | |||
for h in range(4, 200, 4): | |||
beta_pred = validation_prediction(N_tests, h, "Approx") # Line 0 | |||
if beta_pred < 3: | |||
break | |||
for T_hints in ["Perfect", "Modular", "Q-Modular", "Approx"]: | |||
hint_range = None | |||
if T_hints == "Perfect": | |||
hint_range = range(1, 100) | |||
elif T_hints == "Modular": | |||
hint_range = range(2, 200, 2) | |||
elif T_hints == "Q-Modular": | |||
hint_range = range(1, 100) | |||
elif T_hints == "Approx": | |||
hint_range = range(4, 200, 4) | |||
print(f"\n \n {T_hints}") | |||
print("hints,\t real,\t pred_full, \t pred_light,") | |||
for h in hint_range: | |||
beta_pred = validation_prediction(N_tests, h, T_hints) # Line 0 | |||
if beta_pred < 3: | |||
break |
@@ -30,7 +30,7 @@ class DBDD(DBDD_generic): | |||
self.D = kwargs.get('D', None) # The dual Basis (only B or D is active) | |||
assert self.D.T * self.B == identity_matrix(B.nrows()) | |||
self._dim = B.nrows() | |||
#self._keep_basis = False | |||
self._maintains_basis = True | |||
self.S = S | |||
self.PP = 0 * S # Span of the projections so far (orthonormal) | |||
self.mu = mu | |||
@@ -42,6 +42,7 @@ class DBDD(DBDD_generic): | |||
self.float_type = float_type | |||
self.estimate_attack(silent=True) | |||
self.Pi = identity_matrix(self._dim) # Reduction matrix | |||
self.Gamma = identity_matrix(self._dim) # Substitution matrix | |||
self._restoration_instructions = [] | |||
@@ -100,21 +101,6 @@ class DBDD(DBDD_generic): | |||
else: | |||
self._restoration_instructions.append((type, Gamma, data)) | |||
#@not_after_projections | |||
#@hint_integration_wrapper(force=True, requires=["dual"], invalidates=["primal"]) | |||
#def reduce_dimension(self, Gamma, normalization_matrix=None): | |||
# if normalization_matrix is None: | |||
# normalization_matrix = (Gamma.T * Gamma).inverse() | |||
# normalized_Gamma = Gamma*normalization_matrix | |||
# | |||
# self.D = self.D * Gamma | |||
# self.mu = self.mu * normalized_Gamma | |||
# self.S = normalized_Gamma.T * self.S * normalized_Gamma | |||
# self.PP = 0 * self.S | |||
# | |||
# #self.Pi *= normalized_Gamma | |||
# self.add_restoration_instruction(SUBSTITUTION, Gamma) | |||
@not_after_projections | |||
@hint_integration_wrapper(force=True, requires=["dual"], | |||
invalidates=["primal"]) | |||
@@ -125,11 +111,7 @@ class DBDD(DBDD_generic): | |||
VS = V * self.S | |||
den = scal(VS * V.T) | |||
if den == 0: | |||
raise NotImplementedError('Normally, useless condition') | |||
#raise RejectedHint("Redundant hint") | |||
self.D = lattice_orthogonal_section(self.D, V) | |||
self.D = lattice_orthogonal_section(self.D, V, self._maintains_basis) | |||
self._dim -= 1 | |||
num = self.mu * V.T | |||
@@ -166,24 +148,26 @@ class DBDD(DBDD_generic): | |||
if not smooth: | |||
raise NotImplementedError() | |||
self.D = lattice_modular_intersection(self.D, V, k) | |||
self.D = lattice_modular_intersection(self.D, V, k, self._maintains_basis) | |||
@not_after_projections | |||
@hint_integration_wrapper(force=True, requires=["dual"], invalidates=["primal"]) | |||
def integrate_q_modular_hint(self, v, l, q): | |||
V = concatenate(v, -l) | |||
V = self.get_reduced_hint_vector(V) | |||
V = V % q | |||
if V == 0: | |||
raise RejectedHint("Redundant hint") | |||
_, pivot = V.nonzero_positions()[0] | |||
_, pivot = V.nonzero_positions()[0] # Warning, it is non-zero for F_q! It is why there is "V = V%q" before. | |||
V = V * int(mod(V[0,pivot],q)**(-1)) % q | |||
V = V.apply_map(lambda x: recenter(x,q)) | |||
W = q * canonical_vec(self._dim, pivot) | |||
Gamma = build_standard_substitution_matrix(V, pivot=pivot) | |||
assert scal(V * W.T)/q == 1, f'<V, W> = {scal(V * W.T)/q} != 1' | |||
self.D = lattice_modular_intersection(self.D, V, q) | |||
self.D = lattice_modular_intersection(self.D, V, q, self._maintains_basis) | |||
# So, V/q is a dual vector, and we hope it is a primitive one | |||
## Let build the reduction matrix \Pi | |||
@@ -281,7 +265,7 @@ class DBDD(DBDD_generic): | |||
self.projections += 1 | |||
PV = identity_matrix(V.ncols()) - projection_matrix(V) | |||
try: | |||
self.B = lattice_project_against(self.B, V) | |||
self.B = lattice_project_against(self.B, V, self._maintains_basis) | |||
self._dim -= 1 | |||
except ValueError: | |||
raise InvalidHint("Not in Λ") |
@@ -78,14 +78,35 @@ def cannonical_param(v): | |||
def remove_linear_dependencies(B, dim=None): | |||
nrows = B.nrows() | |||
if dim is None or nrows > dim: | |||
#print(f'Go... [{dim}]') | |||
B = B.LLL() | |||
r = min([i for i in range(B.nrows()) if not B[i].is_zero()]) if dim is None else nrows-dim | |||
B = B[r:] | |||
#print(f'[{nrows}->{B.nrows()}]') | |||
# Determine the number of dependencies | |||
K, r = None, None | |||
if dim is None: | |||
K = B.left_kernel().basis_matrix() # I assume that the cost of "left_kernel" is negligeable before "LLL" | |||
r = K.dimensions()[0] | |||
else: | |||
r = nrows-dim | |||
if r == 1: | |||
# Find a linear dependency | |||
if K is None: | |||
K = B.left_kernel().basis_matrix() | |||
assert K.dimensions()[0] == 1 | |||
combinaison = K[0] | |||
# Detect the redundant vector | |||
pivot, pivot_value = None, None | |||
for ind, value in enumerate(combinaison): | |||
if abs(value) > 0 and (pivot is None or abs(value)<abs(pivot_value)): | |||
pivot, pivot_value = ind, value | |||
B = B[[i for i in range(B.dimensions()[0]) if i != pivot]] | |||
else: | |||
B = B.LLL() | |||
B = B[r:] | |||
return B | |||
def lattice_orthogonal_section(D, V): | |||
def lattice_orthogonal_section(D, V, maintains_basis=True): | |||
""" | |||
Compute the intersection of the lattice L(B) | |||
with the hyperplane orthogonal to Span(V). | |||
@@ -105,18 +126,15 @@ def lattice_orthogonal_section(D, V): | |||
PV = projection_matrix(V) | |||
D = D - D * PV | |||
#print(f'LLL... ({return_basis})', end='') | |||
# Eliminate linear dependencies | |||
#if return_basis: | |||
# D = remove_linear_dependencies(D) | |||
#print(f'{D.nrows()}') | |||
#print('Done.') | |||
if maintains_basis: | |||
D = remove_linear_dependencies(D) | |||
# Go back to the primal | |||
return D | |||
def lattice_project_against(B, V): | |||
def lattice_project_against(B, V, maintains_basis=True): | |||
""" | |||
Compute the projection of the lattice L(B) orthogonally to Span(V). All vectors if V | |||
(or at least their projection on Span(B)) must belong to L(B). | |||
@@ -140,14 +158,14 @@ def lattice_project_against(B, V): | |||
B = B - B * PV | |||
# Eliminate linear dependencies | |||
#if return_basis: | |||
# B = remove_linear_dependencies(B) | |||
if maintains_basis: | |||
B = remove_linear_dependencies(B) | |||
# Go back to the primal | |||
return B | |||
def lattice_modular_intersection(D, V, k): | |||
def lattice_modular_intersection(D, V, k, maintains_basis=True): | |||
""" | |||
Compute the intersection of the lattice L(B) with | |||
the lattice {x | x*V = 0 mod k} | |||
@@ -164,12 +182,11 @@ def lattice_modular_intersection(D, V, k): | |||
# append the equation in the dual | |||
V /= k | |||
# D = dual_basis(B) | |||
D = D.stack(V) | |||
# Eliminate linear dependencies | |||
#if return_basis: | |||
# D = remove_linear_dependencies(D) | |||
if maintains_basis: | |||
D = remove_linear_dependencies(D) | |||
# Go back to the primal | |||
return D |