From f63765b9f7a089eb0f2a62d53f5ad1d56961fa1f Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 19 Sep 2022 17:08:04 +0200 Subject: wallet-core: fix tipping with age restricted denoms --- packages/taler-util/src/talerCrypto.ts | 55 ++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) (limited to 'packages/taler-util') 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 { 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 { + 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 */ -- cgit v1.2.3