Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3aeaf47
switch to to_integer and from_integer
mkannwischer Aug 14, 2023
0e41425
switch to non bitsliced representation
mkannwischer Aug 14, 2023
0f96712
update NISTKATs
mkannwischer Aug 16, 2023
97b3853
change parameters and fix some problems with the latest Sage version
WardBeullens Feb 27, 2024
cb5d509
new KATs + remove assert m % 32 == 0
WardBeullens Dec 3, 2024
e899910
Versions
claucece Jan 6, 2025
0e268ed
Improve CI
claucece Jan 6, 2025
53ec426
Fix
claucece Jan 6, 2025
e1d0267
Upgrade
claucece Jan 6, 2025
bcd86fd
Upgrade 2
claucece Jan 6, 2025
371401e
explicitly mention round 2 in README
mkannwischer Feb 3, 2025
abf6f03
Update python-app.yml
claucece Feb 3, 2025
6c2c2b0
Update python-app.yml
claucece Feb 3, 2025
091f9bd
Update python-app.yml
claucece Feb 3, 2025
62eed47
Update python-app.yml
claucece Feb 3, 2025
d67e92d
Update python-app.yml
claucece Feb 3, 2025
5b27d8f
Update python-app.yml
claucece Feb 3, 2025
ad6ecdd
Update python-app.yml
claucece Feb 3, 2025
a5e4dd7
Update python-app.yml
claucece Feb 3, 2025
0f57a9f
Update python-app.yml
claucece Feb 3, 2025
2b541c2
Update python-app.yml
claucece Feb 3, 2025
3c60ecc
Update python-app.yml
claucece Feb 3, 2025
2699998
Update python-app.yml
claucece Feb 3, 2025
f6dca8a
Update python-app.yml
claucece Feb 3, 2025
1a9c127
Update python-app.yml
claucece Feb 3, 2025
b4aab2e
Update Makefile
claucece Feb 3, 2025
12cff27
Update python-app.yml
claucece Feb 3, 2025
fb04087
Update python-app.yml
claucece Feb 3, 2025
6b7d61c
Update python-app.yml
claucece Feb 3, 2025
86926aa
Update python-app.yml
claucece Feb 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ name: Python application

on:
push:
branches: [ "main" ]
branches: [ "main", "MAYO1.1" ]
pull_request:
branches: [ "main" ]

Expand All @@ -19,18 +19,32 @@ jobs:

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
- name: Set up Python 3.12
uses: actions/setup-python@v3
with:
python-version: "3.10"
python-version: "3.12"
- name: Install dependencies
run: |
sudo apt-get update
apt-cache policy sagemath
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
sudo apt-get install -y make
sudo apt-get install -y sagemath
sage --pip install pycryptodomex
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
bash Miniforge3-$(uname)-$(uname -m).sh -b
source ~/miniforge3/etc/profile.d/conda.sh
conda create -n sage sage python=3.12 -c conda-forge -y
conda run -n sage pip install flake8 pytest
if [ -f requirements.txt ]; then conda run -n sage pip install -r requirements.txt; fi
conda install -y -n sage make -c conda-forge
conda run -n sage sage -pip install pycryptodomex
- name: Check installed versions
run: |
# Print Python version
source $HOME/miniforge3/etc/profile.d/conda.sh
conda run -n sage python --version
conda run -n sage pip --version
conda run -n sage sage --version
- name: Test application
run: |
make test
source $HOME/miniforge3/etc/profile.d/conda.sh
conda activate sage
make test-conda
600 changes: 300 additions & 300 deletions KAT/PQCsignKAT_24_MAYO_1.rsp

Large diffs are not rendered by default.

600 changes: 300 additions & 300 deletions KAT/PQCsignKAT_24_MAYO_2.rsp

Large diffs are not rendered by default.

600 changes: 300 additions & 300 deletions KAT/PQCsignKAT_32_MAYO_3.rsp

Large diffs are not rendered by default.

600 changes: 300 additions & 300 deletions KAT/PQCsignKAT_40_MAYO_5.rsp

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ run: pyfiles
test: pyfiles
sage test_mayo.sage

test-conda: pyfiles
conda run -n sage sage test_mayo.sage

params-check: pyfiles
sage parameter_check.sage

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
This code is part of a NIST submission for the PQC signatures call.
```

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

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

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

```
Make
Python3 >= 3.9.7
pycryptodomex (please, install this version to avoid bugs with pycrypto.
Python3 >= 3.12
pycryptodomex >= 3.21 (please, install this version to avoid bugs with pycrypto.
Install it on sage by running 'sage --pip install pycryptodomex')
Sage
Sage >= 10.5
```

## Building and running
Expand Down
124 changes: 15 additions & 109 deletions mayo.sage
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,7 @@ try:
decode_matrix, \
decode_matrices, \
encode_matrices, \
partial_encode_matrices, \
partial_decode_matrices, \
upper, \
bitsliced_upper, \
bitsliced_matrices_add, \
bitsliced_matrices_matrix_mul, \
bitsliced_matrix_matrices_mul
upper
from sagelib.aes256_ctr_drbg \
import AES256_CTR_DRBG
from sagelib.aes128_ctr \
Expand All @@ -33,23 +27,6 @@ F16 = GF(16, names=('x',))
assert x**4 + x+1 == 0
R = F16['z']
(z,) = R._first_ngens(1)
# import itertools
# F.<x> = GF(16)
# R.<y> = F[]
# m = 72
# for c0 in F:
# if c0 in ZZ:
# continue
# f0 = y^m + c0
# for w in range(1,3):
# for js in itertools.combinations(list(range(1,m)), w):
# f = f0 + sum(y^j for j in js)
# if f.is_irreducible():
# print(f)

assert (z**64 + x**3*z**3 + x*z**2 + x**3).is_irreducible()
assert (z**96 + x*z**3 + x*z + x).is_irreducible()
assert (z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2).is_irreducible()

# The parameters for the MAYO variants. They are:
# q (the size of the finite field F_q), m (the number of multivariate quadratic polynomials in the public key),
Expand All @@ -58,21 +35,21 @@ assert (z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2).is_irreducible()
DEFAULT_PARAMETERS = {
"mayo_1": {
"name": "mayo1",
"n": 66,
"m": 64,
"n": 86,
"m": 78,
"o": 8,
"k": 9,
"k": 10,
"q": 16,
"sk_salt_bytes": 24,
"pk_bytes": 16,
"digest_bytes": 32,
"f": z**64 + x**3*z**3 + x*z**2 + x**3
"f": z**78 + z**2 + z + x**3
},
"mayo_2": {
"name": "mayo2",
"n": 78,
"n": 81,
"m": 64,
"o": 18,
"o": 17,
"k": 4,
"q": 16,
"sk_salt_bytes": 24,
Expand All @@ -82,27 +59,27 @@ DEFAULT_PARAMETERS = {
},
"mayo_3": {
"name": "mayo3",
"n": 99,
"m": 96,
"n": 118,
"m": 108,
"o": 10,
"k": 11,
"q": 16,
"sk_salt_bytes": 32,
"pk_bytes": 16,
"digest_bytes": 48,
"f": z**96 + x*z**3 + x*z + x
"f": z**108 + (x**2+x+1)*z**3 + z**2 + x**3
},
"mayo_5": {
"name": "mayo5",
"n": 133,
"m": 128,
"n": 154,
"m": 142,
"o": 12,
"k": 12,
"q": 16,
"sk_salt_bytes": 40,
"pk_bytes": 16,
"digest_bytes": 64,
"f": z**128 + x*z**4 + x**2*z**3 + x**3*z + x**2
"f": z**142 + z**3 + x**3*z**2 + x**2
},
}

Expand All @@ -127,8 +104,7 @@ class Mayo:
self.O_bytes = math.ceil((self.n - self.o)*self.o * self.q_bytes)
self.v_bytes = math.ceil((self.n - self.o) * self.q_bytes)
self.r_bytes = math.ceil(self.k*self.o*self.q_bytes)
self.P1_bytes = math.ceil(
self.m*math.comb((self.n-self.o+1), 2) * self.q_bytes)
self.P1_bytes = math.ceil(self.m*math.comb((self.n-self.o+1), 2) * self.q_bytes)
self.P2_bytes = math.ceil(self.m*(self.n - self.o)*self.o * self.q_bytes)
self.P3_bytes = math.ceil(self.m*math.comb((self.o+1), 2) * self.q_bytes)

Expand Down Expand Up @@ -194,6 +170,7 @@ class Mayo:
self.o, self.n-self.o, triangular=True) # {P_i^(1)}_(i in [m]) <- Decode_(P(1))(p[0 : P1_bytes])
p2 = decode_matrices(p[self.P1_bytes:self.P1_bytes+self.P2_bytes],
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])

# for i from 0 to m − 1 do
# P(3) <- Upper(−O^(T)P_i^(1) O − O^(T)P_i^((2))
p3 = [matrix(F16, self.o, self.o) for _ in range(self.m)]
Expand All @@ -204,40 +181,6 @@ class Mayo:
csk = seed_sk # csk <- seedsk
return csk, cpk

def compact_key_gen_bitsliced(self):
"""
outputs a pair (csk, cpk) in B^{csk_bytes} x B^{cpk_bytes}, where csk and cpk
are compact representations of a secret key and public key
"""
seed_sk = self.random_bytes(self.sk_seed_bytes)

s = shake_256(seed_sk).digest(int(self.pk_seed_bytes + self.O_bytes))
seed_pk = s[:self.pk_seed_bytes]

o = decode_matrix(s[self.pk_seed_bytes:self.pk_seed_bytes +
self.O_bytes], self.n-self.o, self.o)

ctr = AES128_CTR(seed_pk, self.P1_bytes + self.P2_bytes)
p = ctr.aes_ctr_gen()

p1 = partial_decode_matrices(p[:self.P1_bytes], self.m, self.n -
self.o, self.n-self.o, triangular=True)

p2 = partial_decode_matrices(p[self.P1_bytes:self.P1_bytes+self.P2_bytes],
self.m, self.n-self.o, self.o, triangular=False)

p3 = [ [ None for _ in range(self.o)] for _ in range(self.o) ]

# compute p1o + p2
p1o_p2 = bitsliced_matrices_add(bitsliced_matrices_matrix_mul(p1,o),p2)
# compute p3
p3 = bitsliced_matrix_matrices_mul(o.transpose(), p1o_p2)
p3 = bitsliced_upper(p3)

cpk = seed_pk + partial_encode_matrices(p3, self.m, self.o, self.o, triangular=True)
csk = seed_sk
return csk, cpk

def expand_sk(self, csk):
"""
takes as input csk, the compact representation of a secret key, and outputs sk in B^{sk_bytes},
Expand Down Expand Up @@ -270,43 +213,6 @@ class Mayo:
esk = seed_sk + o_bytestring + p[0:self.P1_bytes] + encode_matrices(l, self.m, self.n-self.o, self.o, triangular=False)
return esk

def expand_sk_bitsliced(self, csk):
"""
takes as input csk, the compact representation of a secret key, and outputs sk in B^{sk_bytes},
an expanded representation of the secret key
"""
assert len(csk) == self.csk_bytes

seed_sk = csk
s = shake_256(seed_sk).digest(int(self.pk_seed_bytes + self.O_bytes))
seed_pk = s[:self.pk_seed_bytes]

o_bytestring = s[self.pk_seed_bytes:self.pk_seed_bytes + self.O_bytes]
o = decode_matrix(o_bytestring, self.n-self.o, self.o)

ctr = AES128_CTR(seed_pk, self.P1_bytes + self.P2_bytes)
p = ctr.aes_ctr_gen()

p1 = partial_decode_matrices(p[:self.P1_bytes], self.m, self.n -
self.o, self.n-self.o, triangular=True)

p2 = partial_decode_matrices(p[self.P1_bytes:self.P1_bytes+self.P2_bytes],
self.m, self.n-self.o, self.o, triangular=False)

# compute (p1 + p1^t)
p1_p1t = p1.copy()
for i in range(self.n-self.o):
p1_p1t[i][i] = (0,0,0,0)
for j in range(i+1,self.n-self.o):
p1_p1t[j][i] = p1_p1t[i][j]

# compute (p1 + p1^t)*o + p2
l = bitsliced_matrices_add(bitsliced_matrices_matrix_mul(p1_p1t, o), p2)

esk = seed_sk + o_bytestring + p[:self.P1_bytes] + partial_encode_matrices(l, self.m, self.n-self.o, self.o, triangular=False)

return esk

def expand_pk(self, cpk):
"""
takes as input cpk and outputs pk in B^{pk_bytes}
Expand Down
33 changes: 15 additions & 18 deletions parameter_check.sage
Original file line number Diff line number Diff line change
Expand Up @@ -7,36 +7,33 @@ print("Field with 16 elements is correct")
Kz = PolynomialRing(K,'z')
Kz.inject_variables()

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

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


for m,k in [(64, 1), (64, 2), (64, 4), (64, 8), (96, 10), (128, 11)]:
if m == 64:
F = F64
if m == 96:
F = F96
if m == 128:
F = F128
for m,k in [(78, 10), (64, 4), (108, 11), (142, 12)]:
Fm = F[m]

CM = companion_matrix(F)
CM = companion_matrix(Fm)

BM = matrix(K, k*m, k*m)
l = k*(k+1)/2-1
assert(l+1 < m)
for i in range(k):
for j in range(k-1,i-1,-1):
BM[ i*m:(i+1)*m, j*m:(j+1)*m ] = CM**l;
BM[ j*m:(j+1)*m, i*m:(i+1)*m ] = CM**l;
l -= 1

assert(l+1 < m)
assert(BM.rank() == m*k)
rk = BM.rank()
print("m,k,rank:", m,k, rk)
assert(rk == m*k)

print("Parameters are correct")
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pycryptodomex==3.16.0
pycryptodomex==3.21.0
9 changes: 2 additions & 7 deletions test_kat.sage
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ try:
decode_matrix, \
encode_matrix, \
decode_matrices, \
encode_matrices, \
bitslice_m_vec, \
unbitslice_m_vec, \
partial_encode_matrices, \
partial_decode_matrices, \
bitsliced_mul_add
encode_matrices
from sagelib.mayo \
import setupMayo, \
Mayo1, \
Expand Down Expand Up @@ -62,7 +57,7 @@ class TestDeterministicDRBGTestValues(unittest.TestCase):
Mayo.set_drbg_seed(seed)

# Assert keygen matches
_sk, _pk = Mayo.compact_key_gen_bitsliced()
_sk, _pk = Mayo.compact_key_gen()
self.assertEqual(pk, _pk)
self.assertEqual(sk, _sk)

Expand Down
Loading