lsd0009

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

commit 570f110ede99657137c5b8357c8b924765d80b03
parent 018ea9e7e0bcadbbd849f3f90cbbd08cee1c48c2
Author: Mikolai Gütschow <mikolai.guetschow@tu-dresden.de>
Date:   Tue, 12 Aug 2025 12:52:36 +0200

introduce Sign-Msg

Diffstat:
Mdraft-guetschow-taler-protocol.md | 66+++++++++++++++++++++++++++++++++++++++++++++---------------------
Mdraft-guetschow-taler-protocol.xml | 324+++++++++++++++++++++++++++++++++++++++++++------------------------------------
2 files changed, 223 insertions(+), 167 deletions(-)

diff --git a/draft-guetschow-taler-protocol.md b/draft-guetschow-taler-protocol.md @@ -57,6 +57,7 @@ Use at your own risk! - `"abc"` denotes the literal string `abc` encoded as ASCII [RFC20] - `a | b` denotes the concatenation of a with b +- `len(a)` denotes the length in bytes of the byte string a - `padZero(y, a)` denotes the byte string a, zero-padded to the length of y bytes - `bits(x)`/`bytes(x)` denotes the minimal number of bits/bytes necessary to represent the multiple precision integer x - `uint(y, x)` denotes the `y` least significant bits of the integer `x` encoded in network byte order (big endian) @@ -364,6 +365,31 @@ Relative timestamps are represented as `uint64(x)` where `x` is given in microse The special value `0xFFFFFFFFFFFFFFFF` represents "forever". --> +### Signatures + +All messages to be signed in Taler start with a header containing their size and +a fixed signing context (purpose) as registered by GANA in the +[GNUnet Signature Purposes](https://gana.gnunet.org/gnunet-signatures/gnunet_signatures.html) +registry. All Taler-related purposes start at 1000 and can be found in the +[registry sources](https://git.taler.net/gana.git/tree/gnunet-signatures/registry.rec#n221). + +~~~ +Sign-Msg(purpose, msg) -> out + +Inputs: + purpose signature purpose as registered at GANA + msg message content (excl. header) to be signed + +Output: + out complete message (incl. header) to be signed +~~~ + +`out` is formed as follows: + +~~~ +out = uint32(len(msg)) | uint32(purpose) | msg +~~~ + // todo: explain persist, check ## Withdrawal @@ -417,11 +443,11 @@ persist *(coin, blind_secret) where `msg0` is formed as follows: ~~~ -msg0 = uint32(160) | uint32(1200) /* TALER_SIGNATURE_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) +msg0 = 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) )) ~~~ The wallet derives coins and blinding secrets using `GenerateCoin` from a master secret and an integer index. @@ -508,16 +534,14 @@ where `msg0`, `*msg1`, and `msg2` are formed as follows: ~~~ h_contract = SHA-512(canonicalJSON(contract)) -msg0 = uint32(72) | uint32(1101) /* TALER_SIGNATURE_MERCHANT_CONTRACT */ - | h_contract -*msg1 = uint32(456) | uint32(1201) /* TALER_SIGNATURE_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 = uint32(72) | uint32(1104) /* TALER_SIGNATURE_MERCHANT_PAYMENT_OK */ - | h_contract +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) ~~~ (without age restriction, policy and wallet data hash) @@ -562,12 +586,12 @@ check EdDSA-Verify(exchange.pub, msg3, sig3) | where `msg3` is formed as follows: ~~~ -msg3 = uint32(344) | uint32(1033) /* TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT */ - | h_contract | contract.h_wire | uint512(0x0) - | exchange_timestamp | contract.wire_deadline - | contract.refund_deadline - | sum(*deposit.fraction - *denom.fee_deposit) - | SHA-512(*deposit.sig1) | merchant.pub +msg3 = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, + ( h_contract | contract.h_wire | uint512(0x0) + | exchange_timestamp | contract.wire_deadline + | contract.refund_deadline + | sum(*deposit.fraction - *denom.fee_deposit) + | SHA-512(*deposit.sig1) | merchant.pub )) ~~~ # Security Considerations diff --git a/draft-guetschow-taler-protocol.xml b/draft-guetschow-taler-protocol.xml @@ -29,7 +29,7 @@ </address> </author> - <date year="2025" month="August" day="11"/> + <date year="2025" month="August" day="12"/> <workgroup>independent</workgroup> @@ -68,6 +68,7 @@ Use at your own risk!</t> <t><list style="symbols"> <t><spanx style="verb">"abc"</spanx> denotes the literal string <spanx style="verb">abc</spanx> encoded as ASCII <xref target="RFC20"></xref></t> <t><spanx style="verb">a | b</spanx> denotes the concatenation of a with b</t> + <t><spanx style="verb">len(a)</spanx> denotes the length in bytes of the byte string a</t> <t><spanx style="verb">padZero(y, a)</spanx> denotes the byte string a, zero-padded to the length of y bytes</t> <t><spanx style="verb">bits(x)</spanx>/<spanx style="verb">bytes(x)</spanx> denotes the minimal number of bits/bytes necessary to represent the multiple precision integer x</t> <t><spanx style="verb">uint(y, x)</spanx> denotes the <spanx style="verb">y</spanx> least significant bits of the integer <spanx style="verb">x</spanx> encoded in network byte order (big endian)</t> @@ -396,6 +397,32 @@ Relative timestamps are represented as `uint64(x)` where `x` is given in microse The special value `0xFFFFFFFFFFFFFFFF` represents "forever". --></t> +</section> +<section anchor="signatures"><name>Signatures</name> + +<t>All messages to be signed in Taler start with a header containing their size and +a fixed signing context (purpose) as registered by GANA in the +<eref target="https://gana.gnunet.org/gnunet-signatures/gnunet_signatures.html">GNUnet Signature Purposes</eref> +registry. All Taler-related purposes start at 1000 and can be found in the +<eref target="https://git.taler.net/gana.git/tree/gnunet-signatures/registry.rec#n221">registry sources</eref>.</t> + +<figure><artwork><![CDATA[ +Sign-Msg(purpose, msg) -> out + +Inputs: + purpose signature purpose as registered at GANA + msg message content (excl. header) to be signed + +Output: + out complete message (incl. header) to be signed +]]></artwork></figure> + +<t><spanx style="verb">out</spanx> is formed as follows:</t> + +<figure><artwork><![CDATA[ +out = uint32(len(msg)) | uint32(purpose) | msg +]]></artwork></figure> + <t>// todo: explain persist, check</t> </section> @@ -451,11 +478,11 @@ persist *(coin, blind_secret) <t>where <spanx style="verb">msg0</spanx> is formed as follows:</t> <figure><artwork><![CDATA[ -msg0 = uint32(160) | uint32(1200) /* TALER_SIGNATURE_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) +msg0 = 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) )) ]]></artwork></figure> <t>The wallet derives coins and blinding secrets using <spanx style="verb">GenerateCoin</spanx> from a master secret and an integer index. @@ -543,16 +570,14 @@ check EdDSA-Verify(merchant.pub, msg2, sig2) | <figure><artwork><![CDATA[ h_contract = SHA-512(canonicalJSON(contract)) -msg0 = uint32(72) | uint32(1101) /* TALER_SIGNATURE_MERCHANT_CONTRACT */ - | h_contract -*msg1 = uint32(456) | uint32(1201) /* TALER_SIGNATURE_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 = uint32(72) | uint32(1104) /* TALER_SIGNATURE_MERCHANT_PAYMENT_OK */ - | h_contract +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) ]]></artwork></figure> <t>(without age restriction, policy and wallet data hash)</t> @@ -598,12 +623,12 @@ check EdDSA-Verify(exchange.pub, msg3, sig3) | <t>where <spanx style="verb">msg3</spanx> is formed as follows:</t> <figure><artwork><![CDATA[ -msg3 = uint32(344) | uint32(1033) /* TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT */ - | h_contract | contract.h_wire | uint512(0x0) - | exchange_timestamp | contract.wire_deadline - | contract.refund_deadline - | sum(*deposit.fraction - *denom.fee_deposit) - | SHA-512(*deposit.sig1) | merchant.pub +msg3 = Sign-Msg(EXCHANGE_CONFIRM_DEPOSIT, + ( h_contract | contract.h_wire | uint512(0x0) + | exchange_timestamp | contract.wire_deadline + | contract.refund_deadline + | sum(*deposit.fraction - *denom.fee_deposit) + | SHA-512(*deposit.sig1) | merchant.pub )) ]]></artwork></figure> </section> @@ -714,7 +739,7 @@ msg3 = uint32(344) | uint32(1033) /* TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT */ -<?line 581?> +<?line 612?> <section anchor="change-log"><name>Change log</name> @@ -732,129 +757,136 @@ Education and Research (BMBF) within the project Concrete Contracts.</t> </back> <!-- ##markdown-source: -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 -->