lsd0009

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

commit 03ef78ac0243a3705c49f41e7edb78f039e957f2
parent 624a15a981cd3e1fd956a1cd3ac692aebab50346
Author: Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
Date:   Mon,  6 Apr 2026 12:07:40 +0200

protocol: pass-through to fix notation

Diffstat:
Mdraft-guetschow-taler-protocol.md | 89++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mdraft-guetschow-taler-protocol.xml | 373++++++++++++++++++++++++++++++++++++++++---------------------------------------
2 files changed, 236 insertions(+), 226 deletions(-)

diff --git a/draft-guetschow-taler-protocol.md b/draft-guetschow-taler-protocol.md @@ -387,22 +387,24 @@ Output: out = uint32(len(msg)) | uint32(purpose) | msg ~~~ -// todo: explain persist, check, knows, sum, indexing (if left of equal sign, single entry; if not refers to whole list) - # The Taler Crypto Protocol +// todo: explain persist, check, knows, sum, indexing/list notation + ## Withdrawal {#withdrawal} -The wallet generates `n > 0` coins (`coinᵢ`) and requests `n` signatures (`blind_sigᵢ`) from the exchange, -attributing value to the coins according to `n` chosen denominations (`denomᵢ`). +The wallet generates `n > 0` coins `⟨coinᵢ⟩` and requests `n` signatures `⟨blind_sigᵢ⟩` from the exchange, +attributing value to the coins according to `n` chosen denominations `⟨denomᵢ⟩`. The total value and withdrawal fee (defined by the exchange per denomination) must be smaller or equal to the amount stored in the single reserve used for withdrawal. +// notation: ⟨⟩ᵢ + // todo: extend with extra roundtrip for CBS ~~~ wallet exchange -knows denomᵢ.pub knows denomᵢ.priv +knows ⟨denomᵢ⟩ knows ⟨denomᵢ.priv⟩ | | +-----------------------------+ | | (W1) reserve key generation | | @@ -420,14 +422,14 @@ knows denomᵢ.pub knows denomᵢ.priv +-----------------------------------+ | | | |-------------- /withdraw -------------->| - | (reserve.pub, ~(coinᵢ.h_denom), | - | ~blind_coin, sig0) | + | (reserve.pub, ⟨coinᵢ.h_denom⟩, | + | ⟨blind_coinᵢ⟩, sig) | | | | +--------------------------------+ | | (E1) coin issuance and signing | | +--------------------------------+ | | - |<----------- (~blind_sig) --------------| + |<---------- (⟨blind_sigᵢ⟩) -------------| | | +----------------------+ | | (W3) coin unblinding | | @@ -461,8 +463,8 @@ coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv) coinᵢ.h_denom = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub) blind_coinᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub) msg = Sign-Msg(WALLET_RESERVE_WITHDRAW, - ( sum(denomᵢ.value) | sum(denomᵢ.fee_withdraw) - | SHA-512( SHA-512(~(denomᵢ.pub)) | uint32(0x1) | blind_coinᵢ ) + ( sum( ⟨denomᵢ.value⟩ ) | sum( ⟨denomᵢ.fee_withdraw⟩ ) + | SHA-512( SHA-512( ⟨denomᵢ.pub⟩ ) | uint32(0x1) | ⟨blind_coinᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) )) sig = EdDSA-Sign(reserve.priv, msg) ~~~ @@ -474,32 +476,32 @@ denomᵢ = Denom-Lookup(coinᵢ.h_denom) check denomᵢ.pub known and not withdrawal-expired check EdDSA-Verify(reserve.pub, msg, sig) check reserve KYC status ok or not needed -total = sum(~(denomᵢ.value)) + sum(~(denomᵢ.fee_withdraw)) +total = sum( ⟨denomᵢ.value⟩ ) + sum( ⟨denomᵢ.fee_withdraw⟩ ) check reserve.balance >= total reserve.balance -= total blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv) -persist withdrawal +persist withdrawal // todo: what exactly? should be checked first? ~~~ ~~~ -(W4) coin unblinding (wallet) +(W3) coin unblinding (wallet) coinᵢ.sig = RSA-FDH-Unblind(blind_sigᵢ, blind_secretᵢ, denomᵢ.pub) check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) -persist (coinᵢ, blind_secretᵢ) +persist (coinᵢ, blind_secretᵢ) // todo: why blind_secret, if master_secret already persisted? ~~~ ## Payment {#payment} The wallet obtains `contract` information for an `order` from the merchant after claiming it with a `nonce`. -Payment of the order is prepared by signing (partial) deposit authorizations (`depositᵢ`) of coins (`coinᵢ`), +Payment of the order is prepared by signing (partial) deposit authorizations `⟨depositᵢ⟩` with coins `⟨coinᵢ⟩` of certain denominations `⟨denomᵢ⟩`, where the sum of all contributions (`contributionᵢ <= denomᵢ.value`) must match the `contract.price` plus potential deposit fees. The payment is complete as soon as the merchant successfully redeems the deposit authorizations at the exchange (cf. {{deposit}}). ~~~ wallet merchant -knows valid coinᵢ knows merchant.priv +knows ⟨coinᵢ⟩ knows merchant.priv knows exchange, payto | | | +-----------------------+ @@ -520,14 +522,14 @@ knows valid coinᵢ knows merchant.priv | | (M2) contract generation | | +--------------------------+ | | - |<---- (contract, merchant.pub, contract_sig) ----| + |<---- (contract, merchant.pub, sig) ----| | | +--------------------------+ | | (W2) payment preparation | | +--------------------------+ | | | |------- /orders/{order.id}/pay -------->| - | (~deposit) | + | (⟨depositᵢ⟩) | | | | +--------------------+ | | (M3) deposit check | @@ -547,6 +549,7 @@ where (without age restriction, policy and wallet data hash) (M1) order generation (merchant) wire_salt = random(128) +determine id, price, info, token? persist order = (id, price, info, token?, wire_salt) ~~~ @@ -565,15 +568,15 @@ or proving the payment without resorting to the individual coins. ~~~ (M2) contract generation (merchant) +check order.token? == 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.order.token == token contract.nonce = nonce.pub persist contract h_contract = SHA-512(canonicalJSON(contract)) msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) -contract_sig = EdDSA-Sign(merchant.priv, msg) +sig = EdDSA-Sign(merchant.priv, msg) ~~~ ~~~ @@ -581,12 +584,11 @@ contract_sig = EdDSA-Sign(merchant.priv, msg) h_contract = SHA-512(canonicalJSON(contract)) msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) -check EdDSA-Verify(merchant.pub, msg, contract_sig) -check contract.nonce = nonce -TODO: double-check extra hash check? -~selection = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here +check EdDSA-Verify(merchant.pub, msg, sig) +check contract.nonce == nonce +// TODO: double-check extra hash check? +⟨selectionᵢ⟩ = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here (coinᵢ, denomᵢ, contributionᵢ) = selectionᵢ -h_contract = SHA-512(canonicalJSON(contract)) msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, ( h_contract | uint256(0x0) | uint512(0x0) | contract.h_wire | coinᵢ.h_denom @@ -595,19 +597,18 @@ msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) sigᵢ = EdDSA-Sign(coinᵢ.priv, msgᵢ) depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ) -persist (contract, ~sig, ~deposit) +persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) ~~~ // TODO: explain CoinSelection -// TODO: maybe better {sigᵢ} instead of ~sig? // TODO: maybe introduce symbol for pub/priv // TODO: maybe rename Sign-Msg as name is currently a bit confusing ~~~ (M3) deposit check (merchant) -check sum(depositᵢ.contribution) == contract.price -check Deposit(~deposit) +check sum( ⟨depositᵢ.contribution⟩ ) == contract.price +check Deposit(⟨depositᵢ⟩) msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) sig = EdDSA-Sign(merchant.priv, msg) ~~~ @@ -623,20 +624,22 @@ check EdDSA-Verify(merchant.pub, msg, sig) // todo: add introductory text +Deposit could also be used directly by a wallet with its own payto and a minimal contract. + ~~~ - merchant/wallet exchange + merchant exchange knows exchange.pub knows exchange.priv -knows contract_sig knows denomᵢ.pub +knows merchant.priv knows ⟨denomᵢ⟩ knows payto, wire_salt | -knows contract, ~deposit | +knows contract, ⟨depositᵢ⟩ | | | +--------------------------+ | | (M1) deposit preparation | | +--------------------------+ | | | |----------- /batch-deposit ------------>| - | (info, h_contract, ~deposit | - | merchant.pub, contract_sig) | + | (info, h_contract, ⟨depositᵢ⟩ | + | merchant.pub, sig) | | | | +-------------------------+ | | (E1) deposit validation | @@ -653,11 +656,13 @@ knows contract, ~deposit | where (without age restriction, policy and wallet data hash) ~~~ -(M1) Deposit preparation (merchant/wallet) +(M1) Deposit preparation (merchant) -h_contract = SHA-512(canonicalJSON(contract)) info.time = contract.{timestamp, wire_deadline, refund_deadline} info.wire = (payto, wire_salt) +h_contract = SHA-512(canonicalJSON(contract)) +msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) +sig = EdDSA-Sign(merchant.priv, msg) ~~~ ~~~ @@ -665,7 +670,7 @@ info.wire = (payto, wire_salt) coinᵢ = depositᵢ.coin denomᵢ = Denom-Lookup(coinᵢ.h_denom) -check denomᵢ.pub known and not deposit-expired +check denomᵢ.pub known and not deposit-expired // todo: check could be included in Denom-Lookup h_wire = HKDF(info.wire.wire_salt, info.wire.payto, "merchant-wire-signature", 64) msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, ( h_contract | uint256(0x0) @@ -683,21 +688,21 @@ msg = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, ( h_contract | h_wire | uint512(0x0) | timestamp | info.time.wire_deadline | info.time.refund_deadline - | sum(depositᵢ.contribution) - sum(denomᵢ.fee_deposit) - | SHA-512(depositᵢ.sig) | merchant.pub )) + | sum( ⟨depositᵢ.contribution⟩ ) + | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) sig = EdDSA-Sign(exchange.priv, msg) ~~~ ~~~ -(M2) Deposit verification (merchant/wallet) +(M2) Deposit verification (merchant) h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) msg = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, ( h_contract | h_wire | uint512(0x0) | timestamp | contract.wire_deadline | contract.refund_deadline - | sum(depositᵢ.contribution) - sum(denomᵢ.fee_deposit) - | SHA-512(depositᵢ.sig) | merchant.pub )) + | sum( ⟨depositᵢ.contribution⟩ ) + | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) check EdDSA-Verify(exchange.pub, msg, sig) ~~~ diff --git a/draft-guetschow-taler-protocol.xml b/draft-guetschow-taler-protocol.xml @@ -24,7 +24,7 @@ <email>mikolai.guetschow@tu-dresden.de</email> </address> </author> - <date year="2026" month="April" day="02"/> + <date year="2026" month="April" day="06"/> <workgroup>independent</workgroup> <keyword>taler</keyword> <keyword>cryptography</keyword> @@ -376,21 +376,22 @@ Output: <artwork><![CDATA[ out = uint32(len(msg)) | uint32(purpose) | msg ]]></artwork> - <t>// todo: explain persist, check, knows, sum, indexing (if left of equal sign, single entry; if not refers to whole list)</t> </section> </section> <section anchor="the-taler-crypto-protocol"> <name>The Taler Crypto Protocol</name> + <t>// todo: explain persist, check, knows, sum, indexing/list notation</t> <section anchor="withdrawal"> <name>Withdrawal</name> - <t>The wallet generates <tt>n &gt; 0</tt> coins (<tt>coinᵢ</tt>) and requests <tt>n</tt> signatures (<tt>blind_sigᵢ</tt>) from the exchange, -attributing value to the coins according to <tt>n</tt> chosen denominations (<tt>denomᵢ</tt>). + <t>The wallet generates <tt>n &gt; 0</tt> coins <tt>⟨coinᵢ⟩</tt> and requests <tt>n</tt> signatures <tt>⟨blind_sigᵢ⟩</tt> from the exchange, +attributing value to the coins according to <tt>n</tt> chosen denominations <tt>⟨denomᵢ⟩</tt>. The total value and withdrawal fee (defined by the exchange per denomination) must be smaller or equal to the amount stored in the single reserve used for withdrawal.</t> + <t>// notation: ⟨⟩ᵢ</t> <t>// todo: extend with extra roundtrip for CBS</t> <artwork><![CDATA[ wallet exchange -knows denomᵢ.pub knows denomᵢ.priv +knows ⟨denomᵢ⟩ knows ⟨denomᵢ.priv⟩ | | +-----------------------------+ | | (W1) reserve key generation | | @@ -408,14 +409,14 @@ knows denomᵢ.pub knows denomᵢ.priv +-----------------------------------+ | | | |-------------- /withdraw -------------->| - | (reserve.pub, ~(coinᵢ.h_denom), | - | ~blind_coin, sig0) | + | (reserve.pub, ⟨coinᵢ.h_denom⟩, | + | ⟨blind_coinᵢ⟩, sig) | | | | +--------------------------------+ | | (E1) coin issuance and signing | | +--------------------------------+ | | - |<----------- (~blind_sig) --------------| + |<---------- (⟨blind_sigᵢ⟩) -------------| | | +----------------------+ | | (W3) coin unblinding | | @@ -445,8 +446,8 @@ coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv) coinᵢ.h_denom = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub) blind_coinᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub) msg = Sign-Msg(WALLET_RESERVE_WITHDRAW, - ( sum(denomᵢ.value) | sum(denomᵢ.fee_withdraw) - | SHA-512( SHA-512(~(denomᵢ.pub)) | uint32(0x1) | blind_coinᵢ ) + ( sum( ⟨denomᵢ.value⟩ ) | sum( ⟨denomᵢ.fee_withdraw⟩ ) + | SHA-512( SHA-512( ⟨denomᵢ.pub⟩ ) | uint32(0x1) | ⟨blind_coinᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) )) sig = EdDSA-Sign(reserve.priv, msg) ]]></artwork> @@ -457,30 +458,30 @@ denomᵢ = Denom-Lookup(coinᵢ.h_denom) check denomᵢ.pub known and not withdrawal-expired check EdDSA-Verify(reserve.pub, msg, sig) check reserve KYC status ok or not needed -total = sum(~(denomᵢ.value)) + sum(~(denomᵢ.fee_withdraw)) +total = sum( ⟨denomᵢ.value⟩ ) + sum( ⟨denomᵢ.fee_withdraw⟩ ) check reserve.balance >= total reserve.balance -= total blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv) -persist withdrawal +persist withdrawal // todo: what exactly? should be checked first? ]]></artwork> <artwork><![CDATA[ -(W4) coin unblinding (wallet) +(W3) coin unblinding (wallet) coinᵢ.sig = RSA-FDH-Unblind(blind_sigᵢ, blind_secretᵢ, denomᵢ.pub) check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) -persist (coinᵢ, blind_secretᵢ) +persist (coinᵢ, blind_secretᵢ) // todo: why blind_secret, if master_secret already persisted? ]]></artwork> </section> <section anchor="payment"> <name>Payment</name> <t>The wallet obtains <tt>contract</tt> information for an <tt>order</tt> from the merchant after claiming it with a <tt>nonce</tt>. -Payment of the order is prepared by signing (partial) deposit authorizations (<tt>depositᵢ</tt>) of coins (<tt>coinᵢ</tt>), +Payment of the order is prepared by signing (partial) deposit authorizations <tt>⟨depositᵢ⟩</tt> with coins <tt>⟨coinᵢ⟩</tt> of certain denominations <tt>⟨denomᵢ⟩</tt>, where the sum of all contributions (<tt>contributionᵢ &lt;= denomᵢ.value</tt>) must match the <tt>contract.price</tt> plus potential deposit fees. The payment is complete as soon as the merchant successfully redeems the deposit authorizations at the exchange (cf. <xref target="deposit"/>).</t> <artwork><![CDATA[ wallet merchant -knows valid coinᵢ knows merchant.priv +knows ⟨coinᵢ⟩ knows merchant.priv knows exchange, payto | | | +-----------------------+ @@ -501,14 +502,14 @@ knows valid coinᵢ knows merchant.priv | | (M2) contract generation | | +--------------------------+ | | - |<---- (contract, merchant.pub, contract_sig) ----| + |<---- (contract, merchant.pub, sig) ----| | | +--------------------------+ | | (W2) payment preparation | | +--------------------------+ | | | |------- /orders/{order.id}/pay -------->| - | (~deposit) | + | (⟨depositᵢ⟩) | | | | +--------------------+ | | (M3) deposit check | @@ -526,6 +527,7 @@ knows valid coinᵢ knows merchant.priv (M1) order generation (merchant) wire_salt = random(128) +determine id, price, info, token? persist order = (id, price, info, token?, wire_salt) ]]></artwork> <artwork><![CDATA[ @@ -541,27 +543,26 @@ or proving the payment without resorting to the individual coins.</t> <artwork><![CDATA[ (M2) contract generation (merchant) +check order.token? == 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.order.token == token contract.nonce = nonce.pub persist contract h_contract = SHA-512(canonicalJSON(contract)) msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) -contract_sig = EdDSA-Sign(merchant.priv, msg) +sig = EdDSA-Sign(merchant.priv, msg) ]]></artwork> <artwork><![CDATA[ (W2) payment preparation (wallet) h_contract = SHA-512(canonicalJSON(contract)) msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) -check EdDSA-Verify(merchant.pub, msg, contract_sig) -check contract.nonce = nonce -TODO: double-check extra hash check? -~selection = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here +check EdDSA-Verify(merchant.pub, msg, sig) +check contract.nonce == nonce +// TODO: double-check extra hash check? +⟨selectionᵢ⟩ = CoinSelection(contract.{exchange,price}) TODO: include MarkDirty here (coinᵢ, denomᵢ, contributionᵢ) = selectionᵢ -h_contract = SHA-512(canonicalJSON(contract)) msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, ( h_contract | uint256(0x0) | uint512(0x0) | contract.h_wire | coinᵢ.h_denom @@ -570,17 +571,16 @@ msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) sigᵢ = EdDSA-Sign(coinᵢ.priv, msgᵢ) depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ) -persist (contract, ~sig, ~deposit) +persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) ]]></artwork> <t>// TODO: explain CoinSelection -// TODO: maybe better {sigᵢ} instead of ~sig? // TODO: maybe introduce symbol for pub/priv // TODO: maybe rename Sign-Msg as name is currently a bit confusing</t> <artwork><![CDATA[ (M3) deposit check (merchant) -check sum(depositᵢ.contribution) == contract.price -check Deposit(~deposit) +check sum( ⟨depositᵢ.contribution⟩ ) == contract.price +check Deposit(⟨depositᵢ⟩) msg = Sign-Msg(MERCHANT_PAYMENT_OK, h_contract) sig = EdDSA-Sign(merchant.priv, msg) ]]></artwork> @@ -594,20 +594,21 @@ check EdDSA-Verify(merchant.pub, msg, sig) <section anchor="deposit"> <name>Deposit</name> <t>// todo: add introductory text</t> + <t>Deposit could also be used directly by a wallet with its own payto and a minimal contract.</t> <artwork><![CDATA[ - merchant/wallet exchange + merchant exchange knows exchange.pub knows exchange.priv -knows contract_sig knows denomᵢ.pub +knows merchant.priv knows ⟨denomᵢ⟩ knows payto, wire_salt | -knows contract, ~deposit | +knows contract, ⟨depositᵢ⟩ | | | +--------------------------+ | | (M1) deposit preparation | | +--------------------------+ | | | |----------- /batch-deposit ------------>| - | (info, h_contract, ~deposit | - | merchant.pub, contract_sig) | + | (info, h_contract, ⟨depositᵢ⟩ | + | merchant.pub, sig) | | | | +-------------------------+ | | (E1) deposit validation | @@ -622,18 +623,20 @@ knows contract, ~deposit | ]]></artwork> <t>where (without age restriction, policy and wallet data hash)</t> <artwork><![CDATA[ -(M1) Deposit preparation (merchant/wallet) +(M1) Deposit preparation (merchant) -h_contract = SHA-512(canonicalJSON(contract)) info.time = contract.{timestamp, wire_deadline, refund_deadline} info.wire = (payto, wire_salt) +h_contract = SHA-512(canonicalJSON(contract)) +msg = Sign-Msg(MERCHANT_CONTRACT, h_contract) +sig = EdDSA-Sign(merchant.priv, msg) ]]></artwork> <artwork><![CDATA[ (E1) Deposit validation (exchange) coinᵢ = depositᵢ.coin denomᵢ = Denom-Lookup(coinᵢ.h_denom) -check denomᵢ.pub known and not deposit-expired +check denomᵢ.pub known and not deposit-expired // todo: check could be included in Denom-Lookup h_wire = HKDF(info.wire.wire_salt, info.wire.payto, "merchant-wire-signature", 64) msgᵢ = Sign-Msg(WALLET_COIN_DEPOSIT, ( h_contract | uint256(0x0) @@ -651,20 +654,20 @@ msg = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, ( h_contract | h_wire | uint512(0x0) | timestamp | info.time.wire_deadline | info.time.refund_deadline - | sum(depositᵢ.contribution) - sum(denomᵢ.fee_deposit) - | SHA-512(depositᵢ.sig) | merchant.pub )) + | sum( ⟨depositᵢ.contribution⟩ ) + | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) sig = EdDSA-Sign(exchange.priv, msg) ]]></artwork> <artwork><![CDATA[ -(M2) Deposit verification (merchant/wallet) +(M2) Deposit verification (merchant) h_wire = HKDF(wire_salt, payto, "merchant-wire-signature", 64) msg = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, ( h_contract | h_wire | uint512(0x0) | timestamp | contract.wire_deadline | contract.refund_deadline - | sum(depositᵢ.contribution) - sum(denomᵢ.fee_deposit) - | SHA-512(depositᵢ.sig) | merchant.pub )) + | sum( ⟨depositᵢ.contribution⟩ ) + | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) check EdDSA-Verify(exchange.pub, msg, sig) ]]></artwork> </section> @@ -776,7 +779,7 @@ check EdDSA-Verify(exchange.pub, msg, sig) <refcontent>National Institute of Standards and Technology (U.S.)</refcontent> </reference> </references> - <?line 732?> + <?line 737?> <section anchor="change-log"> <name>Change log</name> @@ -789,147 +792,149 @@ Education and Research (BMBF) within the project Concrete Contracts.</t> </section> </back> <!-- ##markdown-source: -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 -jGefx2dbfpzOGFoKy54rEDVZpRjQwLqWngju709YWZ2q1j83D/cOTre2Px4e -753o2qcxdLkSaRQncTZVjsxXrXT5O6tUCFW3HC5XIrOxok5mH6Mk8pyVqncq -LlHAdY/wtI0hE1XsZflUksaQerOYTWJE9auizoOmQ8NcoqhhQUyt9mqOd1TI -pBGMIpkO26+plpbHh/m5ICkw+lxQSc6KxxM+AxcyEClWvC7lLFf0Xi6QEZ0G -jv5rFd5X32URLJlNBlGgT/ovk/+rAIN74xORyw06FmooOT+OX6XAZQ9pm0jb -/7nI0bT8skVW1DVdWyblGmgny/Ut1WlLdiii6oWG4+PGX/e34e/h+7LpuK+d -WxTHGfs898TgbsaLbJaum6pls8tnuqJmnBHinpczNo3wSy1gukrlNj388l1K -bpVTQfp28amgKhyKkmwrOZcb+pr1ZNVVBQFFyHiHQLY8aaFat/esNtw+m+75 -oPwYI2aN4//N/Jhyr+UBVqUdvRITn0WnQ2RYX2hFDbMWYHtTseMJ1lkPt5gD -9zwUohdNRe3HqjY9dqLNbCP4Ne2BtFJPWWO6PdHGVCOn4v+fRHurxmzYFTt/ -7yActZJiNGa430uD+aVEZy4RupIDqLTOrprw6l701rzsm5vQxRGAUpTgh4+4 -Pa1GzvemyzlpvpqWkZ0WjXfLU58y/r4l7M7ZWYq7i9b6wHtBTPYUAXhNJGTs -Ouvwu2miZKRyD923lqOgGOB7agl+/hIjWB2pa9mIBZ4zx9M38ZmDUKmVQFcv -C/CdJePsLlVvaLOwIDfml+f2XJS6/RcMEd9tY3q7s3e0f6Mc5Fw2yafoXs/Y -ctWjKgz1bL8xHHfmz7/kAbjsrqlfYVVVBuoOrZQix7kAHO37Vp19r7V2Dyop -/Qgm5Wa1jke3pMQ/jEU1ell2+/MZypEYghsb4+c05FWRoejnsCL5GC7mnrpR -NqWneFF5+pn466SRI6/YxwxmKs6SnHfPnWk2N2VNtyCY6xYEpW74vbosxk/E -buIbkp6qXCbqK6Zb9BXTZ2wPX8aqQhxEIX7vDCOmAXfP6EOJ8jhEEI3wbsNF -9xMIbyQ/l3vZk9/cFN760pAHiVi6Ks1DxyLpk5fn9FEs+jCJLBrT25jqFRX5 -ZVm2Izz6rOk+fdslxoK1tQ05YXFI8UgkggOrmf12/+2O/CZRUavG1wpwTXhq -R+AFyWLSsv4XcFI2TK9YAAA= +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 +638BRvuUOiFaAAA= -->