diff options
Diffstat (limited to 'packages/taler-wallet-core/src/crypto')
-rw-r--r-- | packages/taler-wallet-core/src/crypto/cryptoImplementation.ts | 132 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/crypto/cryptoTypes.ts | 83 |
2 files changed, 210 insertions, 5 deletions
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts index 1d3641836..c177a51dd 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -33,10 +33,12 @@ import { BlindedDenominationSignature, bufferForUint32, buildSigPS, + bytesToString, CoinDepositPermission, CoinEnvelope, createHashContext, decodeCrock, + decryptContractForMerge, DenomKeyType, DepositInfo, ecdheGetPublic, @@ -45,6 +47,7 @@ import { eddsaSign, eddsaVerify, encodeCrock, + encryptContractForMerge, ExchangeProtocolVersion, getRandomBytes, hash, @@ -81,10 +84,17 @@ import { DenominationRecord, WireFee } from "../db.js"; import { CreateRecoupRefreshReqRequest, CreateRecoupReqRequest, + DecryptContractRequest, + DecryptContractResponse, DerivedRefreshSession, DerivedTipPlanchet, DeriveRefreshSessionRequest, DeriveTipRequest, + EncryptContractRequest, + EncryptContractResponse, + EncryptedContract, + SignPurseMergeRequest, + SignPurseMergeResponse, SignTrackTransactionRequest, } from "./cryptoTypes.js"; @@ -185,6 +195,16 @@ export interface TalerCryptoInterface { signPurseDeposits( req: SignPurseDepositsRequest, ): Promise<SignPurseDepositsResponse>; + + encryptContractForMerge( + req: EncryptContractRequest, + ): Promise<EncryptContractResponse>; + + decryptContractForMerge( + req: DecryptContractRequest, + ): Promise<DecryptContractResponse>; + + signPurseMerge(req: SignPurseMergeRequest): Promise<SignPurseMergeResponse>; } /** @@ -326,6 +346,21 @@ export const nullCrypto: TalerCryptoInterface = { ): Promise<SignPurseDepositsResponse> { throw new Error("Function not implemented."); }, + encryptContractForMerge: function ( + req: EncryptContractRequest, + ): Promise<EncryptContractResponse> { + throw new Error("Function not implemented."); + }, + decryptContractForMerge: function ( + req: DecryptContractRequest, + ): Promise<DecryptContractResponse> { + throw new Error("Function not implemented."); + }, + signPurseMerge: function ( + req: SignPurseMergeRequest, + ): Promise<SignPurseMergeResponse> { + throw new Error("Function not implemented."); + }, }; export type WithArg<X> = X extends (req: infer T) => infer R @@ -502,6 +537,9 @@ export interface TransferPubResponse { transferPriv: string; } +/** + * JS-native implementation of the Taler crypto worker operations. + */ export const nativeCryptoR: TalerCryptoInterfaceR = { async eddsaSign( tci: TalerCryptoInterfaceR, @@ -960,9 +998,11 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { maybeAgeCommitmentHash = ach; hAgeCommitment = decodeCrock(ach); if (depositInfo.requiredMinimumAge != null) { - minimumAgeSig = AgeRestriction.commitmentAttest( - depositInfo.ageCommitmentProof, - depositInfo.requiredMinimumAge, + minimumAgeSig = encodeCrock( + AgeRestriction.commitmentAttest( + depositInfo.ageCommitmentProof, + depositInfo.requiredMinimumAge, + ), ); } } else { @@ -1094,7 +1134,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { if (req.meltCoinAgeCommitmentProof) { newAc = await AgeRestriction.commitmentDerive( req.meltCoinAgeCommitmentProof, - transferSecretRes.h, + decodeCrock(transferSecretRes.h), ); newAch = AgeRestriction.hashCommitment(newAc.commitment); } @@ -1280,6 +1320,9 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { for (const c of req.coins) { const sigBlob = buildSigPS(TalerSignaturePurpose.WALLET_PURSE_DEPOSIT) .put(amountToBuffer(Amounts.parseOrThrow(c.contribution))) + .put(decodeCrock(c.denomPubHash)) + // FIXME: use h_age_commitment here + .put(new Uint8Array(32)) .put(decodeCrock(req.pursePub)) .put(hExchangeBaseUrl) .build(); @@ -1300,6 +1343,87 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { deposits, }; }, + async encryptContractForMerge( + tci: TalerCryptoInterfaceR, + req: EncryptContractRequest, + ): Promise<EncryptContractResponse> { + const contractKeyPair = await this.createEddsaKeypair(tci, {}); + const enc = await encryptContractForMerge( + decodeCrock(req.pursePub), + decodeCrock(contractKeyPair.priv), + decodeCrock(req.mergePriv), + req.contractTerms, + ); + const sigBlob = buildSigPS(TalerSignaturePurpose.WALLET_PURSE_ECONTRACT) + .put(hash(enc)) + .put(decodeCrock(contractKeyPair.pub)) + .build(); + const sig = eddsaSign(sigBlob, decodeCrock(req.pursePriv)); + return { + econtract: { + contract_pub: contractKeyPair.pub, + econtract: encodeCrock(enc), + econtract_sig: encodeCrock(sig), + }, + contractPriv: contractKeyPair.priv, + }; + }, + async decryptContractForMerge( + tci: TalerCryptoInterfaceR, + req: DecryptContractRequest, + ): Promise<DecryptContractResponse> { + const res = await decryptContractForMerge( + decodeCrock(req.ciphertext), + decodeCrock(req.pursePub), + decodeCrock(req.contractPriv), + ); + return { + contractTerms: res.contractTerms, + mergePriv: encodeCrock(res.mergePriv), + }; + }, + async signPurseMerge( + tci: TalerCryptoInterfaceR, + req: SignPurseMergeRequest, + ): Promise<SignPurseMergeResponse> { + const mergeSigBlob = buildSigPS(TalerSignaturePurpose.WALLET_PURSE_MERGE) + .put(timestampRoundedToBuffer(req.mergeTimestamp)) + .put(decodeCrock(req.pursePub)) + .put(hashTruncate32(stringToBytes(req.reservePayto + "\0"))) + .build(); + const mergeSigResp = await tci.eddsaSign(tci, { + msg: encodeCrock(mergeSigBlob), + priv: req.mergePriv, + }); + + const reserveSigBlob = buildSigPS( + TalerSignaturePurpose.WALLET_ACCOUNT_MERGE, + ) + .put(timestampRoundedToBuffer(req.purseExpiration)) + .put(amountToBuffer(Amounts.parseOrThrow(req.purseAmount))) + .put(amountToBuffer(Amounts.parseOrThrow(req.purseFee))) + .put(decodeCrock(req.contractTermsHash)) + .put(decodeCrock(req.pursePub)) + .put(timestampRoundedToBuffer(req.mergeTimestamp)) + // FIXME: put in min_age + .put(bufferForUint32(0)) + .put(bufferForUint32(req.flags)) + .build(); + + logger.info( + `signing WALLET_ACCOUNT_MERGE over ${encodeCrock(reserveSigBlob)}`, + ); + + const reserveSigResp = await tci.eddsaSign(tci, { + msg: encodeCrock(reserveSigBlob), + priv: req.reservePriv, + }); + + return { + mergeSig: mergeSigResp.sig, + accountSig: reserveSigResp.sig, + }; + }, }; function amountToBuffer(amount: AmountJson): Uint8Array { diff --git a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts index 52b96b1a5..6f4a5fa95 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts @@ -30,11 +30,16 @@ import { AgeCommitmentProof, AmountJson, + AmountString, CoinEnvelope, DenominationPubKey, + EddsaPublicKeyString, + EddsaSignatureString, ExchangeProtocolVersion, RefreshPlanchetInfo, + TalerProtocolTimestamp, UnblindedSignature, + WalletAccountMergeFlags, } from "@gnu-taler/taler-util"; export interface RefreshNewDenomInfo { @@ -148,4 +153,80 @@ export interface CreateRecoupRefreshReqRequest { denomPub: DenominationPubKey; denomPubHash: string; denomSig: UnblindedSignature; -}
\ No newline at end of file +} + +export interface EncryptedContract { + /** + * Encrypted contract. + */ + econtract: string; + + /** + * Signature over the (encrypted) contract. + */ + econtract_sig: EddsaSignatureString; + + /** + * Ephemeral public key for the DH operation to decrypt the encrypted contract. + */ + contract_pub: EddsaPublicKeyString; +} + +export interface EncryptContractRequest { + contractTerms: any; + + pursePub: string; + pursePriv: string; + + mergePriv: string; +} + +export interface EncryptContractResponse { + econtract: EncryptedContract; + + contractPriv: string; +} + +export interface DecryptContractRequest { + ciphertext: string; + pursePub: string; + contractPriv: string; +} + +export interface DecryptContractResponse { + contractTerms: any; + mergePriv: string; +} + +export interface SignPurseMergeRequest { + mergeTimestamp: TalerProtocolTimestamp; + + pursePub: string; + + reservePayto: string; + + reservePriv: string; + + mergePriv: string; + + purseExpiration: TalerProtocolTimestamp; + + purseAmount: AmountString; + purseFee: AmountString; + + contractTermsHash: string; + + /** + * Flags. + */ + flags: WalletAccountMergeFlags; +} + +export interface SignPurseMergeResponse { + /** + * Signature made by the purse's merge private key. + */ + mergeSig: string; + + accountSig: string; +} |