1010"""
1111
1212import numpy as np
13- import sympy
1413import sys
1514
1615class lattice ():
@@ -56,6 +55,19 @@ def volume(self) -> float:
5655 return np .sqrt (np .linalg .det (self .basis * self .basis .T ))
5756
5857
58+ def dual (self ):
59+ """Computes dual-lattice.
60+
61+ Returns:
62+ lattice: Dual-lattice.
63+ """
64+ c = lattice (self .basis )
65+ self .basis_star , self .mu = self .GSO ()
66+ c .basis = np .matmul (np .matmul (np .linalg .inv (self .mu .T ), np .linalg .inv (np .matmul (self .basis_star , self .basis_star .T ))), self .basis_star )
67+ c .basis_star , c .mu = c .GSO ()
68+ return c
69+
70+
5971 def GSO (self , mode : str = "normal" ) -> np .ndarray :
6072 """Gram-Schmidt's method.
6173
@@ -82,7 +94,6 @@ def GSO(self, mode: str = "normal") -> np.ndarray:
8294 self .basis_star [i ] -= self .mu [i , j ] * np .copy (self .basis_star [j ])
8395 if mode == "square" or mode == "both" :
8496 self .B [i ] = np .dot (self .basis_star [i ], self .basis_star [i ])
85-
8697 if mode == "normal" :
8798 return self .basis_star , self .mu
8899 elif mode == "square" :
@@ -171,7 +182,7 @@ def Gauss(self) -> np.ndarray:
171182
172183
173184 def Lagrange (self ) -> np .ndarray :
174- """Lagrange reduction
185+ """Lagrange reduction. This is other name of Gauss().
175186
176187 Returns:
177188 np.ndarray: Lagrange reduced lattice basis matrix.
@@ -199,15 +210,13 @@ def LLL(self, delta: float = 0.99) -> np.ndarray:
199210 np.ndarray: LLL-reduced basis
200211 """
201212 self .B , self .mu = self .GSO (mode = "square" )
202-
203213 k = 1
204214 while k < self .nrows :
205215 for j in range (k )[::- 1 ]:
206216 if abs (self .mu [k , j ]) > 0.5 :
207217 q = round (self .mu [k , j ])
208218 self .basis [k ] -= q * np .copy (self .basis [j ])
209219 self .mu [k , : j + 1 ] -= q * np .copy (self .mu [j , : j + 1 ])
210-
211220 if self .B [k ] >= (delta - self .mu [k , k - 1 ] * self .mu [k , k - 1 ]) * self .B [k - 1 ]:
212221 k += 1
213222 else :
@@ -257,8 +266,19 @@ def DeepLLL(self, delta : float = 0.99) -> np.ndarray:
257266 self .B , self .mu = self .GSO (mode = "square" )
258267 k = max (i - 1 , 0 )
259268 k += 1
260-
261269 return self .basis
270+
271+
272+ def DEEP (self , delta : float = 0.99 ) -> np .ndarray :
273+ """Other name of DeepLLL().
274+
275+ Args:
276+ delta (float, optional): Reduction parameter. Defaults to 0.99.
277+
278+ Returns:
279+ np.ndarray: Deep-LLL-reduced lattice basis matrix.
280+ """
281+ return self .DeepLLL (delta = delta )
262282
263283
264284 def PotLLL (self , delta : float = 0.99 ) -> np .ndarray :
@@ -281,8 +301,7 @@ def PotLLL(self, delta: float = 0.99) -> np.ndarray:
281301 self .mu [l , : j + 1 ] -= q * np .copy (self .mu [j , : j + 1 ])
282302 P = P_min = 1. ; k = 0
283303 for j in range (l )[::- 1 ]:
284- S = np .sum (self .mu [l , j : l ] * self .mu [l , j : l ] * self .B [j : l ])
285- P *= (self .B [l ] + S ) / self .B [j ]
304+ P *= (self .B [l ] + np .sum (self .mu [l , j : l ] * self .mu [l , j : l ] * self .B [j : l ])) / self .B [j ]
286305 if P < P_min : k = j ; P_min = P
287306 if delta > P_min :
288307 t = np .copy (self .basis [l ])
@@ -370,7 +389,7 @@ def _ENUM_(mu: np.ndarray, B: np.ndarray, n: int, delta: float) -> np.ndarray:
370389 w [k ] = 1
371390 else :
372391 k += 1
373- if k == n : return np . zeros ( n , int )
392+ if k == n : return None
374393 r [k - 1 ] = k
375394 if k >= last_nonzero :
376395 last_nonzero = k
@@ -386,7 +405,7 @@ def _ENUM_(mu: np.ndarray, B: np.ndarray, n: int, delta: float) -> np.ndarray:
386405 while True :
387406 pre_ENUM_v = np .copy (ENUM_v )
388407 ENUM_v = _ENUM_ (self .mu , self .B , self .nrows , delta )
389- if np . all ( ENUM_v == 0 ) : return pre_ENUM_v
408+ if ENUM_v is None : return np . matmul ( pre_ENUM_v , self . basis )
390409 delta *= 0.99
391410
392411
@@ -417,45 +436,6 @@ def project_basis(self, k: int, l: int) -> np.ndarray:
417436 return pi_b
418437
419438
420- def BKZ (self , beta : int , delta : float = 0.99 ) -> np .ndarray :
421- """BKZ-reduces a lattice basis matrix(algorithm is from C. P. Schnorr and M. Euchner(1994)).
422-
423- Now this function is very unstable.
424-
425- Args:
426- beta (int): Block size.
427- delta (float, optional): Reduction parameter. Defaults to 0.99.
428-
429- Returns:
430- np.ndarray: BKZ-reduced basis matirx.
431- """
432- self .basis = self .LLL (delta = delta )
433- z = k = 0
434- while z < self .nrows - 2 :
435- print (z )
436- if k == self .nrows - 1 : k = 0
437- k1 = k ; k += 1
438- l = min (k1 + beta , self .nrows ); h = min (l + 1 , self .nrows )
439- self .B , self .mu = self .GSO (mode = "square" )
440- p = lattice (self .basis [k1 : l , k1 : l ])
441- w = p .ENUM_SVP (); s = w @ self .project_basis (k1 , l - 1 )
442- if (not np .all (s == 0 )) and self .B [k1 ] > np .dot (s , s ):
443- z = 0
444- c = lattice (np .zeros ((h + 1 , self .ncols )))
445- c .basis [: k1 ] = np .copy (self .basis [: k1 ])
446- c .basis [k1 ] = w @ self .basis [k1 : l ]
447- c .basis [k : h + 1 ] = np .copy (self .basis [k1 : h ])
448- _ , inds = sympy .Matrix (c .basis ).T .rref ()
449- c .basis = np .copy (c .basis [np .array (inds )]); c .nrows = h
450- c .basis = c .LLL (delta = delta )
451- self .basis [: h ] = np .copy (c .basis )
452- else :
453- z += 1
454- c = lattice (self .basis [: h ])
455- self .basis [: h ] = c .LLL (delta = delta )
456- return self .basis
457-
458-
459439 def Babai (self , w : np .ndarray ):
460440 """Computes an approximate solution of CVP for target w using Babai's nearest plane algorithm(algorithm is from L. Babai(1986)).
461441
@@ -519,7 +499,7 @@ def _ENUM_(mu: np.ndarray, B: np.ndarray, n: int, a: np.ndarray, R: float) -> np
519499 w [k ] = 1
520500 else :
521501 k += 1
522- if k == n : return np . zeros ( n , int )
502+ if k == n : return None
523503 r [k - 1 ] = k
524504 if v [k ] > c [k ]: v [k ] -= w [k ]
525505 else : v [k ] += w [k ]
@@ -528,11 +508,11 @@ def _ENUM_(mu: np.ndarray, B: np.ndarray, n: int, a: np.ndarray, R: float) -> np
528508 self .B , self .mu = self .GSO (mode = "square" )
529509 ENUM_v = np .zeros (self .nrows , int )
530510 babaivec = self .Babai (t ); R = np .dot (babaivec - t , babaivec - t )
531- a = t @ np .linalg .pinv (self .basis )
511+ a = np . matmul ( t , np .linalg .pinv (self .basis ) )
532512 while True :
533513 pre_ENUM_v = np .copy (ENUM_v )
534514 ENUM_v = _ENUM_ (self .mu , self .B , self .nrows , a , R )
535- if np . all ( ENUM_v == 0 ) : return pre_ENUM_v @ self .basis
515+ if ENUM_v is None : return np . matmul ( pre_ENUM_v , self .basis )
536516 R *= 0.99
537517
538518
0 commit comments