|
- from fpylll import *
- from math import log
- from copy import copy
-
- load("../framework/proba_utils.sage")
- load("../framework/utils.sage")
- load("../framework/geometry.sage")
- load("../framework/DBDD_generic.sage")
-
-
- def cannonical_direction_only(fn):
- def decorated(self, *args, **kwargs):
- if not is_cannonical_direction(args[0]):
- raise InvalidHint(
- "Input hint vector must have a cannonical direction")
- return fn(self, *args, **kwargs)
- return decorated
-
-
- class DBDD_predict_diag(DBDD_generic):
- """
- This class defines all the elements defining a DBDD instance in a diagonal
- prediction mode
- """
-
- def __init__(self, B, S, mu, u=None, verbosity=1, **kwargs):
- """constructor that builds a DBDD instance from a lattice, mean, sigma
- and a target
- ;min_dim: Number of coordinates to find to consider the problem solved
- :B: Basis of the lattice
- :S: The Covariance matrix (Sigma) of the uSVP solution
- :mu: The expectation of the uSVP solution
- :u: The unique vector to be found (optinal, for verification purposes)
- :fp_type: Floating point type to use in FPLLL ("d, ld, dd, qd, mpfrX")
- """
- self.verbosity = verbosity
- if not is_diagonal(S):
- raise ValueError("given Σ not diagonal")
-
- self.S = np.array([RR(S[i, i]) for i in range(S.nrows())])
- self.PP = 0 * self.S # Span of the projections so far (orthonormal)
- # Orthogonal span of the intersection so far so far (orthonormal)
- self.PI = 0 * self.S
- self.PI[-1] = 1
- self.u = u
- self.u_original = u
- self._dim = S.nrows()
- self.projections = 0
- self.Bvol = kwargs.get('Bvol', logdet(B))
- self.save = {"save": None}
- self.can_constraints = S.nrows() * [1]
- self.can_constraints[-1] = None
- self.estimate_attack(silent=True)
-
- def dim(self):
- return self._dim
-
- def S_diag(self):
- return copy(self.S)
-
- def volumes(self):
- Bvol = self.Bvol
- Svol = sum([log(abs(x)) for x in (self.S + self.PP + self.PI)])
- dvol = Bvol - Svol / 2.
- return (Bvol, Svol, dvol)
-
- @cannonical_direction_only
- @hint_integration_wrapper(force=True)
- def integrate_perfect_hint(self, V, l):
- i, vi = cannonical_param(V)
- self.can_constraints[i] = None
- if self.PI[i]:
- raise RejectedHint("Redundant hint, Rejected.")
- if self.PP[i]:
- raise InvalidHint("This direction has been projected out.")
-
- assert(vi)
- self.PI[i] = 1
- self.S[i] = 0
- self.Bvol += log(vi)
- self._dim -= 1
-
- @cannonical_direction_only
- @hint_integration_wrapper(force=True)
- def integrate_modular_hint(self, V, l, k, smooth=True):
-
- i, vi = cannonical_param(V)
- f = (k / vi).numerator()
- self.can_constraints[i] = lcm(f, self.can_constraints[i])
- # vs = vi * self.S[i]
- den = vi**2 * self.S[i]
- if den == 0:
- raise RejectedHint("Redundant hint, Rejected.")
- if self.PP[i]:
- raise InvalidHint("This direction has been projected out.")
-
- if not smooth:
- raise NotImplementedError()
-
- self.Bvol += log(k)
-
- @cannonical_direction_only
- @hint_integration_wrapper(force=True)
- def integrate_approx_hint(self, V, l, variance, aposteriori=False):
- if variance < 0:
- raise InvalidHint("variance must be non-negative !")
- if variance == 0:
- raise InvalidHint("variance=0 : must use perfect hint !")
-
- i, vi = cannonical_param(V)
- vs = vi * self.S[i]
- if self.PP[i]:
- raise InvalidHint("This direction has been projected out.")
-
- if not aposteriori:
- d = vs * vi
- self.S[i] -= (1 / (variance + d) * vs) * vs
- else:
- if not vs:
- raise RejectedHint("0-Eigenvector of Σ forbidden,")
- den = vi**2
- self.S[i] = variance / den
-
- @hint_integration_wrapper()
- def integrate_approx_hint_fulldim(self, center, covariance, aposteriori=False):
- # Using http://www.cs.columbia.edu/~liulp/pdf/linear_normal_dist.pdf
- # with A = Id
- if not is_diagonal(covariance):
- raise ValueError("given covariance not diagonal")
-
- if not aposteriori:
- d = len(self.S) - 1
-
- for i in range(d):
- if covariance[i, i] == 0:
- raise InvalidHint("Covariances not full dimensional")
-
- for i in range(d):
- self.S[i] -= self.S[i]**2 / (self.S[i] + covariance[i, i])
-
- # F = (self.S + block4(covariance, zero.T, zero, vec([1]))).inverse()
- # F[-1,-1] = 0
- # self.S -= self.S * F * self.S
- else:
- raise NotImplementedError()
-
- @cannonical_direction_only
- @hint_integration_wrapper(force=False)
- def integrate_short_vector_hint(self, V):
- i, vi = cannonical_param(V)
-
- vi -= vi * self.PP[i]
- den = vi**2
- if den == 0:
- raise InvalidHint("Redundant hint,")
-
- viPI = vi * self.PI[i]
- if viPI**2:
- raise InvalidHint("Not in Span(Λ),")
-
- if vi % self.can_constraints[i]:
- raise InvalidHint("Not in Λ,")
-
- self.projections += 1
- self.Bvol -= log(RR(den)) / 2.
- self._dim -= 1
- self.PP[i] = 1
- self.S[i] = 0
-
- def attack(self):
- self.logging("Can't run the attack in simulation.", style="WARNING")
- return None
|