Skip to content

Use OQS_SIG_supports_ctx_str for context support detection and fix CI build #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 8 additions & 4 deletions oqs/oqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,11 @@ def get_supported_kem_mechanisms() -> tuple[str, ...]:
return _supported_KEMs


# Register the OQS_SIG_supports_ctx_str function from the C library
native().OQS_SIG_supports_ctx_str.restype = ct.c_bool
native().OQS_SIG_supports_ctx_str.argtypes = [ct.c_char_p]


class Signature(ct.Structure):
"""
An OQS Signature wraps native/C liboqs OQS_SIG structs.
Expand All @@ -485,7 +490,6 @@ class Signature(ct.Structure):
("alg_version", ct.c_char_p),
("claimed_nist_level", ct.c_ubyte),
("euf_cma", ct.c_ubyte),
("sig_with_ctx_support", ct.c_ubyte),
("length_public_key", ct.c_size_t),
("length_secret_key", ct.c_size_t),
("length_signature", ct.c_size_t),
Expand Down Expand Up @@ -515,7 +519,7 @@ def __init__(self, alg_name: str, secret_key: Union[int, bytes, None] = None) ->
self.alg_version = self._sig.contents.alg_version
self.claimed_nist_level = self._sig.contents.claimed_nist_level
self.euf_cma = self._sig.contents.euf_cma
self.sig_with_ctx_support = self._sig.contents.sig_with_ctx_support
self.sig_with_ctx_support = native().OQS_SIG_supports_ctx_str(self.method_name)
self.length_public_key = self._sig.contents.length_public_key
self.length_secret_key = self._sig.contents.length_secret_key
self.length_signature = self._sig.contents.length_signature
Expand Down Expand Up @@ -634,7 +638,7 @@ def sign_with_ctx_str(self, message: bytes, context: bytes) -> bytes:
:param context: the context string.
:param message: the message to sign.
"""
if context and not self._sig.contents.sig_with_ctx_support:
if context and not self.sig_with_ctx_support:
msg = "Signing with context string not supported"
raise RuntimeError(msg)

Expand Down Expand Up @@ -681,7 +685,7 @@ def verify_with_ctx_str(
:param context: the context string.
:param public_key: the signer's public key.
"""
if context and not self._sig.contents.sig_with_ctx_support:
if context and not self.sig_with_ctx_support:
msg = "Verifying with context string not supported"
raise RuntimeError(msg)

Expand Down
27 changes: 26 additions & 1 deletion tests/test_sig.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import random

import oqs
from oqs.oqs import Signature
from oqs.oqs import Signature, native

# Sigs for which unit testing is disabled
disabled_sig_patterns = []
Expand Down Expand Up @@ -44,6 +44,31 @@ def check_correctness_with_ctx_str(alg_name: str) -> None:
assert sig.verify_with_ctx_str(message, signature, context, public_key) # noqa: S101


def test_sig_with_ctx_support_detection() -> None:
"""
Test that sig_with_ctx_support matches the C API and that sign_with_ctx_str
raises on unsupported algorithms.
"""
for alg_name in oqs.get_enabled_sig_mechanisms():
with Signature(alg_name) as sig:
# Check Python attribute matches C API
c_api_result = native().OQS_SIG_supports_ctx_str(sig.method_name)
assert bool(sig.sig_with_ctx_support) == bool(c_api_result), ( # noqa: S101
f"sig_with_ctx_support mismatch for {alg_name}"
)
# If not supported, sign_with_ctx_str should raise
if not sig.sig_with_ctx_support:
try:
sig.sign_with_ctx_str(b"msg", b"context")
except RuntimeError as e:
if "not supported" not in str(e):
msg = f"Unexpected exception message: {e}"
raise AssertionError(msg) from e
else:
msg = f"sign_with_ctx_str did not raise for {alg_name} without context support"
raise AssertionError(msg)


def test_wrong_message() -> tuple[None, str]:
for alg_name in oqs.get_enabled_sig_mechanisms():
if any(item in alg_name for item in disabled_sig_patterns):
Expand Down
Loading