commit 32187fd69c489eece04907b549e76e92ff3f15fe
parent ff5b3a854fd61da30a1962177bcd4363e4cf83ed
Author: Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
Date: Tue, 7 Apr 2026 15:55:01 +0200
protocol: add draft for refresh
Diffstat:
2 files changed, 553 insertions(+), 169 deletions(-)
diff --git a/draft-guetschow-taler-protocol.md b/draft-guetschow-taler-protocol.md
@@ -398,7 +398,9 @@ 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: explain notation: ⟨⟩ᵢ
+
+// todo: document TALER_MAX_COINS = 64 per operation (due to CS-encoding)
// todo: extend with extra roundtrip for CBS
@@ -422,8 +424,7 @@ knows ⟨denomᵢ⟩ knows ⟨denomᵢ.priv⟩
+-----------------------------------+ |
| |
|-------------- /withdraw -------------->|
- | (reserve.pub, ⟨coinᵢ.h_denom⟩, |
- | ⟨blind_coinᵢ⟩, sig) |
+ | (reserve.pub, planchets, sig) |
| |
| +--------------------------------+
| | (E1) coin issuance and signing |
@@ -451,6 +452,8 @@ together with an integer index.
This is strictly speaking an implementation detail since the master secret is never revealed to any other party,
and might be chosen to be implemented differently.
+// todo: blind_secret/coin.priv differently generated in TALER_EXCHANGE_post_withdraw_start/prepare_coins, double check with wallet-core (probably implementation detail here)
+
~~~
(W2) coin generation and blinding (wallet)
@@ -460,27 +463,33 @@ coin_seedᵢ = HKDF(uint32(i), master_secret, "taler-withdrawal-coin-derivation"
blind_secretᵢ = coin_seedᵢ[32:]
coinᵢ.priv = coin_seedᵢ[:32]
coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv)
-coinᵢ.h_denom = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub)
+h_denomᵢ = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub)
blind_coinᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub)
+planchets = (⟨h_denomᵢ⟩, ⟨blind_coinᵢ⟩)
+h_planchetᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinᵢ )
msg = Sign-Msg(WALLET_RESERVE_WITHDRAW,
( sum( ⟨denomᵢ.value⟩ ) | sum( ⟨denomᵢ.fee_withdraw⟩ )
- | SHA-512( SHA-512( ⟨denomᵢ.pub⟩ ) | uint32(0x1) | ⟨blind_coinᵢ⟩ )
- | uint256(0x0) | uint32(0x0) | uint32(0x0) ))
+ | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) ))
sig = EdDSA-Sign(reserve.priv, msg)
~~~
~~~
(E1) coin issuance and signing (exchange)
-denomᵢ = Denom-Lookup(coinᵢ.h_denom)
+(⟨h_denomᵢ⟩, ⟨blind_coinᵢ⟩) = planchets
+denomᵢ = Denom-Lookup(h_denomᵢ)
check denomᵢ.pub known and not withdrawal-expired
+h_planchetᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinᵢ )
+msg = Sign-Msg(WALLET_RESERVE_WITHDRAW,
+ ( sum( ⟨denomᵢ.value⟩ ) | sum( ⟨denomᵢ.fee_withdraw⟩ )
+ | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) ))
check EdDSA-Verify(reserve.pub, msg, sig)
check reserve KYC status ok or not needed
total = sum( ⟨denomᵢ.value⟩ ) + sum( ⟨denomᵢ.fee_withdraw⟩ )
check reserve.balance >= total
-reserve.balance -= total
+persist reserve.balance -= total
blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv)
-persist withdrawal // todo: what exactly? should be checked first?
+persist withdrawal // todo: what exactly? should be checked first for replay?
~~~
~~~
@@ -488,6 +497,7 @@ persist withdrawal // todo: what exactly? should be checked first?
coinᵢ.sig = RSA-FDH-Unblind(blind_sigᵢ, blind_secretᵢ, denomᵢ.pub)
check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub)
+coinᵢ.h_denom = h_denomᵢ
persist (coinᵢ, blind_secretᵢ) // todo: why blind_secret, if master_secret already persisted?
~~~
@@ -601,8 +611,10 @@ persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩)
~~~
// TODO: explain CoinSelection
+
// TODO: maybe introduce symbol for pub/priv
-// TODO: maybe rename Sign-Msg as name is currently a bit confusing
+
+// TODO: maybe rename Sign-Msg as name is currently a bit confusing (not actually signing a message, but just generating the message to be signed)
~~~
(M3) deposit check (merchant)
@@ -708,7 +720,199 @@ check EdDSA-Verify(exchange.pub, msg, sig)
## Refresh {#refresh}
-// todo
+// todo: add introductory text
+
+~~~
+ wallet exchange
+knows ⟨denomᵢ⟩ knows ⟨denomᵢ.priv⟩
+knows coin |
+ | |
++-------------------+ |
+| (W1) coin melting | |
++-------------------+ |
+ | |
+ |---------------- /melt ---------------->|
+ | (coin.{pub,sig,h_denom}, value, |
+ | refresh_seed, planchets, sig) |
+ | |
+ | +---------------------------------------+
+ | | (E1) gamma selection and coin signing |
+ | +---------------------------------------+
+ | |
+ |<------ (ɣ, exchange.pub, sig) ---------|
+ | |
++------------------------+ |
+| (W2) secret revelation | |
++------------------------+ |
+ | |
+ |------------ /reveal-melt ------------->|
+ | (commitment, ⟨revealed_seedₖ⟩) |
+ | |
+ | +----------------------------+
+ | | (E2) commitment validation |
+ | +----------------------------+
+ | |
+ |<---------- (⟨blind_sigᵢ⟩) -------------|
+ | |
++----------------------+ |
+| (W3) coin unblinding | |
++----------------------+ |
+ | |
+~~~
+
+where (for RSA, without age-restriction)
+
+// todo: document ECDH-EdDSA(priv, pub) (returns hash512)
+
+// todo: double-check incompatibility between h_denom and hash of denom used below
+
+// todo: rename blind_coin to planchet, here and in withdrawal, too?
+
+{::comment}
+// see TALER_EXCHANGE_get_melt_data
+⟨batch_seedₖ⟩ // see TALER_refresh_expand_seed_to_kappa_batch_seeds
+⟨transferₖᵢ.priv⟩ // see TALER_refresh_expand_batch_seed_to_transfer_data
+// todo: pretty sure ECDH-GetPub and EdDSA-GetPub are equivalent, if not, transferₖᵢ.pub needs to change
+h_planchetₖᵢ // see TALER_coin_ev_hash
+h_planchetsₖ // see TALER_wallet_blinded_planchet_details_hash
+commitment // see TALER_refresh_get_commitment
+
+⟨ₖᵢ⟩
+{:/}
+
+~~~
+(W1) coin melting (wallet)
+
+h_denomᵢ = SHA-512(uint32(0) | uint32(0x1) | denomᵢ.pub)
+refresh_seed = random(256)
+⟨batch_seedₖ⟩ = HKDF("refresh-batch-seeds", refresh_seed, coin.priv, k*64)
+⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32)
+transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv)
+sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub)
+planchet_seedₖᵢ = HKDF(uint32(i), sharedₖᵢ, "taler-coin-derivation", 64)
+blind_secretₖᵢ = HKDF("bks", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.priv = HKDF("coin", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.pub = EdDSA-GetPub(coinₖᵢ.priv)
+blind_coinₖᵢ = RSA-FDH-Blind(SHA-512(coinₖᵢ.pub), blind_secretₖᵢ, denomᵢ.pub)
+h_planchetₖᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinₖᵢ )
+h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ )
+value = coin.denom.fee_refresh + sum( denomᵢ.value ) + sum( denomᵢ.fee_withdraw )
+commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value
+ | SHA-512( ⟨h_planchetsₖ⟩ ) )
+planchets = (⟨h_denomᵢ⟩, ⟨blind_coinₖᵢ⟩, ⟨transferₖᵢ.pub⟩))
+msg = Sign-Msg(WALLET_COIN_MELT,
+ ( commitment | coin.h_denom | uint256(0x0)
+ | value | denom.fee_refresh ))
+sig = EdDSA-Sign(coin.priv, msg)
+persist (coin.denom.pub, ...) // todo: double-check
+~~~
+
+{::comment}
+
+see TEH_handler_melt
+
+⟨ₖᵢ⟩
+{:/}
+
+~~~
+(E1) gamma selection and coin signing (exchange)
+
+denom = Denom-Lookup(coin.h_denom)
+check denom.pub known and not refresh-expired
+check RSA-FDH-Verify(SHA-512(coin.pub), coin.sig, denom.pub)
+check coin dirty
+(⟨h_denomᵢ⟩, ⟨blind_coinₖᵢ⟩, ⟨transferₖᵢ.pub⟩)) = planchets
+denomᵢ = Denom-Lookup(h_denomᵢ)
+check denomᵢ.pub known and not withdraw-expired
+check value == coin.denom.fee_refresh + sum( denomᵢ.value ) + sum( denomᵢ.fee_withdraw )
+check not overspending coin with denom.value + denom.fee_refresh + sum(denomᵢ.fee_withdraw)
+mark spend
+h_planchetₖᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinₖᵢ )
+h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ )
+commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value
+ | SHA-512( ⟨h_planchetsₖ⟩ ) )
+msg = Sign-Msg(WALLET_COIN_MELT,
+ ( commitment | coin.h_denom | uint256(0x0)
+ | value | denom.fee_refresh ))
+check EdDSA-Verify(coin.pub, msg, sig)
+(ɣ, ⟨blind_sigᵢ⟩) = lookup refresh-record(commitment)
+if refresh-record == NONE:
+ ɣ = 0..kappa at random
+ blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv) // todo: notation for ɣ
+ persist refresh-record = (commitment, ɣ, ⟨blind_sigᵢ⟩, h_planchetsₖ) for k=ɣ
+msg = Sign-Msg(EXCHANGE_CONFIRM_MELT,
+ ( commitment | uint32(ɣ) ))
+sig = EdDSA-Sign(exchange.priv, msg)
+~~~
+
+{::comment}
+
+// see src/lib/exchange_api_post-melt.c: handle_melt_finished
+// see src/lib/exchange_api_post-reveal-melt.c: perform_protocol
+
+⟨ₖᵢ⟩
+{:/}
+
+~~~
+(W2) secret revelation (wallet)
+
+check exchange.pub is expected
+msg = Sign-Msg(EXCHANGE_CONFIRM_MELT,
+ ( commitment | ɣ ))
+check EdDSA-Verify(exchange.pub, msg, sig)
+persist refresh-challenge // what exactly?
+⟨revealed_seedₖ⟩ = ⟨batch_seedₖ⟩ without k = ɣ
+~~~
+
+{::comment}
+
+// see TEH_handler_reveal_melt
+
+⟨ₖᵢ⟩
+{:/}
+
+~~~
+(E2) commitment validation (exchange)
+
+// find_original_refresh
+(ɣ, ⟨blind_sigᵢ⟩) = lookup refresh-record(commitment)
+// verify_commitment, for k != ɣ
+⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32)
+transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv)
+sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub)
+planchet_seedₖᵢ = HKDF(uint32(i), sharedₖᵢ, "taler-coin-derivation", 64)
+blind_secretₖᵢ = HKDF("bks", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.priv = HKDF("coin", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.pub = EdDSA-GetPub(coinₖᵢ.priv)
+blind_coinₖᵢ = RSA-FDH-Blind(SHA-512(coinₖᵢ.pub), blind_secretₖᵢ, denomᵢ.pub)
+h_planchetₖᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinₖᵢ )
+h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ )
+value = coin.denom.fee_refresh + sum( denomᵢ.value ) + sum( denomᵢ.fee_withdraw )
+// todo: h_planchetsₖ for k=ɣ as saved before
+commitment' = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value
+ | SHA-512( ⟨h_planchetsₖ⟩ ) )
+check commitment == commitment'
+persist mark-revealed
+~~~
+
+{::comment}
+
+// see src/lib/exchange_api_post-reveal-melt.c: reveal_melt_ok
+
+⟨ₖᵢ⟩
+{:/}
+
+~~~
+(W3) coin unblinding (wallet)
+
+set k=ɣ
+coinₖᵢ.sig = RSA-FDH-Unblind(blind_sigₖᵢ, blind_secretₖᵢ, denomᵢ.pub)
+check RSA-FDH-Verify(SHA-512(coinₖᵢ.pub), coinₖᵢ.sig, denomᵢ.pub)
+coinₖᵢ.h_denom = h_denomᵢ
+persist ⟨coinₖᵢ⟩
+~~~
+
+// todo: also add linking protocol?
## Refund {#refund}
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="06"/>
+ <date year="2026" month="April" day="07"/>
<workgroup>independent</workgroup>
<keyword>taler</keyword>
<keyword>cryptography</keyword>
@@ -387,7 +387,8 @@ out = uint32(len(msg)) | uint32(purpose) | msg
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: explain notation: ⟨⟩ᵢ</t>
+ <t>// todo: document TALER_MAX_COINS = 64 per operation (due to CS-encoding)</t>
<t>// todo: extend with extra roundtrip for CBS</t>
<artwork><![CDATA[
wallet exchange
@@ -409,8 +410,7 @@ knows ⟨denomᵢ⟩ knows ⟨denomᵢ.priv⟩
+-----------------------------------+ |
| |
|-------------- /withdraw -------------->|
- | (reserve.pub, ⟨coinᵢ.h_denom⟩, |
- | ⟨blind_coinᵢ⟩, sig) |
+ | (reserve.pub, planchets, sig) |
| |
| +--------------------------------+
| | (E1) coin issuance and signing |
@@ -434,6 +434,7 @@ persist (reserve, value)
together with an integer index.
This is strictly speaking an implementation detail since the master secret is never revealed to any other party,
and might be chosen to be implemented differently.</t>
+ <t>// todo: blind_secret/coin.priv differently generated in TALER_EXCHANGE_post_withdraw_start/prepare_coins, double check with wallet-core (probably implementation detail here)</t>
<artwork><![CDATA[
(W2) coin generation and blinding (wallet)
@@ -443,32 +444,39 @@ coin_seedᵢ = HKDF(uint32(i), master_secret, "taler-withdrawal-coin-derivation"
blind_secretᵢ = coin_seedᵢ[32:]
coinᵢ.priv = coin_seedᵢ[:32]
coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv)
-coinᵢ.h_denom = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub)
+h_denomᵢ = SHA-512(uint32(0) | uint32(1) | denomᵢ.pub)
blind_coinᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub)
+planchets = (⟨h_denomᵢ⟩, ⟨blind_coinᵢ⟩)
+h_planchetᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinᵢ )
msg = Sign-Msg(WALLET_RESERVE_WITHDRAW,
( sum( ⟨denomᵢ.value⟩ ) | sum( ⟨denomᵢ.fee_withdraw⟩ )
- | SHA-512( SHA-512( ⟨denomᵢ.pub⟩ ) | uint32(0x1) | ⟨blind_coinᵢ⟩ )
- | uint256(0x0) | uint32(0x0) | uint32(0x0) ))
+ | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) ))
sig = EdDSA-Sign(reserve.priv, msg)
]]></artwork>
<artwork><![CDATA[
(E1) coin issuance and signing (exchange)
-denomᵢ = Denom-Lookup(coinᵢ.h_denom)
+(⟨h_denomᵢ⟩, ⟨blind_coinᵢ⟩) = planchets
+denomᵢ = Denom-Lookup(h_denomᵢ)
check denomᵢ.pub known and not withdrawal-expired
+h_planchetᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinᵢ )
+msg = Sign-Msg(WALLET_RESERVE_WITHDRAW,
+ ( sum( ⟨denomᵢ.value⟩ ) | sum( ⟨denomᵢ.fee_withdraw⟩ )
+ | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) ))
check EdDSA-Verify(reserve.pub, msg, sig)
check reserve KYC status ok or not needed
total = sum( ⟨denomᵢ.value⟩ ) + sum( ⟨denomᵢ.fee_withdraw⟩ )
check reserve.balance >= total
-reserve.balance -= total
+persist reserve.balance -= total
blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv)
-persist withdrawal // todo: what exactly? should be checked first?
+persist withdrawal // todo: what exactly? should be checked first for replay?
]]></artwork>
<artwork><![CDATA[
(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)
+coinᵢ.h_denom = h_denomᵢ
persist (coinᵢ, blind_secretᵢ) // todo: why blind_secret, if master_secret already persisted?
]]></artwork>
</section>
@@ -573,9 +581,9 @@ sigᵢ = EdDSA-Sign(coinᵢ.priv, msgᵢ)
depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ)
persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩)
]]></artwork>
- <t>// TODO: explain CoinSelection
-// TODO: maybe introduce symbol for pub/priv
-// TODO: maybe rename Sign-Msg as name is currently a bit confusing</t>
+ <t>// TODO: explain CoinSelection</t>
+ <t>// TODO: maybe introduce symbol for pub/priv</t>
+ <t>// TODO: maybe rename Sign-Msg as name is currently a bit confusing (not actually signing a message, but just generating the message to be signed)</t>
<artwork><![CDATA[
(M3) deposit check (merchant)
@@ -673,7 +681,147 @@ check EdDSA-Verify(exchange.pub, msg, sig)
</section>
<section anchor="refresh">
<name>Refresh</name>
- <t>// todo</t>
+ <t>// todo: add introductory text</t>
+ <artwork><![CDATA[
+ wallet exchange
+knows ⟨denomᵢ⟩ knows ⟨denomᵢ.priv⟩
+knows coin |
+ | |
++-------------------+ |
+| (W1) coin melting | |
++-------------------+ |
+ | |
+ |---------------- /melt ---------------->|
+ | (coin.{pub,sig,h_denom}, value, |
+ | refresh_seed, planchets, sig) |
+ | |
+ | +---------------------------------------+
+ | | (E1) gamma selection and coin signing |
+ | +---------------------------------------+
+ | |
+ |<------ (ɣ, exchange.pub, sig) ---------|
+ | |
++------------------------+ |
+| (W2) secret revelation | |
++------------------------+ |
+ | |
+ |------------ /reveal-melt ------------->|
+ | (commitment, ⟨revealed_seedₖ⟩) |
+ | |
+ | +----------------------------+
+ | | (E2) commitment validation |
+ | +----------------------------+
+ | |
+ |<---------- (⟨blind_sigᵢ⟩) -------------|
+ | |
++----------------------+ |
+| (W3) coin unblinding | |
++----------------------+ |
+ | |
+]]></artwork>
+ <t>where (for RSA, without age-restriction)</t>
+ <t>// todo: document ECDH-EdDSA(priv, pub) (returns hash512)</t>
+ <t>// todo: double-check incompatibility between h_denom and hash of denom used below</t>
+ <t>// todo: rename blind_coin to planchet, here and in withdrawal, too?</t>
+ <artwork><![CDATA[
+(W1) coin melting (wallet)
+
+h_denomᵢ = SHA-512(uint32(0) | uint32(0x1) | denomᵢ.pub)
+refresh_seed = random(256)
+⟨batch_seedₖ⟩ = HKDF("refresh-batch-seeds", refresh_seed, coin.priv, k*64)
+⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32)
+transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv)
+sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub)
+planchet_seedₖᵢ = HKDF(uint32(i), sharedₖᵢ, "taler-coin-derivation", 64)
+blind_secretₖᵢ = HKDF("bks", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.priv = HKDF("coin", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.pub = EdDSA-GetPub(coinₖᵢ.priv)
+blind_coinₖᵢ = RSA-FDH-Blind(SHA-512(coinₖᵢ.pub), blind_secretₖᵢ, denomᵢ.pub)
+h_planchetₖᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinₖᵢ )
+h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ )
+value = coin.denom.fee_refresh + sum( denomᵢ.value ) + sum( denomᵢ.fee_withdraw )
+commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value
+ | SHA-512( ⟨h_planchetsₖ⟩ ) )
+planchets = (⟨h_denomᵢ⟩, ⟨blind_coinₖᵢ⟩, ⟨transferₖᵢ.pub⟩))
+msg = Sign-Msg(WALLET_COIN_MELT,
+ ( commitment | coin.h_denom | uint256(0x0)
+ | value | denom.fee_refresh ))
+sig = EdDSA-Sign(coin.priv, msg)
+persist (coin.denom.pub, ...) // todo: double-check
+]]></artwork>
+ <artwork><![CDATA[
+(E1) gamma selection and coin signing (exchange)
+
+denom = Denom-Lookup(coin.h_denom)
+check denom.pub known and not refresh-expired
+check RSA-FDH-Verify(SHA-512(coin.pub), coin.sig, denom.pub)
+check coin dirty
+(⟨h_denomᵢ⟩, ⟨blind_coinₖᵢ⟩, ⟨transferₖᵢ.pub⟩)) = planchets
+denomᵢ = Denom-Lookup(h_denomᵢ)
+check denomᵢ.pub known and not withdraw-expired
+check value == coin.denom.fee_refresh + sum( denomᵢ.value ) + sum( denomᵢ.fee_withdraw )
+check not overspending coin with denom.value + denom.fee_refresh + sum(denomᵢ.fee_withdraw)
+mark spend
+h_planchetₖᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinₖᵢ )
+h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ )
+commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value
+ | SHA-512( ⟨h_planchetsₖ⟩ ) )
+msg = Sign-Msg(WALLET_COIN_MELT,
+ ( commitment | coin.h_denom | uint256(0x0)
+ | value | denom.fee_refresh ))
+check EdDSA-Verify(coin.pub, msg, sig)
+(ɣ, ⟨blind_sigᵢ⟩) = lookup refresh-record(commitment)
+if refresh-record == NONE:
+ ɣ = 0..kappa at random
+ blind_sigᵢ = RSA-FDH-Sign(blind_coinᵢ, denomᵢ.priv) // todo: notation for ɣ
+ persist refresh-record = (commitment, ɣ, ⟨blind_sigᵢ⟩, h_planchetsₖ) for k=ɣ
+msg = Sign-Msg(EXCHANGE_CONFIRM_MELT,
+ ( commitment | uint32(ɣ) ))
+sig = EdDSA-Sign(exchange.priv, msg)
+]]></artwork>
+ <artwork><![CDATA[
+(W2) secret revelation (wallet)
+
+check exchange.pub is expected
+msg = Sign-Msg(EXCHANGE_CONFIRM_MELT,
+ ( commitment | ɣ ))
+check EdDSA-Verify(exchange.pub, msg, sig)
+persist refresh-challenge // what exactly?
+⟨revealed_seedₖ⟩ = ⟨batch_seedₖ⟩ without k = ɣ
+]]></artwork>
+ <artwork><![CDATA[
+(E2) commitment validation (exchange)
+
+// find_original_refresh
+(ɣ, ⟨blind_sigᵢ⟩) = lookup refresh-record(commitment)
+// verify_commitment, for k != ɣ
+⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32)
+transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv)
+sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub)
+planchet_seedₖᵢ = HKDF(uint32(i), sharedₖᵢ, "taler-coin-derivation", 64)
+blind_secretₖᵢ = HKDF("bks", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.priv = HKDF("coin", planchet_seedₖᵢ, "", 32)
+coinₖᵢ.pub = EdDSA-GetPub(coinₖᵢ.priv)
+blind_coinₖᵢ = RSA-FDH-Blind(SHA-512(coinₖᵢ.pub), blind_secretₖᵢ, denomᵢ.pub)
+h_planchetₖᵢ = SHA-512( SHA-512( denomᵢ.pub ) | uint32(0x1) | blind_coinₖᵢ )
+h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ )
+value = coin.denom.fee_refresh + sum( denomᵢ.value ) + sum( denomᵢ.fee_withdraw )
+// todo: h_planchetsₖ for k=ɣ as saved before
+commitment' = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value
+ | SHA-512( ⟨h_planchetsₖ⟩ ) )
+check commitment == commitment'
+persist mark-revealed
+]]></artwork>
+ <artwork><![CDATA[
+(W3) coin unblinding (wallet)
+
+set k=ɣ
+coinₖᵢ.sig = RSA-FDH-Unblind(blind_sigₖᵢ, blind_secretₖᵢ, denomᵢ.pub)
+check RSA-FDH-Verify(SHA-512(coinₖᵢ.pub), coinₖᵢ.sig, denomᵢ.pub)
+coinₖᵢ.h_denom = h_denomᵢ
+persist ⟨coinₖᵢ⟩
+]]></artwork>
+ <t>// todo: also add linking protocol?</t>
</section>
<section anchor="refund">
<name>Refund</name>
@@ -779,7 +927,7 @@ check EdDSA-Verify(exchange.pub, msg, sig)
<refcontent>National Institute of Standards and Technology (U.S.)</refcontent>
</reference>
</references>
- <?line 737?>
+ <?line 941?>
<section anchor="change-log">
<name>Change log</name>
@@ -792,149 +940,181 @@ Education and Research (BMBF) within the project Concrete Contracts.</t>
</section>
</back>
<!-- ##markdown-source:
-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
-638BRvuUOiFaAAA=
+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
-->