02

V0.5 Testnet · One signature, every key

Key derivation

Noid mode doesn’t create a second wallet. Your wallet signs one fixed message, menoid_Wallet, and a deterministic “wallet generator” turns that signature into two key pairs. Same wallet, same signature, same keys — on every device and every chain.

signature = sign("menoid_Wallet")
the wallet generator

Spending key pair

sk = H("menoid/spend", signature) mod l

↓

spendPk = sk · Base8

BabyJubJub — proves ownership inside a proof.

Encryption key pair

encPriv = H("menoid/encryption", signature)

↓

encPub = encPriv · G

Encrypts and decrypts note contents (ECIES).

spendPk + your address

userCommitment = Poseidon(address, spendPk.x, spendPk.y)

Your Noid identity — registered on-chain together with encPub.

Exactly
signature      = sign("menoid_Wallet")                         // no gas, touches no chain
sk             = keccak256("menoid/spend" ‖ signature) mod l   // BabyJubJub scalar
spendPk        = sk · Base8                                    // BabyJubJub point (x, y)
encPriv        = keccak256("menoid/encryption" ‖ signature)
encPub         = encPriv · G                                   // secp256k1, 65 bytes on EVM
userCommitment = Poseidon(address, spendPk.x, spendPk.y)

l is BabyJubJub’s prime subgroup order. The two tags make the keys independent — learning one tells you nothing about the other. On Solana, Sui and Aptos the registered encryption key is a 32-byte ed25519 key instead.

Each field, and why

message

The fixed string menoid_Wallet.

WhyConstant, so the same wallet always produces the same signature — which lets the signature act as a seed.

signature

Your wallet’s signature over it. Free: no transaction.

WhyThe one secret every key comes from.

sk

keccak256 of a tag and the signature, mod l.

WhyThe spending key. It proves you own notes inside a proof, and it goes into every nullifier.

spendPk

sk · Base8 on BabyJubJub.

WhyBabyJubJub lives in the proofs’ own field, so a circuit can rebuild spendPk from sk cheaply.

encPriv · encPub

A second key pair, from a second tag.

WhySeals note contents so only you can read them. encPub is registered so senders can encrypt to you.

userCommitment

Poseidon(address, spendPk.x, spendPk.y).

WhyYour Noid identity: your real address (so people pay your normal address) plus your spending key (so only you can spend).

Why two key pairs

SpendingEncryption
CurveBabyJubJubsecp256k1 (EVM)
JobProve ownership inside a proof; make nullifiersEncrypt and decrypt note contents
Lives inThe circuit’s arithmeticOrdinary software
An on-chain account?NoNo

Why derive from a signature

  • No second address. Earlier designs made a separate “noid wallet”, and people reasonably thought they had two wallets. Now there is only your real address.
  • No second seed phrase. Nothing extra to back up.
  • Recovery for free. Sign menoid_Wallet again on a new device and the same keys come back; your notes are rebuilt from chain events alone.
  • One identity everywhere. The same derivation runs on EVM, Solana, Aptos and Sui.

Example

Same wallet, two devices: the extension on your laptop and the Android app both sign menoid_Wallet with the same key, get the same signature — and so the same sk, encPriv and userCommitment. Both show the same private balance.

The signature is the master secret

Anyone who obtains the menoid_Wallet signature can derive both key pairs and spend every note you own. The wallet never transmits it. (V1’s message names the site and the network for exactly this reason — see From V0.5 to V1.)