lsd0009

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

commit f1fd4a6c58e4d2bc7696bf9be64870ba09f1aec7
parent 09acb192cd7319115e366149537a28625eac2df9
Author: Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
Date:   Wed,  8 Apr 2026 15:17:33 +0200

crypto: add description for Ed25519

Diffstat:
Mdraft-guetschow-taler-protocol.md | 133+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mdraft-guetschow-taler-protocol.xml | 569+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
2 files changed, 431 insertions(+), 271 deletions(-)

diff --git a/draft-guetschow-taler-protocol.md b/draft-guetschow-taler-protocol.md @@ -34,6 +34,7 @@ normative: RFC2104: RFC5869: RFC6234: + RFC8032: HKDF: DOI.10.1007/978-3-642-14623-7_34 SHS: DOI.10.6028/NIST.FIPS.180-4 @@ -72,6 +73,8 @@ Use at your own risk! # Cryptographic Primitives +// todo: maybe change this description to something more similar to protocol functions (Julia-inspired syntax) + ## Cryptographic Hash Functions ### SHA-256 {#sha256} @@ -209,6 +212,76 @@ do until OKM < N: ### Ed25519 +Taler uses EdDSA instantiated with curve25519 as Ed25519, +as defined in Section 5.1 of [RFC8032]. +In particular, Taler does _not_ make use of Ed25519ph or Ed25519ctx +as defined in that document. + +#### Key generation + +~~~ +Ed25519-GetPub(priv) -> pub + +Input: + priv private Ed25519 key + +Output: + pub public Ed25519 key +~~~ + +`pub` is calculated as described in Section 5.1.5 of [RFC8032]. + +~~~ +Ed25519-Keygen() -> (priv, pub) + +Output: + priv private Ed25519 key + pub public Ed25519 key +~~~ + +`priv` and `pub` are calculated as described in Section 5.1.5 of [RFC8032], +which is equivalent to the following: + +~~~ +priv = random(256) +pub = Ed25519-GetPub(priv) +~~~ + +#### Signing + +~~~ +Ed25519-Sign(priv, msg) -> sig + +Inputs: + priv Ed25519 private key + msg message to be signed + +Output: + sig signature on the message by the given private key +~~~ + +`sig` is calculated as described in Section 5.1.6 of [RFC8032]. + +#### Verifying + +~~~ +Ed25519-Verify(pub, msg, sig) -> out + +Inputs: + pub Ed25519 public key + msg signed message + sig signature on msg + +Output: + out true, if sig is a valid signature for msg +~~~ + +`out` is the outcome of the last check of Section 5.1.7 of [RFC8032]. + +## Key Agreement + + + ## Blind Signatures ### RSA-FDH {#rsa-fdh} @@ -394,8 +467,8 @@ out = uint32(len(msg)) | uint32(purpose) | msg ## Helper Functions -There are a certain number of functions which are often needed, -and therefore omit the typical function syntax of using parentheses: +There are a certain number of single-argument functions which are often needed, +and therefore omit the parentheses of the typical function syntax: - `Knows data` specifies `data` that is known a priori at the start of the protocol operation - `Check cond` verifies that the boolean condition or variable `cond` is true, @@ -405,7 +478,7 @@ and therefore omit the typical function syntax of using parentheses: - `Sum ⟨dataᵢ⟩` is valid for numerical objects `dataᵢ` including amounts (cf. {{amounts}}), and denotes the numerical sum of these objects -Some more functions that are used throughout {#protocol}: +Some more functions that are commonly used throughout {{protocol}}: ~~~ Hash-Denom(denom) = @@ -419,7 +492,7 @@ Check-Subtract(value, subtrahend) = Persist value -= subtrahend ~~~ -# The Taler Crypto Protocol {#procotol} +# The Taler Crypto Protocol {#protocol} // todo: briefly introduce the three components wallet, exchange, merchant; maybe with ASCII diagram version @@ -475,7 +548,7 @@ where (for RSA, without age-restriction) ~~~ (W1) reserve key generation (wallet) -reserve = EdDSA-Keygen() +reserve = Ed25519-Keygen() Persist (reserve, value) ~~~ @@ -495,7 +568,7 @@ for i in 0..n: coin_seedᵢ = HKDF(uint32(i), batch_seed, "taler-withdrawal-coin-derivation", 64) blind_secretᵢ = coin_seedᵢ[32:] coinᵢ.priv = coin_seedᵢ[:32] - coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv) + coinᵢ.pub = Ed25519-GetPub(coinᵢ.priv) h_denomᵢ = Hash-Denom(denomᵢ) planchetᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub) h_planchetᵢ = Hash-Planchet(planchetᵢ, denomᵢ) @@ -503,7 +576,7 @@ planchets = (⟨h_denomᵢ⟩, ⟨planchetᵢ⟩) msg = Gen-Msg(WALLET_RESERVE_WITHDRAW, ( Sum ⟨denomᵢ.value⟩ | Sum ⟨denomᵢ.fee_withdraw⟩ | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) )) -sig = EdDSA-Sign(reserve.priv, msg) +sig = Ed25519-Sign(reserve.priv, msg) ~~~ ~~~ @@ -517,7 +590,7 @@ for i in 0..n: msg = Gen-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 Ed25519-Verify(reserve.pub, msg, sig) Check reserve KYC status ok or not needed total = Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ Check-Subtract(reserve.balance, total) @@ -602,7 +675,7 @@ Persist order = (id, price, info, token?, wire_salt) ~~~ (W1) nonce generation (wallet) -nonce = EdDSA-Keygen() +nonce = Ed25519-Keygen() Persist nonce.priv ~~~ @@ -622,7 +695,7 @@ contract.nonce = nonce.pub Persist contract h_contract = SHA-512(canonicalJSON(contract)) msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) -sig = EdDSA-Sign(merchant.priv, msg) +sig = Ed25519-Sign(merchant.priv, msg) ~~~ ~~~ @@ -630,7 +703,7 @@ sig = EdDSA-Sign(merchant.priv, msg) h_contract = SHA-512(canonicalJSON(contract)) msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) -Check EdDSA-Verify(merchant.pub, msg, sig) +Check Ed25519-Verify(merchant.pub, msg, sig) Check contract.nonce == nonce // TODO: double-check extra hash check? // todo: maybe get rid of CoinSelection altogether by claiming we already know coinᵢ and contributionᵢ @@ -643,7 +716,7 @@ for i in 0..n: | contract.timestamp | contract.refund_deadline | contributionᵢ + denomᵢ.fee_deposit | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) - sigᵢ = EdDSA-Sign(coinᵢ.priv, msgᵢ) + sigᵢ = Ed25519-Sign(coinᵢ.priv, msgᵢ) depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ) Persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) ~~~ @@ -658,14 +731,14 @@ Persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) Check Sum ⟨depositᵢ.contribution⟩ == contract.price Check Deposit(⟨depositᵢ⟩) msg = Gen-Msg(MERCHANT_PAYMENT_OK, h_contract) -sig = EdDSA-Sign(merchant.priv, msg) +sig = Ed25519-Sign(merchant.priv, msg) ~~~ ~~~ (W3) payment verification (wallet) msg = Gen-Msg(MERCHANT_PAYMENT_OK, h_contract) -Check EdDSA-Verify(merchant.pub, msg, sig) +Check Ed25519-Verify(merchant.pub, msg, sig) ~~~ ## Deposit {#deposit} @@ -710,7 +783,7 @@ info.time = contract.{timestamp, wire_deadline, refund_deadline} info.wire = (payto, wire_salt) h_contract = SHA-512(canonicalJSON(contract)) msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) -sig = EdDSA-Sign(merchant.priv, msg) +sig = Ed25519-Sign(merchant.priv, msg) ~~~ ~~~ @@ -728,7 +801,7 @@ for i in 0..n: | info.time.timestamp | info.time.refund_deadline | totalᵢ | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) - Check EdDSA-Verify(coinᵢ.pub, msgᵢ, depositᵢ.sig) + Check Ed25519-Verify(coinᵢ.pub, msgᵢ, depositᵢ.sig) Check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) Check-Subtract(coinᵢ.value, total) Persist deposit-record @@ -740,7 +813,7 @@ msg = Gen-Msg(EXCHANGE_CONFIRM_DEPOSIT, | info.time.refund_deadline | Sum ⟨depositᵢ.contribution⟩ | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) -sig = EdDSA-Sign(exchange.priv, msg) +sig = Ed25519-Sign(exchange.priv, msg) ~~~ ~~~ @@ -753,7 +826,7 @@ msg = Gen-Msg(EXCHANGE_CONFIRM_DEPOSIT, | contract.refund_deadline | Sum ⟨depositᵢ.contribution⟩ | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) -Check EdDSA-Verify(exchange.pub, msg, sig) +Check Ed25519-Verify(exchange.pub, msg, sig) ~~~ ## Refresh {#refresh} @@ -780,14 +853,16 @@ Refresh-Derive(shared, denom) = 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) + coin.pub = Ed25519-GetPub(coin.priv) planchet = RSA-FDH-Blind(SHA-512(coin.pub), blind_secret, denomᵢ.pub) h_planchet = Hash-Planchet(planchet, denomᵢ) return (coin, blind_secret, planchet, h_planchet) ~~~ Taler uses a cut-and-choose protocol with the fixed parameter `κ=3` to enforce correct derivation -(in (κ-1)/κ, i.e. 2/3, of the cases, making income concealment for tax evasion purposes unpractical). +of `⟨sharedₖᵢ⟩` from a single seed per batch of planchets `⟨batch_seedₖ⟩` +(in (κ-1)/κ of the cases, making income concealment for tax evasion purposes unpractical). + Refreshing consists of two parts: 1. Melting of the old coin and commiting to κ batches of blinded planchet candidates @@ -839,7 +914,7 @@ where (for RSA, without age-restriction) // 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 +// todo: pretty sure ECDH-GetPub and Ed25519-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 @@ -855,7 +930,7 @@ refresh_seed = random(256) for k in 0..κ: ⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32) for i in 0..n: - transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv) + transferₖᵢ.pub = Ed25519-GetPub(transferₖᵢ.priv) sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub) (coinₖᵢ, blind_secretₖᵢ, planchetₖᵢ, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) @@ -868,7 +943,7 @@ planchets = (⟨h_denomᵢ⟩, ⟨planchetₖᵢ⟩, ⟨transferₖᵢ.pub⟩)) msg = Gen-Msg(WALLET_COIN_MELT, ( commitment | coin.h_denom | uint256(0x0) | value | denom.fee_refresh )) -sig = EdDSA-Sign(coin.priv, msg) +sig = Ed25519-Sign(coin.priv, msg) Persist (coin.denom.pub, ...) // todo: double-check ~~~ @@ -902,7 +977,7 @@ commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value msg = Gen-Msg(WALLET_COIN_MELT, ( commitment | coin.h_denom | uint256(0x0) | value | denom.fee_refresh )) -Check EdDSA-Verify(coin.pub, msg, sig) +Check Ed25519-Verify(coin.pub, msg, sig) refresh_record = Lookup by commitment (ɣ, _, _, done, _) = refresh_record if refresh_record not found: @@ -913,7 +988,7 @@ if refresh_record not found: Persist refresh_record = (commitment, ɣ, ⟨blind_sigᵢ⟩, h_planchetsᵧ, false, link_info) msg = Gen-Msg(EXCHANGE_CONFIRM_MELT, ( commitment | uint32(ɣ) )) -sig = EdDSA-Sign(exchange.priv, msg) +sig = Ed25519-Sign(exchange.priv, msg) ~~~ {::comment} @@ -930,7 +1005,7 @@ sig = EdDSA-Sign(exchange.priv, msg) Check exchange.pub known msg = Gen-Msg(EXCHANGE_CONFIRM_MELT, ( commitment | ɣ )) -Check EdDSA-Verify(exchange.pub, msg, sig) +Check Ed25519-Verify(exchange.pub, msg, sig) Persist refresh-challenge // what exactly? for k in 0..κ and k != ɣ: revealed_seedₖ = batch_seedₖ @@ -952,7 +1027,7 @@ Check not done // todo: sure? for k in 0..κ and k != ɣ: ⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32) for i in 0..n: - transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv) + transferₖᵢ.pub = Ed25519-GetPub(transferₖᵢ.priv) sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub) (_, _, _, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) @@ -1019,7 +1094,7 @@ where (for RSA, without age-restriction) (W1) history request (wallet) msg = Gen-Msg(COIN_HISTORY_REQUEST, uint64(0x0)) -sig = EdDSA-Sign(coin.priv, msg) +sig = Ed25519-Sign(coin.priv, msg) ~~~ {::comment} @@ -1062,7 +1137,7 @@ commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value msg = Gen-Msg(WALLET_COIN_MELT, ( commitment | coin.h_denom | uint256(0x0) | value | denom.fee_refresh )) -Check EdDSA-Verify(coin.pub, msg, sig) +Check Ed25519-Verify(coin.pub, msg, sig) if ⟨blind_sigᵢ⟩ returned: for i in 0..n: diff --git a/draft-guetschow-taler-protocol.xml b/draft-guetschow-taler-protocol.xml @@ -31,13 +31,13 @@ <keyword>ecash</keyword> <keyword>payments</keyword> <abstract> - <?line 43?> + <?line 44?> <t>[ TBW ]</t> </abstract> </front> <middle> - <?line 47?> + <?line 48?> <section anchor="introduction"> <name>Introduction</name> @@ -94,6 +94,7 @@ Use at your own risk!</t> </section> <section anchor="cryptographic-primitives"> <name>Cryptographic Primitives</name> + <t>// todo: maybe change this description to something more similar to protocol functions (Julia-inspired syntax)</t> <section anchor="cryptographic-hash-functions"> <name>Cryptographic Hash Functions</name> <section anchor="sha256"> @@ -220,8 +221,70 @@ do until OKM < N: <name>Non-Blind Signatures</name> <section anchor="ed25519"> <name>Ed25519</name> + <t>Taler uses EdDSA instantiated with curve25519 as Ed25519, +as defined in Section 5.1 of <xref target="RFC8032"/>. +In particular, Taler does <em>not</em> make use of Ed25519ph or Ed25519ctx +as defined in that document.</t> + <section anchor="key-generation"> + <name>Key generation</name> + <artwork><![CDATA[ +Ed25519-GetPub(priv) -> pub + +Input: + priv private Ed25519 key + +Output: + pub public Ed25519 key +]]></artwork> + <t><tt>pub</tt> is calculated as described in Section 5.1.5 of <xref target="RFC8032"/>.</t> + <artwork><![CDATA[ +Ed25519-Keygen() -> (priv, pub) + +Output: + priv private Ed25519 key + pub public Ed25519 key +]]></artwork> + <t><tt>priv</tt> and <tt>pub</tt> are calculated as described in Section 5.1.5 of <xref target="RFC8032"/>, +which is equivalent to the following:</t> + <artwork><![CDATA[ +priv = random(256) +pub = Ed25519-GetPub(priv) +]]></artwork> + </section> + <section anchor="signing"> + <name>Signing</name> + <artwork><![CDATA[ +Ed25519-Sign(priv, msg) -> sig + +Inputs: + priv Ed25519 private key + msg message to be signed + +Output: + sig signature on the message by the given private key +]]></artwork> + <t><tt>sig</tt> is calculated as described in Section 5.1.6 of <xref target="RFC8032"/>.</t> + </section> + <section anchor="verifying"> + <name>Verifying</name> + <artwork><![CDATA[ +Ed25519-Verify(pub, msg, sig) -> out + +Inputs: + pub Ed25519 public key + msg signed message + sig signature on msg + +Output: + out true, if sig is a valid signature for msg +]]></artwork> + <t><tt>out</tt> is the outcome of the last check of Section 5.1.7 of <xref target="RFC8032"/>.</t> + </section> </section> </section> + <section anchor="key-agreement"> + <name>Key Agreement</name> + </section> <section anchor="blind-signatures"> <name>Blind Signatures</name> <section anchor="rsa-fdh"> @@ -285,7 +348,7 @@ r_e = r ** pubkey.e (mod pubkey.N) out = r_e * data (mod pubkey.N) ]]></artwork> </section> - <section anchor="signing"> + <section anchor="signing-1"> <name>Signing</name> <artwork><![CDATA[ RSA-FDH-Sign(data, privkey) -> sig @@ -322,7 +385,7 @@ r_inv = inverse of r (mod pubkey.N) out = sig * r_inv (mod pubkey.N) ]]></artwork> </section> - <section anchor="verifying"> + <section anchor="verifying-1"> <name>Verifying</name> <artwork><![CDATA[ RSA-FDH-Verify(msg, sig, pubkey) -> out @@ -394,8 +457,8 @@ out = uint32(len(msg)) | uint32(purpose) | msg </section> <section anchor="helper-functions"> <name>Helper Functions</name> - <t>There are a certain number of functions which are often needed, -and therefore omit the typical function syntax of using parentheses:</t> + <t>There are a certain number of single-argument functions which are often needed, +and therefore omit the parentheses of the typical function syntax:</t> <ul spacing="normal"> <li> <t><tt>Knows data</tt> specifies <tt>data</tt> that is known a priori at the start of the protocol operation</t> @@ -415,7 +478,7 @@ or aborts the protocol operation otherwise</t> and denotes the numerical sum of these objects</t> </li> </ul> - <t>Some more functions that are used throughout {#protocol}:</t> + <t>Some more functions that are commonly used throughout <xref target="protocol"/>:</t> <artwork><![CDATA[ Hash-Denom(denom) = SHA-512(uint32(0) | uint32(1) | denom.pub) @@ -429,7 +492,7 @@ Check-Subtract(value, subtrahend) = ]]></artwork> </section> </section> - <section anchor="procotol"> + <section anchor="protocol"> <name>The Taler Crypto Protocol</name> <t>// todo: briefly introduce the three components wallet, exchange, merchant; maybe with ASCII diagram version</t> <t>// todo: capitalize wallet, exchange, merchant?</t> @@ -478,7 +541,7 @@ Knows ⟨denomᵢ⟩ Knows ⟨denomᵢ.priv⟩ <artwork><![CDATA[ (W1) reserve key generation (wallet) -reserve = EdDSA-Keygen() +reserve = Ed25519-Keygen() Persist (reserve, value) ]]></artwork> <t>The wallet derives coins and blinding secrets using a HKDF from a single seed per withdrawal operation, @@ -495,7 +558,7 @@ for i in 0..n: coin_seedᵢ = HKDF(uint32(i), batch_seed, "taler-withdrawal-coin-derivation", 64) blind_secretᵢ = coin_seedᵢ[32:] coinᵢ.priv = coin_seedᵢ[:32] - coinᵢ.pub = EdDSA-GetPub(coinᵢ.priv) + coinᵢ.pub = Ed25519-GetPub(coinᵢ.priv) h_denomᵢ = Hash-Denom(denomᵢ) planchetᵢ = RSA-FDH-Blind(SHA-512(coinᵢ.pub), blind_secretᵢ, denomᵢ.pub) h_planchetᵢ = Hash-Planchet(planchetᵢ, denomᵢ) @@ -503,7 +566,7 @@ planchets = (⟨h_denomᵢ⟩, ⟨planchetᵢ⟩) msg = Gen-Msg(WALLET_RESERVE_WITHDRAW, ( Sum ⟨denomᵢ.value⟩ | Sum ⟨denomᵢ.fee_withdraw⟩ | SHA-512( ⟨h_planchetᵢ⟩ ) | uint256(0x0) | uint32(0x0) | uint32(0x0) )) -sig = EdDSA-Sign(reserve.priv, msg) +sig = Ed25519-Sign(reserve.priv, msg) ]]></artwork> <artwork><![CDATA[ (E1) coin issuance and signing (exchange) @@ -516,7 +579,7 @@ for i in 0..n: msg = Gen-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 Ed25519-Verify(reserve.pub, msg, sig) Check reserve KYC status ok or not needed total = Sum ⟨denomᵢ.value⟩ + Sum ⟨denomᵢ.fee_withdraw⟩ Check-Subtract(reserve.balance, total) @@ -596,7 +659,7 @@ Persist order = (id, price, info, token?, wire_salt) <artwork><![CDATA[ (W1) nonce generation (wallet) -nonce = EdDSA-Keygen() +nonce = Ed25519-Keygen() Persist nonce.priv ]]></artwork> <t>Note that the private key of <tt>nonce</tt> is currently not used anywhere in the protocol. @@ -614,14 +677,14 @@ contract.nonce = nonce.pub Persist contract h_contract = SHA-512(canonicalJSON(contract)) msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) -sig = EdDSA-Sign(merchant.priv, msg) +sig = Ed25519-Sign(merchant.priv, msg) ]]></artwork> <artwork><![CDATA[ (W2) payment preparation (wallet) h_contract = SHA-512(canonicalJSON(contract)) msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) -Check EdDSA-Verify(merchant.pub, msg, sig) +Check Ed25519-Verify(merchant.pub, msg, sig) Check contract.nonce == nonce // TODO: double-check extra hash check? // todo: maybe get rid of CoinSelection altogether by claiming we already know coinᵢ and contributionᵢ @@ -634,7 +697,7 @@ for i in 0..n: | contract.timestamp | contract.refund_deadline | contributionᵢ + denomᵢ.fee_deposit | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) - sigᵢ = EdDSA-Sign(coinᵢ.priv, msgᵢ) + sigᵢ = Ed25519-Sign(coinᵢ.priv, msgᵢ) depositᵢ = (coinᵢ.{pub,sig,h_denom}, contributionᵢ, sigᵢ) Persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) ]]></artwork> @@ -646,13 +709,13 @@ Persist (contract, ⟨sigᵢ⟩, ⟨depositᵢ⟩) Check Sum ⟨depositᵢ.contribution⟩ == contract.price Check Deposit(⟨depositᵢ⟩) msg = Gen-Msg(MERCHANT_PAYMENT_OK, h_contract) -sig = EdDSA-Sign(merchant.priv, msg) +sig = Ed25519-Sign(merchant.priv, msg) ]]></artwork> <artwork><![CDATA[ (W3) payment verification (wallet) msg = Gen-Msg(MERCHANT_PAYMENT_OK, h_contract) -Check EdDSA-Verify(merchant.pub, msg, sig) +Check Ed25519-Verify(merchant.pub, msg, sig) ]]></artwork> </section> <section anchor="deposit"> @@ -693,7 +756,7 @@ info.time = contract.{timestamp, wire_deadline, refund_deadline} info.wire = (payto, wire_salt) h_contract = SHA-512(canonicalJSON(contract)) msg = Gen-Msg(MERCHANT_CONTRACT, h_contract) -sig = EdDSA-Sign(merchant.priv, msg) +sig = Ed25519-Sign(merchant.priv, msg) ]]></artwork> <artwork><![CDATA[ (E1) Deposit validation (exchange) @@ -710,7 +773,7 @@ for i in 0..n: | info.time.timestamp | info.time.refund_deadline | totalᵢ | denomᵢ.fee_deposit | merchant.pub | uint512(0x0) )) - Check EdDSA-Verify(coinᵢ.pub, msgᵢ, depositᵢ.sig) + Check Ed25519-Verify(coinᵢ.pub, msgᵢ, depositᵢ.sig) Check RSA-FDH-Verify(SHA-512(coinᵢ.pub), coinᵢ.sig, denomᵢ.pub) Check-Subtract(coinᵢ.value, total) Persist deposit-record @@ -722,7 +785,7 @@ msg = Gen-Msg(EXCHANGE_CONFIRM_DEPOSIT, | info.time.refund_deadline | Sum ⟨depositᵢ.contribution⟩ | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) -sig = EdDSA-Sign(exchange.priv, msg) +sig = Ed25519-Sign(exchange.priv, msg) ]]></artwork> <artwork><![CDATA[ (M2) Deposit verification (merchant) @@ -734,7 +797,7 @@ msg = Gen-Msg(EXCHANGE_CONFIRM_DEPOSIT, | contract.refund_deadline | Sum ⟨depositᵢ.contribution⟩ | SHA-512( ⟨depositᵢ.sig⟩ ) | merchant.pub )) -Check EdDSA-Verify(exchange.pub, msg, sig) +Check Ed25519-Verify(exchange.pub, msg, sig) ]]></artwork> </section> <section anchor="refresh"> @@ -762,14 +825,15 @@ Refresh-Derive(shared, denom) = 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) + coin.pub = Ed25519-GetPub(coin.priv) planchet = RSA-FDH-Blind(SHA-512(coin.pub), blind_secret, denomᵢ.pub) h_planchet = Hash-Planchet(planchet, denomᵢ) return (coin, blind_secret, planchet, h_planchet) ]]></artwork> <t>Taler uses a cut-and-choose protocol with the fixed parameter <tt>κ=3</tt> to enforce correct derivation -(in (κ-1)/κ, i.e. 2/3, of the cases, making income concealment for tax evasion purposes unpractical). -Refreshing consists of two parts:</t> +of <tt>⟨sharedₖᵢ⟩</tt> from a single seed per batch of planchets <tt>⟨batch_seedₖ⟩</tt> +(in (κ-1)/κ of the cases, making income concealment for tax evasion purposes unpractical).</t> + <t>Refreshing consists of two parts:</t> <ol spacing="normal" type="1"><li> <t>Melting of the old coin and commiting to κ batches of blinded planchet candidates</t> </li> @@ -824,7 +888,7 @@ refresh_seed = random(256) for k in 0..κ: ⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32) for i in 0..n: - transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv) + transferₖᵢ.pub = Ed25519-GetPub(transferₖᵢ.priv) sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub) (coinₖᵢ, blind_secretₖᵢ, planchetₖᵢ, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) @@ -837,7 +901,7 @@ planchets = (⟨h_denomᵢ⟩, ⟨planchetₖᵢ⟩, ⟨transferₖᵢ.pub⟩)) msg = Gen-Msg(WALLET_COIN_MELT, ( commitment | coin.h_denom | uint256(0x0) | value | denom.fee_refresh )) -sig = EdDSA-Sign(coin.priv, msg) +sig = Ed25519-Sign(coin.priv, msg) Persist (coin.denom.pub, ...) // todo: double-check ]]></artwork> <artwork><![CDATA[ @@ -863,7 +927,7 @@ commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value msg = Gen-Msg(WALLET_COIN_MELT, ( commitment | coin.h_denom | uint256(0x0) | value | denom.fee_refresh )) -Check EdDSA-Verify(coin.pub, msg, sig) +Check Ed25519-Verify(coin.pub, msg, sig) refresh_record = Lookup by commitment (ɣ, _, _, done, _) = refresh_record if refresh_record not found: @@ -874,7 +938,7 @@ if refresh_record not found: Persist refresh_record = (commitment, ɣ, ⟨blind_sigᵢ⟩, h_planchetsᵧ, false, link_info) msg = Gen-Msg(EXCHANGE_CONFIRM_MELT, ( commitment | uint32(ɣ) )) -sig = EdDSA-Sign(exchange.priv, msg) +sig = Ed25519-Sign(exchange.priv, msg) ]]></artwork> <artwork><![CDATA[ (W2) secret revelation (wallet) @@ -882,7 +946,7 @@ sig = EdDSA-Sign(exchange.priv, msg) Check exchange.pub known msg = Gen-Msg(EXCHANGE_CONFIRM_MELT, ( commitment | ɣ )) -Check EdDSA-Verify(exchange.pub, msg, sig) +Check Ed25519-Verify(exchange.pub, msg, sig) Persist refresh-challenge // what exactly? for k in 0..κ and k != ɣ: revealed_seedₖ = batch_seedₖ @@ -896,7 +960,7 @@ Check not done // todo: sure? for k in 0..κ and k != ɣ: ⟨transferₖᵢ.priv⟩ = HKDF("refresh-transfer-private-keys", batch_seedₖ, "", n*32) for i in 0..n: - transferₖᵢ.pub = EdDSA-GetPub(transferₖᵢ.priv) + transferₖᵢ.pub = Ed25519-GetPub(transferₖᵢ.priv) sharedₖᵢ = ECDH-EdDSA(transferₖᵢ.priv, coin.pub) (_, _, _, h_planchetₖᵢ) = Refresh-Derive(sharedₖᵢ, denomᵢ) h_planchetsₖ = SHA-512( ⟨h_planchetₖᵢ⟩ ) @@ -945,7 +1009,7 @@ Knows coin Knows refresh_record for coin (W1) history request (wallet) msg = Gen-Msg(COIN_HISTORY_REQUEST, uint64(0x0)) -sig = EdDSA-Sign(coin.priv, msg) +sig = Ed25519-Sign(coin.priv, msg) ]]></artwork> <artwork><![CDATA[ (E1) refresh secret lookup (exchange) @@ -976,7 +1040,7 @@ commitment = SHA-512( refresh_seed | uint256(0x0) | coin.pub | value msg = Gen-Msg(WALLET_COIN_MELT, ( commitment | coin.h_denom | uint256(0x0) | value | denom.fee_refresh )) -Check EdDSA-Verify(coin.pub, msg, sig) +Check Ed25519-Verify(coin.pub, msg, sig) if ⟨blind_sigᵢ⟩ returned: for i in 0..n: @@ -1066,6 +1130,19 @@ if ⟨blind_sigᵢ⟩ returned: <seriesInfo name="RFC" value="6234"/> <seriesInfo name="DOI" value="10.17487/RFC6234"/> </reference> + <reference anchor="RFC8032"> + <front> + <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title> + <author fullname="S. Josefsson" initials="S." surname="Josefsson"/> + <author fullname="I. Liusvaara" initials="I." surname="Liusvaara"/> + <date month="January" year="2017"/> + <abstract> + <t>This document describes elliptic curve signature scheme Edwards-curve Digital Signature Algorithm (EdDSA). The algorithm is instantiated with recommended parameters for the edwards25519 and edwards448 curves. An example implementation and test vectors are provided.</t> + </abstract> + </front> + <seriesInfo name="RFC" value="8032"/> + <seriesInfo name="DOI" value="10.17487/RFC8032"/> + </reference> <reference anchor="HKDF"> <front> <title>Cryptographic Extraction and Key Derivation: The HKDF Scheme</title> @@ -1091,7 +1168,7 @@ if ⟨blind_sigᵢ⟩ returned: <refcontent>National Institute of Standards and Technology (U.S.)</refcontent> </reference> </references> - <?line 1099?> + <?line 1174?> <section anchor="change-log"> <name>Change log</name> @@ -1104,214 +1181,222 @@ Education and Research (BMBF) within the project Concrete Contracts.</t> </section> </back> <!-- ##markdown-source: -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 -kQAA +H4sIAAAAAAAAA+09y3bcRnZ7fEUNtTDabjQfkmWbY9qhKUpiLFIKSY3G0Sjd +6EaxGyEa6OBBsi1xFvmIbHNOZuHkA7LxyS6r2fgfZr4k91FVKKDRD0qU7JkJ +j47YBOpx677vrVvVnuc5F9viruPkYR7JbbF2OpLi0dFzcepHMhXP0iRPBkm0 +5gTJIPbH0CJI/bPcGxYyzwaj5NLLsaE3UQ2dgZ/LYZJOt0UYnyWOE07SbZGn +RZZvbWx8sbHlXCbp+TBNigm2COREwn9x7mR5Kv1x9dm5nELrYNsRwhM0D30a +pNNJngxTfzKa0gM58LMRfZr40zH0zBznzoWMC7nt3BEilZNkW4zyfJJtr68P +w7wzjItY5p0kHa5HWbABgHXg8To2jgD+LC+bw/uG5uuO4xf5KEkBNg9mFoKR +cxieJ5Efikf/+z+MHnoHHbfF6fMH4kEqM1iZeB6HFzLNwnwqkjNxKgejOImS +4ZRa+/1+Ki+wg25PjxFBEgB7LKPxKIny7+FBR2xu0MsBDLVdaT5IAoDngbex +uXH/C/WkiHMkzCOZjv2YJ5NjP4y2xZjh7hiy/l1eeAEP1wmk48QJ9MkBaiTG +8cO9rQ39YXPjnvr46ef3v1Af72/d1U8/37i7hR8ff/vgIQD09KCzuQH/Nj5b +/+Kzz7273v17W97mPejgfda9ew8anjw+Me3ub2x9vn50cHLaeXjw7KSz+fmG +dw94CjjLgOM4nucB0gAd/iB3nN+9FKffvBC/e8UvxmEQRLCAO+IAVp8ExSAP +k7jS7Bt56adS5CM/h//CTACvF8hGAj5neRhFApnWC2Nk8yFgJRN+HIixPwWk +xrkfxkKmaZJmHed5JgUMM02KVCSXsUjD7PxXOPtRkvs8syd6a35/sNYTgNwE +uA0mlSIKc5n6EZI5jIeiBy16QsZIxkD4mdg92Ts4EC8J9a9wDF+8Ef3qGAAM +il9MEyFn+eIyzEeij+0jGbt+qzapjIfwHuDvT/EZdMHH+IcGxMe+Ez/4R5km +7rQt6kNU2rbF99DMg+YIdZ7Yk8DYU54GR+yHeeZetXrrPXqEHyvDjsM4HAM6 +4mLcBz0EnbHHOoMZywHQwE+nOAVIN1AEqUX9iigPJ5EU8HAQZoiHMAaNBGNc +4bwF/IXLqM/Xm/YAUD/LRRYO4/AsHPgwIs6pkaKH6V31qstEVtCEAkyCpkBu +YcSA9oIubj8cQpMg9OOWBuI7WvLlSALn9b7rIav5YpKATgCuNpOp5cNL+S9F +eAEqENeZqHV8R+vAEVMAIhm7U2tVvuCH0VQMZQy8lQN8GQwDsEpFDVges9LH +oi/ccRKIIxhhnZ5UHlVIwygGDBGbrQt5NUliACw0fDefCggXIqzfFjB2ESXi +CCEAeQas9sIz+P/CT0O/D539DGlBgtjbgRfYD1g8CHEa4I1kgqtKcEwU30T0 +GXEpzIqLjcJzlGoZgh2bgrKO1/++iELfQiWtPvBzvwOmprpKkHQYHhR0j17B +CvBp0v9nOci5DyF+o9OJqx3l1SAqMiQi4H9ImK5SMxNnaTKGrj2iZOxt0kh/ +/vf/xFH/9N//8ed//68eCS5wk08aRl7lOE4vFDuiOmMPPjNQGUMF/QFVRiiY +J8dyDCYZ1QiPF8ZFUiDaUn9anRsRcZP5/ZhH0VKC8CjUhQgeIw80ESjRRlhR +N+6VBj0cgM8RjkkKwIqvrwOOArDeoGuBuoMRoZSVtMwGaTghlgM8ZslYIsRD +4CvghgzGiPwU32jXRJwVMSn/TLjECKDQs0mYolhMQYtftQCWOjCPwbMQD3VH +bHAHDNSut/XpffH6Tjby4cO14/z+97931GN3nA1bwvtKjNApcQ7iSZFvk62F +F/gLCAKPgCagwpg/lIZ8Ir4UW/90f1Mkg1yiD/O0yE1nHI0GUd2CcAh+CvY+ +C6+Q2XkMhPcJeBg74u6WHgeBc3o4AKkZ4mMaGXvrxQBvANHEiVQoutfZbItP +8b/7+B/K3v3OFvZ4qez7q06Jjk83txgd8MFCB/z1rujY3Pr0dvBx/97K+MDV +zOJjC/Gxhfi4q/FxbwE+CKsueL5kkwP9uGXw5NG7KrZug4FuDWM1Djot8aSQ +N0hS0DKg/INMG/uzMIUxTU+tFmbxG8izMGbt9Pq1YpzrbUZGLscTmN/mIIeg +3xH46uXG9t3NVwwUuFW258YmAVVCEJ6dGV2rRlpXjG7N/RK8zVf4gU086B0w +LDQXWIhCAklRJxwqlO2Cz4+GTpm+PbD5Sic8PtzdA8qOxr6mKD7xEJku6MC2 +QB1KVAVUAF1IbzFdHiu6DCqKh2DQGovdOIXEKp0qDAIzEYNkcgAmkP4sucPP +lYeje2JLUu2GpVApk7ZOwTVA/4q7VvkIwBDqt6JpDSKWL3hN4jXwo0ERkQjU +UK+ih1cKyd8CtA9kCqaZllxTuhg+IILPg7Nr5kWcDkaa00242KMlioxn43g2 +JIsFej/3bX/lpYpeXjmEaHDgFP+g71GhBDBUkhKz7F9RwEGaYP9qgr+yXE5w +kVkxRNFSy0Q4Xm07PfztqV49hAusIDEJcCcwJ1jty1EIbo9uiEPW2wED94Q7 +OOuA0BCvXbc6it2gk5v5Ud4WB98etin6bosnxHJPvz1UbJIxCbEdkXCiXCl6 +QBwvXF/ESewpFmIfkl+1fk2dy5/wDJrmaGAvQvB+YVIOmST5qL4OCwDBoHzR +ZYYACfsBgJYeAy4lsw0sAo5f5PCbs6QCoPZCEM3+pPQ+swk4mOCtCxMTJnEN +ShdceXQNffbaFbMybC1q+0S1LCMVxds10JCcSiPWpvhyR2x9+unHoPd2xOeb +9zdaVZF5qhY8b1wXpnyihm7NaFvsPSNIZ0kUJZeZ0pjPjr+FmW0OK3mhxdrj +MStQrX9d2zK2HJzDDICc58KQFhfVhyDjZpsKBbYWVe8wCSCy9lH6lO9MElxR ++yTM121W3UbXAdsVaUyCilCRckeugnAQRRj+Rrd0CA5ivCjcO7IEA6Fxj9qi +Jh/NwnGkqTp/8IoQ/dxStIIYfQA5uhm/V4h5ZLE8cAdGdsrNgHHIhgQQz6Vj +Yhz9MczQDEcQ3fY1k/mc4kI1z4Y8/B5lJSd4FTfoFhDHOEEi4I8wInC/FEcM ++5WSg7oyFW8EBt2b9101RqvN6Qz3qNUyq96hRi6lN45aGJ+XuTeY9pMdsakF +RRwBg3wThUCJE4hzfeB67U3sB6BNNr8AlJDVIhuwHzw42bVMFyyNhHJQpBeS +mqNaUD3bTtXWKjcWHXpt7zAvB6b3IBYTH4I1VC1pW5nJIIEJu8CVXaAZBNEA +AHZTg09ARab6j0F+VZuLBFan0NgnZuOu0hCUBEMcqBG8RzJ/VvTdCdhwkshJ +0a94NfhC/4Z165mRq6psBx2F+g2MXWnHPgm8aPRJMJLsz2Cq82kNVxWoYUWw +IJcgJtjbOG9NEBaBvhrE0LFH0srAY6bjraBvO+BdDEazqSTy2smYgIgqc0Jg +7yi15YKubzkI6Y5oIplR/HeIj2GUKqLwoUKQjmyycFjVuRpPGgEaXxpPOvLR +sQsnezA9JIMqxuGZUL9ZpLT50V37U/qT7Yc9DyMc+t2ERe7XWYTw8BtQc2fT +GUzwYxdQSahoI5BlTFDBh+ILgw/mjzo6GAF6afPXD+2bfXgIQWUbLRB2oxQk +MEYYWL3R3cXuVadexXSDZCx1iBdhaDEYycE5hXkWjj6bxRHpg91hKiUqCYcD +gGZdeHyy6z188Bh8/zTzvbNgdK2ZrZhMEtBcYFisWAHhVF1cwjGgDtBGaIbO +VTTX2EqjnsIoGMRCOxrODG0OW2LKXRYZ+AoomqqZzoMKWUU2TEuznBVR5IFA +4X4BBRU4EECQXIDK5Wk7RwrR0KfOhsbOaY+GY1t2ozyA6Pp61jEky7Uj1hgl +u+Lh6SR78as1h1yVHW3R2I5pEFqt0tZV3khl6OC1blt+lA6uc8dAZ4bTbhdR +g9yu0twDldHJwg0PWrFyMShoQ92ECQp/6KPVA94EpyEchJi5VMRBeQB5vtDi +pjMBIN6ppI08oNt4jOkAGSfgNWC6WLjDQdCifCbNqZUrAUtI3+xU+Mij8FK6 +/fOswk4zUgsNCD19ZGQEBxlHuYB2lsZOrbwfltPy3cRyCGUTyzUE7O/Ect9o +LEBfw3CVpwA+xSpAE8qfADRry7iIiGBxEakCPWiVbPSUlcBS0jVpgl8eOY0N +Q4iAMqiclRgsp6FWpIqEWps2UJDSQDuiSY06afmiSS6ctCvRc8D9I60YeBvJ +aBcHVwNNoOHHnHGqvZ/jT+hZyZ/Afm0y35qkMz4FDa1/2w5Dm3NAHCZWIhE1 +HoiEdkqQcETH0lFYTEjVzlByFfeEIAQ9piZc6IlUKYXD7XB/RLgCP1AY1aux +Ufo87jcKi3ruwogriIteBvUpF/MLFZsi1gJTQrooSVnF8XKOD2P0luF/mXKg +lDazPGLtY8Ht5/J8zXfUMyvfUbuNN9dmDZx3pnFO5gC9vPdLh6Xe5gfTYgCp +pscyPeXyODu4OivJtRf54KV4J1i6k6a4i/kA2uXTieTikLLeAxrvjjH+z8CH +9fkT+LD6GUZ0te1aDsJxB0rXA9AOjTdJQGtxFilzqvTo0dMedkL3B3NPsRz6 +lWICjPNNiQfgE1MHqYwH07ZDW7dnaIsB5J4KjgCSIlYVEEBXMSriAHdLx2EU +QTMQYndTep+35oxJfpX+00B219vcVMUsg5GPM+IuTYj1XsaHK0cBR+zFSMby +grMggd6p0Xu6bZ4YHLt0WmKxrH+JRY8xjvzkUNXE/XsuP+pwOk75une39GON +BnyjC182t8Bo8GsNWqvHkcxpCFKW++MJBB+7/SyJCtyRMg9n6At40HBYFSBX +9d00h6tgBmkCqpOeZSEWbvQ2v/hsw9vYhH9iY2N7Y0Ps7Z+c9oSL7Z8fHfxW +yEkyGLU65F9TWs+PVFKyt3H1sPbTK2HLxBoheq3jfPkrzyv33jmowzSllLrg +hYAd5M6xjJjJ3mbFIOKG0+ylvhXs4Asp6D3vK6KMHUnuRpHWhlnFGSjlDaAH ++aCcmi9G0sfKHVXepdgyhEbh9xIR4Phq1zRjF8UkVsFhTUFsga9g2akcgohK +FBow7492j3YVAzsvHx09j8EgGhjFM+6XvXJNpaIf+3btIX/0jLbM1JNu+aQz +yscRmCSaN512eGleKlmLKtgytVaIlTY3NjZUtPNIxt5hNtQLKLM1DdkJamGZ +Ev2kumYYH9fcmMEhfIE2c7FepqPw3VqQ2NFGBAK6SSTzMqHjglzMG6FqTzCz +3WThWdErLYB1crhySzEYkr4pUyG4zyEjLBGwkg+nxNrI/74YyJQqA8sKNhDg +YSQ9Px1ydWG5p8ipOZ9sMmBFCRqr0BzHROYWEMBycAuKHPqPZFaW7IHhwXR4 +uYvCJS3bVG74bQxrJS+xpxP9UpXg9Mz+ynmM9Yo+eo1JGgoVRzOjqElMJY3Z +ZsfR90g9oOD2OBIPqRJKDdBPkkiCHjaFW5g7NiVePe6GGSX0DRyslRV+P0nz +bM6MIkGEXIaZxLmfYRVtlqu1TfivzErw6UWqUsQEcYSP0Fbp4i+g/ZMkOS8m +KKRUsASuahqCNslw6+cCMw7RVI8ODKQGrWQSqdIJRzwpxqJWywXLY0cH4zXg +B0ASwjFTCyWQkwvymZWfoPd6tdtw3UIcIVvYJWflkBlMzsTKdLEasOUJpumo +LKpkOSIQZZMpQQLr46TLKE2K4Qgl4vVrjX1TmIEbfuADx8nYpYRKS+xQwS7X +aShp2bAkZxM/U9MOJ8dphGeRH4NRyd2J+tAWDcOVH8wAwhp644oG10MIGJw4 +0Tsp+rwDSoYDvGX6G7yIgMdnfmWr8tWO9RreaX7it17lLYu9QNPEBoMrxUyN +PHh3BmFW5VofOOkM0Buq8mPJ8jpKJeGePWZQARiGAiJAHVKRG6hfmeLH/Neq ++I0sE3tOQegPU38sqIgcfczSVvuTMKedrwUjfk3q6wWMF6Q+NAPIL80fqrqC +e5vSUaw0FF+JDXRTQmAfLBnET5rFkSVTLC5F8cNCv9ImUVsKwNBQ6Q7kv6t6 +SQbP8XOQun5BLi0TQIktT+kPwOkg4aCySYBkBErZSu0RX1MtIz5RE7EvkYM3 +rj0JBLVcrjgDOrh6+0qJtIaJSsDs8VvOuAD2QAOj8gYg0bBsGEfBypIKejNJ +S3eVNT9mO2V6odKbqAtKMDoWDU35+enuk/3j7uHub7t7Tw+OTriIDUEqtaEb +MJr2TjyqQea9WDMUeCRSLZeTbQLEOw4AzxMCYO+bE5ZsYf0o0i/90Vhy2L5U +ET+/20zrDiYqoEttvxmEe8WfN84n3qKfTxb0fCPcF6BINGnOK/uUC0B4lznf +fp31B9aEwu378TnYUT/OztARst591TCnC6oN7cO2XnuH9qWYf7dVrcLtQtvc +bjEevU9WHOaNUd5uZUE6yvuw0DTAt4Rh5rMNM+lWi/SgzZ1USK+zbE2AvMuc +b7/O+oPqbGJdaz1RfdHEpPBTpaY295naPL19aJvbLcXj6mzq7m8qUoZZVvgY +1PtxGUh+cIgaYJzp+aVFP3fWnLeqpHwXcsxZ1nx1anqikNxVmC3ihXJxa3PW +HyzrUfYkb5JTIS5a4uOT3TbZaXS9IayFmB1LqzgTxTZ6kaFy2WhDS92gLNbQ +lSpOXUFq5VjuxyrTH1CaO9OOl61mOJGfgQ9DYQpX9ZEz52s3J5OYapC2e1N6 +LG0nT4YSYziVaim3YjBFf4X+GsRLdPIOlw+eM4Ss/jnNBm0x+B+bHF8gIcaO +VGqMPC2cO8QjYpgyxIwQuOq0l+zHU44dKQ+q8pPjcDgid075kuoQkZ4E6810 +HXA0tX00JQCEjHVEEzkxdmvr1BWmmMiV2//t3uPdo0f73UmS5V2Nni4F2esQ +amJg3yWkQ0SUFBghc/KNUMXE8QYYyLkQavQhhJ7OwQgylmGbZaajZJ6+nw9G +XUJitfxHs07ZwEGuDXFteCIIczQ4B70CpaCL6FSwFmKxnOnaFmt8arhkEA87 +e4Gp415rU1mqqCCax7WneXl3a/uVmlp7kvUm23e3Kk2aCpns/jjrqKudU1xI +LeqFp9hGmyJuVN101qGrNSlioLoWFfXq9zRtddDmaLnSteUYk4ibFaCbS9hB +M7fR0bY6orJ2MBe3I3S+78Xukyf7p93j/ZP949/sd18cnD5+cLz7ok3KDaJw +lc/QoJLKQAf/zcwrCKUMU2t//k0ZxhNsVVhMQI/nXjauNirx/cxfrZba8KyU +lhn/wJSYsT4j3l9sa10dwgDrr4Q6mNuge1YALJ4pE0rlmCb3YNqpnBtAhBXA +GnWevKJjaW/LEH/B5GX81OrlKg6gqZtTbbW5+/a7PUxW5kUmknOMyhGjnEd1 +OPrfmb/WT5autZZa0iD1fVwvGFKaojXLErajZGkJrolsIp9SQVrfWibU2J5L +TN3JKx+N49ciA48hCtiGAYyYWaAzWAgKWJTIn35tyUOTh1Sq/0aVjkCx2NVr +BezFraDdmGC1De1mTWnNOzuOfqkkCwCryJh+bcMDbeqGxMYn+Bj+haw0oX1q +yxz6USr9wMoCf21oVEmFmd2BZ3wVBWYF+VM1sZb0cXcgowy4OhJkld4T9XD3 +kg6QW9kyncJz/DOsJx9EfjhGGoZm56oXJ8CRvY6jAdBH8OgoekgpbfQzKNll +FCHVgAMHA7Jp01nw9Rbh95W0Gr2yTyjPyQbClHr7Y3F2rq1cYHLdOHeNJ4UJ +J5QKpNO6PftvpN2XO6IqxL2WoMTcGAnGB5E1XlGgAB+gtwvcUM/poHpk1gmC +rvYbFZmo8EDvMeFhrgTdpayCfYB1gFcQYHkd7jsHUo65xRz0qc0Qk1dUaX3V +ujzFZccIq6bhDEuYxFpJigXduLXuTGqnHs4s6VsmlgF1efKzxeA3CL0PwR1g +QbCTfB9o/gaI5gbawv2HYw/Pl4p1cfRwD/5/fnxghdmLYHZphZ3XYdDOk3MZ +f33dshu+hwzWskjZpFlJN62WYH33OesPlnRY0FMTZZ0wm62/ZgyHwfU6aWBF +lzkZLPhxaeHswXBfpowhzM+awbqJAFEsyZr1NmXofYgRaFkFadvSc0gCPnex +RIyWzbloKYt7qnSuNjhskFeQh3eZs/5gxWXeTBhgRUZFzRcG/nHrHkWr3vzn +EYmbCMPd0l/iPM0HmbkBlkUJW6aWa3i+8vOeBGAhN5pUrRYArhoZLJeAd5nz +7ddpp2qtDK2wMrTgAiVROJjy5rJKomJpCR660Hm4RufD1ZoJWl1C1N9VByVU +8m1z6/OWY46/CjDpgvxZfTSbzYgJRXj4HeHOaYgpZjWHnSVpNM1lWMivFiSU +lXVDF3LmVg5ZqZ3HUlUOUMjPplpKTJZitE7b4n48ZVTXKj07zuPkEpO6dD56 +oGNeuyj0rKBaNL7yB8K55BLWko3CiSoFZeTQBilXeLYdGfsY9A1xHG/gU2lc +gaVYmVgrYh1drWE+QW+spioTrUbDxLJKK8NkOCaeycCz3KqUVTO55hzgGnVq +TVUMYBR+EQYFnc6GaKqj2WWOqbU5hkNq26PASmXFFKMuEltnYg3hlbveFmt6 +IA/flXWFKvdacp2p7cSLpc4KiJEDiIUBb1Lxk/7TMfDu2F4oMyLxoXJI7aoU +BrO9+iwtM01Hc6ZxrwxL6iaABQsok20AosVYMfX3J0+PjJvQqufODvePMWF/ +2t17enR6vLt3itCa1k3JyEo8NZONnGf1S1F7j9A25taqflE9uVbHs0I0boOc +Pn3wdFttUnhs/LjAhI6Z0YOv69d3DfEqhDBAcdwDTj+RkTolClypN4X60zKp +cSlN2gUzpTqzoy+Cs1MCDngTmR5Pxb471VkM4jqvDfMRZ0J4xKvh8jspDv30 +/EGIl7+hJprNiulkVZmaatfhwUyxDY9DFbCcBKxlZrG2p/tg/9nTk4PTtjJT +rkW5WgrV0fYLHyJ3qEyqWZ0S+zf1PJnpaFoaibMf1mSv2svKwXwiKslS5QeZ +5k0vsX7W4rf6Guh0qUmVVsTK3p9pK0y2KOOuHUjUOLrVa2RmTB2qlV/PkKet +5rH2RMtYAVlJ72y3xYybyvJsREBeTSJMdFV4zXrPrF9W/2XTcR8vo+Oje+tk +NJXCn3EnZ1W9yVNriDr2yojrd0Q19aV6PuAus273PC3ybPe7w334/fTbd9V6 +81y9Uu3dEIQbqTKdkFUIEK/v6LSbtZ/rB4GhUY53JWIxv+PoPuxv+FGWGKcj +CPEABN4/MsV7Vtnno5woHZm5jNnM8k0r5j5TQ5rZfJ9JLi77qdXd6T87+tKA +mZ96O2S5hvTfgr7VtK3qrNyI0mtd+vNG9azIWoUbl/WvP1g+p+75TuE6uu5a +NP8yw3UKAtdpQ8PTK7HhmVd9xdFDKXxzSbYQ5ob0y/tZbXO7+XS4YdmWxhyV +899W5uu2437hWq60rR3ef+JredyPUY3B4t9O3P+gQXnY1h3FjPwxYZnv1xYd +KxHQTIR0zQOoeM+ta+bWLyoK2rfwYQmSXYxRDV3N2jpWEFs+XC2cnbe3jefn +bW8qjOdVcsz60wvLOdSoVjUHFQk0TFk6cPO96vccPSwNGgyDVqKG8um8sEGv ++Z0Dg0afz6oa0GFB28YtOYC3V3lQqwLRbdVBI1UDYs6kKfqDm5ikgZOBSx8U +ER6Ttsr0KVtFu6clWjHKvnTrUmhqB0EKHx4cH1aJXiO5IaeNR1Ww00y/ah6n +TvMm6r5ZHow0lAhViaNrhCrUby7zqrivMzoFzcqDJrNiK9l3TIh9AHoY1d9E +joUh+vukRqPoVR2L2XDrWJ6BoRzhvV38aU79S9wTsbycX0iyuIDEwe/e0FUV +qOLxooIkwpsHYJiZAUSP/mo4ftaxDu/i/b+p9DM+mmuFd1hPRsfHg4QuLd12 +nM2OeNrXZ8SLGOhx7nPdLoHEZTpcLE2nLP3KNQwI5EeZOpgWFJxbNsGyqhLR +9UPXuH1gnKeZEpK2E3ZkRx+vr1gVXS+jimWcrQ6QB7DO01E9WJ/PGId1u4Xp +6NOyOienS7uYsnhyDvP5CqXqsDJRs0K0j9SVFQ0n77K5R++Wn7QDGDhrztjT +ZU6G9grw2u6D9Acjw3B431iA/oc0nPfnf/0360iaOpoMupru4QD6cWl8UDIQ +TqjIaE/VM0XhPeci9LE6nivRcKJshAVYPBUfn6ycbVSio26bUUcYVfeQTtjz +bgAxGt9YDQ3Q+4hkwDfCW9MLnJ6/YgYMjzlRrfgHH1L90SlVL5l7tGWc0eFN +2sWp7KSwpLqV6WrbPC0uokpVhsRsnVTOtBPBfX3W1hhEf5yQJNF3RuFBAp+/ +SgKvhiMJGvmTiYxpVVpQ+EA0sW2bfC98qdhU3+VWwanLFKicO9blmLr8vV6/ +rruo2vVVCtb1KGv982ytXZ0BBoJHeHEyu6K6dp074JPlPeaVsps6dnM6elGB +ekN1+qLS9LllyHYNslDXOHNStj542aMcVp9CKW+8Bc1U5B7Q1huMErxdwvCu +4Xm+gwMjqjHuVoneTz/u3KXj/hKLKQdSc6HF2g6KR5MQzjnFQjkTuizJFNrT +iWZTGwpDkCmCOEW4P/3obbbWf/rRaHjcVGzjNbpUphnTlZn4RU3Sj/gWCNxb +9K+EvPDpimlzR0cRT+gmGojPsDxQMbC6a4TvOcA5LhMSEWWLDmWkrwSylZPa +MhnjF6uwkgEIaQV8hYS+H8vQ2CjGjI3FBd3zwrfq4BLNOSBEhT5mY2Oj3IYt +v02HAAe5HuiR8JWre7dWBOgdSiVv/cSyTmcChm/0c9vpl6VH1YRVhEfgjhWj +rDLxu8xZf7BCpzk96/OLdVzDTEnLvLojVnUNW0MqelsArbIkSgk3HUH9BRxA +1VS5WUJz6I/HfrlTqfQE8MetH0e9IXwNEM8rchLuH/8wN9FJP+8l27mE/02Z +n/4OgFKHLpn9XeasP1i6wLk97WnFOitpb1biFogbWhs0cbRl0GAjfhGicxN5 +oYIcvarb3QN4P5JBtPv/89plz/qDZT3Knjc8rz17mcv+Hjjf9CUO1rcFoPfD +33aCGwb49WCO83p7G7mMTgzBMCAv9dPDQwgIUBK7uNXgNPiiotJPmy9JX+xC +zbp50j2HOMrvll0zHEmHYdUweOF45Qg4qh6AYTNowK9kzKcCY0rGBEcr/O1J +lQCGMjDlVxS01fejtEUdNGhq8jHKrSujCW5UhZtOBcuLLn2vWtk0g7bVhuxO +dpUPahp2+Wx1xgNYmqARO0ikso2DyP3Tf/9gwg0g8/q1VX5Zccrs0/yl61E7 +kt1Edx0+qm4e7/cSddfaNT/GBIptcf6x3iE5VzskP/2IWyTzGaI+kW7mqSyA +dy6nOGUFQg5g4485hJ3ZkBFNJJ6JbxsA4kyqHc9ht1LeGrq0TQTNnd0y91MN +VvWzKmPZgSs/wYKvxhyD7mDHxjXm25lziNYwi2g5nCXho+0dTubhBorOxc2e +YL3B4VaLlS1QKqw3c4zXJCDesAPdeHZs3ungTLFrSzTsyy0/e7/6iXeDwXYT +Lxd9tIVzDkzTxtrh/hOT0LewpJavD6A2bLEprOj9rgqtmvc3LHGkvQ2rMM1Q +nFzbTqfTEpZ9KSsw2UjZ9sMhvbT/GFRWHESglVHDLNRFKwUF9latPoNb3Sc1 ++4fWFumS/dGlm3TWDp21PccyrOtVFVOWMwVYx7nkcP9KXPJhj/4T93z0nuTd +ugHxI6wXZAFu2NzUO5vqmphZA9Ggw2ds8Lx04S0pxp9VeX14zTF3G7y+D6cx +wNvPNQE1bgmFzl36FyRYWNJFRq/2dcADq42GPHuGNwkizf/4B/5a6J9+xHPO +7KI088ZqtyH8YLPFD7aRx82Krvp+EbfqzcwT3LaYFX2+HoZLA7SanUFXJYBF +LM2GUbYXkAGobXHmR3hzsoFz6abxXDZRGw9//MO8a0/m7odX9L9yTbN0sB6F +/XXdqetPQrqEiCL6zmBbsIHgsOIMv15vBFpoaW8rLYCDTGSKVxh0daJ+sdfb +mBspXd89dajAqm4lpfnWKAU+velmdo07wMwidLixC6ip3MNRU46k2c/Fr3Zg +1m3aDammP/BCCts1nk8623rzKCsY8bmZCtty30BDrML78/UHo5xsPm7PG98F +o8FliPsbCkG6WhP/dcYWH92yfV7JQGu/sPQRdqy/PqoLuKX+DTX4W0u6b6Vd +a/rRkt9ucr5YO77NRT0//GmVu3p+mAlyazb3Jjf2/FAvndMwzLu35werurB+ +dc/MjTo//Klyqc4d8QRrGF7foaqF5cc3bmmfcPn+HrerMRESSdWT1vh2xZ93 +za5CKDcKM8KHupv7l5pdrT9QqWu6WTFbf631wfW6Xg83WHbHAP64tdMG7wHa +5na3tu1At36yKlb+UsSG+pe87YDkc0nRqW/atn9+vjto9FWY/uBfijALf8F3 +0Nxww6FqmJYkm+taYd5BPIpkHx+cnD49/q57vP8Pz/dPTttCfZcP2uqVMlmz +dnNJ/qmZ21d2XVlXzHdcTaxbhmmNMS82QttquBjdAhzU9Gsav+VIiAEX97sh +Thq5tqTZcpi+xgUacJzbCJ1hQDNlgz+yLB+2Uippvjttsdgs6Ctl9P96/ez/ +T4PZETwK8qxAqOpEGczhvPfjTt+2Q30bLjUyfAEhN5Xpw4fSq1ZvBwkIL77F +D7W3L/hG6jzx+JN4VgB5ypsvL7cuvUlBpf9LukXRTLcoqnTDrxQv0jCfij0s +fwzUdSiZ4/zupTj95oH43StsdYBfslZvcQSavOM46JP0/cE5ttvj+vwoGeJf +uwNdzowgZKB8+Wu7ZLCzRjm9tevKPHRH+WWSnkNIgVfG0DeR8000VN6vitkf +yXTsx+KhRFgicYh5tTzFOnRnHyKV8iruY5lJPx2MhPvN4TcPW2Tnywtw8Gs6 +cE3IWxI/UIY+6zj/Bxn0s+G/lwAA -->