Skip to content

ML-DSA-65 Post-Quantum Transaction Signatures - #645

Merged
gagdiez merged 10 commits into
masterfrom
wiezzel/pq-signatures
Jul 21, 2026
Merged

ML-DSA-65 Post-Quantum Transaction Signatures#645
gagdiez merged 10 commits into
masterfrom
wiezzel/pq-signatures

Conversation

@Wiezzel

@Wiezzel Wiezzel commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

This draft NEP adds FIPS 204 ML-DSA-65 as a third transaction-signature scheme for NEAR, offered alongside ed25519 and secp256k1 (which are not deprecated). It documents the feature as stabilized at protocol version 85 (neard 2.13):

  • ML-DSA-65 access keys (full-access and function-call) and transaction signing, including DelegateAction inner signers.
  • Access keys stored on-trie by a 32-byte SHA3-256 hash of the public key, so an ML-DSA-65 key costs the same storage stake as an ed25519 key despite a 1952-byte public key.
  • Verification gas pricing (100 Ggas burnt per signature at transaction conversion), so post-quantum signers pay for the extra cost while classical-scheme users are unaffected.
  • Transaction-size accounting that counts the ~3.3 KiB signature in the witness and transaction-size limits.
  • The deliberately out-of-scope items and follow-ups: validator keys, implicit accounts, on-chain verification host functions, and cross-network mirroring.

The reference implementation lives in nearcore behind ProtocolFeature::PostQuantumSignatures; the load-bearing design decisions are captured in the in-tree design note docs/architecture/how/post_quantum_signatures.md.

Status

Draft, opened for Subject Matter Expert review. The NEP number and file name are aligned with this PR number.

@github-project-automation github-project-automation Bot moved this to NEW in NEPs Jul 1, 2026
@github-project-automation github-project-automation Bot moved this to NEW❗ in DevRel Jul 1, 2026
@Wiezzel
Wiezzel force-pushed the wiezzel/pq-signatures branch from 2e339e7 to 5969077 Compare July 1, 2026 10:52
Draft NEP documenting ML-DSA-65 (FIPS 204) as a third transaction-signature
scheme, offered alongside ed25519 and secp256k1 and stabilized at protocol
version 85 (neard 2.13). Covers access-key storage by hash, verification gas
pricing, transaction-size accounting, security implications, and the
out-of-scope follow-ups (validator keys, implicit accounts, host functions).
@Wiezzel
Wiezzel force-pushed the wiezzel/pq-signatures branch from 5969077 to 44d2830 Compare July 1, 2026 10:57
iso.org returns 403 to the link-checker bot (the link resolves fine in a
browser), failing the folder-wide check on a pre-existing link in nep-0177.
Mirrors the eprint.iacr.org ignore added in #644.
@Wiezzel
Wiezzel marked this pull request as ready for review July 2, 2026 08:02
@Wiezzel
Wiezzel requested a review from a team as a code owner July 2, 2026 08:02
@walnut-the-cat walnut-the-cat moved this from NEW to REVIEW in NEPs Jul 2, 2026
@walnut-the-cat walnut-the-cat added the S-review/needs-sme-review A NEP in the REVIEW stage is waiting for Subject Matter Expert review. label Jul 2, 2026
@walnut-the-cat

walnut-the-cat commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Thank you @Wiezzel for submitting this NEP.

As a moderator, I reviewed this NEP and it meets the proposed template guidelines. I am moving this NEP to the REVIEW stage and suggest @gilcu3, @SimonRastikian, and @darioush as SME reviewers to complete a technical review (see expectations). @near/wg-protocol working group members, please let us know if you have better suggestions.

Please find some guidelines below for completing the technical review.

Technical Review Guidelines
  • First, review the proposal within one week. If you have any suggestions that could be fixed, leave them as comments to the author. It may take a couple of iterations to resolve any open comments.
  • Second, once all the suggestions are addressed, produce:
    • A recommendation for the working group if the NEP is ready for voting (it could be approving or rejecting recommendation)
    • A summary of benefits (example)
    • A summary of concerns and blockers that were identified on the way and their status (some will be resolved, others dismissed, etc) (example)

Please tag the @near/nep-moderators once you are done, so we can move this NEP to the voting stage. Thanks again.

@darioush darioush 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.

This is a well written proposal that accurately reflects the implementation in 2.13 release. I recommend the working group consider approving this NEP.

Benefits

  • Allows users to authorize transactions and custody assets using quantum resistant keys today, addressing concerns regarding upredictable timing of quantum computing advancement.
  • Charging the extra verification compute as burnt gas is a practical way to make post-quantum signers pay for the work they add, leaving classical-scheme users unaffected. The additional witness space/bandwidth is bounded by the size-limit accounting but per-byte pricing is deliberately deferred.

Concerns

  • The suggested cryptography scheme has large signatures not amenable to aggregation. Adding a future scheme for use in consensus could require downstream dependencies (wallets, explorers, exchanges) to update again.
  • Deferring universal account scheme to a later protocol upgrade means an account must first go through one of the existing access keys to add a quantum-resistant key.

Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md

@SimonRastikian SimonRastikian left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please next time when you write a doc, do add line breaks so the review is easier to make and so we can propose changes per line not per paragraph

Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md

### ML-DSA-65 parameters and library

ML-DSA-65 is the middle of the three FIPS 204 variants (44 / 65 / 87). It targets **NIST Security Category 3** (comparable to a brute-force key search on AES-192; a Grover-style quantum search gives only a quadratic speedup and remains far out of practical reach).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Instead of the parenthesis say how many bits of security it provides and link the paragraph

Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md
This extra cost is charged as **gas** at transaction conversion, through a new runtime parameter:

- `ml_dsa_65_verification_cost = 100_000_000_000` (100 Ggas), introduced at protocol version 85.
- It is wired through `RuntimeFeesConfig::signature_verification_costs`, an `EnumMap<SignatureKind, ParameterCost>` over `SignatureKind { Ed25519, Secp256k1, MlDsa65 }`. Only `MlDsa65` is non-zero; `Ed25519` and `Secp256k1` are zero, so the classical schemes are unaffected and backwards-compatible.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why here it's MlDsa65 not MLDSA65

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That's a code name. I believe we have a convention of not capitalizing all characters in acronyms, only the first one, when it's a part of a camel-case name.

Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md
### View API and RPC representation

- **`view_access_key_list`** returns `ml-dsa-65-hash:<bs58>` for ML-DSA-65 entries, because the trie stores only the hash. The full public key is not recoverable from chain state. Wallets, explorers, and indexers MUST know their own public key (or recompute the handle from it) to reconcile a chain entry with a known key. This is the same model already used for ETH-style implicit accounts, whose on-chain identifier is also a hash.
- **Rosetta-RPC** gains `CurveType::MlDsa65` and `SignatureType::MlDsa65` (serialized as `"ml_dsa_65"`), with full conversions to and from `KeyType::MLDSA65`. The corresponding upstream addition to the Coinbase Mesh specification is [mesh-specifications#129](https://github.com/coinbase/mesh-specifications/pull/129). Mesh clients that have not picked up the new enum value yet may reject it; this is accepted.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Please MLDSA65 not MlDsa65. It's called Module-Lattice-Based Digital Signature Standard not like Ed25519 where Ed stands for Edwards.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

See my reply here: #645 (comment)

Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md Outdated
Comment thread neps/nep-0645.md

- **Pricing witness/wire size.** Charging for the extra bytes the large signature and public key add is deliberately deferred. The team agreed not to implement it for this milestone; whether and how to track it for a future release was raised and not resolved in the design discussion.
- **External audit.** Whether ML-DSA-65 integration warrants a dedicated external audit beyond the Trail of Bits library recommendation was raised during design and not formally resolved.
- **Mirror / fork-network behavior** is inconsistent (some paths panic, others silently skip). Unifying this to a visible "log and skip" before any serious mirroring of a post-quantum-bearing chain is an open task.

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.

Seems better to resolve this issue soon as well. Maybe the tooling added in offline_test.py can be used for checking the PQ keys work with mirror

- Lead framing with ML-DSA-65; keep PostQuantumSignatures as gate name
- Reframe quantum threat as future forgeability
- Correct signature-count bound (one DelegateAction per tx max)
- Note receipt-carried pubkey, gas-key support, near-sdk UnknownCurve compat
- Trim variable-time section; secp256k1 -> ECDSA wording; minor edits
@Wiezzel Wiezzel changed the title Post-Quantum Transaction Signatures (ML-DSA-65) ML-DSA-65 Post-Quantum Transaction Signatures Jul 6, 2026
Wiezzel added 4 commits July 6, 2026 10:25
RFC 2119 consistency with the surrounding bullets (review nit).
- Reword Positive backwards-compat bullet to avoid overclaiming (SDK caveat)
- Move large-transaction bullet from Neutral to Negative
- Drop redundant mirror Negative (covered in Future/Unresolved)
- Trim SHA3-384 alternative to cross-reference the Security section
The table column mixed casing (ED25519/SECP256K1 vs MlDsa65) because it
mirrored the code enum, which is itself inconsistent. Present scheme names
consistently, matching the trie-encoding table (review nit).
Not adding validator keys / implicit accounts / on-chain verification is
unchanged behavior, not something made worse by the NEP; it is already
listed under Future possibilities (review r3519122004).

@SimonRastikian SimonRastikian left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thank you, much better. One last comment to fix please.

Comment thread neps/nep-0645.md Outdated
Drop the absolute 'a misbehaving signer cannot inflate it' claim. State that
invalid-signature txs are rejected free (uncharged), the gas charge covers
included txs, and the benches (valid/random/tampered) are empirical evidence,
not a formal constant-time guarantee (review r3528320712).
@walnut-the-cat walnut-the-cat added S-voting/needs-wg-voting-indication A NEP in the VOTING stage that needs the working group voting indication. and removed S-review/needs-sme-review A NEP in the REVIEW stage is waiting for Subject Matter Expert review. labels Jul 6, 2026
rfc-editor.org blocks the link-checker bot (Status 0) for a live RFC link in
nep-0488, failing the folder-wide check. Same treatment as the other
standards hosts already ignored (w3.org, eprint.iacr.org, iso.org).
@gagdiez

gagdiez commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

As the moderator, I would like to thank @Wiezzel for submitting this NEP, and for the SME for your review.

Based on the discussion it seems like this proposal is ready to be voted. We have already scheduled a meeting for this Wednesday, and might be able to present the proposal there if you all have time to join.

No worries if not, simply react with a thumbs down (👎) and we will try to find a more suitable time. @Wiezzel during this meeting it would be nice to briefly present the NEP, 1 or 2 slides would suffice.

Meeting Info
📅 Date: Wednesday July 8, 1pm UTC
✏️ Register

cc @Wiezzel @SimonRastikian @darioush

@SimonRastikian SimonRastikian left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thank you!

@birchmd birchmd 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.

As a protocol working group member, I approve this proposal.

I appreciate that the scope of this feature is clearly defined, and while not "fully complete" in a certain sense (missing host function validation for example), it is a minimum viable feature that brings value to users immediately. Even though the total number of NEPs will be higher, I think having smaller proposals iterate on the protocol in manageable-sized increments will be better for stability in the long term.

Adding the option for post-quantum security using a well-accepted algorithm (and corresponding implementation) is a forward-facing upgrade I am happy to see in Near protocol.

I have one minor technical comment, but otherwise the proposal looks good to me.

Comment thread neps/nep-0645.md
Wiezzel added a commit to near/nearcore that referenced this pull request Jul 9, 2026
PublicKey and PublicKeyHandle share a borsh/Hash discriminant-tag
namespace but use disjoint tag sets: PublicKey owns {0,1,2} (tag 2 =
full 1952-byte ML-DSA-65 key) and PublicKeyHandle owns {0,1,3} (tag 3 =
32-byte SHA3-256 hash), so a full key in the trie and a hash on the wire
stay unrepresentable. The reservation was enforced only by hand-written
magic-number match arms, so a future variant could silently reuse a
reserved tag.

Introduce a shared KeyTag enum as the single source of tag bytes, used
by both enums' Hash/BorshSerialize/BorshDeserialize impls, and match it
exhaustively in both deserializers. Adding a future scheme now fails to
compile in both enums until handled explicitly, and the reserved tags
are explicit named error arms (tag 2 rejected by PublicKeyHandle, tag 3
by PublicKey). Encoding is byte-for-byte unchanged.

Addresses review feedback on near/NEPs#645.
@walnut-the-cat walnut-the-cat added S-approved A NEP that was approved by a working group. and removed S-voting/needs-wg-voting-indication A NEP in the VOTING stage that needs the working group voting indication. labels Jul 9, 2026
@walnut-the-cat walnut-the-cat moved this from REVIEW to APPROVED NEPs in NEPs Jul 9, 2026
pull Bot pushed a commit to See887777/nearcore that referenced this pull request Jul 13, 2026
near#16043)

`PublicKey` and `PublicKeyHandle` deliberately use disjoint borsh/hash
tag spaces: `PublicKey` owns {0, 1, 2} (tag 2 = full 1952-byte ML-DSA-65
key) and `PublicKeyHandle` owns {0, 1, 3} (tag 3 = 32-byte SHA3-256
hash), so "a full key in the trie" and "a hash on the wire" stay
unrepresentable. The reservation was enforced only by hand-written
magic-number match arms, so a future variant could silently reuse a
reserved tag.

This introduces a shared `KeyTag` enum as the single source of tag
bytes, used by both enums' `Hash`/`BorshSerialize`/`BorshDeserialize`
impls, and matches it exhaustively in both deserializers. Adding a
future scheme now fails to compile in both enums until it is handled
explicitly, and the reserved tags become explicit named error arms (tag
2 rejected by `PublicKeyHandle`, tag 3 by `PublicKey`). Encoding is
byte-for-byte unchanged, guarded by the existing round-trip and
backwards-compat tests.

Addresses review feedback on
near/NEPs#645 (comment).
@gagdiez

gagdiez commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Thank you to everyone who attended the Contracts Standard meeting on Wednesday! The working group members reviewed the NEP and reached the following consensus:

Status: Approved

#645
Anton approved it during the meeting

Meeting Recording: https://youtu.be/zdDVwdG3yzw

@Wiezzel thanks for authoring this NEP!

Next Steps:

  • @near/nep-moderators To approve and merge the NEP

If anyone is interested in revisiting this NEP, please submit a new one.

@Wiezzel

Wiezzel commented Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

@gagdiez Can I merge now?

@gagdiez
gagdiez merged commit d23a598 into master Jul 21, 2026
2 of 3 checks passed
@gagdiez
gagdiez deleted the wiezzel/pq-signatures branch July 21, 2026 08:38
@github-project-automation github-project-automation Bot moved this from NEW❗ to Shipped 🚀 in DevRel Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-approved A NEP that was approved by a working group.

Projects

Status: Shipped 🚀
Status: APPROVED NEPs

Development

Successfully merging this pull request may close these issues.

7 participants