Skip to content

Commit c975475

Browse files
mkannwischerWardBeullensclaucece
authored
NIST Round 2 (#5)
* switch to to_integer and from_integer * switch to non bitsliced representation * update NISTKATs * change parameters and fix some problems with the latest Sage version * new KATs + remove assert m % 32 == 0 * Versions * Improve CI * Fix * Upgrade * Upgrade 2 * explicitly mention round 2 in README * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update Makefile * Update python-app.yml * Update python-app.yml * Update python-app.yml * Update python-app.yml --------- Co-authored-by: Ward Beullens <[email protected]> Co-authored-by: Sofía Celi <[email protected]> Co-authored-by: Sofía Celi <[email protected]>
1 parent 7db59d7 commit c975475

13 files changed

+1330
-1588
lines changed

.github/workflows/python-app.yml

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ name: Python application
55

66
on:
77
push:
8-
branches: [ "main" ]
8+
branches: [ "main", "MAYO1.1" ]
99
pull_request:
1010
branches: [ "main" ]
1111

@@ -19,18 +19,32 @@ jobs:
1919

2020
steps:
2121
- uses: actions/checkout@v3
22-
- name: Set up Python 3.10
22+
- name: Set up Python 3.12
2323
uses: actions/setup-python@v3
2424
with:
25-
python-version: "3.10"
25+
python-version: "3.12"
2626
- name: Install dependencies
2727
run: |
28+
sudo apt-get update
29+
apt-cache policy sagemath
2830
python -m pip install --upgrade pip
29-
pip install flake8 pytest
30-
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
31-
sudo apt-get install -y make
32-
sudo apt-get install -y sagemath
33-
sage --pip install pycryptodomex
31+
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
32+
bash Miniforge3-$(uname)-$(uname -m).sh -b
33+
source ~/miniforge3/etc/profile.d/conda.sh
34+
conda create -n sage sage python=3.12 -c conda-forge -y
35+
conda run -n sage pip install flake8 pytest
36+
if [ -f requirements.txt ]; then conda run -n sage pip install -r requirements.txt; fi
37+
conda install -y -n sage make -c conda-forge
38+
conda run -n sage sage -pip install pycryptodomex
39+
- name: Check installed versions
40+
run: |
41+
# Print Python version
42+
source $HOME/miniforge3/etc/profile.d/conda.sh
43+
conda run -n sage python --version
44+
conda run -n sage pip --version
45+
conda run -n sage sage --version
3446
- name: Test application
3547
run: |
36-
make test
48+
source $HOME/miniforge3/etc/profile.d/conda.sh
49+
conda activate sage
50+
make test-conda

KAT/PQCsignKAT_24_MAYO_1.rsp

Lines changed: 300 additions & 300 deletions
Large diffs are not rendered by default.

KAT/PQCsignKAT_24_MAYO_2.rsp

Lines changed: 300 additions & 300 deletions
Large diffs are not rendered by default.

KAT/PQCsignKAT_32_MAYO_3.rsp

Lines changed: 300 additions & 300 deletions
Large diffs are not rendered by default.

KAT/PQCsignKAT_40_MAYO_5.rsp

Lines changed: 300 additions & 300 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
This code is part of a NIST submission for the PQC signatures call.
88
```
99

10-
This is the sage implementation of our MAYO scheme. Learn about it on our [website](https://pqmayo.org/).
10+
This is the sage implementation of the round-2 version fo the MAYO scheme. Learn about it on our [website](https://pqmayo.org/).
1111

1212
*Warning*: This code is a research prototype. Do not use it in production.
1313

@@ -17,10 +17,10 @@ In order to natively build, run, test and benchmark the library, you will need t
1717

1818
```
1919
Make
20-
Python3 >= 3.9.7
21-
pycryptodomex (please, install this version to avoid bugs with pycrypto.
20+
Python3 >= 3.12
21+
pycryptodomex >= 3.21 (please, install this version to avoid bugs with pycrypto.
2222
Install it on sage by running 'sage --pip install pycryptodomex')
23-
Sage
23+
Sage >= 10.5
2424
```
2525

2626
## Building and running

mayo.sage

Lines changed: 15 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ try:
99
decode_matrix, \
1010
decode_matrices, \
1111
encode_matrices, \
12-
partial_encode_matrices, \
13-
partial_decode_matrices, \
14-
upper, \
15-
bitsliced_upper, \
16-
bitsliced_matrices_add, \
17-
bitsliced_matrices_matrix_mul, \
18-
bitsliced_matrix_matrices_mul
12+
upper
1913
from sagelib.aes256_ctr_drbg \
2014
import AES256_CTR_DRBG
2115
from sagelib.aes128_ctr \
@@ -33,23 +27,6 @@ F16 = GF(16, names=('x',))
3327
assert x**4 + x+1 == 0
3428
R = F16['z']
3529
(z,) = R._first_ngens(1)
36-
# import itertools
37-
# F.<x> = GF(16)
38-
# R.<y> = F[]
39-
# m = 72
40-
# for c0 in F:
41-
# if c0 in ZZ:
42-
# continue
43-
# f0 = y^m + c0
44-
# for w in range(1,3):
45-
# for js in itertools.combinations(list(range(1,m)), w):
46-
# f = f0 + sum(y^j for j in js)
47-
# if f.is_irreducible():
48-
# print(f)
49-
50-
assert (z**64 + x**3*z**3 + x*z**2 + x**3).is_irreducible()
51-
assert (z**96 + x*z**3 + x*z + x).is_irreducible()
52-
assert (z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2).is_irreducible()
5330

5431
# The parameters for the MAYO variants. They are:
5532
# q (the size of the finite field F_q), m (the number of multivariate quadratic polynomials in the public key),
@@ -58,21 +35,21 @@ assert (z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2).is_irreducible()
5835
DEFAULT_PARAMETERS = {
5936
"mayo_1": {
6037
"name": "mayo1",
61-
"n": 66,
62-
"m": 64,
38+
"n": 86,
39+
"m": 78,
6340
"o": 8,
64-
"k": 9,
41+
"k": 10,
6542
"q": 16,
6643
"sk_salt_bytes": 24,
6744
"pk_bytes": 16,
6845
"digest_bytes": 32,
69-
"f": z**64 + x**3*z**3 + x*z**2 + x**3
46+
"f": z**78 + z**2 + z + x**3
7047
},
7148
"mayo_2": {
7249
"name": "mayo2",
73-
"n": 78,
50+
"n": 81,
7451
"m": 64,
75-
"o": 18,
52+
"o": 17,
7653
"k": 4,
7754
"q": 16,
7855
"sk_salt_bytes": 24,
@@ -82,27 +59,27 @@ DEFAULT_PARAMETERS = {
8259
},
8360
"mayo_3": {
8461
"name": "mayo3",
85-
"n": 99,
86-
"m": 96,
62+
"n": 118,
63+
"m": 108,
8764
"o": 10,
8865
"k": 11,
8966
"q": 16,
9067
"sk_salt_bytes": 32,
9168
"pk_bytes": 16,
9269
"digest_bytes": 48,
93-
"f": z**96 + x*z**3 + x*z + x
70+
"f": z**108 + (x**2+x+1)*z**3 + z**2 + x**3
9471
},
9572
"mayo_5": {
9673
"name": "mayo5",
97-
"n": 133,
98-
"m": 128,
74+
"n": 154,
75+
"m": 142,
9976
"o": 12,
10077
"k": 12,
10178
"q": 16,
10279
"sk_salt_bytes": 40,
10380
"pk_bytes": 16,
10481
"digest_bytes": 64,
105-
"f": z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2
82+
"f": z**142 + z**3 + x**3*z**2 + x**2
10683
},
10784
}
10885

@@ -127,8 +104,7 @@ class Mayo:
127104
self.O_bytes = math.ceil((self.n - self.o)*self.o * self.q_bytes)
128105
self.v_bytes = math.ceil((self.n - self.o) * self.q_bytes)
129106
self.r_bytes = math.ceil(self.k*self.o*self.q_bytes)
130-
self.P1_bytes = math.ceil(
131-
self.m*math.comb((self.n-self.o+1), 2) * self.q_bytes)
107+
self.P1_bytes = math.ceil(self.m*math.comb((self.n-self.o+1), 2) * self.q_bytes)
132108
self.P2_bytes = math.ceil(self.m*(self.n - self.o)*self.o * self.q_bytes)
133109
self.P3_bytes = math.ceil(self.m*math.comb((self.o+1), 2) * self.q_bytes)
134110

@@ -194,6 +170,7 @@ class Mayo:
194170
self.o, self.n-self.o, triangular=True) # {P_i^(1)}_(i in [m]) <- Decode_(P(1))(p[0 : P1_bytes])
195171
p2 = decode_matrices(p[self.P1_bytes:self.P1_bytes+self.P2_bytes],
196172
self.m, self.n-self.o, self.o, triangular=False) # {P_i^(2)}_(i in [m]) <- Decode_(P(2))(p[P1_bytes : P1_bytes + P2_bytes])
173+
197174
# for i from 0 to m − 1 do
198175
# P(3) <- Upper(−O^(T)P_i^(1) O − O^(T)P_i^((2))
199176
p3 = [matrix(F16, self.o, self.o) for _ in range(self.m)]
@@ -204,40 +181,6 @@ class Mayo:
204181
csk = seed_sk # csk <- seedsk
205182
return csk, cpk
206183

207-
def compact_key_gen_bitsliced(self):
208-
"""
209-
outputs a pair (csk, cpk) in B^{csk_bytes} x B^{cpk_bytes}, where csk and cpk
210-
are compact representations of a secret key and public key
211-
"""
212-
seed_sk = self.random_bytes(self.sk_seed_bytes)
213-
214-
s = shake_256(seed_sk).digest(int(self.pk_seed_bytes + self.O_bytes))
215-
seed_pk = s[:self.pk_seed_bytes]
216-
217-
o = decode_matrix(s[self.pk_seed_bytes:self.pk_seed_bytes +
218-
self.O_bytes], self.n-self.o, self.o)
219-
220-
ctr = AES128_CTR(seed_pk, self.P1_bytes + self.P2_bytes)
221-
p = ctr.aes_ctr_gen()
222-
223-
p1 = partial_decode_matrices(p[:self.P1_bytes], self.m, self.n -
224-
self.o, self.n-self.o, triangular=True)
225-
226-
p2 = partial_decode_matrices(p[self.P1_bytes:self.P1_bytes+self.P2_bytes],
227-
self.m, self.n-self.o, self.o, triangular=False)
228-
229-
p3 = [ [ None for _ in range(self.o)] for _ in range(self.o) ]
230-
231-
# compute p1o + p2
232-
p1o_p2 = bitsliced_matrices_add(bitsliced_matrices_matrix_mul(p1,o),p2)
233-
# compute p3
234-
p3 = bitsliced_matrix_matrices_mul(o.transpose(), p1o_p2)
235-
p3 = bitsliced_upper(p3)
236-
237-
cpk = seed_pk + partial_encode_matrices(p3, self.m, self.o, self.o, triangular=True)
238-
csk = seed_sk
239-
return csk, cpk
240-
241184
def expand_sk(self, csk):
242185
"""
243186
takes as input csk, the compact representation of a secret key, and outputs sk in B^{sk_bytes},
@@ -270,43 +213,6 @@ class Mayo:
270213
esk = seed_sk + o_bytestring + p[0:self.P1_bytes] + encode_matrices(l, self.m, self.n-self.o, self.o, triangular=False)
271214
return esk
272215

273-
def expand_sk_bitsliced(self, csk):
274-
"""
275-
takes as input csk, the compact representation of a secret key, and outputs sk in B^{sk_bytes},
276-
an expanded representation of the secret key
277-
"""
278-
assert len(csk) == self.csk_bytes
279-
280-
seed_sk = csk
281-
s = shake_256(seed_sk).digest(int(self.pk_seed_bytes + self.O_bytes))
282-
seed_pk = s[:self.pk_seed_bytes]
283-
284-
o_bytestring = s[self.pk_seed_bytes:self.pk_seed_bytes + self.O_bytes]
285-
o = decode_matrix(o_bytestring, self.n-self.o, self.o)
286-
287-
ctr = AES128_CTR(seed_pk, self.P1_bytes + self.P2_bytes)
288-
p = ctr.aes_ctr_gen()
289-
290-
p1 = partial_decode_matrices(p[:self.P1_bytes], self.m, self.n -
291-
self.o, self.n-self.o, triangular=True)
292-
293-
p2 = partial_decode_matrices(p[self.P1_bytes:self.P1_bytes+self.P2_bytes],
294-
self.m, self.n-self.o, self.o, triangular=False)
295-
296-
# compute (p1 + p1^t)
297-
p1_p1t = p1.copy()
298-
for i in range(self.n-self.o):
299-
p1_p1t[i][i] = (0,0,0,0)
300-
for j in range(i+1,self.n-self.o):
301-
p1_p1t[j][i] = p1_p1t[i][j]
302-
303-
# compute (p1 + p1^t)*o + p2
304-
l = bitsliced_matrices_add(bitsliced_matrices_matrix_mul(p1_p1t, o), p2)
305-
306-
esk = seed_sk + o_bytestring + p[:self.P1_bytes] + partial_encode_matrices(l, self.m, self.n-self.o, self.o, triangular=False)
307-
308-
return esk
309-
310216
def expand_pk(self, cpk):
311217
"""
312218
takes as input cpk and outputs pk in B^{pk_bytes}

parameter_check.sage

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,33 @@ print("Field with 16 elements is correct")
77
Kz = PolynomialRing(K,'z')
88
Kz.inject_variables()
99

10-
# irreducible polynomials for m = 64, 96, and 128
11-
F64 = z**64 + x**3*z**3 + x*z**2 + x**3
12-
F96 = z**96 + x*z**3 + x*z + x
13-
F128 = z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2
10+
# irreducible polynomials
11+
F = {}
12+
F[64] = z**64 + x**3*z**3 + x*z**2 + x**3
13+
F[78] = z**78 + z**2 + z + x**3
14+
F[108] = z**108 + (x**2+x+1)*z**3 + z**2 + x**3
15+
F[142] = z**142 + z**3 + x**3*z**2 + x**2
1416

15-
assert (F64).is_irreducible()
16-
assert (F96).is_irreducible()
17-
assert (F128).is_irreducible()
18-
print("Polynomials are irreducible")
17+
for m in F:
18+
print("F_"+str(m)+" is irreducible: ", F[m].is_irreducible())
1919

2020

21-
for m,k in [(64, 1), (64, 2), (64, 4), (64, 8), (96, 10), (128, 11)]:
22-
if m == 64:
23-
F = F64
24-
if m == 96:
25-
F = F96
26-
if m == 128:
27-
F = F128
21+
for m,k in [(78, 10), (64, 4), (108, 11), (142, 12)]:
22+
Fm = F[m]
2823

29-
CM = companion_matrix(F)
24+
CM = companion_matrix(Fm)
3025

3126
BM = matrix(K, k*m, k*m)
3227
l = k*(k+1)/2-1
28+
assert(l+1 < m)
3329
for i in range(k):
3430
for j in range(k-1,i-1,-1):
3531
BM[ i*m:(i+1)*m, j*m:(j+1)*m ] = CM**l;
3632
BM[ j*m:(j+1)*m, i*m:(i+1)*m ] = CM**l;
3733
l -= 1
3834

39-
assert(l+1 < m)
40-
assert(BM.rank() == m*k)
35+
rk = BM.rank()
36+
print("m,k,rank:", m,k, rk)
37+
assert(rk == m*k)
4138

4239
print("Parameters are correct")

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pycryptodomex==3.16.0
1+
pycryptodomex==3.21.0

test_kat.sage

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ try:
1616
decode_matrix, \
1717
encode_matrix, \
1818
decode_matrices, \
19-
encode_matrices, \
20-
bitslice_m_vec, \
21-
unbitslice_m_vec, \
22-
partial_encode_matrices, \
23-
partial_decode_matrices, \
24-
bitsliced_mul_add
19+
encode_matrices
2520
from sagelib.mayo \
2621
import setupMayo, \
2722
Mayo1, \
@@ -62,7 +57,7 @@ class TestDeterministicDRBGTestValues(unittest.TestCase):
6257
Mayo.set_drbg_seed(seed)
6358

6459
# Assert keygen matches
65-
_sk, _pk = Mayo.compact_key_gen_bitsliced()
60+
_sk, _pk = Mayo.compact_key_gen()
6661
self.assertEqual(pk, _pk)
6762
self.assertEqual(sk, _sk)
6863

0 commit comments

Comments
 (0)