1 /** 
2 * Wallet records to store the wallet information
3 */
4 module tagion.wallet.WalletRecords;
5 
6 import tagion.basic.Types : Buffer;
7 import tagion.crypto.SecureInterfaceNet : HashNet;
8 import tagion.crypto.Types : Pubkey;
9 import tagion.dart.DARTBasic;
10 import tagion.hibon.Document : Document;
11 import tagion.hibon.HiBONRecord;
12 import tagion.wallet.Basic : saltHash;
13 import tagion.wallet.KeyRecover : KeyRecover;
14 
15 /// Contains the quiz question
16 @safe
17 @recordType("Quiz")
18 struct Quiz {
19     @label("$Q") string[] questions; /// List of questions
20     mixin HiBONRecord;
21 }
22 
23 /// Devices recovery for the pincode
24 @safe
25 @recordType("PIN")
26 struct DevicePIN {
27     Buffer D; /// Device number
28     Buffer U; /// Device random
29     Buffer S; /// Check sum value
30     bool recover(
31             const HashNet net,
32             ref scope ubyte[] R,
33             scope const(ubyte[]) P) const {
34         import tagion.utils.Miscellaneous : xor;
35 
36         const pinhash = net.saltHash(P, U);
37         xor(R, D, pinhash);
38         return S == net.saltHash(R);
39     }
40 
41     void setPin(
42             scope const HashNet net,
43             scope const(ubyte[]) R,
44     scope const(ubyte[]) P,
45     Buffer salt) scope {
46         import tagion.utils.Miscellaneous : xor;
47 
48         U = salt;
49         const pinhash = net.saltHash(P, U);
50         D = xor(R, pinhash);
51         S = net.saltHash(R);
52 
53     }
54 
55     mixin HiBONRecord;
56 }
57 
58 @safe
59 unittest {
60     import std.array;
61     import std.random;
62     import std.range;
63     import std.string : representation;
64     import tagion.crypto.SecureNet : StdHashNet;
65     import tagion.hibon.HiBONJSON;
66     import tagion.utils.Miscellaneous;
67 
68     auto rnd = Random(unpredictableSeed);
69     auto rnd_range = generate!(() => uniform!ubyte(rnd));
70     const net = new StdHashNet;
71     //auto R=new ubyte[net.hashSize];
72     {
73         auto salt = iota(ubyte(0), ubyte(net.hashSize & ubyte.max)).array.idup;
74         const R = rnd_range.take(net.hashSize).array;
75         DevicePIN pin;
76         const pin_code = "1234".representation;
77         pin.setPin(net, R, pin_code, salt);
78 
79         ubyte[] recovered_R = new ubyte[net.hashSize];
80         { /// Recover the seed R with the correct pin-code 
81             const recovered = pin.recover(net, recovered_R, pin_code);
82             assert(recovered);
83             assert(R == recovered_R);
84         }
85 
86         { /// Try to recover the seed R with the wrong pin-code 
87             const recovered = pin.recover(net, recovered_R, "wrong pin code".representation);
88             assert(!recovered);
89             assert(R != recovered_R);
90         }
91 
92     }
93 }
94 /// Key-pair recovery generator
95 @safe
96 @recordType("Wallet")
97 struct RecoverGenerator {
98     Buffer[] Y; /// Recorvery seed
99     Buffer S; /// Check value S=H(H(R))
100     @label("N") uint confidence; /// Confidence of the correct answers
101     mixin HiBONRecord;
102 }