# MWEB Consensus
## Prerequisites
### Notation
* Let `G` and `H` be independent generators of the elliptic curve group
* `H(α||β||γ)` represents BLAKE3 hash of concatenated serializations
* Scalar multiplication denoted as `a⋅G` where `a` is scalar
* Point addition/subtraction uses standard `+`/`-` operators
### Cryptographic Assumptions
* All elliptic curve operations use secp256k1
* BLAKE3 outputs are interpreted as scalars modulo the curve order when used in arithmetic
### Glossary
* **PMMR**: Pruned Merkle Mountain Range (data structure for storing UTXOs)
* **TXO**: Transaction Output
* **UTXO**: Unspent Transaction Output
* **HogEx**: MWEB integration transaction
### Transaction Structure
##### Transaction
* x = kernel offset (scalar)
* x' = stealth offset (scalar)
##### Inputs
* Fi = Input features (bitmask)
* 0x01 = Additional input key
* 0x02 = Extra Data (Indicating additional byte vector to be included in the signature message)
* OID = ID of the output being spent
* Ci = Input commitment (Co of the output being spent)
* Ki = Input stealth public key (if 0x01 is set in Fi)
* Mi = Additional input message data (if 0x02 is set in Fi)
* σ = Input signature
##### Kernels
* M = Type, fee, etc.
* E = Kernel excess
* E' = (Optional) Stealth excess
* ψ = Kernel signature
##### Outputs
* Co = Output commitment
* Ks = Sender public key
* Ko = Output public key
* Ke = Key exchange public key
* t[0] = View tag
* v' = Encrypted value
* n' = Encrypted nonce
* ρ = Output signature
## Rules
For kernel-specific rules (feature bits, feature-gated fields, and kernel signature message layout), see [kernels.md](./kernels.md).
#### Identifiers
* The kernel ID (KID) is the BLAKE3 hash of the serialized kernel.
* See [kernels.md](./kernels.md) for the kernel serialization format.
* The output ID (OID) is the BLAKE3 hash of the serialized output.
* OID = H(Co||H(OM)||H(π)||ρ)
---
#### Transaction Uniqueness
* Output hashes (OID) in the UTXO set shall be unique at all times.
* A block shall not contain 2 inputs that spend the same output ID (OID).
* A block shall not be included when it contains an output ID (OID) which already exists in the UTXO set.
* Block is still invalid even if it also contains an input with said output ID (OID).
* A block shall not contain 2 outputs with the same ID (OID).
* Block is still invalid even if it also contains an input with said output ID (OID).
* A block *could* contain an input which spends an output created in the same block, provided the output ID (OID) was not already in the UTXO set.
* To better support payment proofs, the outputs shall still be added to the TXO MMR, but shall be marked as spent.
* A block shall not contain 2 kernels with the same ID (KID).
---
#### Ordering
* Inputs in a block shall be in ascending order by output ID (OID).
* Outputs in a block shall be in ascending order by output ID (OID).
* Kernels in a block shall be ordered by descending supply change (vpegin - (vpegout + f)), with ties broken by ascending kernel ID (KID).
---
#### PMMRs
* After building an MMR with all of the kernels from a block, the root shall match the header's kernel root.
* The number of kernels in a block shall match the header's kernel size.
* After adding all outputs from a block to the end of the output PMMR, the root shall match the header's output root.
* After adding all outputs from a block to the end of the output PMMR, the size shall match the header's output size.
---
#### UTXO LeafSet
* A simple bitset shall be created and maintained to keep track of which TXOs in the output PMMR remain unspent.
* The bit positions shall map 1-to-1 to to PMMR leaf indices. A `0` at that bit position means spent, whereas a `1` means unspent.
* Ex: If byte 0 bit 2 is a `1`, that means TXO at leaf index `2` is unspent. If byte 2 bit 1 is a `0`, the TXO at leaf index `17` has been spent. etc.
* The hash of the serialized UTXO set after applying the transactions in a block shall match the header's UTXO leafset hash.
* Each input spent by a block must reference an existing unspent UTXO entry.
* For each spent input, the input's commitment and output pubkey must exactly match the referenced UTXO.
---
#### Signatures
* Each kernel without a stealth excess (`E'`) shall have a valid signature (ψ) of H(KM) that verifies for the kernel's excess(`E`).
* See [kernels.md](./kernels.md) for the signature message (KM) serialization format
* Each kernel with a stealth excess (`E'`) shall have a valid signature (ψ) of H(KM) for key Eagg = H(E||E')⋅E + E'.
* Each input shall have a valid signature (σ) of IM for key Ksig
* If an input stealth pubkey Ki is included (0x01 set in Fi), Ksig = Ki + H(Ki||Ko)⋅Ko. Otherwise, Ksig = Ko.
* If extra data Mi is included (0x02 set in Fi), IM = H(Fi||OID||Mi). Otherwise, IM = H(Fi||OID).
* Each output shall have a valid signature (ρ) of (Co||OM||H(π)) for the output's sender pubkey (Ks).
* `output_message` (OM) is serialized as OM = (Ko||Ke||t[0]||v'||n'||Ks)
---
#### Bulletproofs
* Each output shall be coupled with a bulletproof that proves the commitment is to a value in the range `[0, 2^64)`.
* Each bulletproof (π) shall commit to the `output_message` using its `extra_commit` functionality.
---
#### Kernel Sums
* The sum of all output commitments (Co) in the UTXO set at a given block height shall equal the sum of all kernel commitments (`E`) plus the `total_kernel_offset*G` (`x*G`) and the `expected_supply*H` (v_total) of the block.
* ΣCo = ΣE + (x⋅G) + (v_total⋅H) where v_total is the total MWEB supply at the block height.
---
#### Stealth Sums
* The sum of all sender pubkeys (Ks) in a block and all input pubkeys (Ki) in the block must equal the sum of all stealth excesses (`E'`) plus `total_stealth_offset*G` (`x'*G`) plus the sum of all output pubkeys (Ko) being spent in the block.
* ΣKs + ΣKi = ΣE' + x'⋅G + ΣKo
---
#### Pegging-In && Pegging-Out
* Kernels may include an optional pegout, containing the `amount` & a `scriptPubKey` (serialized `CScript`)
* The `scriptPubKey` for a pegout shall be non-empty.
* Miners shall include a matching output in a block's `HogEx` transaction with the exact `amount` and `scriptPubKey` for each pegout in the block.
* Kernels may include an optional pegin `amount`
* Each pegin kernel must have a corresponding pegin output on the canonical LTC side where the value is vpegin, witness version is 9, and witness program is the kernel ID (KID).
* The extension block peg-in set must exactly match canonical pegins by `(kernel ID, amount)`.
* Kernel IDs in the canonical block pegin set must be unique.
* The total MWEB supply (v_total) shall increase by the sum of the block's pegins (vpegin), and decrease by the sum of the block's pegouts (vpegout) and the sum of all fees (`f`).
* v_totalnew = v_totalprev + Σvpegin - (Σvpegout + Σf)
* Pegged-out coins require 6 blocks to mature before they can be spent.
---
#### Block Weight
* Outputs shall be counted as having a weight of 17 + 1 (if "standard fields" are included).
* An additional 1 weight shall be added for every 42 bytes included in the `extra_data` field.
* Kernels shall be counted as having a weight of either 2 (without stealth excess) or 3 (with stealth excess).
* For each pegout script included, 1 weight shall be added per every 42 bytes of its `scriptPubKey`.
* An additional 1 weight shall be added for every 42 bytes included in the `extra_data` field.
* Extension blocks shall be capped at a maximum total weight of 200,000.
* Extension blocks shall contain at most 50,000 inputs.
* Inputs shall not contribute toward the block weight unless they contain `extra_data`, which will cost 1 weight per 42 bytes.
#### HogEx
* `HogEx` is a canonical transaction marked with the MWEB serialization flag and an empty MWEB transaction payload.
* `HogEx` is only valid in blocks (never as a loose mempool transaction).
* When MWEB is active:
* A non-null extension block must be present.
* The final transaction in the block must be marked as `HogEx`.
* No earlier transaction in the block may be marked as `HogEx`.
* When MWEB is not active, extension block data must be absent.
* Transactions inside a block must not carry embedded MWEB transaction payloads (`HasMWEBTx() == false`), including `HogEx`.
* `HogEx` must contain at least one output.
* The first `HogEx` output (`vout[0]`) must be a HogAddr witness program: version `8`, 32-byte program.
* That 32-byte program must equal the MWEB block hash committed by the extension block.
* The extension block height must match the canonical block height.
* Peg-in scripts (witness version `9`, 32-byte program) are not allowed in coinbase or `HogEx` outputs.
* HogEx inputs must match block peg-ins exactly, in block/txout scan order:
* For the first `HogEx` after activation, every `HogEx` input is a pegin input.
* For later blocks, `HogEx.vin[0]` must spend the previous block's `HogEx` output `0`, and remaining `HogEx` inputs must be pegin inputs.
* Missing or extra `HogEx` inputs are invalid.
* `HogEx` outputs after the first (`vout[1..]`) are pegout outputs.
* They must match the extension block pegouts by (`amount`, `scriptPubKey`) multiset equality.
* Let Hprev be the previous `HogEx.vout[0]` amount (or `0` for first `HogEx`), and let P be this block's total pegins.
* The `HogEx` fee must be (Hprev + P) - vout_total, and this must equal the extension block total fee.
* The new `HogEx.vout[0]` amount must equal Hprev + supply_change, where supply_change = P - (pegouts + fees).
* Pegout maturity handling:
* `HogEx.vout[0]` is not a pegout and is exempt from pegout maturity.
* `HogEx.vout[1..]` are pegouts and require 6 confirmations before spending.
* Current consensus does **not** globally forbid HogAddr-looking scripts outside `HogEx.vout[0]`; only the first output of `HogEx` is interpreted as the mandatory HogAddr commitment.