Skip to content

Commit f956587

Browse files
dstebilaclaude
andauthored
Fix StatefulSignature.export_secret_key TypeErrors on Windows (#141)
Two failures reported in #136, both in export_secret_key: 1. On Python 3.14 32-bit: ct.util.find_library("c") returns None on Windows, so CDLL(None) raises TypeError. Even on Unix where it worked, liboqs's malloc and libc's free can come from different CRT heaps on Windows. Use liboqs's own OQS_MEM_secure_free instead — ABI-compatible by construction, and also zeroizes the secret-key bytes before freeing. 2. On Python 3.14 64-bit: OQS_SIG_STFL_SECRET_KEY_serialize fails with "OverflowError: int too long to convert" on argument 3 (the secret-key handle). Cause: restype c_void_p auto-unwraps the returned pointer to a Python int, and on Windows Python 3.14 the int -> c_void_p arg conversion path chokes on high-bit-set addresses. Use a c_void_p subclass as the restype so ctypes keeps the pointer as an object; subsequent calls take the same-type fast path and skip int conversion entirely. Closes #136. Signed-off-by: Douglas Stebila <dstebila@uwaterloo.ca> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent dac0c08 commit f956587

1 file changed

Lines changed: 16 additions & 2 deletions

File tree

oqs/oqs.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,7 +1161,7 @@ def export_secret_key(self) -> bytes:
11611161
msg = "Secret‑key serialization failed"
11621162
raise ValueError(msg)
11631163
data = ct.string_at(buf_ptr, buf_len.value)
1164-
ct.CDLL(ct.util.find_library("c")).free(buf_ptr)
1164+
native().OQS_MEM_secure_free(buf_ptr, buf_len.value)
11651165
return data
11661166

11671167
def sigs_total(self) -> int:
@@ -1212,7 +1212,19 @@ def free(self) -> None:
12121212

12131213

12141214
native().OQS_SIG_STFL_new.restype = ct.POINTER(StatefulSignature)
1215-
native().OQS_SIG_STFL_SECRET_KEY_new.restype = ct.c_void_p
1215+
1216+
1217+
# Subclass c_void_p so the returned pointer stays as a ctypes object rather
1218+
# than being auto-unwrapped to a Python int. On 64-bit Windows Python 3.14,
1219+
# a pointer with the high bit set round-tripping through a Python int into
1220+
# a c_void_p argument triggers "OverflowError: int too long to convert".
1221+
# Keeping it as a ctypes object uses the same-type fast path on the way back
1222+
# in and avoids the int conversion entirely. (Issue #136.)
1223+
class _OQS_SIG_STFL_SECRET_KEY_p(ct.c_void_p):
1224+
pass
1225+
1226+
1227+
native().OQS_SIG_STFL_SECRET_KEY_new.restype = _OQS_SIG_STFL_SECRET_KEY_p
12161228
native().OQS_SIG_STFL_SECRET_KEY_new.argtypes = [ct.c_char_p]
12171229
# Added precise signatures for (de)serialization to avoid ABI issues
12181230
native().OQS_SIG_STFL_SECRET_KEY_serialize.restype = ct.c_int
@@ -1221,6 +1233,8 @@ def free(self) -> None:
12211233
ct.POINTER(ct.c_size_t),
12221234
ct.c_void_p,
12231235
]
1236+
native().OQS_MEM_secure_free.restype = None
1237+
native().OQS_MEM_secure_free.argtypes = [ct.c_void_p, ct.c_size_t]
12241238
native().OQS_SIG_STFL_SECRET_KEY_deserialize.restype = ct.c_int
12251239
native().OQS_SIG_STFL_SECRET_KEY_deserialize.argtypes = [
12261240
ct.c_void_p,

0 commit comments

Comments
 (0)