Appendix D: Solutions for Chapter 7
This page collects solutions and editorial notes for the exercises in Chapter 7: Lattices for programmers. Compute and derivation exercises have worked solutions; open-ended exercises have an editorial note describing what a strong answer addresses.
The fuller versions of these routines are in the lattices package under solutions/ch07-lattices. From a clone of the companion repository, pytest tests/ch07 runs its suite. Appendix C has the setup.
Exercise 1: unimodular change of basis
Section titled “Exercise 1: unimodular change of basis”For the chapter’s running example, and . Since , the inverse is , and
Every entry is an integer, and . The second construction reads the same matrix off the columns of . Writing gives the first column ; writing gives the second, . The two constructions agree, and the rest of this solution says why they always do.
In general, let be two bases of the same lattice . The defining property of “same lattice” is that every column of is an integer combination of columns of , and vice versa. Writing this column by column gives a matrix with integer entries such that , and a matrix with integer entries such that . Substituting one into the other gives , so (since has full column rank as a matrix over ). Both and have integer entries, so and are integers, and their product is . Two integers that multiply to 1 must each be , so and is unimodular.
The two constructions in the exercise both produce :
- as matrices over . Because and generate the same lattice, this rational matrix has integer entries.
- as the matrix whose -th column is the integer-coefficient vector expressing the -th column of in the basis . This is just the column-by-column expansion of .
The two constructions are the same calculation written from different starting points, so they must agree. The exercise is the canonical check that two bases generate the same lattice: the change-of-basis matrix between them is integer with determinant .
Exercise 2
Section titled “Exercise 2”The dual-of-dual identity is . Floating-point error means np.allclose(D2, B) is true but D2 == B may not hold exactly. The dual basis has rational entries in general because enters denominators (here , so ‘s entries are multiples of ). Only when is guaranteed integer.
import numpy as npB = np.array([[2, 0, 1], [1, 3, 0], [0, 1, 4]], dtype=float)D = np.linalg.inv(B).TD2 = np.linalg.inv(D).Tprint(np.allclose(D2, B))# ==> TrueExercise 3
Section titled “Exercise 3”. Minkowski’s bound is . The first basis vector has Euclidean norm , which is below the bound. In the given basis its coefficient vector is .
import mathdet_L = 2 * 3 * 5 * 7bound = math.sqrt(4) * det_L ** 0.25print(det_L, round(bound, 3))# ==> 210 7.614Exercise 4
Section titled “Exercise 4”A reference statement to compare against your own version:
- SVP. Input: a basis of a lattice . Output: a nonzero lattice vector with (the minimum nonzero norm).
- CVP. Input: a basis of and a target . Output: a lattice vector minimizing .
- (approximate, search). Input: a basis and a slack factor . Output: a nonzero with .
- (approximate, search). Input: and . Output: with .
- (promise decision). Input: . Decide whether or , promised that one of the two cases holds.
- (promise decision). Input: . Decide whether or , under the same promise.
Keep the search and decision versions apart: returns a vector, while returns one bit. The lattice cryptography literature works with the approximate and promise versions rather than exact SVP or CVP. That is what the worst-case-to-average-case reductions in (Ajtai, 1996) and (Regev, 2009) target: Regev’s Theorem 1.1 reduces from and at an approximation factor , where is the LWE noise rate (Regev, 2009).