Skip to content

feat: add post-quantum ML-DSA crypt module (PqcSigner and PqcVerifier) - #18130

Draft
ohmayr wants to merge 2 commits into
mainfrom
pqc-stack-1-module
Draft

feat: add post-quantum ML-DSA crypt module (PqcSigner and PqcVerifier)#18130
ohmayr wants to merge 2 commits into
mainfrom
pqc-stack-1-module

Conversation

@ohmayr

@ohmayr ohmayr commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

WIP

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces post-quantum ML-DSA (Module-Lattice-Based Digital Signature Algorithm) signing and verification capabilities to the google-auth library, adding the PqcSigner and PqcVerifier classes under a new pqc module along with corresponding unit tests. The review feedback suggests optimizing the is_mldsa_key helper to avoid unnecessary parsing overhead on raw DER bytes, enhancing safety in __setstate__ by copying the state dictionary and using explicit keyword arguments, and improving test robustness by replacing a lambda mock with mock.Mock.

Comment on lines +75 to +89
if any(oid in key_bytes for oid in _MLDSA_OIDS):
return True

try:
import base64

pem_body = b"".join(
line.strip()
for line in key_bytes.splitlines()
if not line.startswith(b"-----")
)
der = base64.b64decode(pem_body)
return any(oid in der for oid in _MLDSA_OIDS)
except Exception:
return False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Optimizing is_mldsa_key by checking if the input contains b"-----BEGIN" before attempting to split lines and base64-decode it. This avoids unnecessary overhead and potential false positives/errors when the input is already raw DER bytes.

Suggested change
if any(oid in key_bytes for oid in _MLDSA_OIDS):
return True
try:
import base64
pem_body = b"".join(
line.strip()
for line in key_bytes.splitlines()
if not line.startswith(b"-----")
)
der = base64.b64decode(pem_body)
return any(oid in der for oid in _MLDSA_OIDS)
except Exception:
return False
if b"-----BEGIN" in key_bytes:
try:
import base64
pem_body = b"".join(
line.strip()
for line in key_bytes.splitlines()
if not line.startswith(b"-----")
)
der = base64.b64decode(pem_body)
return any(oid in der for oid in _MLDSA_OIDS)
except Exception:
return False
return any(oid in key_bytes for oid in _MLDSA_OIDS)

Comment on lines +248 to +253
def __setstate__(self, state: Dict[str, Any]) -> None:
"""Pickle helper that deserializes the _key attribute."""
if mldsa is None:
raise RuntimeError(_UPGRADE_ERROR)
state["_key"] = serialization.load_pem_private_key(state["_key"], None)
self.__dict__.update(state)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Improve consistency and safety in __setstate__ by copying the state dictionary to avoid mutating the unpickled state in-place, and passing explicit keyword arguments (password=None and backend=_BACKEND) to load_pem_private_key to match the implementation in from_string.

Suggested change
def __setstate__(self, state: Dict[str, Any]) -> None:
"""Pickle helper that deserializes the _key attribute."""
if mldsa is None:
raise RuntimeError(_UPGRADE_ERROR)
state["_key"] = serialization.load_pem_private_key(state["_key"], None)
self.__dict__.update(state)
def __setstate__(self, state: Dict[str, Any]) -> None:
"""Pickle helper that deserializes the _key attribute."""
if mldsa is None:
raise RuntimeError(_UPGRADE_ERROR)
state = state.copy()
state["_key"] = serialization.load_pem_private_key(
state["_key"], password=None, backend=_BACKEND
)
self.__dict__.update(state)

Comment on lines +177 to +181
monkeypatch.setattr(
pqc.serialization,
"load_pem_private_key",
lambda pem, pw: loaded_key,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Update the mock for load_pem_private_key to use mock.Mock instead of a lambda with a fixed signature. This makes the test robust against changes to the arguments passed to load_pem_private_key (such as passing keyword arguments like password and backend).

Suggested change
monkeypatch.setattr(
pqc.serialization,
"load_pem_private_key",
lambda pem, pw: loaded_key,
)
monkeypatch.setattr(
pqc.serialization,
"load_pem_private_key",
mock.Mock(return_value=loaded_key),
)

@ohmayr
ohmayr force-pushed the pqc-stack-1-module branch from b03e9e1 to f602d58 Compare August 17, 2026 21:01
@ohmayr
ohmayr force-pushed the pqc-stack-1-module branch from f602d58 to fe7dbe4 Compare August 17, 2026 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant