Skip to content

[DRAFT] PQC xwing (codex generated) - #3210

Closed
dmihalcik-virtru wants to merge 4 commits into
mainfrom
post-quantum-hybrid-codex-2026-03-dm
Closed

[DRAFT] PQC xwing (codex generated)#3210
dmihalcik-virtru wants to merge 4 commits into
mainfrom
post-quantum-hybrid-codex-2026-03-dm

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Mar 26, 2026

Copy link
Copy Markdown
Member
  • feat(kas): add ml-kem key wrapping support
  • feat(kas): add ml-kem-1024 support
  • Add X-Wing hybrid KAO wrapping support

PROMPT

This branch adds support for ML-KEM wrapping to our TDF Key Access Object wrapping. I would like to explicitly support hybrid keys with xwing, as defined in https://www.ietf.org/archive/id/draft-connolly-cfrg-xwing-kem-10.txt. So, like this PR adds the mlkem-wrapped SchemeType, it should also offer the hybrid SchemeType.
This will be supported by a new lib/ocrypto HybridXWing KeyType = "hpqt:xwing" in ec_key_pair.go (maybe move those to a new file with a neutral name?). Let KAS and the policy service store and serve a composite public
key as a single byte array (or in a PEM). E.g. let the key data be a concatenated set of traditional and post-quantum keys, or an ASN.1 object with additional data that contains both types of keys. Simmilarly, the KEM objects themselves should be base64 encoded in the same field in the KAO they are now, but will be much longer and more structured with ASN.1 Data so the server can later perform rewrap without additional json fields or data beyond the schema that currently exists (i.e. without needing a new ciphertext field or similar)

@github-actions github-actions Bot added comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati comp:kas Key Access Server docs Documentation comp:lib:ocrypto labels Mar 26, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces post-quantum cryptographic (PQC) capabilities to the system by adding support for ML-KEM and the X-Wing hybrid KEM. These changes include new encryption/decryption implementations, updated key management logic, and necessary modifications to the protocol definitions to enable these algorithms across the platform.

Highlights

  • ML-KEM Support: Added support for ML-KEM-768 and ML-KEM-1024 key wrapping, including new decapsulation and encapsulation implementations.
  • X-Wing Hybrid KEM: Implemented X-Wing hybrid key wrapping support, combining ML-KEM-768 and X25519.
  • Infrastructure Updates: Updated gRPC documentation, protobuf definitions, and internal security providers to support the new post-quantum cryptographic algorithms.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: docs/openapi/**/* (12)
    • docs/openapi/authorization/authorization.openapi.yaml
    • docs/openapi/authorization/v2/authorization.openapi.yaml
    • docs/openapi/policy/actions/actions.openapi.yaml
    • docs/openapi/policy/attributes/attributes.openapi.yaml
    • docs/openapi/policy/kasregistry/key_access_server_registry.openapi.yaml
    • docs/openapi/policy/namespaces/namespaces.openapi.yaml
    • docs/openapi/policy/objects.openapi.yaml
    • docs/openapi/policy/obligations/obligations.openapi.yaml
    • docs/openapi/policy/registeredresources/registered_resources.openapi.yaml
    • docs/openapi/policy/resourcemapping/resource_mapping.openapi.yaml
    • docs/openapi/policy/subjectmapping/subject_mapping.openapi.yaml
    • docs/openapi/policy/unsafe/unsafe.openapi.yaml
  • Ignored by pattern: protocol/**/* (2)
    • protocol/go/policy/kasregistry/key_access_server_registry.pb.go
    • protocol/go/policy/objects.pb.go
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


Quantum threats are on the way, But X-Wing keeps the keys at bay. With ML-KEM we stand our ground, Where post-quantum safety is found.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@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 support for Post-Quantum Cryptography (PQC) by implementing ML-KEM (768 and 1024) and the X-Wing hybrid KEM. The changes span the cryptographic library (ocrypto), SDK key access logic, and KAS rewrap/indexing services, along with necessary protobuf updates for policy definitions. Feedback focuses on improving the clarity and conciseness of new error messages, ensuring binary data in metadata is Base64 encoded rather than cast directly to strings, and simplifying logic within the security providers and key access layers.

Comment on lines +62 to +64
decap1024, err1024 := mlkem.NewDecapsulationKey1024(block.Bytes)
if err1024 != nil {
return nil, fmt.Errorf("mlkem.NewDecapsulationKey1024 failed after mlkem.NewDecapsulationKey768 failed: %w / %w", err, err1024)

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

The error message here is a bit verbose and might be confusing. If mlkem.NewDecapsulationKey768 fails, the subsequent call to mlkem.NewDecapsulationKey1024 failing with a different error might obscure the root cause. Consider a more concise error message or logging the first error separately before returning a combined error.

Comment on lines +231 to +232
func (d MLKEMDecryptor768) Decrypt(_ []byte) ([]byte, error) {
return nil, errors.New("ciphertext encapsulation is required for ML-KEM decryption")

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

The error message "ciphertext encapsulation is required for ML-KEM decryption" is technically correct but could be clearer. ML-KEM uses encapsulation/decapsulation, not traditional encryption/decryption of a ciphertext directly. Perhaps "ML-KEM decryption requires an encapsulated ciphertext, not a direct ciphertext" or similar.

Comment on lines +235 to +236
func (d MLKEMDecryptor1024) Decrypt(_ []byte) ([]byte, error) {
return nil, errors.New("ciphertext encapsulation is required for ML-KEM decryption")

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

The error message "ciphertext encapsulation is required for ML-KEM decryption" is technically correct but could be clearer. ML-KEM uses encapsulation/decapsulation, not traditional encryption/decryption of a ciphertext directly. Perhaps "ML-KEM decryption requires an encapsulated ciphertext, not a direct ciphertext" or similar.

Comment on lines +170 to +172
encap1024, err1024 := mlkem.NewEncapsulationKey1024(block.Bytes)
if err1024 != nil {
return nil, fmt.Errorf("mlkem.NewEncapsulationKey1024 failed after mlkem.NewEncapsulationKey768 failed: %w / %w", err, err1024)

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

Similar to the decryption side, the error message mlkem.NewEncapsulationKey1024 failed after mlkem.NewEncapsulationKey768 failed: %w / %w is quite verbose. It might be better to log the first error and then return a simpler error for the second failure, or combine them more concisely.


func (e MLKEMEncryptor768) Metadata() (map[string]string, error) {
m := make(map[string]string)
m["encapsulatedKey"] = string(e.EphemeralKey())

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

Converting e.EphemeralKey() (which is []byte) directly to a string using string() can lead to unexpected results if the byte slice does not represent valid UTF-8. It's generally safer to base64 encode binary data when storing it as a string, especially in metadata.

Suggested change
m["encapsulatedKey"] = string(e.EphemeralKey())
m["encapsulatedKey"] = Base64Encode(e.EphemeralKey())

Comment on lines +183 to +188
if encryptor.Type() == ocrypto.EC {
ephemeralPublicKeyPEM, err := encryptor.PublicKeyInPemFormat()
if err != nil {
return "", "", "", fmt.Errorf("failed to encode EC ephemeral public key: %w", err)
}
return wrappedKey, keyType, ephemeralPublicKeyPEM, nil

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

The ephemeralPublicKeyPEM variable is only used if encryptor.Type() == ocrypto.EC. If encryptor.Type() is ocrypto.MLKEM or ocrypto.Hybrid, the ephemeralKey is base64 encoded directly. This logic could be simplified by always base64 encoding ephemeralKey and letting the PublicKeyInPemFormat handle the PEM encoding for EC keys internally if needed, or by having a consistent return type for EphemeralKey() that is always base64 encoded if it's meant for string representation.


keyAccess := keyAccessList[0]
assert.Equal(t, "eccWrapped", keyAccess.KeyType, "EC keys should use 'eccWrapped' key type")
assert.Equal(t, "ec-wrapped", keyAccess.KeyType, "EC keys should use 'ec-wrapped' key type")

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

The previous value eccWrapped was changed to ec-wrapped. This is a good change for consistency with the SchemeType enum, but it's worth noting if this was a deliberate correction or just a refactor. If eccWrapped was used elsewhere, those might need updating too.

require.NoError(t, err, "Should wrap key with EC public key")
assert.NotEmpty(t, wrappedKey, "Should return wrapped key")
assert.Equal(t, "eccWrapped", keyType, "EC keys should use 'eccWrapped' type")
assert.Equal(t, "ec-wrapped", keyType, "EC keys should use 'ec-wrapped' type")

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

The previous value eccWrapped was changed to ec-wrapped. This is a good change for consistency with the SchemeType enum, but it's worth noting if this was a deliberate correction or just a refactor. If eccWrapped was used elsewhere, those might need updating too.

Comment on lines +93 to +94
case ocrypto.RSA2048Key, ocrypto.RSA4096Key, ocrypto.MLKEM768Key, ocrypto.MLKEM1024Key, ocrypto.HybridXWingKey:
return "", errors.New("certificates only available for EC keys")

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

The error message "certificates only available for EC keys" is duplicated. It can be simplified by having a single return statement after the switch, or by making the default case return this error.

Comment on lines 350 to 352
if !ok {
return "", ErrCertNotFound
}

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

There's a redundant if !ok check here. The if !ok on line 348 already handles the case where k is not found. This can be removed.

Suggested change
if !ok {
return "", ErrCertNotFound
}
if !ok {
return "", ErrCertNotFound
}
rsa, ok := k.(PrivateKeyCrypto)

Signed-off-by: David Mihalcik <dmihalcik@virtru.com>
Signed-off-by: David Mihalcik <dmihalcik@virtru.com>
@dmihalcik-virtru
dmihalcik-virtru force-pushed the post-quantum-hybrid-codex-2026-03-dm branch from 21ec012 to 0d61cb0 Compare April 9, 2026 12:30
@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fbdd7e13-7da1-4b3f-9df3-4efeeb0ca898

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch post-quantum-hybrid-codex-2026-03-dm

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • lib/fixtures

See the workflow run for details.

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 203.368284ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 100.701264ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 388.31056ms
Throughput 257.53 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.065529341s
Average Latency 439.53155ms
Throughput 113.47 requests/second

@github-actions

github-actions Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

@dmihalcik-virtru

Copy link
Copy Markdown
Member Author

Merged in #3276

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:db DB component comp:kas Key Access Server comp:lib:ocrypto comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati docs Documentation pqc size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant