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
open Client_keys_v0
open Tezos_sapling.Core.Client
module Mnemonic = struct
let new_random = Bip39.of_entropy (Tezos_crypto.Hacl.Rand.gen 32)
let to_sapling_key mnemonic =
let seed_64_to_seed_32 (seed_64 : bytes) : bytes =
assert (Bytes.length seed_64 = 64) ;
let first_32 = Bytes.sub seed_64 0 32 in
let second_32 = Bytes.sub seed_64 32 32 in
let seed_32 = Bytes.create 32 in
for i = 0 to 31 do
Bytes.set
seed_32
i
(Char.chr
(Char.code (Bytes.get first_32 i)
lxor Char.code (Bytes.get second_32 i)))
done ;
seed_32
in
Spending_key.of_seed (seed_64_to_seed_32 (Bip39.to_seed mnemonic))
let words_pp = Format.(pp_print_list ~pp_sep:pp_print_space pp_print_string)
end
let to_uri unencrypted cctxt sapling_key =
if unencrypted then
Tezos_signer_backends.Unencrypted.make_sapling_key sapling_key >>?= return
else Tezos_signer_backends.Encrypted.encrypt_sapling_key cctxt sapling_key
(** Transform an uri into a spending key, asking for a password if the uri was
encrypted. *)
let from_uri (cctxt : #Client_context.full) uri =
Tezos_signer_backends.Encrypted.decrypt_sapling_key cctxt uri
let register (cctxt : #Client_context.full) ?(force = false)
?(unencrypted = false) mnemonic name =
let sk = Mnemonic.to_sapling_key mnemonic in
to_uri unencrypted cctxt sk >>=? fun sk_uri ->
let key =
{
sk = sk_uri;
path = [Spending_key.child_index sk];
address_index = Viewing_key.default_index;
}
in
Sapling_key.add ~force cctxt name key >>=? fun () ->
return @@ Viewing_key.of_sk sk
let derive (cctxt : #Client_context.full) ?(force = false)
?(unencrypted = false) src_name dst_name child_index =
Sapling_key.find cctxt src_name >>=? fun k ->
from_uri cctxt k.sk >>=? fun src_sk ->
let child_index = Int32.of_int child_index in
let dst_sk = Spending_key.derive_key src_sk child_index in
to_uri unencrypted cctxt dst_sk >>=? fun dst_sk_uri ->
let dst_key =
{
sk = dst_sk_uri;
path = child_index :: k.path;
address_index = Viewing_key.default_index;
}
in
let _ = force in
Sapling_key.add ~force:true cctxt dst_name dst_key >>=? fun () ->
let path =
String.concat "/" (List.map Int32.to_string (List.rev dst_key.path))
in
return (path, Viewing_key.of_sk dst_sk)
let find_vk cctxt name =
Sapling_key.find cctxt name >>=? fun k ->
from_uri cctxt k.sk >>=? fun sk -> return (Viewing_key.of_sk sk)
let new_address (cctxt : #Client_context.full) name index_opt =
Sapling_key.find cctxt name >>=? fun k ->
let index =
match index_opt with
| None -> k.address_index
| Some i -> Viewing_key.index_of_int64 (Int64.of_int i)
in
from_uri cctxt k.sk >>=? fun sk ->
return (Viewing_key.of_sk sk) >>=? fun vk ->
let corrected_index, address = Viewing_key.new_address vk index in
Sapling_key.update
cctxt
name
{k with address_index = Viewing_key.index_succ corrected_index}
>>=? fun () -> return (sk, corrected_index, address)
let export_vk cctxt name =
find_vk cctxt name >>=? fun vk ->
return (Data_encoding.Json.construct Viewing_key.encoding vk)