This commit is contained in:
parent
fe5751044d
commit
c59cb116fc
3 changed files with 141 additions and 137 deletions
|
|
@ -51,21 +51,10 @@ let signkey_data =
|
||||||
Signkey.
|
Signkey.
|
||||||
{ pub; stamp_start; stamp_expire; stamp_end; master_sig; revoked_sig }
|
{ pub; stamp_start; stamp_expire; stamp_end; master_sig; revoked_sig }
|
||||||
->
|
->
|
||||||
match master_sig with
|
Ok (pub, stamp_start, stamp_expire, stamp_end, master_sig, revoked_sig))
|
||||||
| None -> Error "signkey_data master_sig is none"
|
|
||||||
| Some master_sig ->
|
|
||||||
Ok (pub, stamp_start, stamp_expire, stamp_end, master_sig, revoked_sig))
|
|
||||||
~decode:(fun
|
~decode:(fun
|
||||||
(pub, stamp_start, stamp_expire, stamp_end, master_sig, revoked_sig) ->
|
(pub, stamp_start, stamp_expire, stamp_end, master_sig, revoked_sig) ->
|
||||||
Ok
|
Ok { pub; stamp_start; stamp_expire; stamp_end; master_sig; revoked_sig })
|
||||||
{
|
|
||||||
pub;
|
|
||||||
stamp_start;
|
|
||||||
stamp_expire;
|
|
||||||
stamp_end;
|
|
||||||
master_sig= Some master_sig;
|
|
||||||
revoked_sig;
|
|
||||||
})
|
|
||||||
(t6 eddsa_pub time time time master_sig revoked_sig)
|
(t6 eddsa_pub time time time master_sig revoked_sig)
|
||||||
|
|
||||||
let denom_data =
|
let denom_data =
|
||||||
|
|
@ -91,22 +80,19 @@ let denom_data =
|
||||||
revoked_sig;
|
revoked_sig;
|
||||||
}
|
}
|
||||||
->
|
->
|
||||||
match master_sig with
|
Ok
|
||||||
| None -> Error "denom_data master_sig is none"
|
( pub,
|
||||||
| Some master_sig ->
|
value,
|
||||||
Ok
|
stamp_start,
|
||||||
( pub,
|
stamp_expire_withdraw,
|
||||||
value,
|
stamp_expire_deposit,
|
||||||
stamp_start,
|
stamp_expire_legal,
|
||||||
stamp_expire_withdraw,
|
fee_withdraw,
|
||||||
stamp_expire_deposit,
|
fee_deposit,
|
||||||
stamp_expire_legal,
|
fee_refresh,
|
||||||
fee_withdraw,
|
fee_refund,
|
||||||
fee_deposit,
|
age_mask,
|
||||||
fee_refresh,
|
(h_pub, master_sig, revoked_sig) ))
|
||||||
fee_refund,
|
|
||||||
age_mask,
|
|
||||||
(h_pub, master_sig, revoked_sig) ))
|
|
||||||
~decode:(fun
|
~decode:(fun
|
||||||
( pub,
|
( pub,
|
||||||
value,
|
value,
|
||||||
|
|
@ -135,7 +121,7 @@ let denom_data =
|
||||||
fee_refund;
|
fee_refund;
|
||||||
age_mask;
|
age_mask;
|
||||||
h_pub;
|
h_pub;
|
||||||
master_sig= Some master_sig;
|
master_sig;
|
||||||
revoked_sig;
|
revoked_sig;
|
||||||
})
|
})
|
||||||
(t12 rsa_pub amount time time time time amount amount amount amount int
|
(t12 rsa_pub amount time time time time amount amount amount amount int
|
||||||
|
|
|
||||||
199
src/secmod.ml
199
src/secmod.ml
|
|
@ -1,6 +1,7 @@
|
||||||
module type S = sig
|
module type S = sig
|
||||||
open Crypto
|
open Crypto
|
||||||
|
|
||||||
|
val sm_pubkey : eddsa_pub
|
||||||
val sign_with_sm_key : string -> eddsa_sig
|
val sign_with_sm_key : string -> eddsa_sig
|
||||||
val sign_with_signkey : pub:eddsa_pub -> string -> eddsa_sig
|
val sign_with_signkey : pub:eddsa_pub -> string -> eddsa_sig
|
||||||
val verify_with_master_key : eddsa_sig -> msg:string -> (unit, string) result
|
val verify_with_master_key : eddsa_sig -> msg:string -> (unit, string) result
|
||||||
|
|
@ -9,26 +10,20 @@ module type S = sig
|
||||||
val verify_with_signkey :
|
val verify_with_signkey :
|
||||||
pub:eddsa_pub -> eddsa_sig -> msg:string -> (unit, string) result
|
pub:eddsa_pub -> eddsa_sig -> msg:string -> (unit, string) result
|
||||||
|
|
||||||
(* TODO query database instead? *)
|
val get_signkeys : unit -> Signkey.t list
|
||||||
val get_sm_key_pub : unit -> eddsa_pub
|
val get_denominations : unit -> Denomination.t list
|
||||||
val get_signkeys_data : unit -> Signkey.t list
|
val get_future_signkeys : unit -> Api.FutureSignKey.t list
|
||||||
val get_denoms_data : unit -> Denomination.t list
|
val get_future_denominations : unit -> Api.FutureDenom.t list
|
||||||
val find_signkey_data : eddsa_pub -> Signkey.t option
|
val find_signkey : eddsa_pub -> Signkey.t option
|
||||||
val find_denomination : denomination_hash -> Denomination.t option
|
val find_denomination : rsa_pub -> Denomination.t option
|
||||||
val find_denom_section_name : denomination_hash -> string option
|
|
||||||
|
|
||||||
(* - management operations - *)
|
val certify_future_signkey :
|
||||||
(* TODO
|
eddsa_pub ->
|
||||||
problem of keeping db and secmod state syncronized
|
Signatures.ExchangeSigningKeyValidity.t ->
|
||||||
do db interaction from secmod? *)
|
|
||||||
|
|
||||||
val add_signkey_master_signatures :
|
|
||||||
(eddsa_pub * Signatures.ExchangeSigningKeyValidity.t) list ->
|
|
||||||
(unit, string) result
|
(unit, string) result
|
||||||
|
|
||||||
val add_denom_master_signatures :
|
val certify_future_denomination :
|
||||||
(denomination_hash * Signatures.DenominationKeyValidity.t) list ->
|
rsa_pub -> Signatures.DenominationKeyValidity.t -> (unit, string) result
|
||||||
(unit, string) result
|
|
||||||
|
|
||||||
val revoke_signkey :
|
val revoke_signkey :
|
||||||
eddsa_pub ->
|
eddsa_pub ->
|
||||||
|
|
@ -36,11 +31,11 @@ module type S = sig
|
||||||
(unit, string) result
|
(unit, string) result
|
||||||
|
|
||||||
val revoke_denomination :
|
val revoke_denomination :
|
||||||
denomination_hash ->
|
rsa_pub ->
|
||||||
Signatures.MasterDenominationKeyRevocation.t ->
|
Signatures.MasterDenominationKeyRevocation.t ->
|
||||||
(unit, string) result
|
(unit, string) result
|
||||||
|
|
||||||
val store : unit -> (unit, string) result
|
val save : unit -> (unit, string) result
|
||||||
end
|
end
|
||||||
|
|
||||||
module Make (Conn : Pg.CONN) = struct
|
module Make (Conn : Pg.CONN) = struct
|
||||||
|
|
@ -52,7 +47,7 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
type dn = Denomination.t
|
type dn = Denomination.t
|
||||||
type future_dn = Api.FutureDenom.t
|
type future_dn = Api.FutureDenom.t
|
||||||
|
|
||||||
(* TODO use lock *)
|
(* TODO use lock! *)
|
||||||
type t = {
|
type t = {
|
||||||
sm_key: eddsa_priv;
|
sm_key: eddsa_priv;
|
||||||
sm_pubkey: eddsa_pub;
|
sm_pubkey: eddsa_pub;
|
||||||
|
|
@ -64,6 +59,7 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
future_dn_ht: (rsa_pub, future_dn) Hashtbl.t;
|
future_dn_ht: (rsa_pub, future_dn) Hashtbl.t;
|
||||||
future_sk_key_ht: (eddsa_pub, eddsa_priv) Hashtbl.t;
|
future_sk_key_ht: (eddsa_pub, eddsa_priv) Hashtbl.t;
|
||||||
future_dn_key_ht: (rsa_pub, rsa_priv) Hashtbl.t;
|
future_dn_key_ht: (rsa_pub, rsa_priv) Hashtbl.t;
|
||||||
|
dn_section_name_ht: (rsa_pub, string) Hashtbl.t;
|
||||||
}
|
}
|
||||||
|
|
||||||
let database_find_sk conn fname pub =
|
let database_find_sk conn fname pub =
|
||||||
|
|
@ -166,6 +162,7 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
future_dn_ht= Hashtbl.create 0xff;
|
future_dn_ht= Hashtbl.create 0xff;
|
||||||
future_sk_key_ht= Hashtbl.create 0xff;
|
future_sk_key_ht= Hashtbl.create 0xff;
|
||||||
future_dn_key_ht= Hashtbl.create 0xff;
|
future_dn_key_ht= Hashtbl.create 0xff;
|
||||||
|
dn_section_name_ht= Hashtbl.create 0xff;
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
Ok (Some t)
|
Ok (Some t)
|
||||||
|
|
@ -280,6 +277,7 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
future_dn_ht= Hashtbl.create 0xff;
|
future_dn_ht= Hashtbl.create 0xff;
|
||||||
future_sk_key_ht= Hashtbl.create 0xff;
|
future_sk_key_ht= Hashtbl.create 0xff;
|
||||||
future_dn_key_ht= Hashtbl.create 0xff;
|
future_dn_key_ht= Hashtbl.create 0xff;
|
||||||
|
dn_section_name_ht= Hashtbl.create 0xff;
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
make_future_sk t;
|
make_future_sk t;
|
||||||
|
|
@ -297,6 +295,7 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
t
|
t
|
||||||
| Error e -> Fmt.failwith "secmod init failure: %s." e
|
| Error e -> Fmt.failwith "secmod init failure: %s." e
|
||||||
|
|
||||||
|
let sm_pubkey = t.sm_pubkey
|
||||||
let sign_with_sm_key s = sign_with_sm_key t s
|
let sign_with_sm_key s = sign_with_sm_key t s
|
||||||
let verify_with_sm_key s ~msg = EddsaSignature.verify ~key:t.sm_pubkey s ~msg
|
let verify_with_sm_key s ~msg = EddsaSignature.verify ~key:t.sm_pubkey s ~msg
|
||||||
|
|
||||||
|
|
@ -309,12 +308,11 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
EddsaSignature.verify ~key:Config.master_public_key
|
EddsaSignature.verify ~key:Config.master_public_key
|
||||||
|
|
||||||
let verify_with_signkey ~pub s ~msg =
|
let verify_with_signkey ~pub s ~msg =
|
||||||
(* check that the key we are verifying with is one of our own *)
|
(* check that [pub] is one of our own keys *)
|
||||||
match Hashtbl.find_opt t.sk_ht pub with
|
match Hashtbl.find_opt t.sk_ht pub with
|
||||||
| None -> Fmt.failwith "secmod failure: signkey not found."
|
| None -> Fmt.failwith "secmod failure: signkey not found."
|
||||||
| Some _priv -> EddsaSignature.verify ~key:pub s ~msg
|
| Some _priv -> EddsaSignature.verify ~key:pub s ~msg
|
||||||
|
|
||||||
let sm_pubkey = t.sm_pubkey
|
|
||||||
let get_signkeys () = t.sk_ht |> Hashtbl.to_seq_values |> List.of_seq
|
let get_signkeys () = t.sk_ht |> Hashtbl.to_seq_values |> List.of_seq
|
||||||
let get_denominations () = t.dn_ht |> Hashtbl.to_seq_values |> List.of_seq
|
let get_denominations () = t.dn_ht |> Hashtbl.to_seq_values |> List.of_seq
|
||||||
|
|
||||||
|
|
@ -367,88 +365,113 @@ module Make (Conn : Pg.CONN) = struct
|
||||||
let* () = Pg.insert_signkey (module Conn) sk |> unwrap_err_caqti in
|
let* () = Pg.insert_signkey (module Conn) sk |> unwrap_err_caqti in
|
||||||
Ok ())
|
Ok ())
|
||||||
|
|
||||||
let add_signkey_master_signatures l =
|
let certify_future_denomination pub master_sig =
|
||||||
Miou.Mutex.protect t.lock @@ fun () ->
|
match
|
||||||
list_iter
|
( Hashtbl.find_opt t.future_dn_ht pub,
|
||||||
(fun (pub, master_sig) ->
|
Hashtbl.find_opt t.future_dn_key_ht pub )
|
||||||
match Hashtbl.find_opt t.sk_ht pub with
|
with
|
||||||
| None -> Error "secmod failure: public key not found."
|
| None, _ | _, None -> Error "secmod failure: future signkey not found."
|
||||||
| Some signkey ->
|
| Some future_dn, Some priv -> (
|
||||||
let sk_data =
|
match Hashtbl.find_opt t.dn_ht pub with
|
||||||
{ signkey.sk_data with master_sig= Some master_sig }
|
| Some _dn ->
|
||||||
|
Error
|
||||||
|
"secmod failure: this denomination already has a master signature"
|
||||||
|
| None ->
|
||||||
|
let Api.FutureDenom.
|
||||||
|
{
|
||||||
|
section_name;
|
||||||
|
value;
|
||||||
|
stamp_start;
|
||||||
|
stamp_expire_withdraw;
|
||||||
|
stamp_expire_deposit;
|
||||||
|
stamp_expire_legal;
|
||||||
|
denom_pub= _;
|
||||||
|
fee_withdraw;
|
||||||
|
fee_deposit;
|
||||||
|
fee_refresh;
|
||||||
|
fee_refund;
|
||||||
|
denom_secmod_sig= _;
|
||||||
|
} =
|
||||||
|
future_dn
|
||||||
in
|
in
|
||||||
let signkey = { signkey with sk_data } in
|
(* TODO dn hash
|
||||||
let* () =
|
need to compute it from denom_pub *)
|
||||||
Pg.insert_signkey (module Conn) sk_data |> unwrap_err_caqti
|
let h_pub =
|
||||||
|
Hash.DenominationHash.hash (RsaPublicKey.to_octets pub)
|
||||||
in
|
in
|
||||||
Hashtbl.replace t.sk_ht pub signkey;
|
let dn =
|
||||||
Ok ())
|
Denomination.
|
||||||
l
|
{
|
||||||
|
pub;
|
||||||
|
value;
|
||||||
|
stamp_start;
|
||||||
|
stamp_expire_withdraw;
|
||||||
|
stamp_expire_deposit;
|
||||||
|
stamp_expire_legal;
|
||||||
|
fee_withdraw;
|
||||||
|
fee_deposit;
|
||||||
|
fee_refresh;
|
||||||
|
fee_refund;
|
||||||
|
age_mask= 0;
|
||||||
|
h_pub;
|
||||||
|
master_sig;
|
||||||
|
revoked_sig= None;
|
||||||
|
}
|
||||||
|
in
|
||||||
|
Hashtbl.replace t.dn_ht pub dn;
|
||||||
|
Hashtbl.replace t.dn_key_ht pub priv;
|
||||||
|
Hashtbl.replace t.dn_section_name_ht pub section_name;
|
||||||
|
Hashtbl.remove t.future_dn_ht pub;
|
||||||
|
Hashtbl.remove t.future_dn_key_ht pub;
|
||||||
|
|
||||||
let add_denom_master_signatures l =
|
let* () = Pg.insert_denom (module Conn) dn |> unwrap_err_caqti in
|
||||||
Miou.Mutex.protect t.lock @@ fun () ->
|
|
||||||
list_iter
|
|
||||||
(fun (h_denom_pub, master_sig) ->
|
|
||||||
match Hashtbl.find_opt t.dn_ht h_denom_pub with
|
|
||||||
| None -> Error "secmod failure: denomination hash not found."
|
|
||||||
| Some denom ->
|
|
||||||
let dn_data = { denom.dn_data with master_sig= Some master_sig } in
|
|
||||||
let denom = { denom with dn_data } in
|
|
||||||
let* () =
|
|
||||||
Pg.insert_denom (module Conn) dn_data |> unwrap_err_caqti
|
|
||||||
in
|
|
||||||
Hashtbl.replace t.dn_ht h_denom_pub denom;
|
|
||||||
Ok ())
|
Ok ())
|
||||||
l
|
|
||||||
|
|
||||||
let revoke_signkey exchange_pub revoked_sig =
|
let revoke_signkey pub revoked_sig =
|
||||||
Miou.Mutex.protect t.lock @@ fun () ->
|
match Hashtbl.find_opt t.sk_ht pub with
|
||||||
match Hashtbl.find_opt t.sk_ht exchange_pub with
|
| None -> Error "secmod failure: signkey not found."
|
||||||
| None -> Error "secmod failure: denomination hash not found."
|
| Some sk ->
|
||||||
| Some signkey ->
|
let sk = { sk with revoked_sig= Some revoked_sig } in
|
||||||
let sk_data = { signkey.sk_data with revoked_sig= Some revoked_sig } in
|
Hashtbl.replace t.sk_ht pub sk;
|
||||||
let signkey = { signkey with sk_data } in
|
|
||||||
Hashtbl.replace t.sk_ht exchange_pub signkey;
|
(* TODO revoke, apply to database *)
|
||||||
Ok ()
|
Ok ()
|
||||||
|
|
||||||
let revoke_denomination h_denom_pub revoked_sig =
|
let revoke_denomination pub revoked_sig =
|
||||||
Miou.Mutex.protect t.lock @@ fun () ->
|
match Hashtbl.find_opt t.dn_ht pub with
|
||||||
match Hashtbl.find_opt t.dn_ht h_denom_pub with
|
| None -> Error "secmod failure: denomination not found."
|
||||||
| None -> Error "secmod failure: denomination hash not found."
|
| Some dn ->
|
||||||
| Some denom ->
|
let dn = { dn with revoked_sig= Some revoked_sig } in
|
||||||
let dn_data = { denom.dn_data with revoked_sig= Some revoked_sig } in
|
Hashtbl.replace t.dn_ht pub dn;
|
||||||
let denom = { denom with dn_data } in
|
|
||||||
Hashtbl.replace t.dn_ht h_denom_pub denom;
|
(* TODO revoke, apply to database *)
|
||||||
Ok ()
|
Ok ()
|
||||||
|
|
||||||
let store () =
|
let save () =
|
||||||
Miou.Mutex.protect t.lock @@ fun () ->
|
|
||||||
let* () =
|
let* () =
|
||||||
Data_file.write_eddsa Fpath.(Config.secrets_dir / "sk_sm") t.sm_key_priv
|
let fname = Fpath.(Config.secrets_dir / "sk_sm") in
|
||||||
|
Data_file.write_eddsa fname t.sm_key
|
||||||
in
|
in
|
||||||
let* () =
|
let* () =
|
||||||
Hashtbl.to_seq_values t.sk_ht
|
Hashtbl.to_seq_values t.sk_key_ht
|
||||||
|> List.of_seq
|
|> List.of_seq
|
||||||
|> List.mapi (fun i (key : signkey) ->
|
|> List.mapi (fun i priv ->
|
||||||
let fname = Fpath.(Config.secrets_dir / Fmt.str "sk_%d" i) in
|
let fname = Fpath.(Config.secrets_dir / Fmt.str "sk_%d" i) in
|
||||||
(fname, key.priv))
|
Data_file.write_eddsa fname priv)
|
||||||
|> list_iter (fun (fname, key) -> Data_file.write_eddsa fname key)
|
|> list_iter Fun.id
|
||||||
in
|
in
|
||||||
let* () =
|
let* () =
|
||||||
let* l =
|
Hashtbl.to_seq t.dn_key_ht
|
||||||
Hashtbl.to_seq_values t.dn_ht
|
|> List.of_seq
|
||||||
|> List.of_seq
|
|> list_iter (fun (pub, priv) ->
|
||||||
|> Syntax.list_map (fun (key : denom) ->
|
let* section_name =
|
||||||
let+ section_name =
|
match Hashtbl.find_opt t.dn_section_name_ht pub with
|
||||||
match Hashtbl.find_opt t.dn_section_name_ht key.dn_data.h_pub with
|
| None -> Error "invalid state, section_name not found"
|
||||||
| None -> Error "invalid state, section_name not found"
|
| Some s -> Ok s
|
||||||
| Some s -> Ok s
|
in
|
||||||
in
|
let fname = Fpath.(Config.secrets_dir / section_name) in
|
||||||
let fname = Fpath.(Config.secrets_dir / section_name) in
|
Data_file.write_rsa fname priv)
|
||||||
(fname, key.priv))
|
|
||||||
in
|
|
||||||
list_iter (fun (fname, key) -> Data_file.write_rsa fname key) l
|
|
||||||
in
|
in
|
||||||
Logs.info (fun m -> m "stored secmod data to file");
|
Logs.info (fun m -> m "saved secmod private keys data");
|
||||||
Ok ()
|
Ok ()
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
module type S = sig
|
module type S = sig
|
||||||
open Crypto
|
open Crypto
|
||||||
|
|
||||||
|
val sm_pubkey : eddsa_pub
|
||||||
val sign_with_sm_key : string -> eddsa_sig
|
val sign_with_sm_key : string -> eddsa_sig
|
||||||
val sign_with_signkey : pub:eddsa_pub -> string -> eddsa_sig
|
val sign_with_signkey : pub:eddsa_pub -> string -> eddsa_sig
|
||||||
val verify_with_master_key : eddsa_sig -> msg:string -> (unit, string) result
|
val verify_with_master_key : eddsa_sig -> msg:string -> (unit, string) result
|
||||||
|
|
@ -9,26 +10,20 @@ module type S = sig
|
||||||
val verify_with_signkey :
|
val verify_with_signkey :
|
||||||
pub:eddsa_pub -> eddsa_sig -> msg:string -> (unit, string) result
|
pub:eddsa_pub -> eddsa_sig -> msg:string -> (unit, string) result
|
||||||
|
|
||||||
(* TODO query database instead? *)
|
val get_signkeys : unit -> Signkey.t list
|
||||||
val get_sm_key_pub : unit -> eddsa_pub
|
val get_denominations : unit -> Denomination.t list
|
||||||
val get_signkeys_data : unit -> Signkey.t list
|
val get_future_signkeys : unit -> Api.FutureSignKey.t list
|
||||||
val get_denoms_data : unit -> Denomination.t list
|
val get_future_denominations : unit -> Api.FutureDenom.t list
|
||||||
val find_signkey_data : eddsa_pub -> Signkey.t option
|
val find_signkey : eddsa_pub -> Signkey.t option
|
||||||
val find_denomination : denomination_hash -> Denomination.t option
|
val find_denomination : rsa_pub -> Denomination.t option
|
||||||
val find_denom_section_name : denomination_hash -> string option
|
|
||||||
|
|
||||||
(* - management operations - *)
|
val certify_future_signkey :
|
||||||
(* TODO
|
eddsa_pub ->
|
||||||
problem of keeping db and secmod state syncronized
|
Signatures.ExchangeSigningKeyValidity.t ->
|
||||||
do db interaction from secmod? *)
|
|
||||||
|
|
||||||
val add_signkey_master_signatures :
|
|
||||||
(eddsa_pub * Signatures.ExchangeSigningKeyValidity.t) list ->
|
|
||||||
(unit, string) result
|
(unit, string) result
|
||||||
|
|
||||||
val add_denom_master_signatures :
|
val certify_future_denomination :
|
||||||
(denomination_hash * Signatures.DenominationKeyValidity.t) list ->
|
rsa_pub -> Signatures.DenominationKeyValidity.t -> (unit, string) result
|
||||||
(unit, string) result
|
|
||||||
|
|
||||||
val revoke_signkey :
|
val revoke_signkey :
|
||||||
eddsa_pub ->
|
eddsa_pub ->
|
||||||
|
|
@ -36,11 +31,11 @@ module type S = sig
|
||||||
(unit, string) result
|
(unit, string) result
|
||||||
|
|
||||||
val revoke_denomination :
|
val revoke_denomination :
|
||||||
denomination_hash ->
|
rsa_pub ->
|
||||||
Signatures.MasterDenominationKeyRevocation.t ->
|
Signatures.MasterDenominationKeyRevocation.t ->
|
||||||
(unit, string) result
|
(unit, string) result
|
||||||
|
|
||||||
val store : unit -> (unit, string) result
|
val save : unit -> (unit, string) result
|
||||||
end
|
end
|
||||||
|
|
||||||
module Make (_ : Pg.CONN) : S
|
module Make (_ : Pg.CONN) : S
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue