Overview
Your Nyx private account follows one simple rule:The only way to authorize anything from your Nyx private account is to sign a
message with your connected Ethereum wallet, and what you sign is exactly
what gets executed.
Your account is a smart contract
On Aztec, every account is a smart contract (see Account overview). That contract decides what counts as a valid authorization. Nyx private accounts run a contract calledEip712SignedMessageAccount. It has three key properties:
- One key, set at creation. When your private account is created, your Ethereum wallet’s public key is written into the contract as an immutable private note. No function exists to change it, add another key, or bypass it.
- No admin, no backdoor. The contract has no owner, guardian, or recovery key. The Nyx backend has no way to authorize a transaction for you.
- Your wallet does the signing. Authorization uses standard EIP-712 typed data signatures, the same kind used across Ethereum for permits and off-chain orders. Any Ethereum EOA wallet (non-smart contract wallet) works, including hardware wallets, and your private key never leaves it.
What you sign
Each time you send a private transaction, your wallet shows a structured EIP-712 message instead of an unreadable hex blob. Here is a simplified example of a private send of 1 USDC:Why what you sign is what gets executed
A typical Ethereum transaction signature covers raw calldata, and your wallet has to decode it to show you something readable. If the wallet decodes it wrong, or a site tricks it, what you see can differ from what you sign. Nyx works the other way around. The human-readable message is what gets signed, and the account contract checks it against the transaction it is about to run. When your transaction executes, the account contract:- Receives the list of function calls to execute.
- Rebuilds the full EIP-712 message from those exact calls: their target addresses, function signatures, and arguments as text.
- Verifies your wallet’s signature against that rebuilt message, using the public key stored at account creation.
- Executes the calls only if the signature is valid. Otherwise the transaction fails.
- Function signature → function. The function that gets called is computed from the signature text you saw.
You can’t sign
transfer(...)and have the account callwithdraw_everything(...). - Args → argsHash → execution. The contract re-encodes the displayed arguments and checks that they hash to
argsHash, which is the exact input passed to the call. You can’t sign “send 1 USDC” and have the account send 1,000. Numeric text such as1000000is parsed back into a number inside the contract, so the text can’t be faked either. - Target address → target. The call goes to exactly the
targetAddressyou saw. - Account, network, and transaction binding.
outerHashcombines your account address, the network’s chain ID and rollup version, and a hash of the whole payload including a randomnonce. A signature for one transaction can’t be reused for a different account, a different network, or different calls.
The description is a non-verified comment
Thedescription field is a plain-language summary written by the app, such as “Privately send 1 USDC to Alice.”
It’s part of the signed message, so it can’t be changed after you sign, but the contract does not check that it matches the function calls.
That’s impossible in general: the description is free text.
Treat the description as a helpful comment and the functionCalls as the truth.
If the two disagree, trust functionCalls, and don’t sign.
Reading the caution line
Thecaution line comes from a fixed set built into the account contract.
An app can’t choose its own caution text, and the contract checks that the right one was shown.
Letting a contract act for you
Some actions need another contract to do something on your behalf. For example, when you send funds from your private account to Ethereum, the token bridge contract has to burn tokens from your private balance. In Aztec, that permission is called an authentication witness. Nyx shows it as a separate signing request with primary typeAztecCallIntent:
calleris the only contract allowed to use this permission.functionCallis the only call it may make with it, with exactly these arguments.
Blind signing
Clear signing has fixed size limits, because every displayed value must be processed inside a zero-knowledge circuit. Currently, a transaction is clear-signed when:- It has at most 2 function calls.
- Each call has at most 6 arguments (call intents: at most 6).
- Each function signature fits in 93 bytes, and each text argument fits in 31 bytes.
- All arguments are field elements, unsigned integers, booleans, or short strings.
AztecOpaqueTransactionRequest (or AztecOpaqueCallIntent). It shows the caution, description, account address, and network, plus an outerHash in place of the readable calls.
Blind signatures are still bound to one account, one network, and one exact set of calls. The outerHash commits to all of that, so the signature can’t be reused for anything else.
What you lose is the ability to see the calls in your wallet. You’re relying on the app to have built the transaction honestly.
Checklist before you sign
- Make sure you started the action. Only sign a request that comes right after something you did in the app, such as clicking Send. If a signing request appears out of nowhere, reject it.
- Check the site. Make sure you’re on
nyx.money, especially if the caution line asks you to. - Check the caution line. If it starts with
Blind signing., take extra care. - Check the account.
accountAddressshould be your own private account. - Check the calls, not just the description. Look at
targetAddress,functionSignature, andargsfor each call. Expect a smallsponsor()call to Nyx’s JuiceBar contract, which pays your network fees. - Check the amounts in smallest units, and check recipient addresses.
- For call intents, check
caller. It should be the contract you expect, such as the token bridge for a withdrawal.
Source code
Nyx is still under active development, and the details on this page may change as it evolves. The behavior described here is implemented in two places:- The on-chain account contract, which verifies signatures and executes calls.
- The client-side code in the Nyx app, which builds the EIP-712 messages your wallet shows.