From 576983481f470ad033ee88fa48b99c248e15b6a8 Mon Sep 17 00:00:00 2001 From: swrup Date: Fri, 28 Nov 2025 14:00:11 +0100 Subject: [PATCH] --- data/eddsa_master_offline | 1 + src/api.ml | 17 +++++++- src/bin_type.ml | 19 ++++----- src/crypto.ml | 1 + tools/offline.ml | 83 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 data/eddsa_master_offline diff --git a/data/eddsa_master_offline b/data/eddsa_master_offline new file mode 100644 index 00000000..3e6eca77 --- /dev/null +++ b/data/eddsa_master_offline @@ -0,0 +1 @@ +mÔ¯9Wàü]w×LèyÛ ãï[ººº¶ \㘊Ug( \ No newline at end of file diff --git a/src/api.ml b/src/api.ml index 988c2e4d..257891cd 100644 --- a/src/api.ml +++ b/src/api.ml @@ -29,9 +29,18 @@ module ErrorDetail = struct |> Jsont.Object.finish end -module HashCode = struct +module HashCode : sig + type t + + val hash : string -> t + val jsont : t Jsont.t +end = struct type t = B32.t + let hash s = + let open Digestif.SHA256 in + s |> digest_string |> to_raw_string + let jsont = Jsont.of_of_string ~kind:"HashCode" B32.decode ~enc:B32.encode end @@ -46,6 +55,12 @@ module Timestamp = struct | Seconds of float | Never + (* TODO time + - check this + - what value for never? + - better way for conversion to bin_types? *) + let to_int64 t = match t with Never -> 0_L | Seconds v -> Int64.of_float v + let to_ptime t = Util.ptime_of_int64 @@ to_int64 t let of_ptime p = Seconds (Ptime.to_float_s p) let number_or_never_jsont = diff --git a/src/bin_type.ml b/src/bin_type.ml index c2a0ffc6..b9e7a867 100644 --- a/src/bin_type.ml +++ b/src/bin_type.ml @@ -65,13 +65,15 @@ module INT64 = struct let bin = Bin.neint64 let of_ptime v = Util.ptime_to_int64 v + let of_int64 i = i end module INT64_NBO = struct type t = int64 let bin = Bin.beint64 - let of_ptime = Util.ptime_to_int64 + let of_ptime v = Util.ptime_to_int64 v + let of_int64 i = i end (* -- Time -- *) @@ -80,6 +82,7 @@ module type Time_S = sig val bin : t Bin.t val of_ptime : Ptime.t -> t + val of_int64 : int64 -> t end module TimeAbsolute : Time_S = INT64 @@ -262,22 +265,20 @@ module AmountP = struct currency: string; } - (* TODO BE here? *) + let of_amount Amount.{ sign= _; currency; value; fraction } = + { value; fraction; currency } + 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 neint64 (fun t -> t.value) + |+ field neint32 (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; - } + include AmountP let bin = let open Bin in diff --git a/src/crypto.ml b/src/crypto.ml index b6e99c94..1e2f7e2c 100644 --- a/src/crypto.ml +++ b/src/crypto.ml @@ -32,6 +32,7 @@ module EddsaPrivateKey = struct type t = priv + let pub_of_priv = pub_of_priv let to_octets t = priv_to_octets t let of_octets t = priv_of_octets t |> Result.get_ok let bin = Bin.map (Bin.bytes 32) of_octets to_octets diff --git a/tools/offline.ml b/tools/offline.ml index c127e643..000b501f 100644 --- a/tools/offline.ml +++ b/tools/offline.ml @@ -12,6 +12,66 @@ let download ~base_url ~output = let wget = Cmd.(v "wget" % "-O" % output % uri) in OS.Cmd.run wget +let setup ~output = + let output = Fpath.v output in + let () = Mirage_crypto_rng_unix.use_default () in + let priv, _pub = Mirage_crypto_ec.Ed25519.generate () in + let priv_data = Mirage_crypto_ec.Ed25519.priv_to_octets priv in + Bos.OS.File.write output priv_data + +let _denom_signature master_priv master_pub + 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= _; + (* TODO check sigs *) + denom_secmod_sig= _; + } = + let pub_octets = + let denom_pub = + match denom_pub with + | Rsa v -> v + | CS _ -> Fmt.failwith "CS key types are not supported." + in + let pub = denom_pub.Api.RsaDenominationKey.rsa_pub in + Crypto.RsaPublicKey.to_octets pub + in + let h_denom_pub = Api.HashCode.hash pub_octets in + let master_sig = + let open Bin_type in + let open Bin_signature.DenominationKeyValidityPS in + let of_time ts : TimeAbsoluteNBO.t = + TimeAbsoluteNBO.of_int64 @@ Api.Timestamp.to_int64 ts + in + let of_amount v = AmountNBO.of_amount v in + let denom_key_validity = + { + master= master_pub; + start= of_time stamp_start; + expire_withdraw= of_time stamp_expire_withdraw; + expire_spend= of_time stamp_expire_deposit; + expire_legal= of_time stamp_expire_legal; + value= of_amount value; + fee_withdraw= of_amount fee_withdraw; + fee_deposit= of_amount fee_deposit; + fee_refresh= of_amount fee_refresh; + denom_hash= Bin_type.DenominationHash.hash pub_octets; + } + in + let data = Bin.to_string bin denom_key_validity in + Crypto.EddsaSignature.sign ~key:master_priv data + in + Api.DenomSignature.{ h_denom_pub; master_sig } + let sign ~input ~output ~master_key = let open Syntax in let open Bos.OS in @@ -31,6 +91,24 @@ let sign ~input ~output ~master_key = open Cmdliner open Cmdliner.Term.Syntax +let setup_cmd = + let doc = "Generate offline master keys" in + let output = + let doc = "Output file for the generated private Eddsa key." in + Arg.( + value + & opt filepath "data/eddsa_master_offline" + & info [ "o"; "output" ] ~doc) + in + Cmd.make (Cmd.info "setup" ~version:"%%VERSION%%" ~doc) + @@ + let+ output = output in + match setup ~output with + | Error (`Msg err) -> + Fmt.epr "Setup failure: %s@." err; + exit 1 + | Ok () -> () + let download_cmd = let doc = "Downloads /management/keys/" in let man = @@ -82,6 +160,7 @@ let sign_cmd = exit 1 | Ok () -> () -let main () = Cmd.eval download_cmd -let _main () = Cmd.eval sign_cmd +let main () = Cmd.eval setup_cmd +let _main () = Cmd.eval download_cmd +let __main () = Cmd.eval sign_cmd let () = if !Sys.interactive then () else exit (main ())