Skip to content

Commit a663807

Browse files
authored
UpdateV14 (#116)
* Update _install_liboqs. - Added STFL flags. - Allow to test with pre-released version. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update Exceptions to show allowed algs. - Only for STFL algs. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update KEM wrapper and tests. - Added key generation from seed. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update Signature wrapper. - Added new function to check if the algorithm supports signing with context. - Added new flag and changed falg types to ct._c_bool. Signed-off-by: Guiliano <guilianolehmann@live.de> * Add StatefulSignature wrapper. - Added new wrapper. - Added supported and enabled check funs. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update KEM example. - Added example with seed. Signed-off-by: Guiliano <guilianolehmann@live.de> * Add STFL example. - Added a simple XMSS example. Signed-off-by: Guiliano <guilianolehmann@live.de> * Add STFL tests. - Added same test as for SIG (without ctx). Signed-off-by: Guiliano <guilianolehmann@live.de> * Update oqs_python_version to auto install project version. - Use tomli or tomllib to get the version. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update version to v14. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update pipeline for STFL and v14. Signed-off-by: Guiliano <guilianolehmann@live.de> * Update doc for new changes. Signed-off-by: Guiliano <guilianolehmann@live.de> * Made ruff happier Signed-off-by: Guiliano <guilianolehmann@live.de> --------- Signed-off-by: Guiliano <guilianolehmann@live.de>
1 parent f646683 commit a663807

File tree

15 files changed

+790
-61
lines changed

15 files changed

+790
-61
lines changed

.github/workflows/python_detailed.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ env:
1515
BUILD_TYPE: Debug
1616
LD_LIBRARY_PATH: /usr/local/lib
1717
WIN_LIBOQS_INSTALL_PATH: C:\liboqs
18+
VERSION: 0.14.0
1819

1920
jobs:
2021
build:
@@ -42,8 +43,11 @@ jobs:
4243
- name: Install liboqs POSIX
4344
if: matrix.os != 'windows-latest'
4445
run: |
45-
git clone --branch main --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
46-
cmake -S liboqs -B liboqs/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_SHARED_LIBS=ON -DOQS_BUILD_ONLY_LIB=ON
46+
git clone --branch ${{env.VERSION}} --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
47+
cmake -S liboqs -B liboqs/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_SHARED_LIBS=ON \
48+
-DOQS_BUILD_ONLY_LIB=ON -DOQS_BUILD_ONLY_LIB=ON -DOQS_ENABLE_SIG_STFL_LMS=ON \
49+
-DOQS_ENABLE_SIG_STFL_XMSS=ON -DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON \
50+
-DOQS_ALLOW_STFL_KEY_AND_SIG_GEN=ON
4751
cmake --build liboqs/build --parallel 4
4852
sudo cmake --build liboqs/build --target install
4953
@@ -56,6 +60,8 @@ jobs:
5660
uv run examples/sig.py
5761
echo
5862
uv run examples/rand.py
63+
echo
64+
uv run examples/stfl_sig.py
5965
6066
- name: Run unit tests POSIX
6167
if: matrix.os != 'windows-latest'
@@ -66,8 +72,8 @@ jobs:
6672
if: matrix.os == 'windows-latest'
6773
shell: cmd
6874
run: |
69-
git clone --branch main --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
70-
cmake -S liboqs -B liboqs\build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=${{env.WIN_LIBOQS_INSTALL_PATH}} -DBUILD_SHARED_LIBS=ON -DOQS_BUILD_ONLY_LIB=ON
75+
git clone --branch ${{env.VERSION}} --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
76+
cmake -S liboqs -B liboqs\build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=${{env.WIN_LIBOQS_INSTALL_PATH}} -DBUILD_SHARED_LIBS=ON -DOQS_BUILD_ONLY_LIB=ON -DOQS_BUILD_ONLY_LIB=ON -DOQS_ENABLE_SIG_STFL_LMS=ON -DOQS_ENABLE_SIG_STFL_XMSS=ON -DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON ‑DOQS_ALLOW_STFL_KEY_AND_SIG_GEN=ON
7177
cmake --build liboqs\build --parallel 4
7278
cmake --build liboqs\build --target install
7379
@@ -82,6 +88,8 @@ jobs:
8288
uv run examples/sig.py
8389
echo.
8490
uv run examples/rand.py
91+
echo.
92+
uv run examples/stfl_sig.py
8593
8694
- name: Run unit tests Windows
8795
shell: cmd

.github/workflows/python_simplified.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ jobs:
3737
uv run examples/kem.py
3838
uv run examples/sig.py
3939
uv run examples/rand.py
40+
uv run examples/stfl_sig.py
4041
4142
- name: Run unit tests
4243
run: |

Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ RUN apt-get -y update && \
77
# Get liboqs
88
RUN git clone --depth 1 --branch main https://github.com/open-quantum-safe/liboqs
99

10-
# Install liboqs
11-
RUN cmake -S liboqs -B liboqs/build -DBUILD_SHARED_LIBS=ON && \
10+
# Install liboqs with stateful-signature algorithms enabled
11+
RUN cmake -S liboqs -B liboqs/build \
12+
-DBUILD_SHARED_LIBS=ON \
13+
-DOQS_ENABLE_SIG_STFL_LMS=ON \
14+
-DOQS_ENABLE_SIG_STFL_XMSS=ON \
15+
-DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON && \
1216
cmake --build liboqs/build --parallel 4 && \
1317
cmake --build liboqs/build --target install
1418

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The project contains the following files and directories
2626
- `examples/kem.py`: key encapsulation example
2727
- `examples/rand.py`: RNG example
2828
- `examples/sig.py`: signature example
29+
- `examples/stfl_sig.py`: stateful signature example
2930
- `tests`: unit tests
3031

3132
---
@@ -141,6 +142,7 @@ Execute
141142
```shell
142143
python3 liboqs-python/examples/kem.py
143144
python3 liboqs-python/examples/sig.py
145+
python3 liboqs-python/examples/stfl_sig.py
144146
python3 liboqs-python/examples/rand.py
145147
```
146148

@@ -162,11 +164,14 @@ liboqs-python can be imported into Python programs with
162164
import oqs
163165
```
164166

165-
liboqs-python defines two main classes: `KeyEncapsulation` and `Signature`,
166-
providing post-quantum key encapsulation and signature mechanisms,
167-
respectively. Each must be instantiated with a string identifying one of
168-
mechanisms supported by liboqs; these can be enumerated using the
169-
`get_enabled_KEM_mechanisms()` and `get_enabled_sig_mechanisms()` functions.
167+
liboqs-python defines three main classes: `KeyEncapsulation`, `Signature`, and
168+
`StatefulSignature`, providing post-quantum key encapsulation as well as
169+
stateless and stateful signature mechanisms. Each must be instantiated with a
170+
string identifying one of the mechanisms supported by liboqs; these can be
171+
enumerated using the `get_enabled_kem_mechanisms()`,
172+
`get_enabled_sig_mechanisms()` and `get_enabled_stateful_sig_mechanisms()`
173+
functions. ML-KEM key pairs can also be deterministically generated from a
174+
seed using `KeyEncapsulation.generate_keypair_seed()`.
170175
The files in `examples/` demonstrate the wrapper's API. Support for alternative
171176
RNGs is provided via the `randombytes_*()` functions.
172177

RELEASE.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
1-
# liboqs-python version 0.12.0
1+
# liboqs-python version 0.14.0
22

33
---
4+
# Added in version 0.14.0 July 2025
5+
6+
- Added stateful signature support via the `StatefulSignature` class.
7+
- New enumeration helpers `get_enabled_stateful_sig_mechanisms()` and
8+
`get_supported_stateful_sig_mechanisms()`.
9+
- Updated to liboqs 0.14.0.
10+
- ML-KEM keys can be generated from a seed via
11+
`KeyEncapsulation.generate_keypair_seed()`.
412

513
## About
614

@@ -24,9 +32,9 @@ See in particular limitations on intended use.
2432

2533
## Release notes
2634

27-
This release of liboqs-python was released on January 15, 2025. Its release
35+
This release of liboqs-python was released on July 10, 2025. Its release
2836
page on GitHub is
29-
https://github.com/open-quantum-safe/liboqs-python/releases/tag/0.12.0.
37+
https://github.com/open-quantum-safe/liboqs-python/releases/tag/0.14.0.
3038

3139
---
3240

docker/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# Multi-stage build: First the full builder image:
22

33
# liboqs build type variant; maximum portability of image; no openssl dependency:
4-
ARG LIBOQS_BUILD_DEFINES="-DOQS_DIST_BUILD=ON -DBUILD_SHARED_LIBS=ON -DOQS_USE_OPENSSL=OFF"
4+
ARG LIBOQS_BUILD_DEFINES="-DOQS_DIST_BUILD=ON -DBUILD_SHARED_LIBS=ON -DOQS_USE_OPENSSL=OFF \
5+
-DOQS_ENABLE_SIG_STFL_LMS=ON -DOQS_ENABLE_SIG_STFL_XMSS=ON \
6+
-DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON"
57

68
# make build arguments: Adding -j here speeds up build but may tax hardware
79
ARG MAKE_DEFINES="-j 2"

docker/Dockerfile-simple

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# Multi-stage build: First the full builder image:
22

33
# liboqs build type variant; maximum portability of image; no openssl dependency:
4-
ARG LIBOQS_BUILD_DEFINES="-DOQS_DIST_BUILD=ON -DBUILD_SHARED_LIBS=ON -DOQS_USE_OPENSSL=OFF"
4+
ARG LIBOQS_BUILD_DEFINES="-DOQS_DIST_BUILD=ON -DBUILD_SHARED_LIBS=ON -DOQS_USE_OPENSSL=OFF \
5+
-DOQS_ENABLE_SIG_STFL_LMS=ON -DOQS_ENABLE_SIG_STFL_XMSS=ON \
6+
-DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON"
57

68
FROM alpine:3.16 as intermediate
79
# Take in all global args

docker/minitest.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import ssl
2+
import sys
23
import urllib.request
34
import json
45
import os
@@ -7,7 +8,7 @@
78
# Example code testing oqs signature functionality. See more example code at
89
# https://github.com/open-quantum-safe/liboqs-python/tree/main/examples
910

10-
message = "This is the message to sign".encode()
11+
message = b"This is the message to sign"
1112

1213
# create signer and verifier with sample signature mechanisms
1314
sigalg = "Dilithium2"
@@ -17,46 +18,56 @@
1718
signature = signer.sign(message)
1819
is_valid = verifier.verify(message, signature, signer_public_key)
1920

20-
if (not is_valid):
21+
if not is_valid:
2122
print("Failed to validate signature. Exiting.")
22-
exit(1)
23+
sys.exit(1)
2324
else:
2425
print("Validated signature for OQS algorithm %s" % (sigalg))
2526

2627
# Example code iterating over all supported OQS algorithms integrated into TLS
2728

28-
sslContext= ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
29+
sslContext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
2930
sslContext.verify_mode = ssl.CERT_REQUIRED
3031
# Trust LetsEncrypt root CA:
3132
sslContext.load_verify_locations(cafile="isrgrootx1.pem")
3233

3334
# Retrieve interop test server root CA
34-
with urllib.request.urlopen('https://test.openquantumsafe.org/CA.crt', context=sslContext) as response:
35-
data=response.read()
35+
with urllib.request.urlopen(
36+
"https://test.openquantumsafe.org/CA.crt", context=sslContext
37+
) as response:
38+
data = response.read()
3639
with open("CA.crt", "w+b") as f:
3740
f.write(data)
3841

3942
# Retrieve JSON structure of all alg/port combinations:
40-
with urllib.request.urlopen('https://test.openquantumsafe.org/assignments.json', context=sslContext) as response:
41-
assignments=json.loads(response.read())
43+
with urllib.request.urlopen(
44+
"https://test.openquantumsafe.org/assignments.json", context=sslContext
45+
) as response:
46+
assignments = json.loads(response.read())
4247

4348
# Trust test.openquantumsafe.org root CA:
4449
sslContext.load_verify_locations(cafile="CA.crt")
4550

4651
# Iterate over all algorithm/port combinations:
4752
for sigs, kexs in assignments.items():
4853
for kex, port in kexs.items():
49-
if (kex != "*"): # '*' denoting any classic KEX alg
54+
if kex != "*": # '*' denoting any classic KEX alg
5055
# Enable use of the specific QSC KEX algorithm
51-
os.environ["TLS_DEFAULT_GROUPS"]=kex
52-
try:
53-
with urllib.request.urlopen('https://test.openquantumsafe.org:'+str(port), context=sslContext) as response:
54-
if response.getcode() != 200:
55-
print("Failed to test %s successfully" % (kex))
56-
else:
57-
print("Success testing %s at port %d" % (kex, port))
58-
except:
59-
print("Test of algorithm combination SIG %s/KEX %s failed. Are all algorithms supported by current OQS library?" % (sigs, kex))
56+
os.environ["TLS_DEFAULT_GROUPS"] = kex
57+
try:
58+
with urllib.request.urlopen(
59+
"https://test.openquantumsafe.org:" + str(port), context=sslContext
60+
) as response:
61+
if response.getcode() != 200:
62+
print("Failed to test %s successfully" % (kex))
63+
else:
64+
print("Success testing %s at port %d" % (kex, port))
65+
except:
66+
print(
67+
"Test of algorithm combination SIG %s/KEX %s failed. "
68+
"Are all algorithms supported by current OQS library?"
69+
% (sigs, kex)
70+
)
6071

6172
if "SHORT_TEST" in os.environ:
62-
exit(0)
73+
sys.exit(0)

examples/kem.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,30 @@
4242
"Shared secretes coincide: %s",
4343
shared_secret_client == shared_secret_server,
4444
)
45+
46+
# Example for using a seed to generate a keypair.
47+
kemalg = "ML-KEM-512"
48+
seed = b"This is a 64-byte seed for key generation" + b"\x00" * 23
49+
with oqs.KeyEncapsulation(kemalg) as client:
50+
with oqs.KeyEncapsulation(kemalg) as server:
51+
logger.info("Key encapsulation details:\n%s", pformat(client.details))
52+
53+
# Client generates its keypair
54+
public_key_client = client.generate_keypair_seed(seed)
55+
# Optionally, the secret key can be obtained by calling export_secret_key()
56+
# and the client can later be re-instantiated with the key pair:
57+
# secret_key_client = client.export_secret_key()
58+
59+
# Store key pair, wait... (session resumption):
60+
# client = oqs.KeyEncapsulation(kemalg, secret_key_client)
61+
62+
# The server encapsulates its secret using the client's public key
63+
ciphertext, shared_secret_server = server.encap_secret(public_key_client)
64+
65+
# The client decapsulates the server's ciphertext to obtain the shared secret
66+
shared_secret_client = client.decap_secret(ciphertext)
67+
68+
logger.info(
69+
"Shared secretes coincide: %s",
70+
shared_secret_client == shared_secret_server,
71+
)

examples/stfl_sig.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Stateful signature examples
2+
3+
import logging
4+
from pprint import pformat
5+
from sys import stdout
6+
7+
import oqs
8+
from oqs import StatefulSignature
9+
10+
logger = logging.getLogger(__name__)
11+
logger.setLevel(logging.INFO)
12+
logger.addHandler(logging.StreamHandler(stdout))
13+
14+
logger.info("liboqs version: %s", oqs.oqs_version())
15+
logger.info("liboqs-python version: %s", oqs.oqs_python_version())
16+
logger.info(
17+
"Enabled stateful signature mechanisms:\n%s",
18+
pformat(oqs.get_enabled_stateful_sig_mechanisms(), compact=True),
19+
)
20+
21+
message = b"This is the message to sign"
22+
23+
# Create signer and verifier with sample signature mechanisms
24+
stfl_sigalg = "XMSS-SHA2_10_256"
25+
with StatefulSignature(stfl_sigalg) as signer, StatefulSignature(stfl_sigalg) as verifier:
26+
logger.info("Signature details:\n%s", pformat(signer.details))
27+
28+
# Signer generates its keypair
29+
signer_public_key = signer.generate_keypair()
30+
logger.info("Generated public key:\n%s", signer_public_key.hex())
31+
# Optionally, the secret key can be obtained by calling export_secret_key()
32+
# and the signer can later be re-instantiated with the key pair:
33+
# secret_key = signer.export_secret_key()
34+
35+
# Store key pair, wait... (session resumption):
36+
# signer = oqs.Signature(sigalg, secret_key)
37+
38+
# Signer signs the message
39+
signature = signer.sign(message)
40+
41+
# Verifier verifies the signature
42+
is_valid = verifier.verify(message, signature, signer_public_key)
43+
44+
logger.info("Valid signature? %s", is_valid)

0 commit comments

Comments
 (0)