package ledgerwallet-tezos
Ledger wallet library for OCaml: Tezos app
Install
Dune Dependency
Authors
Maintainers
Sources
0.4.1.tar.gz
sha256=d147a3a94679e4d95cc7f98cdf696eda435dcec36ccf7a9759eeb9bdfb9e6b9d
sha512=cc81784f5bea5af3608ab1cc0b38e4ebc9cb35d01077e844e7d7022ca84b7f5c294c00c84e4ddad1b08c7cdaf0aa1b76bebde59045ed88d6fdf7b9868d884bc4
doc/src/ledgerwallet-tezos/ledgerwallet_tezos.ml.html
Source file ledgerwallet_tezos.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
(*--------------------------------------------------------------------------- Copyright (c) 2017 Vincent Bernardoff. All rights reserved. Distributed under the ISC license, see terms at the end of the file. ---------------------------------------------------------------------------*) open Lwt_result open Lwt_result.Infix open Ledgerwallet module Version = struct type app_class = Tezos | TezBake let pp_app_class ppf = function | Tezos -> Format.pp_print_string ppf "Tezos Wallet" | TezBake -> Format.pp_print_string ppf "Tezos Baking" let class_of_int = function | 0 -> Tezos | 1 -> TezBake | _ -> invalid_arg "class_of_int" type t = {app_class : app_class; major : int; minor : int; patch : int} let pp ppf {app_class; major; minor; patch} = Format.fprintf ppf "%a %d.%d.%d" pp_app_class app_class major minor patch let create ~app_class ~major ~minor ~patch = {app_class; major; minor; patch} type Status.t += Tezos_impossible_to_read_version let () = Status.register_string_f (function | Tezos_impossible_to_read_version -> Some "Impossible to read version" | _ -> None) let read cs = try let app_class = class_of_int (Cstruct.get_uint8 cs 0) in let major = Cstruct.get_uint8 cs 1 in let minor = Cstruct.get_uint8 cs 2 in let patch = Cstruct.get_uint8 cs 3 in return (create ~app_class ~major ~minor ~patch) with _ -> Lwt.return (Transport.app_error ~msg:"Version.read" (Error Tezos_impossible_to_read_version)) end type ins = | Version | Git_commit | Authorize_baking | Get_public_key | Prompt_public_key | Sign | Sign_unsafe | Reset_high_watermark | Query_high_watermark | Setup | Query_all_high_watermarks | Make_deterministic_nonce | Sign_with_hash let int_of_ins = function | Version -> 0x00 | Authorize_baking -> 0x01 | Get_public_key -> 0x02 | Prompt_public_key -> 0x03 | Sign -> 0x04 | Sign_unsafe -> 0x05 | Reset_high_watermark -> 0x06 | Query_high_watermark -> 0x08 | Git_commit -> 0x09 | Get_authorized_key -> 0x07 | Setup -> 0x0A | Query_all_high_watermarks -> 0x0B | Deauthorize_baking -> 0x0C | Get_authorized_path_and_curve -> 0x0D | Make_deterministic_nonce -> 0x0E | Sign_with_hash -> 0x0F type curve = Ed25519 | Secp256k1 | Secp256r1 | Bip32_ed25519 let pp_curve ppf = function | Ed25519 -> Format.pp_print_string ppf "ed25519" | Secp256k1 -> Format.pp_print_string ppf "secp256k1" | Secp256r1 -> Format.pp_print_string ppf "P-256" | Bip32_ed25519 -> Format.pp_print_string ppf "bip25519" let pp_curve_short ppf = function | Ed25519 -> Format.pp_print_string ppf "ed" | Secp256k1 -> Format.pp_print_string ppf "secp" | Secp256r1 -> Format.pp_print_string ppf "p2" | Bip32_ed25519 -> Format.pp_print_string ppf "bip25519" let curve_of_string str = match String.lowercase_ascii str with | "ed" | "ed25519" -> Some Ed25519 | "bip25519" | "bip32-ed25519" -> Some Bip32_ed25519 | "secp256k1" -> Some Secp256k1 | "p256" | "p-256" | "secp256r1" -> Some Secp256r1 | _ -> None let int_of_curve = function | Ed25519 -> 0x00 | Secp256k1 -> 0x01 | Secp256r1 -> 0x02 | Bip32_ed25519 -> 0x03 let curve_of_int = function | 0x00 -> Some Ed25519 | 0x01 -> Some Secp256k1 | 0x02 -> Some Secp256r1 | 0x03 -> Some Bip32_ed25519 | _ -> None type Status.t += Tezos_invalid_curve_code of int | Payload_too_big of int let () = Status.register_string_f (function | Tezos_invalid_curve_code curve_code -> Some ("Unrecognized curve code: " ^ string_of_int curve_code) | Payload_too_big size -> Some (Printf.sprintf "Payload too big: %d bytes" size) | _ -> None) let () = Status.register_help_suggestor_f (function | Status.Conditions_of_use_not_satisfied -> Some "Either you rejected the operation or you waited long enough to \ respond that the device rejected it for you." | Status.Incorrect_class -> Some "A Tezos application wasn't found on the device. Is the Tezos \ Wallet or Tezos Baking application open on the device? Is the \ device busy talking to another process?" | Status.Security_status_unsatisfied -> Some "The operation was automatically rejected for security reasons. If \ baking, you may need to setup the device or reset the high-water \ mark." | _ -> None) let wrap_ins cmd = Apdu.create_cmd ~cmd ~cla_of_cmd:(fun _ -> 0x80) ~ins_of_cmd:int_of_ins let get_version ?pp ?buf h = let apdu = Apdu.create (wrap_ins Version) in Transport.apdu ~msg:"get_version" ?pp ?buf h apdu >>= Version.read let get_git_commit ?pp ?buf h = let apdu = Apdu.create (wrap_ins Git_commit) in Transport.apdu ~msg:"get_git_commit" ?pp ?buf h apdu >|= Cstruct.to_string let read_path_with_length buf = let length = Cstruct.get_uint8 buf 0 in let rec go acc path = if Cstruct.length path = 0 || List.length acc = length then List.rev acc else go (Cstruct.BE.get_uint32 path 0 :: acc) (Cstruct.shift path 4) in go [] (Cstruct.shift buf 1) let ?pp ?buf h = let apdu = Apdu.create (wrap_ins Get_authorized_key) in Transport.apdu ~msg:"get_authorized_key" ?pp ?buf h apdu >|= fun path -> read_path_with_length path let ?pp ?buf h = let apdu = Apdu.create (wrap_ins Get_authorized_path_and_curve) in Transport.apdu ~msg:"get_authorized_path_and_curve" ?pp ?buf h apdu >>= fun payload -> let curve_code = Cstruct.get_uint8 payload 0 in match curve_of_int curve_code with | None -> Lwt.return (Transport.app_error ~msg:"get_authorized_path_and_curve" (Error (Tezos_invalid_curve_code curve_code))) | Some curve -> let path_components = read_path_with_length (Cstruct.shift payload 1) in return (path_components, curve) let write_path cs path = ListLabels.fold_left path ~init:cs ~f:(fun cs i -> Cstruct.BE.set_uint32 cs 0 i ; Cstruct.shift cs 4) let get_public_key_like cmd ?pp ?buf h curve path = let nb_derivations = List.length path in if nb_derivations > 10 then invalid_arg "get_public_key: max 10 derivations" ; let lc = 1 + (4 * nb_derivations) in let data_init = Cstruct.create lc in Cstruct.set_uint8 data_init 0 nb_derivations ; let data = Cstruct.shift data_init 1 in let _data = write_path data path in let msg = "get_public_key" in let apdu = Apdu.create ~p2:(int_of_curve curve) ~lc ~data:data_init (wrap_ins cmd) in Transport.apdu ~msg ?pp ?buf h apdu >|= fun addr -> let keylen = Cstruct.get_uint8 addr 0 in Cstruct.sub addr 1 keylen let get_public_key ?(prompt = true) = let cmd = if prompt then Prompt_public_key else Get_public_key in get_public_key_like cmd let = get_public_key_like Authorize_baking let setup_baking ?pp ?buf h ~main_chain_id ~main_hwm ~test_hwm curve path = let nb_derivations = List.length path in if nb_derivations > 10 then invalid_arg "Ledgerwallet_tezos.setup: max 10 derivations" ; let lc = (* [ chain-id | main-hwm | test-hwm | derivations-path ] *) (* derivations-path = [ length | paths ] *) (3 * 4) + 1 + (4 * nb_derivations) in let data_init = Cstruct.create lc in (* If the size of chain-ids changes, then all assumptions of this binary format are broken (the ledger expects a uint32). *) assert (String.length main_chain_id = 4) ; for ith = 0 to 3 do Cstruct.set_uint8 data_init ith (int_of_char main_chain_id.[ith]) done ; Cstruct.BE.set_uint32 data_init 4 main_hwm ; Cstruct.BE.set_uint32 data_init 8 test_hwm ; Cstruct.set_uint8 data_init 12 nb_derivations ; let (_ : Cstruct.t) = let data = Cstruct.shift data_init (12 + 1) in write_path data path in let msg = "setup" in let apdu = Apdu.create ~p2:(int_of_curve curve) ~lc ~data:data_init (wrap_ins Setup) in Transport.apdu ~msg ?pp ?buf h apdu >|= fun addr -> let keylen = Cstruct.get_uint8 addr 0 in Cstruct.sub addr 1 keylen let ?pp ?buf h = let apdu = Apdu.create (wrap_ins Deauthorize_baking) in Transport.apdu ~msg:"deauthorize_baking" ?pp ?buf h apdu >|= fun _ -> () let get_high_watermark ?pp ?buf h = let apdu = Apdu.create (wrap_ins Query_high_watermark) in Transport.apdu ~msg:"get_high_watermark" ?pp ?buf h apdu >|= fun data -> let has_migrated_to_tenderbake = Cstruct.length data >= 8 in if has_migrated_to_tenderbake then (Cstruct.BE.get_uint32 data 0, Some (Cstruct.BE.get_uint32 data 4)) else (Cstruct.BE.get_uint32 data 0, None) let get_all_high_watermarks ?pp ?buf h = let apdu = Apdu.create (wrap_ins Query_all_high_watermarks) in Transport.apdu ~msg:"get_high_watermark" ?pp ?buf h apdu >|= fun data -> let has_migrated_to_tenderbake = Cstruct.length data >= 20 in if has_migrated_to_tenderbake then let main_hwm = Cstruct.BE.get_uint32 data 0 in let main_hwm_round = Cstruct.BE.get_uint32 data 4 in let test_hwm = Cstruct.BE.get_uint32 data 8 in let test_hwm_round = Cstruct.BE.get_uint32 data 12 in let chain_id = Cstruct.to_string data ~off:16 ~len:4 in ( `Main_hwm (main_hwm, Some main_hwm_round), `Test_hwm (test_hwm, Some test_hwm_round), `Chain_id chain_id ) else let main_hwm = Cstruct.BE.get_uint32 data 0 in let test_hwm = Cstruct.BE.get_uint32 data 4 in let chain_id = Cstruct.to_string data ~off:8 ~len:4 in (`Main_hwm (main_hwm, None), `Test_hwm (test_hwm, None), `Chain_id chain_id) let set_high_watermark ?pp ?buf h hwm = let data = Cstruct.create 4 in Cstruct.BE.set_uint32 data 0 hwm ; let apdu = Apdu.create ~lc:4 ~data (wrap_ins Reset_high_watermark) in Transport.apdu ~msg:"set_high_watermark" ?pp ?buf h apdu >|= ignore let sign ?pp ?buf ?(hash_on_ledger = true) h curve path payload = let nb_derivations = List.length path in if nb_derivations > 10 then invalid_arg "get_public_key: max 10 derivations" ; let lc = 1 + (4 * nb_derivations) in let data_init = Cstruct.create lc in Cstruct.set_uint8 data_init 0 nb_derivations ; let data = Cstruct.shift data_init 1 in let _data = write_path data path in let cmd = wrap_ins (if hash_on_ledger then Sign else Sign_unsafe) in let msg = "sign" in let apdu = Apdu.create ~p2:(int_of_curve curve) ~lc ~data:data_init cmd in Transport.apdu ~msg ?pp ?buf h apdu >>= fun _addr -> Transport.write_payload ~mark_last:true ?pp ?buf ~msg ~cmd h ~p1:0x01 payload let get_deterministic_nonce ?pp ?buf h curve path payload = let nb_derivations = List.length path in if nb_derivations > 10 then invalid_arg "get_deterministic_nonce: max 10 derivations" ; let path_data = let lc = 1 + (4 * nb_derivations) in let data = Cstruct.create lc in Cstruct.set_uint8 data 0 nb_derivations ; let _ = write_path (Cstruct.shift data 1) path in data in let data = Cstruct.append path_data payload in let cmd = wrap_ins Make_deterministic_nonce in let lc = Cstruct.length data in if lc >= Apdu.max_data_length then Lwt.return (Transport.app_error ~msg:"get_deterministic_nonce" (Error (Payload_too_big (Cstruct.length payload)))) else let apdu = Apdu.create ~p2:(int_of_curve curve) ~lc ~data cmd in let msg = "make-deterministic-nonce" in Transport.apdu ~msg ?pp ?buf h apdu let sign_and_hash ?pp ?buf h curve path payload = let nb_derivations = List.length path in if nb_derivations > 10 then invalid_arg "get_public_key: max 10 derivations" ; let lc = 1 + (4 * nb_derivations) in let data_init = Cstruct.create lc in Cstruct.set_uint8 data_init 0 nb_derivations ; let data = Cstruct.shift data_init 1 in let _data = write_path data path in let cmd = wrap_ins Sign_with_hash in let msg = "sign-with-hash" in let apdu = Apdu.create ~p2:(int_of_curve curve) ~lc ~data:data_init cmd in Transport.apdu ~msg ?pp ?buf h apdu >>= fun _apdu -> Transport.write_payload ~mark_last:true ?pp ?buf ~msg ~cmd h ~p1:0x01 payload >>= fun bytes -> let hash, signature = Cstruct.split bytes 32 in return (hash, signature) (*--------------------------------------------------------------------------- Copyright (c) 2017 Vincent Bernardoff Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ---------------------------------------------------------------------------*)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>