Vendors: import ocaml-ledger-wallet

This commit is contained in:
Vincent Bernardoff 2018-05-30 18:04:50 +02:00 committed by Benjamin Canou
parent 8bc9695ad0
commit 3a2a11d888
12 changed files with 703 additions and 0 deletions

13
vendors/ocaml-ledger-wallet/LICENSE.md vendored Normal file
View File

@ -0,0 +1,13 @@
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.

View File

@ -0,0 +1,20 @@
opam-version: "1.2"
name: "ledgerwallet-tezos"
version: "dev"
authors: "Vincent Bernardoff <vb@luminar.eu.org>"
maintainer: "Vincent Bernardoff <vb@luminar.eu.org>"
license: "ISC"
homepage: "https://github.com/vbmithr/ocaml-ledger-wallet"
bug-reports: "https://github.com/vbmithr/ocaml-ledger-wallet/issues"
dev-repo: "git://github.com/vbmithr/ocaml-ledger-wallet"
available: [
ocaml-version >= "4.02.0"
]
build: [ "jbuilder" "build" "-j" jobs "-p" name "@install" ]
build-test: [ "jbuilder" "runtest" "-p" name "-j" jobs ]
depends: [
"jbuilder" {build & >= "1.0+beta16"}
"ledgerwallet" {= "dev"}
]

View File

@ -0,0 +1,22 @@
opam-version: "1.2"
name: "ledgerwallet"
version: "dev"
authors: "Vincent Bernardoff <vb@luminar.eu.org>"
maintainer: "Vincent Bernardoff <vb@luminar.eu.org>"
license: "ISC"
homepage: "https://github.com/vbmithr/ocaml-ledger-wallet"
bug-reports: "https://github.com/vbmithr/ocaml-ledger-wallet/issues"
dev-repo: "git://github.com/vbmithr/ocaml-ledger-wallet"
available: [
ocaml-version >= "4.02.0"
]
build: [ "jbuilder" "build" "-j" jobs "-p" name "@install" ]
build-test: [ "jbuilder" "runtest" "-p" name "-j" jobs ]
depends: [
"jbuilder" {build & >= "1.0+beta16"}
"result" {>= "1.3"}
"cstruct" {>= "3.2.1"}
"hidapi" {>= "1.0"}
]

61
vendors/ocaml-ledger-wallet/src/apdu.ml vendored Normal file
View File

@ -0,0 +1,61 @@
(*---------------------------------------------------------------------------
Copyright (c) 2017 Vincent Bernardoff. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)
type cmd = Apdu_command : {
cmd : 'a ;
cla_of_cmd : 'a -> int ;
ins_of_cmd : 'a -> int ;
} -> cmd
let create_cmd ~cmd ~cla_of_cmd ~ins_of_cmd =
Apdu_command { cmd ; cla_of_cmd ; ins_of_cmd }
type t = {
cmd : cmd ;
p1 : int ;
p2 : int ;
lc : int ;
le : int ;
data : Cstruct.t ;
}
let max_data_length = 230
let create ?(p1=0) ?(p2=0) ?(lc=0) ?(le=0) ?(data=Cstruct.create 0) cmd =
{ cmd ; p1 ; p2 ; lc ; le ; data }
let create_string ?(p1=0) ?(p2=0) ?(lc=0) ?(le=0) ?(data="") cmd =
let data = Cstruct.of_string data in
{ cmd ; p1 ; p2 ; lc ; le ; data }
let length { data ; _ } = 5 + Cstruct.len data
let write cs { cmd = Apdu_command { cmd ; cla_of_cmd ; ins_of_cmd } ;
p1 ; p2 ; lc ; le ; data } =
let len = match lc, le with | 0, _ -> le | _ -> lc in
let datalen = Cstruct.len data in
Cstruct.set_uint8 cs 0 (cla_of_cmd cmd) ;
Cstruct.set_uint8 cs 1 (ins_of_cmd cmd) ;
Cstruct.set_uint8 cs 2 p1 ;
Cstruct.set_uint8 cs 3 p2 ;
Cstruct.set_uint8 cs 4 len ;
Cstruct.blit data 0 cs 5 datalen ;
Cstruct.shift cs (5 + datalen)
(*---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------*)

View File

@ -0,0 +1,55 @@
(*---------------------------------------------------------------------------
Copyright (c) 2017 Vincent Bernardoff. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)
type cmd = Apdu_command : {
cmd : 'a ;
cla_of_cmd : 'a -> int ;
ins_of_cmd : 'a -> int ;
} -> cmd
(** Arbitrary type of a command, with its converters. *)
val create_cmd :
cmd:'a -> cla_of_cmd:('a -> int) -> ins_of_cmd:('a -> int) -> cmd
type t = {
cmd : cmd ;
p1 : int ;
p2 : int ;
lc : int ;
le : int ;
data : Cstruct.t ;
}
(** Type of an ADPU. *)
val max_data_length : int
(** [max_data_length] is the maximum data length of an APDU. *)
val create :
?p1:int -> ?p2:int -> ?lc:int -> ?le:int -> ?data:Cstruct.t -> cmd -> t
val create_string :
?p1:int -> ?p2:int -> ?lc:int -> ?le:int -> ?data:string -> cmd -> t
val length : t -> int
(** [length t] is the size of [t] in bytes. *)
val write : Cstruct.t -> t -> Cstruct.t
(** [write cs t] writes t at [cs] and returns [cs] shifted by [length
t] bytes. *)
(*---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------*)

15
vendors/ocaml-ledger-wallet/src/jbuild vendored Normal file
View File

@ -0,0 +1,15 @@
(jbuild_version 1)
(library
((name ledgerwallet)
(public_name ledgerwallet)
(modules (Apdu Transport))
(synopsis "Ledger wallet library for OCaml: common parts")
(libraries (result cstruct hidapi))))
(library
((name ledgerwallet_tezos)
(public_name ledgerwallet-tezos)
(modules (Ledgerwallet_tezos))
(synopsis "Ledger wallet library for OCaml: Tezos app")
(libraries (ledgerwallet))))

View File

@ -0,0 +1,78 @@
(*---------------------------------------------------------------------------
Copyright (c) 2017 Vincent Bernardoff. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)
open Ledgerwallet
type ins =
| Get_public_key
| Sign
let int_of_ins = function
| Get_public_key -> 0x02
| Sign -> 0x04
type curve =
| Ed25519
| Secp256k1
| Secp256r1
let int_of_curve = function
| Ed25519 -> 0x00
| Secp256k1 -> 0x01
| Secp256r1 -> 0x02
let wrap_ins cmd =
Apdu.create_cmd ~cmd ~cla_of_cmd:(fun _ -> 0x80) ~ins_of_cmd:int_of_ins
let write_path cs path =
ListLabels.fold_left path ~init:cs ~f:begin fun cs i ->
Cstruct.BE.set_uint32 cs 0 i ;
Cstruct.shift cs 4
end
let get_public_key ?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 = "Tezos.get_public_key" in
let apdu = Apdu.create ~p2:(int_of_curve curve)
~lc ~data:data_init (wrap_ins Get_public_key) in
let addr = Transport.apdu ~msg ?pp ?buf h apdu in
let keylen = Cstruct.get_uint8 addr 0 in
Cstruct.sub addr 1 keylen
let sign ?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 in
let msg = "Tezos.sign" in
let apdu = Apdu.create ~p2:(int_of_curve curve) ~lc ~data:data_init cmd in
let _addr = Transport.apdu ~msg ?pp ?buf h apdu in
Transport.write_payload ~mark_last:true ?pp ?buf ~msg ~cmd h ~p1:0x01 payload
(*---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------*)

View File

@ -0,0 +1,37 @@
(*---------------------------------------------------------------------------
Copyright (c) 2017 Vincent Bernardoff. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)
type curve =
| Ed25519
| Secp256k1
| Secp256r1
val get_public_key :
?pp:Format.formatter -> ?buf:Cstruct.t ->
Hidapi.t -> curve -> int32 list -> Cstruct.t
(** [get_public_key ?pp ?buf ledger curve path] is [0x02 || pk] from
[ledger] at [path] for curve [curve]. *)
val sign :
?pp:Format.formatter -> ?buf:Cstruct.t ->
Hidapi.t -> curve -> int32 list -> Cstruct.t -> Cstruct.t
(** [sign ?pp ?buf h curve path payload] is [signature], signed from
[ledger] with key from curve [curve] at [path]. *)
(*---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------*)

View File

@ -0,0 +1,248 @@
(*---------------------------------------------------------------------------
Copyright (c) 2017 Vincent Bernardoff. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)
let packet_length = 64
let channel = 0x0101
let apdu = 0x05
let ping = 0x02
module Status = struct
type t =
| Invalid_pin of int
| Incorrect_length
| Incompatible_file_structure
| Security_status_unsatisfied
| Conditions_of_use_not_satisfied
| Incorrect_data
| File_not_found
| Incorrect_params
| Ins_not_supported
| Technical_problem of int
| Ok
let of_int = function
| 0x6700 -> Incorrect_length
| 0x6981 -> Incompatible_file_structure
| 0x6982 -> Security_status_unsatisfied
| 0x6985 -> Conditions_of_use_not_satisfied
| 0x6a80 -> Incorrect_data
| 0x9404 -> File_not_found
| 0x6b00 -> Incorrect_params
| 0x6d00 -> Ins_not_supported
| 0x9000 -> Ok
| v when v >= 0x63c0 && v <= 0x63cf -> Invalid_pin (v land 0x0f)
| v when v >= 0x6f00 && v <= 0x6fff -> Technical_problem (v land 0xff)
| v -> invalid_arg (Printf.sprintf "Status.of_int: got 0x%x" v)
let to_string = function
| Invalid_pin i -> Printf.sprintf "Invalid pin %d" i
| Incorrect_length -> "Incorrect length"
| Incompatible_file_structure -> "Incompatible file structure"
| Security_status_unsatisfied -> "Security status unsatisfied"
| Conditions_of_use_not_satisfied -> "Conditions of use not satisfied"
| Incorrect_data -> "Incorrect data"
| File_not_found -> "File not found"
| Incorrect_params -> "Incorrect params"
| Ins_not_supported -> "Instruction not supported"
| Technical_problem i -> Printf.sprintf "Technical problem %d" i
| Ok -> "Ok"
let show t = to_string t
let pp ppf t =
Format.pp_print_string ppf (to_string t)
end
module Header = struct
type t = {
cmd : [`Ping | `Apdu] ;
seq : int ;
}
let read cs =
let open Cstruct in
if BE.get_uint16 cs 0 <> channel then
invalid_arg "Transport.read_header: invalid channel id" ;
let cmd = match get_uint8 cs 2 with
| 0x05 -> `Apdu
| 0x02 -> `Ping
| _ -> invalid_arg "Transport.read_header: invalid command tag"
in
let seq = BE.get_uint16 cs 3 in
{ cmd ; seq }, Cstruct.shift cs 5
let check_exn ?cmd ?seq t =
begin match cmd with
| None -> ()
| Some expected ->
if expected <> t.cmd then failwith "Header.check: unexpected command"
end ;
begin match seq with
| None -> ()
| Some expected ->
if expected <> t.seq then failwith "Header.check: unexpected seq num"
end
end
let write_ping ?(buf=Cstruct.create packet_length) h =
let open Cstruct in
BE.set_uint16 buf 0 channel ;
set_uint8 buf 2 ping ;
BE.set_uint16 buf 3 0 ;
memset (sub buf 5 59) 0 ;
match Hidapi.write h (to_bigarray (sub buf 0 packet_length)) with
| Error msg -> failwith msg
| Ok nb_written when nb_written <> packet_length -> failwith "Transport.write_ping"
| _ -> ()
let write_apdu
?pp
?(buf=Cstruct.create packet_length)
h p =
let apdu_len = Apdu.length p in
let apdu_buf = Cstruct.create apdu_len in
let _nb_written = Apdu.write apdu_buf p in
begin match pp with
| None -> ()
| Some pp ->
Format.fprintf pp "-> %a@." Cstruct.hexdump_pp apdu_buf
end ;
let apdu_p = ref 0 in (* pos in the apdu buf *)
let i = ref 0 in (* packet id *)
let open Cstruct in
(* write first packet *)
BE.set_uint16 buf 0 channel ;
set_uint8 buf 2 apdu ;
BE.set_uint16 buf 3 !i ;
BE.set_uint16 buf 5 apdu_len ;
let nb_to_write = (min apdu_len (packet_length - 7)) in
blit apdu_buf 0 buf 7 nb_to_write ;
begin match Hidapi.write h (to_bigarray (sub buf 0 packet_length)) with
| Error msg -> failwith msg
| Ok nb_written when nb_written <> packet_length ->
failwith "Transport.write_apdu"
| _ -> ()
end ;
apdu_p := !apdu_p + nb_to_write ;
incr i ;
(* write following packets *)
while !apdu_p < apdu_len do
memset buf 0 ;
BE.set_uint16 buf 0 channel ;
set_uint8 buf 2 apdu ;
BE.set_uint16 buf 3 !i ;
let nb_to_write = (min (apdu_len - !apdu_p) (packet_length - 5)) in
blit apdu_buf !apdu_p buf 5 nb_to_write ;
begin match Hidapi.write h (to_bigarray (sub buf 0 packet_length)) with
| Error err -> failwith err
| Ok nb_written when nb_written <> packet_length ->
failwith "Transport.write_apdu"
| _ -> ()
end ;
apdu_p := !apdu_p + nb_to_write ;
incr i
done
let read ?(buf=Cstruct.create packet_length) h =
let expected_seq = ref 0 in
let full_payload = ref (Cstruct.create 0) in
let payload = ref (Cstruct.create 0) in
(* let pos = ref 0 in *)
let rec inner () =
begin match Hidapi.read ~timeout:600000 h
(Cstruct.to_bigarray buf) packet_length with
| Error err -> failwith err
| Ok nb_read when nb_read <> packet_length ->
failwith (Printf.sprintf "Transport.read: read %d bytes" nb_read)
| _ -> ()
end ;
let hdr, buf = Header.read buf in
Header.check_exn ~seq:!expected_seq hdr ;
if hdr.seq = 0 then begin (* first frame *)
let len = Cstruct.BE.get_uint16 buf 0 in
let cs = Cstruct.shift buf 2 in
payload := Cstruct.create len ;
full_payload := !payload ;
let nb_to_read = min len (packet_length - 7) in
Cstruct.blit cs 0 !payload 0 nb_to_read ;
payload := Cstruct.shift !payload nb_to_read ;
(* pos := !pos + nb_to_read ; *)
expected_seq := !expected_seq + 1 ;
end else begin (* next frames *)
(* let rem = Bytes.length !payload - !pos in *)
let nb_to_read = min (Cstruct.len !payload) (packet_length - 5) in
Cstruct.blit buf 0 !payload 0 nb_to_read ;
payload := Cstruct.shift !payload nb_to_read ;
(* pos := !pos + nb_to_read ; *)
expected_seq := !expected_seq + 1
end ;
if Cstruct.len !payload = 0 then
if hdr.cmd = `Ping then Status.Ok, Cstruct.create 0
else
(* let sw_pos = Bytes.length !payload - 2 in *)
let payload_len = Cstruct.len !full_payload in
Status.of_int Cstruct.(BE.get_uint16 !full_payload (payload_len - 2)),
Cstruct.sub !full_payload 0 (payload_len - 2)
else inner ()
in
inner ()
let ping ?buf h =
write_ping ?buf h ;
match read ?buf h with
| Status.Ok, _ -> ()
| s, _ -> failwith ((Status.to_string s))
let apdu ?pp ?(msg="") ?buf h apdu =
write_apdu ?pp ?buf h apdu ;
match read ?buf h with
| Status.Ok, payload ->
begin match pp with
| None -> ()
| Some pp ->
Format.fprintf pp "<- %a %a@." Status.pp Status.Ok Cstruct.hexdump_pp payload
end ;
payload
| s, payload ->
begin match pp with
| None -> ()
| Some pp ->
Format.fprintf pp "<- %a %a@." Status.pp s Cstruct.hexdump_pp payload
end ;
failwith ((Status.to_string s) ^ " " ^ msg)
let write_payload
?pp ?(msg="write_payload") ?buf ?(mark_last=false) ~cmd ?p1 ?p2 h cs =
let rec inner cs =
let cs_len = Cstruct.len cs in
let lc = min Apdu.max_data_length cs_len in
let last = lc = cs_len in
let p1 = match last, mark_last, p1 with
| true, true, None -> Some 0x80
| true, true, Some p1 -> Some (0x80 lor p1)
| _ -> p1 in
let response = apdu ?pp ~msg ?buf h
Apdu.(create ?p1 ?p2 ~lc ~data:(Cstruct.sub cs 0 lc) cmd) in
if last then response
else inner (Cstruct.shift cs lc) in
if Cstruct.len cs = 0 then cs else inner cs
(*---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------*)

View File

@ -0,0 +1,66 @@
(*---------------------------------------------------------------------------
Copyright (c) 2017 Vincent Bernardoff. All rights reserved.
Distributed under the ISC license, see terms at the end of the file.
---------------------------------------------------------------------------*)
module Status : sig
type t =
| Invalid_pin of int
| Incorrect_length
| Incompatible_file_structure
| Security_status_unsatisfied
| Conditions_of_use_not_satisfied
| Incorrect_data
| File_not_found
| Incorrect_params
| Ins_not_supported
| Technical_problem of int
| Ok
val to_string : t -> string
val show : t -> string
val pp : Format.formatter -> t -> unit
end
val write_apdu :
?pp:Format.formatter -> ?buf:Cstruct.t ->
Hidapi.t -> Apdu.t -> unit
(** [write_apdu ?pp ?buf ledger apdu] writes [apdu] to [ledger]. *)
val read : ?buf:Cstruct.t -> Hidapi.t -> Status.t * Cstruct.t
(** [read ?buf ledger] reads from [ledger] a status response and a
payload. *)
val ping : ?buf:Cstruct.t -> Hidapi.t -> unit
(** [ping ?buf ledger] writes a ping packet to [ledger], optionally
containing [buf]. *)
val apdu :
?pp:Format.formatter -> ?msg:string -> ?buf:Cstruct.t ->
Hidapi.t -> Apdu.t -> Cstruct.t
(** [apdu ?pp ?msg ?buf ledger apdu] writes [apdu] to [ledger] and
returns the response. *)
val write_payload :
?pp:Format.formatter -> ?msg:string -> ?buf:Cstruct.t ->
?mark_last:bool -> cmd:Apdu.cmd -> ?p1:int -> ?p2:int ->
Hidapi.t -> Cstruct.t -> Cstruct.t
(** [write_payload ?pp ?msg ?buf ?mark_last ~cmd ?p1 ?p2 ledger
payload] writes the [payload] of [cmd] into [ledger] and returns
the response. *)
(*---------------------------------------------------------------------------
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.
---------------------------------------------------------------------------*)

View File

@ -0,0 +1,9 @@
(executable
((name test_tezos)
(modules (Test_tezos))
(libraries (hex alcotest ledgerwallet-tezos tweetnacl uecc))))
(alias
((name runtest-ledgerwallet-tezos)
(deps (test_tezos.exe))
(action (run ${<}))))

View File

@ -0,0 +1,79 @@
open Ledgerwallet_tezos
let vendor_id = 0x2C97
let product_id = 0x0001
let test_open_close () =
let h = Hidapi.open_id_exn ~vendor_id ~product_id in
Hidapi.close h
let test_ping () =
let h = Hidapi.open_id_exn ~vendor_id ~product_id in
Ledgerwallet.Transport.ping h ;
Hidapi.close h
let hard x =
Int32.logor x 0x8000_0000l
let path = [
hard 44l ; hard 1729l
]
let curves = [Ed25519; Secp256k1; Secp256r1]
let msg = Cstruct.of_string "Voulez-vous coucher avec moi, ce soir ?"
let msg_ba = Cstruct.to_bigarray msg
let test_getpk h curve =
let pk = get_public_key h curve path in
Alcotest.(check int "pklen"
(if curve = Ed25519 then 33 else 65) (Cstruct.len pk))
let test_getpk () =
let h = Hidapi.open_id_exn ~vendor_id ~product_id in
List.iter (test_getpk h) curves ;
Hidapi.close h
let test_sign h curve =
let open Alcotest in
let pk = get_public_key h curve path in
let signature = sign h curve path msg in
match curve with
| Ed25519 ->
let pk = Tweetnacl.Sign.(pk_of_cstruct_exn (Cstruct.sub pk 1 pkbytes)) in
check bool "sign Ed25519" true
(Tweetnacl.Sign.verify_detached ~key:pk ~signature msg)
| Secp256k1 -> begin
let pk = Cstruct.to_bigarray pk in
let signature = Cstruct.to_bigarray signature in
match Uecc.(pk_of_bytes secp256k1 pk) with
| None -> assert false
| Some pk ->
check bool "sign Secp256k1" true (Uecc.verify pk ~msg:msg_ba ~signature)
end
| Secp256r1 -> begin
let pk = Cstruct.to_bigarray pk in
let signature = Cstruct.to_bigarray signature in
match Uecc.(pk_of_bytes secp256r1 pk) with
| None -> assert false
| Some pk ->
check bool "sign Secp256r1" true (Uecc.verify pk ~msg:msg_ba ~signature)
end
let test_sign () =
let h = Hidapi.open_id_exn ~vendor_id ~product_id in
(* List.iter (test_sign h) curves ; *)
(* List.iter (test_sign h) [Secp256k1] ; *)
Hidapi.close h
let basic = [
"open_close", `Quick, test_open_close ;
"ping", `Quick, test_ping ;
"get_public_key", `Quick, test_getpk ;
"sign", `Quick, test_sign ;
]
let () =
Alcotest.run "ledgerwallet.tezos" [
"basic", basic ;
]