# Contractless Browser Core

The `core` directory contains the deterministic cryptography and transaction
codec layer for the Contractless Web3 wallet. Its Rust crate and generated
WASM package retain the name `contractless-browser-core`.

The crate is intentionally independent from the Contractless node runtime. It
does not connect to RPC servers, broadcast transactions, access PostgreSQL or
Sled, run Tokio tasks, or read files from the operating system.

The browser wallet is responsible for:

- obtaining wallet files through browser file APIs;
- keeping decrypted private keys inside the extension;
- presenting transaction details for user approval;
- calling this package to hash, sign, verify, and encode transactions; and
- sending signed transaction bytes to a configured Contractless PHP API.

The initial API exposes:

- Skein-128, Skein-256, and Skein-512 hashing;
- FN-DSA signing and verification;
- public-key to short-address derivation; and
- short-address byte encoding and decoding.
- signed transfer creation and fixed 750-byte transfer decoding.
- strict inspection and signing for every externally submitted transaction type;
- signer-role checks against the wallet public key;
- staged signing for swaps and loans; and
- exact fixed-width wire encoding for completed transactions.
- domain-separated website message signing and verification.
- browser-native wallet generation and AES-256-GCM encrypted storage;
- direct import from existing Contractless private-key images;
- direct import from hexadecimal FN-DSA private keys;
- export compatibility with existing Contractless wallet images; and
- wallet-registration payload creation.

Browser transfer inputs use decimal strings for `value` and `txfee`. This
prevents JavaScript's numeric precision limit from changing a signed `u64`
value.

Fixed transaction codecs will be added individually and tested against the
native Contractless implementation before they are used by the wallet.

## Wallet storage

New browser wallets encrypt their FN-DSA private key with AES-256-GCM. The key
is derived from the wallet password with PBKDF2-SHA256 and a unique random
salt. Only the encrypted wallet JSON is stored persistently by the extension.

Existing Contractless wallet files can be imported with their encryption key.
Browser wallets can also be exported back to the existing wallet image format
for use with the CLI or desktop wallet. The encrypted browser-wallet backup and
its password are both required for recovery.

## Transaction request flow

Websites submit unsigned transaction JSON to `inspect_transaction_request`.
The core rejects unsupported types, missing fields, extra fields, invalid
addresses, incorrect fixed-width values, and malformed numeric values. The
returned review object is the canonical data the wallet must show to the user.

After approval, `sign_transaction_request` receives the wallet private and
public keys. The public key determines the wallet address, and that address
must match the signer role stored in the transaction.

For swaps and loans, signer two must also provide signer one's registered
public key. The core verifies the first signature before adding the second.
Only a complete transaction receives `bytes_hex` suitable for broadcasting.

Genesis and mining reward transactions are intentionally excluded from the
signing registry because users and websites must never create them.

## Website message proofs

`sign_message_request` signs a short-lived website proof without creating a
transaction. The signed payload contains the requesting origin, wallet
address, message, random nonce, issue time, and expiration time.

Message proofs use a Contractless-specific domain prefix. Their signatures
cannot be reused as transaction signatures. Proofs are limited to 15 minutes,
and production origins must use HTTPS.

`verify_message_proof` verifies the public key, derived wallet address,
signature, expected origin, expected nonce, and current validity window.
