(* https://docs.taler.net/core/api-common.html#binary-formats numeric values are in network byte order (big endian) *) (* structs that are 'packed' and do not contain pointers and are thus suitable for hashing or similar operations are distinguished by adding a 'P' at the end of the name. (NEW) Note that this convention does not hold for the GNUnet-structs (yet). structs that are used with a purpose for signatures, additionally get an 'S' at the end of the name. (from https://docs.taler.net/taler-developer-manual.html) *) (* TODO - check that our struct are well packed - it looks like Bin only define packed structs - we don't need to worry about struct having "P" suffix remove them - test them - union: not sure what to do of them not needed or relevant i think - some purpose (`TALER_SIGNATURE_XXX`) are missing - exchange and gana master branch are not in sync and we should use a specific git tag instead - outdated doc(?) - some missing struct documentation - correctly handle endianness *) (* TODO hash and C(ancer)-terminated strings - "A JSON object is canonicalized by converting it to an ASCII byte array with the algorithm specified in RFC 8785. The resulting bytes are terminated with a single 0-byte and then hashed with SHA512." - from the code it looks like its the same for all stringy-strings ! not strings that are raw-bytes-data-like ? only for "HashCode" and "ShortHashCode" *) let int32_size = 4 let int64_size = 8 (* -- Time -- *) (* microseconds since the UNIX Epoch UINT64_MAX represents "never" *) module MK_TIME () = struct type t = { v: int64 } (* not BE (?) *) let bin = let open Bin in record (fun v -> { v }) |+ field neint64 (fun t -> t.v) |> sealr end module MK_TIME_NBO () = struct type t = { v: int64 } let bin = let open Bin in record (fun v -> { v }) |+ field beint64 (fun t -> t.v) |> sealr end module TimeAbsolute = MK_TIME () module TimeAbsoluteNBO = MK_TIME_NBO () module TimeRelative = MK_TIME () module TimeRelativeNBO = MK_TIME_NBO () module Timestamp = MK_TIME () module TimestampNBO = MK_TIME_NBO () (* TODO clean up ? rm all of UTIL ? Bin.map int64 to Ptime.t here *) module UTIL = struct module type Bytes_sig = sig type t = { v: string } val of_octets : string -> t val bin : t Bin.t end (* MK_XX functor for structs like: struct Foo { uint8t thing[XX]; } MK_HASH_XX for hashed value taler doc: - Taler uses 512-bit hash codes (64 bytes). - usually SHA-512 *) module MK_32 () : Bytes_sig = struct type t = { v: string } let of_octets v = match String.length v = 32 with | false -> Fmt.failwith "of_octets failure: data is not 32 bytes" | true -> { v } let bin = let open Bin in record (fun v -> { v }) |+ field (bytes 32) (fun t -> t.v) |> sealr end module MK_64 () : Bytes_sig = struct type t = { v: string } let of_octets v = match String.length v = 64 with | false -> Fmt.failwith "of_octets failure: data is not 64 bytes" | true -> { v } let bin = let open Bin in record (fun v -> { v }) |+ field (bytes 64) (fun t -> t.v) |> sealr end module Bytes_32 = MK_32 () module Bytes_64 = MK_64 () module type H_sig = sig type t val hash : string -> t val bin : t Bin.t end module HHH_64 : H_sig = struct type t = { hash: Digestif.SHA512.t } let hash s = let hash = Digestif.SHA512.(digest_string s) in { hash } let hash_bin = let open Bin in map (bytes 64) Digestif.SHA512.of_raw_string Digestif.SHA512.to_raw_string let bin = let open Bin in record (fun hash -> { hash }) |+ field hash_bin (fun t -> t.hash) |> sealr end (* sha512 with string size check *) module Hash_64 : H_sig = struct include HHH_64 let hash s = match String.length s = 64 with | false -> Fmt.failwith "SHA512 failure: data is not 64 bytes" | true -> hash s end (* sha512 but add a null termination to the given string this is "HashCode" in GNU TALER todo: maybe need to have a cstring.ml *) module Cstring_hash_64 : H_sig = struct include HHH_64 let hash s = let s = s ^ "\x00" in hash s end module MK_HASH_64 () : H_sig = struct include HHH_64 end module HHH_32 : H_sig = struct type t = { hash: Digestif.SHA256.t } let hash s = let hash = Digestif.SHA256.(digest_string s) in { hash } let hash_bin = let open Bin in map (bytes 32) Digestif.SHA256.of_raw_string Digestif.SHA256.to_raw_string let bin = let open Bin in record (fun hash -> { hash }) |+ field hash_bin (fun t -> t.hash) |> sealr end (* sha256 with string size check *) module Hash_32 : H_sig = struct include HHH_32 let hash s = match String.length s = 32 with | false -> Fmt.failwith "SHA256 failure: data is not 32 bytes" | true -> hash s end (* sha256 but add a null termination to the given string this is "HashCode" in GNU TALER todo: maybe need to have a cstring.ml *) module Cstring_hash_32 : H_sig = struct include HHH_32 let hash s = let s = s ^ "\x00" in hash s end module MK_HASH_32 () : H_sig = struct include HHH_32 end module MK_SRC_HASH_64 (M : sig type src val to_octets : src -> string end) : sig type t val bin : t Bin.t val hash : M.src -> t end = struct include Hash_64 let hash src = hash (M.to_octets src) end module MK_SRC_HASH_32 (M : sig type src val to_octets : src -> string end) : sig type t val bin : t Bin.t val hash : M.src -> t end = struct include Hash_32 let hash src = hash (M.to_octets src) end end include UTIL module Taler_signatures = Include.Taler_signatures (* -- Cryptographic primitives -- *) (* GNUNET_CRYPTO format *) module GNUNET_RsaPublicKey = struct (* libgnuutil format: https://docs.gnunet.org/doxygen/d9/dbe/structGNUNET__CRYPTO__RsaPublicKeyHeaderP.html https://docs.gnunet.org/doxygen/d6/d70/group__libgnunetutil.html#ga9c99a81e8cd649c1c925d23211a0738f https://www.gnupg.org/documentation/manuals/gcrypt/MPI-formats.html format: - rsa header - modulus - public_exponent integer in big-endian format (MSB first). Leading zeroes are stripped unless they are required to keep a value positive. *) type t = { n_len: int; e_len: int; n: Z.t; e: Z.t; } let rev_string len s = String.init len (fun i -> s.[len - 1 - i]) (* todo: need to strip leading zeros or something? *) (* reverse bytes because Z.of_bits reads little endian *) let z_of_bits_be src pos len = String.sub src pos len |> rev_string len |> Z.of_bits let of_pub ({ n; e } : Mirage_crypto_pk.Rsa.pub) = { n_len= Z.size n; e_len= Z.size e; n; e } let to_octets { n_len; e_len; n; e } = let len = 4 + n_len + e_len in let b = Bytes.make len '\x00' in Bytes.set_uint16_be b 0 n_len; Bytes.set_uint16_be b 2 e_len; let n = Z.to_bits n |> rev_string n_len in let e = Z.to_bits e |> rev_string e_len in Bytes.blit_string n 0 b 4 n_len; Bytes.blit_string e 0 b (4 + n_len) e_len; Bytes.unsafe_to_string b let of_octets s = let error = Error "GNUNET_RsaPublicKey.of_octets: invalid data" in let len = String.length s in match len >= 4 with | false -> error | true -> ( let n_len = String.get_uint16_be s 0 in let e_len = String.get_uint16_be s 2 in match len = n_len + e_len + 4 with | false -> error | true -> let n = z_of_bits_be s 4 n_len in let e = z_of_bits_be s (4 + n_len) e_len in Ok { n_len; e_len; n; e }) end module DenominationHash = MK_SRC_HASH_32 (struct type src = Mirage_crypto_pk.Rsa.pub let to_octets pub = GNUNET_RsaPublicKey.of_pub pub |> GNUNET_RsaPublicKey.to_octets end) module ExchangePublicKeyP = struct type t = Mirage_crypto_ec.Ed25519.pub let bin = let open Mirage_crypto_ec.Ed25519 in let open Bin in let open Bytes_32 in map bin (fun { v } -> pub_of_octets v |> Result.get_ok) (fun pub -> { v= pub_to_octets pub }) end (* --- Hashes --- *) (* Hash over a full payto://-URI, including receiver-name (and possibly BIC and other optional fields). *) module FullPaytoHash = MK_HASH_32 () (* Hash over a normalized payto://-URI, including all optional fields and also with account-part canonicalized (so no BIC). *) module NormalizedPaytoHash = MK_HASH_32 () module PrivateContractHash = MK_HASH_64 () module ExtensionsPolicyHash = MK_HASH_64 () module MerchantWireHash = MK_HASH_64 () (* TODO missing doc *) module AgeCommitmentHash = MK_HASH_64 () (* Hash over: a) the hash of the denomination's public key, b) an enum value identifying the cipher, and c) cipher-dependant blinded information. See implementation of `TALER_CoinEvHash` in libtalerexchange for details. *) module BlindedCoinHash = MK_HASH_64 () module CoinPubHash = MK_HASH_64 () module OutputCommitmentHash = MK_HASH_64 () (* This is the running SHA512-hash over all `TALER_BlindedCoinHashP` values of an array of coins. Note that each `TALER_BlindedCoinHashP` itself captures the hash of the corresponding denomination's public key. *) module HashPlanchetsP = MK_HASH_64 () (* --- Keys --- *) module PursePublicKey = MK_32 () (* missing doc *) module AuditorPublicKeyP = MK_32 () (* missing doc *) module BlindingMasterSeed = MK_32 () module BlindingMasterSecret = MK_32 () module ReservePublicKeyP = MK_32 () module ReservePrivateKeyP = MK_32 () module MerchantPublicKeyP = MK_32 () module MerchantPrivateKeyP = MK_32 () module TransferPublicKeyP = MK_32 () module TransferPrivateKeyP = MK_32 () module AmlOfficerPublicKeyP = MK_32 () module AmlOfficerPrivateKeyP = MK_32 () (*module ExchangePublicKeyP = MK_32 ()*) module ExchangePrivateKeyP = MK_32 () module MasterPublicKeyP = MK_32 () module MasterPrivateKeyP = MK_32 () module WireTransferIdentifierRawP = MK_32 () module CoinSpendPublicKeyP = MK_32 () (* union *) module CoinSpendPrivateKeyP = MK_32 () (* union *) module TokenPublicKeyP = MK_32 () (* union *) module PublicRefreshCoinNonceP = MK_64 () (* missing doc *) module ReserveSignatureP = MK_64 () module ExchangeSignatureP = MK_64 () module MasterSignatureP = MK_64 () module CoinSpendSignatureP = MK_64 () module TransferSecretP = MK_64 () module LinkSecretP = MK_64 () module EncryptedLinkSecretP = MK_64 () (* TODO ? need to use/save a specific nonce for cryptographic blinding *) (* Secret for blinding/unblinding. An RSA blinding secret, which is basically a 256-bit nonce, converted to Crockford `Base32`. type DenominationBlindingKeyP = string; *) module DenominationBlindingKeyP = MK_32 () (* --- Various --- *) module RefreshCommitmentP = MK_64 () module UUID = struct (* uint32t value[4]; *) type t = { value: string } let size = 4 * int32_size let bin = let open Bin in record (fun value -> { value }) |+ field (bytes size) (fun t -> t.value) |> sealr end module WadId = struct (* uint32t value[6]; *) type t = { raw: string } let size = 6 * int32_size let bin = let open Bin in record (fun raw -> { raw }) |+ field (bytes size) (fun t -> t.raw) |> sealr end module AgeMask = struct type t = { mask: int32 } let bin = let open Bin in record (fun mask -> { mask }) |+ field beint32 (fun t -> t.mask) |> sealr end (* TODO - why is the non-NBO version only used in TALER_WithdrawRequestPS? - correctly do the padding and 0-termination - handle "invalid" values *) (* documentation: *) (* Number of characters (plus 1 for 0-termination) for currency names. typically an ISO 4217 currency code when an alphanumeric 3-digit code is used. For regional currencies, the first character should be a "*" followed by a region-specific name (i.e. "*BRETAGNEFR"). Currency codes are compared case-insensitively. Currency string, left adjusted and padded with zeros. All zeros for "invalid" values. Name of the currency, using either a three-character ISO 4217 currency code, or a regional currency identifier between 4 and 11 characters, consisting of ASCII alphabetic characters ("a-zA-Z"). Should be padded to 12 bytes with 0-characters. Currency codes are compared case-insensitively. *) let currency_len = 12 (* TODO missing doc found in src/include/taler/taler_amount_lib.h *) module Amount = struct type t = { value: int64; fraction: int32; currency: string; } (* TODO BE here? *) let bin = let open Bin in record (fun value fraction currency -> { value; fraction; currency }) |+ field beint64 (fun t -> t.value) |+ field beint32 (fun t -> t.fraction) |+ field (bytes currency_len) (fun t -> t.currency) |> sealr end module AmountNBO = struct type t = { value: int64; fraction: int32; currency: string; } let bin = let open Bin in record (fun value fraction currency -> { value; fraction; currency }) |+ field beint64 (fun t -> t.value) |+ field beint32 (fun t -> t.fraction) |+ field (bytes currency_len) (fun t -> t.currency) |> sealr end (* -- Signatures -- *) (* PS: Packed Signature *) (* EccSignaturePurpose *) module Purpose = struct type t = { size: int32; purpose: int32; } let bin = let open Bin in record (fun size purpose -> { size; purpose }) |+ field beint32 (fun t -> t.size) |+ field beint32 (fun t -> t.purpose) |> sealr let make ~size purpose = { size= Int32.of_int size; purpose } let dummy = make ~size:0 0_l (* helper function to make ['signature Bin.t] to compute [t.size], we first build a bin with a dummy purpose *) let make_bin = let get_size f = let open Bin in match Size.of_value (Size.size_of (f dummy)) with | Dynamic _ | Unknown -> Fmt.failwith "size_of failure: size is not Static" | Static n -> n in fun code f -> make ~size:(get_size f) code |> f let field purpose = Bin.field bin (fun _t -> purpose) end module WithdrawRequestPS = struct (* Purpose is #TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW *) type t = { amount: Amount.t; fee: Amount.t; h_planchets: HashPlanchetsP.t; blinding_seed: BlindingMasterSecret.t; max_age_group: int32; mask: AgeMask.t; } let bin = let open Bin in Purpose.make_bin Taler_signatures.wallet_reserve_withdraw @@ fun purpose -> record (fun _purpose amount fee h_planchets blinding_seed max_age_group mask -> { amount; fee; h_planchets; blinding_seed; max_age_group; mask }) |+ Purpose.field purpose |+ field Amount.bin (fun t -> t.amount) |+ field Amount.bin (fun t -> t.fee) |+ field HashPlanchetsP.bin (fun t -> t.h_planchets) |+ field BlindingMasterSecret.bin (fun t -> t.blinding_seed) |+ field beint32 (fun t -> t.max_age_group) |+ field AgeMask.bin (fun t -> t.mask) |> sealr end module WithdrawConfirmationPS = struct (* Purpose is #TALER_SIGNATURE_EXCHANGE_CONFIRM_WITHDRAW. Signed by a `struct TALER_ExchangePrivateKeyP` using EdDSA. *) type t = { (* TODO TALER doc missing TALER_HashBlindedPlanchetsP*) h_planchets: HashPlanchetsP.t; noreveal_index: int32; } let bin = let open Bin in Purpose.make_bin Taler_signatures.exchange_confirm_withdraw @@ fun purpose -> record (fun _purpose h_planchets noreveal_index -> { h_planchets; noreveal_index }) |+ Purpose.field purpose |+ field HashPlanchetsP.bin (fun t -> t.h_planchets) |+ field beint32 (fun t -> t.noreveal_index) |> sealr end module DenominationKeyAnnouncementPS = struct (* TODO taler_signatures purpose we use TALER_SIGNATURE_SM_RSA_DENOMINATION_KEY instead here *) (* purpose.purpose = TALER_SIGNATURE_SM_DENOMINATION_KEY *) type t = { h_denom_pub: DenominationHash.t; h_section_name: Cstring_hash_64.t; anchor_time: TimeAbsoluteNBO.t; duration_withdraw: TimeRelativeNBO.t; } let bin = let open Bin in Purpose.make_bin Taler_signatures.sm_rsa_denomination_key @@ fun purpose -> record (fun _purpose h_denom_pub h_section_name anchor_time duration_withdraw -> { h_denom_pub; h_section_name; anchor_time; duration_withdraw }) |+ Purpose.field purpose |+ field DenominationHash.bin (fun t -> t.h_denom_pub) |+ field Cstring_hash_64.bin (fun t -> t.h_section_name) |+ field TimeAbsoluteNBO.bin (fun t -> t.anchor_time) |+ field TimeRelativeNBO.bin (fun t -> t.duration_withdraw) |> sealr end module SigningKeyAnnouncementPS = struct (* purpose.purpose = TALER_SIGNATURE_SM_SIGNING_KEY *) type t = { exchange_pub: ExchangePublicKeyP.t; anchor_time: TimeAbsoluteNBO.t; duration: TimeRelativeNBO.t; } let bin = let open Bin in Purpose.make_bin Taler_signatures.sm_signing_key @@ fun purpose -> record (fun _purpose exchange_pub anchor_time duration -> { exchange_pub; anchor_time; duration }) |+ Purpose.field purpose |+ field ExchangePublicKeyP.bin (fun t -> t.exchange_pub) |+ field TimeAbsoluteNBO.bin (fun t -> t.anchor_time) |+ field TimeRelativeNBO.bin (fun t -> t.duration) |> sealr end (* ### BIN IMPL END ### *) module SingleWithdrawRequestPS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW *) type t = { amount_with_fee: AmountNBO.t; h_denomination_pub: DenominationHash.t; h_coin_envelope: BlindedCoinHash.t; } end module DepositRequestPS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_DEPOSIT *) type t = { h_contract_terms: PrivateContractHash.t; h_age_commitment: AgeCommitmentHash.t; h_policy: ExtensionsPolicyHash.t; h_wire: MerchantWireHash.t; h_denom_pub: DenominationHash.t; timestamp: TimeAbsoluteNBO.t; refund_deadline: TimeAbsoluteNBO.t; amount_with_fee: AmountNBO.t; deposit_fee: AmountNBO.t; merchant: MerchantPublicKeyP.t; wallet_data_hash: Cstring_hash_64.t; } end module DepositConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT *) type t = { h_contract_terms: PrivateContractHash.t; h_wire: MerchantWireHash.t; h_policy: ExtensionsPolicyHash.t; timestamp: TimeAbsoluteNBO.t; refund_deadline: TimeAbsoluteNBO.t; amount_without_fee: AmountNBO.t; coin_pub: CoinSpendPublicKeyP.t; merchant: MerchantPublicKeyP.t; } end module RefreshMeltCoinAffirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_MELT *) type t = { session_hash: RefreshCommitmentP.t; h_denom_pub: DenominationHash.t; h_age_commitment: AgeCommitmentHash.t; amount_with_fee: AmountNBO.t; melt_fee: AmountNBO.t; } end module RefreshMeltConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT *) type t = { session_hash: RefreshCommitmentP.t; noreveal_index: int; (* uint16_t mapped to OCaml int *) } end module ExchangeSigningKeyValidityPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_SIGNING_KEY_VALIDITY *) type t = { start: TimeAbsoluteNBO.t; expire: TimeAbsoluteNBO.t; end_: TimeAbsoluteNBO.t; (* "end" renamed to end_ *) signkey_pub: ExchangePublicKeyP.t; } end module ExchangeKeySetPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_KEY_SET *) type t = { list_issue_date: TimeAbsoluteNBO.t; hc: Cstring_hash_64.t; } end module DenominationKeyValidityPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY *) type t = { master: MasterPublicKeyP.t; start: TimeAbsoluteNBO.t; expire_withdraw: TimeAbsoluteNBO.t; expire_spend: TimeAbsoluteNBO.t; expire_legal: TimeAbsoluteNBO.t; value: AmountNBO.t; fee_withdraw: AmountNBO.t; fee_deposit: AmountNBO.t; fee_refresh: AmountNBO.t; denom_hash: DenominationHash.t; } end module MasterWireDetailsPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_DETAILS *) type t = { h_wire_details: FullPaytoHash.t; h_conversion_url: Cstring_hash_64.t; h_credit_restrictions: Cstring_hash_64.t; h_debit_restrictions: Cstring_hash_64.t; } end module MasterWireFeePS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_WIRE_FEES *) type t = { h_wire_method: Cstring_hash_64.t; start_date: TimeAbsoluteNBO.t; end_date: TimeAbsoluteNBO.t; wire_fee: AmountNBO.t; closing_fee: AmountNBO.t; } end module GlobalFeesPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_GLOBAL_FEES *) type t = { start_date: TimeAbsoluteNBO.t; end_date: TimeAbsoluteNBO.t; purse_timeout: TimeRelativeNBO.t; kyc_timeout: TimeRelativeNBO.t; history_expiration: TimeRelativeNBO.t; history_fee: AmountNBO.t; kyc_fee: AmountNBO.t; account_fee: AmountNBO.t; purse_fee: AmountNBO.t; purse_account_limit: int; (* uint32_t → int *) } end module MasterDrainProfitPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_DRAIN_PROFITS *) type t = { wtid: WireTransferIdentifierRawP.t; date: TimeAbsoluteNBO.t; amount: AmountNBO.t; h_section: Cstring_hash_64.t; h_payto: FullPaytoHash.t; } end module DepositTrackPS = struct (* purpose.purpose = TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION *) type t = { h_contract_terms: PrivateContractHash.t; h_wire: MerchantWireHash.t; coin_pub: CoinSpendPublicKeyP.t; } end module WireDepositDetailP = struct type t = { h_contract_terms: PrivateContractHash.t; execution_time: TimeAbsoluteNBO.t; coin_pub: CoinSpendPublicKeyP.t; deposit_value: AmountNBO.t; deposit_fee: AmountNBO.t; } end module WireDepositDataPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT *) type t = { total: AmountNBO.t; wire_fee: AmountNBO.t; merchant_pub: MerchantPublicKeyP.t; h_wire: MerchantWireHash.t; h_details: Cstring_hash_64.t; } end module ExchangeKeyValidityPS = struct (* purpose.purpose = TALER_SIGNATURE_AUDITOR_EXCHANGE_KEYS *) type t = { auditor_url_hash: Cstring_hash_64.t; master: MasterPublicKeyP.t; start: TimeAbsoluteNBO.t; expire_withdraw: TimeAbsoluteNBO.t; expire_spend: TimeAbsoluteNBO.t; expire_legal: TimeAbsoluteNBO.t; value: AmountNBO.t; fee_withdraw: AmountNBO.t; fee_deposit: AmountNBO.t; fee_refresh: AmountNBO.t; denom_hash: DenominationHash.t; } end module PaymentResponsePS = struct (* purpose.purpose = TALER_SIGNATURE_MERCHANT_PAYMENT_OK *) type t = { h_contract_terms: PrivateContractHash.t } end module ContractPS = struct (* purpose.purpose = TALER_SIGNATURE_MERCHANT_CONTRACT *) type t = { h_contract_terms: PrivateContractHash.t } end module ConfirmWirePS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE *) type t = { h_wire: MerchantWireHash.t; h_contract_terms: PrivateContractHash.t; wtid: WireTransferIdentifierRawP.t; coin_pub: CoinSpendPublicKeyP.t; execution_time: TimeAbsoluteNBO.t; coin_contribution: AmountNBO.t; } end module RefundConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND *) type t = { h_contract_terms: PrivateContractHash.t; coin_pub: CoinSpendPublicKeyP.t; merchant: MerchantPublicKeyP.t; rtransaction_id: int64; refund_amount: AmountNBO.t; } end module DepositTrackPS2 = struct (* purpose.purpose = TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION *) type t = { h_contract_terms: PrivateContractHash.t; h_wire: MerchantWireHash.t; merchant: MerchantPublicKeyP.t; coin_pub: CoinSpendPublicKeyP.t; } end module RefundRequestPS = struct (* purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND *) type t = { h_contract_terms: PrivateContractHash.t; coin_pub: CoinSpendPublicKeyP.t; rtransaction_id: int64; refund_amount: AmountNBO.t; refund_fee: AmountNBO.t; } end module MerchantRefundConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_MERCHANT_REFUND_OK *) (* Hash of the order ID (a string), hashed without the 0-termination. *) type t = { h_order_id: Cstring_hash_64.t } end module RecoupRequestPS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_RECOUP or TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH *) type t = { h_denom_pub: DenominationHash.t; coin_blind: DenominationBlindingKeyP.t; } end module RecoupRefreshConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH *) type t = { timestamp: TimeAbsoluteNBO.t; recoup_amount: AmountNBO.t; coin_pub: CoinSpendPublicKeyP.t; old_coin_pub: CoinSpendPublicKeyP.t; } end module RecoupConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP *) type t = { timestamp: TimeAbsoluteNBO.t; recoup_amount: AmountNBO.t; coin_pub: CoinSpendPublicKeyP.t; reserve_pub: ReservePublicKeyP.t; } end module DenominationUnknownAffirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN *) type t = { timestamp: TimeAbsoluteNBO.t; h_denom_pub: DenominationHash.t; } end module DenominationExpiredAffirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_GENERIC_DENOMINATIN_EXPIRED *) type t = { timestamp: TimeAbsoluteNBO.t; operation: string; (* char[8] → string *) h_denom_pub: DenominationHash.t; } end module ReserveCloseConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED *) type t = { timestamp: TimeAbsoluteNBO.t; closing_amount: AmountNBO.t; reserve_pub: ReservePublicKeyP.t; h_wire: FullPaytoHash.t; } end module CoinLinkSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_LINK *) type t = { h_denom_pub: DenominationHash.t; old_coin_pub: CoinSpendPublicKeyP.t; transfer_pub: TransferPublicKeyP.t; coin_envelope_hash: BlindedCoinHash.t; } end module RefreshNonceSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_COIN_LINK *) type t = { nonce: PublicRefreshCoinNonceP.t } end module ReserveStatusRequestSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_RESERVE_STATUS_REQUEST *) type t = { request_timestamp: TimeAbsoluteNBO.t } end module ReserveHistoryRequestSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_RESERVE_HISTORY_REQUEST *) type t = { history_fee: AmountNBO.t; request_timestamp: TimeAbsoluteNBO.t; } end module PurseStatusRequestSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_PURSE_STATUS_REQUEST *) type t = unit end module PurseStatusResponseSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_PURSE_STATUS_RESPONSE *) type t = { total_purse_amount: AmountNBO.t; total_deposit_amount: AmountNBO.t; max_deposit_fees: AmountNBO.t; purse_expiration: TimeAbsoluteNBO.t; status_timestamp: TimeAbsoluteNBO.t; h_contract_terms: PrivateContractHash.t; } end module ReserveCloseRequestSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_CLOSE *) type t = unit end module PurseRequestSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_PURSE_CREATE *) type t = { purse_expiration: TimeAbsoluteNBO.t; merge_value_after_fees: AmountNBO.t; h_contract_terms: PrivateContractHash.t; min_age: int; } end module PurseDepositSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_PURSE_DEPOSIT *) type t = { coin_contribution: AmountNBO.t; h_denom_pub: DenominationHash.t; h_age_commitment: AgeCommitmentHash.t; purse_pub: PursePublicKey.t; h_exchange_base_url: Cstring_hash_64.t; } end module PurseDepositSignaturePS2 = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_OPEN_DEPOSIT *) type t = { reserve_sig: ReserveSignatureP.t; coin_contribution: AmountNBO.t; } end module PurseDepositConfirmedSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_PURSE_DEPOSIT_CONFIRMED *) type t = { total_purse_amount: AmountNBO.t; total_deposit_fees: AmountNBO.t; purse_pub: PursePublicKey.t; purse_expiration: TimeAbsoluteNBO.t; h_contract_terms: PrivateContractHash.t; } end module PurseMergeSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_PURSE_MERGE *) type t = { merge_timestamp: TimeAbsoluteNBO.t; h_wire: NormalizedPaytoHash.t; } end module AccountMergeSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_ACCOUNT_MERGE *) type t = { reserve_pub: ReservePublicKeyP.t; purse_pub: PursePublicKey.t; merge_amount_after_fees: AmountNBO.t; merge_timestamp: TimeAbsoluteNBO.t; purse_expiration: TimeAbsoluteNBO.t; h_contract_terms: PrivateContractHash.t; min_age: int; } end module AccountSetupRequestSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_ACCOUNT_SETUP *) type t = { threshold: AmountNBO.t } end module PurseMergeSuccessSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_PURSE_MERGE_SUCCESS *) type t = { reserve_pub: ReservePublicKeyP.t; purse_pub: PursePublicKey.t; merge_amount_after_fees: AmountNBO.t; contract_time: TimeAbsoluteNBO.t; h_contract_terms: PrivateContractHash.t; h_wire: NormalizedPaytoHash.t; min_age: int; } end module WadDataSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_WAD_DATA *) type t = { wad_execution_time: TimeAbsoluteNBO.t; total_amount: AmountNBO.t; h_items: Cstring_hash_64.t; wad_id: WadId.t; } end module WadPartnerSignaturePS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_PARTNER_DETAILS *) type t = { h_partner_base_url: Cstring_hash_64.t; master_public_key: MasterPublicKeyP.t; start_date: TimeAbsoluteNBO.t; end_date: TimeAbsoluteNBO.t; wad_fee: AmountNBO.t; wad_frequency: TimeRelativeNBO.t; } end module P2PFeesPS = struct (* purpose.purpose = TALER_SIGNATURE_P2P_FEES *) type t = { start_date: TimeAbsoluteNBO.t; end_date: TimeAbsoluteNBO.t; kyc_fee: AmountNBO.t; purse_fee: AmountNBO.t; account_history_fee: AmountNBO.t; account_annual_fee: AmountNBO.t; account_kyc_timeout: TimeRelativeNBO.t; purse_timeout: TimeRelativeNBO.t; purse_account_limit: int; } end module CoinPurseRefundConfirmationPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_CONFIRM_PURSE_REFUND *) type t = { purse_pub: PursePublicKey.t; coin_pub: CoinSpendPublicKeyP.t; refunded_amount: AmountNBO.t; refund_fee: AmountNBO.t; } end module MasterDenominationKeyRevocationPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED *) type t = { h_denom_pub: DenominationHash.t } end module MasterSigningKeyRevocationPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_SIGNING_KEY_REVOKED *) type t = { exchange_pub: ExchangePublicKeyP.t } end module MasterAddAuditorPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_ADD_AUDITOR *) type t = { start_date: TimeAbsoluteNBO.t; auditor_pub: AuditorPublicKeyP.t; h_auditor_url: Cstring_hash_64.t; } end module MasterDelAuditorPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_DEL_AUDITOR *) type t = { end_date: TimeAbsoluteNBO.t; auditor_pub: AuditorPublicKeyP.t; } end module MasterAddWirePS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_ADD_WIRE *) type t = { start_date: TimeAbsoluteNBO.t; h_wire: FullPaytoHash.t; h_conversion_url: Cstring_hash_64.t; h_credit_restrictions: Cstring_hash_64.t; h_debit_restrictions: Cstring_hash_64.t; } end module MasterDelWirePS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_DEL_WIRE *) type t = { end_date: TimeAbsoluteNBO.t; h_wire: FullPaytoHash.t; } end module MasterAmlOfficerStatusPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_AML_KEY *) type t = { change_date: TimestampNBO.t; officer_pub: AmlOfficerPublicKeyP.t; h_officer_name: Cstring_hash_64.t; is_active: int; } end module AmlDecisionPS = struct (* purpose.purpose = TALER_SIGNATURE_AML_DECISION *) type t = { h_justification: Cstring_hash_64.t; decision_time: TimestampNBO.t; new_threshold: AmountNBO.t; h_payto: NormalizedPaytoHash.t; h_kyc_requirements: Cstring_hash_64.t; new_state: int; } end module PartnerConfigurationPS = struct (* purpose.purpose = TALER_SIGNATURE_MASTER_PARNTER_DETAILS *) type t = { partner_pub: MasterPublicKeyP.t; start_date: TimestampNBO.t; end_date: TimestampNBO.t; wad_frequency: TimeRelativeNBO.t; wad_fee: AmountNBO.t; h_url: Cstring_hash_64.t; } end module ReserveOpenPS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_OPEN *) type t = { reserve_payment: AmountNBO.t; request_timestamp: TimestampNBO.t; reserve_expiration: TimestampNBO.t; purse_limit: int; } end module ReserveClosePS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_RESERVE_CLOSE *) type t = { request_timestamp: TimestampNBO.t; target_account_h_payto: FullPaytoHash.t; } end module ReserveAttestRequestPS = struct (* purpose.purpose = TALER_SIGNATURE_WALLET_ATTEST_REQUEST *) type t = { request_timestamp: TimestampNBO.t; h_details: Cstring_hash_64.t; } end module ExchangeAttestPS = struct (* purpose.purpose = TALER_SIGNATURE_EXCHANGE_RESERVE_ATTEST_DETAILS *) type t = { attest_timestamp: TimestampNBO.t; expiration_time: TimestampNBO.t; reserve_pub: ReservePublicKeyP.t; h_attributes: Cstring_hash_64.t; } end