Skip to content

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.

For the chapter’s running example, B1=(3112)B_1 = \begin{pmatrix} 3 & 1 \\ 1 & 2 \end{pmatrix} and B2=(3413)B_2 = \begin{pmatrix} 3 & 4 \\ 1 & 3 \end{pmatrix}. Since detB1=5\det B_1 = 5, the inverse is B11=15(2113)B_1^{-1} = \tfrac{1}{5} \begin{pmatrix} 2 & -1 \\ -1 & 3 \end{pmatrix}, and

U=B11B2=15(5505)=(1101).U = B_1^{-1} B_2 = \frac{1}{5} \begin{pmatrix} 5 & 5 \\ 0 & 5 \end{pmatrix} = \begin{pmatrix} 1 & 1 \\ 0 & 1 \end{pmatrix}.

Every entry is an integer, and detU=1110=1\det U = 1 \cdot 1 - 1 \cdot 0 = 1. The second construction reads the same matrix off the columns of B2B_2. Writing b1=(3,1)=1b1+0b2b'_1 = (3, 1) = 1 \cdot b_1 + 0 \cdot b_2 gives the first column (1,0)T(1, 0)^T; writing b2=(4,3)=1b1+1b2b'_2 = (4, 3) = 1 \cdot b_1 + 1 \cdot b_2 gives the second, (1,1)T(1, 1)^T. The two constructions agree, and the rest of this solution says why they always do.

In general, let B1,B2B_1, B_2 be two bases of the same lattice LL. The defining property of “same lattice” is that every column of B2B_2 is an integer combination of columns of B1B_1, and vice versa. Writing this column by column gives a matrix UU with integer entries such that B2=B1UB_2 = B_1 U, and a matrix VV with integer entries such that B1=B2VB_1 = B_2 V. Substituting one into the other gives B1=B1UVB_1 = B_1 U V, so UV=InU V = I_n (since B1B_1 has full column rank as a matrix over Q\mathbb{Q}). Both UU and VV have integer entries, so detU\det U and detV\det V are integers, and their product is det(In)=1\det(I_n) = 1. Two integers that multiply to 1 must each be ±1\pm 1, so detU=±1\det U = \pm 1 and UU is unimodular.

The two constructions in the exercise both produce UU:

  • U=B11B2U = B_1^{-1} B_2 as matrices over Q\mathbb{Q}. Because B1B_1 and B2B_2 generate the same lattice, this rational matrix has integer entries.
  • UU as the matrix whose jj-th column is the integer-coefficient vector expressing the jj-th column of B2B_2 in the basis B1B_1. This is just the column-by-column expansion of B11B2B_1^{-1} B_2.

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 ±1\pm 1.

The dual-of-dual identity is (BT)T=B(B^{-T})^{-T} = B. Floating-point error means np.allclose(D2, B) is true but D2 == B may not hold exactly. The dual basis DD has rational entries in general because detB\det B enters denominators (here detB=25\det B = 25, so DD‘s entries are multiples of 1/251/25). Only when detB=1|\det B| = 1 is DD guaranteed integer.

import numpy as np
B = np.array([[2, 0, 1], [1, 3, 0], [0, 1, 4]], dtype=float)
D = np.linalg.inv(B).T
D2 = np.linalg.inv(D).T
print(np.allclose(D2, B))
# ==> True

det(L)=2357=210\det(L) = 2 \cdot 3 \cdot 5 \cdot 7 = 210. Minkowski’s bound is 42101/423.8077.614\sqrt{4} \cdot 210^{1/4} \approx 2 \cdot 3.807 \approx 7.614. The first basis vector b1=(2,0,0,0)b_1 = (2, 0, 0, 0) has Euclidean norm 22, which is below the bound. In the given basis its coefficient vector is (1,0,0,0)(1, 0, 0, 0).

import math
det_L = 2 * 3 * 5 * 7
bound = math.sqrt(4) * det_L ** 0.25
print(det_L, round(bound, 3))
# ==> 210 7.614

A reference statement to compare against your own version:

  • SVP. Input: a basis BB of a lattice LRnL \subset \mathbb{R}^n. Output: a nonzero lattice vector vLv \in L with v=λ1(L)\lVert v \rVert = \lambda_1(L) (the minimum nonzero norm).
  • CVP. Input: a basis BB of LL and a target tRnt \in \mathbb{R}^n. Output: a lattice vector vLv \in L minimizing vt\lVert v - t \rVert.
  • SVPγ\mathrm{SVP}_\gamma (approximate, search). Input: a basis BB and a slack factor γ1\gamma \geq 1. Output: a nonzero vLv \in L with vγλ1(L)\lVert v \rVert \leq \gamma \lambda_1(L).
  • CVPγ\mathrm{CVP}_\gamma (approximate, search). Input: (B,t)(B, t) and γ1\gamma \geq 1. Output: vLv \in L with vtγdist(t,L)\lVert v - t \rVert \leq \gamma \cdot \mathrm{dist}(t, L).
  • GapSVPγ\mathrm{GapSVP}_\gamma (promise decision). Input: (B,d)(B, d). Decide whether λ1(L)d\lambda_1(L) \leq d or λ1(L)>γd\lambda_1(L) > \gamma d, promised that one of the two cases holds.
  • GapCVPγ\mathrm{GapCVP}_\gamma (promise decision). Input: (B,t,d)(B, t, d). Decide whether dist(t,L)d\mathrm{dist}(t, L) \leq d or dist(t,L)>γd\mathrm{dist}(t, L) > \gamma d, under the same promise.

Keep the search and decision versions apart: SVPγ\mathrm{SVP}_\gamma returns a vector, while GapSVPγ\mathrm{GapSVP}_\gamma 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 GapSVP\mathrm{GapSVP} and SIVP\mathrm{SIVP} at an approximation factor O~(n/α)\tilde{O}(n/\alpha), where α\alpha is the LWE noise rate (Regev, 2009).

Ajtai, M. (1996). Generating hard instances of lattice problems (extended abstract). Proceedings of the 28th Annual ACM Symposium on Theory of Computing (STOC), 99–108. https://doi.org/10.1145/237814.237838
Regev, O. (2009). On lattices, learning with errors, random linear codes, and cryptography. Journal of the ACM, 56(6), 34:1-34:40. https://doi.org/10.1145/1568318.1568324