062-pq-refresh.rst (14628B)
1 DD 62: PQ Refresh Protocol 2 ########################## 3 4 Summary 5 ======= 6 This document specifies a change to GNU Taler's refresh protocol that provides 7 post-quantum resistance through hash-based cryptography and unique 8 signatures, eliminating reliance on Diffie-Hellman operations, for the key 9 derivation for the fresh coin from a dirty coin. 10 11 Motivation 12 ========== 13 14 The current refresh protocol uses cryptographic primitives vulnerable to 15 quantum attacks to derive the key material for a fresh coin from the key of the 16 dirty coin. The rational for the elaborate derivation in first place is to 17 ensure taxability: When original and new coins remain linked (by the owner of 18 the original coin), passing coin outside the Taler protocols is discouraged. 19 20 This redesign: 21 22 1. Removes DH operations from refresh derivation 23 2. Uses unique signatures for ownership proofs 24 3. Derives key material from (unforgeable) signatures 25 4. Maintains backward compatibility with other parts of the protocol stack 26 27 Requirements 28 ============ 29 30 * PQ-resistant refresh key derivation without computational hardness assumptions 31 * Preservation of unlinkability between old/new coins (except for coin owner) 32 * Compatibility with existing denomination types 33 * Minimal bandwidth/storage overhead 34 35 Proposed Solution 36 ================= 37 38 RefreshDerive Algorithm 39 ^^^^^^^^^^^^^^^^^^^^^^^^^ 40 41 The core mechanism uses two hash functions and unique signatures to 42 derive the key material of a fresh coin from the old coin: 43 44 .. sourcecode:: python 45 46 # Notation: 47 # r = random seed, cs = dirty coin secret, Cp = dirty coin public key 48 # pkD = denomination public key 49 50 def RefreshDerive(r, cs, Cp, pkD): 51 t = Hash1a("Refresh", Cp, r) 52 s = SignUnique(cs, t) 53 x = Hash1b(s) 54 b = Hash2(s) 55 c2_s, C2_p = KeyGen(x) 56 m = Blind(C2_p, b, pkD) 57 return (s, c2_s, C2_p, m) 58 59 60 Key Changes to the existing ``RefreshDerive``: 61 1. *Proof of ownership*: ``s`` proves ownership through signature, without DH 62 2. *Key derivation*: ``x`` derived through hashing of the signature 63 64 The hash functions ``Hash1x`` might be the same, but can be pair-wise 65 different. However, the hash function ``Hash2`` must be different from 66 all of the others. 67 68 Note that the value ``r`` in the algorithm itself is a public value and can be 69 considered as a kind of a commitment ("I'm going to sign this value") by the 70 dirty coin. Actual *secret* is the signature which needs to be disclosed 71 during the reveal-part of the refresh operation. 72 73 A variant of this algorithm that is suitable for retrieving a batch of ``n`` 74 fresh coins from a dirty coin is as follows: 75 76 .. sourcecode:: python 77 78 # Notation: 79 # r = random dees, cs = dirty coin's secret, Cp = dirty coin's public key 80 # pkD[] = array of denomination public keys, 81 # meta = additional information, f.e. the index in a cut-and-choose 82 def RefreshDeriveBatch(r, cs, Cp, pkDs: list[denomPublicKey], meta): 83 t = Hash1a("Refresh", Cp, r, pkDs, meta) 84 s = SignUnique(cs, t) 85 for i, pkD in enumerate(pkDs): 86 x[i] = Hash1b(s, i) # Note: use one HKDF for all i 87 b[i] = Hash2(s, i) # Note: use one HKDF for all i 88 for i, pkD in enumerate(pkDs): 89 c2_s[i], C2_p[i] = KeyGen(x[i]) 90 m[i] = Blind(C2_p[i], b[i], pkD) 91 return (s, c2_s, C2_p, m) 92 93 Note that the above deriviation will need to be done ``κ`` times with 94 ``κ - 1`` of the signatures ``s`` being checked by the exchange as part of 95 the reveal state of the cut-and-choose protocol. Again, each of the ``κ`` 96 values ``r`` is a public value and can be considered as a kind of a commitment 97 ("I'm going to sign this value") by the dirty coin. The actual *secrets* are 98 the ``κ`` signatures ``s`` which need to be disclosed during the 99 reveal-part of the refresh operation. 100 101 102 Protocol Modifications 103 ^^^^^^^^^^^^^^^^^^^^^^ 104 105 Here is a short description of the main steps, with only one fresh coin being 106 requested. We will provide further details, once the related paper [1]_ is 107 published. 108 109 1. **Melting/Commit Phase**: 110 111 - Client chooses a master (public) seed ``r`` and derives ``κ`` nonces ``r_1, ... r_κ``. 112 - Client generates, using ``RefreshDeriveBatch``, ``κ*n`` blinded coin planchets 113 ``m[1][1],...,m[1][n],...,m[κ][1],...,m[κ][n]`` from the nonces 114 - Sends dirty coin public key ``Cp``, seed ``r``, all ``m[i][j]`` and 115 fresh coin denomination selections ``pkD[1],...pkD[n]`` to the exchange, 116 with signature ``σ_c`` made with the dirty coins' private key ``cs`` over the request. 117 - Exchange verifies the request. 118 - Exchange calculates ``h_m[i] = H(m[i][1],...,m[i][n])`` for all ``i`` from ``1...κ`` 119 - Exchange calculates ``H_m = H(h_m[1],...,h_m[κ])`` 120 - Exchange calculates ``rc = H(r, pkD[], H_m, meta, <maybe more>)`` 121 - Exchange chooses ``γ`` from ``1...κ`` and signs all ``m[γ][]``, 122 resulting in ``σ[γ][]``. This is done now as the exchange may later 123 have deleted (or lost) its private signing key. 124 - Exchange persists ``rc → (r, γ, pkD[], H_m, h_m[γ], σ[γ][], σ_c)``, 125 deducts the cost for the operation from the old coin balance 126 (in the same database transaction) and returns ``γ`` to the client. 127 128 2. **Reveal Phase**: 129 130 - Client discloses together with ``h_m`` all except the ``γ``-th 131 (secret) signatures ``s[1],...,s[κ]`` from the ``κ`` calls to 132 ``RefreshDeriveBatch``. 133 - Exchange derives ``r_i`` from ``r`` and verifies each signature 134 ``s[i]`` over ``Hash1a("Refresh", C_p, r_i, pkDs)``. 135 - Exchange reconstructs the blinded coins ``m'[i][]`` for ``i != γ``. 136 - Exchange calculates ``h'_m[i] = H(m'[i][])`` for all ``i != γ``. 137 - Exchange calculates ``H'_m = H(h'_m[1],...,h_m[γ],...h'_m[κ])``. 138 - Exchange verifies ``rc == H(r, pkD[], H'_m, ...)`` equality. 139 - Exchange returns ``σ[γ][]`` on success. 140 141 It is worth noting that, in contrast to the existing refresh protocol, the 142 client sends all ``n*κ`` tuples ``m[][]`` already in the commitment phase. This is 143 necessary such that the exchange can sign the request with a valid denomination 144 key *at the moment of melting*. This ensures idempotency of the melting/commit 145 request and that caries over to the reveal phase. 146 147 Also note, as described above, the master seed ``r`` for the refresh operation 148 is a **public** value and can be considered a commitment ("I'm going to sign 149 this value") made by the dirty coin. The actual *secrets* are the signatures 150 which are reveal in the second phase. 151 152 Note that for the Linking protocol, given the dirty coin's public key, the 153 Exchange simply returns the master seed ``r`` and the dirty coins' signature 154 ``σ_c`` over the original refresh request. The owner of the private key of 155 the dirty coin can then replay the refresh protocol and can be sure that the 156 master seed was of its own origin. Furthermore, the coin history endpoint 157 must already return this information (so that clients can verify the old coin 158 history about the refresh), thus obsoleting the need for a separate "/link" 159 endpoint. 160 161 162 Database Changes 163 ^^^^^^^^^^^^^^^^ 164 165 Not taking sharding and coinstraints into account, the table layout will look 166 basically like this (names might change): 167 168 .. table:: SQL table layout for refresh 169 :align: left 170 171 ============== ============ ================================================ 172 Field Type Description 173 ============== ============ ================================================ 174 refresh_id BIGINT autoincremented identity of the record 175 rc BYTEA refresh commitment ``h_m``, serving as primary key 176 timestamp INT8 execution date of the refresh 177 amount taler_amount amount with fee of the refresh 178 old_coin_pub BYTEA old coin's public key ``Cp`` 179 old_coin_sig BYTEA old coin's signature over the refresh request 180 old_age_com_h BYTEA old coin's hash of age commitment, if applicable 181 noreveal_index SMALLINT the ``γ`` for cut-and-choose, chosen by the exchange 182 planchets_h BYTEA the hash over *all* blinded coin envelopes ``m[][]`` 183 selected_h BYTEA the hash over only the *selected* blinded envelopes ``m[γ][]`` 184 refresh_seed BYTEA the master seed for the refresh, the ``r`` above 185 blinding_seed BYTEA the master seed for CS nonces 186 cs_r_values BYTEA[] the pairs of R-Values for CS signatures 187 cs_r_choices INT8 the bitvector representing the chosen public R-Values 188 denom_serials INT8[] the row ID's of the denominations in the DB 189 denom_sigs BYTEA[] the (blinded) denom signatures ``σ[γ][]`` 190 ============== ============ ================================================ 191 192 193 API endpoints 194 ^^^^^^^^^^^^^^ 195 196 A new ``/melt`` request takes a `NewMeltRequest` as request body, see below. 197 As in the existing melting/commit phase, it updates the old coin balance and 198 chooses a random ``γ`` for the cut-and-choose protocol. Taler uses a global 199 parameter ``κ`` for the cut-and-choose component of the protocol, for which 200 this request is the commitment. Thus, various arguments are given ``κ``-times 201 in this step. At present ``κ`` is always 3. 202 203 :http:statuscode:`200 OK`: 204 The request was successful. The response body is `MeltResponse` in this case. 205 :http:statuscode:`403 Forbidden`: 206 One of the signatures (by the old coin or the denomination signature over 207 the old coin) is invalid. 208 :http:statuscode:`404 Not found`: 209 The exchange does not recognize the denomination key as belonging to the exchange, 210 or it is past the legal expiration time (and thus forgotten entirely). 211 If the denomination key is unknown, the response will be 212 a `DenominationUnknownMessage`. 213 :http:statuscode:`409 Conflict`: 214 The operation is not allowed as the coin has insufficient 215 residual value, or because the same public key of the coin has been 216 previously used with a different denomination. Which case it is 217 can be decided by looking at the error code 218 (``TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS`` or 219 ``TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY``). 220 The response is `MeltForbiddenResponse` in both cases. 221 :http:statuscode:`410 Gone`: 222 The requested denomination key is not yet or no longer valid. 223 It either before the validity start, past the expiration or was revoked. 224 The response is a `DenominationGoneMessage`. 225 Clients must evaluate the error code provided to understand which of the 226 cases this is and handle it accordingly. 227 228 229 Wire Formats 230 ^^^^^^^^^^^^ 231 232 Modified melt request structure: 233 234 .. ts:def:: NewMeltRequest 235 236 interface NewMeltRequest { 237 // The old coin's public key 238 old_coin_pub: CoinPublicKey; 239 240 // Hash of the denomination public key of the old coin, to determine total coin value. 241 old_denom_pub_h: HashCode; 242 243 // The hash of the age-commitment for the old coin. Only present 244 // if the denomination has support for age restriction. 245 old_age_commitment_h?: AgeCommitmentHash; 246 247 // Signature over the old `coin public key <eddsa-coin-pub>` by the denomination. 248 old_denom_sig: DenominationSignature; 249 250 // Amount of the value of the old coin that should be melted as part of 251 // this refresh operation, including melting fee. 252 value_with_fee: Amount; 253 254 // Array of ``n`` new hash codes of denomination public keys 255 // for the new coins to order. 256 denoms_h: HashCode[]; 257 258 // Seed from which the nonces for the ``n*kappa`` coin candidates are derived 259 // from. 260 refresh_seed: HashCode; 261 262 // Master seed for the Clause-Schnorr R-value 263 // creation. Must match the /blinding-prepare request. 264 // Must not have been used in any prior melt request. 265 // Must be present if and only if one of the fresh coin's 266 // denominations is of type Clause-Schnorr. 267 blinding_seed?: BlindingMasterSeed; 268 269 // kappa arrays of ``n`` entries for blinded coin candidates, 270 // each matching the respective entries in ``denoms_h``. 271 // 272 // Note: These are essentially the m_i values in the RefreshDeriveBatch 273 // function. 274 coin_evs: CoinEnvelope[kappa][]; 275 276 // Signature by the old `coin <coin-priv>` over `TALER_RefreshMeltCoinAffirmationPS`. 277 confirm_sig: CoinSignature; 278 279 } 280 281 282 TODO: definition of ``CoinSignature`` 283 284 .. ts:def:: CoinSignature 285 286 // TODO: this needs to be fully expanded into a new interface 287 type CoinSignature = string; 288 289 290 TODO: explain /reveal-melt endpoint. 291 292 .. ts:def:: NewMeltRevealRequest 293 294 interface NewMeltRevealRequest { 295 // The refresh commitment corresponding to the previous call to /melt 296 // This is the Hash over: 297 // 1. refresh_seed 298 // 2. hash of all pairs of R-values, if applicable, skip otherwise 299 // 3. denominations in order 300 // 4. amount_with_fee 301 // 5. kappa*n blinded planchet hashes (which include denomination information), 302 // depths first: [0..n)[0..n)[0..n) 303 rc: RefreshCommitmentHash; 304 305 // The disclosed kappaκ-1 signatures by the old coin's private key, 306 // over Hash1a("Refresh", Cp, r, i), where Cp is the melted coin's public key, 307 // r is the public refresh nonce from the metling step and i runs over the 308 // _disclosed_ kappaκ-1 indices. 309 signatures: CoinSignature[kappa-1]; 310 311 // IFF the denomination of the old coin had support for age restriction, 312 // the client MUST provide the original age commitment, i. e. the 313 // vector of public keys, or omitted otherwise. 314 // The size of the vector MUST be the number of age groups as defined by the 315 // Exchange in the field ``.age_groups`` of the extension ``age_restriction``. 316 age_commitment?: Edx25519PublicKey[]; 317 318 // NOTE: THIS FIELD IS WORK-IN-PROGRESS 319 // The old coin signs H(rc, noreveal_index). This value MUST be stored by the 320 // exchange and provided as part of the coin's history. That way, the wallet 321 // can be sure that the exchange hasn't altered the nonreveal_index when the 322 // wallet does an idempotent melt request. 323 noreveal_sig: CoinSignature; 324 } 325 326 Security Analysis 327 ================= 328 329 TODO 330 331 Drawbacks 332 ========= 333 334 TODO 335 336 Migration Strategy 337 ================== 338 339 TODO 340 341 Discussion/Q&A 342 ============== 343 344 TODO 345 346 347 References 348 ========== 349 .. [1] Work by Jonathan Levin et al., TU Eindhoven. Reference be added here once published