gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: wallet-core: fix tipping with


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet-core: fix tipping with age restricted denoms
Date: Mon, 19 Sep 2022 17:08:10 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new f63765b9f wallet-core: fix tipping with age restricted denoms
f63765b9f is described below

commit f63765b9f7a089eb0f2a62d53f5ad1d56961fa1f
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Sep 19 17:08:04 2022 +0200

    wallet-core: fix tipping with age restricted denoms
---
 packages/taler-util/src/talerCrypto.ts             | 55 +++++++++++++-
 packages/taler-wallet-cli/src/harness/harness.ts   |  3 +-
 .../test-age-restrictions-merchant.ts              | 85 +++++++++++++++++++---
 .../src/integrationtests/test-tipping.ts           |  4 +-
 .../src/crypto/cryptoImplementation.ts             | 12 ++-
 .../taler-wallet-core/src/crypto/cryptoTypes.ts    |  1 +
 packages/taler-wallet-core/src/operations/tip.ts   |  1 +
 7 files changed, 144 insertions(+), 17 deletions(-)

diff --git a/packages/taler-util/src/talerCrypto.ts 
b/packages/taler-util/src/talerCrypto.ts
index c9eeb0584..28fdab8e3 100644
--- a/packages/taler-util/src/talerCrypto.ts
+++ b/packages/taler-util/src/talerCrypto.ts
@@ -724,6 +724,8 @@ export interface FreshCoin {
   coinPub: Uint8Array;
   coinPriv: Uint8Array;
   bks: Uint8Array;
+  maxAge: number;
+  ageCommitmentProof: AgeCommitmentProof | undefined;
 }
 
 export function bufferForUint32(n: number): Uint8Array {
@@ -742,10 +744,11 @@ export function bufferForUint8(n: number): Uint8Array {
   return buf;
 }
 
-export function setupTipPlanchet(
+export async function setupTipPlanchet(
   secretSeed: Uint8Array,
+  denomPub: DenominationPubKey,
   coinNumber: number,
-): FreshCoin {
+): Promise<FreshCoin> {
   const info = stringToBytes("taler-tip-coin-derivation");
   const saltArrBuf = new ArrayBuffer(4);
   const salt = new Uint8Array(saltArrBuf);
@@ -754,10 +757,20 @@ export function setupTipPlanchet(
   const out = kdf(64, secretSeed, salt, info);
   const coinPriv = out.slice(0, 32);
   const bks = out.slice(32, 64);
+  let maybeAcp: AgeCommitmentProof | undefined;
+  if (denomPub.age_mask != 0) {
+    maybeAcp = await AgeRestriction.restrictionCommitSeeded(
+      denomPub.age_mask,
+      AgeRestriction.AGE_UNRESTRICTED,
+      secretSeed,
+    );
+  }
   return {
     bks,
     coinPriv,
     coinPub: eddsaGetPublic(coinPriv),
+    maxAge: AgeRestriction.AGE_UNRESTRICTED,
+    ageCommitmentProof: maybeAcp,
   };
 }
 /**
@@ -1062,6 +1075,44 @@ export namespace AgeRestriction {
     };
   }
 
+  export async function restrictionCommitSeeded(
+    ageMask: number,
+    age: number,
+    seed: Uint8Array,
+  ): Promise<AgeCommitmentProof> {
+    invariant((ageMask & 1) === 1);
+    const numPubs = countAgeGroups(ageMask) - 1;
+    const numPrivs = getAgeGroupIndex(ageMask, age);
+
+    const pubs: Edx25519PublicKey[] = [];
+    const privs: Edx25519PrivateKey[] = [];
+
+    for (let i = 0; i < numPubs; i++) {
+      const privSeed = await kdfKw({
+        outputLength: 32,
+        ikm: seed,
+        info: stringToBytes("age-restriction-commit"),
+        salt: bufferForUint32(i),
+      });
+      const priv = await Edx25519.keyCreateFromSeed(privSeed);
+      const pub = await Edx25519.getPublic(priv);
+      pubs.push(pub);
+      if (i < numPrivs) {
+        privs.push(priv);
+      }
+    }
+
+    return {
+      commitment: {
+        mask: ageMask,
+        publicKeys: pubs.map((x) => encodeCrock(x)),
+      },
+      proof: {
+        privateKeys: privs.map((x) => encodeCrock(x)),
+      },
+    };
+  }
+
   /**
    * Check that c1 = c2*salt
    */
diff --git a/packages/taler-wallet-cli/src/harness/harness.ts 
b/packages/taler-wallet-cli/src/harness/harness.ts
index ca0ea1f2f..137027964 100644
--- a/packages/taler-wallet-cli/src/harness/harness.ts
+++ b/packages/taler-wallet-cli/src/harness/harness.ts
@@ -1991,8 +1991,7 @@ export function getRandomIban(salt: string | null = 
null): string {
   return `DE${check_digits}${bban}`;
 }
 
-// Only used in one tipping test.
-export function getWireMethod(): string {
+export function getWireMethodForTest(): string {
   if (useLibeufinBank) return "iban";
   return "x-taler-bank";
 }
diff --git 
a/packages/taler-wallet-cli/src/integrationtests/test-age-restrictions-merchant.ts
 
b/packages/taler-wallet-cli/src/integrationtests/test-age-restrictions-merchant.ts
index 01ddac4d9..ff589dd79 100644
--- 
a/packages/taler-wallet-cli/src/integrationtests/test-age-restrictions-merchant.ts
+++ 
b/packages/taler-wallet-cli/src/integrationtests/test-age-restrictions-merchant.ts
@@ -17,8 +17,14 @@
 /**
  * Imports.
  */
+import { BankApi, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
 import { defaultCoinConfig } from "../harness/denomStructures.js";
-import { GlobalTestState, WalletCli } from "../harness/harness.js";
+import {
+  getWireMethodForTest,
+  GlobalTestState,
+  MerchantPrivateApi,
+  WalletCli,
+} from "../harness/harness.js";
 import {
   createSimpleTestkudosEnvironment,
   withdrawViaBank,
@@ -31,14 +37,19 @@ import {
 export async function runAgeRestrictionsMerchantTest(t: GlobalTestState) {
   // Set up test environment
 
-  const { wallet: walletOne, bank, exchange, merchant } =
-    await createSimpleTestkudosEnvironment(
-      t,
-      defaultCoinConfig.map((x) => x("TESTKUDOS")),
-      {
-        ageMaskSpec: "8:10:12:14:16:18:21",
-      },
-    );
+  const {
+    wallet: walletOne,
+    bank,
+    exchange,
+    merchant,
+    exchangeBankAccount,
+  } = await createSimpleTestkudosEnvironment(
+    t,
+    defaultCoinConfig.map((x) => x("TESTKUDOS")),
+    {
+      ageMaskSpec: "8:10:12:14:16:18:21",
+    },
+  );
 
   const walletTwo = new WalletCli(t, "walletTwo");
   const walletThree = new WalletCli(t, "walletThree");
@@ -129,6 +140,62 @@ export async function runAgeRestrictionsMerchantTest(t: 
GlobalTestState) {
     await wallet.runUntilDone();
   }
 
+  // Pay with coin from tipping
+  {
+    const mbu = await BankApi.createRandomBankUser(bank);
+    const tipReserveResp = await MerchantPrivateApi.createTippingReserve(
+      merchant,
+      "default",
+      {
+        exchange_url: exchange.baseUrl,
+        initial_balance: "TESTKUDOS:10",
+        wire_method: getWireMethodForTest(),
+      },
+    );
+
+    t.assertDeepEqual(
+      tipReserveResp.payto_uri,
+      exchangeBankAccount.accountPaytoUri,
+    );
+
+    await BankApi.adminAddIncoming(bank, {
+      amount: "TESTKUDOS:10",
+      debitAccountPayto: mbu.accountPaytoUri,
+      exchangeBankAccount,
+      reservePub: tipReserveResp.reserve_pub,
+    });
+
+    await exchange.runWirewatchOnce();
+
+    const tip = await MerchantPrivateApi.giveTip(merchant, "default", {
+      amount: "TESTKUDOS:5",
+      justification: "why not?",
+      next_url: "https://example.com/after-tip";,
+    });
+
+    const walletTipping = new WalletCli(t, "age-tipping");
+
+    const ptr = await walletTipping.client.call(WalletApiOperation.PrepareTip, 
{
+      talerTipUri: tip.taler_tip_uri,
+    });
+
+    await walletTipping.client.call(WalletApiOperation.AcceptTip, {
+      walletTipId: ptr.walletTipId,
+    });
+
+    await walletTipping.runUntilDone();
+
+    const order = {
+      summary: "Buy me!",
+      amount: "TESTKUDOS:4",
+      fulfillment_url: "taler://fulfillment-success/thx",
+      minimum_age: 9,
+    };
+
+    await makeTestPayment(t, { wallet: walletTipping, merchant, order });
+    await walletTipping.runUntilDone();
+  }
 }
 
 runAgeRestrictionsMerchantTest.suites = ["wallet"];
+runAgeRestrictionsMerchantTest.timeoutMs = 120 * 1000;
diff --git a/packages/taler-wallet-cli/src/integrationtests/test-tipping.ts 
b/packages/taler-wallet-cli/src/integrationtests/test-tipping.ts
index f04293ed8..d31e0c06b 100644
--- a/packages/taler-wallet-cli/src/integrationtests/test-tipping.ts
+++ b/packages/taler-wallet-cli/src/integrationtests/test-tipping.ts
@@ -21,7 +21,7 @@ import { WalletApiOperation, BankApi } from 
"@gnu-taler/taler-wallet-core";
 import {
   GlobalTestState,
   MerchantPrivateApi,
-  getWireMethod,
+  getWireMethodForTest,
 } from "../harness/harness.js";
 import { createSimpleTestkudosEnvironment } from "../harness/helpers.js";
 
@@ -42,7 +42,7 @@ export async function runTippingTest(t: GlobalTestState) {
     {
       exchange_url: exchange.baseUrl,
       initial_balance: "TESTKUDOS:10",
-      wire_method: getWireMethod(),
+      wire_method: getWireMethodForTest(),
     },
   );
 
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts 
b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
index c21ee99e8..bfc48d961 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts
@@ -743,9 +743,16 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
     if (req.denomPub.cipher !== DenomKeyType.Rsa) {
       throw Error(`unsupported cipher (${req.denomPub.cipher})`);
     }
-    const fc = setupTipPlanchet(decodeCrock(req.secretSeed), 
req.planchetIndex);
+    const fc = await setupTipPlanchet(
+      decodeCrock(req.secretSeed),
+      req.denomPub,
+      req.planchetIndex,
+    );
+    const maybeAch = fc.ageCommitmentProof
+      ? AgeRestriction.hashCommitment(fc.ageCommitmentProof.commitment)
+      : undefined;
     const denomPub = decodeCrock(req.denomPub.rsa_public_key);
-    const coinPubHash = hash(fc.coinPub);
+    const coinPubHash = hashCoinPub(encodeCrock(fc.coinPub), maybeAch);
     const blindResp = await tci.rsaBlind(tci, {
       bks: encodeCrock(fc.bks),
       hm: encodeCrock(coinPubHash),
@@ -763,6 +770,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = {
       ),
       coinPriv: encodeCrock(fc.coinPriv),
       coinPub: encodeCrock(fc.coinPub),
+      ageCommitmentProof: fc.ageCommitmentProof,
     };
     return tipPlanchet;
   },
diff --git a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts 
b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
index 4c75aa91e..0858cffa9 100644
--- a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
+++ b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts
@@ -122,6 +122,7 @@ export interface DerivedTipPlanchet {
   coinEvHash: string;
   coinPriv: string;
   coinPub: string;
+  ageCommitmentProof: AgeCommitmentProof | undefined;
 }
 
 export interface SignTrackTransactionRequest {
diff --git a/packages/taler-wallet-core/src/operations/tip.ts 
b/packages/taler-wallet-core/src/operations/tip.ts
index 571721658..a0fd8d328 100644
--- a/packages/taler-wallet-core/src/operations/tip.ts
+++ b/packages/taler-wallet-core/src/operations/tip.ts
@@ -319,6 +319,7 @@ export async function processTip(
       status: CoinStatus.Fresh,
       coinEvHash: planchet.coinEvHash,
       maxAge: AgeRestriction.AGE_UNRESTRICTED,
+      ageCommitmentProof: planchet.ageCommitmentProof,
     });
   }
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]