Skip to content

Commit

Permalink
refactor polynomial rings to make Kyber values explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
GiacomoPope committed Jul 19, 2024
1 parent 3844f73 commit 93934a8
Show file tree
Hide file tree
Showing 9 changed files with 642 additions and 690 deletions.
73 changes: 7 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,33 +125,20 @@ ring $R_{11} = \mathbb{F}_{11}[X] /(X^8 + 1)$ in the following way:
0
```

We additionally include functions for `PolynomialRing` and `Polynomial`
We additionally include functions for `PolynomialRingKyber` and `PolynomialKyber`
to move from bytes to polynomials (and back again).

- `PolynomialRing`
- `PolynomialRingKyber`
- `parse(bytes)` takes $3n$ bytes and produces a random polynomial in $R_q$
- `decode(bytes, l)` takes $\ell n$ bits and produces a polynomial in $R_q$
- `cbd(beta, eta)` takes $\eta \cdot n / 4$ bytes and produces a polynomial in $R_q$ with coefficents taken from a centered binomial distribution
- `Polynomial`
- `PolynomialKyber`
- `self.encode(l)` takes the polynomial and returns a length $\ell n / 8$ bytearray

#### Example

```python
>>> R = PolynomialRing(11, 8)
>>> f = R.random_element()
>>> # If we do not specify `l` then it is computed for us (minimal value)
>>> f_bytes = f.encode()
>>> f_bytes.hex()
'06258910'
>>> R.decode(f_bytes) == f
True
>>> # We can also set `l` ourselves
>>> f_bytes = f.encode(l=10)
>>> f_bytes.hex()
'00180201408024010000'
>>> R.decode(f_bytes, l=10) == f
True
TODO
```

Lastly, we define a `self.compress(d)` and `self.decompress(d)` method for
Expand All @@ -175,14 +162,7 @@ function on every polynomial.
#### Example

```python
>>> R = PolynomialRing(11, 8)
>>> f = R.random_element()
>>> f
9 + 3*x + 5*x^2 + 2*x^3 + 9*x^4 + 10*x^5 + 6*x^6 + x^7
>>> f.compress(1)
x + x^2 + x^6
>>> f.decompress(1)
6*x + 6*x^2 + 6*x^6
TODO
```

**Note**: compression is lossy! We do not get the same polynomial back
Expand Down Expand Up @@ -256,45 +236,6 @@ lets revisit the ring from the previous example:
[ 2 + 6*x^4 + x^5]
```

We also carry through `Matrix.encode()` and
`Module.decode(bytes, n_rows, n_cols)`
which simply use the above functions defined for polynomials and run for each
element.

#### Example

We can see how encoding / decoding a vector works in the following example.
Note that we can swap the rows/columns to decode bytes into the transpose
when working with a vector.

```python
>>> R = PolynomialRing(11, 8)
>>> M = Module(R)
>>> v = M([R.random_element() for _ in range(2)])
>>> v_bytes = v.encode()
>>> v_bytes.hex()
'd'
>>> M.decode(v_bytes, 1, 2) == v
True
>>> v_bytes = v.encode(l=10)
>>> v_bytes.hex()
'a014020100103004000040240a03009030080200'
>>> M.decode(v_bytes, 1, 2, l=10) == v
True
>>> M.decode(v_bytes, 2, 1, l=10) == v.transpose()
True
>>> # We can also compress and decompress elements of the module
>>> v
[5 + 10*x + 4*x^2 + 2*x^3 + 8*x^4 + 3*x^5 + 2*x^6, 2 + 9*x + 5*x^2 + 3*x^3 + 9*x^4 + 3*x^5 + x^6 + x^7]
>>> v.compress(1)
[1 + x^2 + x^4 + x^5, x^2 + x^3 + x^5]
>>> v.decompress(1)
[6 + 6*x^2 + 6*x^4 + 6*x^5, 6*x^2 + 6*x^3 + 6*x^5]
```

## Baby Kyber

A great resource for learning Kyber is available at
[Approachable Cryptography](https://cryptopedia.dev/posts/kyber/).
### TODO

We include code corresponding to their example in `baby_kyber.py`.
Explain the extra functions available in `ModuleKyber` and `MatrixKyber`.
109 changes: 0 additions & 109 deletions baby-kyber.py

This file was deleted.

25 changes: 9 additions & 16 deletions kyber.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import os
from hashlib import sha3_256, sha3_512, shake_128, shake_256
from polynomials import PolynomialRing
from modules import Module
from ntt_helper import NTTHelperKyber
from polynomials import PolynomialRingKyber
from modules import ModuleKyber

try:
from aes256_ctr_drbg import AES256_CTR_DRBG
except ImportError as e:
Expand All @@ -13,25 +13,20 @@

DEFAULT_PARAMETERS = {
"kyber_512" : {
"n" : 256,
"k" : 2,
"q" : 3329,
"eta_1" : 3,
"eta_2" : 2,
"du" : 10,
"dv" : 4,
},
"kyber_768" : {
"n" : 256,
"k" : 3,
"q" : 3329,
"eta_1" : 2,
"eta_2" : 2,
"du" : 10,
"dv" : 4,
},
"kyber_1024" : {
"n" : 256,
"k" : 4,
"q" : 3329,
"eta_1" : 2,
Expand All @@ -43,16 +38,14 @@

class Kyber:
def __init__(self, parameter_set):
self.n = parameter_set["n"]
self.k = parameter_set["k"]
self.q = parameter_set["q"]
self.eta_1 = parameter_set["eta_1"]
self.eta_2 = parameter_set["eta_2"]
self.du = parameter_set["du"]
self.dv = parameter_set["dv"]

self.R = PolynomialRing(self.q, self.n, ntt_helper=NTTHelperKyber)
self.M = Module(self.R)
self.R = PolynomialRingKyber()
self.M = ModuleKyber()

self.drbg = None
self.random_bytes = os.urandom
Expand Down Expand Up @@ -174,11 +167,11 @@ def _cpapke_keygen(self):

# Generate the error vector s ∈ R^k
s, N = self._generate_error_vector(sigma, self.eta_1, N)
s.to_ntt()
s = s.to_ntt()

# Generate the error vector e ∈ R^k
e, N = self._generate_error_vector(sigma, self.eta_1, N)
e.to_ntt()
e = e.to_ntt()

# Construct the public key
t = (A @ s) + e
Expand Down Expand Up @@ -216,7 +209,7 @@ def _cpapke_enc(self, pk, m, coins):

# Generate the error vector r ∈ R^k
r, N = self._generate_error_vector(coins, self.eta_1, N)
r.to_ntt()
r = r.to_ntt()

# Generate the error vector e1 ∈ R^k
e1, N = self._generate_error_vector(coins, self.eta_2, N)
Expand Down Expand Up @@ -253,7 +246,7 @@ def _cpapke_dec(self, sk, c):

# Recover the vector u and convert to NTT form
u = self.M.decode_vector(c, self.k, l=self.du).decompress(self.du)
u.to_ntt()
u = u.to_ntt()

# Recover the polynomial v
v = self.R.decode(c2, l=self.dv).decompress(self.dv)
Expand Down
Loading

0 comments on commit 93934a8

Please sign in to comment.