aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-util
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2022-09-19 17:08:04 +0200
committerFlorian Dold <florian@dold.me>2022-09-19 17:08:04 +0200
commitf63765b9f7a089eb0f2a62d53f5ad1d56961fa1f (patch)
tree07bfe90b5ca4cd8a75f49e54d0d6b6cfddba5874 /packages/taler-util
parentffe6a9521400ceabca713c08010532ece03152a8 (diff)
wallet-core: fix tipping with age restricted denoms
Diffstat (limited to 'packages/taler-util')
-rw-r--r--packages/taler-util/src/talerCrypto.ts55
1 files changed, 53 insertions, 2 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
*/