From 43d265dde5f76d64e210a6c37c63c89d287adb32 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Wed, 25 May 2022 13:52:39 +0200 Subject: wallet-core: age restriction benchmarking --- packages/taler-util/src/talerCrypto.ts | 47 +++++++++++++++++++--- packages/taler-wallet-cli/src/index.ts | 73 ++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 5 deletions(-) diff --git a/packages/taler-util/src/talerCrypto.ts b/packages/taler-util/src/talerCrypto.ts index e27e329a9..ebbfccda5 100644 --- a/packages/taler-util/src/talerCrypto.ts +++ b/packages/taler-util/src/talerCrypto.ts @@ -679,7 +679,8 @@ export function hashDenomPub(pub: DenominationPubKey): Uint8Array { return nacl.hash(uint8ArrayBuf); } else { throw Error( - `unsupported cipher (${(pub as DenominationPubKey).cipher + `unsupported cipher (${ + (pub as DenominationPubKey).cipher }), unable to hash`, ); } @@ -783,7 +784,7 @@ export enum TalerSignaturePurpose { export class SignaturePurposeBuilder { private chunks: Uint8Array[] = []; - constructor(private purposeNum: number) { } + constructor(private purposeNum: number) {} put(bytes: Uint8Array): SignaturePurposeBuilder { this.chunks.push(Uint8Array.from(bytes)); @@ -1031,6 +1032,27 @@ export namespace AgeRestriction { }; } + /** + * Check that c1 = c2*salt + */ + export async function commitCompare( + c1: AgeCommitment, + c2: AgeCommitment, + salt: OpaqueData, + ): Promise { + if (c1.publicKeys.length != c2.publicKeys.length) { + return false; + } + for (let i = 0; i < c1.publicKeys.length; i++) { + const k1 = c1.publicKeys[i]; + const k2 = await Edx25519.publicKeyDerive(c2.publicKeys[i], salt); + if (k1 != k2) { + return false; + } + } + return true; + } + export async function commitmentDerive( commitmentProof: AgeCommitmentProof, salt: OpaqueData, @@ -1081,9 +1103,24 @@ export namespace AgeRestriction { } export function commitmentVerify( - commitmentProof: AgeCommitmentProof, + commitment: AgeCommitment, + sig: string, age: number, - ): Edx25519Signature { - throw Error("not implemented"); + ): boolean { + const d = buildSigPS(TalerSignaturePurpose.WALLET_AGE_ATTESTATION) + .put(bufferForUint32(commitment.mask)) + .put(bufferForUint32(age)) + .build(); + const group = getAgeGroupIndex(commitment.mask, age); + if (group === 0) { + // No attestation required. + return true; + } + const pub = commitment.publicKeys[group - 1]; + return nacl.crypto_edx25519_sign_detached_verify( + d, + decodeCrock(sig), + decodeCrock(pub), + ); } } diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts index 43bed3cc1..339533dfc 100644 --- a/packages/taler-wallet-cli/src/index.ts +++ b/packages/taler-wallet-cli/src/index.ts @@ -46,6 +46,9 @@ import { LogLevel, setGlobalLogLevelFromString, parsePaytoUri, + AgeRestriction, + getRandomBytes, + encodeCrock, } from "@gnu-taler/taler-util"; import { NodeHttpLib, @@ -59,6 +62,7 @@ import { CryptoDispatcher, SynchronousCryptoWorkerFactory, nativeCrypto, + performanceNow, } from "@gnu-taler/taler-wallet-core"; import { lintExchangeDeployment } from "./lint.js"; import { runBench1 } from "./bench1.js"; @@ -1077,6 +1081,75 @@ const testCli = walletCli.subcommand("testingArgs", "testing", { help: "Subcommands for testing.", }); +testCli + .subcommand("withdrawTestkudos", "withdraw-testkudos") + .action(async (args) => { + await withWallet(args, async (wallet) => { + wallet.client.call(WalletApiOperation.WithdrawTestkudos, {}); + }); + }); + +testCli + .subcommand("benchmarkAgeRestrictions", "benchmark-age-restrictions") + .action(async (args) => { + const numReps = 100; + let tCommit: bigint = BigInt(0); + let tAttest: bigint = BigInt(0); + let tVerify: bigint = BigInt(0); + let tDerive: bigint = BigInt(0); + let tCompare: bigint = BigInt(0); + let start: bigint; + + console.log("starting benchmark"); + + for (let i = 0; i < numReps; i++) { + console.log(`doing iteration ${i}`); + start = process.hrtime.bigint(); + const commitProof = await AgeRestriction.restrictionCommit( + 0b1000001010101010101001, + 21, + ); + tCommit = tCommit + process.hrtime.bigint() - start; + + start = process.hrtime.bigint(); + const attest = AgeRestriction.commitmentAttest(commitProof, 18); + tAttest = tAttest + process.hrtime.bigint() - start; + + start = process.hrtime.bigint(); + const attestRes = AgeRestriction.commitmentVerify( + commitProof.commitment, + attest, + 18, + ); + tVerify = tVerify + process.hrtime.bigint() - start; + if (!attestRes) { + throw Error(); + } + + const salt = encodeCrock(getRandomBytes(32)); + start = process.hrtime.bigint(); + const deriv = await AgeRestriction.commitmentDerive(commitProof, salt); + tDerive = tDerive + process.hrtime.bigint() - start; + + start = process.hrtime.bigint(); + const res2 = await AgeRestriction.commitCompare( + deriv.commitment, + commitProof.commitment, + salt, + ); + tCompare = tCompare + process.hrtime.bigint() - start; + if (!res2) { + throw Error(); + } + } + + console.log(`edx25519-commit (ns): ${tCommit / BigInt(numReps)}`); + console.log(`edx25519-attest (ns): ${tAttest / BigInt(numReps)}`); + console.log(`edx25519-verify (ns): ${tVerify / BigInt(numReps)}`); + console.log(`edx25519-derive (ns): ${tDerive / BigInt(numReps)}`); + console.log(`edx25519-compare (ns): ${tCompare / BigInt(numReps)}`); + }); + testCli.subcommand("logtest", "logtest").action(async (args) => { logger.trace("This is a trace message."); logger.info("This is an info message."); -- cgit v1.2.3