diff options
author | Florian Dold <florian@dold.me> | 2022-08-23 11:29:45 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2022-08-23 20:35:11 +0200 |
commit | f3ff5a72257dda27cab555f8b8d921d45bfc3e4b (patch) | |
tree | 708494a3aa2346fead51931fe4bfc41cc0249659 /packages/taler-wallet-core/src/crypto | |
parent | 4ca38113abee2c0ca17b26aa55cf6a0ecafe49c9 (diff) | |
download | wallet-core-f3ff5a72257dda27cab555f8b8d921d45bfc3e4b.tar.xz |
peer-to-peer pull payments MVP
p2p pull wip
Diffstat (limited to 'packages/taler-wallet-core/src/crypto')
-rw-r--r-- | packages/taler-wallet-core/src/crypto/cryptoImplementation.ts | 140 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/crypto/cryptoTypes.ts | 66 |
2 files changed, 203 insertions, 3 deletions
diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts index 099bf09fe..2f39f7806 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -33,11 +33,11 @@ import { BlindedDenominationSignature, bufferForUint32, buildSigPS, - bytesToString, CoinDepositPermission, CoinEnvelope, createHashContext, decodeCrock, + decryptContractForDeposit, decryptContractForMerge, DenomKeyType, DepositInfo, @@ -47,6 +47,7 @@ import { eddsaSign, eddsaVerify, encodeCrock, + encryptContractForDeposit, encryptContractForMerge, ExchangeProtocolVersion, getRandomBytes, @@ -85,17 +86,23 @@ import { DenominationRecord } from "../db.js"; import { CreateRecoupRefreshReqRequest, CreateRecoupReqRequest, + DecryptContractForDepositRequest, + DecryptContractForDepositResponse, DecryptContractRequest, DecryptContractResponse, DerivedRefreshSession, DerivedTipPlanchet, DeriveRefreshSessionRequest, DeriveTipRequest, + EncryptContractForDepositRequest, + EncryptContractForDepositResponse, EncryptContractRequest, EncryptContractResponse, EncryptedContract, SignPurseMergeRequest, SignPurseMergeResponse, + SignReservePurseCreateRequest, + SignReservePurseCreateResponse, SignTrackTransactionRequest, } from "./cryptoTypes.js"; @@ -205,7 +212,19 @@ export interface TalerCryptoInterface { req: DecryptContractRequest, ): Promise<DecryptContractResponse>; + encryptContractForDeposit( + req: EncryptContractForDepositRequest, + ): Promise<EncryptContractForDepositResponse>; + + decryptContractForDeposit( + req: DecryptContractForDepositRequest, + ): Promise<DecryptContractForDepositResponse>; + signPurseMerge(req: SignPurseMergeRequest): Promise<SignPurseMergeResponse>; + + signReservePurseCreate( + req: SignReservePurseCreateRequest, + ): Promise<SignReservePurseCreateResponse>; } /** @@ -362,6 +381,21 @@ export const nullCrypto: TalerCryptoInterface = { ): Promise<SignPurseMergeResponse> { throw new Error("Function not implemented."); }, + encryptContractForDeposit: function ( + req: EncryptContractForDepositRequest, + ): Promise<EncryptContractForDepositResponse> { + throw new Error("Function not implemented."); + }, + decryptContractForDeposit: function ( + req: DecryptContractForDepositRequest, + ): Promise<DecryptContractForDepositResponse> { + throw new Error("Function not implemented."); + }, + signReservePurseCreate: function ( + req: SignReservePurseCreateRequest, + ): Promise<SignReservePurseCreateResponse> { + throw new Error("Function not implemented."); + }, }; export type WithArg<X> = X extends (req: infer T) => infer R @@ -1047,7 +1081,8 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { if (depositInfo.requiredMinimumAge != null) { s.minimum_age_sig = minimumAgeSig; - s.age_commitment = depositInfo.ageCommitmentProof?.commitment.publicKeys; + s.age_commitment = + depositInfo.ageCommitmentProof?.commitment.publicKeys; } else if (depositInfo.ageCommitmentProof) { (s as any).h_age_commitment = hAgeCommitment; } @@ -1389,6 +1424,43 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { mergePriv: encodeCrock(res.mergePriv), }; }, + async encryptContractForDeposit( + tci: TalerCryptoInterfaceR, + req: EncryptContractForDepositRequest, + ): Promise<EncryptContractForDepositResponse> { + const contractKeyPair = await this.createEddsaKeypair(tci, {}); + const enc = await encryptContractForDeposit( + decodeCrock(req.pursePub), + decodeCrock(contractKeyPair.priv), + 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 decryptContractForDeposit( + tci: TalerCryptoInterfaceR, + req: DecryptContractForDepositRequest, + ): Promise<DecryptContractForDepositResponse> { + const res = await decryptContractForDeposit( + decodeCrock(req.ciphertext), + decodeCrock(req.pursePub), + decodeCrock(req.contractPriv), + ); + return { + contractTerms: res.contractTerms, + }; + }, async signPurseMerge( tci: TalerCryptoInterfaceR, req: SignPurseMergeRequest, @@ -1431,6 +1503,70 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { accountSig: reserveSigResp.sig, }; }, + async signReservePurseCreate( + tci: TalerCryptoInterfaceR, + req: SignReservePurseCreateRequest, + ): Promise<SignReservePurseCreateResponse> { + 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, + }); + + logger.info(`payto URI: ${req.reservePayto}`); + logger.info( + `signing WALLET_PURSE_MERGE over ${encodeCrock(mergeSigBlob)}`, + ); + + 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, + }); + + const mergePub = encodeCrock(eddsaGetPublic(decodeCrock(req.mergePriv))); + + const purseSigBlob = buildSigPS(TalerSignaturePurpose.WALLET_PURSE_CREATE) + .put(timestampRoundedToBuffer(req.purseExpiration)) + .put(amountToBuffer(Amounts.parseOrThrow(req.purseAmount))) + .put(decodeCrock(req.contractTermsHash)) + .put(decodeCrock(mergePub)) + // FIXME: add age! + .put(bufferForUint32(0)) + .build(); + + const purseSigResp = await tci.eddsaSign(tci, { + msg: encodeCrock(purseSigBlob), + priv: req.pursePriv, + }); + + return { + mergeSig: mergeSigResp.sig, + accountSig: reserveSigResp.sig, + purseSig: purseSigResp.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 6f4a5fa95..6e0e01627 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoTypes.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoTypes.ts @@ -187,6 +187,19 @@ export interface EncryptContractResponse { contractPriv: string; } +export interface EncryptContractForDepositRequest { + contractTerms: any; + + pursePub: string; + pursePriv: string; +} + +export interface EncryptContractForDepositResponse { + econtract: EncryptedContract; + + contractPriv: string; +} + export interface DecryptContractRequest { ciphertext: string; pursePub: string; @@ -198,6 +211,16 @@ export interface DecryptContractResponse { mergePriv: string; } +export interface DecryptContractForDepositRequest { + ciphertext: string; + pursePub: string; + contractPriv: string; +} + +export interface DecryptContractForDepositResponse { + contractTerms: any; +} + export interface SignPurseMergeRequest { mergeTimestamp: TalerProtocolTimestamp; @@ -227,6 +250,47 @@ export interface SignPurseMergeResponse { * Signature made by the purse's merge private key. */ mergeSig: string; - + + accountSig: string; +} + +export interface SignReservePurseCreateRequest { + mergeTimestamp: TalerProtocolTimestamp; + + pursePub: string; + + pursePriv: string; + + reservePayto: string; + + reservePriv: string; + + mergePriv: string; + + purseExpiration: TalerProtocolTimestamp; + + purseAmount: AmountString; + purseFee: AmountString; + + contractTermsHash: string; + + /** + * Flags. + */ + flags: WalletAccountMergeFlags; +} + +/** + * Response with signatures needed for creation of a purse + * from a reserve for a PULL payment. + */ +export interface SignReservePurseCreateResponse { + /** + * Signature made by the purse's merge private key. + */ + mergeSig: string; + accountSig: string; + + purseSig: string; } |