7.4 Closest vectors by Kannan embedding
Add one coordinate and a noisy lattice point becomes a short vector that reduction can find.
Many measurement problems end with the same question: a device reports a point that should lie on a known lattice, but noise has pushed it off. Lattice codes in digital communication, integer ambiguity resolution in satellite positioning and rounding in signal processing all ask for the lattice point that produced . That is the closest vector problem. This guide shows the most common way to hand it to a lattice reducer: the Kannan embedding, which turns “close to the lattice” into “short in a lattice one dimension larger”. Rows of every matrix are basis vectors, as in g6k-rs.
CVP and bounded distance decoding
Given a basis of a lattice and a target , CVP asks for a lattice point nearest to . In a decoding problem we know more: was produced as
When , the point is the unique closest lattice point, and the problem is called bounded distance decoding (BDD). Past that radius another lattice point can be as close as , so success means recovering the planted , not merely some nearby point. We measure noise relative to the Gaussian heuristic , which estimates for a random-looking lattice.
The embedding
The small object is the error . The relation is affine, because of the constant , so we homogenize it: append one coordinate to every basis vector and add as a new row with an embedding factor in the new coordinate.
Every vector of the new lattice has the form for integers and . Take and choose with . The result is
Kannan embedding at a glance
- Dimension: .
- Determinant: , because is block triangular.
- Target: with norm .
- Heuristic condition: .
- Extraction: find a reduced row whose last coordinate is , flip its sign so the last entry is , read off , and return .
The heuristic condition says the target is shorter than a typical shortest vector of a random lattice with the same volume. The planting ratio measures the margin: larger is better. It is a heuristic for random-looking lattices, not a proof that is the shortest vector.
Choosing the embedding factor M
is a weight on one extra coordinate. Reduction minimizes the Euclidean norm, so a balanced target has every coordinate of roughly the same size. The coordinates of have typical size , the per-coordinate noise level, so the balanced choice is , not . The difference matters. With the target norm grows by a factor , while grows only like .
The table uses the lattice from the experiments below (, , so ).
| M | target norm | planting ratio | ||
|---|---|---|---|---|
| 0.5 | 77.5 | 147.2 | 1.90 | |
| 0.5 | 108.3 | 154.0 | 1.42 | |
| 0.7 | 108.5 | 148.4 | 1.37 | |
| 0.7 | 151.6 | 155.3 | 1.02 | |
| 0.9 | 139.5 | 149.3 | 1.07 | |
| 0.9 | 194.9 | 156.2 | 0.80 |
Both extremes fail in instructive ways:
- M too large. Any vector with last coordinate is minus a lattice vector. Size reduction of the new row against the reduced is exactly Babai’s nearest-plane step, and a long row is never swapped forward. The embedding degrades to Babai, and the measurements below show identical success counts.
- M too small. Vectors with , of the form for , pay almost nothing for their last coordinate and can compete. must also be a positive integer if the basis stays integral, so is the floor.
Measured on a fixed set of 40 random instances (, separate from the instances in the larger table below), counting how often the planted was recovered:
| M | , LLL | , BKZ-20 |
|---|---|---|
| 1 | 31/40 | 23/40 |
| 31/40 | 30/40 | |
| 27/40 | 27/40 | |
| 19/40 | 24/40 | |
| 13/40 | 6/40 | |
| 13/40 | 6/40 | |
| 13/40 | 6/40 | |
| Babai, same reduction | 13/40 | 4/40 |
Anything from to about works well; from upward the embedding does no better than Babai. A rule that holds up: start at and try a smaller value if you see in the last coordinate of short rows.
What can beat the target
The planting ratio compares the target with a random lattice. Before trusting it, check the vectors this particular construction is guaranteed to contain:
- Inherited vectors with . Their length is at least , so the target must be shorter than , not only shorter than .
- Multiples of the target row with . These are short when happens to lie close to and is tiny.
- Structure in L. A lattice with a dense sublattice or very short vectors (for example, one with many repeated rows) can have competitors that the Gaussian heuristic does not see. The random q-ary lattices used here have no such structure.
A complete example in Rust
The program below builds a random 30-dimensional lattice with , hides a point , adds noise with (so ), and decodes it both ways after LLL and BKZ-10. It needs only g6k-rs = "=0.1.0" in Cargo.toml.
// Decode a noisy lattice point two ways: Babai nearest plane and Kannan embedding.
// Rows of every matrix are basis vectors. Cargo.toml: g6k-rs = "=0.1.0"
use g6k_rs::{BKZParams, GSO, LatticeBasis, babai_nearest_plane, bkz_reduce, lll};
const N: usize = 30; // lattice dimension
const Q: i64 = 10007; // det(L) = Q^(N/2)
// Small deterministic generator so the example needs no extra crates.
struct Rng(u64);
impl Rng {
fn next(&mut self) -> u64 {
self.0 = self.0.wrapping_add(0x9E3779B97F4A7C15);
let mut z = self.0;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB);
z ^ (z >> 31)
}
fn below(&mut self, m: u64) -> i64 { (self.next() % m) as i64 }
fn gauss(&mut self) -> f64 {
let u = ((self.next() >> 11) as f64 / (1u64 << 53) as f64).max(1e-300);
let v = (self.next() >> 11) as f64 / (1u64 << 53) as f64;
(-2.0 * u.ln()).sqrt() * (2.0 * std::f64::consts::PI * v).cos()
}
}
fn reduce(b: &mut LatticeBasis) {
let _ = lll(b);
let _ = bkz_reduce(b, &BKZParams { block_size: 10, max_tours: 8, ..Default::default() });
}
fn main() {
let mut rng = Rng(2);
// 1. A known lattice: rows [Q*I | 0] and [A | I].
let k = N / 2;
let mut b = vec![vec![0i64; N]; N];
for i in 0..k { b[i][i] = Q; }
for i in k..N {
for j in 0..k { b[i][j] = rng.below(Q as u64); }
b[i][i] = 1;
}
// 2. A hidden lattice point v, received as t = v + e.
let x: Vec<i64> = (0..N).map(|_| rng.below(21) - 10).collect();
let v: Vec<i64> = (0..N).map(|j| (0..N).map(|i| x[i] * b[i][j]).sum()).collect();
let sigma = 17.0; // per-coordinate noise size
let e: Vec<i64> = (0..N).map(|_| (sigma * rng.gauss()).round() as i64).collect();
let t: Vec<i64> = (0..N).map(|j| v[j] + e[j]).collect();
let e_norm = e.iter().map(|&c| (c * c) as f64).sum::<f64>().sqrt();
println!("||e|| = {:.1}", e_norm);
// 3a. Babai nearest plane on a reduced basis.
let mut lb = LatticeBasis::from_integers(&b);
reduce(&mut lb);
let gso = GSO::new(&lb);
let tf: Vec<f64> = t.iter().map(|&c| c as f64).collect();
let np = babai_nearest_plane(&lb, &gso, &tf);
let babai_ok = np.closest.iter().zip(&v).all(|(a, &b)| (a - b as f64).abs() < 0.5);
println!("Babai nearest plane: distance {:.1}, found v: {}", np.dist_sq.sqrt(), babai_ok);
// 3b. Kannan embedding: rows [B | 0] and [t | M], with M about sigma.
let m = sigma.round() as i64;
let mut rows: Vec<Vec<i64>> = b.iter().map(|r| { let mut r = r.clone(); r.push(0); r }).collect();
let mut last = t.clone();
last.push(m);
rows.push(last);
let mut kb = LatticeBasis::from_integers(&rows);
reduce(&mut kb);
// 4. Extract: a row with last coordinate +-M is +-(e, M).
for (i, r) in kb.basis.iter().enumerate() {
if (r[N].abs() - m as f64).abs() < 0.5 {
let s = r[N].signum();
let e_hat: Vec<i64> = (0..N).map(|j| (s * r[j]).round() as i64).collect();
let v_hat: Vec<i64> = (0..N).map(|j| t[j] - e_hat[j]).collect();
println!("Kannan: row {} has last coordinate {}, norm {:.1}, found v: {}",
i, r[N], kb.norm_sq(i).sqrt(), v_hat == v);
break;
}
}
}Output with seed 2 (cargo run --release):
||e|| = 100.4
Babai nearest plane: distance 171.7, found v: false
Kannan: row 0 has last coordinate 17, norm 101.8, found v: trueThis seed was chosen to show a case where the two methods disagree; with most seeds at this noise level both succeed. Babai returned a lattice point at distance 171.7, farther than the true error of 100.4, because did not fit inside the Gram–Schmidt box of the reduced basis. The embedding found as the first reduced row, with norm .
Measured success rates at n = 20, 30, 40
Each cell counts recoveries of the planted point over 40 random instances (fixed seeds, identical instances in every column). Kannan uses equal to rounded to the nearest integer. Babai runs nearest plane on the basis reduced the same way.
| n | LLL: Babai / Kannan | BKZ-10: Babai / Kannan | BKZ-20: Babai / Kannan | |
|---|---|---|---|---|
| 20 | 0.5 | 40 / 40 | 39 / 40 | 40 / 40 |
| 20 | 0.7 | 36 / 40 | 33 / 40 | 36 / 40 |
| 20 | 0.9 | 21 / 30 | 25 / 31 | 19 / 30 |
| 20 | 1.1 | 8 / 15 | 9 / 18 | 7 / 17 |
| 30 | 0.5 | 38 / 40 | 38 / 40 | 39 / 40 |
| 30 | 0.7 | 25 / 37 | 33 / 40 | 25 / 40 |
| 30 | 0.9 | 14 / 19 | 14 / 34 | 10 / 36 |
| 30 | 1.1 | 2 / 3 | 3 / 12 | 4 / 10 |
| 40 | 0.5 | 36 / 40 | 39 / 40 | 40 / 40 |
| 40 | 0.7 | 16 / 25 | 25 / 40 | 14 / 39 |
| 40 | 0.9 | 4 / 7 | 4 / 19 | 3 / 30 |
| 40 | 1.1 | 0 / 2 | 0 / 6 | 0 / 8 |
Three patterns stand out.
- Up to half the Gaussian heuristic, Babai is enough. Both methods recover nearly every point. Babai is also cheaper when you decode many targets: reduce the basis once, then each target costs one nearest-plane pass. The embedding needs a fresh reduction per target.
- Between 0.7 and 0.9, the embedding pulls ahead, and stronger reduction widens the gap. At and , BKZ-20 on the embedding decodes 30 of 40 points against Babai’s 3.
- Past the Gaussian heuristic, nothing is reliable. At 1.1 the error is larger than half the expected shortest vector, so the planted point need not be the closest lattice point, and no decoder can be expected to return it.
With 40 trials a count moves by a few points from sampling alone, which explains small inversions such as Babai doing slightly better after BKZ-10 than after BKZ-20 in some rows. On the lattice the reductions themselves are ordered as expected: the first basis vector has norm 220.6 after LLL, 178.4 after BKZ-10, 174.3 after BKZ-20 and 161.8 after BKZ-30.
Scaling up
The embedding adds a single dimension, so the cost is that of reducing an -dimensional lattice well enough to expose a vector that is shorter than expected by the planting ratio. Smaller ratios need larger BKZ block sizes, which is where sieve-backed BKZ and progressive strategies from the recipes page come in; the BKZ chapter explains the trade-off. The same homogenization step reappears whenever an equation has a constant term, most directly in short solutions of Ax = b.
Common mistakes
- Setting M to the full error norm. The target becomes times longer and the embedding behaves like Babai. Match to one coordinate of .
- Reading the wrong row. The first reduced row is not always the target. Search for a row whose last coordinate is and verify .
- Forgetting the sign. Reduction returns or . Normalize so the last coordinate is before subtracting.
- Mixing conventions. With column bases the new vector is a column and goes in the last column. Pick rows or columns and keep it throughout.
- Unscaled coordinates. If some coordinates of are much larger than others, weight them first so the error is roughly isotropic, as in Diophantine approximation.
Further reading
Ravi Kannan, “Minkowski’s convex body theorem and integer programming”, Mathematics of Operations Research 12(3), 1987, introduces the embedding. László Babai, “On Lovász’ lattice reduction and the nearest lattice point problem”, Combinatorica 6, 1986, gives the nearest-plane algorithm. For the positioning application, see P. J. G. Teunissen, “The least-squares ambiguity decorrelation adjustment”, Journal of Geodesy 70, 1995. Daniele Micciancio and Shafi Goldwasser’s book Complexity of Lattice Problems (2002) covers CVP, BDD and the reductions between them.