A stealth address is a pair (A = a*G
, B = b*G
) where A
is the scan key and B
the spend key. Additional subaddress support is described here.
A transaction consists of:
A list of outputs: tuples of the form (C, π, v', n', Ks, Kr, Ke, ρ)
associated to an output address (A, B) composed of:
- an ephemeral key
Ks = ks*G
, chosen by the sender - a receiver public key
Kr = kr*G
whose private key is known only by the receiver - A key exchange public key
Ke = sB = sb*G
, wheres
can be calculated by sender and receiver, butb
is known only by the receiver - a masked value
v'
which is the valuev
encrypted by a shared secrett
- a masked nonce
n'
which is a one-time noncen
encrypted by a shared secrett
- a coin
C = v*H + q*G
for its valuev
, the openingq
of the coin is shared between the sender and recipient of the coin (see 2.3) - a rangeproof
π
that attests thatC
is a commitment to a valuev
<v_max
and also commits to a message(v'||n'||Ks||Kr||Ke||ρ)
- a signature
ρ
, valid under verification keyKs
and message(v'||n'||Ks||Kr||Ke)
Section 2.3.1 describes the calculation of n
, s
, t
, and q
.
A list of inputs. An input is just a signature σ
under some verification key Kr
referencing a previously unspent output.
A kernel, which is composed of:
- the supply
s
, indicating the money created in the transaction - the fee
f
, indicating the fee paid for the transaction - the excess
E = (ΣC + f*H) - (ΣC' + t*G)
wheret
is the transaction's kernel offset - a signature
ψ
, valid under verification keyE
and message(s||f)
The kernel offset t
is a randomly generated scalar which is used to prevent deaggregation of a transaction.
Each kernel could have an associated stealth excess (prunable beyond horizon), which is composed of:
- a reference to a kernel in the transaction:
λ = (s||f||E||ψ)
- stealth excess
E' = e'*G
wheree'
is randomly generated - a signature
φ
, valid under verification keyE'
and messageλ
A transaction must also have 2 associated offsets(scalars), easily summed when aggregating transactions:
- a kernel offset
t = (Σks - Σkr) - Σe
- a stealth offset
t' = (Σks - Σkr) - Σe'
To create an output for value v
to a receiver's stealth address pair (A, B)
, the sender must:
- Randomly generate the sender's keypair
(ks, Ks)
- Derive the nonce
n = HASH16(T_NONCE||ks)
- Derive the sending key
s = HASH32(T_SEND||A||B||v||n)
- Derive the shared secret
t = HASH32(T_DERIVE||s*A)
- Compute the receiver's one-time public key
Kr = B + HASH32(T_RECEIVE||t)*G
- Compute the key exchange public key
Ke = s*B
- Encrypt the value
v' = v ^ HASH8(T_VMASK, t)
- Encrypt the nonce
n' = n ^ HASH16(T_NMASK, t)
- Generate the signature
ρ
for message(v'||n'||Ks||Kr||Ke)
using the sender's keyks
- Compute the commitment
C = v*H + q*G
whereq = HASH32(T_BLIND, t)
- Generate the rangeproof
π
, provingv < v_max
, while also committing to the message(v'||n'||Ks||Kr||Ke||ρ)
Using the receiver private key (kr
) of an unspent output, sign a message (message can be empty string).
same as vanilla MW...need to document
similar to kernel...need to document
In the vanilla Mimblewimble protocol, the chain state can be aggregated into a single transaction with no inputs, all historical kernels, and all unspent outputs (the UTXO set).
With our proposal however, inputs are kept until they have been buried under a sufficient amount of PoW. In particular, we define a horizon height h
for which all inputs & stealth excesses must be kept, and their signatures verified.
To aggregate multiple transactions together, create a new transaction with the combination of all inputs, all outputs, all kernels, all stealth excesses, and calculate:
- kernel offset
t_agg = Σt (mod p)
- stealth offset
t_agg' = Σt' (mod p)
A transaction (or aggregated transaction) is valid iff:
(1) all input signatures are valid signatures under verification key Kr
of the corresponding UTXO
(2) all range proofs are valid, and commit to the associated output data (v'||n'||Ks||Kr||Ke||ρ)
(3) all output signatures ρ
are valid under verification key Ks
and message (v'||n'||Ks||Kr||Ke)
(4) all kernel signatures ψ
are valid under verification key E
and message (s||f)
(5) all stealth excess signatures φ
are valid under verification key E'
and message λ
(6) all kernels referenced (λ
) by stealth excesses must be present in the transaction
(7) values are balanced: (ΣC + (Σf - Σs)*H) - ΣC' = ΣE + t*G
(8) stealth excesses are balanced: (ΣKs - ΣKr) = ΣE' + t'*G
(9) all inputs reference valid UTXOs
While in vanilla MW, outputs could be cut-through as soon as a block spends them, or for unconfirmed transactions, before ever even being included in a block, our proposal explicitly prevents this.
Cut-through (pruning of spent outputs) does not occur until the spend has occured h
blocks in the past (i.e. beyond the horizon). Without knowledge of ks
, which only the sender (output originator) knows, neither receiver nor adversarial observer is able to cut-through an output while still balancing the stealth excess equation (8).
TODO
Would like to Discuss:
- Transaction Malleability
- Consequences of leaking stealth offset
t'
(Σks - Σkr
) in a 1-1 transaction- NOTE: LTC's MWEB currently always creates a change output, even if zero-valued, to avoid this and other issues
- Replay Attacks
- The best solution I could come up with is to have the inputs include an additional "epoch" field, which is basically an acceptable height range.
- Receiver Public Key (
Kr
) reuse- Aside from the obvious privacy leak, could this be used to somehow learn
kr
?
- Aside from the obvious privacy leak, could this be used to somehow learn