Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 12 additions & 4 deletions .github/workflows/python_detailed.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ env:
BUILD_TYPE: Debug
LD_LIBRARY_PATH: /usr/local/lib
WIN_LIBOQS_INSTALL_PATH: C:\liboqs
VERSION: 0.14.0

jobs:
build:
Expand Down Expand Up @@ -42,8 +43,11 @@ jobs:
- name: Install liboqs POSIX
if: matrix.os != 'windows-latest'
run: |
git clone --branch main --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
cmake -S liboqs -B liboqs/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_SHARED_LIBS=ON -DOQS_BUILD_ONLY_LIB=ON
git clone --branch ${{env.VERSION}} --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
cmake -S liboqs -B liboqs/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -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
cmake --build liboqs/build --parallel 4
sudo cmake --build liboqs/build --target install

Expand All @@ -56,6 +60,8 @@ jobs:
uv run examples/sig.py
echo
uv run examples/rand.py
echo
uv run examples/stfl_sig.py

- name: Run unit tests POSIX
if: matrix.os != 'windows-latest'
Expand All @@ -66,8 +72,8 @@ jobs:
if: matrix.os == 'windows-latest'
shell: cmd
run: |
git clone --branch main --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
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
git clone --branch ${{env.VERSION}} --single-branch --depth 1 https://github.com/open-quantum-safe/liboqs
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
cmake --build liboqs\build --parallel 4
cmake --build liboqs\build --target install

Expand All @@ -82,6 +88,8 @@ jobs:
uv run examples/sig.py
echo.
uv run examples/rand.py
echo.
uv run examples/stfl_sig.py

- name: Run unit tests Windows
shell: cmd
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/python_simplified.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
uv run examples/kem.py
uv run examples/sig.py
uv run examples/rand.py
uv run examples/stfl_sig.py

- name: Run unit tests
run: |
Expand Down
8 changes: 6 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ RUN apt-get -y update && \
# Get liboqs
RUN git clone --depth 1 --branch main https://github.com/open-quantum-safe/liboqs

# Install liboqs
RUN cmake -S liboqs -B liboqs/build -DBUILD_SHARED_LIBS=ON && \
# Install liboqs with stateful-signature algorithms enabled
RUN cmake -S liboqs -B liboqs/build \
-DBUILD_SHARED_LIBS=ON \
-DOQS_ENABLE_SIG_STFL_LMS=ON \
-DOQS_ENABLE_SIG_STFL_XMSS=ON \
-DOQS_HAZARDOUS_EXPERIMENTAL_ENABLE_SIG_STFL_KEY_SIG_GEN=ON && \
cmake --build liboqs/build --parallel 4 && \
cmake --build liboqs/build --target install

Expand Down
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The project contains the following files and directories
- `examples/kem.py`: key encapsulation example
- `examples/rand.py`: RNG example
- `examples/sig.py`: signature example
- `examples/stfl_sig.py`: stateful signature example
- `tests`: unit tests

---
Expand Down Expand Up @@ -141,6 +142,7 @@ Execute
```shell
python3 liboqs-python/examples/kem.py
python3 liboqs-python/examples/sig.py
python3 liboqs-python/examples/stfl_sig.py
python3 liboqs-python/examples/rand.py
```

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

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

Expand Down
14 changes: 11 additions & 3 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# liboqs-python version 0.12.0
# liboqs-python version 0.14.0

---
# Added in version 0.14.0 July 2025

- Added stateful signature support via the `StatefulSignature` class.
- New enumeration helpers `get_enabled_stateful_sig_mechanisms()` and
`get_supported_stateful_sig_mechanisms()`.
- Updated to liboqs 0.14.0.
- ML-KEM keys can be generated from a seed via
`KeyEncapsulation.generate_keypair_seed()`.

## About

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

## Release notes

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

---

Expand Down
4 changes: 3 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Multi-stage build: First the full builder image:

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

# make build arguments: Adding -j here speeds up build but may tax hardware
ARG MAKE_DEFINES="-j 2"
Expand Down
4 changes: 3 additions & 1 deletion docker/Dockerfile-simple
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Multi-stage build: First the full builder image:

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

FROM alpine:3.16 as intermediate
# Take in all global args
Expand Down
49 changes: 30 additions & 19 deletions docker/minitest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ssl
import sys
import urllib.request
import json
import os
Expand All @@ -7,7 +8,7 @@
# Example code testing oqs signature functionality. See more example code at
# https://github.com/open-quantum-safe/liboqs-python/tree/main/examples

message = "This is the message to sign".encode()
message = b"This is the message to sign"

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

if (not is_valid):
if not is_valid:
print("Failed to validate signature. Exiting.")
exit(1)
sys.exit(1)
else:
print("Validated signature for OQS algorithm %s" % (sigalg))

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

sslContext= ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
sslContext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
sslContext.verify_mode = ssl.CERT_REQUIRED
# Trust LetsEncrypt root CA:
sslContext.load_verify_locations(cafile="isrgrootx1.pem")

# Retrieve interop test server root CA
with urllib.request.urlopen('https://test.openquantumsafe.org/CA.crt', context=sslContext) as response:
data=response.read()
with urllib.request.urlopen(
"https://test.openquantumsafe.org/CA.crt", context=sslContext
) as response:
data = response.read()
with open("CA.crt", "w+b") as f:
f.write(data)

# Retrieve JSON structure of all alg/port combinations:
with urllib.request.urlopen('https://test.openquantumsafe.org/assignments.json', context=sslContext) as response:
assignments=json.loads(response.read())
with urllib.request.urlopen(
"https://test.openquantumsafe.org/assignments.json", context=sslContext
) as response:
assignments = json.loads(response.read())

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

# Iterate over all algorithm/port combinations:
for sigs, kexs in assignments.items():
for kex, port in kexs.items():
if (kex != "*"): # '*' denoting any classic KEX alg
if kex != "*": # '*' denoting any classic KEX alg
# Enable use of the specific QSC KEX algorithm
os.environ["TLS_DEFAULT_GROUPS"]=kex
try:
with urllib.request.urlopen('https://test.openquantumsafe.org:'+str(port), context=sslContext) as response:
if response.getcode() != 200:
print("Failed to test %s successfully" % (kex))
else:
print("Success testing %s at port %d" % (kex, port))
except:
print("Test of algorithm combination SIG %s/KEX %s failed. Are all algorithms supported by current OQS library?" % (sigs, kex))
os.environ["TLS_DEFAULT_GROUPS"] = kex
try:
with urllib.request.urlopen(
"https://test.openquantumsafe.org:" + str(port), context=sslContext
) as response:
if response.getcode() != 200:
print("Failed to test %s successfully" % (kex))
else:
print("Success testing %s at port %d" % (kex, port))
except:
print(
"Test of algorithm combination SIG %s/KEX %s failed. "
"Are all algorithms supported by current OQS library?"
% (sigs, kex)
)

if "SHORT_TEST" in os.environ:
exit(0)
sys.exit(0)
27 changes: 27 additions & 0 deletions examples/kem.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,30 @@
"Shared secretes coincide: %s",
shared_secret_client == shared_secret_server,
)

# Example for using a seed to generate a keypair.
kemalg = "ML-KEM-512"
seed = b"This is a 64-byte seed for key generation" + b"\x00" * 23
with oqs.KeyEncapsulation(kemalg) as client:
with oqs.KeyEncapsulation(kemalg) as server:
logger.info("Key encapsulation details:\n%s", pformat(client.details))

# Client generates its keypair
public_key_client = client.generate_keypair_seed(seed)
# Optionally, the secret key can be obtained by calling export_secret_key()
# and the client can later be re-instantiated with the key pair:
# secret_key_client = client.export_secret_key()

# Store key pair, wait... (session resumption):
# client = oqs.KeyEncapsulation(kemalg, secret_key_client)

# The server encapsulates its secret using the client's public key
ciphertext, shared_secret_server = server.encap_secret(public_key_client)

# The client decapsulates the server's ciphertext to obtain the shared secret
shared_secret_client = client.decap_secret(ciphertext)

logger.info(
"Shared secretes coincide: %s",
shared_secret_client == shared_secret_server,
)
44 changes: 44 additions & 0 deletions examples/stfl_sig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Stateful signature examples

import logging
from pprint import pformat
from sys import stdout

import oqs
from oqs import StatefulSignature

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(logging.StreamHandler(stdout))

logger.info("liboqs version: %s", oqs.oqs_version())
logger.info("liboqs-python version: %s", oqs.oqs_python_version())
logger.info(
"Enabled stateful signature mechanisms:\n%s",
pformat(oqs.get_enabled_stateful_sig_mechanisms(), compact=True),
)

message = b"This is the message to sign"

# Create signer and verifier with sample signature mechanisms
stfl_sigalg = "XMSS-SHA2_10_256"
with StatefulSignature(stfl_sigalg) as signer, StatefulSignature(stfl_sigalg) as verifier:
logger.info("Signature details:\n%s", pformat(signer.details))

# Signer generates its keypair
signer_public_key = signer.generate_keypair()
logger.info("Generated public key:\n%s", signer_public_key.hex())
# Optionally, the secret key can be obtained by calling export_secret_key()
# and the signer can later be re-instantiated with the key pair:
# secret_key = signer.export_secret_key()

# Store key pair, wait... (session resumption):
# signer = oqs.Signature(sigalg, secret_key)

# Signer signs the message
signature = signer.sign(message)

# Verifier verifies the signature
is_valid = verifier.verify(message, signature, signer_public_key)

logger.info("Valid signature? %s", is_valid)
8 changes: 8 additions & 0 deletions oqs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
MechanismNotEnabledError,
MechanismNotSupportedError,
Signature,
StatefulSignature,
get_enabled_kem_mechanisms,
get_enabled_sig_mechanisms,
get_enabled_stateful_sig_mechanisms,
get_supported_kem_mechanisms,
get_supported_sig_mechanisms,
get_supported_stateful_sig_mechanisms,
is_kem_enabled,
is_sig_enabled,
sig_supports_context,
native,
oqs_python_version,
oqs_version,
Expand All @@ -23,13 +27,17 @@
"MechanismNotEnabledError",
"MechanismNotSupportedError",
"Signature",
"StatefulSignature",
"get_enabled_kem_mechanisms",
"get_enabled_sig_mechanisms",
"get_enabled_stateful_sig_mechanisms",
"get_supported_kem_mechanisms",
"get_supported_sig_mechanisms",
"get_supported_stateful_sig_mechanisms",
"is_kem_enabled",
"is_sig_enabled",
"native",
"oqs_python_version",
"oqs_version",
"sig_supports_context",
)
Loading
Loading