Exercise - Manual Kyber Computation

Updated 4 Oct 2026

Exercise Solution: Manual Kyber Computation

Given:

  • q=17q = 17, A=[3572]A = \begin{bmatrix} 3 & 5 \\ 7 & 2 \end{bmatrix}, s=[21]s = \begin{bmatrix} 2 \\ 1 \end{bmatrix}, e=[11]e = \begin{bmatrix} 1 \\ 1 \end{bmatrix}
  • r=[12]r = \begin{bmatrix} 1 \\ 2 \end{bmatrix}, m=1m = 1, e1=[10]e_1 = \begin{bmatrix} 1 \\ 0 \end{bmatrix}, e2=1e_2 = 1

Step 1: Public Key t=As+e(mod17)t = As + e \pmod{17}

Compute AsAs:

As=[3572][21]=[(3)(2)+(5)(1)(7)(2)+(2)(1)]=[6+514+2]=[1116]As = \begin{bmatrix} 3 & 5 \\ 7 & 2 \end{bmatrix} \begin{bmatrix} 2 \\ 1 \end{bmatrix} = \begin{bmatrix} (3)(2) + (5)(1) \\ (7)(2) + (2)(1) \end{bmatrix} = \begin{bmatrix} 6 + 5 \\ 14 + 2 \end{bmatrix} = \begin{bmatrix} 11 \\ 16 \end{bmatrix}

Add noise ee:

t=As+e=[1116]+[11]=[1217](mod17)=[120]t = As + e = \begin{bmatrix} 11 \\ 16 \end{bmatrix} + \begin{bmatrix} 1 \\ 1 \end{bmatrix} = \begin{bmatrix} 12 \\ 17 \end{bmatrix} \pmod{17} = \begin{bmatrix} 12 \\ 0 \end{bmatrix}

t=[120]\boxed{t = \begin{bmatrix} 12 \\ 0 \end{bmatrix}}

Public key is pk=(A,t)pk = (A, t). Bob keeps sk=s=[2,1]Tsk = s = [2, 1]^T secret.


Step 2a: Ciphertext u=ATr+e1(mod17)u = A^T r + e_1 \pmod{17}

First, compute ATA^T:
AT=[3752]A^T = \begin{bmatrix} 3 & 7 \\ 5 & 2 \end{bmatrix}

Compute ATrA^T r:
ATr=[3752][12]=[(3)(1)+(7)(2)(5)(1)+(2)(2)]=[3+145+4]=[179]A^T r = \begin{bmatrix} 3 & 7 \\ 5 & 2 \end{bmatrix} \begin{bmatrix} 1 \\ 2 \end{bmatrix} = \begin{bmatrix} (3)(1) + (7)(2) \\ (5)(1) + (2)(2) \end{bmatrix} = \begin{bmatrix} 3 + 14 \\ 5 + 4 \end{bmatrix} = \begin{bmatrix} 17 \\ 9 \end{bmatrix}

Add noise e1e_1:
u=ATr+e1=[179]+[10]=[189](mod17)=[19]u = A^T r + e_1 = \begin{bmatrix} 17 \\ 9 \end{bmatrix} + \begin{bmatrix} 1 \\ 0 \end{bmatrix} = \begin{bmatrix} 18 \\ 9 \end{bmatrix} \pmod{17} = \begin{bmatrix} 1 \\ 9 \end{bmatrix}

u=[19]\boxed{u = \begin{bmatrix} 1 \\ 9 \end{bmatrix}}

Step 2b: Ciphertext v=tTr+e2+⌊q/2⌋⋅m(mod17)v = t^T r + e_2 + \lfloor q/2 \rfloor \cdot m \pmod{17}

Compute ⌊q/2⌋\lfloor q/2 \rfloor:
⌊172⌋=⌊8.5⌋=8\left\lfloor \frac{17}{2} \right\rfloor = \lfloor 8.5 \rfloor = 8
Compute tTrt^T r:
tTr=[120][12]=(12)(1)+(0)(2)=12t^T r = \begin{bmatrix} 12 & 0 \end{bmatrix} \begin{bmatrix} 1 \\ 2 \end{bmatrix} = (12)(1) + (0)(2) = 12
Add e2e_2 and message encoding ⌊q/2⌋⋅m\lfloor q/2 \rfloor \cdot m:
v=12+1+8⋅1=12+1+8=21(mod17)=4v = 12 + 1 + 8 \cdot 1 = 12 + 1 + 8 = 21 \pmod{17} = 4

v=4\boxed{v = 4}

Note: m=1m = 1 is encoded as ⌊q/2⌋=8\lfloor q/2 \rfloor = 8 so it sits roughly in the "upper half" of Zq\mathbb{Z}_q. If m=0m = 0 it adds nothing. This is how a single bit is hidden inside the ciphertext.


Step 3: Bob Computes v−sTu(mod17)v - s^T u \pmod{17}

Compute sTus^T u:

sTu=[21][19]=(2)(1)+(1)(9)=2+9=11s^T u = \begin{bmatrix} 2 & 1 \end{bmatrix} \begin{bmatrix} 1 \\ 9 \end{bmatrix} = (2)(1) + (1)(9) = 2 + 9 = 11

Subtract from vv:

v−sTu=4−11=−7(mod17)=10v - s^T u = 4 - 11 = -7 \pmod{17} = 10

v−sTu=10\boxed{v - s^T u = 10}

Why does this work? Expanding the math:v - s^T u = (t^T r + e_2 + \lfloor q/2 \rfloor m) - s^T(A^T r + e_1)$$$$= t^T r - s^T A^T r + e_2 - s^T e_1 + \lfloor q/2 \rfloor m

Since t=As+et = As + e, we have tT=sTAT+eTt^T = s^T A^T + e^T, so tTr−sTATr=eTrt^T r - s^T A^T r = e^T r (small noise).
The result is approximately ⌊q/2⌋⋅m\lfloor q/2 \rfloor \cdot m plus small noise terms.


Step 4: Recover mm

We got v−sTu=10v - s^T u = 10.

Now check: is 1010 closer to 00 or to ⌊q/2⌋=8\lfloor q/2 \rfloor = 8?

ValueDistance to 00Distance to 88
10101010∥10−8∥=2\|10 - 8\| = 2 ✅

Since 1010 is closer to 88 (which represents m=1m = 1) than to 00 (which represents m=0m = 0):

m=1✓\boxed{m = 1} \quad \checkmark

Decoding rule:

  • If result is close to 00 → m=0m = 0
  • If result is close to ⌊q/2⌋=8\lfloor q/2 \rfloor = 8 → m=1m = 1

The threshold is at q/4≈4.25q/4 \approx 4.25. Values in [0,4][0, 4] decode to 00; values in [5,12][5, 12] decode to 11; and so on (wrapping around mod qq).

The noise terms (eTr−sTe1e^T r - s^T e_1) were small enough not to push us past the threshold — that's the whole design!


Step 5: Shared Key K=H(m)K = H(m)

Both Alice and Bob recovered the same m=1m = 1, so they compute:

K=H(1)\boxed{K = H(1)}

In real Kyber, HH = SHA3-256 (or SHAKE-256 for the final KDF):

K=SHAKE256(K′∥H(c))K = \text{SHAKE256}(K' \| H(c))

In this toy example with m=1m = 1:

K=H(1)=SHA3-256(1)=67... (some 256-bit value)K = H(1) = \text{SHA3-256}(1) = \texttt{67...} \text{ (some 256-bit value)}

Both parties now share the same secret key KK, which is used for symmetric encryption:

C=AES-GCM(K,message)C = \text{AES-GCM}(K, \text{message})


Full Solution Summary

StepFormulaResult
1. Public keyt=As+e(mod17)t = As + e \pmod{17}t=[12,0]Tt = [12, 0]^T
2a. Ciphertext uuu=ATr+e1(mod17)u = A^T r + e_1 \pmod{17}u=[1,9]Tu = [1, 9]^T
2b. Ciphertext vvv=tTr+e2+8m(mod17)v = t^T r + e_2 + 8m \pmod{17}v=4v = 4
3. Bob's decryptionv−sTu(mod17)v - s^T u \pmod{17}1010
4. Recover mm10≈8=⌊q/2⌋10 \approx 8 = \lfloor q/2 \rfloorm=1m = 1 ✅
5. Shared keyK=H(m)K = H(m)K=H(1)K = H(1)