5.3 KiB
Warning
Code in this repository is not audited and may contain serious security holes. Use at your own risk.
Safe + Magnetar
This repository brings Magnetar post-quantum threshold signatures to the Safe smart account on the Lux C-Chain EVM. Magnetar is a public-DKG MPC threshold hash-based signature, FIPS 205 byte-equal (FIPS 205 (SLH-DSA) — a Magnetar MPC ceremony signature is byte-equal to a single-party SLH-DSA signature).
Unlike safe-frost — which ships a self-contained secp256k1 Schnorr verifier in
Solidity — Magnetar verification is performed by the on-chain magnetarVerify
precompile at 0x012207 (part of the Lux LP-4200 unified PQCrypto block). The
Solidity in this repository is a thin, decomplected adapter: it frames the
precompile's exact calldata, staticcalls it under a strict success-word check,
and binds the verified key to a Safe owner.
safe-magnetar supports the same three use cases as safe-frost:
- as a Safe signer (an EIP-1271 owner — MagnetarSigner)
- as a Safe co-signer (a transaction guard — SafeMagnetarCoSigner)
- as an ERC-4337 account (MagnetarAccount)
Precompile
| Field | Value |
|---|---|
| Address | 0x012207 |
| Verify ABI (raw wire format) | mode:uint8(1) ‖ pkLen:uint16(2) ‖ pubkey ‖ msgLen:uint16(2)=32 ‖ message(32) ‖ signature |
| Domain-separation context | lux-evm-precompile-magnetar-v1 |
| Return value | 32-byte word: bytes32(1) iff valid, bytes32(0) otherwise (never reverts on a cryptographic false) |
| Reference implementation | github.com/luxfi/precompile/magnetar |
The "message" for every Safe use is the 32-byte Safe-transaction hash (or the
ERC-4337 userOpHash), which is EIP-712-bound to the Safe address, chain id and
nonce — so a signature authorises exactly one Safe / chain / nonce. The
precompile additionally binds the domain-separation context above, so a Magnetar
signature cannot be replayed against any other precompile in the PQCrypto block.
Important
The precompile reads its calldata as a raw packed layout, not an ABI-encoded function call — there is no 4-byte selector. Magnetar.sol frames the bytes exactly as the Go
Run()parses them. Sending an ABI-encoded call (with a selector) would misalign every field.
Contracts
contracts/Magnetar.sol— the verifier library. One function,verify(...), that framesa singlemodebyte (FIPS 205 parameter set; 0x00 = SHA2-128s), the public key / signature and the 32-byte hash into the precompile's wire format and strict-staticcalls0x012207. Holds no state and enforces no policy (decomplected: dispatch only).contracts/SafeMagnetarSigner.sol— an EIP-1271 validator that makes a single Magnetar key a first-class Safe owner. Commit the key once viaaddOwnerWithThreshold; the Safe'scheckNSignaturesvalidates this owner's slice through thev = 0contract-signature path. M-of-N thresholds mixing ECDSA, secp256r1 and Magnetar owners work natively.contracts/SafeMagnetarCoSigner.sol— a Safe transaction guard requiring everyexecTransactionto additionally carry a valid Magnetar co-signature.contracts/MagnetarAccount.sol— an ERC-4337 account authorised by a committed Magnetar key.
Key binding
Magnetar signatures are a standard FIPS 205 SLH-DSA signature (7856 bytes for SHA2-128s). An owner / account therefore commits
a keccak256 of the FIPS 205 group public key at construction (immutable, so the validators are stateless view
functions and side-step the Safe's state-changing-validator guard). At verify
time the supplied key is re-hashed against the commitment, closing the "attacker
supplies an arbitrary key" attack via second-preimage resistance.
Signature payload
The contract-signature / userOp signature payload is abi.encode(bytes pubkey, bytes magnetarSignature) — a standard ABI (bytes, bytes) tuple of the full Magnetar public key and signature.
Testing
forge test
The tests prove verify() against a real known-answer-test (KAT) vector —
7856-byte SLH-DSA-SHA2-128s signature produced by a genuine Magnetar ceremony. The KAT was generated by
lux/precompile/cmd/safekatdump and independently proven to verify against
the real Go precompile by lux/precompile/cmd/safekatverify, so the bytes the
Solidity frames are known to be accepted on-chain.
Because the precompile is a luxd-native Go precompile (absent from a stock
Foundry EVM), the tests install a mock at 0x012207 via vm.etch whose sole job
is to assert calldata-framing conformance: it returns the success word iff
the incoming calldata is byte-for-byte identical to the proven KAT input. Any
drift in the wire format (field order, length-prefix widths, an accidental ABI
selector) changes the calldata and the test fails. The headline test is
Magnetar.t.sol::test_CalldataFramingMatchesPrecompileABI.
The fixture lives at tests/kat.json.
Integration with the Lux ecosystem
This package is part of the Lux blockchain ecosystem.
- GitHub: https://github.com/luxfi
- Docs: https://docs.lux.network
- Sibling PQ Safe wiring:
luxfi/safe/contracts/pq(ML-DSA / SLH-DSA / Pulsar) - Verifier precompile family:
luxfi/precompile(LP-4200 PQCrypto block)