Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,15 @@
"overrides": [
{
"files": ["src/**/*.ts"],
"excludedFiles": ["src/ledger/**"],
"excludedFiles": ["src/ledger/**", "src/falcon/**"],
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "starknet",
"message": "Inside src, import from a relative path. Only src/ledger may import the package by its name: anywhere else, the built dist/index.* would load itself."
"message": "Inside src, import from a relative path. Only src/ledger and src/falcon may import the package by its name: anywhere else, the built dist/index.* would load itself."
}
]
}
Expand Down
67 changes: 67 additions & 0 deletions .github/workflows/_package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,73 @@ jobs:
export const missing = signer.transporter.notAMethod;
EOF
- name: check starknet/falcon (part specific to this entry point)
# The only run of the built Falcon code: a new key pair signs a SNIP-12 message, and the
# signature is checked, with require and with import.
working-directory: ${{ runner.temp }}/consumer
run: |
cat > falcon-message.json <<'EOF'
{
"types": {
"StarkNetDomain": [
{ "name": "name", "type": "felt" },
{ "name": "chainId", "type": "felt" },
{ "name": "version", "type": "felt" }
],
"Message": [{ "name": "message", "type": "felt" }]
},
"primaryType": "Message",
"domain": { "name": "Package check", "chainId": "SN_SEPOLIA", "version": "1" },
"message": { "message": "1234" }
}
EOF
cat > falcon.cjs <<'EOF'
const assert = require('node:assert');
const { Falcon512Signer, falcon512 } = require('starknet/falcon');
const typedData = require('./falcon-message.json');
async function main() {
const { secretKey, publicKey } = falcon512.generateKeyPair();
const signature = await new Falcon512Signer(secretKey).signMessage(typedData, '0x123');
assert.strictEqual(signature.length, 61);
assert.ok(falcon512.verifyMessage(typedData, signature, publicKey, '0x123'));
assert.ok(!falcon512.verifyMessage(typedData, signature, publicKey, '0x456'));
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
EOF
node falcon.cjs
cat > falcon.mjs <<'EOF'
import assert from 'node:assert';
import { readFileSync } from 'node:fs';
import { Falcon512Signer, falcon512 } from 'starknet/falcon';
const typedData = JSON.parse(readFileSync('falcon-message.json', 'utf8'));
const { secretKey, publicKey } = falcon512.generateKeyPair();
const signature = await new Falcon512Signer(secretKey).signMessage(typedData, '0x123');
assert.strictEqual(signature.length, 61);
assert.ok(falcon512.verifyMessage(typedData, signature, publicKey, '0x123'));
assert.ok(!falcon512.verifyMessage(typedData, signature, publicKey, '0x456'));
EOF
node falcon.mjs
# Type-checked in the last step.
cat > falcon.ts <<'EOF'
import { Account, RpcProvider } from 'starknet';
import { Falcon512Signer, falcon512, type Falcon512KeyPair } from 'starknet/falcon';
const keys: Falcon512KeyPair = falcon512.generateKeyPair();
const signer = new Falcon512Signer(keys.secretKey);
// The signer of starknet/falcon fits the Account of starknet.
export const account = new Account({ provider: new RpcProvider(), address: '0x123', signer });
// @ts-expect-error signRaw is protected: no public method signs an arbitrary hash.
export const refused = signer.signRaw('0x1');
EOF
- name: type-check every check file
# entries.ts, plus the .ts files of the parts specific to an entry point. An unused
# `@ts-expect-error` is an error too, so a lost type check fails here.
Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vendored copy of @noble/post-quantum, checked by SHA-256 (see src/falcon/engine/noble/PATCH.md).
# Remove this line together with the folder, when starknet/falcon switches to the npm package.
src/falcon/engine/noble/
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ namespaces (`hash`, `num`, `cairo`, `shortString`, …).
| `channel/transport/` | What carries the envelopes, below the channels and independent of the spec version: `HttpTransport`, `WsTransport`, `ReconnectingWsTransport`. |
| `signer/` | `Signer`, `EthSigner`, `LedgerSigner*` (+ `SignerInterface`) — message/transaction signing. The `LedgerSigner*` exported from here are deprecated: see `ledger/`. |
| `ledger/` | Entry point of `starknet/ledger` (built to `dist/ledger/`): `LedgerSigner*` typed with the Ledger `Transport`. In v11 they extend the classes of `signer/`. |
| `falcon/` | Entry point of `starknet/falcon` (built to `dist/falcon/`): `Falcon512Signer`, a post-quantum signer for the S2morrow account. `engine/noble/` is a patched copy of noble: see `PATCH.md`. |
| `wallet/` | `WalletAccountV6` (recommended) / `WalletAccountV5` / `WalletAccount` (deprecated) — browser wallet (get-starknet / wallet-standard) integration. |
| `paymaster/` | `PaymasterRpc` (+ `PaymasterInterface`) — gasless / sponsored transaction flows. |
| `deployer/` | `Deployer` (+ `DeployerInterface`) — UDC-based contract deployment helpers. |
Expand Down
11 changes: 11 additions & 0 deletions __mocks__/cairo/falcon512Account/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Falcon-512 account of S2morrow

Compiled class of the S2morrow account, which checks Falcon-512 signatures on-chain. Used by
`__tests__/falconAccount.test.ts`, which declares it on devnet before the tests.

- Source: `packages/falcon_account/src/preset.cairo` in https://github.com/feltroidprime/s2morrow.
The exact commit is not known: this class was compiled with Cairo 2.12.3 (`compiler_version` of the
`.casm` file), while S2morrow at commit `4eff9ab` uses Cairo 2.15.1.
- Class hash: `0x37c7626b50ba517835c9556b53bce57cb6633704bb702f8c2f13a44cf151d5`. It is the class declared
on Sepolia and on Mainnet (checked on 2026-10-16 with `starknet_getClass` on both networks).
- Constructor: `pk_packed`, the 29 felts of the packed public key (`Falcon512Signer.getPackedPublicKey()`).
Loading
Loading