Repository navigation
Falcon512 - #1731
Merged
Merged
Falcon512#1731
Conversation
…or the S2morrow account New entry point `starknet/falcon` (built to `dist/falcon/`). `Falcon512Signer` signs for the S2morrow account, whose contract verifies Falcon-512 signatures on a Poseidon hash point. The `falcon512` namespace adds key tools (`generateKeyPair`, `getPublicKey`, `getPackedPublicKey`, `importFalconRsSecretKey`, `exportFalconRsSecretKey`) and off-chain checks (`verify`, `verifyMessage`). Only V3 transactions are supported, and a signature is 61 felts. Security notes are in `src/falcon/SECURITY.md`. The Falcon code is a copy of `@noble/post-quantum` 0.7.1 in `src/falcon/engine/noble/`, with one addition: `falcon512.internal.sign` and `verify` on a hash point computed outside noble, proposed upstream to noble. `PATCH.md` records the diff and the SHA-256 of each copied file, checked by a test. ESLint and Prettier skip the copy. `engine/engine.ts` is the only file that imports it; its JSDoc lists the steps to switch to the npm package once noble publishes this API. `@noble/ciphers` ~2.4.0 becomes a dependency: only the copy imports it, and npm shares it with the copy that `ox` already installs. The main bundle (`dist/index.*`) does not change. Tests: unit tests in `__tests__/utils/falcon/`, with reference data from S2morrow and falcon-rs in `__mocks__/falcon/`, and a devnet test that declares the account class, deploys an account, sends an INVOKE and a DECLARE, and checks a SNIP-12 message off-chain and on-chain. The package check of the CI signs and verifies a message with the built code, with require and import, and type-checks its use with `Account`. Docs: a guide chapter on post-quantum signatures, linked from the Signature guide; a TypeDoc instance and a sidebar category for `starknet/falcon`; a line in AGENTS.md. The API docs no longer show protected members (`excludeProtected`), such as `signRaw` of the signers: they are for subclasses, not for the users of an object.
The examples of `falcon512.generateKeyPair`, `getPublicKey`, `getPackedPublicKey`, `exportFalconRsSecretKey`, and of `Falcon512Signer.getPubKey` and `getPackedPublicKey` built the key from a fixed seed (`new Uint8Array(48).fill(1)`). These examples are published in the API docs and in the type declarations, and a reader who copies one gets a key that anyone can rebuild. They now call `generateKeyPair()` without a seed, and describe the result by what does not depend on the randomness: the sizes, and the header bytes of the formats (89 for the secret key, 9 for the public key). The examples of internal functions, which are not published, keep their fixed seed and exact values. Only comments change.
CodeQL (js/implicit-operand-conversion) flagged `MSG + 1n` in `signature.test.ts`, saying the expression could be converted from undefined to a number. This is a false positive: `MSG` is a bigint constant of the module, so the sum is a bigint and nothing is converted. The test now uses a named constant, `OTHER_MSG` (the value of `MSG + 1`), which also says plainly that the hash is a different one.
Contributor
|
🎉 This PR is included in version 11.4.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation and Resolution
Post-quantum accounts are possible on Starknet today, and starknet.js can now sign for them.
A standard Starknet account signs with ECDSA on the Stark curve. For NIST, ECDSA is "no longer secure" against a large-scale quantum computer (NISTIR 8105, table 1): such a computer could compute the private key of an account from its public key, which is visible on-chain. No such computer exists today, and NIST describes these machines as "years or decades away" (NIST PQC project). But a migration takes years, so NIST already plans it: a draft report (NIST IR 8547, November 2024) proposes to disallow ECDSA in its standards after 2035.
Falcon is one of the three post-quantum signature algorithms selected by NIST in 2022, "for applications that need smaller signatures" (NIST). It rests on lattice problems, which are believed to be hard even for a quantum computer. Thanks to native account abstraction, a Starknet account can check any signature scheme: the S2morrow account contract verifies Falcon-512 signatures on-chain, and its class (
0x37c7626b50ba517835c9556b53bce57cb6633704bb702f8c2f13a44cf151d5) is already declared on Sepolia and Mainnet.This PR adds a signer for this account, in a new entry point
starknet/falcon, so the main bundle does not grow:@noble/post-quantum0.7.1 with one addition: signing and verifying a hash point computed outside noble, because the account hashes the transaction with Poseidon, not with SHAKE256. This addition is proposed upstream to noble. Once noble publishes it,starknet/falconwill use the npm package, with no change to its API (the steps are listed in the JSDoc ofsrc/falcon/engine/engine.ts).src/falcon/SECURITY.mdand in the guide.RPC version (if applicable)
Not applicable: the signer does not depend on the RPC version. Tested on devnet with RPC 0.10.2.
Usage related changes
New entry point
starknet/falcon:Falcon512Signer, aSignerInterfaceto use withAccount;falcon512namespace:generateKeyPair,getPublicKey,getPackedPublicKey,importFalconRsSecretKey,exportFalconRsSecretKey,verify,verifyMessage;Falcon512KeyPair.Fees. Checking a Falcon signature on-chain costs much more L2 gas than an ECDSA one. Measured on devnet: a STRK transfer uses about 25 million L2 gas (about 13 times an ECDSA account), and the deployment about 39 million. By default, starknet.js estimates fees without running the validation of the account, and the node then rejects the transaction: always pass
{ skipValidate: false }.Accounts created with falcon-rs keep working:
Falcon512Signer.fromFalconRs(secretKey)imports their key. A warning explains why such keys should move to a new account for real funds.New dependency
@noble/ciphers(~2.4.0), imported only by the Falcon code; npm shares it with the copy thatoxalready installs.Size:
dist/index.*is unchanged, byte for byte. An app that importsstarknet/falcongrows by about 31 KB gzip; the others do not change. The npm archive grows by 254 KB (compressed).Docs: a new guide chapter, "Post-quantum signature (Falcon-512)", linked from the Signature guide, and API pages for
starknet/falcon. The API docs no longer list protected members, such assignRawof the signers, for all classes: these members are for subclasses, not for the users of an object.Development related changes
src/falcon/, built by tsup as a third entry point (exports,typesVersions), following "Adding an entry point" (the model isstarknet/ledger):engine/engine.tsis the only file that imports the copy of noble;engine/noble/holds the copy, protected from ESLint (header) and Prettier (.prettierignore);PATCH.mdrecords the diff and the SHA-256 of each file;s2morrow/holds the code specific to the account (Poseidon hash-to-point, packing in felts, key formats).__tests__/utils/falcon/, with reference data from S2morrow and falcon-rs in__mocks__/falcon/, plus a test of the SHA-256 of the copy and a test of the import boundaries;__tests__/falconAccount.test.ts: declare the account class, deploy an account, send an INVOKE and a DECLARE, and check a SNIP-12 message off-chain and on-chain, over HTTP and WebSocket.__mocks__/cairo/falcon512Account/, used by the devnet test. Its README gives the source and provenance.starknet/falconblock. It signs and verifies a message with the built code, withrequireandimport, and type-checks its use withAccount, including thatsignRawstays protected.starknet/falcon, andexcludeProtected: truein the shared TypeDoc options.AGENTS.mdlists the new module.Checklist: