> For the complete documentation index, see [llms.txt](https://quantumwing.gitbook.io/quantumwing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://quantumwing.gitbook.io/quantumwing/transactions/signing.md).

# Signing Process

Signing pre-image, Dilithium and ECDSA paths, replay protection

A QuantumWing transaction is signed by either:

1. **Dilithium Mode 3** — quantum-safe native signature (`SignatureTypeDilithium`).
2. **Authorized ECDSA** — Ethereum-shaped signature pre-authorized to act for a Dilithium account (`SignatureTypeECDSAAuthorized`). Allows MetaMask (and other Ethereum-shaped wallets) to send native QWING transfers. Note: this path signs native transfers only — MetaMask/Remix/Hardhat cannot deploy or call QWVM contracts (no EVM bytecode).

Both paths sign the same canonical pre-image. Only the signature scheme differs.

## Pre-image construction

`blockchain/types/block.go::Transaction.CalculateHash`:

```go
data := fmt.Sprintf("%s|%s|%s|%s|%s|%d|%s|%d|%s",
    tx.Type,            // "transfer", "contract_deploy", ...
    tx.ChainID,         // EIP-155-style replay protection
    tx.From,
    tx.To,
    tx.Value,           // string, Wei
    tx.Nonce,           // uint64
    tx.GasPrice,        // string, Wei
    tx.Gas,             // uint64
    hex(tx.Data),       // empty string if nil/empty
)

// EIP-1559 fields, appended only when present
if MaxFeePerGas != "" || MaxPriorityFeePerGas != "" {
    data += "|1559|" + MaxFeePerGas + "|" + MaxPriorityFeePerGas
}

// Auth-specific fields for ECDSA authorization txs
if tx.Type in {ECDSAAuthorization, ECDSARevocation} {
    data += AuthChainID + AuthVersion + AuthLabel +
            hex(AuthDilithiumPubKey) + hex(AuthDilithiumSig) +
            hex(ECDSAPubKey)
}

txHash = SHA3-256(data)
```

The hash is the Dilithium signing input. **It excludes** `Timestamp`, `Signature`, and `PublicKey` so wire-level reordering or signature replay on a re-broadcast does not change the hash.

`ChainID` is part of the pre-image — testnet / mainnet replay protection is automatic. A transaction signed for `chainID=quantum-mainnet-1` will fail verification on `quantum-testnet-2`.

## Path 1: Dilithium signing

```go
keyPair := &dilithium.KeyPair{PrivateKey: priv, Mode: dilithium.Mode3}
signer  := dilithium.NewSigner(keyPair)

tx.CalculateHash()
sig, _ := signer.Sign([]byte(tx.Hash))
tx.Signature = sig.Signature   // 3293 bytes for Mode 3
tx.PublicKey = pub             // 1952 bytes for Mode 3
```

Verification (`tx.Verify()`):

```go
verifier := verify.NewVerifier([]dilithium.Mode{dilithium.Mode3})
result   := verifier.VerifyWithPublicKey(
              []byte(tx.Hash), tx.Signature, tx.PublicKey, dilithium.Mode3)
return result.Valid
```

The address is independently re-derived from `tx.PublicKey` via `Keccak256(pub)[12:]` and checked against `tx.From`.

## Path 2: Authorized ECDSA

Used by MetaMask and any Ethereum-shape wallet. The Ethereum address must have been pre-authorized to spend from a Dilithium account by submitting a gas-free `TxTypeECDSAAuthorization` transaction (signed by the master Dilithium key).

```go
// MetaMask signs the standard EIP-155 / EIP-2930 / EIP-1559 hash:
ECDSASigningHash := MetaMask-computed hash
ECDSASignature   := 65 bytes (r||s||v)
ECDSAPubKey      := 33 bytes (compressed)
```

Verification (`tx.VerifyECDSA`):

```go
1. len(ECDSASignature) == 65
2. len(ECDSASigningHash) == 32
3. addr_of(ECDSAPubKey)  == tx.From
4. SigToPub(ECDSASigningHash, ECDSASignature) == ECDSAPubKey
5. authStore.IsAuthorized(tx.From, ECDSAPubKey)
6. chainID matches genesis
```

All five checks must pass. Step 5 looks up the authorization store (`blockchain/core/authorization_store.go`) populated by prior auth transactions; a missing entry is a hard fail (no implicit allow-list).

See [../wallets-clients/eip712.md](/quantumwing/wallets-and-clients/eip712.md) for the EIP-712 typed-signing variant.

## Replay protection layers

| Layer         | Mechanism                              |
| ------------- | -------------------------------------- |
| Cross-chain   | `ChainID` in pre-image (EIP-155-style) |
| Same-chain    | Sequential `Nonce` per sender          |
| Same-nonce    | Mempool drops duplicates by `Hash`     |
| Cross-version | `AuthVersion` for ECDSA authorizations |

A double-signed transaction (same sender, same nonce, different content) is one of the inputs the slashing system tracks at the block level — see [../economics/slashing.md](/quantumwing/economics/slashing.md).

## What is NOT in the hash

These fields are wire-level and reset to zero before hashing:

```
Timestamp     (set by node receive time, not by sender)
Signature     (the output we are computing)
PublicKey     (carried alongside, not signed)
Hash          (self-reference)
```

Mempool gossip carries them as extra fields on the wire envelope.

## Code paths

* `blockchain/types/block.go::CalculateHash` — pre-image
* `blockchain/types/block.go::Sign` / `Verify` / `VerifyECDSA`
* `blockchain/core/blockchain.go::AddTransaction` — admission verification
* `blockchain/core/authorization_store.go` — ECDSA auth store
* `crypto/dilithium/` — Mode 2/3/5 sign+verify primitives

## Related

* [format.md](/quantumwing/transactions/format.md) — `Transaction` struct fields
* [../cryptography/dilithium.md](/quantumwing/cryptography/dilithium.md) — Mode 3 details
* [../architecture/canonical-encoding.md](/quantumwing/architecture/canonical-encoding.md) — block-level canonical hash (different mechanism)
* [../wallets-clients/eip712.md](/quantumwing/wallets-and-clients/eip712.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://quantumwing.gitbook.io/quantumwing/transactions/signing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
