lsd0009

LSD0009: The GNU Taler Protocol
Log | Files | Refs | README

commit 84a863a52709045697e2493c69c739b89028b21a
parent 9c03927d864fafd51116f9f4cad18c2a4ea1cdd8
Author: Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
Date:   Tue, 12 Aug 2025 16:32:26 +0200

protocol: migrate payment to Florian-suggested structure

Diffstat:
Mdraft-guetschow-taler-protocol.md | 119++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mdraft-guetschow-taler-protocol.xml | 378++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
2 files changed, 288 insertions(+), 209 deletions(-)

diff --git a/draft-guetschow-taler-protocol.md b/draft-guetschow-taler-protocol.md @@ -490,74 +490,113 @@ persist (coin[i], blind_secret[i]) ~~~ wallet merchant knows merchant.pub knows merchant.priv -knows valid *coin knows exchange, payto +knows valid coin[i] knows exchange, payto | | - | wire_salt = random(128) - | persist order = (id, price, info, token?, wire_salt) + | +----------------------+ + | | (1) order generation | + | +----------------------+ | | |<-------- (order.{id,token?}) ----------| | | -nonce = EdDSA-Keygen() | -persist nonce.priv | ++----------------------+ | +| (2) nonce generation | | ++----------------------+ | | | |------- /orders/{order.id}/claim ------>| | (nonce.pub, token?) | | | - | h_wire = HKDF(wire_salt, payto, - | "merchant-wire-signature", 64) - | determine timestamp, refund_deadline, wire_deadline - | contract = (order.{id,price,info,token?}, - | exchange, h_wire, timestamp, - | refund_deadline, wire_deadline) - | check contract.token = token? - | contract.nonce = nonce - | persist contract - | sig0 = EdDSA-Sign(merchant.priv, msg0) + | +-------------------------+ + | | (3) contract generation | + | +-------------------------+ | | - |<----------- contract, sig0 ------------| + |<----------- contract, sig -------------| | | -check EdDSA-Verify(merchant.pub, msg0, sig0) | -check contract.nonce = nonce | -TODO: double-check extra hash check? | -*(coin, fraction) = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here -*sig1 = EdDSA-Sign(*coin.priv, *msg1) | -*deposit = *(coin.{pub,sig,h_denom}, fraction, sig1) | -persist (contract, sig, *deposit) | ++-------------------------+ | +| (4) payment preparation | | ++-------------------------+ | | | |------- /orders/{order.id}/pay -------->| - | (*deposit) | + | (deposit[i]) | | | - | check sum(*deposit.fraction) = contract.price - | *check Deposit(deposit) - | sig2 = EdDSA-Sign(merchant.priv, msg2) + | +-------------------+ + | | (5) deposit check | + | +-------------------+ | | - |<---------------- sig2 -----------------| + |<---------------- sig ------------------| | | -check EdDSA-Verify(merchant.pub, msg2, sig2) | ++--------------------------+ | +| (6) payment verification | | ++--------------------------+ | ~~~ -where `msg0`, `*msg1`, and `msg2` are formed as follows: +where (without age restriction, policy and wallet data hash) ~~~ -h_contract = SHA-512(canonicalJSON(contract)) +(1) order generation (merchant) -msg0 = Sign-Msg(MERCHANT_CONTRACT, h_contract) -*msg1 = Sign-Msg(WALLET_COIN_DEPOSIT, - ( h_contract | uint256(0x0) - | uint512(0x0) | contract.h_wire | *coin.h_denom - | contract.timestamp | contract.refund_deadline - | *fraction + *denom.fee_deposit - | *denom.fee_deposit | merchant.pub | uint512(0x0) )) -msg2 = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) +wire_salt = random(128) +persist order = (id, price, info, token?, wire_salt) ~~~ -(without age restriction, policy and wallet data hash) +~~~ +(2) nonce generation (wallet) + +nonce = EdDSA-Keygen() +persist nonce.priv +~~~ Note that the private key of `nonce` is currently not used anywhere in the protocol. However, it could be used in the future to prove ownership of an order transaction, enabling use-cases such as "unclaiming" or transferring an order to another person, or proving the payment without resorting to the individual coins. +~~~ +(3) contract generation (merchant) + +h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) +determine timestamp, refund_deadline, wire_deadline +contract = (order.{id,price,info,token?}, exchange, h_wire, timestamp, refund_deadline, wire_deadline) +check contract.order.token = token? +contract.nonce = nonce.pub +persist contract +h_contract = SHA-512(canonicalJSON(contract)) +msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) +sig = EdDSA-Sign(merchant.priv, msg) +~~~ + +~~~ +(4) payment preparation (wallet) + +check EdDSA-Verify(merchant.pub, msg, sig) +check contract.nonce = nonce +TODO: double-check extra hash check? +deposit = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here +msg[i] = Sign-Msg(WALLET_COIN_DEPOSIT, + ( h_contract | uint256(0x0) + | uint512(0x0) | contract.h_wire | coin[i].h_denom + | contract.timestamp | contract.refund_deadline + | deposit[i] + denom[i].fee_deposit + | denom[i].fee_deposit | merchant.pub | uint512(0x0) )) +sig[i] = EdDSA-Sign(coin[i].priv, msg[i]) +deposit[i] = (coin[i].{pub,sig,h_denom}, fraction[i], sig[i]) +persist (contract, sig[i], deposit[i]) +~~~ + +~~~ +(5) deposit check (merchant) + +check sum(deposit[i].fraction) == contract.price +check Deposit(deposit)[i] +msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) +sig = EdDSA-Sign(merchant.priv, msg) +~~~ + +~~~ +(6) payment verification + +check EdDSA-Verify(merchant.pub, msg, sig) +~~~ + ## Deposit ~~~ diff --git a/draft-guetschow-taler-protocol.xml b/draft-guetschow-taler-protocol.xml @@ -526,74 +526,113 @@ persist (coin[i], blind_secret[i]) <figure><artwork><![CDATA[ wallet merchant knows merchant.pub knows merchant.priv -knows valid *coin knows exchange, payto +knows valid coin[i] knows exchange, payto | | - | wire_salt = random(128) - | persist order = (id, price, info, token?, wire_salt) + | +----------------------+ + | | (1) order generation | + | +----------------------+ | | |<-------- (order.{id,token?}) ----------| | | -nonce = EdDSA-Keygen() | -persist nonce.priv | ++----------------------+ | +| (2) nonce generation | | ++----------------------+ | | | |------- /orders/{order.id}/claim ------>| | (nonce.pub, token?) | | | - | h_wire = HKDF(wire_salt, payto, - | "merchant-wire-signature", 64) - | determine timestamp, refund_deadline, wire_deadline - | contract = (order.{id,price,info,token?}, - | exchange, h_wire, timestamp, - | refund_deadline, wire_deadline) - | check contract.token = token? - | contract.nonce = nonce - | persist contract - | sig0 = EdDSA-Sign(merchant.priv, msg0) + | +-------------------------+ + | | (3) contract generation | + | +-------------------------+ | | - |<----------- contract, sig0 ------------| + |<----------- contract, sig -------------| | | -check EdDSA-Verify(merchant.pub, msg0, sig0) | -check contract.nonce = nonce | -TODO: double-check extra hash check? | -*(coin, fraction) = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here -*sig1 = EdDSA-Sign(*coin.priv, *msg1) | -*deposit = *(coin.{pub,sig,h_denom}, fraction, sig1) | -persist (contract, sig, *deposit) | ++-------------------------+ | +| (4) payment preparation | | ++-------------------------+ | | | |------- /orders/{order.id}/pay -------->| - | (*deposit) | + | (deposit[i]) | | | - | check sum(*deposit.fraction) = contract.price - | *check Deposit(deposit) - | sig2 = EdDSA-Sign(merchant.priv, msg2) + | +-------------------+ + | | (5) deposit check | + | +-------------------+ | | - |<---------------- sig2 -----------------| + |<---------------- sig ------------------| | | -check EdDSA-Verify(merchant.pub, msg2, sig2) | ++--------------------------+ | +| (6) payment verification | | ++--------------------------+ | ]]></artwork></figure> -<t>where <spanx style="verb">msg0</spanx>, <spanx style="verb">*msg1</spanx>, and <spanx style="verb">msg2</spanx> are formed as follows:</t> +<t>where (without age restriction, policy and wallet data hash)</t> <figure><artwork><![CDATA[ -h_contract = SHA-512(canonicalJSON(contract)) +(1) order generation (merchant) -msg0 = Sign-Msg(MERCHANT_CONTRACT, h_contract) -*msg1 = Sign-Msg(WALLET_COIN_DEPOSIT, - ( h_contract | uint256(0x0) - | uint512(0x0) | contract.h_wire | *coin.h_denom - | contract.timestamp | contract.refund_deadline - | *fraction + *denom.fee_deposit - | *denom.fee_deposit | merchant.pub | uint512(0x0) )) -msg2 = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) +wire_salt = random(128) +persist order = (id, price, info, token?, wire_salt) ]]></artwork></figure> -<t>(without age restriction, policy and wallet data hash)</t> +<figure><artwork><![CDATA[ +(2) nonce generation (wallet) + +nonce = EdDSA-Keygen() +persist nonce.priv +]]></artwork></figure> <t>Note that the private key of <spanx style="verb">nonce</spanx> is currently not used anywhere in the protocol. However, it could be used in the future to prove ownership of an order transaction, enabling use-cases such as "unclaiming" or transferring an order to another person, or proving the payment without resorting to the individual coins.</t> +<figure><artwork><![CDATA[ +(3) contract generation (merchant) + +h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) +determine timestamp, refund_deadline, wire_deadline +contract = (order.{id,price,info,token?}, exchange, h_wire, timestamp, refund_deadline, wire_deadline) +check contract.order.token = token? +contract.nonce = nonce.pub +persist contract +h_contract = SHA-512(canonicalJSON(contract)) +msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) +sig = EdDSA-Sign(merchant.priv, msg) +]]></artwork></figure> + +<figure><artwork><![CDATA[ +(4) payment preparation (wallet) + +check EdDSA-Verify(merchant.pub, msg, sig) +check contract.nonce = nonce +TODO: double-check extra hash check? +deposit = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here +msg[i] = Sign-Msg(WALLET_COIN_DEPOSIT, + ( h_contract | uint256(0x0) + | uint512(0x0) | contract.h_wire | coin[i].h_denom + | contract.timestamp | contract.refund_deadline + | deposit[i] + denom[i].fee_deposit + | denom[i].fee_deposit | merchant.pub | uint512(0x0) )) +sig[i] = EdDSA-Sign(coin[i].priv, msg[i]) +deposit[i] = (coin[i].{pub,sig,h_denom}, fraction[i], sig[i]) +persist (contract, sig[i], deposit[i]) +]]></artwork></figure> + +<figure><artwork><![CDATA[ +(5) deposit check (merchant) + +check sum(deposit[i].fraction) == contract.price +check Deposit(deposit)[i] +msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) +sig = EdDSA-Sign(merchant.priv, msg) +]]></artwork></figure> + +<figure><artwork><![CDATA[ +(6) payment verification + +check EdDSA-Verify(merchant.pub, msg, sig) +]]></artwork></figure> + </section> <section anchor="deposit"><name>Deposit</name> @@ -746,7 +785,7 @@ msg3 = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, -<?line 612?> +<?line 651?> <section anchor="change-log"><name>Change log</name> @@ -764,134 +803,135 @@ Education and Research (BMBF) within the project Concrete Contracts.</t> </back> <!-- ##markdown-source: -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 -/wPrnFD5KU0AAA== +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 -->