Compare commits
1841 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
542dcd32c7 | ||
|
|
0ef6413cd8 | ||
|
|
97d86c9571 | ||
|
|
edae8c1ee6 | ||
|
|
553405776f | ||
|
|
ad2088d231 | ||
|
|
67a5c6c270 | ||
|
|
eb112eb3a1 | ||
|
|
0d04e5e1f8 | ||
|
|
59eb529a20 | ||
|
|
d5aba396a6 | ||
|
|
6fd256dbdc | ||
|
|
6716fcbacb | ||
|
|
1dddd88525 | ||
|
|
d656f371c7 | ||
|
|
7e92e5162a | ||
|
|
74d34cfcf7 | ||
|
|
64658621bb | ||
|
|
755353f029 | ||
|
|
2981d15933 | ||
|
|
9ff3f5c447 | ||
|
|
f5a1ef32c9 | ||
|
|
841e44335e | ||
|
|
38616234e7 | ||
|
|
8e3bbfdf84 | ||
|
|
f9b65ce968 | ||
|
|
8d71040acf | ||
|
|
5feae87e03 | ||
|
|
0949c0ac86 | ||
|
|
c36eac23d2 | ||
|
|
a24a894cfd | ||
|
|
ca06dfd250 | ||
|
|
3a1ef6fe50 | ||
|
|
883be60fc5 | ||
|
|
393ebf5b43 | ||
|
|
2b5178bd63 | ||
|
|
44e7be3681 | ||
|
|
300323f18d | ||
|
|
c998432fc4 | ||
|
|
9c6cfcbbd7 | ||
|
|
be614dab92 | ||
|
|
02bd428786 | ||
|
|
6869ba87b0 | ||
|
|
d0f834570b | ||
|
|
00afe533ca | ||
|
|
621523c1a8 | ||
|
|
fdf630ab31 | ||
|
|
d2ad7a5923 | ||
|
|
29ef16be63 | ||
|
|
3344975607 | ||
|
|
15191eaaa5 | ||
|
|
717a3f591a | ||
|
|
74790ab80d | ||
|
|
50b1704c60 | ||
|
|
1e9338c550 | ||
|
|
17fc097cbd | ||
|
|
6f6563c2cb | ||
|
|
4904d38bb6 | ||
|
|
1ea83d9b70 | ||
|
|
2410897c86 | ||
|
|
6541812e20 | ||
|
|
2604f4d092 | ||
|
|
c6da2612ef | ||
|
|
538b1a6df8 | ||
|
|
2edf3c72e4 | ||
|
|
5e3f7a9321 | ||
|
|
00beed7b94 | ||
|
|
12e0af3f5c | ||
|
|
01629e1396 | ||
|
|
d893575ecf | ||
|
|
0cc6818728 | ||
|
|
b7bc614323 | ||
|
|
02b5a75675 | ||
|
|
e35f60ed5e | ||
|
|
0b425b8609 | ||
|
|
43ef951d83 | ||
|
|
38553d1ac5 | ||
|
|
9b131b2eff | ||
|
|
c19be4f41e | ||
|
|
e92a8ccde1 | ||
|
|
7d937aca84 | ||
|
|
382eef61d2 | ||
|
|
cfc46b565e | ||
|
|
45542d1d4f | ||
|
|
470fe2843c | ||
|
|
6c247d4852 | ||
|
|
6f366d1603 | ||
|
|
d53c7b2e1b | ||
|
|
598ccda8c0 | ||
|
|
1bbaeef439 | ||
|
|
eb50a0e198 | ||
|
|
08d0a70de2 | ||
|
|
a3d5d6152e | ||
|
|
9f832476eb | ||
|
|
78195d8fb9 | ||
|
|
aecc870c6b | ||
|
|
0c43c802e1 | ||
|
|
4ce43c74c6 | ||
|
|
1176c83e34 | ||
|
|
ef2f35b1fb | ||
|
|
5d7d5d881d | ||
|
|
5047512bae | ||
|
|
9862f53bec | ||
|
|
6a34760943 | ||
|
|
d0576a205f | ||
|
|
dfd52e5c03 | ||
|
|
6fd47d4c16 | ||
|
|
06879c59e0 | ||
|
|
21392bd3df | ||
|
|
e4d2326959 | ||
|
|
72e336628a | ||
|
|
7ca3baae43 | ||
|
|
89d6e226d7 | ||
|
|
f966d47012 | ||
|
|
dbf9482fea | ||
|
|
ecd796b3a5 | ||
|
|
b1fe2cca26 | ||
|
|
5d9ab62595 | ||
|
|
7dbbf29b8d | ||
|
|
722c45df0a | ||
|
|
88e4a5e8ab | ||
|
|
910c096145 | ||
|
|
a3d5485fd2 | ||
|
|
366670b4d5 | ||
|
|
0fffb07e9e | ||
|
|
4e91d2ca3f | ||
|
|
eb467988bb | ||
|
|
9fbf208c3f | ||
|
|
da1d6e28bd | ||
|
|
c1e17d3a26 | ||
|
|
a2f0eb323a | ||
|
|
53c6d33c2f | ||
|
|
a6a66bc367 | ||
|
|
386cbcbb1d | ||
|
|
d5713851ea | ||
|
|
91f96ff870 | ||
|
|
c25af2bfb1 | ||
|
|
b3cd82ed61 | ||
|
|
02ee6a58e2 | ||
|
|
192f2d2dda | ||
|
|
f235a83cf3 | ||
|
|
d34f59697c | ||
|
|
f966d3b079 | ||
|
|
6b7294cea0 | ||
|
|
efa8e1d56a | ||
|
|
946b4e9ae4 | ||
|
|
0d1104dfe0 | ||
|
|
1e371d9297 | ||
|
|
f88b8da729 | ||
|
|
52a090e31b | ||
|
|
cbd1b841b9 | ||
|
|
82fabe75d4 | ||
|
|
bc8b55a059 | ||
|
|
c54b3801ce | ||
|
|
076bb34285 | ||
|
|
48709f3329 | ||
|
|
ef0ba6a556 | ||
|
|
a08550cfd8 | ||
|
|
3e818cbbf6 | ||
|
|
fe0041f99c | ||
|
|
15e571b0d9 | ||
|
|
36521dfef9 | ||
|
|
25249eb68c | ||
|
|
be1328c720 | ||
|
|
8d6ce99cd3 | ||
|
|
fcd848d821 | ||
|
|
203394a709 | ||
|
|
284616d597 | ||
|
|
55c9ee4626 | ||
|
|
47430cb211 | ||
|
|
dd1bea1949 | ||
|
|
2aea18ba53 | ||
|
|
3c4922e3ca | ||
|
|
c6ec10206c | ||
|
|
88a9f4719b | ||
|
|
6a3eec50f1 | ||
|
|
722facf0d9 | ||
|
|
0a9d99429b | ||
|
|
d8c13ddc73 | ||
|
|
d73c1bd8d3 | ||
|
|
5764073837 | ||
|
|
259be18962 | ||
|
|
248e0b568d | ||
|
|
ca00ee0798 | ||
|
|
f3aaf3d5cb | ||
|
|
06fa4f338c | ||
|
|
2d81b7251d | ||
|
|
91f10c2f35 | ||
|
|
52e7c75539 | ||
|
|
a1e7e4c8de | ||
|
|
fce9503d0e | ||
|
|
5fc25566ee | ||
|
|
b88590f8e8 | ||
|
|
765cc2a5a4 | ||
|
|
1a591a70eb | ||
|
|
26680a00f0 | ||
|
|
429b8e645e | ||
|
|
74fd862c9c | ||
|
|
0625aa462c | ||
|
|
faa5ebf11e | ||
|
|
d0c5998e55 | ||
|
|
50d20713a0 | ||
|
|
2445b4d435 | ||
|
|
a8366f55e0 | ||
|
|
41b8167837 | ||
|
|
3461ce336d | ||
|
|
4457576ad4 | ||
|
|
038199a3e2 | ||
|
|
1929067aa1 | ||
|
|
2b115059e8 | ||
|
|
88110bc5c5 | ||
|
|
0a2c0cba12 | ||
|
|
1e9e3ffb9d | ||
|
|
863e0d85ad | ||
|
|
2109ab4ab1 | ||
|
|
e5dce7105b | ||
|
|
0237fd29ba | ||
|
|
3efeb4f1ef | ||
|
|
8b3603b15f | ||
|
|
e8ba25fd04 | ||
|
|
9e762d29a5 | ||
|
|
de043f2250 | ||
|
|
20ce5f2bae | ||
|
|
3353f3d4a4 | ||
|
|
4d2349fef4 | ||
|
|
54dcf2dce8 | ||
|
|
3291faa31e | ||
|
|
bbac20b453 | ||
|
|
98420f8ac3 | ||
|
|
5b26b306b5 | ||
|
|
a3cac15a53 | ||
|
|
c7a19ee50f | ||
|
|
e42c0631d0 | ||
|
|
609af3a257 | ||
|
|
7daa67cc63 | ||
|
|
3f24307dcd | ||
|
|
372954e43a | ||
|
|
391aea0462 | ||
|
|
ee464f4a40 | ||
|
|
54d58d4b43 | ||
|
|
4bd8d12d9d | ||
|
|
8ceb6a4602 | ||
|
|
76cc136a9e | ||
|
|
8d84979ddf | ||
|
|
bb391515a0 | ||
|
|
16c3caee28 | ||
|
|
ab1b656277 | ||
|
|
1a1daf32e3 | ||
|
|
6b1c38fe2f | ||
|
|
43544f4f96 | ||
|
|
d15de0321d | ||
|
|
0420d4b6eb | ||
|
|
00b2f67d55 | ||
|
|
6ab63b9dcf | ||
|
|
d053398a9a | ||
|
|
d9a601e87c | ||
|
|
6abb24443e | ||
|
|
9d54e261ec | ||
|
|
335df666ab | ||
|
|
7c5503d81a | ||
|
|
a4c7f95dc1 | ||
|
|
dbb2a21798 | ||
|
|
f12457cbb5 | ||
|
|
28ba1adce3 | ||
|
|
a62d5fb31e | ||
|
|
b8435fdd79 | ||
|
|
d3caf63265 | ||
|
|
c3a454abd6 | ||
|
|
73bb6b850d | ||
|
|
bc49347a69 | ||
|
|
9a4d3986b7 | ||
|
|
f89061ffbe | ||
|
|
3eb99272b3 | ||
|
|
56e5b98438 | ||
|
|
123caec8d1 | ||
|
|
637624dea9 | ||
|
|
9d5b86e39b | ||
|
|
7bd952973e | ||
|
|
aa4524339b | ||
|
|
5dd034c051 | ||
|
|
f90973af9b | ||
|
|
d71f24959c | ||
|
|
00b05e20b8 | ||
|
|
11da344abf | ||
|
|
89dfe1f6d4 | ||
|
|
81f2830425 | ||
|
|
efb445fbe3 | ||
|
|
0a899727b5 | ||
|
|
6d17350293 | ||
|
|
86d5eb890b | ||
|
|
b3b384b7d6 | ||
|
|
6dbedfaeb5 | ||
|
|
e29e0b65e3 | ||
|
|
2b750c993b | ||
|
|
17a715bfc5 | ||
|
|
15678037d5 | ||
|
|
213fdd3c57 | ||
|
|
406ab5adaa | ||
|
|
416f2efffd | ||
|
|
8aba8fe655 | ||
|
|
68d5a8fc35 | ||
|
|
170b701e94 | ||
|
|
4a0cd36c9c | ||
|
|
6a5311e8f5 | ||
|
|
20a8d14ede | ||
|
|
bab58af710 | ||
|
|
d4c4cc1b69 | ||
|
|
75a9f9f3eb | ||
|
|
e856343c66 | ||
|
|
51bbee9eb1 | ||
|
|
f40d16b76b | ||
|
|
227196da42 | ||
|
|
ea9d183a48 | ||
|
|
32cfd53569 | ||
|
|
49087f6f41 | ||
|
|
6c0ee684dc | ||
|
|
bee2f95e0a | ||
|
|
594e64affc | ||
|
|
6f3cbf20c8 | ||
|
|
7ca83c5929 | ||
|
|
3bf9c13bbb | ||
|
|
063ee4cf4d | ||
|
|
d7b9ed4813 | ||
|
|
10b82e080f | ||
|
|
a1b319347a | ||
|
|
709207f28e | ||
|
|
c680b0461f | ||
|
|
a4fa421a17 | ||
|
|
2f35c0d496 | ||
|
|
315e650344 | ||
|
|
d9be8cb2f1 | ||
|
|
176a7f80cb | ||
|
|
2441e6044e | ||
|
|
f076695120 | ||
|
|
6a3c8ae676 | ||
|
|
28926acd06 | ||
|
|
adcf2c8e22 | ||
|
|
1ae8c51a3c | ||
|
|
36d4df8a49 | ||
|
|
1aed412080 | ||
|
|
bc0f3e2d12 | ||
|
|
cae59ecddd | ||
|
|
9b95d29152 | ||
|
|
d376c4efbf | ||
|
|
e021fc7317 | ||
|
|
ef72dc00ae | ||
|
|
e2fc69661a | ||
|
|
b65f2948d4 | ||
|
|
fbbf0a3413 | ||
|
|
c4b7260686 | ||
|
|
6a63c7bde9 | ||
|
|
efd5a4ff45 | ||
|
|
b866e0912d | ||
|
|
9ba8aeaaad | ||
|
|
3239dc6cd5 | ||
|
|
8a18e413e9 | ||
|
|
78fcfa56a5 | ||
|
|
634bb69873 | ||
|
|
00f8d7a5ca | ||
|
|
0a200d1f1c | ||
|
|
30bc6a1f57 | ||
|
|
f23d7f09bf | ||
|
|
5c5f8902a1 | ||
|
|
6bba62224c | ||
|
|
8837cdcdda | ||
|
|
c4b56d95d0 | ||
|
|
2156844d18 | ||
|
|
b47412bbc1 | ||
|
|
1ca170946f | ||
|
|
0dedaf353d | ||
|
|
6779345665 | ||
|
|
698f84ff97 | ||
|
|
6a5f4843aa | ||
|
|
e851e4382a | ||
|
|
fc21241a49 | ||
|
|
5de2ba364d | ||
|
|
cc62502ab1 | ||
|
|
0815fbcc81 | ||
|
|
a676ef8eb7 | ||
|
|
78e560376c | ||
|
|
7e65cc3e47 | ||
|
|
a954821826 | ||
|
|
828b09dba2 | ||
|
|
2b88a14124 | ||
|
|
8acb15e4ce | ||
|
|
97d8398e8a | ||
|
|
5f87d21811 | ||
|
|
5c8a73ddb0 | ||
|
|
979a4e65e9 | ||
|
|
6e5c68abe5 | ||
|
|
d3634b3448 | ||
|
|
67fa34666d | ||
|
|
39adb2ac41 | ||
|
|
6fd2ef619e | ||
|
|
4f25f6dbf5 | ||
|
|
b4eeeda53a | ||
|
|
f8bc38b558 | ||
|
|
414793053e | ||
|
|
b885976601 | ||
|
|
ec64a9aa38 | ||
|
|
0aa0fc4500 | ||
|
|
3ebde0ea34 | ||
|
|
b6098a94e5 | ||
|
|
e726637319 | ||
|
|
446bea9926 | ||
|
|
9a28d36097 | ||
|
|
a4d7f884c0 | ||
|
|
ce1ce080ab | ||
|
|
e06449f59f | ||
|
|
ffda830f66 | ||
|
|
d23187f187 | ||
|
|
15766b418d | ||
|
|
7450940730 | ||
|
|
d1fd24c9ef | ||
|
|
19ce22e607 | ||
|
|
4476089d0f | ||
|
|
341265c486 | ||
|
|
f3a2f59549 | ||
|
|
4a245ce553 | ||
|
|
de443d5b89 | ||
|
|
ff756f086e | ||
|
|
cd1728b81d | ||
|
|
633120b760 | ||
|
|
3fd8fb9dc1 | ||
|
|
7a27adfcfd | ||
|
|
33faa04652 | ||
|
|
56f0d56a08 | ||
|
|
481d64d2dd | ||
|
|
e3ae6bcbdf | ||
|
|
e150150d11 | ||
|
|
f117423210 | ||
|
|
962bb4b0f2 | ||
|
|
ae9806f702 | ||
|
|
66e4cf130f | ||
|
|
72fef6d5b8 | ||
|
|
bb3073af76 | ||
|
|
b09bb521a8 | ||
|
|
22ff7b1fe9 | ||
|
|
7eb5a7ea03 | ||
|
|
6b9e2ef9b9 | ||
|
|
7c9436d237 | ||
|
|
8bf4731cf5 | ||
|
|
e14fb64904 | ||
|
|
12f62f95bc | ||
|
|
58eec8be8b | ||
|
|
b5a6bf5d18 | ||
|
|
70acd6a602 | ||
|
|
1fe0c58b76 | ||
|
|
18ea47f334 | ||
|
|
96b8d48136 | ||
|
|
4a463da9db | ||
|
|
239d1ebd00 | ||
|
|
77956158ae | ||
|
|
3d4336bab7 | ||
|
|
b2f6e290d1 | ||
|
|
f920020ba0 | ||
|
|
4a234e8452 | ||
|
|
d980c42dad | ||
|
|
37c7119ae4 | ||
|
|
ab55c00065 | ||
|
|
6f93847f8a | ||
|
|
2eb615b358 | ||
|
|
c899f6e7ce | ||
|
|
d0f7a451ef | ||
|
|
14be94e049 | ||
|
|
5fb1839620 | ||
|
|
a2eed31416 | ||
|
|
9203c4f2aa | ||
|
|
3d08b749b3 | ||
|
|
58b5d1071f | ||
|
|
f795f9027f | ||
|
|
2cf006beaa | ||
|
|
0c28987190 | ||
|
|
012433aba4 | ||
|
|
57cdd69c81 | ||
|
|
9e082570aa | ||
|
|
117daaf17f | ||
|
|
359d05dc7b | ||
|
|
77059ffcf1 | ||
|
|
17306e2a38 | ||
|
|
1f1045b401 | ||
|
|
29b860e84e | ||
|
|
0849e538b5 | ||
|
|
44dae36141 | ||
|
|
8a8860d9a0 | ||
|
|
0a185669d0 | ||
|
|
6445fad042 | ||
|
|
0ccd701421 | ||
|
|
7ff8342e01 | ||
|
|
0009028817 | ||
|
|
7e9ce496d8 | ||
|
|
869e317db8 | ||
|
|
6df24f646d | ||
|
|
9d863edcdb | ||
|
|
4c308205a6 | ||
|
|
2641650090 | ||
|
|
84a476d586 | ||
|
|
8b97535a40 | ||
|
|
119fc35c43 | ||
|
|
2feade4f74 | ||
|
|
9761c65614 | ||
|
|
00d8c841f7 | ||
|
|
531ae613c7 | ||
|
|
ac782fdd59 | ||
|
|
d35ccc1ade | ||
|
|
2c52cca4bd | ||
|
|
07e66811f3 | ||
|
|
077d502139 | ||
|
|
4030f6f59f | ||
|
|
15990fa0f6 | ||
|
|
ef01a57626 | ||
|
|
d21515e2cf | ||
|
|
fc5e99c226 | ||
|
|
bc59709966 | ||
|
|
d983549fae | ||
|
|
b6fc24e705 | ||
|
|
fcae022ba8 | ||
|
|
65d202160e | ||
|
|
4fb37d7850 | ||
|
|
5b69ec07fc | ||
|
|
60d254314b | ||
|
|
0f3fe830b9 | ||
|
|
4087f8f25b | ||
|
|
6b770024ce | ||
|
|
bbd8f9b282 | ||
|
|
d81d6ea80c | ||
|
|
8edef87ae5 | ||
|
|
9cc6ce368d | ||
|
|
e037037924 | ||
|
|
5b38dd87a6 | ||
|
|
b55db05aab | ||
|
|
6d4b3d6990 | ||
|
|
c7d216fff3 | ||
|
|
a3f815a74d | ||
|
|
e61493668b | ||
|
|
eb325e5fec | ||
|
|
242641d396 | ||
|
|
a507677dc1 | ||
|
|
262c4ea717 | ||
|
|
a16516b8e1 | ||
|
|
695c3b4b29 | ||
|
|
08bb9783d2 | ||
|
|
4515e688ed | ||
|
|
5694ada611 | ||
|
|
d2636c7621 | ||
|
|
67febe2758 | ||
|
|
7e6be45e2d | ||
|
|
660b4617bd | ||
|
|
afe85a3772 | ||
|
|
6c91bd7328 | ||
|
|
9c7f4c5451 | ||
|
|
4ea455aa20 | ||
|
|
9e38974f7a | ||
|
|
75751b8d2b | ||
|
|
dd66cd8811 | ||
|
|
a640dd5d78 | ||
|
|
14e85304df | ||
|
|
1eec58ece7 | ||
|
|
41cde6be6c | ||
|
|
15536e4c9e | ||
|
|
2feb991d96 | ||
|
|
a2bdfc9a58 | ||
|
|
d3c50521e8 | ||
|
|
2558ed7ac0 | ||
|
|
4f8f1fe593 | ||
|
|
3878897369 | ||
|
|
1a18258b5a | ||
|
|
38c92ef0c1 | ||
|
|
cc7097b4f7 | ||
|
|
9b597592bc | ||
|
|
70d303af78 | ||
|
|
cd6d74d9f3 | ||
|
|
a71f350c78 | ||
|
|
ce1026cb4b | ||
|
|
e039fb8603 | ||
|
|
a0949ecb87 | ||
|
|
a8202972b3 | ||
|
|
85ff2dcf45 | ||
|
|
262df4a257 | ||
|
|
e9d17e5efb | ||
|
|
513a3b8258 | ||
|
|
ac761c23d5 | ||
|
|
de0a679eef | ||
|
|
92a776cfc3 | ||
|
|
f2a3667593 | ||
|
|
6b73eb2fa6 | ||
|
|
66b01c1fd5 | ||
|
|
14ce2ca6e0 | ||
|
|
86fe33137f | ||
|
|
c65280cd42 | ||
|
|
2fb66da58d | ||
|
|
87b5142145 | ||
|
|
6aedb0a73a | ||
|
|
072eb24ed9 | ||
|
|
b443f38d60 | ||
|
|
8957ad3c10 | ||
|
|
d270cf66c6 | ||
|
|
c425fc6bcc | ||
|
|
c9882d7a8a | ||
|
|
85b478346b | ||
|
|
95b13083dc | ||
|
|
5568082f35 | ||
|
|
8f86ed1c0e | ||
|
|
1b54536eff | ||
|
|
d1d104cb7e | ||
|
|
9e1ce7a956 | ||
|
|
f30686f252 | ||
|
|
3dbc9caa73 | ||
|
|
114d1dd675 | ||
|
|
e64a623a4e | ||
|
|
6514275a05 | ||
|
|
7a438fe834 | ||
|
|
81ebecddb6 | ||
|
|
b5f31fb9de | ||
|
|
0cac3b7c41 | ||
|
|
603109d36e | ||
|
|
2772af753c | ||
|
|
de186d5f27 | ||
|
|
741189da06 | ||
|
|
e1b810c8f6 | ||
|
|
5e42fbf2fc | ||
|
|
3ec3095e20 | ||
|
|
2d004bccd5 | ||
|
|
4e52900d10 | ||
|
|
b1704a73b1 | ||
|
|
24b1dc2251 | ||
|
|
2b0fb901b4 | ||
|
|
22e3ec40e7 | ||
|
|
b6381fdbb5 | ||
|
|
8de49876b4 | ||
|
|
837c649168 | ||
|
|
dee80eef3a | ||
|
|
ee2b721c27 | ||
|
|
915f103c8f | ||
|
|
dccf27b40e | ||
|
|
21b93f1f0b | ||
|
|
8a7f0d046c | ||
|
|
602cc622bb | ||
|
|
4579b1eff3 | ||
|
|
fac58c6969 | ||
|
|
7fc656ac53 | ||
|
|
383aafe6f7 | ||
|
|
5fa2f385ef | ||
|
|
58f7c59a6e | ||
|
|
cdeeb7ee63 | ||
|
|
133c18e7c1 | ||
|
|
48c7227c08 | ||
|
|
3edbb4e560 | ||
|
|
592c2e324c | ||
|
|
5fa1b2ade9 | ||
|
|
93b7bcbf2b | ||
|
|
5059f5bdee | ||
|
|
ea619e0596 | ||
|
|
457d3bd8a3 | ||
|
|
a3ef684e91 | ||
|
|
2715d87e37 | ||
|
|
08602b5d9a | ||
|
|
7bbe300e7a | ||
|
|
6ffdee7a84 | ||
|
|
ec27f410ea | ||
|
|
4a1628f9d5 | ||
|
|
74bbcfacfd | ||
|
|
2d85b3299c | ||
|
|
8ade0946c6 | ||
|
|
97c9ad5f9c | ||
|
|
1bc488214a | ||
|
|
1536011f44 | ||
|
|
89c59e4e4c | ||
|
|
f5dc1a1d44 | ||
|
|
9471daab91 | ||
|
|
a1ce940436 | ||
|
|
840c87cf64 | ||
|
|
5eacd63cf5 | ||
|
|
dda27300dd | ||
|
|
817ea30fa1 | ||
|
|
e4f925c7bf | ||
|
|
aaddedd4c6 | ||
|
|
80d1b5317f | ||
|
|
f7a0902c1a | ||
|
|
dfbc3c9031 | ||
|
|
577ea92e1e | ||
|
|
e73765b9fb | ||
|
|
1a72c70290 | ||
|
|
d4c559a302 | ||
|
|
6d31ed05ef | ||
|
|
139009970b | ||
|
|
5296a8aa7a | ||
|
|
9eab533dd9 | ||
|
|
f0457bf4a7 | ||
|
|
deb6e542cd | ||
|
|
5cfc29878e | ||
|
|
a1c11c6e28 | ||
|
|
f95f988078 | ||
|
|
536bc43308 | ||
|
|
22befce4e6 | ||
|
|
fced4a9bd5 | ||
|
|
625b7b8ccc | ||
|
|
fe703aba4e | ||
|
|
44a0f874b5 | ||
|
|
cf4f826c35 | ||
|
|
ec246e292f | ||
|
|
5e37125bd8 | ||
|
|
34ae8b2bb0 | ||
|
|
eaa03f56ed | ||
|
|
f746755110 | ||
|
|
3e4f68e52c | ||
|
|
03427e7bb5 | ||
|
|
e2901f8e28 | ||
|
|
e03d3d4339 | ||
|
|
07bdad7211 | ||
|
|
36a3558fb3 | ||
|
|
cc7f24c75c | ||
|
|
69ed3bc9fc | ||
|
|
40d7adea3c | ||
|
|
13a8e16371 | ||
|
|
599ca53030 | ||
|
|
7f5aeb6143 | ||
|
|
76883a5d72 | ||
|
|
ecbed88127 | ||
|
|
e908083694 | ||
|
|
13365dc258 | ||
|
|
7e1b6dd7b5 | ||
|
|
7cffec944d | ||
|
|
e1a17ac43f | ||
|
|
1abb04f928 | ||
|
|
9f1df84d26 | ||
|
|
180fa944f3 | ||
|
|
604edbd21c | ||
|
|
3a433ce82b | ||
|
|
41931df6df | ||
|
|
d373a863ef | ||
|
|
95d1476a68 | ||
|
|
2dc83743ed | ||
|
|
c7f06670c6 | ||
|
|
d712fe9d81 | ||
|
|
d1ad9f31f7 | ||
|
|
df73778b1e | ||
|
|
81f7af1857 | ||
|
|
947ec35d68 | ||
|
|
d68903b3bd | ||
|
|
8335ccc009 | ||
|
|
de41770853 | ||
|
|
85c1a8cc63 | ||
|
|
a6d87758f0 | ||
|
|
121f500d05 | ||
|
|
2b738fc2fd | ||
|
|
8c0e94715d | ||
|
|
24bfca106a | ||
|
|
03ff4f842e | ||
|
|
9fe6ab13ef | ||
|
|
bc601ae1ec | ||
|
|
34328a0d30 | ||
|
|
90466a502a | ||
|
|
4789bd85d5 | ||
|
|
ccfac53917 | ||
|
|
8fb572bd21 | ||
|
|
c8cabd8948 | ||
|
|
53fe2d4e26 | ||
|
|
80c07f6c1e | ||
|
|
ea4d489253 | ||
|
|
9dea698f1a | ||
|
|
a0bf320e54 | ||
|
|
b13f68a7be | ||
|
|
2b99b94222 | ||
|
|
4e4847da1b | ||
|
|
f686236a16 | ||
|
|
ca819b7dfd | ||
|
|
af3a2712cc | ||
|
|
9169bedc87 | ||
|
|
a4133e1b1d | ||
|
|
28d1b2f44a | ||
|
|
c45a6c33bc | ||
|
|
090993b642 | ||
|
|
c89ad02972 | ||
|
|
cf289d4cb7 | ||
|
|
21174226db | ||
|
|
7c0f225ff6 | ||
|
|
6b65efca11 | ||
|
|
b540d28124 | ||
|
|
950b604a93 | ||
|
|
72c9390093 | ||
|
|
afd19c54cc | ||
|
|
3f11894929 | ||
|
|
71b5ef7f73 | ||
|
|
7db94542bf | ||
|
|
12b2febd7a | ||
|
|
3fbde4a7a3 | ||
|
|
c5eb37d464 | ||
|
|
aa1e837ebe | ||
|
|
f05da2460a | ||
|
|
6a58c27ae5 | ||
|
|
88b152076e | ||
|
|
8ddd600b34 | ||
|
|
14c6365314 | ||
|
|
492b3ef2f3 | ||
|
|
11297b8e8f | ||
|
|
93d27beffc | ||
|
|
34456a44b6 | ||
|
|
f572537d67 | ||
|
|
17a76482a6 | ||
|
|
071ae11d63 | ||
|
|
9a7d4a6312 | ||
|
|
5aca245283 | ||
|
|
6e851b1271 | ||
|
|
77f576c50c | ||
|
|
c028c5ba7b | ||
|
|
327cfa5505 | ||
|
|
f42518148a | ||
|
|
3886fa0019 | ||
|
|
f11a345e87 | ||
|
|
7cf39eac2e | ||
|
|
89b80e584f | ||
|
|
cf03da130c | ||
|
|
df6f827f89 | ||
|
|
5c0ae6f1e5 | ||
|
|
341552f001 | ||
|
|
359978aac8 | ||
|
|
a040fe0097 | ||
|
|
87ff4ea9c3 | ||
|
|
99dbca9d3d | ||
|
|
7d82b43332 | ||
|
|
ecca4c7e6e | ||
|
|
767651e6b6 | ||
|
|
90b8b02724 | ||
|
|
46e908ac0a | ||
|
|
45d6f7c055 | ||
|
|
bb8ba5135c | ||
|
|
fb08b21d83 | ||
|
|
f007f169b7 | ||
|
|
8a32583f57 | ||
|
|
dd7e820013 | ||
|
|
79625e8df4 | ||
|
|
2eb0646e66 | ||
|
|
1431c2a58d | ||
|
|
762819a87e | ||
|
|
7af0589105 | ||
|
|
b134d89ed0 | ||
|
|
b519ea172c | ||
|
|
e7505a28bc | ||
|
|
87eda8619d | ||
|
|
524e40512c | ||
|
|
ab894d174d | ||
|
|
11f31d0466 | ||
|
|
562609af67 | ||
|
|
df881409e3 | ||
|
|
1d8b81d494 | ||
|
|
51b719a7d5 | ||
|
|
aa452f5578 | ||
|
|
16d506fd9f | ||
|
|
698a087c94 | ||
|
|
014953e2fa | ||
|
|
0423cbafc9 | ||
|
|
0a076e04f2 | ||
|
|
24935b7784 | ||
|
|
5ab96643b4 | ||
|
|
f07665c8f3 | ||
|
|
f4590d8596 | ||
|
|
59c7272a82 | ||
|
|
609b824ac9 | ||
|
|
5f0636c4e7 | ||
|
|
6598be34d4 | ||
|
|
9b3673b470 | ||
|
|
5e77e0a02b | ||
|
|
7bdd05e51d | ||
|
|
be7501f3da | ||
|
|
a80f7076d7 | ||
|
|
a839f02e80 | ||
|
|
e15d6697da | ||
|
|
1c455b99ee | ||
|
|
ef97f9e131 | ||
|
|
3f62b4e05e | ||
|
|
efc4ae2fca | ||
|
|
0f5653de62 | ||
|
|
d623514422 | ||
|
|
751cd7707e | ||
|
|
7640410d71 | ||
|
|
a51468118d | ||
|
|
3eee677648 | ||
|
|
2411c7566d | ||
|
|
3c016d2669 | ||
|
|
a3f1f7f5de | ||
|
|
964c8b77ab | ||
|
|
c7bc3e8348 | ||
|
|
10b066f193 | ||
|
|
6c12a124f2 | ||
|
|
3dbeedceda | ||
|
|
f7a94ad18a | ||
|
|
735f161966 | ||
|
|
4faa4303fe | ||
|
|
51eabbcd81 | ||
|
|
e4de80d028 | ||
|
|
17a0b39da8 | ||
|
|
654952842a | ||
|
|
b201cfa664 | ||
|
|
d22df75b7c | ||
|
|
bc6fab8c9f | ||
|
|
e55006f74b | ||
|
|
18864ad67f | ||
|
|
019d09c770 | ||
|
|
0a5ec22ddd | ||
|
|
8bb8e100d3 | ||
|
|
ffa513906a | ||
|
|
de12eb6c4a | ||
|
|
98d8b45dc4 | ||
|
|
e9a770315d | ||
|
|
c966f9a2f3 | ||
|
|
ad8626b1eb | ||
|
|
f19cbfa718 | ||
|
|
7819f0b4d8 | ||
|
|
64a2e5bc91 | ||
|
|
fd54ad7314 | ||
|
|
cae9340a5d | ||
|
|
c9641bcd55 | ||
|
|
d963dab12a | ||
|
|
1e9fcd95c9 | ||
|
|
3e2aec1a03 | ||
|
|
b66fd79d21 | ||
|
|
57b813f39d | ||
|
|
b62073ce77 | ||
|
|
3f37d9c9c1 | ||
|
|
bde879104e | ||
|
|
e7b481d93e | ||
|
|
51af760783 | ||
|
|
104a485302 | ||
|
|
6db13355e7 | ||
|
|
eafae52ba5 | ||
|
|
0c71e02e56 | ||
|
|
7e60cdb198 | ||
|
|
79f77125e1 | ||
|
|
61513f910b | ||
|
|
5228119251 | ||
|
|
2fa29b90cc | ||
|
|
c9ecc2ddf7 | ||
|
|
1468cf0051 | ||
|
|
e71c28ef99 | ||
|
|
c0442a131c | ||
|
|
086c0ec5c7 | ||
|
|
6e40db4975 | ||
|
|
1713f2f9aa | ||
|
|
38531c77ab | ||
|
|
3cf8aff57f | ||
|
|
3d87b9ccab | ||
|
|
2aecce6161 | ||
|
|
adf1b0408c | ||
|
|
7380a8b163 | ||
|
|
1ed6dd76c6 | ||
|
|
3258313300 | ||
|
|
16f3f7e9fd | ||
|
|
6174b97b99 | ||
|
|
df8901ca3a | ||
|
|
697ebc6599 | ||
|
|
2728aa6db0 | ||
|
|
3e7a3a879b | ||
|
|
98f2341a4b | ||
|
|
8fdfdc0f50 | ||
|
|
cfd26f7d18 | ||
|
|
a0b281a035 | ||
|
|
e96fe12663 | ||
|
|
2a865e78f8 | ||
|
|
c640480e6d | ||
|
|
93941f5e1b | ||
|
|
a5bfd9b9b8 | ||
|
|
0eb1b6ac8b | ||
|
|
87b89e54ba | ||
|
|
64c0549844 | ||
|
|
7665c73acc | ||
|
|
b68ef803ce | ||
|
|
4f2f50e32e | ||
|
|
d717fe28e4 | ||
|
|
f728f01857 | ||
|
|
ba3cc9061f | ||
|
|
fb12383641 | ||
|
|
fce952b71c | ||
|
|
2d8e148e95 | ||
|
|
ce560b2bb2 | ||
|
|
5e62325a18 | ||
|
|
65b652a6f4 | ||
|
|
35509356f0 | ||
|
|
9799dd2455 | ||
|
|
33f2bb0d79 | ||
|
|
86db5cd629 | ||
|
|
347862ac5a | ||
|
|
dfcdf4419d | ||
|
|
287d2929c9 | ||
|
|
f2c64f1925 | ||
|
|
a690092acf | ||
|
|
cda6eb261e | ||
|
|
e5aa66fe72 | ||
|
|
7f629160d4 | ||
|
|
0de432be00 | ||
|
|
c0b0ec216a | ||
|
|
0b4efea5b8 | ||
|
|
11c68af70c | ||
|
|
3cf02c33ef | ||
|
|
189781312b | ||
|
|
fd21495b10 | ||
|
|
05738a14ab | ||
|
|
65cbefdc80 | ||
|
|
80ea6ad839 | ||
|
|
c1c6f549cd | ||
|
|
320b46783a | ||
|
|
7af08a4b48 | ||
|
|
3053fb6b38 | ||
|
|
92be45cdad | ||
|
|
31c9d17a78 | ||
|
|
bf05d4779b | ||
|
|
5d3eccdb0f | ||
|
|
b6e543bc2b | ||
|
|
9a8dab92d1 | ||
|
|
729e05af40 | ||
|
|
ce662e5c3a | ||
|
|
b8f69d39ce | ||
|
|
1c8381be73 | ||
|
|
0e7e81e8c0 | ||
|
|
f687b17645 | ||
|
|
4f147b7bbc | ||
|
|
316e4aff8a | ||
|
|
61ad847513 | ||
|
|
5173a4e533 | ||
|
|
527d24a5fd | ||
|
|
71c9417d75 | ||
|
|
746b85abc3 | ||
|
|
259b9b063e | ||
|
|
d41f254bea | ||
|
|
8e43f6f4fc | ||
|
|
c40c78dfdd | ||
|
|
7d45999ace | ||
|
|
7ded800457 | ||
|
|
6560f9a2e9 | ||
|
|
5c9c1b8e3c | ||
|
|
68964f4b75 | ||
|
|
a6f549e867 | ||
|
|
e9e6ec9d22 | ||
|
|
40e39f12be | ||
|
|
1e1fc5ad54 | ||
|
|
833979c77a | ||
|
|
10830dacbc | ||
|
|
85bce938fc | ||
|
|
ddf02b5ea1 | ||
|
|
8e8e103b0a | ||
|
|
444262d856 | ||
|
|
b466aec998 | ||
|
|
c1afdbfbd7 | ||
|
|
cf393afbcb | ||
|
|
8dd42aba14 | ||
|
|
42828ba0a9 | ||
|
|
688ef4da7d | ||
|
|
8c15ff6ae6 | ||
|
|
0a38118f51 | ||
|
|
7579ce796d | ||
|
|
1decdebab9 | ||
|
|
c691adc894 | ||
|
|
c5e984eb72 | ||
|
|
236363eb99 | ||
|
|
77963577b1 | ||
|
|
e32d1ff144 | ||
|
|
085f703ec9 | ||
|
|
7a76942833 | ||
|
|
6c793047f3 | ||
|
|
b197cee5fa | ||
|
|
1e49d9cc81 | ||
|
|
afea316ea0 | ||
|
|
074ad08911 | ||
|
|
aebf66b9aa | ||
|
|
9643d9d72c | ||
|
|
5c0fe5b634 | ||
|
|
f8a084c5e9 | ||
|
|
726180dc36 | ||
|
|
95a1b63b80 | ||
|
|
d1f4c5f1c3 | ||
|
|
952f88936c | ||
|
|
4ad0326ec3 | ||
|
|
d4885cc30a | ||
|
|
8cb010ca04 | ||
|
|
989d084075 | ||
|
|
6b044b18cf | ||
|
|
2ceb53d630 | ||
|
|
94dccba69c | ||
|
|
ad9f213399 | ||
|
|
011e9c4437 | ||
|
|
c965aaf380 | ||
|
|
a312d1e96e | ||
|
|
e85cd6aa3a | ||
|
|
de7e98b3fd | ||
|
|
55cbc8610c | ||
|
|
3dbda0ab5f | ||
|
|
c82d6050b0 | ||
|
|
dc22d2e7ee | ||
|
|
8c70a8b961 | ||
|
|
c225e168bf | ||
|
|
a251f16ae7 | ||
|
|
0bb1504c38 | ||
|
|
e2a1bcbc3e | ||
|
|
3dd2ace221 | ||
|
|
d7846eb049 | ||
|
|
d924f7b4ed | ||
|
|
84d0a7e002 | ||
|
|
ec17c24c9f | ||
|
|
fa93e4cf95 | ||
|
|
4e6881c088 | ||
|
|
9890b0a8b9 | ||
|
|
131c717f0f | ||
|
|
412bd411dc | ||
|
|
e257e225f7 | ||
|
|
3a77095e09 | ||
|
|
1ee50b95c6 | ||
|
|
6dae87a349 | ||
|
|
376ecb60b6 | ||
|
|
36823f55f4 | ||
|
|
c526616e84 | ||
|
|
6aff15bb45 | ||
|
|
909e32c084 | ||
|
|
da106e70ae | ||
|
|
0fd5a43618 | ||
|
|
b121b0de51 | ||
|
|
cfb8ebe66b | ||
|
|
91e536efb4 | ||
|
|
6be0394931 | ||
|
|
6a185aba71 | ||
|
|
c5f52f352a | ||
|
|
0cb05ed5d6 | ||
|
|
51b293d883 | ||
|
|
27447d3c46 | ||
|
|
482926ce8a | ||
|
|
bc8fa0b83c | ||
|
|
4190b3316b | ||
|
|
d208be330b | ||
|
|
41bb8a8267 | ||
|
|
c8f9981c28 | ||
|
|
f357bc3d8b | ||
|
|
e8a4795ff6 | ||
|
|
9e1f61bd67 | ||
|
|
e26b849d20 | ||
|
|
a5a6ba2384 | ||
|
|
fa0ea70500 | ||
|
|
415c9f9dcb | ||
|
|
d0a22014dd | ||
|
|
6538dc9cb6 | ||
|
|
3542a79b5a | ||
|
|
dad8b50b8c | ||
|
|
3f12554d36 | ||
|
|
ad5d25460e | ||
|
|
b3c3d2d21a | ||
|
|
0d6504caac | ||
|
|
79d4307520 | ||
|
|
a51734237a | ||
|
|
a5a88b8d16 | ||
|
|
cce74865d0 | ||
|
|
53088fb169 | ||
|
|
2859d8902b | ||
|
|
3ce1b5dd61 | ||
|
|
eb9f154ee5 | ||
|
|
d27ec0b417 | ||
|
|
726fda5dd3 | ||
|
|
f89aa8204d | ||
|
|
4daf0bbc08 | ||
|
|
bd5e795dba | ||
|
|
18a931ee11 | ||
|
|
5dd3568167 | ||
|
|
aff1a7bc44 | ||
|
|
0c368bab99 | ||
|
|
053adbc5cd | ||
|
|
406079954f | ||
|
|
36acb54012 | ||
|
|
a757483db0 | ||
|
|
d54f57457e | ||
|
|
5b4c81c21b | ||
|
|
f5f7162c4d | ||
|
|
bd05d2f4c0 | ||
|
|
3a04b50051 | ||
|
|
eae64dc18b | ||
|
|
388842988d | ||
|
|
ae87b63524 | ||
|
|
6715c73834 | ||
|
|
cb2268aa1a | ||
|
|
c283381b44 | ||
|
|
b810fbd98f | ||
|
|
b259c01dcf | ||
|
|
b7f4ae5b01 | ||
|
|
f970aa1a9a | ||
|
|
a788c4769d | ||
|
|
927225f4fa | ||
|
|
9d32f971d4 | ||
|
|
e75e4be9ff | ||
|
|
b59046a3bd | ||
|
|
c394053016 | ||
|
|
a4d99f8a28 | ||
|
|
e9af823446 | ||
|
|
26656fec7d | ||
|
|
5e5682b51b | ||
|
|
7cbd85f350 | ||
|
|
2867560199 | ||
|
|
c944aa11b9 | ||
|
|
49b5a434f0 | ||
|
|
b19570043c | ||
|
|
dd42e3f8ca | ||
|
|
bd91f5f83e | ||
|
|
bf4aa1ba4b | ||
|
|
15e86494a3 | ||
|
|
bc686ef1ad | ||
|
|
30480f084a | ||
|
|
2ac2e4ed63 | ||
|
|
4880292eae | ||
|
|
b0957d770f | ||
|
|
89d7cca418 | ||
|
|
0ea48acfd2 | ||
|
|
2d2f8f3d9d | ||
|
|
0c4977af91 | ||
|
|
ebc5830977 | ||
|
|
81d5c1c87b | ||
|
|
ee3ac849ea | ||
|
|
d7ced1e954 | ||
|
|
5525d6ed29 | ||
|
|
3e282a0569 | ||
|
|
58d7630ef3 | ||
|
|
9007bf94ef | ||
|
|
418be24d01 | ||
|
|
76c99abbf4 | ||
|
|
c704a2e01d | ||
|
|
25173d83c6 | ||
|
|
6853c82026 | ||
|
|
3f7d144e99 | ||
|
|
d4d4abfd8e | ||
|
|
65245e28f6 | ||
|
|
b95f29bbaf | ||
|
|
cfaabdbba9 | ||
|
|
4c39d61b3b | ||
|
|
257be0e609 | ||
|
|
f46c349e43 | ||
|
|
54c1a6e06b | ||
|
|
9bbf8943ec | ||
|
|
2c08f6dc68 | ||
|
|
14387d1d71 | ||
|
|
104dd842a3 | ||
|
|
62937ee9e2 | ||
|
|
387f562991 | ||
|
|
b88f63edf0 | ||
|
|
35c2a064e2 | ||
|
|
9efda25855 | ||
|
|
370cf9de26 | ||
|
|
82b9ad0705 | ||
|
|
565ae1dec8 | ||
|
|
d87387e77e | ||
|
|
b1858490f1 | ||
|
|
bf74da8aef | ||
|
|
33c578e90a | ||
|
|
8cb32c6458 | ||
|
|
20ab243d31 | ||
|
|
fad62952d7 | ||
|
|
998827c456 | ||
|
|
1c178d3ebc | ||
|
|
85a90e3516 | ||
|
|
49d302ded9 | ||
|
|
b29187fa93 | ||
|
|
d726a1e13c | ||
|
|
607a78ffe4 | ||
|
|
21e24fb75b | ||
|
|
7de0729543 | ||
|
|
23a7119fad | ||
|
|
846a00137f | ||
|
|
bf4fddca02 | ||
|
|
23f4b0a2bb | ||
|
|
04d29c70dd | ||
|
|
bc9bf3ee61 | ||
|
|
a7c3539bb1 | ||
|
|
ef8e1a63d2 | ||
|
|
6ee936db79 | ||
|
|
6f77347dc3 | ||
|
|
a785422049 | ||
|
|
b161e9a0e1 | ||
|
|
6d978f2a94 | ||
|
|
387502018f | ||
|
|
be73522f53 | ||
|
|
325cff977f | ||
|
|
23e263347e | ||
|
|
932dd8d06d | ||
|
|
bb6318c62c | ||
|
|
f066f60543 | ||
|
|
93c3afacbf | ||
|
|
96544fd819 | ||
|
|
5f41a73938 | ||
|
|
cd8733e5c8 | ||
|
|
248f5f769b | ||
|
|
5559950997 | ||
|
|
633a2d193e | ||
|
|
0755676585 | ||
|
|
86ce1fde06 | ||
|
|
a28cbfab3f | ||
|
|
fff2fc522b | ||
|
|
2ab4dfb9e8 | ||
|
|
0cf0bc0bd7 | ||
|
|
9036ae9475 | ||
|
|
4077e3ed51 | ||
|
|
23f145d8bc | ||
|
|
45855062c2 | ||
|
|
c67c9ad4d5 | ||
|
|
9826e6a174 | ||
|
|
b2afc88b4c | ||
|
|
4678fc3b3e | ||
|
|
db19cb6862 | ||
|
|
c72a7aab5e | ||
|
|
bf4a7d69e4 | ||
|
|
5c37b9d20c | ||
|
|
8b4ac42ec7 | ||
|
|
1bd9a4cdec | ||
|
|
f0872f2dac | ||
|
|
cae4c25810 | ||
|
|
712923547f | ||
|
|
0f62518dde | ||
|
|
f15913d044 | ||
|
|
4efb76821d | ||
|
|
57bf27e78f | ||
|
|
4e1b0f0f69 | ||
|
|
10e9a4f929 | ||
|
|
a63d3bdf40 | ||
|
|
68c0499e21 | ||
|
|
c1a474dc83 | ||
|
|
319c267e34 | ||
|
|
209cdba897 | ||
|
|
78101a7f66 | ||
|
|
b20a1c2419 | ||
|
|
d41d13683f | ||
|
|
ad947e4d49 | ||
|
|
28c3ab5af3 | ||
|
|
60a8df882d | ||
|
|
65caaef1e6 | ||
|
|
7404df4269 | ||
|
|
e996470196 | ||
|
|
32ba53f06f | ||
|
|
e734087706 | ||
|
|
f755947f7e | ||
|
|
17d0e7d345 | ||
|
|
7ac6915202 | ||
|
|
1fc6cd4dc6 | ||
|
|
010156f690 | ||
|
|
34e9006702 | ||
|
|
369e21f430 | ||
|
|
e444b823c2 | ||
|
|
024655be6b | ||
|
|
d31fee5d22 | ||
|
|
90aebe81cc | ||
|
|
fb7cdd7d98 | ||
|
|
fc0ad052dd | ||
|
|
a951c80bf6 | ||
|
|
b7d2cdf6b5 | ||
|
|
b46ad42885 | ||
|
|
f738f277c8 | ||
|
|
6f23c781ae | ||
|
|
a36506d7a0 | ||
|
|
dd0ce1a2ba | ||
|
|
1278024384 | ||
|
|
4e12ba97f7 | ||
|
|
28404489d1 | ||
|
|
d52c0089bd | ||
|
|
5a7ea48438 | ||
|
|
f8a0574b93 | ||
|
|
6fb20e0d62 | ||
|
|
f991f4125e | ||
|
|
55d5490852 | ||
|
|
d289bfc7c2 | ||
|
|
93bf6d9509 | ||
|
|
fe9c2b2490 | ||
|
|
af380d0358 | ||
|
|
d3d176cafe | ||
|
|
21cb0ec248 | ||
|
|
4cbc932967 | ||
|
|
e14e024a4e | ||
|
|
d7e8333aed | ||
|
|
bb98e94183 | ||
|
|
c8d1dc92ac | ||
|
|
7716846541 | ||
|
|
96c9fd3806 | ||
|
|
94f696ca01 | ||
|
|
ebf0b7bec6 | ||
|
|
17d60844e6 | ||
|
|
96173d7500 | ||
|
|
dc216ff081 | ||
|
|
e0afee6b13 | ||
|
|
313fb74dc7 | ||
|
|
f3db5d7822 | ||
|
|
d7b63d072a | ||
|
|
f81bb5cd22 | ||
|
|
155c71de86 | ||
|
|
a0eda9c6aa | ||
|
|
00a56eaa8a | ||
|
|
f5df3f93ac | ||
|
|
8423f6d2d7 | ||
|
|
b3109e2241 | ||
|
|
2b633b99a3 | ||
|
|
cf521d26c7 | ||
|
|
158a6f26e2 | ||
|
|
c4ffe25603 | ||
|
|
e8d593e467 | ||
|
|
f6aec0ec2a | ||
|
|
7cea7ef549 | ||
|
|
84a6a44bbe | ||
|
|
5bfdc4f45a | ||
|
|
5102e55b7e | ||
|
|
46dc0b5b6d | ||
|
|
5cb63b299d | ||
|
|
979c27387e | ||
|
|
f6f977503e | ||
|
|
2b5a99ed59 | ||
|
|
d1c5b907c0 | ||
|
|
58f0adc560 | ||
|
|
697b6e211d | ||
|
|
3977ae2ce0 | ||
|
|
09b9065e10 | ||
|
|
3197ad19e5 | ||
|
|
4359a9735b | ||
|
|
77f63ecd28 | ||
|
|
2f369e1d38 | ||
|
|
9367098259 | ||
|
|
de9072a1b5 | ||
|
|
1ef283ad22 | ||
|
|
858faf2c88 | ||
|
|
9824e59ef9 | ||
|
|
9594efcf03 | ||
|
|
3e5fd573a6 | ||
|
|
79c143b7eb | ||
|
|
af753c38be | ||
|
|
5b826cc9e9 | ||
|
|
b50afff4a1 | ||
|
|
7d5641bae7 | ||
|
|
03500503ab | ||
|
|
0237c94a5f | ||
|
|
a27a985551 | ||
|
|
4a39fc82f1 | ||
|
|
4428efbc3b | ||
|
|
88bd695007 | ||
|
|
84215b1721 | ||
|
|
8ec2c7f88c | ||
|
|
9188c7faf2 | ||
|
|
f8ac8eda89 | ||
|
|
8e689db6d7 | ||
|
|
c602789ac4 | ||
|
|
b91156db9b | ||
|
|
b3fb8a7a15 | ||
|
|
89236042c2 | ||
|
|
27ee8c90d5 | ||
|
|
d330c09e60 | ||
|
|
33cc1f0b2d | ||
|
|
ea5717da6e | ||
|
|
2a906b02fb | ||
|
|
913b7304d6 | ||
|
|
1ad42867bc | ||
|
|
412979f721 | ||
|
|
68c7f0f000 | ||
|
|
2029fe08f1 | ||
|
|
71b46ea44e | ||
|
|
5ff976793e | ||
|
|
522d838ec5 | ||
|
|
c1441a8dab | ||
|
|
a7a1e6e8b0 | ||
|
|
b3bddd33ea | ||
|
|
28ea702901 | ||
|
|
ec62c80ccc | ||
|
|
e9ae9a9922 | ||
|
|
dd5cb223a9 | ||
|
|
d4f13317fc | ||
|
|
2ca125ab07 | ||
|
|
30546d0b5e | ||
|
|
60074be670 | ||
|
|
2e2f7bd7c4 | ||
|
|
8ae490c7b2 | ||
|
|
f85112afa9 | ||
|
|
589d0b9dde | ||
|
|
285c90999e | ||
|
|
cd00c626c7 | ||
|
|
138cbad573 | ||
|
|
801fbb89b5 | ||
|
|
15a4277302 | ||
|
|
b21a684180 | ||
|
|
f8d66cf76e | ||
|
|
205da83357 | ||
|
|
da21039a38 | ||
|
|
559c014bc4 | ||
|
|
6fce68aa76 | ||
|
|
5131631de5 | ||
|
|
01ba495e10 | ||
|
|
4e395eafbb | ||
|
|
3162e8db93 | ||
|
|
ecd57daa56 | ||
|
|
6dccaa5841 | ||
|
|
c8bded4468 | ||
|
|
a1f6743de2 | ||
|
|
32a39e530a | ||
|
|
69882216e9 | ||
|
|
83341c30a0 | ||
|
|
bac6a98a72 | ||
|
|
7a72106197 | ||
|
|
9c569ed87e | ||
|
|
5dcbc9a5d3 | ||
|
|
0d625d516f | ||
|
|
652e9a3d3d | ||
|
|
67d61ac11e | ||
|
|
8541dbd8c6 | ||
|
|
99b8481f4d | ||
|
|
074065b190 | ||
|
|
f63db63e76 | ||
|
|
359c343854 | ||
|
|
a18c05e41a | ||
|
|
87c5da1ba0 | ||
|
|
b8fc6e5227 | ||
|
|
100132d20a | ||
|
|
60cee89061 | ||
|
|
377f16d6e6 | ||
|
|
b0213fe517 | ||
|
|
f791019ad1 | ||
|
|
cb2be2f382 | ||
|
|
89f5cbfb78 | ||
|
|
b16b685bb7 | ||
|
|
73af932419 | ||
|
|
d3833180e8 | ||
|
|
fc226dc578 | ||
|
|
d7c3e23b00 | ||
|
|
da11ed70a4 | ||
|
|
6f2a30e18f | ||
|
|
3ac0b2462f | ||
|
|
2c21320679 | ||
|
|
1d05a87a8c | ||
|
|
74a6d00c42 | ||
|
|
543adf32cf | ||
|
|
5399481a0d | ||
|
|
67fe10b128 | ||
|
|
d6e8404560 | ||
|
|
dae2133d58 | ||
|
|
f1fc2d1ba6 | ||
|
|
283ff13016 | ||
|
|
007a2aafb0 | ||
|
|
035d2d50f3 | ||
|
|
011e25e298 | ||
|
|
ae9fabb001 | ||
|
|
02b004b3cd | ||
|
|
4b7d331bef | ||
|
|
3652388aa5 | ||
|
|
f69157dcd9 | ||
|
|
f3527e1960 | ||
|
|
a2268c6560 | ||
|
|
3cc888d053 | ||
|
|
0acaee5871 | ||
|
|
f4c6c470db | ||
|
|
3aa4bd1eb6 | ||
|
|
f2c5a6fe91 | ||
|
|
9c8827cdab | ||
|
|
4b6247105a | ||
|
|
cafb573a39 | ||
|
|
c37197f91a | ||
|
|
a9dcc52b10 | ||
|
|
940096746f | ||
|
|
ec0254739f | ||
|
|
f3a3191730 | ||
|
|
5ea4029e0a | ||
|
|
2c5305d2f6 | ||
|
|
c32df6489f | ||
|
|
3e3a833332 | ||
|
|
bccabdc5ba | ||
|
|
dd2be687e1 | ||
|
|
3c71a30cbb | ||
|
|
fd8c22bb26 | ||
|
|
d1088b70dd | ||
|
|
9054726d53 | ||
|
|
cc6dfc8068 | ||
|
|
c192c26447 | ||
|
|
ddf2e6a0f3 | ||
|
|
a7041eda93 | ||
|
|
657097029c | ||
|
|
70c189b56a | ||
|
|
b5988ffa0f | ||
|
|
2764c0beef | ||
|
|
11887fd53a | ||
|
|
e47a6ba988 | ||
|
|
14efa6248e | ||
|
|
81f5afc76f | ||
|
|
9cd25bd5ff | ||
|
|
3ecd474137 | ||
|
|
04152d09f5 | ||
|
|
8c706e2a4c | ||
|
|
094a3b5c52 | ||
|
|
f2724daa5b | ||
|
|
3781f7a08d | ||
|
|
394d1c0590 | ||
|
|
63291a1906 | ||
|
|
3e77d1efae | ||
|
|
c8adf9cefa | ||
|
|
05b86b6375 | ||
|
|
eb77c7cbde | ||
|
|
0493aee1ae | ||
|
|
f11e1b7e1a | ||
|
|
7d3c213b7e | ||
|
|
c3e0c1449a | ||
|
|
989984b05e | ||
|
|
ddceab0c5e | ||
|
|
c6e0fd7fa7 | ||
|
|
ce0d82dfbc | ||
|
|
5eba49e20a | ||
|
|
343918bd8a | ||
|
|
a4d33afe60 | ||
|
|
86ef471467 | ||
|
|
ce8c5dacd5 | ||
|
|
1fd6f1a1c3 | ||
|
|
7e622c391d | ||
|
|
cc1bb2306b | ||
|
|
4d1ab35ddf | ||
|
|
2c18f0dbc1 | ||
|
|
11db6004e4 | ||
|
|
0e2be61276 | ||
|
|
8324a1fefa | ||
|
|
a5d9010494 | ||
|
|
0a5e06c569 | ||
|
|
13af836ca1 | ||
|
|
675b815ce0 | ||
|
|
c3f5af6d60 | ||
|
|
d4a9789efc | ||
|
|
a9fb99fbbc | ||
|
|
55e81b75dc | ||
|
|
8620d8fb68 | ||
|
|
7225e445ce | ||
|
|
afd1c8cda1 | ||
|
|
88496cd851 | ||
|
|
1f4c2298aa | ||
|
|
b4ff436b5f | ||
|
|
e912ef64fe | ||
|
|
4d0241e61d | ||
|
|
62cb894484 | ||
|
|
b4d0aadaeb | ||
|
|
6072544004 | ||
|
|
f61b8c9337 | ||
|
|
9a048f250d | ||
|
|
bef465e2c7 | ||
|
|
3eb98562ef | ||
|
|
1407e0cf26 | ||
|
|
69d2b8641b | ||
|
|
b286be7d22 | ||
|
|
7f6a1e0140 | ||
|
|
535e70637f | ||
|
|
0fa2b5ce6d | ||
|
|
eabc237a59 | ||
|
|
f4791be5c3 | ||
|
|
9b6dec06bc | ||
|
|
819a513030 | ||
|
|
a33c1fb733 | ||
|
|
f8a4166c6c | ||
|
|
a2452767cb | ||
|
|
efe1180e1c | ||
|
|
b830201675 | ||
|
|
bda639a23b | ||
|
|
c6502101d4 | ||
|
|
95e6d0371d | ||
|
|
7f6cde45d1 | ||
|
|
04a7d08c1a | ||
|
|
28b909e4fb | ||
|
|
cd57742602 | ||
|
|
338136bd4c | ||
|
|
a7c7496465 | ||
|
|
82cf526f43 | ||
|
|
f02b6aa9de | ||
|
|
a7c1cdf8ff | ||
|
|
9b6b676dd1 | ||
|
|
3ea0711b28 | ||
|
|
b85f9b22a1 | ||
|
|
279da41b1d | ||
|
|
645a172801 | ||
|
|
020cef6706 | ||
|
|
6b0bcf3927 | ||
|
|
125489b4ea | ||
|
|
77828b3d00 | ||
|
|
31b4823281 | ||
|
|
407737df09 | ||
|
|
30a66adb60 | ||
|
|
cf5834653f | ||
|
|
c115e6e816 | ||
|
|
a5e2c1600a | ||
|
|
2f2a56bd12 | ||
|
|
21e84b84ef | ||
|
|
e71d932b30 | ||
|
|
ced5f068b1 | ||
|
|
883c79b14f | ||
|
|
073e8cf98b | ||
|
|
73b84862fb | ||
|
|
d5f5956187 | ||
|
|
1b90f240b1 | ||
|
|
56e26d051e | ||
|
|
dc6625e466 | ||
|
|
080f935a42 | ||
|
|
e797e7d78b | ||
|
|
a65b1fcc09 | ||
|
|
e3014390c4 | ||
|
|
81e8f3dee2 | ||
|
|
55fc81755f | ||
|
|
ec7b54979e | ||
|
|
adb9939df0 | ||
|
|
48be2d9005 | ||
|
|
8a4b4b3d7b | ||
|
|
c9cf5b7db8 | ||
|
|
bb6fea731e | ||
|
|
05a08b6ff8 | ||
|
|
3784e1e007 | ||
|
|
e1ac204e04 | ||
|
|
1a761d0daf | ||
|
|
93860bab2e | ||
|
|
09322abfd4 | ||
|
|
8d304f408a | ||
|
|
52d71a615f | ||
|
|
5734b316d0 | ||
|
|
cb6fef244d | ||
|
|
e635f5d9bc | ||
|
|
349a739e86 | ||
|
|
e798765056 | ||
|
|
ee9e01bc6b | ||
|
|
75235b240e | ||
|
|
c2b8527f0c | ||
|
|
58ba4000b5 | ||
|
|
bceaaf92e0 | ||
|
|
f91925c187 | ||
|
|
fe63163c85 | ||
|
|
325435b678 | ||
|
|
9f408c2167 | ||
|
|
efda6f84dd | ||
|
|
e5d1782b9d | ||
|
|
6655238409 | ||
|
|
d497e5006e | ||
|
|
4fb9148cfd | ||
|
|
5782dafed2 | ||
|
|
690b667b2f | ||
|
|
5393e924ba | ||
|
|
aaa178d5bb | ||
|
|
79ce4ae115 | ||
|
|
cd068f7bbc | ||
|
|
36fb1144de | ||
|
|
f9d206d844 | ||
|
|
0c92824b46 | ||
|
|
1122eaafa8 | ||
|
|
7e1460b501 | ||
|
|
3cec82d912 | ||
|
|
fc06f73017 | ||
|
|
519d4ef5f1 | ||
|
|
f4588ab6f1 | ||
|
|
673d8ab3e2 | ||
|
|
205a2713d4 | ||
|
|
5a0e423e5d | ||
|
|
5d0b6357be | ||
|
|
fba7de33cf | ||
|
|
b282b5598d | ||
|
|
90dff02591 | ||
|
|
263800d720 | ||
|
|
500f730265 | ||
|
|
0d271d9027 | ||
|
|
836980d9ce | ||
|
|
99eb4b0345 | ||
|
|
5172b3b9cd | ||
|
|
6fd6684004 | ||
|
|
dadc6bc452 | ||
|
|
71b893f417 | ||
|
|
689496f018 | ||
|
|
ffb4cd32e9 | ||
|
|
a3b466fc71 | ||
|
|
0fe230e150 | ||
|
|
39a125a753 | ||
|
|
39c3e89b69 | ||
|
|
cc043e2fdf | ||
|
|
ebd4cd9812 | ||
|
|
0fa8c8b0d2 | ||
|
|
bf7fa7b713 | ||
|
|
c488882862 | ||
|
|
abddb41dd0 | ||
|
|
1667ee8369 | ||
|
|
2dedccb0fb | ||
|
|
d0a318000f | ||
|
|
9b2ef862cb | ||
|
|
0874324372 | ||
|
|
e406b27838 | ||
|
|
573456885f | ||
|
|
762cfb3a86 | ||
|
|
0e455fde27 | ||
|
|
c6f58e5eb4 | ||
|
|
63debfebaf | ||
|
|
eb0f22ec6b | ||
|
|
037fc27dcd | ||
|
|
c9fbe0e251 | ||
|
|
56f99f41de | ||
|
|
feca7268c2 | ||
|
|
c126553147 | ||
|
|
f7af32cce7 | ||
|
|
fe4b13a81b | ||
|
|
627d042a1d | ||
|
|
6278f5c0ef | ||
|
|
b5056c8ab8 | ||
|
|
a1504934c1 | ||
|
|
0b56737e25 | ||
|
|
a93b5dc534 | ||
|
|
cdb79f6d63 | ||
|
|
6dbfa81e18 | ||
|
|
e4693e0738 | ||
|
|
dd8b257705 | ||
|
|
c157a9505a | ||
|
|
8cc55e8539 | ||
|
|
4bfec18ac3 | ||
|
|
c37ebd3f1a | ||
|
|
83d82cb162 | ||
|
|
571b67e913 | ||
|
|
1f2f8bc1e9 | ||
|
|
643126161d | ||
|
|
f5fc03c661 | ||
|
|
1af410e9ec | ||
|
|
98459a62c1 | ||
|
|
c566e389c8 | ||
|
|
2ee65e628c | ||
|
|
64843e42e3 | ||
|
|
6111d552ea | ||
|
|
c437f19cf3 | ||
|
|
9629664bf5 | ||
|
|
1226502170 | ||
|
|
265edcd1d2 | ||
|
|
67f5640b53 | ||
|
|
8270b98993 | ||
|
|
4146cafd6f | ||
|
|
8028416329 | ||
|
|
2c07c37bd4 | ||
|
|
295b6c7fbf | ||
|
|
2f769f1219 | ||
|
|
5140ae001f | ||
|
|
88e00a8b2f | ||
|
|
a30e4aaeca | ||
|
|
a25ada8416 | ||
|
|
1d68536ba1 | ||
|
|
3a0ac0f14c | ||
|
|
43524a8ef5 | ||
|
|
42abaf3bc9 | ||
|
|
a1bc4617d1 | ||
|
|
6ade41606a | ||
|
|
157673da8f | ||
|
|
6fe6ff565d | ||
|
|
2f8f950679 | ||
|
|
b535d7ed22 | ||
|
|
c86b527d13 | ||
|
|
ebd34c81b3 | ||
|
|
d2e61b692d | ||
|
|
5e89cf687a | ||
|
|
307df0c013 | ||
|
|
d6193d5636 |
2
.gitignore
vendored
@ -24,3 +24,5 @@ __pycache__/
|
|||||||
|
|
||||||
.tags
|
.tags
|
||||||
pp
|
pp
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
|||||||
8
.gitmodules
vendored
@ -1,7 +1,7 @@
|
|||||||
[submodule "external/micropython"]
|
[submodule "external/micropython"]
|
||||||
path = external/micropython
|
path = external/micropython
|
||||||
url = https://github.com/Coldcard/micropython.git
|
url = https://github.com/Coldcard/micropython.git
|
||||||
branch = master
|
branch = mk4-base
|
||||||
[submodule "external/ckcc-protocol"]
|
[submodule "external/ckcc-protocol"]
|
||||||
path = external/ckcc-protocol
|
path = external/ckcc-protocol
|
||||||
url = https://github.com/Coldcard/ckcc-protocol.git
|
url = https://github.com/Coldcard/ckcc-protocol.git
|
||||||
@ -14,3 +14,9 @@
|
|||||||
[submodule "stm32/mk4-bootloader/hal"]
|
[submodule "stm32/mk4-bootloader/hal"]
|
||||||
path = stm32/mk4-bootloader/hal
|
path = stm32/mk4-bootloader/hal
|
||||||
url = https://github.com/STMicroelectronics/STM32CubeL4.git
|
url = https://github.com/STMicroelectronics/STM32CubeL4.git
|
||||||
|
[submodule "misc/gpu/external/stm32c0xx_hal_driver"]
|
||||||
|
path = misc/gpu/external/stm32c0xx_hal_driver
|
||||||
|
url = https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git
|
||||||
|
[submodule "misc/gpu/external/cmsis_device_c0"]
|
||||||
|
path = misc/gpu/external/cmsis_device_c0
|
||||||
|
url = https://github.com/STMicroelectronics/cmsis_device_c0.git
|
||||||
|
|||||||
67
README.md
@ -1,6 +1,6 @@
|
|||||||
# Coldcard Wallet
|
# COLDCARD Hardware Wallet
|
||||||
|
|
||||||
Coldcard is a Cheap, Ultra-secure & Verifiable Hardware Wallet for Bitcoin.
|
Coldcard is an Affordable, Ultra-secure & Verifiable Hardware Wallet for Bitcoin.
|
||||||
Get yours at [Coldcard.com](http://coldcard.com)
|
Get yours at [Coldcard.com](http://coldcard.com)
|
||||||
|
|
||||||
[Follow @COLDCARDwallet on Twitter](https://twitter.com/coldcardwallet) to keep up
|
[Follow @COLDCARDwallet on Twitter](https://twitter.com/coldcardwallet) to keep up
|
||||||
@ -8,7 +8,13 @@ with the latest updates and security alerts.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Quick Links
|
||||||
|
|
||||||
|
- [Latest firmware changes and updates](releases/ChangeLog.md)
|
||||||
|
- [PGP signature file](releases/signatures.txt)
|
||||||
|
- [Firmware binaries](https://coldcard.com/downloads)
|
||||||
|
|
||||||
## Reproducible Builds
|
## Reproducible Builds
|
||||||
|
|
||||||
@ -18,23 +24,45 @@ has been automated using Docker. Steps are as follows:
|
|||||||
|
|
||||||
1. Install [Docker](https://www.docker.com) and start it.
|
1. Install [Docker](https://www.docker.com) and start it.
|
||||||
2. Install [make (GNUMake)](https://www.gnu.org/software/make/) if you don't already have it.
|
2. Install [make (GNUMake)](https://www.gnu.org/software/make/) if you don't already have it.
|
||||||
3. Checkout the code, and start the process.
|
3. Checkout a specific version of the code, and start the process.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone https://github.com/Coldcard/firmware.git
|
git clone https://github.com/Coldcard/firmware.git
|
||||||
cd firmware/stm32
|
cd firmware
|
||||||
make repro
|
# DOWNLOAD https://coldcard.com/downloads
|
||||||
|
# get a copy of binary into ./releases/2026-03-05T2052-v5.5.0-mk-coldcard.dfu
|
||||||
|
git checkout 2026-03-05T2052-v5.5.0
|
||||||
|
cd stm32
|
||||||
|
make -f MK4-Makefile repro
|
||||||
```
|
```
|
||||||
|
|
||||||
4. At the end of the process a clear confirmation message is shown, or the differences.
|
4. At the end of the process a clear confirmation message is shown, or the differences.
|
||||||
5. Build products can be found `firmware/stm32/built`.
|
5. Build products can be found `firmware/stm32/built`.
|
||||||
|
6. If you do not trust the results of `make repro` refer to `docs/notes-on-repro.md`
|
||||||
|
which breaks down the process.
|
||||||
|
7. Process for Q firmware is the same, but change `MK4-Makefile` in last step to `Q1-Makefile`
|
||||||
|
|
||||||
|
## Long-Lived Branches
|
||||||
|
|
||||||
|
We are now maintaining two branches: `master` and `edge`.
|
||||||
|
|
||||||
|
"Edge" will contain features that may not be ready for prime time,
|
||||||
|
such as Taproot or Miniscript. Our standards for releasing new Edge
|
||||||
|
versions are lower, so we can iterate faster and get these advancements
|
||||||
|
out to other developers.
|
||||||
|
|
||||||
|
Q and Mk series share the same code base. Individual files that are added,
|
||||||
|
or removed, can be see in differences between `shared/manifest_mk4.py`
|
||||||
|
and `shared/manifest_q1.py`. Common files are in `shared/manifest.py`.
|
||||||
|
Firmware built for Mk5, supports the Mk4 without any functional differences.
|
||||||
|
|
||||||
|
|
||||||
## Check-out and Setup
|
## Check-out and Setup
|
||||||
|
|
||||||
**NOTE** This is the `master` branch and covers the latest hardware (Mk4).
|
**NOTE** This is the `master` branch and covers the latest hardware (Mk and Q).
|
||||||
See branch `v4-legacy` for firmware which supports only Mk3/Mk2 and earlier.
|
See branch `v4-legacy` for firmware which supports only Mk3/Mk2 and earlier.
|
||||||
|
|
||||||
Do a checkout, recursively to get all the submodules:
|
Do a checkout, recursively, to get all the submodules:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
git clone --recursive https://github.com/Coldcard/firmware.git
|
git clone --recursive https://github.com/Coldcard/firmware.git
|
||||||
@ -57,7 +85,7 @@ git submodule update --init --recursive
|
|||||||
```
|
```
|
||||||
|
|
||||||
Do not use a path with any spaces in it. The Makefiles do not handle
|
Do not use a path with any spaces in it. The Makefiles do not handle
|
||||||
that well, and we're not planning to fix it.
|
that well and we're not planning to fix it.
|
||||||
|
|
||||||
Keep in mind that python requirements may change between versions,
|
Keep in mind that python requirements may change between versions,
|
||||||
so at the top level, do this command:
|
so at the top level, do this command:
|
||||||
@ -158,7 +186,16 @@ git clone --recursive https://github.com/Coldcard/firmware.git
|
|||||||
cd firmware
|
cd firmware
|
||||||
|
|
||||||
# Apply address patch
|
# Apply address patch
|
||||||
git apply unix/linux_addr.patch
|
# if unix/linux_addr.patch exists use below command
|
||||||
|
# not needed in current revision
|
||||||
|
# git apply unix/linux_addr.patch
|
||||||
|
|
||||||
|
# * below is needed for ubuntu 24.04
|
||||||
|
pushd external/micropython
|
||||||
|
git apply ../../ubuntu24_mpy.patch
|
||||||
|
popd
|
||||||
|
# *
|
||||||
|
|
||||||
|
|
||||||
# Create Python virtual environment and activate it
|
# Create Python virtual environment and activate it
|
||||||
python3 -m venv ENV # or virtualenv -p python3 ENV
|
python3 -m venv ENV # or virtualenv -p python3 ENV
|
||||||
@ -198,8 +235,8 @@ Top-level dirs:
|
|||||||
|
|
||||||
- shared code between desktop test version and real-deal
|
- shared code between desktop test version and real-deal
|
||||||
- expected to be largely in python, and higher-level
|
- expected to be largely in python, and higher-level
|
||||||
- new code found only on the Mk4 will be listed in `manifest_mk4.py` code exclusive
|
- code exclusive to the Mk4 or Mk5 will be listed in `manifest_mk4.py`, and
|
||||||
to earlier hardware is in `manifest_mk3.py`
|
to the Q will be listed in `manifest_q1.py`
|
||||||
|
|
||||||
`unix`
|
`unix`
|
||||||
|
|
||||||
@ -229,13 +266,14 @@ Top-level dirs:
|
|||||||
- however, you can inspect what code is on your coldcard and compare to this.
|
- however, you can inspect what code is on your coldcard and compare to this.
|
||||||
|
|
||||||
`stm32/mk4-bootloader`
|
`stm32/mk4-bootloader`
|
||||||
|
`stm32/q1-bootloader`
|
||||||
|
|
||||||
- 128k of factory-set code that you cannot change for Mk4
|
- 128k of factory-set code that you cannot change
|
||||||
- however, you can inspect what code is on your coldcard and compare to this.
|
- however, you can inspect what code is on your coldcard and compare to this.
|
||||||
|
|
||||||
`hardware`
|
`hardware`
|
||||||
|
|
||||||
- schematic and bill of materials for the Coldcard
|
- schematic and bill of materials for the Coldcard, all versions.
|
||||||
|
|
||||||
`unix/work/...`
|
`unix/work/...`
|
||||||
|
|
||||||
@ -248,3 +286,4 @@ Top-level dirs:
|
|||||||
## Support
|
## Support
|
||||||
|
|
||||||
Found a bug? Email: support@coinkite.com
|
Found a bug? Email: support@coinkite.com
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from setuptools import setup
|
|||||||
setup(
|
setup(
|
||||||
name='signit',
|
name='signit',
|
||||||
version='1.0',
|
version='1.0',
|
||||||
py_modules=['signit'],
|
py_modules=['signit', 'sigheader'],
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'Click',
|
'Click',
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
../stm32/bootloader/sigheader.py
|
../stm32/sigheader.py
|
||||||
@ -208,7 +208,9 @@ def readback(fname):
|
|||||||
if v & MK_2_OK: d.append('Mk2')
|
if v & MK_2_OK: d.append('Mk2')
|
||||||
if v & MK_3_OK: d.append('Mk3')
|
if v & MK_3_OK: d.append('Mk3')
|
||||||
if v & MK_4_OK: d.append('Mk4')
|
if v & MK_4_OK: d.append('Mk4')
|
||||||
if v & ~(MK_1_OK | MK_2_OK | MK_3_OK | MK_4_OK):
|
if v & MK_5_OK: d.append('Mk5')
|
||||||
|
if v & MK_Q1_OK: d.append('Q1')
|
||||||
|
if v & ~(MK_1_OK | MK_2_OK | MK_3_OK | MK_4_OK | MK_5_OK | MK_Q1_OK):
|
||||||
d.append('?other?')
|
d.append('?other?')
|
||||||
v = nv + '+'.join(d)
|
v = nv + '+'.join(d)
|
||||||
elif fld == 'timestamp':
|
elif fld == 'timestamp':
|
||||||
@ -244,7 +246,7 @@ def readback(fname):
|
|||||||
@click.option('--pubkey-num', '-k', type=int, help='Which key # to use for signing', default=0)
|
@click.option('--pubkey-num', '-k', type=int, help='Which key # to use for signing', default=0)
|
||||||
@click.option('--high_water', '-h', is_flag=True, help='Mark version as new highwater mark (no downgrades below this version)')
|
@click.option('--high_water', '-h', is_flag=True, help='Mark version as new highwater mark (no downgrades below this version)')
|
||||||
@click.option('--verbose', '-v', default=False, is_flag=True, help='Show numbers related to signature')
|
@click.option('--verbose', '-v', default=False, is_flag=True, help='Show numbers related to signature')
|
||||||
@click.option('--hw-compat', '-m', type=int, metavar='BITMASK', help="Set HW compat field (mk number)")
|
@click.option('--hw-compat', '-m', type=str, metavar='mk', help="Set HW compat field (hw_label value)")
|
||||||
@click.option('--backdate', type=int, metavar='DAYS',
|
@click.option('--backdate', type=int, metavar='DAYS',
|
||||||
help='Make downgrade attack test version', default=0)
|
help='Make downgrade attack test version', default=0)
|
||||||
@click.option('--build_dir', '-b', default='l-port/build-COLDCARD')
|
@click.option('--build_dir', '-b', default='l-port/build-COLDCARD')
|
||||||
@ -277,9 +279,12 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False,
|
|||||||
vectors = open(build_dir + '/firmware0.bin', 'rb').read()
|
vectors = open(build_dir + '/firmware0.bin', 'rb').read()
|
||||||
body = open(build_dir + '/firmware1.bin', 'rb').read()
|
body = open(build_dir + '/firmware1.bin', 'rb').read()
|
||||||
|
|
||||||
if hw_compat == 4:
|
if hw_compat in { 'mk4', '4', 'mk5', '5', 'mk' }:
|
||||||
hw_compat = MK_4_OK
|
# Mk4 and 5 can run the same firmware, once Mk5 support was added
|
||||||
elif hw_compat in {3, None}:
|
hw_compat = MK_4_OK | MK_5_OK
|
||||||
|
elif hw_compat == 'q1':
|
||||||
|
hw_compat = MK_Q1_OK
|
||||||
|
elif hw_compat in { 'mk3', '3'}:
|
||||||
hw_compat = MK_2_OK | MK_3_OK
|
hw_compat = MK_2_OK | MK_3_OK
|
||||||
else:
|
else:
|
||||||
assert not "known"
|
assert not "known"
|
||||||
@ -293,8 +298,12 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False,
|
|||||||
# bugfix: size must be non-page aligned, so extra bytes are erased past end
|
# bugfix: size must be non-page aligned, so extra bytes are erased past end
|
||||||
if (body_len % 4096) == 0:
|
if (body_len % 4096) == 0:
|
||||||
body_len += 512
|
body_len += 512
|
||||||
|
assert body_len % 512 == 0, body_len
|
||||||
assert body_len % 512 == 0, body_len
|
else:
|
||||||
|
# bugfix: PSRAM-based products (Mk4, Q1) need to erase 4k blocks, so
|
||||||
|
# trouble happens if final binary isn't aligned to that size.
|
||||||
|
body_len = align_to(body_len, 4096)
|
||||||
|
assert body_len % 4096 == 0, body_len
|
||||||
|
|
||||||
# pad out
|
# pad out
|
||||||
vectors = pad_to(vectors, FW_HEADER_OFFSET)
|
vectors = pad_to(vectors, FW_HEADER_OFFSET)
|
||||||
@ -312,14 +321,15 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False,
|
|||||||
pubkey_num=pubkey_num,
|
pubkey_num=pubkey_num,
|
||||||
timestamp=timestamp(backdate) )
|
timestamp=timestamp(backdate) )
|
||||||
|
|
||||||
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length
|
|
||||||
|
|
||||||
if hw_compat & MK_4_OK:
|
if hw_compat & MK_3_OK:
|
||||||
# new value for Mk4: limited only by final binary size, not SPI flash
|
|
||||||
USB_MAX_LEN = 1472 * 1024
|
|
||||||
else:
|
|
||||||
# actual file length limited by size of SPI flash area reserved to txn data/uploads
|
# actual file length limited by size of SPI flash area reserved to txn data/uploads
|
||||||
|
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length
|
||||||
USB_MAX_LEN = (786432-128)
|
USB_MAX_LEN = (786432-128)
|
||||||
|
else:
|
||||||
|
# new value for Mk4 and later: limited only by final binary size, not SPI flash
|
||||||
|
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH_MK4, hdr.firmware_length
|
||||||
|
USB_MAX_LEN = 1472 * 1024
|
||||||
|
|
||||||
assert hdr.firmware_length <= USB_MAX_LEN, \
|
assert hdr.firmware_length <= USB_MAX_LEN, \
|
||||||
"too big for our USB upgrades: %d = %d bytes too big" % (
|
"too big for our USB upgrades: %d = %d bytes too big" % (
|
||||||
|
|||||||
@ -3,14 +3,32 @@
|
|||||||
These docs are meant for you hackers out there... but also for anyone who
|
These docs are meant for you hackers out there... but also for anyone who
|
||||||
wants to understand why it's safe to put your moneys into Coldcard.
|
wants to understand why it's safe to put your moneys into Coldcard.
|
||||||
|
|
||||||
|
- [`security-model.md`](security-model.md) The COLDCARD Mk4/Mk5/Q security model.
|
||||||
- [`pin-entry.md`](pin-entry.md) Huge and detailed discussion of PIN codes and the security element that holds the secrets.
|
- [`pin-entry.md`](pin-entry.md) Huge and detailed discussion of PIN codes and the security element that holds the secrets.
|
||||||
|
- [`secure-elements.md`](secure-elements.md) How the dual secure elements work together.
|
||||||
- [`dev-access.md`](dev-access.md) How developers can modify Coldcard to extend it.
|
- [`dev-access.md`](dev-access.md) How developers can modify Coldcard to extend it.
|
||||||
- [`memory-map.md`](memory-map.md) Memory map highlights
|
- [`memory-map.md`](memory-map.md) Memory map highlights
|
||||||
|
- [`notes-on-repro.md`](notes-on-repro.md) Detailed breakdown of the reproducible build process.
|
||||||
|
- [`upgrade-recovery.md`](upgrade-recovery.md) Firmware upgrade and recovery process.
|
||||||
- [`backup-files.md`](backup-files.md) Some details of our encrypted backup files.
|
- [`backup-files.md`](backup-files.md) Some details of our encrypted backup files.
|
||||||
|
- [`temporary-seeds.md`](temporary-seeds.md) Temporary (ephemeral) seeds and the Seed Vault.
|
||||||
|
- [`seed-xor.md`](seed-xor.md) More about _Seed XOR_ feature, including fully worked Seed XOR example, and useful XOR lookup chart.
|
||||||
|
- [`key-teleport.md`](key-teleport.md) Key Teleport: encrypted transfer of seeds and secrets between Q devices.
|
||||||
|
- [`spending-policy.md`](spending-policy.md) Spending policy: autonomous signing with configurable limits.
|
||||||
|
- [`microsd-2fa.md`](microsd-2fa.md) Using a MicroSD card as a second factor for login.
|
||||||
|
- [`web2fa.md`](web2fa.md) Web 2FA authentication.
|
||||||
|
- [`bip85-passwords.md`](bip85-passwords.md) Deriving deterministic passwords via BIP-85.
|
||||||
|
- [`msg-signing.md`](msg-signing.md) COLDCARD message signing.
|
||||||
|
- [`proof-of-reserves-bip-322.md`](proof-of-reserves-bip-322.md) BIP-322 generic signed message format and proof of reserves.
|
||||||
|
- [`generic-wallet-export.md`](generic-wallet-export.md) Generic JSON wallet export file format.
|
||||||
|
- [`bip-21-extensions.md`](bip-21-extensions.md) Coldcard's BIP-21 URI extensions, including multisig ownership address check.
|
||||||
|
- [`nfc-coldcard.md`](nfc-coldcard.md) NFC support on Coldcard Mk4 and Q.
|
||||||
|
- [`nfc-pushtx.md`](nfc-pushtx.md) NFC Push Transaction: broadcast a signed transaction via your phone.
|
||||||
|
- [`usb-batteries.md`](usb-batteries.md) Using USB battery packs with Coldcard.
|
||||||
- [`electrum-usage.md`](electrum-usage.md) Importing seed words into Electrum for funds usage (and other tips).
|
- [`electrum-usage.md`](electrum-usage.md) Importing seed words into Electrum for funds usage (and other tips).
|
||||||
- [`bitcoin-core-usage.md`](bitcoin-core-usage.md) How to use with Bitcoin Core.
|
- [`bitcoin-core-usage.md`](bitcoin-core-usage.md) How to use with Bitcoin Core.
|
||||||
|
- [`bitcoin-core2of2desc.md`](bitcoin-core2of2desc.md) Airgapped 2-of-2 multisig with Bitcoin Core using descriptors.
|
||||||
- [`limitations.md`](limitations.md) Documented limitations, policy choices, and TODO items.
|
- [`limitations.md`](limitations.md) Documented limitations, policy choices, and TODO items.
|
||||||
- [`paperwallet.pdf`](paperwallet.pdf) Example paper wallet template file.
|
- [`paperwallet.pdf`](paperwallet.pdf) Example paper wallet template file.
|
||||||
- [`seed-xor.md`](seed-xor.md) More about _Seed XOR_ feature, including fully worked Seed XOR example, and useful XOR lookup chart.
|
|
||||||
- [`menu-tree.txt`](menu-tree.txt) Dump of the menu system. Incomplete, may be out of date.
|
- [`menu-tree.txt`](menu-tree.txt) Dump of the menu system. Incomplete, may be out of date.
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,17 @@ a single file, which is a simple text file and
|
|||||||
easy to read. Before version 4.0.0, this text file was always
|
easy to read. Before version 4.0.0, this text file was always
|
||||||
called `ckcc-backup.txt`, but the filename is now picked randomly.
|
called `ckcc-backup.txt`, but the filename is now picked randomly.
|
||||||
|
|
||||||
|
## BIP39 Passphrase
|
||||||
|
|
||||||
|
If BIP39 passphrase is active the default behavior is to back-up
|
||||||
|
main wallet - not BIP39 passphrase wallet. From version `5.2.0`
|
||||||
|
users can choose to back-up also BIP39 passphrase wallet.
|
||||||
|
|
||||||
|
## Ephemeral Seeds
|
||||||
|
|
||||||
|
If ephemeral seed is active the default behavior is to always
|
||||||
|
back-up ephemeral wallet instead of the main wallet.
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
- The archive file names are not encrypted. You can see there is a single
|
- The archive file names are not encrypted. You can see there is a single
|
||||||
|
|||||||
15
docs/bip-21-extensions.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
## Multisig Ownership address check: "wallet"
|
||||||
|
|
||||||
|
If the name of the multisig wallet related to an address is provided, address search
|
||||||
|
can be greatly accelerated. Just provide `wallet=name` parameter in a standard
|
||||||
|
[BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) URL
|
||||||
|
shown in QR code or NFC record. If omitted, search will continue across
|
||||||
|
all multisig wallets known by COLDCARD.
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=goldmine
|
||||||
|
|
||||||
|
bitcoin:mtHSVByP9EYZmB26jASDdPVm19gvpecb5R?label=coldcard_purchase&amount=50&wallet=Haystack%20Four
|
||||||
|
```
|
||||||
@ -1,19 +1,17 @@
|
|||||||
# BIP-85 Passwords
|
# BIP-85 Passwords
|
||||||
|
|
||||||
This feature derives a deterministic password according from your seed,
|
This feature derives a deterministic password from your seed,
|
||||||
according to [BIP-85](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki)
|
according to [BIP-85 PWD BASE64](https://github.com/bitcoin/bips/blob/master/bip-0085.mediawiki#pwd-base64).
|
||||||
(with the recent changes
|
|
||||||
[proposed here](https://github.com/scgbckbone/bips/blob/passwords/bip-0085.mediawiki)).
|
|
||||||
Generated passwords can be sent as keystrokes via USB to the host computer,
|
Generated passwords can be sent as keystrokes via USB to the host computer,
|
||||||
effectively using Coldcard as specialized password manager.
|
effectively using Coldcard as specialized password manager.
|
||||||
|
|
||||||
In addition to deriving up to 10,000 distinct secure passwords, the Coldcard Mk4
|
In addition to deriving up to 10,000 distinct secure passwords, the Coldcard
|
||||||
can also type them into a computer by emulating a USB keyboard, and simulating the
|
can also type them into a computer by emulating a USB keyboard, and simulating the
|
||||||
keystrokes needed to type the password.
|
keystrokes needed to type the password.
|
||||||
|
|
||||||
#### Requirements
|
#### Requirements
|
||||||
|
|
||||||
* Coldcard Mk4 with version 5.0.5 or newer
|
* Coldcard Mk4 or Mk5 (firmware 5.0.5 or newer), or any Q
|
||||||
* USB-C with data link (won't work with power only cable from Coinkite)
|
* USB-C with data link (won't work with power only cable from Coinkite)
|
||||||
|
|
||||||
## Type Passwords over USB
|
## Type Passwords over USB
|
||||||
@ -34,11 +32,13 @@ to exit. Exiting from "Type Passwords" will cause Coldcard to turn off keyboard
|
|||||||
1. Go to Advanced/Tools -> Derive Seed B85 -> Passwords
|
1. Go to Advanced/Tools -> Derive Seed B85 -> Passwords
|
||||||
2. Choose "Password/Index number" (BIP-85 index) and press OK to generate password.
|
2. Choose "Password/Index number" (BIP-85 index) and press OK to generate password.
|
||||||
3. Screen shows generated password, path, and entropy from which password was derived
|
3. Screen shows generated password, path, and entropy from which password was derived
|
||||||
4. A few different options are available at this point:
|
4. A few different options are available at this point (on Mk; on Q the NFC and
|
||||||
1. press 1 to save password backup file on MicroSD card (cleartext!)
|
QR buttons are used instead of (3)/(4)):
|
||||||
2. press 2 to send keystrokes (this will first of all enable keyboard emulation, then send keystrokes + enter, and finally disables keyboard emulation)
|
1. press (1) to save password backup file on MicroSD card (cleartext!)
|
||||||
3. press 3 to view password as QR code
|
2. press (2) to save to Virtual Disk (only when available)
|
||||||
4. press 4 to send over NFC (only appears when NFC is enabled)
|
3. press (3) to send over NFC (only appears when NFC is enabled)
|
||||||
|
4. press (4) to view password as QR code
|
||||||
|
5. press (6) to send keystrokes over USB (this enables keyboard emulation, sends keystrokes + enter, then disables keyboard emulation)
|
||||||
|
|
||||||
## Keyboard language settings
|
## Keyboard language settings
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ Step 2: Export descriptor from Coldcard to Core
|
|||||||
- in Bitcoin Core, go to Windows -> Console
|
- in Bitcoin Core, go to Windows -> Console
|
||||||
- select your newly created descriptor wallet in the wallet pulldown (top left)
|
- select your newly created descriptor wallet in the wallet pulldown (top left)
|
||||||
- paste the `importdescriptor` command. It should respond with a success message
|
- paste the `importdescriptor` command. It should respond with a success message
|
||||||
|
- in Bitcoin Core v24.1, the console response will include `"message": "Ranged descriptors should not have a label"` and Bitcoin Core won't allow address generation. Removing the entry `"label": "Coldcard x0x0x0x0"` from the .txt file fixes this issue.
|
||||||
|
|
||||||
NOTE: If you are importing an existing wallet this way, with UTXO on the blockchain,
|
NOTE: If you are importing an existing wallet this way, with UTXO on the blockchain,
|
||||||
you may need to rescan and/or delete "timestamp=now" from the command. If the
|
you may need to rescan and/or delete "timestamp=now" from the command. If the
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
# Ephemeral Seeds
|
|
||||||
|
|
||||||
Ephemeral seed is temporary secret stored only in Coldcard volatile
|
|
||||||
memory (RAM). It only survives single boot, meaning after Coldcard
|
|
||||||
restart it is gone. Ephemeral seeds *completely* defeats the design
|
|
||||||
of Coldcard's security model, based on secure elements.
|
|
||||||
|
|
||||||
Make sure you know what you're doing!
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
- go to `Advanced/Tools -> Ephemeral Seed`
|
|
||||||
- if ephemeral seed is already in use, the menu option `CLEAR [<xfp>]` is visible
|
|
||||||
with fingerprint of ephemeral master secret
|
|
||||||
- an ephemeral seed can be Imported or Generated at random
|
|
||||||
- `Generate`:
|
|
||||||
- `Advanced/Tools -> Ephemeral Seed -> Generate`
|
|
||||||
- same options as generating new seeds, dice rolls included
|
|
||||||
- `Import`:
|
|
||||||
- `Advanced/Tools -> Ephemeral Seed -> Import`
|
|
||||||
- same options as importing seeds
|
|
||||||
- an ephemeral seed can also be a BIP-85 derived value
|
|
||||||
|
|
||||||
## Trick PIN Notes
|
|
||||||
|
|
||||||
If you intend to use the ephemeral seed feature frequently, you can
|
|
||||||
define a "Trick PIN" which takes you to a "look blank" trick wallet
|
|
||||||
(ie. no seed set appears to be set). Then you may then safely
|
|
||||||
unlock your Coldcard, without revealing the true PIN, and perform
|
|
||||||
all your ephemeral seed work in that state.
|
|
||||||
|
|
||||||
## Purpose
|
|
||||||
|
|
||||||
This feature is intended for those one-off signings, like recovering
|
|
||||||
a lost seed from some other system or importing some seed as an
|
|
||||||
balance check. We do not recommend handing unencrypted seed material
|
|
||||||
on a regular basis!
|
|
||||||
|
|
||||||
@ -5,9 +5,12 @@ wallet systems, but we also have a file format for general purpose
|
|||||||
exports, which we hope future wallet makers will leverage.
|
exports, which we hope future wallet makers will leverage.
|
||||||
|
|
||||||
It contains master XPUB, XFP for that, and derived values for the top hardened
|
It contains master XPUB, XFP for that, and derived values for the top hardened
|
||||||
position of BIP44, BIP84 and BIP49.
|
position of the single-signature schemes BIP44, BIP49 and BIP84, plus the
|
||||||
|
multisig schemes BIP48 (`bip48_1` = `.../1h` P2SH-P2WSH and `bip48_2` = `.../2h` P2WSH).
|
||||||
|
When the account number is zero, a BIP45 (`m/45h`) multisig section is also included
|
||||||
|
(it is omitted for non-zero accounts, as in the example below).
|
||||||
|
|
||||||
The feature can be found here: _Advanced > MicroSD > Export Wallet > Generic JSON_
|
The feature can be found here: _Advanced/Tools > Export Wallet > Generic JSON_
|
||||||
|
|
||||||
Please contact us (or better yet, make a pull request), if you need something
|
Please contact us (or better yet, make a pull request), if you need something
|
||||||
more in this file.
|
more in this file.
|
||||||
@ -18,32 +21,51 @@ Here is an example, produced by the Simulator for account number 123.
|
|||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
"chain": "XTN",
|
"chain": "BTC",
|
||||||
"xfp": "0F056943",
|
"xfp": "0F056943",
|
||||||
"xpub": "tpubD6NzVbkrYhZ4XzL5Dhayo67Gorv1YMS7j8pRUvVMd5odC2LBPLAygka9p7748JtSq82FNGPppFEz5xxZUdasBRCqJqXvUHq6xpnsMcYJzeh",
|
|
||||||
"account": 123,
|
"account": 123,
|
||||||
|
"xpub": "xpub661MyMwAqRbcGC9DmWbtbAmuUjpMYxw4BWE88NSDHB3jSjfUK7KtYJuKa52GbowD3DVLkgsxH9QwPnTx5mjdHykYFEncnmAsNsCTbWzBhA7",
|
||||||
"bip44": {
|
"bip44": {
|
||||||
"deriv": "m/44'/1'/123'",
|
|
||||||
"first": "n44vs1Rv7T8SANrg2PFGQhzVkhr5Q6jMMD",
|
|
||||||
"name": "p2pkh",
|
"name": "p2pkh",
|
||||||
"xfp": "B7908B26",
|
"xfp": "5F898064",
|
||||||
"xpub": "tpubDCiHGUNYdRRGoSH22j8YnruUKgguCK1CC2NFQUf9PApeZh8ewAJJWGMUrhggDNK73iCTanWXv1RN5FYemUH8UrVUBjqDb8WF2VoKmDh9UTo"
|
"deriv": "m/44h/0h/123h",
|
||||||
|
"xpub": "xpub6DStQXfAgHuLbMpCf86ruVkF4yT9pSLyWsFiqQTWY9osuinq8Dyee4W5jCjMfyku5LNkRB9oFinrY5ufn9XXEn8Vvzc2jnifKMaQCNV7RBZ",
|
||||||
|
"desc": "pkh([0f056943/44h/0h/123h]xpub6DStQXfAgHuLbMpCf86ruVkF4yT9pSLyWsFiqQTWY9osuinq8Dyee4W5jCjMfyku5LNkRB9oFinrY5ufn9XXEn8Vvzc2jnifKMaQCNV7RBZ/<0;1>/*)#4tl8jryn",
|
||||||
|
"first": "1GTNtzG5xX2UhdD5e3Nu7i1WPxFdjxQMJt"
|
||||||
},
|
},
|
||||||
"bip49": {
|
"bip49": {
|
||||||
"_pub": "upub5DMRSsh6mNak9KbcVjJ7xAgHJvbE3Nx22CBTier5C35kv8j7g2q58ywxskBe6JCcAE2VH86CE2aL4MifJyKbRw8Gj9ay7SWvUBkp2DJ7y52",
|
"name": "p2sh-p2wpkh",
|
||||||
"deriv": "m/49'/1'/123'",
|
"xfp": "A748B1FC",
|
||||||
"first": "2N87V39riUUCd4vmXfDjMWAu9gUCiBji5jB",
|
"deriv": "m/49h/0h/123h",
|
||||||
"name": "p2wpkh-p2sh",
|
"xpub": "xpub6DDm8WzH5a9qjKkttzqSB3uGofNohU9D3n3UG8WMxkUZzJEMPTYiQRf1dvTFCQR82MjGW4LUMVuTtnW4hF17RpzCqVwhf6Z2fnJPWtjG164",
|
||||||
"xfp": "CEE1D809",
|
"desc": "sh(wpkh([0f056943/49h/0h/123h]xpub6DDm8WzH5a9qjKkttzqSB3uGofNohU9D3n3UG8WMxkUZzJEMPTYiQRf1dvTFCQR82MjGW4LUMVuTtnW4hF17RpzCqVwhf6Z2fnJPWtjG164/<0;1>/*))#5j7t2n2u",
|
||||||
"xpub": "tpubDCDqt7XXvhAdy1MpSze5nMJA9x8DrdRaKALRRPasfxyHpiqWWEAr9cbDBQ9BcX7cB3up98Pk97U2QQ3xrvQsi5dNPmRYYhdcsKY9wwEY87T"
|
"_pub": "ypub6Y42SBfCEFhKacx1jMd4P8zmydXFe68hxtZh3XQFLkrT3Q3ae7iH2VK9f8QqCK53Rzr5FXw2pAG1n57dQwR8E4fohqe8F1NWwWN2uVRfBry",
|
||||||
|
"first": "3CeBRbJKCpg7BpJME2vM8ZxhCjBnhG4toy"
|
||||||
},
|
},
|
||||||
"bip84": {
|
"bip84": {
|
||||||
"_pub": "vpub5Y5a91QvDT45EnXQaKeuvJupVvX8f9BiywDcadSTtaeJ1VgJPPXMitnYsqd9k7GnEqh44FKJ5McJfu6KrihFXhAmvSWgm7BAVVK8Gupu4fL",
|
|
||||||
"deriv": "m/84'/1'/123'",
|
|
||||||
"first": "tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l",
|
|
||||||
"name": "p2wpkh",
|
"name": "p2wpkh",
|
||||||
"xfp": "78CF94E5",
|
"xfp": "2C5207AA",
|
||||||
"xpub": "tpubDC7jGaaSE66VDB6VhEDFYQSCAyugXmfnMnrMVyHNzW9wryyTxvha7TmfAHd7GRXrr2TaAn2HXn9T8ep4gyNX1bzGiieqcTUNcu2poyntrET"
|
"deriv": "m/84h/0h/123h",
|
||||||
|
"xpub": "xpub6CaWStGvcXqSW9BzU2vpCoP7aWjz9VfR5DS2nuYWVvKV2nug2dESg3HdFsaWHeoZaxuAhNcPB3TH2gq8MugS3JX1yGuhB4QbC2BneaYqB16",
|
||||||
|
"desc": "wpkh([0f056943/84h/0h/123h]xpub6CaWStGvcXqSW9BzU2vpCoP7aWjz9VfR5DS2nuYWVvKV2nug2dESg3HdFsaWHeoZaxuAhNcPB3TH2gq8MugS3JX1yGuhB4QbC2BneaYqB16/<0;1>/*)#yk84tprf",
|
||||||
|
"_pub": "zpub6rF34DckutvQCjaE8kW4cya7vT2t2jeQuSUUMhLHFw5F8zY8XwZZvAbuJHVgHU7QQF8nCKoW6NANoG4FoJWTdmtDhxJYLt3ZjUK5RqUSMdF",
|
||||||
|
"first": "bc1qhj6avwmp5lhpgqwm6dgxrf3v5lf67rjm99a8an"
|
||||||
|
},
|
||||||
|
"bip48_1": {
|
||||||
|
"name": "p2sh-p2wsh",
|
||||||
|
"xfp": "845A3542",
|
||||||
|
"deriv": "m/48h/0h/123h/1h",
|
||||||
|
"xpub": "xpub6EkcQSTygvxVnBP2X2fM6HY5D7wv46tWbBc54ADaypuCr47vQh1GPdPAZFdx81ou5Rp4vBnzeJT5MDWDZstzijxkHfrofXRycpt1ASfg1La",
|
||||||
|
"desc": "sh(wsh(sortedmulti(M,[0f056943/48h/0h/123h/1h]xpub6EkcQSTygvxVnBP2X2fM6HY5D7wv46tWbBc54ADaypuCr47vQh1GPdPAZFdx81ou5Rp4vBnzeJT5MDWDZstzijxkHfrofXRycpt1ASfg1La/0/*,...)))",
|
||||||
|
"_pub": "Ypub6kUxqLsLQa4M43jXJ3ux8SyP6t8dD5ZbpZmxkpP1jc7VXLW4RkZ76ouEPAZ1gMgiiXzrYFPfzBC8MfjYaoTxfTm1zUfdeqiTnHDX8raCfeg"
|
||||||
|
},
|
||||||
|
"bip48_2": {
|
||||||
|
"name": "p2wsh",
|
||||||
|
"xfp": "2A01C6B0",
|
||||||
|
"deriv": "m/48h/0h/123h/2h",
|
||||||
|
"xpub": "xpub6EkcQSTygvxVneXmk3ywiS2PFhBdiPxeMxYf6RFxHCHH36NxdcN7DjUpudCppAAxs58CG6DQLjtqZNmyC3MpgVob6wpdeATjpZZ1woX92EF",
|
||||||
|
"desc": "wsh(sortedmulti(M,[0f056943/48h/0h/123h/2h]xpub6EkcQSTygvxVneXmk3ywiS2PFhBdiPxeMxYf6RFxHCHH36NxdcN7DjUpudCppAAxs58CG6DQLjtqZNmyC3MpgVob6wpdeATjpZZ1woX92EF/0/*,...))",
|
||||||
|
"_pub": "Zpub75KE91YFZFbpup5PMS2AxgZCKRWnozdEWTEmaUKGQysSmUaKuL5WYyf2kk5UNQhhupRnddQe9GzST7crvfLoRTHTg6KtDPZiFjxBJobzcUz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -51,16 +73,23 @@ Here is an example, produced by the Simulator for account number 123.
|
|||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
1. The `first` address is formed by added `/0/0` onto the given derivation, and is assumed
|
1. The `first` address is formed by added `/0/0` onto the given derivation, and is assumed
|
||||||
to be the first (non-change) receive address for the wallet.
|
to be the first (non-change) receive address for the wallet. It is only present on the
|
||||||
|
single-signature sections (`bip44`, `bip49`, `bip84`); multisig sections omit it.
|
||||||
|
|
||||||
|
1a. Each section includes a `desc` field: a ready-to-import Bitcoin output descriptor
|
||||||
|
(with `#checksum`). Single-sig descriptors use the `<0;1>/*` multipath form. Multisig
|
||||||
|
sections (`bip48_1`, `bip48_2`, and `bip45` when present) emit a `sortedmulti(...)`
|
||||||
|
template with `M` and a trailing `...` as placeholders, to be completed with your
|
||||||
|
threshold and the other co-signers' keys.
|
||||||
|
|
||||||
2. The user may specify any value (up to 9999) for the account number, and it's meant to
|
2. The user may specify any value (up to 9999) for the account number, and it's meant to
|
||||||
segregate funds into sub-wallets. Don't assume it's zero.
|
segregate funds into sub-wallets. Don't assume it's zero.
|
||||||
|
|
||||||
3. When making your PSBT files to spend these amounts, remember that the XFP of the master
|
3. When making your PSBT files to spend these amounts, remember that the XFP of the master
|
||||||
(`0F056943` in this example) is is the root of the subkey paths found in the file, and
|
(`0F056943` in this example) is the root of the subkey paths found in the file, and
|
||||||
you must include the full derivation path from master. So based on this example,
|
you must include the full derivation path from master. So based on this example,
|
||||||
to spend a UTXO on `tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l`, the input section
|
to spend a UTXO on `bc1qhj6avwmp5lhpgqwm6dgxrf3v5lf67rjm99a8an`, the input section
|
||||||
of your PSBT would need to specify `(m=0F056943)/84'/1'/123'/0/0`.
|
of your PSBT would need to specify `(m=0F056943)/84'/0'/123'/0/0`.
|
||||||
|
|
||||||
4. The `_pub` value is the [SLIP-132](https://github.com/satoshilabs/slips/blob/master/slip-0132.md) style "ypub/zpub/etc" which some systems might want. It implies
|
4. The `_pub` value is the [SLIP-132](https://github.com/satoshilabs/slips/blob/master/slip-0132.md) style "ypub/zpub/etc" which some systems might want. It implies
|
||||||
a specific address format.
|
a specific address format.
|
||||||
|
|||||||
224
docs/key-teleport.md
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
|
||||||
|
# Key Teleport
|
||||||
|
|
||||||
|
Purpose: Send a small quantity of very secret data between two COLDCARD Q systems, with
|
||||||
|
no risk of anything in the middle learning the secret.
|
||||||
|
|
||||||
|
Method: ECDH and AES-256-CTR plus an extra wrapping layer, transmitted over a mixture of
|
||||||
|
NFC, passive websites, and QR/BBQr codes.
|
||||||
|
|
||||||
|
# Protocol Overview
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
- Receiver picks an EC keypair, stores it in settings, and publishes the pubkey via a QR/NFC
|
||||||
|
- The pubkey is encrypted by a short 8-digit numeric code, which should be
|
||||||
|
sent by a different channel.
|
||||||
|
- Sender gets QR and numeric code, picks own keypair, and does ECDH to arrive at a
|
||||||
|
shared session key
|
||||||
|
- Sender picks a human-readable secret which is independent of anything else (P key)
|
||||||
|
- The secret data (perhaps a seed phrase, XPRV, secure note, full backup, etc) is
|
||||||
|
AES-256-CTR encrypted with P key, then encrypted + MAC added with session key
|
||||||
|
- Data packet is sent to receiver (via BBQr), who can reconstruct the session key via ECDH
|
||||||
|
- Prompt user for the P key to finish decoding
|
||||||
|
- Decoded secret value is saved to Seed Vault or secure notes as appropriate
|
||||||
|
- Receiver destroys EC keypair used in transfer
|
||||||
|
|
||||||
|
### When used for PSBT Multisig
|
||||||
|
|
||||||
|
- No action required on receiver
|
||||||
|
- Sender uses the pubkey derived from pre-shared XPUB involved in the multisig wallet.
|
||||||
|
- Same steps, but drops immediately into signing process when decoded correctly
|
||||||
|
|
||||||
|
## Notes and Limitations
|
||||||
|
|
||||||
|
- max 4k (after encoding) of data is possible due to HTTP limitations
|
||||||
|
- all transfers are "data typed" and decode only on COLDCARD
|
||||||
|
- Q model is required due to the use of QR codes to ultimately get data into the COLDCARD
|
||||||
|
|
||||||
|
|
||||||
|
# Details
|
||||||
|
|
||||||
|
## Data Type Codes
|
||||||
|
|
||||||
|
The first byte encodes what the package contents (under all the encryption).
|
||||||
|
|
||||||
|
- `s` - 12/18/24 words/raw master/xprv - 17-72 bytes follow, encoded in an internal format
|
||||||
|
- `x` - XPRV mode, full details - 4 bytes (XPRV) + base58 *decoded* binary-XPRV follows
|
||||||
|
- `n` - one or many notes export (JSON array)
|
||||||
|
- `v` - seed vault export (JSON: one secret key but includes name, source of key)
|
||||||
|
- `p` - binary PSBT to be signed, perhaps multisig but not required.
|
||||||
|
- `b` - complete system backup file (text lines, internal format)
|
||||||
|
|
||||||
|
## QR details
|
||||||
|
|
||||||
|
BBQr is always used for the QR's involved in this process, even if
|
||||||
|
they are short enough for a normal QR code. Because the BBQr is
|
||||||
|
being generated by the COLDCARD embedded firmware, it will not be
|
||||||
|
compressed and will always be Base32 encoded.
|
||||||
|
|
||||||
|
New type codes for BBQr are defined for the purposes of this application:
|
||||||
|
|
||||||
|
- `R` contains `(pubkey)` ... begins the process from receiver; compressed pubkey is 33 bytes
|
||||||
|
- `S` contains `(pubkey)(data)` ... data from sender; first 33 bytes are sender's pubkey
|
||||||
|
- `E` for Multisig PSBT: `(randint)(data)` ... randint (4 byte nonce) indicates which
|
||||||
|
derived subkey from pre-shared xpub associated with receiver
|
||||||
|
|
||||||
|
All the data is encrypted with the exception randint. Keep in mind
|
||||||
|
this is a nonce value picked uniquely for each transfer. The
|
||||||
|
receiver's pubkey is only weakly encrypted by the 8-digit numeric
|
||||||
|
password, but is also a nonce effectively.
|
||||||
|
|
||||||
|
### PSBT Key Selection
|
||||||
|
|
||||||
|
When sending PSBT data, a nonce is picked at random by the sender
|
||||||
|
in range: `0..(2^28)`
|
||||||
|
|
||||||
|
This nonce is called `randint`. The receiver's pubkey will be
|
||||||
|
|
||||||
|
.../20250317/(randint)
|
||||||
|
|
||||||
|
where `...` is the derivation used in the multisig wallet for the co-signer who will
|
||||||
|
receive the package. The sender's keypair has the same sub key path assuming all
|
||||||
|
co-signers have same derivation path from root (not required).
|
||||||
|
|
||||||
|
Because both the sender and receiver already have each other's XPUB they can derive
|
||||||
|
the appropriate pubkeys (and privkey for their side) without communicating
|
||||||
|
more than `randint`. The sending COLDCARD will pick a new random value each time.
|
||||||
|
|
||||||
|
When receiving a multisig PSBT encrypted this way, the receiver does not need
|
||||||
|
to do any setup (nor numeric password) and can receive a QR code at any time.
|
||||||
|
This works because the shared multisig wallet is already setup. Receiver will
|
||||||
|
take the nonce value (randint) and seach all pre-defined multisig wallets for
|
||||||
|
any pubkey that can decrypt the package successfully (based on checksum inside
|
||||||
|
first layer of ECDH encryption).
|
||||||
|
|
||||||
|
The next layer of encryption (paranoid password) is unchanged.
|
||||||
|
|
||||||
|
## Encryption Details
|
||||||
|
|
||||||
|
AES-256-CTR is used exclusively. Session key is picked via ECDH with final
|
||||||
|
key value being the SHA256 over 64 bytes of coordinate X (concat) Y.
|
||||||
|
|
||||||
|
While ECDH is enough to assure privacy from men in the middle, we
|
||||||
|
add an additional layer of encryption. We call this the "paranoid key" internally
|
||||||
|
and in the UX it is called "Teleport Password".
|
||||||
|
|
||||||
|
The user sees a random 8-character password, generated as a random 40-bit value, but
|
||||||
|
shown in Base32 (8 chars) for the human to enter. We apply PBKDF2-SHA512 with
|
||||||
|
an iteration count of 5000 to stretch that to 512 bits, of which we use half.
|
||||||
|
The session key is used as the key for the KDF, and the entered value as salt.
|
||||||
|
|
||||||
|
- ECDH arrives at session key
|
||||||
|
- decrypt (AES-256-CTR) the binary body of message
|
||||||
|
- verify checksum:
|
||||||
|
- final 2 bytes should be `== SHA256(decrypted body[0:-2])[-2:]`
|
||||||
|
- if not, corruption, truncation, or wrong keys
|
||||||
|
- if that decryption is correct, then prompt user for the paranoid key (8 chars)
|
||||||
|
- stretch that value using session key and 5000 iterations of PBKDF2-SHA512
|
||||||
|
- use upper 256 bits and run AES-256-CTR again
|
||||||
|
- same checksum of 2 bytes of SHA256 are found inside after decryption
|
||||||
|
|
||||||
|
Encryption adds 4 bytes of overhead because of these MAC values,
|
||||||
|
but should catch truncation and bitrot. There are no other
|
||||||
|
protections against truncation as length data is not transmitted.
|
||||||
|
|
||||||
|
# Receiver Password
|
||||||
|
|
||||||
|
When the teleport process is started, the receiver shares his pubkey
|
||||||
|
as QR. However, we also show an 8-digit numeric password. The
|
||||||
|
purpose of this is force the receiver to share this separately from
|
||||||
|
the pubkey QR on another channel. The code is randomly picked, but
|
||||||
|
only represents about 26 bits of entropy and is stretched with
|
||||||
|
a single round of SHA256 before being used as a AES-256-CTR key
|
||||||
|
to decrypt the pubkey. No checksum verifies correct
|
||||||
|
decryption, so any code is accepted, and will with near-50% odds,
|
||||||
|
decrypt to a valid pubkey.
|
||||||
|
|
||||||
|
When the sender is given the receiver's pubkey via QR code, it
|
||||||
|
prompts for the numeric code and uses it to decrypt the pubkey.
|
||||||
|
Thus a MiTM who injects their pubkey will be detected and blocked.
|
||||||
|
|
||||||
|
The "paranoid key" serves the same role in the other direction but
|
||||||
|
it is Base32 character set, so it will not look similar or be
|
||||||
|
confusing as to its purpose.
|
||||||
|
|
||||||
|
# Web Component
|
||||||
|
|
||||||
|
In order to "teleport" the contents of a QR code over NFC, we will
|
||||||
|
publish a static website directly from an open Github repository.
|
||||||
|
The single-page website contains javascript code which looks at the
|
||||||
|
"hash" part of the incoming URL (`window.location.hash`) and if it
|
||||||
|
meets the requirements, renders a large QR. The QR data must look like
|
||||||
|
a correctly-encoded BBQr with one of the 3 type-codes above (`R` `S` or `E`).
|
||||||
|
Otherwise the website could render any QR, which we don't want to
|
||||||
|
support.
|
||||||
|
|
||||||
|
The page will offer "copy to clipboard" features for the data inside
|
||||||
|
the QR as a URL (ie. same URL as shown) and as an image and of course,
|
||||||
|
the COLDCARD Q can scan from the web browser screen itself.
|
||||||
|
|
||||||
|
When the BBQr data is larger than comfortable for a single QR, the
|
||||||
|
website can split into a multi-frame BBQr. The website can
|
||||||
|
do this without understanding the contents of the BBQr data (all
|
||||||
|
of which is encrypted). Download options will be provided for
|
||||||
|
single-frame QR, animated PNG, and "stacked BBQr" (a single tall
|
||||||
|
PNG with each QR frame stacked).
|
||||||
|
|
||||||
|
On the COLDCARD side, when NFC is tapped, it will offer a long URL
|
||||||
|
to this site with the data to be transferred "after the hash". This
|
||||||
|
is optional since the QR can be shown on the Q itself, and would
|
||||||
|
pass the same data.
|
||||||
|
|
||||||
|
Since the website is running on Github, Coinkite does not have
|
||||||
|
access to IP addresses or other access log details. Because the data for
|
||||||
|
teleport is "after the hash" it is never sent to Github's servers
|
||||||
|
but remains in the browser only. All JS resources referenced by the
|
||||||
|
webpage will have content hashes applied to prevent interference,
|
||||||
|
and the site will be served over SSL.
|
||||||
|
|
||||||
|
Visit [keyteleport.com](https://keyteleport.com/), or an
|
||||||
|
[example small QR](https://keyteleport.com/#B$2R0100VHT2AGUUH7KUZUUSTOWOIWHJX3XM7GA2N4BHQOXDFHXLVHVA7K6ZO)
|
||||||
|
and [view source code](https://github.com/coinkite/keyteleport.com).
|
||||||
|
|
||||||
|
# UX Details
|
||||||
|
|
||||||
|
- When the receive process is started by the user, a pubkey is picked
|
||||||
|
and stored, so that they can come back later (after a power cycle)
|
||||||
|
and make use of the data encoded by the sender. However once a package
|
||||||
|
is decoded successfully, that key is deleted.
|
||||||
|
|
||||||
|
- Sender must start by scanning the QR from a receiver. Then can pick what
|
||||||
|
to send, from secure notes to seeds and so on.
|
||||||
|
|
||||||
|
- For PSBT multisig, user must pick a single co-signer (who hasn't already
|
||||||
|
signed) and the QR is prepared for that receiver. Because we
|
||||||
|
cannot do arbitary combining, it's best if the next signer continues
|
||||||
|
to teleport the updated PSBT to further signers. In other words,
|
||||||
|
a daisy-chain pattern is prefered to a star pattern. The signer
|
||||||
|
who completes the Mth (of N) signature will be able to finalize
|
||||||
|
the transaction, and ideally with PushTx feature, broadcast it.
|
||||||
|
|
||||||
|
# Security Comments
|
||||||
|
|
||||||
|
## Such short passwords?
|
||||||
|
|
||||||
|
We are using 8-character passwords because we want them to be
|
||||||
|
practical to share over non-digital channels such as a voice phone
|
||||||
|
call, or hand-written note.
|
||||||
|
|
||||||
|
It is very important to remind users that the passwords should be sent
|
||||||
|
by a different channel from the QR itself. Best is to call up your
|
||||||
|
other party and say the letters to them directly.
|
||||||
|
|
||||||
|
## Is it safe to save image of QR to cloud?
|
||||||
|
|
||||||
|
Yes, this seems safe. Of course, if you can control it, perhaps not
|
||||||
|
a risk to accept... but the QR is encrypted via ECDH using a key
|
||||||
|
that is forgotten after the transfer, so forward privacy is protected.
|
||||||
|
Also your cloud service (or photo roll, chat app log, etc) will not
|
||||||
|
have the 8-character password which is also required unpack the secrets.
|
||||||
|
|
||||||
|
The QR codes themselves are fully random and do not reveal the
|
||||||
|
identity of your COLDCARD, your on chain funds or anything linked
|
||||||
|
to you.
|
||||||
@ -1,12 +1,12 @@
|
|||||||
# BIP39 Import
|
# BIP-39 Import
|
||||||
|
|
||||||
- there must be 12, 18 or 24 words in your mnemonic
|
- there must be 12, 18 or 24 words in your mnemonic
|
||||||
- we have only the English word list
|
- we have only the English word list
|
||||||
- we support BIP39 passwords during import
|
- we support BIP-39 passwords during import
|
||||||
|
|
||||||
# XPRV Import
|
# XPRV Import
|
||||||
|
|
||||||
- we can import a BIP32 HD-wallet root private key in XPRV format
|
- we can import a BIP-32 HD-wallet root private key in XPRV format
|
||||||
- it's assumed to be top-level, and we don't store the parent fingerprint or depth value
|
- it's assumed to be top-level, and we don't store the parent fingerprint or depth value
|
||||||
- SLIP-132 format HD-wallet keys are also supported (xprv/yprv/zprv), but we strip
|
- SLIP-132 format HD-wallet keys are also supported (xprv/yprv/zprv), but we strip
|
||||||
the implied address format
|
the implied address format
|
||||||
@ -14,11 +14,12 @@
|
|||||||
# PIN Codes
|
# PIN Codes
|
||||||
|
|
||||||
- 2-2 through 6-6 in size, numeric digits only
|
- 2-2 through 6-6 in size, numeric digits only
|
||||||
- pin code 999999-999999 is reserved (means 'clear pin')
|
- pin code 999999-999999 was reserved (meaning 'clear pin'), but now available again
|
||||||
|
|
||||||
# Backup Files
|
# Backup Files
|
||||||
|
|
||||||
- we don't know what day it is, so meta data on files will not have correct date/time
|
- we don't know what day it is, so meta data on files will not have correct date/time
|
||||||
|
- release date of the firmware version that made the file is used instead of true date
|
||||||
- encrypted files produced cannot be changed, and we don't support other tools making them
|
- encrypted files produced cannot be changed, and we don't support other tools making them
|
||||||
|
|
||||||
# Micro SD
|
# Micro SD
|
||||||
@ -32,7 +33,7 @@
|
|||||||
- with Electrum, we support classic payment addresses (p2pkh), Bech32 Segwit and P2SH/Segwit
|
- with Electrum, we support classic payment addresses (p2pkh), Bech32 Segwit and P2SH/Segwit
|
||||||
- however, each wallet must be of a single address type; cannot be mixed (their limitation)
|
- however, each wallet must be of a single address type; cannot be mixed (their limitation)
|
||||||
- the same Coldcard could be used in each of the three modes (we don't care about address format)
|
- the same Coldcard could be used in each of the three modes (we don't care about address format)
|
||||||
- with Bitcoin Core (version 0.17?), we can do PSBT transactions, which support all address types
|
- with Bitcoin Core (version 0.17+), we can do PSBT transactions, which support all address types
|
||||||
- we don't support signing coinbase transactions, so don't mine directly into a Coldcard wallet
|
- we don't support signing coinbase transactions, so don't mine directly into a Coldcard wallet
|
||||||
|
|
||||||
# Max Transaction Size
|
# Max Transaction Size
|
||||||
@ -41,40 +42,62 @@
|
|||||||
- we support transactions up to 384k-bytes in size when serialized into PSBT format
|
- we support transactions up to 384k-bytes in size when serialized into PSBT format
|
||||||
- we can handle transactions with up to 20 inputs to be signed at one time.
|
- we can handle transactions with up to 20 inputs to be signed at one time.
|
||||||
- a maximum of 250 outputs per transaction is supported (will attempt more if memory allows)
|
- a maximum of 250 outputs per transaction is supported (will attempt more if memory allows)
|
||||||
- mk4:
|
- mk4/Q:
|
||||||
- we support PSBT files up to 2M bytes in size.
|
- we support PSBT files up to 2M bytes in size.
|
||||||
- any number of inputs and outputs are supported, limited only by final transaction size (100k)
|
- any number of inputs and outputs are supported, limited only by final transaction size (100k)
|
||||||
- tested with: 250 inputs, 2000 outputs
|
- tested with: 250 inputs, 2000 outputs
|
||||||
- bitcoin limits transactions to 100k, but there could be large input transactions
|
- bitcoin limits transactions to 100k, but there could be large input transactions
|
||||||
inside the PSBT. Reduce this by using segwit signatures and provide only the
|
inside the PSBT. Reduce this by using segwit signatures and provide only the
|
||||||
individual UTXO ("out points").
|
individual UTXO ("out points").
|
||||||
|
- every transaction needs to have at least one output, or we reject it
|
||||||
|
|
||||||
|
|
||||||
# P2SH / Multisig
|
# P2SH / Multisig
|
||||||
|
|
||||||
- only one signature will be added per input. However, if needed the partly-signed
|
- only one signature will be added per input. However, if needed the partly-signed
|
||||||
PSBT can be given again, and the "next" leg will be signed.
|
PSBT can be given again, and the "next" leg will be signed.
|
||||||
- we do not support PSBT combining or finalizing of transactions involving
|
- finalizing of multisig transactions involving P2SH signatures:
|
||||||
P2SH signatures (so the combine step must be off-device)
|
* SD/Vdisk signing exports both signed PSBT and finalized txn ready for broadcast (if txn is complete)
|
||||||
|
* QR/NFC outputs finalized txn ready for broadcast if txn is complete otherwise signed PSBT only
|
||||||
|
* USB signing requires `--finalize` parameter (as for standard single signature wallets)
|
||||||
|
|
||||||
- we can sign for P2SH and P2WSH addresses that represent multisig (M of N) but
|
- we can sign for P2SH and P2WSH addresses that represent multisig (M of N) but
|
||||||
we cannot sign for non-standard scripts because we don't know how to present
|
we cannot sign for non-standard scripts because we don't know how to present
|
||||||
that to the user for approval.
|
that to the user for approval.
|
||||||
- during USB "show address" for multisig, we limit subkey paths to
|
- during USB "show address" for multisig, we limit subkey paths to
|
||||||
16 levels deep (including master fingerprint)
|
16 levels deep (including master fingerprint)
|
||||||
- max of 15 co-signers due to 520 byte script limitation in consensus layer with classic P2SH
|
- max of 15 co-signers due to 1650 byte `scriptSig` limitation in policy with classic P2SH (same limit applies to segwit even though consensus allows up to 20 co-signers).
|
||||||
|
note: the consensus layer sets an upper bound of 520 bytes for the length of each stack element
|
||||||
- (mk3) we have space for up to 8 M-of-3 wallets, or a single M-of-15 wallet. YMMV
|
- (mk3) we have space for up to 8 M-of-3 wallets, or a single M-of-15 wallet. YMMV
|
||||||
- only a single multisig wallet can be involved in a PSBT; can't sign inputs from two different
|
- only a single multisig wallet can be involved in a PSBT; can't sign inputs from two different
|
||||||
multisig wallets at the same time.
|
multisig wallets at the same time.
|
||||||
- we always store xpubs in BIP32 format, although we can read SLIP132 format (Ypub/Zpub/etc)
|
- we always store xpubs in BIP-32 format, although we can read SLIP132 format (Ypub/Zpub/etc)
|
||||||
- change outputs (indicated with paths, scripts in output section) must correspond to
|
- change outputs (indicated with paths, scripts in output section) must correspond to
|
||||||
the active multisig wallet, and cannot be used to describe an unrelated (multisig) wallet.
|
the active multisig wallet, and cannot be used to describe an unrelated (multisig) wallet.
|
||||||
- derivation path for each cosigner must be known and consistent with PSBT
|
- derivation path for each cosigner must be known and consistent with PSBT
|
||||||
- fixed: XFP values (fingerprints) for each of the co-signers must be unique (limitation removed)
|
- XFP values (fingerprints) MUST be unique for each of the co-signers
|
||||||
|
- multisig wallet `name` can only contain printable ASCII characters `range(32, 127)`
|
||||||
|
|
||||||
|
### BIP-67
|
||||||
|
|
||||||
|
- importing multisig from PSBT can ONLY create `sortedmulti(...)` multisig according to BIP-67, DO NOT use with `multi(...)`
|
||||||
|
- creating airgapped multisig using COLDCARD as coordinator always produces `sortedmulti(...)` multisig according to BIP-67
|
||||||
|
- COLDCARD import/export [format](https://coldcard.com/docs/multisig/#configuration-text-file-for-multisig) only supports `sortedmulti(...)` multisig according to BIP-67. To import multisig wallet with `multi(...)` use descriptor import [format](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki)
|
||||||
|
- encrypted COLDCARD backups that contains multisig wallets with `multi(...)` MUST only be restored on firmware versions with `multi(...)` support
|
||||||
|
- all imported `multi(...)` must differ in keys (same as `sortedmulti(...)`). If `wsh(multi(2,A,B))` is already registered, `wsh(multi(2,B,A))` will be rejected upon import as duplicate, even thought they are actually different script/wallet.
|
||||||
|
- just BIP67 difference is also treated as duplicate. If `wsh(multi(2,A,B)` is registered, `wsh(sortedmulti(2,A,B))` will be rejected as duplicate and vice-versa.
|
||||||
|
|
||||||
# SIGHASH types
|
# SIGHASH types
|
||||||
|
|
||||||
- only `SIGHASH_ALL` is supported at this time
|
- all sighash flags are supported:
|
||||||
- in time, we will add support for others, especially to support Coinjoin usage
|
- `ALL`
|
||||||
|
- `NONE`
|
||||||
|
- `SINGLE`
|
||||||
|
- `ALL|ANYONECANPAY`
|
||||||
|
- `NONE|ANYONECANPAY`
|
||||||
|
- `SINGLE|ANYONECANPAY`
|
||||||
|
- any value other than ALL will cause a warning to be shown to user
|
||||||
|
- by default, we reject `NONE` and `NONE|ANYONECANPAY` but there is a setting to allow
|
||||||
|
|
||||||
# U2F Protocol / Web Access to USB / WebUSB
|
# U2F Protocol / Web Access to USB / WebUSB
|
||||||
|
|
||||||
@ -96,7 +119,7 @@
|
|||||||
|
|
||||||
We will summarize transaction outputs as "change" back into same wallet, however:
|
We will summarize transaction outputs as "change" back into same wallet, however:
|
||||||
|
|
||||||
- PSBT must specify BIP32 path in corresponding output section for us to treat as change
|
- PSBT must specify BIP-32 path in corresponding output section for us to treat as change
|
||||||
- for p2sh-wrapped segwit outputs, redeem script must be provided when needed
|
- for p2sh-wrapped segwit outputs, redeem script must be provided when needed
|
||||||
- any incorrect values here are assumed to be fraud attempts, and are highlighted to user
|
- any incorrect values here are assumed to be fraud attempts, and are highlighted to user
|
||||||
- the _redeemScript_ for `p2wsh-p2sh` is optional, but if provided must be
|
- the _redeemScript_ for `p2wsh-p2sh` is optional, but if provided must be
|
||||||
@ -117,21 +140,25 @@ We will summarize transaction outputs as "change" back into same wallet, however
|
|||||||
|
|
||||||
- key derivatation paths must be 12 or less in depth (`MAX_PATH_DEPTH`)
|
- key derivatation paths must be 12 or less in depth (`MAX_PATH_DEPTH`)
|
||||||
|
|
||||||
|
# Pay-to-Pubkey
|
||||||
|
|
||||||
# NFC Feature (Mk4)
|
- although we have some code for "pay to pubkey" (P2PK not P2PKH), it is untested
|
||||||
|
and unused since this style of payment address is obsolete and largely unused today
|
||||||
|
|
||||||
|
# NFC Feature
|
||||||
|
|
||||||
- can share up to 8000 bytes of PSBT or signed transaction data.
|
- can share up to 8000 bytes of PSBT or signed transaction data.
|
||||||
- NFC-V (ISO-15693) radio/modulation is common on mobile phones but very rare on desktops
|
- NFC-V (ISO-15693) radio/modulation is common on mobile phones but very rare on desktops
|
||||||
|
|
||||||
# Fast Wipe (Mk4)
|
# Fast Wipe
|
||||||
|
|
||||||
- each use of "fast wipe" feature consumes a MCU key slot, of which there are 256.
|
- each use of "fast wipe" feature consumes a MCU key slot, of which there are 256.
|
||||||
- use _Advanced > Danger Zone > MCU Key Slots_ to view usage
|
- use _Advanced > Danger Zone > MCU Key Slots_ to view usage
|
||||||
|
|
||||||
# Trick Pins (Mk4)
|
# Trick Pins
|
||||||
|
|
||||||
- "deltamode" PIN must be same length as true pin, and differ only in final 4 positions.
|
- "deltamode" PIN must be same length as true pin, and differ only in final 4 positions.
|
||||||
- there are 14 trick "slots", but we avoid slot 10, so 13 available.
|
- there are 14 trick "slots", but on mk4, we avoid slot 10, so 13 available. (Q: 14)
|
||||||
- duress wallets consume 2 slots (or 3 slots for legacy duress wallet) which must be contiguous
|
- duress wallets consume 2 slots (or 3 slots for legacy duress wallet) which must be contiguous
|
||||||
- when restoring trick pins from backup files, "forgotten" pins are not restored,
|
- when restoring trick pins from backup files, "forgotten" pins are not restored,
|
||||||
and any trick pin which matches the true PIN of the restored system will be dropped
|
and any trick pin which matches the true PIN of the restored system will be dropped
|
||||||
@ -139,9 +166,58 @@ We will summarize transaction outputs as "change" back into same wallet, however
|
|||||||
is not compatible, the deltamode trick PIN is dropped and not restored
|
is not compatible, the deltamode trick PIN is dropped and not restored
|
||||||
- duress wallets are supported when derived from 24- or 12-word seed phrases
|
- duress wallets are supported when derived from 24- or 12-word seed phrases
|
||||||
|
|
||||||
# Debug Serial Port (Mk4)
|
# Debug Serial Port
|
||||||
|
|
||||||
- virtual USB serial port disabled completely by default, and even if enabled
|
- virtual USB serial port disabled completely by default, and even if enabled
|
||||||
in Danger Zone, only echos output, and does not accept any input
|
in Danger Zone, only echos output, and does not accept any input
|
||||||
- use hardware serial port for interactive REPL access (3.3v TTL levels)
|
- use hardware serial port for interactive REPL access (3.3v TTL levels)
|
||||||
|
|
||||||
|
# BBQr Scanning (Q)
|
||||||
|
|
||||||
|
- files up to 2MiB in size can be accepted
|
||||||
|
- when 14 or less parts, we display status of each part, if more, just percent complete
|
||||||
|
|
||||||
|
# QR Scanning (Q)
|
||||||
|
|
||||||
|
- if not BBQr (or sent as unicode inside BBQr) we auto detect these data types:
|
||||||
|
- PSBT in Base64 or hex
|
||||||
|
- Wire Transaction in Base64 or hex
|
||||||
|
- XPRV, XPUB, bare payment addresses, BIP-21 invoices
|
||||||
|
- seed words (truncated, or full)
|
||||||
|
- SeedQR (but not Compact SeedQR)
|
||||||
|
- for Base58, Bech32 encoded values, if checksum is wrong then it is shown as text
|
||||||
|
- binary QR codes are not supported
|
||||||
|
- when pasting into a secure note, if the QR's data is > 60 chars long, we assume done
|
||||||
|
|
||||||
|
# Secure Notes & Passwords (Q)
|
||||||
|
|
||||||
|
- when Q picks a password for you (using F1 thru F5), the entropy is 126 bits or more,
|
||||||
|
except F3 which makes an easier to type password of around 48 bits entropy.
|
||||||
|
- Title, Sitename and Username fields are limited to 32 characters in length.
|
||||||
|
- Passwords are limited to 128 characters.
|
||||||
|
- Note text is unlimited, but storing very large notes may affect performance system-wide.
|
||||||
|
- Q Backup files restored onto Mk4 will lose their notes, since notes feature is not supported.
|
||||||
|
|
||||||
|
# Address Ownership
|
||||||
|
|
||||||
|
- only the first 1528 addresses (764 each from internal and external (change/not) paths)
|
||||||
|
are considered
|
||||||
|
- if you have used an sub-account, without ever exploring it in the Address Explorer, nor
|
||||||
|
signing a PSBT with those account numbers, we do not search it.
|
||||||
|
- does not search Seed Vault, you'll need to load each of those and re-search
|
||||||
|
- if you have an XFP collision between multiple wallets in SeedVault (ie. two wallets
|
||||||
|
with same descriptors, but different seeds) you will get false negatives
|
||||||
|
|
||||||
|
# Spending Policy
|
||||||
|
|
||||||
|
- (Cosign mode) only 12 or 24 word seeds (not XPRV) are accepted for "key C"
|
||||||
|
- velocity limit:
|
||||||
|
- based on a max magnitude per txn, and a required minimum block height
|
||||||
|
gap, based on previous `nLockTime` value in last-signed PSBT.
|
||||||
|
- if you sign a transaction, but never broadcast it, you will still have to wait out
|
||||||
|
the velocity policy.
|
||||||
|
- PSBT creator must put in `nLockTime` block heights (most already do to avoid fee sniping)
|
||||||
|
- maximum of 25 whitelisted addresses can be stored
|
||||||
|
- Web2FA: any number of mobile devices can be enrolled, but all will have the same shared secret
|
||||||
|
- any warning from the PSBT, such as huge fees, will cause the transaction to be rejected
|
||||||
|
|
||||||
|
|||||||
@ -38,7 +38,7 @@ directly from python programs.
|
|||||||
|
|
||||||
| Start | Size | Notes
|
| Start | Size | Notes
|
||||||
|---------------|-----------|--------------------------
|
|---------------|-----------|--------------------------
|
||||||
| 0x0800 0000 | 128k | Bootloader code, including reset vector. See `stm32/mk4-bootloader`
|
| 0x0800 0000 | 112k | Bootloader code, including reset vector. See `stm32/mk4-bootloader`
|
||||||
| 0x0801 c000 | 8k | Sensitive "pairing secrets" for SE1 and SE2
|
| 0x0801 c000 | 8k | Sensitive "pairing secrets" for SE1 and SE2
|
||||||
| 0x0801 e000 | 8k | MCU keys, consumable; 256 32-bit write-once slots.
|
| 0x0801 e000 | 8k | MCU keys, consumable; 256 32-bit write-once slots.
|
||||||
| 0x0802 0000 | 16k | Interrupt handlers, file header (Micropython and Coldcard code)
|
| 0x0802 0000 | 16k | Interrupt handlers, file header (Micropython and Coldcard code)
|
||||||
|
|||||||
@ -2,11 +2,6 @@
|
|||||||
Choose PIN Code
|
Choose PIN Code
|
||||||
Advanced/Tools
|
Advanced/Tools
|
||||||
View Identity
|
View Identity
|
||||||
Upgrade Firmware
|
|
||||||
Show Version
|
|
||||||
From MicroSD
|
|
||||||
From VirtDisk [IF VIRTDISK ENABLED]
|
|
||||||
Bless Firmware
|
|
||||||
Paper Wallets
|
Paper Wallets
|
||||||
Perform Selftest
|
Perform Selftest
|
||||||
Secure Logout
|
Secure Logout
|
||||||
@ -16,71 +11,95 @@
|
|||||||
|
|
||||||
[IF BLANK WALLET]
|
[IF BLANK WALLET]
|
||||||
New Seed Words
|
New Seed Words
|
||||||
24 Word (default)
|
|
||||||
12 Word
|
|
||||||
24 Word Dice Roll
|
|
||||||
12 Word Dice Roll
|
|
||||||
Import Existing
|
|
||||||
24 Words
|
|
||||||
[SEED WORD MENUS]
|
|
||||||
18 Words
|
|
||||||
[SEED WORD MENUS]
|
|
||||||
12 Words
|
12 Words
|
||||||
[SEED WORD MENUS]
|
24 Words
|
||||||
|
Advanced
|
||||||
|
12 Word Dice Roll
|
||||||
|
24 Word Dice Roll
|
||||||
|
Import Existing
|
||||||
|
12 Words
|
||||||
|
[SEED WORD ENTRY]
|
||||||
|
18 Words
|
||||||
|
[SEED WORD ENTRY]
|
||||||
|
24 Words
|
||||||
|
[SEED WORD ENTRY]
|
||||||
|
Scan QR Code [IF QR SCANNER]
|
||||||
Restore Backup
|
Restore Backup
|
||||||
Clone Coldcard
|
Clone Coldcard
|
||||||
Import XPRV
|
Import XPRV
|
||||||
|
Tapsigner Backup
|
||||||
Seed XOR
|
Seed XOR
|
||||||
|
Migrate Coldcard
|
||||||
|
Key Teleport (start)
|
||||||
Help
|
Help
|
||||||
Advanced/Tools
|
Advanced/Tools
|
||||||
View Identity
|
View Identity
|
||||||
Upgrade Firmware
|
Temporary Seed
|
||||||
|
Generate Words
|
||||||
|
12 Words
|
||||||
|
24 Words
|
||||||
|
12 Word Dice Roll
|
||||||
|
24 Word Dice Roll
|
||||||
|
Import from QR Scan [IF QR SCANNER]
|
||||||
|
Import Words
|
||||||
|
12 Words
|
||||||
|
18 Words
|
||||||
|
24 Words
|
||||||
|
Import via NFC [IF NFC ENABLED]
|
||||||
|
Import XPRV
|
||||||
|
Tapsigner Backup
|
||||||
|
Coldcard Backup
|
||||||
|
Restore Seed XOR
|
||||||
|
Upgrade Firmware [IF NOT TMP SEED]
|
||||||
Show Version
|
Show Version
|
||||||
From MicroSD
|
From MicroSD
|
||||||
From VirtDisk [IF VIRTDISK ENABLED]
|
From VirtDisk [IF VIRTDISK ENABLED]
|
||||||
Bless Firmware
|
|
||||||
File Management
|
File Management
|
||||||
Verify Backup
|
Verify Backup
|
||||||
List Files
|
List Files
|
||||||
|
Verify Sig File
|
||||||
NFC File Share [IF NFC ENABLED]
|
NFC File Share [IF NFC ENABLED]
|
||||||
|
BBQr File Share [IF QR SCANNER]
|
||||||
|
QR File Share [IF QR SCANNER]
|
||||||
Format SD Card
|
Format SD Card
|
||||||
Format RAM Disk [IF VIRTDISK ENABLED]
|
Format RAM Disk [IF VIRTDISK ENABLED]
|
||||||
|
Key Teleport (start)
|
||||||
Paper Wallets
|
Paper Wallets
|
||||||
Perform Selftest
|
Perform Selftest
|
||||||
I Am Developer.
|
I Am Developer.
|
||||||
Serial REPL
|
Serial REPL
|
||||||
Wipe LFS
|
|
||||||
Warm Reset
|
Warm Reset
|
||||||
Restore Txt Bkup
|
Restore Bkup
|
||||||
|
Reflash GPU [IF QWERTY KEYBOARD]
|
||||||
Secure Logout
|
Secure Logout
|
||||||
Settings
|
Settings
|
||||||
Login Settings
|
Login Settings
|
||||||
Change Main PIN
|
Change Main PIN
|
||||||
PIN Options
|
|
||||||
Trick PINs
|
|
||||||
Trick PINs:
|
|
||||||
↳22-22
|
|
||||||
Add New Trick
|
|
||||||
Add If Wrong
|
|
||||||
Delete All
|
|
||||||
Set Nickname
|
Set Nickname
|
||||||
Scramble Keypad
|
Scramble Keys
|
||||||
Kill Key
|
Kill Key
|
||||||
Login Countdown
|
Login Countdown
|
||||||
Disabled
|
Disabled
|
||||||
|
5 minutes
|
||||||
15 minutes
|
15 minutes
|
||||||
30 minutes
|
30 minutes
|
||||||
4 hours
|
|
||||||
1 hour
|
1 hour
|
||||||
5 minutes
|
2 hours
|
||||||
|
4 hours
|
||||||
8 hours
|
8 hours
|
||||||
12 hours
|
12 hours
|
||||||
2 hours
|
|
||||||
3 days
|
|
||||||
48 hours
|
|
||||||
1 week
|
|
||||||
24 hours
|
24 hours
|
||||||
|
48 hours
|
||||||
|
3 days
|
||||||
|
1 week
|
||||||
28 days later
|
28 days later
|
||||||
|
MicroSD 2FA [IF SECRET AND NOT TMP SEED]
|
||||||
|
Add Card
|
||||||
|
Check Card
|
||||||
|
Remove Card #1
|
||||||
|
Calculator Login [IF QWERTY KEYBOARD]
|
||||||
|
Default Off
|
||||||
|
Calculator Login
|
||||||
Test Login Now
|
Test Login Now
|
||||||
Hardware On/Off
|
Hardware On/Off
|
||||||
USB Port
|
USB Port
|
||||||
@ -93,13 +112,11 @@
|
|||||||
NFC Sharing
|
NFC Sharing
|
||||||
Default Off
|
Default Off
|
||||||
Enable NFC
|
Enable NFC
|
||||||
Multisig Wallets
|
NFC Push Tx
|
||||||
(none setup yet)
|
coldcard.com
|
||||||
Import from SD
|
mempool.space
|
||||||
Export XPUB
|
Custom URL...
|
||||||
Create Airgapped
|
Disable
|
||||||
Trust PSBT?
|
|
||||||
Skip Checks?
|
|
||||||
Display Units
|
Display Units
|
||||||
BTC
|
BTC
|
||||||
mBTC
|
mBTC
|
||||||
@ -118,17 +135,106 @@
|
|||||||
4 hours
|
4 hours
|
||||||
8 hours
|
8 hours
|
||||||
Never
|
Never
|
||||||
|
Idle Timeout (on battery) [IF BATTERIES]
|
||||||
|
30 seconds
|
||||||
|
60 seconds
|
||||||
|
2 minutes
|
||||||
|
5 minutes
|
||||||
|
10 minutes
|
||||||
|
15 minutes
|
||||||
|
30 minutes
|
||||||
|
1 hour
|
||||||
|
4 hours
|
||||||
|
Never
|
||||||
|
LCD Brightness (on battery) [IF BATTERIES]
|
||||||
|
25%
|
||||||
|
50%
|
||||||
|
60%
|
||||||
|
70%
|
||||||
|
80%
|
||||||
|
90%
|
||||||
|
95% (default)
|
||||||
|
100%
|
||||||
Delete PSBTs
|
Delete PSBTs
|
||||||
Default Keep
|
Default Keep
|
||||||
Delete PSBTs
|
Delete PSBTs
|
||||||
|
Buried Settings
|
||||||
|
Home Menu XFP [IF SECRET AND NOT TMP SEED]
|
||||||
|
Only Tmp
|
||||||
|
Always Show
|
||||||
|
Menu Wrapping
|
||||||
|
Default
|
||||||
|
Always Wrap
|
||||||
|
[QR key shortcut] [IF QR SCANNER]
|
||||||
---
|
---
|
||||||
|
|
||||||
[NORMAL OPERATION]
|
[NORMAL OPERATION]
|
||||||
Ready To Sign
|
Ready To Sign
|
||||||
Passphrase
|
Passphrase [IF WORD BASED SEED]
|
||||||
|
Restore Saved
|
||||||
|
c*******
|
||||||
|
[3A14F788]
|
||||||
|
Restore
|
||||||
|
Delete
|
||||||
|
Edit Phrase
|
||||||
|
Scan Any QR Code [IF QR SCANNER]
|
||||||
Start HSM Mode [IF HSM POLICY]
|
Start HSM Mode [IF HSM POLICY]
|
||||||
Address Explorer
|
Address Explorer
|
||||||
Secure Logout
|
Classic P2PKH
|
||||||
|
↳ mtHSVByP9EYZ⋯Vm19gvpecb5R
|
||||||
|
P2SH-Segwit
|
||||||
|
↳ 2NCAJ5wD4Gvm⋯NphNU8UYoEJv
|
||||||
|
Segwit P2WPKH
|
||||||
|
↳ tb1qupyd58nd⋯vu9jtdyws9n9
|
||||||
|
Applications
|
||||||
|
Samourai
|
||||||
|
Post-mix
|
||||||
|
Pre-mix
|
||||||
|
Wasabi
|
||||||
|
Account Number
|
||||||
|
Custom Path
|
||||||
|
CC-2-of-4
|
||||||
|
Secure Notes & Passwords [IF ENBALED] [MAYBE]
|
||||||
|
1: note0
|
||||||
|
"note0"
|
||||||
|
View Note
|
||||||
|
Edit
|
||||||
|
Delete
|
||||||
|
Export
|
||||||
|
Sign Note Text
|
||||||
|
2: secret-PWD
|
||||||
|
"secret-PWD"
|
||||||
|
↳ satoshi
|
||||||
|
↳ abc.org
|
||||||
|
View Password
|
||||||
|
Send Password [MAYBE]
|
||||||
|
Export
|
||||||
|
Edit Metadata
|
||||||
|
Delete
|
||||||
|
Change Password
|
||||||
|
Sign Note Text
|
||||||
|
New Note
|
||||||
|
New Password
|
||||||
|
Export All
|
||||||
|
Sort By Title
|
||||||
|
Import
|
||||||
|
Type Passwords [MAYBE]
|
||||||
|
Seed Vault [MAYBE]
|
||||||
|
1: [7126EB3C]
|
||||||
|
[7126EB3C]
|
||||||
|
Use This Seed
|
||||||
|
Rename
|
||||||
|
Delete
|
||||||
|
2: [CCEE13B9]
|
||||||
|
[CCEE13B9]
|
||||||
|
Use This Seed
|
||||||
|
Rename
|
||||||
|
Delete
|
||||||
|
3: [03EE9989]
|
||||||
|
[03EE9989]
|
||||||
|
Use This Seed
|
||||||
|
Rename
|
||||||
|
Delete
|
||||||
Advanced/Tools
|
Advanced/Tools
|
||||||
Backup
|
Backup
|
||||||
Backup System
|
Backup System
|
||||||
@ -136,101 +242,229 @@
|
|||||||
Restore Backup
|
Restore Backup
|
||||||
Clone Coldcard
|
Clone Coldcard
|
||||||
Export Wallet
|
Export Wallet
|
||||||
|
Sparrow
|
||||||
|
Cove
|
||||||
Bitcoin Core
|
Bitcoin Core
|
||||||
|
Nunchuk
|
||||||
|
Bull Bitcoin
|
||||||
|
Blue Wallet
|
||||||
Electrum Wallet
|
Electrum Wallet
|
||||||
Wasabi Wallet
|
Wasabi Wallet
|
||||||
Unchained Capital
|
Fully Noded
|
||||||
|
Unchained
|
||||||
|
Theya
|
||||||
|
Bitcoin Safe
|
||||||
|
Zeus
|
||||||
|
Samourai Postmix
|
||||||
|
Samourai Premix
|
||||||
|
Descriptor
|
||||||
Generic JSON
|
Generic JSON
|
||||||
Export XPUB
|
Export XPUB
|
||||||
Segwit (BIP-84)
|
Segwit (BIP-84)
|
||||||
Classic (BIP-44)
|
Classic (BIP-44)
|
||||||
P2WPKH/P2SH (49)
|
P2WPKH/P2SH (BIP-49)
|
||||||
Master XPUB
|
Master XPUB
|
||||||
Current XFP
|
Current XFP
|
||||||
|
Key Expression
|
||||||
Dump Summary
|
Dump Summary
|
||||||
Upgrade Firmware
|
Upgrade Firmware [IF NOT TMP SEED]
|
||||||
Show Version
|
Show Version
|
||||||
From MicroSD
|
From MicroSD
|
||||||
From VirtDisk [IF VIRTDISK ENABLED]
|
From VirtDisk [IF VIRTDISK ENABLED]
|
||||||
Bless Firmware
|
|
||||||
File Management
|
File Management
|
||||||
Verify Backup
|
Verify Backup
|
||||||
Backup System
|
Backup System
|
||||||
Export Wallet
|
Export Wallet
|
||||||
|
Sparrow
|
||||||
|
Cove
|
||||||
Bitcoin Core
|
Bitcoin Core
|
||||||
|
Nunchuk
|
||||||
|
Bull Bitcoin
|
||||||
|
Blue Wallet
|
||||||
Electrum Wallet
|
Electrum Wallet
|
||||||
Wasabi Wallet
|
Wasabi Wallet
|
||||||
Unchained Capital
|
Fully Noded
|
||||||
|
Unchained
|
||||||
|
Theya
|
||||||
|
Bitcoin Safe
|
||||||
|
Zeus
|
||||||
|
Samourai Postmix
|
||||||
|
Samourai Premix
|
||||||
|
Descriptor
|
||||||
Generic JSON
|
Generic JSON
|
||||||
Export XPUB
|
Export XPUB
|
||||||
Segwit (BIP-84)
|
Segwit (BIP-84)
|
||||||
Classic (BIP-44)
|
Classic (BIP-44)
|
||||||
P2WPKH/P2SH (49)
|
P2WPKH/P2SH (BIP-49)
|
||||||
Master XPUB
|
Master XPUB
|
||||||
Current XFP
|
Current XFP
|
||||||
|
Key Expression
|
||||||
Dump Summary
|
Dump Summary
|
||||||
Sign Text File
|
Sign Text File
|
||||||
Clone Coldcard
|
Batch Sign PSBT
|
||||||
|
Teleport Multisig PSBT
|
||||||
List Files
|
List Files
|
||||||
|
Verify Sig File
|
||||||
NFC File Share [IF NFC ENABLED]
|
NFC File Share [IF NFC ENABLED]
|
||||||
|
BBQr File Share [IF QR SCANNER]
|
||||||
|
QR File Share [IF QR SCANNER]
|
||||||
|
Clone Coldcard
|
||||||
Format SD Card
|
Format SD Card
|
||||||
Format RAM Disk [IF VIRTDISK ENABLED]
|
Format RAM Disk [IF VIRTDISK ENABLED]
|
||||||
Derive Seed B85
|
Secure Notes & Passwords [IF QWERTY KEYBOARD]
|
||||||
|
1: note0
|
||||||
|
"note0"
|
||||||
|
View Note
|
||||||
|
Edit
|
||||||
|
Delete
|
||||||
|
Export
|
||||||
|
Sign Note Text
|
||||||
|
2: secret-PWD
|
||||||
|
"secret-PWD"
|
||||||
|
↳ satoshi
|
||||||
|
↳ abc.org
|
||||||
|
View Password
|
||||||
|
Send Password [MAYBE]
|
||||||
|
Export
|
||||||
|
Edit Metadata
|
||||||
|
Delete
|
||||||
|
Change Password
|
||||||
|
Sign Note Text
|
||||||
|
New Note
|
||||||
|
New Password
|
||||||
|
Export All
|
||||||
|
Sort By Title
|
||||||
|
Import
|
||||||
|
Derive Seeds (BIP-85)
|
||||||
View Identity
|
View Identity
|
||||||
|
Temporary Seed
|
||||||
|
Generate Words
|
||||||
|
12 Words
|
||||||
|
24 Words
|
||||||
|
12 Word Dice Roll
|
||||||
|
24 Word Dice Roll
|
||||||
|
Import from QR Scan [IF QR SCANNER]
|
||||||
|
Import Words
|
||||||
|
12 Words
|
||||||
|
18 Words
|
||||||
|
24 Words
|
||||||
|
Import via NFC [IF NFC ENABLED]
|
||||||
|
Import XPRV
|
||||||
|
Tapsigner Backup
|
||||||
|
Coldcard Backup
|
||||||
|
Restore Seed XOR
|
||||||
|
Key Teleport (start)
|
||||||
|
Spending Policy [IF SECRET AND NOT TMP SEED]
|
||||||
|
Single-Signer [IF SECRET AND NOT TMP SEED]
|
||||||
|
Co-Sign Multisig (CCC) [IF NOT TMP SEED]
|
||||||
|
HSM Mode [IF HSM AND SECRET]
|
||||||
|
Default Off
|
||||||
|
Enable
|
||||||
|
User Management [MAYBE]
|
||||||
Paper Wallets
|
Paper Wallets
|
||||||
User Management
|
WIF Store
|
||||||
(no users yet)
|
NFC Tools [IF NFC ENABLED]
|
||||||
|
Sign PSBT
|
||||||
|
Show Address
|
||||||
|
Sign Message
|
||||||
|
Verify Sig File
|
||||||
|
Verify Address
|
||||||
|
File Share
|
||||||
|
Import Multisig
|
||||||
|
Push Transaction [IF PUSHTX ENABLED]
|
||||||
Danger Zone
|
Danger Zone
|
||||||
Debug Functions
|
Debug Functions
|
||||||
Seed Functions
|
Seed Functions
|
||||||
View Seed Words
|
View Seed Words
|
||||||
Seed XOR
|
Seed XOR
|
||||||
Split Existing
|
Split Existing [IF WORD BASED SEED]
|
||||||
Restore Seed XOR
|
Restore Seed XOR
|
||||||
Destroy Seed
|
Destroy Seed [IF SECRET AND NOT TMP SEED]
|
||||||
Lock Down Seed
|
Lock Down Seed [MAYBE]
|
||||||
|
Export SeedQR [IF WORD BASED SEED]
|
||||||
I Am Developer.
|
I Am Developer.
|
||||||
Serial REPL
|
Serial REPL
|
||||||
Wipe LFS
|
|
||||||
Warm Reset
|
Warm Reset
|
||||||
Restore Txt Bkup
|
Restore Bkup
|
||||||
|
BKPW Override
|
||||||
|
Reflash GPU [IF QWERTY KEYBOARD]
|
||||||
|
Seed Vault [IF SECRET AND NOT TMP SEED]
|
||||||
|
Default Off
|
||||||
|
Enable
|
||||||
Perform Selftest
|
Perform Selftest
|
||||||
Set High-Water
|
Set High-Water
|
||||||
Wipe HSM Policy [IF HSM POLICY]
|
Wipe HSM Policy [IF HSM POLICY]
|
||||||
Clear OV cache
|
Clear OV cache
|
||||||
|
Clear Address cache
|
||||||
|
Sighash Checks
|
||||||
|
Default: Block
|
||||||
|
Warn
|
||||||
Testnet Mode
|
Testnet Mode
|
||||||
Bitcoin
|
Bitcoin
|
||||||
Testnet3
|
Testnet4
|
||||||
|
Regtest
|
||||||
|
AE Start Index
|
||||||
|
Default Off
|
||||||
|
Enable
|
||||||
|
B85 Idx Values
|
||||||
|
Default Off
|
||||||
|
Unlimited
|
||||||
Settings Space
|
Settings Space
|
||||||
MCU Key Slots
|
MCU Key Slots
|
||||||
|
Bless Firmware
|
||||||
|
Wipe LFS
|
||||||
|
Nuke Device
|
||||||
Settings
|
Settings
|
||||||
Login Settings
|
Login Settings
|
||||||
Change Main PIN
|
Change Main PIN
|
||||||
PIN Options
|
Trick PINs [IF SECRET AND NOT TMP SEED]
|
||||||
Trick PINs
|
|
||||||
Trick PINs:
|
Trick PINs:
|
||||||
↳22-22
|
↳11-11
|
||||||
|
PIN 11-11
|
||||||
|
↳Bricks CC
|
||||||
|
Hide Trick
|
||||||
|
Delete Trick
|
||||||
|
Change PIN
|
||||||
|
↳333-3334
|
||||||
|
PIN 333-3334
|
||||||
|
↳Duress Wallet
|
||||||
|
Activate Wallet
|
||||||
|
Hide Trick
|
||||||
|
Delete Trick
|
||||||
|
Change PIN
|
||||||
|
↳WRONG PIN
|
||||||
|
After 3 wrong:
|
||||||
|
↳Wipes seed
|
||||||
|
↳Reboots
|
||||||
|
Hide Trick
|
||||||
|
Delete Trick
|
||||||
Add New Trick
|
Add New Trick
|
||||||
Add If Wrong
|
|
||||||
Delete All
|
Delete All
|
||||||
Set Nickname
|
Set Nickname
|
||||||
Scramble Keypad
|
Scramble Keys
|
||||||
Kill Key
|
Kill Key
|
||||||
Login Countdown
|
Login Countdown
|
||||||
Disabled
|
Disabled
|
||||||
|
5 minutes
|
||||||
15 minutes
|
15 minutes
|
||||||
30 minutes
|
30 minutes
|
||||||
4 hours
|
|
||||||
1 hour
|
1 hour
|
||||||
5 minutes
|
2 hours
|
||||||
|
4 hours
|
||||||
8 hours
|
8 hours
|
||||||
12 hours
|
12 hours
|
||||||
2 hours
|
|
||||||
3 days
|
|
||||||
48 hours
|
|
||||||
1 week
|
|
||||||
24 hours
|
24 hours
|
||||||
|
48 hours
|
||||||
|
3 days
|
||||||
|
1 week
|
||||||
28 days later
|
28 days later
|
||||||
|
MicroSD 2FA [IF SECRET AND NOT TMP SEED]
|
||||||
|
Add Card
|
||||||
|
Check Card
|
||||||
|
Remove Card #1
|
||||||
|
Calculator Login [IF QWERTY KEYBOARD]
|
||||||
|
Default Off
|
||||||
|
Calculator Login
|
||||||
Test Login Now
|
Test Login Now
|
||||||
Hardware On/Off
|
Hardware On/Off
|
||||||
USB Port
|
USB Port
|
||||||
@ -244,12 +478,30 @@
|
|||||||
Default Off
|
Default Off
|
||||||
Enable NFC
|
Enable NFC
|
||||||
Multisig Wallets
|
Multisig Wallets
|
||||||
(none setup yet)
|
2/4: CC-2-of-4
|
||||||
Import from SD
|
"CC-2-of-4"
|
||||||
|
View Details
|
||||||
|
Delete
|
||||||
|
Coldcard Export
|
||||||
|
Electrum Wallet
|
||||||
|
Descriptors
|
||||||
|
View Descriptor
|
||||||
|
Export
|
||||||
|
Bitcoin Core
|
||||||
|
Import
|
||||||
Export XPUB
|
Export XPUB
|
||||||
Create Airgapped
|
Create Airgapped
|
||||||
Trust PSBT?
|
Trust PSBT?
|
||||||
Skip Checks?
|
Skip Checks?
|
||||||
|
Full Address View?
|
||||||
|
Partly Censor
|
||||||
|
Show Full
|
||||||
|
Unsorted Multisig?
|
||||||
|
NFC Push Tx
|
||||||
|
coldcard.com
|
||||||
|
mempool.space
|
||||||
|
Custom URL...
|
||||||
|
Disable
|
||||||
Display Units
|
Display Units
|
||||||
BTC
|
BTC
|
||||||
mBTC
|
mBTC
|
||||||
@ -268,17 +520,205 @@
|
|||||||
4 hours
|
4 hours
|
||||||
8 hours
|
8 hours
|
||||||
Never
|
Never
|
||||||
|
Idle Timeout (on battery) [IF BATTERIES]
|
||||||
|
30 seconds
|
||||||
|
60 seconds
|
||||||
|
2 minutes
|
||||||
|
5 minutes
|
||||||
|
10 minutes
|
||||||
|
15 minutes
|
||||||
|
30 minutes
|
||||||
|
1 hour
|
||||||
|
4 hours
|
||||||
|
Never
|
||||||
|
LCD Brightness (on battery) [IF BATTERIES]
|
||||||
|
25%
|
||||||
|
50%
|
||||||
|
60%
|
||||||
|
70%
|
||||||
|
80%
|
||||||
|
90%
|
||||||
|
95% (default)
|
||||||
|
100%
|
||||||
Delete PSBTs
|
Delete PSBTs
|
||||||
Default Keep
|
Default Keep
|
||||||
Delete PSBTs
|
Delete PSBTs
|
||||||
|
Keyboard EMU
|
||||||
|
Default Off
|
||||||
|
Enable
|
||||||
|
Buried Settings
|
||||||
|
Home Menu XFP [IF SECRET AND NOT TMP SEED]
|
||||||
|
Only Tmp
|
||||||
|
Always Show
|
||||||
|
Menu Wrapping
|
||||||
|
Default
|
||||||
|
Always Wrap
|
||||||
|
Secure Logout
|
||||||
|
[NFC key shortcut] [IF NFC ENABLED]
|
||||||
|
Sign PSBT
|
||||||
|
Show Address
|
||||||
|
Sign Message
|
||||||
|
Verify Sig File
|
||||||
|
Verify Address
|
||||||
|
File Share
|
||||||
|
Import Multisig
|
||||||
|
Push Transaction [IF PUSHTX ENABLED]
|
||||||
---
|
---
|
||||||
|
|
||||||
[FACTORY MODE]
|
[FACTORY MODE]
|
||||||
Bag Me Now
|
Bag Me Now
|
||||||
|
Version: 5.x.x
|
||||||
DFU Upgrade
|
DFU Upgrade
|
||||||
Show Version
|
|
||||||
Ship W/O Bag
|
Ship W/O Bag
|
||||||
Debug Functions
|
Debug Functions
|
||||||
Perform Selftest
|
Perform Selftest
|
||||||
---
|
---
|
||||||
|
|
||||||
|
[SSSP]
|
||||||
|
Ready To Sign
|
||||||
|
Passphrase [IF WORD BASED SEED & SSSP RELATED KEYS ENABLED]
|
||||||
|
Restore Saved
|
||||||
|
c*******
|
||||||
|
[3A14F788]
|
||||||
|
Restore
|
||||||
|
Delete
|
||||||
|
Edit Phrase
|
||||||
|
Scan Any QR Code [IF QR SCANNER]
|
||||||
|
Address Explorer
|
||||||
|
Classic P2PKH
|
||||||
|
↳ mtHSVByP9EYZ⋯Vm19gvpecb5R
|
||||||
|
P2SH-Segwit
|
||||||
|
↳ 2NCAJ5wD4Gvm⋯NphNU8UYoEJv
|
||||||
|
Segwit P2WPKH
|
||||||
|
↳ tb1qupyd58nd⋯vu9jtdyws9n9
|
||||||
|
Applications
|
||||||
|
Samourai
|
||||||
|
Post-mix
|
||||||
|
Pre-mix
|
||||||
|
Wasabi
|
||||||
|
Account Number
|
||||||
|
Custom Path
|
||||||
|
CC-2-of-4
|
||||||
|
Secure Notes & Passwords[IF ENABLED & SSSP ALLOW NOTES]
|
||||||
|
1: note0
|
||||||
|
"note0"
|
||||||
|
View Note
|
||||||
|
Sign Note Text
|
||||||
|
2: secret-PWD
|
||||||
|
"secret-PWD"
|
||||||
|
↳ satoshi
|
||||||
|
↳ abc.org
|
||||||
|
View Password
|
||||||
|
Send Password [MAYBE]
|
||||||
|
Sign Note Text
|
||||||
|
Type Passwords [MAYBE]
|
||||||
|
Seed Vault[IF ENABLED & SSSP RELATED KEYS ENABLED]
|
||||||
|
1: [7126EB3C]
|
||||||
|
[7126EB3C]
|
||||||
|
Use This Seed
|
||||||
|
2: [CCEE13B9]
|
||||||
|
[CCEE13B9]
|
||||||
|
Use This Seed
|
||||||
|
3: [03EE9989]
|
||||||
|
[03EE9989]
|
||||||
|
Use This Seed
|
||||||
|
Advanced/Tools
|
||||||
|
File Management
|
||||||
|
Sign Text File
|
||||||
|
Batch Sign PSBT
|
||||||
|
List Files
|
||||||
|
Export Wallet
|
||||||
|
Sparrow
|
||||||
|
Cove
|
||||||
|
Bitcoin Core
|
||||||
|
Nunchuk
|
||||||
|
Bull Bitcoin
|
||||||
|
Blue Wallet
|
||||||
|
Electrum Wallet
|
||||||
|
Wasabi Wallet
|
||||||
|
Fully Noded
|
||||||
|
Unchained
|
||||||
|
Theya
|
||||||
|
Bitcoin Safe
|
||||||
|
Zeus
|
||||||
|
Samourai Postmix
|
||||||
|
Samourai Premix
|
||||||
|
Descriptor
|
||||||
|
Generic JSON
|
||||||
|
Export XPUB
|
||||||
|
Segwit (BIP-84)
|
||||||
|
Classic (BIP-44)
|
||||||
|
P2WPKH/P2SH (BIP-49)
|
||||||
|
Master XPUB
|
||||||
|
Current XFP
|
||||||
|
Key Expression
|
||||||
|
Dump Summary
|
||||||
|
Verify Sig File
|
||||||
|
NFC File Share [IF NFC ENABLED]
|
||||||
|
BBQr File Share [IF QR SCANNER]
|
||||||
|
QR File Share [IF QR SCANNER]
|
||||||
|
Format SD Card
|
||||||
|
Format RAM Disk [IF VIRTDISK ENABLED]
|
||||||
|
Export Wallet
|
||||||
|
Sparrow
|
||||||
|
Cove
|
||||||
|
Bitcoin Core
|
||||||
|
Nunchuk
|
||||||
|
Bull Bitcoin
|
||||||
|
Blue Wallet
|
||||||
|
Electrum Wallet
|
||||||
|
Wasabi Wallet
|
||||||
|
Fully Noded
|
||||||
|
Unchained
|
||||||
|
Theya
|
||||||
|
Bitcoin Safe
|
||||||
|
Zeus
|
||||||
|
Samourai Postmix
|
||||||
|
Samourai Premix
|
||||||
|
Descriptor
|
||||||
|
Generic JSON
|
||||||
|
Export XPUB
|
||||||
|
Segwit (BIP-84)
|
||||||
|
Classic (BIP-44)
|
||||||
|
P2WPKH/P2SH (BIP-49)
|
||||||
|
Master XPUB
|
||||||
|
Current XFP
|
||||||
|
Key Expression
|
||||||
|
Dump Summary
|
||||||
|
Teleport Multisig PSBT [MAYBE]
|
||||||
|
View Identity
|
||||||
|
Temporary Seed [IF SSSP RELATED KEYS ENABLED]
|
||||||
|
Import from QR Scan [IF QR SCANNER]
|
||||||
|
Import Words
|
||||||
|
12 Words
|
||||||
|
18 Words
|
||||||
|
24 Words
|
||||||
|
Import via NFC [IF NFC ENABLED]
|
||||||
|
Import XPRV
|
||||||
|
Tapsigner Backup
|
||||||
|
Coldcard Backup
|
||||||
|
Restore Seed XOR
|
||||||
|
Paper Wallets
|
||||||
|
WIF Store
|
||||||
|
NFC Tools [IF NFC ENABLED]
|
||||||
|
Sign PSBT
|
||||||
|
Show Address
|
||||||
|
Sign Message
|
||||||
|
Verify Sig File
|
||||||
|
Verify Address
|
||||||
|
File Share
|
||||||
|
Push Transaction [IF PUSHTX ENABLED]
|
||||||
|
Show Firmware Version
|
||||||
|
Destroy Seed [IF SECRET AND NOT TMP SEED]
|
||||||
|
Secure Logout
|
||||||
|
EXIT TEST DRIVE [MAYBE]
|
||||||
|
[NFC key shortcut] [IF NFC ENABLED]
|
||||||
|
Sign PSBT
|
||||||
|
Show Address
|
||||||
|
Sign Message
|
||||||
|
Verify Sig File
|
||||||
|
Verify Address
|
||||||
|
File Share
|
||||||
|
Push Transaction [IF PUSHTX ENABLED]
|
||||||
|
---
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,9 @@ tools may or may not hide it from you based on Unix filename
|
|||||||
conventions. Reformating the card will certainly remove this file,
|
conventions. Reformating the card will certainly remove this file,
|
||||||
so keep that in mind when managing your "special" cards.
|
so keep that in mind when managing your "special" cards.
|
||||||
|
|
||||||
|
If using COLDCARD Q and both card slot are populated during login
|
||||||
|
make sure that enrolled card is in top slot (slot A).
|
||||||
|
|
||||||
## Menu Settings
|
## Menu Settings
|
||||||
|
|
||||||
See menu in: `Settings -> Login Settings -> MicroSD 2FA`
|
See menu in: `Settings -> Login Settings -> MicroSD 2FA`
|
||||||
|
|||||||
62
docs/msg-signing.md
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# COLDCARD Message Signing
|
||||||
|
|
||||||
|
COLDCARD can sign messages send to it via USB with the help of `ckcc` utility,
|
||||||
|
sign messages provided via specially crafted file on SD card or Vdisk,
|
||||||
|
and NFC-equipped models (Mk4, Mk5, and Q) can also sign messages sent to COLDCARD via NFC.
|
||||||
|
The resulting signature can be returned over SD card/Vdisk, NFC, or — on Q — as a QR code.
|
||||||
|
|
||||||
|
Signature format follows [BIP-0137](https://github.com/bitcoin/bips/blob/master/bip-0137.mediawiki) specification.
|
||||||
|
COLDCARD Mk3 and COLDCARD Mk4 up to version `5.1.0` used compressed P2PKH header byte for all script types.
|
||||||
|
From version `5.1.0` correct header byte is used for corresponding script type.
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
|
||||||
|
From version `5.1.0` users can verify signed messages directly on the device.
|
||||||
|
If signature file is on SD card or Virtual disk `Advanced/Tools -> File Management -> Verify Sig File`. In case
|
||||||
|
signature file is detached signature of signed export (or any other file), COLDCARD can check if digest of file
|
||||||
|
specified in the message matches contents of file. This requires file signed to be available on SD card or Vdisk.
|
||||||
|
File size limit for signature files is approximately 10KB.
|
||||||
|
If signature file is imported via NFC `Advance/Tools -> NFC Tools -> Verify Sig File`.
|
||||||
|
To cross-verify COLDCARD verification use https://www.verifybitcoinmessage.com/ as it supports multiple script types.
|
||||||
|
Bitcoin core can only verify P2PKH.
|
||||||
|
|
||||||
|
## Signed Exports
|
||||||
|
|
||||||
|
From version `5.1.0` most of SD card and Virtual disk exports are accompanied by detached signature file.
|
||||||
|
If exported file name is `addresses.csv` signature file name will be `addresses.sig`.
|
||||||
|
|
||||||
|
### Message construction and signature file format
|
||||||
|
|
||||||
|
1. contents of the exported file are hashed with single SHA256 hash
|
||||||
|
2. `msg = hash from step 1. + two spaces + exported filename (basename)`
|
||||||
|
3. msg from step 2. is hashed again with Bitcoin msg hash `"Bitcoin Signed Message:" + ser_compact_size(len(msg)) + msg`
|
||||||
|
4. detached signature file format:
|
||||||
|
```text
|
||||||
|
-----BEGIN BITCOIN SIGNED MESSAGE-----
|
||||||
|
f1591bfb04a89f723e1f14eb01a6b2f6f507eb0967d0a5d7822b329b98018ae4 coldcard-export.json
|
||||||
|
-----BEGIN BITCOIN SIGNATURE-----
|
||||||
|
mtHSVByP9EYZmB26jASDdPVm19gvpecb5R
|
||||||
|
IFOvGVJrm31S0j+F4dVfQ5kbRKWKcmhmXIn/Lw8iIgaCG5QNZswjrN4X673R7jTZo1kvLmiD4hlIrbuLh/HqDuk=
|
||||||
|
-----END BITCOIN SIGNATURE-----
|
||||||
|
```
|
||||||
|
|
||||||
|
### What Is Signed
|
||||||
|
|
||||||
|
1. **Single sig address explorer exports:** Signed by the key corresponding to the first (0th) address on the exported list.
|
||||||
|
2. **Specific single sig exports:** Signed by the key corresponding to the external address at index zero of chosen application specific derivation `m/<app_deriv>h/<coin_type>'h/<account>h/0/0`.
|
||||||
|
* Bitcoin Core
|
||||||
|
* Electrum Wallet
|
||||||
|
* Wasabi Wallet
|
||||||
|
* Samourai Postmix
|
||||||
|
* Samourai Premix
|
||||||
|
* Descriptor
|
||||||
|
3. **Generic single sig exports:** Signed by key that corresponds to first (0th) external address at derivation `m/44h/<coin_type>h/<account>h/0/0`.
|
||||||
|
* Lily Wallet
|
||||||
|
* Generic JSON
|
||||||
|
* Dump Summary
|
||||||
|
4. **BIP85 derived entropy exports:** Signed by path that corresponds to specific BIP85 application.
|
||||||
|
5. **Paper wallet exports:** Signed by key and address exported as paper wallet itself.
|
||||||
|
6. **Multisig exports:** public keys are encoded as P2PKH address for all multisg signature exports
|
||||||
|
* Multisig wallet descriptor: signed by the key corresponding to the first external address of own enrolled extended key `my_key/0/0`
|
||||||
|
* Generic XPUBs export: signed by the key corresponding to the first external address of own standard P2WSH derivation `m/48h/<coin_type>h/<account>h/2h/0/0`
|
||||||
|
* Multisig address explorer export: Signed by own key at the same derivation as first (0th) row on exported list. `my_key/<change>/<start_index>`
|
||||||
@ -1,10 +1,20 @@
|
|||||||
# NFC and Coldcard Mk4
|
# NFC and Coldcard
|
||||||
|
|
||||||
(Applies to Coldcard Mk4 only)
|
(Applies to NFC-equipped models: Mk4, Mk5, and Q)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Mk4 NFC antenna is centered under number `8` on the keypad. Before using NFC,
|
The NFC antenna location depends on the hardware:
|
||||||
|
|
||||||
|
- **Mk4**: a PCB trace loop, centered under number `8` on the keypad.
|
||||||
|
- **Mk5**: a discrete coil (`L6`) in the **top-right corner** of the device
|
||||||
|
- **Q1**: a flexible "sticker" antenna behind the display. The green LED below the
|
||||||
|
bottom-right of the display (`D12`) lights up while an NFC transfer is active —
|
||||||
|
it is the activity indicator, not the antenna.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Before using NFC,
|
||||||
it is important to locate the position of NFC antenna on your device and point it
|
it is important to locate the position of NFC antenna on your device and point it
|
||||||
correctly towards the Coldcard NFC antenna. Picture below shows an example with iPhone
|
correctly towards the Coldcard NFC antenna. Picture below shows an example with iPhone
|
||||||
that has NFC antenna located at the top right edge. The NFC smartphone antenna
|
that has NFC antenna located at the top right edge. The NFC smartphone antenna
|
||||||
@ -36,7 +46,7 @@ in general. Good interoperability is critical with radio standards.
|
|||||||
|
|
||||||
## Lower Layers
|
## Lower Layers
|
||||||
|
|
||||||
The Coldcard Mk4 has an chip that acts as a Type 5 NFC tag. The
|
The Coldcard has a chip that acts as a Type 5 NFC tag. The
|
||||||
radio standard is called "NFC-V" or ISO-15693, and operates on a
|
radio standard is called "NFC-V" or ISO-15693, and operates on a
|
||||||
13.56 Mhz carrier wave.
|
13.56 Mhz carrier wave.
|
||||||
|
|
||||||
@ -58,9 +68,13 @@ unless we are actively sharing something. We disable the "energy
|
|||||||
harvesting" features of the chip, so it will not do anything when
|
harvesting" features of the chip, so it will not do anything when
|
||||||
the Coldcard is powered-down, regardless of the NFC setting.
|
the Coldcard is powered-down, regardless of the NFC setting.
|
||||||
|
|
||||||
If the above is not enough for you, the antenna can be destroyed
|
If the above is not enough for you, the antenna can be destroyed:
|
||||||
by cutting the trace labeled "NFC" inside the hole for the MicroSD
|
|
||||||
card. Use the point of a sharp knife to cut and peel up the trace.
|
- **Mk4**: cut the trace labeled "NFC" inside the hole for the MicroSD card,
|
||||||
|
using the point of a sharp knife to cut and peel up the trace.
|
||||||
|
- **Mk5**: has no such trace — its antenna is the discrete coil `L6` in the
|
||||||
|
top-right corner, which would have to be physically removed instead.
|
||||||
|
- **Q1**: cut the trace labeled "NFC DATA" under the batteries.
|
||||||
|
|
||||||
The NFC traffic is not encrypted and is subject to eavesdropping.
|
The NFC traffic is not encrypted and is subject to eavesdropping.
|
||||||
While the NFC feature is active, your Coldcard can be uniquely
|
While the NFC feature is active, your Coldcard can be uniquely
|
||||||
|
|||||||
103
docs/nfc-pushtx.md
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# NFC Push Tx
|
||||||
|
|
||||||
|
This feature allows single-tap broadcast of the freshly-signed transaction.
|
||||||
|
|
||||||
|
`PSBT ==[SD|QR|NFC]==> COLDCARD signed TXN ==[NFC tap]==> Phone Browser ==> Server TXN Broadcast`
|
||||||
|
|
||||||
|
Once enabled with a URL, the COLDCARD will show the NFC animation
|
||||||
|
after signing the transaction. When the user taps their phone, the
|
||||||
|
phone will see an NFC tag with URL inside. That URL contains the
|
||||||
|
signed transaction ready to go, and once opening in the mobile
|
||||||
|
browser, that URL will load. The landing page will connect to a
|
||||||
|
Bitcoin node (or similar) and send the transaction on the public
|
||||||
|
Bitcoin network.
|
||||||
|
|
||||||
|
This feature is available on Q and Mk4 and requires NFC to be enabled.
|
||||||
|
See `Settings > NFC Push Tx`.
|
||||||
|
|
||||||
|
See the latest on our feature minisite: [PushTx.org](https://pushtx.org)
|
||||||
|
|
||||||
|
## Protocol Spec
|
||||||
|
|
||||||
|
The COLDCARD needs a URL prefix. To that it appends some values:
|
||||||
|
|
||||||
|
- `t=...`
|
||||||
|
- this is the transaction, in binary encoded with
|
||||||
|
[base64url](https://datatracker.ietf.org/doc/html/rfc4648#section-5)
|
||||||
|
|
||||||
|
- `&c=...`
|
||||||
|
- the rightmost 8 bytes of SHA256 over the transaction. Also `base64url` encoded.
|
||||||
|
|
||||||
|
- `&n=XTN`
|
||||||
|
- if, and only if, the COLDCARD is set for Testnet, this value is appended to
|
||||||
|
indicate that the transaction is for Testnet3 and not MainNet.
|
||||||
|
- when RegTest is enabled, the value will be `XRT`
|
||||||
|
|
||||||
|
We provide a few default URL values to our customers, including one backend we
|
||||||
|
will operate on `coldcard.com`. The URL can also be directly entered by the
|
||||||
|
customer. On the Q, it can be scanned from a QR code.
|
||||||
|
|
||||||
|
For COLDCARD backend, the url used is:
|
||||||
|
|
||||||
|
https://coldcard.com/pushtx#
|
||||||
|
|
||||||
|
The complete URL with a typical transaction might look like this (but longer):
|
||||||
|
|
||||||
|
https://coldcard.com/pushtx#t=AgAAAAMNCxXtp2GVYVhkRXHLMmdZFs4p3kbFK ⋯ ABf&c=uiSVRda-1tw
|
||||||
|
|
||||||
|
We are using hash symbol here so that our server logs do not get
|
||||||
|
contaminated with the arguments. The landing page uses javascript
|
||||||
|
to read the hash part of the URL and decodes from there. If you
|
||||||
|
prefer, your URL can end with `?` and then the arguments will be
|
||||||
|
sent by the phone's browser to your server. Your processing can be
|
||||||
|
entirely done in the backend in this case.
|
||||||
|
|
||||||
|
## Expectations for the Backend
|
||||||
|
|
||||||
|
Your code should decode the transaction and check the SHA-256 hash
|
||||||
|
matches. If it does not match, or if `c` value is missing, assume
|
||||||
|
the URL has been truncated and report that to the user.
|
||||||
|
|
||||||
|
Once decoded, your code should immediately broadcast the transaction.
|
||||||
|
A confirmation step is not required in our opinion. Once it is
|
||||||
|
submitted to Bitcoin Core (or other API), any status response should
|
||||||
|
be decoded and shown to the user so they know it is on it's way.
|
||||||
|
If it was not accepted, please report the error to the user as
|
||||||
|
clearly as possible.
|
||||||
|
|
||||||
|
Next, it would make sense to either link to the TXID on a block
|
||||||
|
explorer to provide further proof that it has been sent and that
|
||||||
|
it is now waiting in the mempool.
|
||||||
|
|
||||||
|
## Backend Implementations
|
||||||
|
|
||||||
|
- Mempool.space's [implementation of this feature](https://github.com/mempool/mempool/pull/5132).
|
||||||
|
|
||||||
|
- A single-file (html and javascript) file is available
|
||||||
|
at [coldcard.com/static/coldcard-pushtx.html](https://coldcard.com/static/coldcard-pushtx.html).
|
||||||
|
You can host this file anywhere your phone can reach, and then use that URL in your
|
||||||
|
COLDCARD settings. It uses your phone's browser to submit directly
|
||||||
|
to `mempool.space` and `blockstream.info` sites (both at same time). It is equivalent
|
||||||
|
to the page hosted at `https://coldcard.com/pushtx#`. Full source code is published here:
|
||||||
|
[github.com/Coldcard/push-tx](https://github.com/Coldcard/push-tx)
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- Complete URL might be as large as 8,000 bytes. Some web servers will not support beyond
|
||||||
|
4k bytes and the NFC implementation of the phone may also have limits.
|
||||||
|
- The service URL provided must end in `?` or `#` or `&`.
|
||||||
|
- `base64url` values from COLDCARD will not have padding (`=` bytes) at end.
|
||||||
|
- POST cannot be used directly because the expect the phone to do a GET on the URL provided.
|
||||||
|
- Honest backends will not log the IP address of incoming transactions, but there is
|
||||||
|
no way to enforce that, and CloudFlare sees all.
|
||||||
|
|
||||||
|
## Example URL
|
||||||
|
|
||||||
|
```
|
||||||
|
https://mempool.space/pushtx#t=AgAAAAOHqK3w3hC6PSC0buthnJA5R9Y88WAlEvm9cifNVUPhIwAAAABqRzBEAiB-M9YprNYoohqHdQHg4wY_qcEMwDmyIQH8prykk8-0KwIgARxcojKrtixicouiUxhk4jQq_MAl11ptIgHDlRjgk5ABIQM4bgMAVDbDSr_9CvLjbg5nxrWnDGI-kVmkfL81GXZtCf____8OaH0RxW7DjZKdIF6rvbHvvyFGCBQ0PTgpx20nA_wbLgAAAABqRzBEAiBwUFigORJDPK8ptnYPAntjV-RUn1jAuzphicQstwVv-QIgEbMC8FWXQ5Jve5DaAqKJsqoj3peK83iub_oOkmbiYg4BIQO5Ehn2t0oUG3hnK4cBnwCwMc33DcdJ8aSMWzRQ_wjZL_____-UG6M-eBeAun-EZp6EbVypvVJ3mXCQrN_fUDn-kwoEnQAAAABqRzBEAiAgFAtVTpQYTKplc9NuV7Ws7ZFYeNO8BCS4ozgWrgd2ogIgGTTcw98xQdcGWeWQhVfVm_vZorBIOYovQPQeK0Lg9t8BIQLPWPioVWvj1z4NMHBCkeirYOUalCa83wbSH0CREnGZvv____8CjM_wCAAAAAAZdqkUIJA8_yqzaj0NzhvYVEIBno5gETGIrIzP8AgAAAAAGXapFEaV7xTyleuEX9OejdlUlsz7RTr0iKwAAAAA&c=hre47vyMC78&n=XTN
|
||||||
|
```
|
||||||
|
|
||||||
|
- this transaction doesn't have valid inputs, and will cause an error
|
||||||
|
- mempool.space will redirect this to a testnet endpoint (because ends with `n=XTN`)
|
||||||
|
|
||||||
|
|
||||||
BIN
docs/nfc-tap-locations.png
Normal file
|
After Width: | Height: | Size: 258 KiB |
196
docs/notes-on-repro.md
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
# Notes on Reproducible Builds
|
||||||
|
|
||||||
|
The following document aims to breakdown how reproducibility is verified in the `make repro` build step.
|
||||||
|
|
||||||
|
## stm32/shared.mk
|
||||||
|
|
||||||
|
The entrypoint makefile for repro builds.
|
||||||
|
|
||||||
|
### repro
|
||||||
|
|
||||||
|
The `repro` command in `shared.mk` is the first step in the repro build process, which triggers a docker build and run process.
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
repro: submods-match code-committed
|
||||||
|
repro:
|
||||||
|
docker build -t coldcard-build - < dockerfile.build
|
||||||
|
(cd ..; docker run $(DOCK_RUN_ARGS) sh src/stm32/repro-build.sh $(VERSION_STRING) $(HW_MODEL) $(PARENT_MKFILE))
|
||||||
|
```
|
||||||
|
|
||||||
|
`$(HW_MODEL)` is the model string (e.g. `mk4`, `q1`) and `$(PARENT_MKFILE)` is the
|
||||||
|
top-level makefile being used (`MK-Makefile` or `Q1-Makefile`). The `submods-match`
|
||||||
|
and `code-committed` prerequisites ensure the submodules and working tree are clean
|
||||||
|
before a repro build.
|
||||||
|
|
||||||
|
Below are interesting sections from the docker logs that give an idea as to what is going on in build process:
|
||||||
|
|
||||||
|
```stdout
|
||||||
|
+ mkdir /tmp/checkout
|
||||||
|
+ mount -t tmpfs tmpfs /tmp/checkout
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
We will pull the release from coldcard.com into the `/tmp/checkout` directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
+ git clone /work/src/.git firmware
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
+ cd firmware/external
|
||||||
|
+ git submodule update --init
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
Successfully installed signit-1.0
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
+ cd ../stm32
|
||||||
|
+ cd ../releases
|
||||||
|
+ '[' -f '*-v5.0.7-mk4-coldcard.dfu' ]
|
||||||
|
+ dd 'bs=66' 'skip=1'
|
||||||
|
+ grep -F v5.0.7-mk4-coldcard.dfu signatures.txt
|
||||||
|
0+1 records in
|
||||||
|
0+1 records out
|
||||||
|
+ PUBLISHED_BIN=2022-10-05T1724-v5.0.7-mk4-coldcard.dfu
|
||||||
|
+ '[' -z 2022-10-05T1724-v5.0.7-mk4-coldcard.dfu ]
|
||||||
|
+ wget -S https://coldcard.com/downloads/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
'2022-10-05T1724-v5.0.7-mk4-coldcard.dfu' saved
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
+ PUBLISHED_BIN=/tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
+ make -f MK-Makefile setup
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
+ make -f MK-Makefile firmware-signed.bin firmware-signed.dfu production.bin dev.dfu firmware.lss firmware.elf
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
signit sign -b l-port/build-COLDCARD_MK4 -m mk4 5.0.7 -o firmware-signed.bin
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
signit sign -m mk4 5.0.7 -r firmware-signed.bin -k 1 -o production.bin
|
||||||
|
You don't have that key (1), so using key zero instead!
|
||||||
|
...
|
||||||
|
|
||||||
|
cd ../external/micropython/ports/stm32 && make BOARD=COLDCARD_MK4 -j 4 EXCLUDE_NGU_TESTS=1 DEBUG_BUILD=0
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
../external/micropython/tools/dfu.py -b 0x08020000:dev.bin dev.dfu
|
||||||
|
arm-none-eabi-objdump -h -S l-port/build-COLDCARD_MK4/firmware.elf > firmware.lss
|
||||||
|
cp l-port/build-COLDCARD_MK4/firmware.elf .
|
||||||
|
+ '[' /tmp/checkout/firmware/stm32 '!=' /work/src/stm32 ]
|
||||||
|
+ rsync -av --ignore-missing-args firmware-signed.bin firmware-signed.dfu production.bin dev.dfu firmware.lss firmware.elf /work/built
|
||||||
|
sending incremental file list
|
||||||
|
dev.dfu
|
||||||
|
firmware-signed.bin
|
||||||
|
firmware-signed.dfu
|
||||||
|
firmware.elf
|
||||||
|
firmware.lss
|
||||||
|
production.bin
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
+ make -f MK-Makefile 'PUBLISHED_BIN=/tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu' check-repro
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
Comparing against: /tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu
|
||||||
|
test -n "/tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu" -a -f /tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu
|
||||||
|
rm -f -f check-fw.bin check-bootrom.bin
|
||||||
|
signit split /tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu check-fw.bin check-bootrom.bin
|
||||||
|
start 293 for 870400 bytes: Firmware => check-fw.bin
|
||||||
|
start 870701 for 114688 bytes: Bootrom => check-bootrom.bin
|
||||||
|
signit check check-fw.bin
|
||||||
|
magic_value: 0xcc001234
|
||||||
|
timestamp: 2022-10-05 17:24:55 UTC
|
||||||
|
version_string: 5.0.7
|
||||||
|
pubkey_num: 1
|
||||||
|
firmware_length: 870400
|
||||||
|
install_flags: 0x0 =>
|
||||||
|
hw_compat: 0x8 => Mk4
|
||||||
|
best_ts: b'\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
future: 0000000000000000 ... 0000000000000000
|
||||||
|
signature: 293948e7ce4a3555 ... 766437aa65d3e88a
|
||||||
|
sha256^2: 7f3a7c5f794ce72f68280447cddc837fa62245fdf4b795822127624f8775dca2
|
||||||
|
ECDSA Signature: CORRECT
|
||||||
|
signit check firmware-signed.bin
|
||||||
|
magic_value: 0xcc001234
|
||||||
|
timestamp: 2022-10-24 13:33:16 UTC
|
||||||
|
version_string: 5.0.7
|
||||||
|
pubkey_num: 0
|
||||||
|
firmware_length: 870400
|
||||||
|
install_flags: 0x0 =>
|
||||||
|
hw_compat: 0x8 => Mk4
|
||||||
|
best_ts: b'\x00\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
future: 0000000000000000 ... 0000000000000000
|
||||||
|
signature: deb643d0a140d89e ... c544f09cd80fa65c
|
||||||
|
sha256^2: a46ddd6e599a49a573bf76054f438c9efe1ee031bfae74a00b0e7bbe76f516c3
|
||||||
|
ECDSA Signature: CORRECT
|
||||||
|
hexdump -C firmware-signed.bin | sed -e 's/^00003f[89abcdef]0 .*/(firmware signature here)/' > repro-got.txt
|
||||||
|
hexdump -C check-fw.bin | sed -e 's/^00003f[89abcdef]0 .*/(firmware signature here)/' > repro-want.txt
|
||||||
|
diff repro-got.txt repro-want.txt
|
||||||
|
|
||||||
|
SUCCESS.
|
||||||
|
|
||||||
|
You have built a bit-for-bit identical copy of Coldcard firmware for v5.0.7
|
||||||
|
```
|
||||||
|
|
||||||
|
## check-repro
|
||||||
|
|
||||||
|
The `check-repro` section of the makefile contains the steps required to verify that the build artifacts are infact a bit-for-bit match to the release candidates.
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
check-repro: TRIM_SIG = sed -e 's/^00003f[89abcdef]0 .*/(firmware signature here)/'
|
||||||
|
check-repro: firmware-signed.bin
|
||||||
|
ifeq ($(PUBLISHED_BIN),)
|
||||||
|
@echo ""
|
||||||
|
@echo "Need published binary for: $(VERSION_STRING)"
|
||||||
|
@echo ""
|
||||||
|
@echo "Copy it into ../releases"
|
||||||
|
@echo ""
|
||||||
|
else
|
||||||
|
@echo Comparing against: $(PUBLISHED_BIN)
|
||||||
|
test -n "$(PUBLISHED_BIN)" -a -f $(PUBLISHED_BIN)
|
||||||
|
$(RM) -f check-fw.bin check-bootrom.bin
|
||||||
|
$(SIGNIT) split $(PUBLISHED_BIN) check-fw.bin check-bootrom.bin
|
||||||
|
$(SIGNIT) check check-fw.bin
|
||||||
|
$(SIGNIT) check firmware-signed.bin
|
||||||
|
hexdump -C firmware-signed.bin | $(TRIM_SIG) > repro-got.txt
|
||||||
|
hexdump -C check-fw.bin | $(TRIM_SIG) > repro-want.txt
|
||||||
|
diff repro-got.txt repro-want.txt
|
||||||
|
@echo ""
|
||||||
|
@echo "SUCCESS. "
|
||||||
|
@echo ""
|
||||||
|
@echo "You have built a bit-for-bit identical copy of Coldcard firmware for v$(VERSION_STRING)"
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
To summarize `check-repro`:
|
||||||
|
|
||||||
|
- At the final `check-repro` step, we have a locally built `firmware-signed.bin` and we want to check that it matches the binary release provided by Coinkite.
|
||||||
|
|
||||||
|
- This step verifies the signature of the binary is valid, using either the Coinkite key factory key or the "debug" key zero which is public.
|
||||||
|
|
||||||
|
- An identical checksum match will not be possible as is, since there is signature data embedded into into the binary, which must be removed.
|
||||||
|
|
||||||
|
- The specific release of the version that is being built is fetched, and placed it under /tmp/checkout/firmware/releases/*.dfu
|
||||||
|
|
||||||
|
- `split` (cli/signit.py: Line 153-175) is run against the release `*.dfu` resulting in a `check-fw.bin` and `check-bootrom.bin`. "This splits the DFU file into the two parts it contains: the main firmware (COLDCARD application) and the boot loader code."
|
||||||
|
|
||||||
|
- `check` (cli/signit.py: Line 176-243) is run against each the release `check-fw.bin` and our built `firmware-signed.bin`.
|
||||||
|
|
||||||
|
- a hexdump is taken of each the release `check-fw.bin` and our built `firmware-signed.bin` piped through $TRIM_SIG which removes 64 bytes of signature data and subsitutes it with a common string.
|
||||||
|
|
||||||
|
- Finally the diff of the two hexdumps are compared to prove reproducibility.
|
||||||
@ -81,7 +81,7 @@ of your duress PIN.
|
|||||||
The attackers could tell when the brick-me PIN has worked, but when
|
The attackers could tell when the brick-me PIN has worked, but when
|
||||||
the brick-me PIN works, the Coldcard will immediately use it to
|
the brick-me PIN works, the Coldcard will immediately use it to
|
||||||
destroy the main pairing secret. This renders the security element
|
destroy the main pairing secret. This renders the security element
|
||||||
useless. This happens in about 50 milliseconds and is done long before
|
useless. This happens in about 50 milliseconds and is done long
|
||||||
before anyone gets an on-screen confirmation that it worked.
|
before anyone gets an on-screen confirmation that it worked.
|
||||||
|
|
||||||
There is little time to interrupt this or jam the bus to stop it.
|
There is little time to interrupt this or jam the bus to stop it.
|
||||||
@ -183,12 +183,12 @@ This double-hashed value is what's stored inside the secure element
|
|||||||
as it travels on the bus. Because of the inclusion of the pairing
|
as it travels on the bus. Because of the inclusion of the pairing
|
||||||
secret, the hashes generated by each Coldcard will be different.
|
secret, the hashes generated by each Coldcard will be different.
|
||||||
|
|
||||||
With Mark3 hardware, we've added a key-streching step, which starts
|
With Mark3 hardware, we've added a key-stretching step, which starts
|
||||||
with the above value, and does HMAC-SHA256 using a secret key known
|
with the above value, and does HMAC-SHA256 using a secret key known
|
||||||
only to the 608a (repeatedly). That value is used directly to check the
|
only to the 608a (repeatedly). That value is used directly to check the
|
||||||
duress PIN, and if that doesn't match, it is HMAC-SHA256'ed again,
|
duress PIN, and if that doesn't match, it is HMAC-SHA256'ed again,
|
||||||
using a key that is usage limited. This limits actual PIN login attempts
|
using a key that is usage limited. This limits actual PIN login attempts
|
||||||
to a set value and is enfoced by the 608a internally.
|
to a set value and is enforced by the 608a internally.
|
||||||
|
|
||||||
## Genuine vs. Caution Lights
|
## Genuine vs. Caution Lights
|
||||||
|
|
||||||
@ -281,7 +281,7 @@ Here's what the warning screen looks like:
|
|||||||
|
|
||||||
### Benefits
|
### Benefits
|
||||||
|
|
||||||
- no warnings, but still trustable thanks to ATECC608A
|
- no warnings, but still trustable thanks to ATECC608
|
||||||
- random devs can replace 99% of firmware at Micropython layer (everything but bootloader)
|
- random devs can replace 99% of firmware at Micropython layer (everything but bootloader)
|
||||||
- but they need to retain our code for talking to bootloader and secure element,
|
- but they need to retain our code for talking to bootloader and secure element,
|
||||||
so that PIN can be entered and verified.
|
so that PIN can be entered and verified.
|
||||||
|
|||||||
112
docs/proof-of-reserves-bip-322.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
# BIP-322 Generic Signed Message Format
|
||||||
|
|
||||||
|
BIP-322 specification: <https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki>
|
||||||
|
|
||||||
|
## Proof of Reserves (POR)
|
||||||
|
|
||||||
|
### PoR PSBT
|
||||||
|
|
||||||
|
COLDCARD accepts a specially crafted PSBT file to sign as BIP-322 Proof of Reserves. The PSBT
|
||||||
|
must meet all these requirements:
|
||||||
|
|
||||||
|
* COLDCARD acts as a BIP-322 PSBT signer. It validates the BIP-322 `to_sign`
|
||||||
|
transaction, shows the message from `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE`, and
|
||||||
|
adds signatures to the PSBT. Finalizing and encoding the final BIP-322
|
||||||
|
signature string is the responsibility of the finalizer.
|
||||||
|
* PSBT MUST include `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE = 0x09`; the value is
|
||||||
|
the exact message shown to the user and signed by BIP-322.
|
||||||
|
* PSBT requires `PSBT_IN_BIP32_DERIVATION` for each input
|
||||||
|
* P2SH wrapped segwit addresses MUST have proper redeem script in PSBT: `PSBT_IN_REDEEM_SCRIPT`
|
||||||
|
* P2WSH segwit addresses MUST have proper witness script in PSBT: `PSBT_IN_WITNESS_SCRIPT`
|
||||||
|
* PSBT (`to_sign`) MUST have at least one input.
|
||||||
|
* First (0th) input of `to_sign` MUST spend the BIP-322 `to_spend` output.
|
||||||
|
* Input 0 MUST include one of `PSBT_IN_NON_WITNESS_UTXO` or `PSBT_IN_WITNESS_UTXO`.
|
||||||
|
* When input 0 provides `PSBT_IN_WITNESS_UTXO`, COLDCARD reconstructs the
|
||||||
|
expected `to_spend` txid from `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE` and the
|
||||||
|
witness UTXO scriptPubKey.
|
||||||
|
* When input 0 provides `PSBT_IN_NON_WITNESS_UTXO`, it MUST be the BIP-322
|
||||||
|
`to_spend` transaction as defined in
|
||||||
|
[BIP-322](https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki#full):
|
||||||
|
* 1 input, 1 output
|
||||||
|
* output nValue is 0
|
||||||
|
* input prevout hash is 0
|
||||||
|
* input prevout n is 0xffffffff
|
||||||
|
* input scriptSig is `OP_0 PUSH32 message_hash`
|
||||||
|
* PSBT (`to_sign`) MUST only have one output with null-data `OP_RETURN`
|
||||||
|
* `to_sign` transaction version MUST be 0 or 2.
|
||||||
|
* Optionally inputs can be added to `to_sign` for Proof of Reserve signing.
|
||||||
|
* PSBT MUST be version 0 or 2.
|
||||||
|
* Foreign inputs not allowed in POR PSBT.
|
||||||
|
|
||||||
|
The signatures created by the BIP-322 process will never be suitable
|
||||||
|
for a on-chain Bitcoin transaction that could move funds, because
|
||||||
|
of these restrictions imposed by BIP-322.
|
||||||
|
|
||||||
|
### Output
|
||||||
|
|
||||||
|
COLDCARD always returns a signed PSBT for BIP-322 message signing and Proof of
|
||||||
|
Reserves. It never returns an extracted/finalized transaction for these PSBTs.
|
||||||
|
This is true even when finalization is requested over USB, such as with
|
||||||
|
`ckcc unsigned.psbt --finalize`.
|
||||||
|
|
||||||
|
The signed PSBT is the handoff artifact for the external finalizer/verifier. It
|
||||||
|
keeps the PSBT metadata needed to verify or finalize the BIP-322 signature,
|
||||||
|
including public keys, scripts, partial signatures, and UTXO data. This matters
|
||||||
|
because the address being proven normally commits only to a hash of the public
|
||||||
|
key or script, not the public key or script itself.
|
||||||
|
|
||||||
|
### Proof of Reserves Signing Experience
|
||||||
|
|
||||||
|
After Coldcard recognizes a BIP-322 PSBT it reads the message from
|
||||||
|
`PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE` and shows it to the user for approval.
|
||||||
|
COLDCARD verifies that the message hash matches the input 0 `to_spend`
|
||||||
|
commitment before offering to sign.
|
||||||
|
|
||||||
|
When the PSBT contains only input 0, COLDCARD labels the request as
|
||||||
|
`BIP-322 Message`, because it is message signing and does not prove ownership
|
||||||
|
of any additional reserve UTXOs. In that case it does not show transaction
|
||||||
|
input/output counts. When the PSBT contains additional inputs, COLDCARD labels
|
||||||
|
the request as `Proof of Reserves` and shows the reserve amount.
|
||||||
|
|
||||||
|
If the message contains non-ASCII characters, COLDCARD warns that some
|
||||||
|
characters may not be readable on screen.
|
||||||
|
|
||||||
|
Legacy PoR PSBTs without `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE` are rejected by
|
||||||
|
this flow.
|
||||||
|
|
||||||
|
Read more [here.](https://gist.github.com/orangesurf/0c1d0a31d3ebe7e48335a34d56788d4c)
|
||||||
|
|
||||||
|
Example screen text for a one-input BIP-322 message signing PSBT:
|
||||||
|
|
||||||
|
```text
|
||||||
|
BIP-322 Message
|
||||||
|
|
||||||
|
Message:
|
||||||
|
This is the signed message
|
||||||
|
|
||||||
|
Challenge Address:
|
||||||
|
bc1qzvjnhf7k70uxv6xvneaqxql7k09dd6nsr5wheq
|
||||||
|
|
||||||
|
Press ENTER to approve and sign message. Press (2) to explore transaction.
|
||||||
|
CANCEL to abort.
|
||||||
|
```
|
||||||
|
|
||||||
|
Example screen text for a Proof of Reserves PSBT:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Proof of Reserves
|
||||||
|
|
||||||
|
Message:
|
||||||
|
POR
|
||||||
|
|
||||||
|
Amount 0.20000000 BTC
|
||||||
|
|
||||||
|
Challenge Address:
|
||||||
|
bc1qzvjnhf7k70uxv6xvneaqxql7k09dd6nsr5wheq
|
||||||
|
|
||||||
|
21 inputs
|
||||||
|
1 output
|
||||||
|
|
||||||
|
Press ENTER to approve and sign proof of reserves. Press (2) to explore transaction.
|
||||||
|
CANCEL to abort.
|
||||||
|
```
|
||||||
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
The Mk4 **COLDCARD<sup>®</sup>** has two secure elements:
|
The **COLDCARD<sup>®</sup>** Mk4 and Q have two secure elements:
|
||||||
|
|
||||||
- SE1 (Secure Element 1): Microchip ATECC608B
|
- SE1 (Secure Element 1): Microchip ATECC608
|
||||||
- SE2 (Secure Element 2): Maxim DS28C36B
|
- SE2 (Secure Element 2): Maxim DS28C36B
|
||||||
|
|
||||||
Because different vendors make them, they do not share bugs and weaknesses.
|
Because different vendors make them, they do not share bugs and weaknesses.
|
||||||
@ -20,15 +20,13 @@ HMAC-SHA256.
|
|||||||
|
|
||||||
Assume attackers have physical access to a COLDCARD, have opened
|
Assume attackers have physical access to a COLDCARD, have opened
|
||||||
the case, and can probe the bus connections between the MCU and SE1
|
the case, and can probe the bus connections between the MCU and SE1
|
||||||
or SE2. They may even desolder SE1 and SE2 from the board, and put
|
or SE2. They may even de-solder SE1 and SE2 from the board, and put
|
||||||
active circuits between them and the MCU — an active MiTM
|
active circuits between them and the MCU — an active MiTM attack.
|
||||||
attack. (The Mk4 has improved goop on all three parts and all these
|
|
||||||
critical signals run on internal layers of the PCBA.)
|
|
||||||
|
|
||||||
|
|
||||||
### The Solutions
|
### The Solutions
|
||||||
|
|
||||||
Three parties hold secrets in the Mk4: the main MCU (microcontroller)
|
Three parties hold secrets in the COLDCARD: the main MCU (microcontroller)
|
||||||
and the two secure elements. Our goal is that **all three** must
|
and the two secure elements. Our goal is that **all three** must
|
||||||
be fully compromised to access the seed words. Thus, if one part
|
be fully compromised to access the seed words. Thus, if one part
|
||||||
has a vulnerability, the COLDCARD as a whole is still secure.
|
has a vulnerability, the COLDCARD as a whole is still secure.
|
||||||
@ -37,7 +35,7 @@ if all three devices are cracked wide open. (This is a last line
|
|||||||
of defence, a brute-force attack on all PIN combinations will breach
|
of defence, a brute-force attack on all PIN combinations will breach
|
||||||
it.)
|
it.)
|
||||||
|
|
||||||
The Mk4 also supports new Trick PIN codes with side effects such
|
COLDCARD also supports new Trick PIN codes with side effects such
|
||||||
as wiping or bricking the COLDCARD, or providing access to a decoy
|
as wiping or bricking the COLDCARD, or providing access to a decoy
|
||||||
or duress wallet. Ideally, attackers will not detect using a false
|
or duress wallet. Ideally, attackers will not detect using a false
|
||||||
PIN, even while probing the signals on the board.
|
PIN, even while probing the signals on the board.
|
||||||
@ -53,7 +51,7 @@ and the MicroPython code cannot read this area of the chip. Using
|
|||||||
an internal firewall feature and PCROP (proprietary code readout
|
an internal firewall feature and PCROP (proprietary code readout
|
||||||
protection) achieves this result.
|
protection) achieves this result.
|
||||||
|
|
||||||
Mk4 also shares a secret between SE2 and the MCU. Just like SE1,
|
COLDCARD also shares a secret between SE2 and the MCU. Just like SE1,
|
||||||
this authenticates SE2 to the MCU and encrypts their mutual
|
this authenticates SE2 to the MCU and encrypts their mutual
|
||||||
communications. The Pairing Secret for SE2 is not stored in SE1 and
|
communications. The Pairing Secret for SE2 is not stored in SE1 and
|
||||||
is unique from the other Pairing Secret used for SE1.
|
is unique from the other Pairing Secret used for SE1.
|
||||||
@ -94,8 +92,8 @@ increases flexibility and resistance to known plain text attacks.
|
|||||||
| `pin stretch` | slot 2 | HMAC | SE1 | Key stretching for PIN entry and anti-phish words
|
| `pin stretch` | slot 2 | HMAC | SE1 | Key stretching for PIN entry and anti-phish words
|
||||||
| `firmware` | slot 14 | SHA256d | SE1 | Firmware checksum, controls green/red LEDs
|
| `firmware` | slot 14 | SHA256d | SE1 | Firmware checksum, controls green/red LEDs
|
||||||
| `nonce/chksum` | slot 10 | data | SE1 | AES nonce and GMAC tag, protected by PIN
|
| `nonce/chksum` | slot 10 | data | SE1 | AES nonce and GMAC tag, protected by PIN
|
||||||
| `SE2 easy key` | page 15 | AES via HMAC | SE2 | Another SE2 part of AES seed key
|
| `SE2 easy key` | page 14 | AES via HMAC | SE2 | Another SE2 part of AES seed key
|
||||||
| `SE2 hard key` | page 14 | AES via ECC | SE2 | SE2's part of AES seed key; ECC used to unlock
|
| `SE2 hard key` | page 15 | AES via ECC | SE2 | SE2's part of AES seed key; ECC used to unlock
|
||||||
| `tpin key` | `tpin_key` | HMAC(key) | MCU | Key for HMAC used to encrypt trick PINs
|
| `tpin key` | `tpin_key` | HMAC(key) | MCU | Key for HMAC used to encrypt trick PINs
|
||||||
| `trick PIN slots` | pages 0-12 | HMAC | SE2 | Protect duress wallet seeds and pins (6 spots)
|
| `trick PIN slots` | pages 0-12 | HMAC | SE2 | Protect duress wallet seeds and pins (6 spots)
|
||||||
| `SE2 trash` | secret B | HMAC | SE2 | Used to destroy values (only SE2 knows the value)
|
| `SE2 trash` | secret B | HMAC | SE2 | Used to destroy values (only SE2 knows the value)
|
||||||
@ -195,7 +193,7 @@ user enters against all the slots and works silently to support the
|
|||||||
Trick features.
|
Trick features.
|
||||||
|
|
||||||
The type of support depends on the type of Trick. Duress wallets
|
The type of support depends on the type of Trick. Duress wallets
|
||||||
require storing 32 bytes of seed words (generated from the true
|
require storing 32 or 64 bytes of seed words (generated from the true
|
||||||
seed via BIP-85). Other cases dictate encoding a short numeric code
|
seed via BIP-85). Other cases dictate encoding a short numeric code
|
||||||
provided to higher layers for implementation. For example, a flag
|
provided to higher layers for implementation. For example, a flag
|
||||||
in that code can trigger the boot ROM to wipe the `mcu seed key`.
|
in that code can trigger the boot ROM to wipe the `mcu seed key`.
|
||||||
@ -206,7 +204,8 @@ key` being zero makes the seed permanently inaccessible.
|
|||||||
|
|
||||||
The MCU code may continue speaking to SE1 to complete the fraud,
|
The MCU code may continue speaking to SE1 to complete the fraud,
|
||||||
but in general, SE1 will no longer store the duress wallet or Brick
|
but in general, SE1 will no longer store the duress wallet or Brick
|
||||||
Me PINs. Mk4 implements those feature in SE2.
|
Me PINs as in previous generations (Mk1-3). Mk4 and Q implement
|
||||||
|
those feature in SE2.
|
||||||
|
|
||||||
|
|
||||||
### Trick PIN Operation
|
### Trick PIN Operation
|
||||||
@ -268,7 +267,7 @@ inside SE1. This storage is called Spare Secrets. Spare Secrets has
|
|||||||
3 × 72 bytes of space, protected by the same measures as the
|
3 × 72 bytes of space, protected by the same measures as the
|
||||||
seed words.
|
seed words.
|
||||||
|
|
||||||
Mk4 still supports the Long Secret (416 bytes), but its API is
|
Mk4/Q still supports the Long Secret (416 bytes), but its API is
|
||||||
changed. The slow speed of fetching the Long Secret in 32-byte
|
changed. The slow speed of fetching the Long Secret in 32-byte
|
||||||
blocks due to the reconstructing the primary AES Seed Key for each
|
blocks due to the reconstructing the primary AES Seed Key for each
|
||||||
call necessitated the change.
|
call necessitated the change.
|
||||||
@ -292,7 +291,7 @@ PINs that continue operation (duress PINs), unlike the average thug.
|
|||||||
|
|
||||||
## Fast Brick
|
## Fast Brick
|
||||||
|
|
||||||
On the Mk4, quickly bricking the system is done by rotating the SE1
|
Quickly bricking the system is done by rotating the SE1
|
||||||
pairing secret by mixing in a random nonce via the chip's key
|
pairing secret by mixing in a random nonce via the chip's key
|
||||||
rotation process. Only a knowledge of the old pairing secret is
|
rotation process. Only a knowledge of the old pairing secret is
|
||||||
needed for this change. This is similar the to `brick_me` PIN
|
needed for this change. This is similar the to `brick_me` PIN
|
||||||
@ -1,4 +1,4 @@
|
|||||||
# COLDCARD Mk4 Security Model
|
# COLDCARD Mk4/Mk5/Q Security Model
|
||||||
|
|
||||||
## Abstract
|
## Abstract
|
||||||
|
|
||||||
@ -8,11 +8,14 @@ seed words used to generate a deterministic wallet. This secure
|
|||||||
element is in a limited and read-only state until authorized by PIN entry.
|
element is in a limited and read-only state until authorized by PIN entry.
|
||||||
|
|
||||||
Clearing the secure element is impossible without first entering
|
Clearing the secure element is impossible without first entering
|
||||||
the correct PIN. The Mark 4 COLDCARD (Mk4) introduces several new
|
the correct PIN. The Mk4 COLDCARD introduced several new security
|
||||||
security features, including a second secure element and Trick PINs
|
features, including a second secure element and Trick PINs which
|
||||||
which can render stored data unrecoverable, or brick the COLDCARD
|
can render stored data unrecoverable, or brick the COLDCARD entirely
|
||||||
entirely if necessary, without entering the true authorization PIN
|
if necessary, without entering the true authorization PIN (True
|
||||||
(True PIN).
|
PIN).
|
||||||
|
|
||||||
|
The COLDCARD Q continues with the same security model introduced
|
||||||
|
in Mk4.
|
||||||
|
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
@ -22,7 +25,7 @@ the Microchip ATECC508A and later the ATECC608B, to store its
|
|||||||
secrets. This secure element has 72 bytes of storage protected by
|
secrets. This secure element has 72 bytes of storage protected by
|
||||||
a 4- to 12-digit PIN code.
|
a 4- to 12-digit PIN code.
|
||||||
|
|
||||||
Mk4 adds a second secure element to the COLDCARD. The ATECC608B is
|
Mk4 adds a second secure element to the COLDCARD. The ATECC608 is
|
||||||
still used, now called SE1 (Secure Element 1), along with a new
|
still used, now called SE1 (Secure Element 1), along with a new
|
||||||
chip, the Maxim DS28C36B, called SE2 (Secure Element 2). The
|
chip, the Maxim DS28C36B, called SE2 (Secure Element 2). The
|
||||||
DS28C36B (SE2) has more memory with fifteen 32-byte slots of secure
|
DS28C36B (SE2) has more memory with fifteen 32-byte slots of secure
|
||||||
@ -93,9 +96,10 @@ user entered the True PIN. An attacker will only have access to the
|
|||||||
duress wallet. They won't have access to steal the main stash.
|
duress wallet. They won't have access to steal the main stash.
|
||||||
|
|
||||||
The private key can be automatically derived using BIP-85 methods,
|
The private key can be automatically derived using BIP-85 methods,
|
||||||
based on account numbers 1001, 1002, or 1003. Because this is BIP-85
|
based on account numbers 1001, 1002, or 1003 for a 24-word duress wallet
|
||||||
based and uses a 24-word seed, it behaves exactly like a normal
|
(or 2001, 2002, 2003 for a 12-word one). Because this is BIP-85
|
||||||
wallet. Defining a passphrase for the wallet is also possible.
|
based, it behaves exactly like a normal wallet. Defining a passphrase
|
||||||
|
for the wallet is also possible.
|
||||||
|
|
||||||
The Mk4 also supports older COLDCARD duress wallets and their UTXOs
|
The Mk4 also supports older COLDCARD duress wallets and their UTXOs
|
||||||
on the blockchain. There is an option to create compatible wallets
|
on the blockchain. There is an option to create compatible wallets
|
||||||
@ -187,9 +191,9 @@ customers suggested.
|
|||||||
|
|
||||||
### Kill Key Feature
|
### Kill Key Feature
|
||||||
|
|
||||||
This feature allows the user to execute a Fast Wipe when the
|
On the Mk4, this feature allows the user to execute a Fast Wipe
|
||||||
anti-phishing words are displayed on the screen. This feature is
|
when the anti-phishing words are displayed on the screen. This
|
||||||
turned off by default.
|
feature is turned off by default.
|
||||||
|
|
||||||
The user sets a particular key number to trigger Fast Wipe. If that
|
The user sets a particular key number to trigger Fast Wipe. If that
|
||||||
key is pressed while viewing the anti-phishing words, the seed is
|
key is pressed while viewing the anti-phishing words, the seed is
|
||||||
@ -200,13 +204,19 @@ It is strongly recommended that the first digit for the second half
|
|||||||
of the True PIN is **not** used as the Kill Key. Missing a step
|
of the True PIN is **not** used as the Kill Key. Missing a step
|
||||||
would unintentionally wipe the seed.
|
would unintentionally wipe the seed.
|
||||||
|
|
||||||
|
For the COLDCARD Q, the same feature exists: any letter may be
|
||||||
|
specified but numbers are not supported. This change allows the
|
||||||
|
"kill button" to be active through-out the entire login process.
|
||||||
|
It can be even be pressed while the nickname is shown, and at any
|
||||||
|
point during the PIN entry.
|
||||||
|
|
||||||
|
|
||||||
### SPI Serial Flash Removed
|
### SPI Serial Flash Removed
|
||||||
|
|
||||||
The Mk3 and earlier had a dedicated, external chip to hold settings
|
The Mk3 and earlier had a dedicated, external chip to hold settings
|
||||||
and the PSBT during operation. Mk4 does not have that chip. The
|
and the PSBT during operation. Mk4 and later, do not have that
|
||||||
settings now reside inside the main MCU, increasing security.
|
chip. The settings now reside inside the main MCU, increasing
|
||||||
Settings are still AES-encrypted as before.
|
security. Settings are still AES-encrypted as before.
|
||||||
|
|
||||||
The separate settings chip could be blanked externally or even
|
The separate settings chip could be blanked externally or even
|
||||||
removed/replaced. This possibility might enable getting around
|
removed/replaced. This possibility might enable getting around
|
||||||
@ -234,11 +244,11 @@ COLDCARD's case to do so, but the option is there if needed.
|
|||||||
|
|
||||||
## SD Card Recovery Mode
|
## SD Card Recovery Mode
|
||||||
|
|
||||||
Mk4 bootloader is smart enough to be able to read an SD card. You
|
Mk4/Mk5/Q bootloader is smart enough to be able to read an SD card. You
|
||||||
will only be able to trigger the SD card loading code, if the
|
will only be able to trigger the SD card loading code, if the
|
||||||
COLDCARD was powered down during the upgrade process. At that point,
|
COLDCARD was powered down during the upgrade process. At that point,
|
||||||
the intended firmware image has been lost because it it held in
|
the intended firmware image has been lost because it it held in
|
||||||
PSRAM only during the flash writing process. The bootloader knows
|
PSRAM only, during the flash writing process. The bootloader knows
|
||||||
main flash (ie. Micropython code) is corrupt because it fails the
|
main flash (ie. Micropython code) is corrupt because it fails the
|
||||||
checksum check (and/or signature check).
|
checksum check (and/or signature check).
|
||||||
|
|
||||||
@ -256,6 +266,9 @@ If any other parts of flash---beyond the normal upgradable firmware
|
|||||||
area---have also been corrupted, this process will not work and the
|
area---have also been corrupted, this process will not work and the
|
||||||
unit will be a brick.
|
unit will be a brick.
|
||||||
|
|
||||||
|
On the COLDCARD Q, only the top slot (A) is supported for this
|
||||||
|
operation.
|
||||||
|
|
||||||
|
|
||||||
## Flash ECC (Error Detection/Correction Codes)
|
## Flash ECC (Error Detection/Correction Codes)
|
||||||
|
|
||||||
@ -274,7 +287,7 @@ that it's an attack, such as exposing the bare die to targeted UV-C
|
|||||||
radiation. If the attacker is able to flip 2 or more bits, then
|
radiation. If the attacker is able to flip 2 or more bits, then
|
||||||
this will effectively brick the COLDCARD once the ECC error is detected.
|
this will effectively brick the COLDCARD once the ECC error is detected.
|
||||||
|
|
||||||
Critical flash cells, such as those that prevent both JTAG access,
|
Critical flash cells, such as those that prevent JTAG access, are
|
||||||
are not a single bit (it's a special bit pattern), and regardless
|
not a single bit (it's a special bit pattern), and regardless are
|
||||||
are protected via ECC the same as other flash cells.
|
protected via ECC the same as other flash cells.
|
||||||
|
|
||||||
@ -12,31 +12,32 @@ are not discrete and you could be compelled to produce the passphrase.
|
|||||||
|
|
||||||
Enter [_Seed XOR_](https://seedxor.com), a plausibly deniable means
|
Enter [_Seed XOR_](https://seedxor.com), a plausibly deniable means
|
||||||
of storing secrets in two or more parts that look and behave just
|
of storing secrets in two or more parts that look and behave just
|
||||||
like the original secret. One 24-word seed phrase becomes two or more parts
|
like the original secret. One 12-, 18-, or 24-word seed phrase becomes two or more parts
|
||||||
that are also BIP-39 compatible seeds phrases. These should be backed up in your
|
that are also BIP-39 compatible seeds phrases. These should be backed up in your
|
||||||
preferred method, metal or otherwise. These parts can be individually loaded
|
preferred method, metal or otherwise. These parts can be individually loaded
|
||||||
with honeypot funds as each one is 24 words, with the 24th being
|
with honeypot funds as each one has same word length, with the last being
|
||||||
the checksum and will work as such in any normal BIP-39 compatible wallet.
|
the checksum and will work as such in any normal BIP-39 compatible wallet.
|
||||||
|
|
||||||
This one more solution for your game-theory arsenal.
|
This one more solution for your game-theory arsenal.
|
||||||
|
|
||||||
- *Q*: I'm lazy, can I do this to my Existing Seed?
|
- *Q*: I'm lazy, can I do this to my Existing Seed?
|
||||||
- *A*: Yes. You can split the words you have already in your Coldcard, making
|
- *A*: Yes. You can split the words you have already in your Coldcard, making
|
||||||
2, 3 or 4 new SEEDPLATES. You could also any number of existing SEEDPLATES
|
2, 3 or 4 new SEEDPLATES. You could also use any number of existing SEEDPLATES
|
||||||
you have, and combine them to make a new random wallet that is the XOR of
|
you have, and combine them to make a new random wallet that is the XOR of
|
||||||
their values. Effectively that makes a new random wallet.
|
their values. Effectively that makes a new random wallet.
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
[_Seed XOR_](https://seedxor.com) works by taking any number of 24-word
|
[_Seed XOR_](https://seedxor.com) works by taking any number of
|
||||||
seed phrases in BIP-39 style, and simply XOR-ing them together,
|
seed phrases in BIP-39 style, and simply XOR-ing them together,
|
||||||
bit-by-bit into a new phrase.
|
bit-by-bit into a new phrase. All seed phrases have to be of the same length.
|
||||||
|
|
||||||
The last word (in 24-word case, which is the only width we support) has
|
The last word contains checksum.
|
||||||
8 bits of checksum. For the "parts" (sometimes called "shares") this checksum
|
For the "parts" (sometimes called "shares") this checksum
|
||||||
is calculated as normal for BIP-39, but those final 8-bits are not used in
|
is calculated as normal for BIP-39, but those final bits are not used in
|
||||||
the XOR process. But the checksums still protects the integrity of the
|
the XOR process. But the checksums still protects the integrity of the
|
||||||
individual parts.
|
individual parts. In 24-words XOR last 8 bits are checksum and in 12-words
|
||||||
|
XOR last 4 bits are checksum.
|
||||||
|
|
||||||
Useful properties of this approach:
|
Useful properties of this approach:
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ Useful properties of this approach:
|
|||||||
- You can store funds on the seeds of any part, and any subset of parts, which
|
- You can store funds on the seeds of any part, and any subset of parts, which
|
||||||
opens even more duress options.
|
opens even more duress options.
|
||||||
|
|
||||||
We recommend storing the checksum word (24-th) of the original
|
We recommend storing the checksum word of the original
|
||||||
wallet along with your N parts. This allows you to be sure you've
|
wallet along with your N parts. This allows you to be sure you've
|
||||||
gotten all the parts and assembled them correctly. This does reveal
|
gotten all the parts and assembled them correctly. This does reveal
|
||||||
3 bits of your real wallet however, and also reveals that a
|
3 bits of your real wallet however, and also reveals that a
|
||||||
@ -72,15 +73,17 @@ Advanced > Danger Zone > Seed Functions > Seed XOR > Split Existing
|
|||||||
You can choose between 2, 3 or 4 parts. You can also choose (next
|
You can choose between 2, 3 or 4 parts. You can also choose (next
|
||||||
screen) to generate them deterministically or using the TRNG. The
|
screen) to generate them deterministically or using the TRNG. The
|
||||||
advantage of the deterministic approach is you'll always get the
|
advantage of the deterministic approach is you'll always get the
|
||||||
same answers, so you can check that you've recorded the correct
|
same answers, so you can check that you've recorded the correct
|
||||||
48 to 96 words right the next day.
|
words right the next day.
|
||||||
|
|
||||||
When the parts are made deterministically, we take a double-SHA256 over
|
When the parts are made deterministically, we take a double-SHA256 over
|
||||||
a fixed string (`Batshitoshi`), your master secret, and the text
|
a fixed string (`Batshitoshi`), your master secret, and the text
|
||||||
`1 of 4 parts` which changes for each part.
|
`0 of 4 parts` which changes for each part (the index is 0-based).
|
||||||
|
|
||||||
In random mode, we simply pick 32 random bytes (and then double-SHA256
|
In random mode, we simply pick random bytes (and then double-SHA256
|
||||||
them) from the Coldcard's True Random Number Generator (TRNG)..
|
them) from the Coldcard's True Random Number Generator (TRNG). The number
|
||||||
|
of bytes matches your secret length: 16, 24, or 32 bytes for a 12-, 18-,
|
||||||
|
or 24-word seed respectively.
|
||||||
|
|
||||||
This is done to make all but the one part. The final part is the
|
This is done to make all but the one part. The final part is the
|
||||||
value needed to get back to your secret, so it's the XOR of the
|
value needed to get back to your secret, so it's the XOR of the
|
||||||
@ -109,7 +112,7 @@ of all the parts.
|
|||||||
|
|
||||||
- You can pick your XOR parts randomly, and the result when XOR'ed
|
- You can pick your XOR parts randomly, and the result when XOR'ed
|
||||||
together, is a random wallet. However, it would be best to get the
|
together, is a random wallet. However, it would be best to get the
|
||||||
24-th word checksum recorded correctly, so please use a tool such
|
last word checksum recorded correctly, so please use a tool such
|
||||||
as the Coldcard to lookup the 24th word and save that (for each
|
as the Coldcard to lookup the 24th word and save that (for each
|
||||||
part). For example, you might take a fresh Coldcard (no secret)
|
part). For example, you might take a fresh Coldcard (no secret)
|
||||||
and draw 23 words from a hat. After providing the 23rd word, the
|
and draw 23 words from a hat. After providing the 23rd word, the
|
||||||
@ -156,9 +159,15 @@ with the others on a SEEDPLATE.
|
|||||||
- right to A, down to B ... take that number, and go to that column
|
- right to A, down to B ... take that number, and go to that column
|
||||||
- down to C, that is answer: a ⊕ b ⊕ c
|
- down to C, that is answer: a ⊕ b ⊕ c
|
||||||
|
|
||||||
|
## Open Standard
|
||||||
|
Seed XOR is an open standard. Other software and hardware wallets are encouraged to
|
||||||
|
implement support. No license or permission is required, including usage of the term
|
||||||
|
"Seed XOR" when referring to implementations of this feature. Such implementations
|
||||||
|
should match the process described in this documentation and be fully interoperable.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# XOR Seed Example Using 3 Parts
|
# 24 Words XOR Seed Example Using 3 Parts
|
||||||
|
|
||||||
## Seed A (1 of 3)
|
## Seed A (1 of 3)
|
||||||
|
|
||||||
@ -209,10 +218,56 @@ with the others on a SEEDPLATE.
|
|||||||
final word between: gas [300] - lend [3FF]
|
final word between: gas [300] - lend [3FF]
|
||||||
correct final word: indoor [398]
|
correct final word: indoor [398]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 12 Words XOR Seed Example Using 3 Parts
|
||||||
|
|
||||||
|
## Seed A (1 of 3)
|
||||||
|
|
||||||
|
1=romance [5DC], 2=wink [7DE], 3=lottery [420], 4=autumn [07D], 5=shop [635], 6=bring [0E1],
|
||||||
|
7=dawn [1BF], 8=tongue [723], 9=range [58E], 10=crater [194], 11=truth [74E], 12=ability [001]
|
||||||
|
|
||||||
|
A = 5DC 7DE 420 07D 635 0E1 1BF 723 58E 194 74E 001
|
||||||
|
|
||||||
|
|
||||||
|
## Seed B (2 of 3)
|
||||||
|
|
||||||
|
1=boat [0C6], 2=unfair [768], 3=shell [62B], 4=violin [7A2], 5=tree [73F], 6=robust [5DA], 7=open [4D9],
|
||||||
|
8=ride [5CB], 9=visual [7A7], 10=forest [2D9], 11=vintage [7A1], 12=approve [056]
|
||||||
|
|
||||||
|
B = 0C6 768 62B 7A2 73F 5DA 4D9 5CB 7A7 2D9 7A1 056
|
||||||
|
|
||||||
|
|
||||||
|
## Seed C (3 of 3)
|
||||||
|
|
||||||
|
1=lion [411], 2=misery [46D], 3=divide [1FF], 4=hurry [37D], 5=latin [3EB], 6=fluid [2CD], 7=camp [106],
|
||||||
|
8=advance [01F], 9=illegal [388], 10=lab [3E0], 11=pyramid [578], 12=unhappy [76A]
|
||||||
|
|
||||||
|
C = 411 46D 1FF 37D 3EB 2CD 106 01F 388 3E0 578 76A
|
||||||
|
|
||||||
|
|
||||||
|
## Calculation (XOR each hex digit)
|
||||||
|
|
||||||
|
A = 5DC 7DE 420 07D 635 0E1 1BF 723 58E 194 74E 001
|
||||||
|
B = 0C6 768 62B 7A2 73F 5DA 4D9 5CB 7A7 2D9 7A1 056
|
||||||
|
C = 411 46D 1FF 37D 3EB 2CD 106 01F 388 3E0 578 76A
|
||||||
|
| | |
|
||||||
|
XOR = 10B 4DB 3F4 4A2 2E1 7F6 460 2F7 1A1 0AD 597 73x
|
||||||
|
|
||||||
|
|
||||||
|
## Resulting Seed Phrase
|
||||||
|
|
||||||
|
1=cannon [10B], 2=opinion [4DB], 3=leader [3F4], 4=nephew [4A2], 5=found [2E1], 6=yard [7F6],
|
||||||
|
7=metal [460], 8=galaxy [2F7], 9=crouch [1A1], 10=between [0AD], 11=real [597]
|
||||||
|
|
||||||
|
final word between: toward [730] - tree [73F]
|
||||||
|
correct final word: trade [735]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- It's not possible to calculate the checksum of the final seed phrase on paper (needs SHA256).
|
- It's not possible to calculate the checksum of the final seed phrase on paper (needs SHA256).
|
||||||
- But it must start with the indicated digit, and there will be only one
|
- But it must start with the indicated digit(s). If using 24 words XOR, there will be only one
|
||||||
suitable choice offered by the Coldcard in that range (x00 to xFF),
|
suitable choice offered by the Coldcard in that range (x00 to xFF),
|
||||||
once you have entered the other 23 words.
|
once you have entered the other 23 words.
|
||||||
- The checksum of each of the XOR-parts protects the final result, assuming your XOR
|
- The checksum of each of the XOR-parts protects the final result, assuming your XOR
|
||||||
math is correct.
|
math is correct.
|
||||||
|
|
||||||
209
docs/spending-policy.md
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
# Spending Policy
|
||||||
|
|
||||||
|
This special mode will stop you from signing transactions if they
|
||||||
|
exceed a spending policy you define beforehand. Once enabled, many
|
||||||
|
features of the COLDCARD are disabled or inaccessible.
|
||||||
|
|
||||||
|
You might want to use this feature when traveling with your COLDCARD.
|
||||||
|
|
||||||
|
## Spending Policy: Multisig (formerly CCC)
|
||||||
|
|
||||||
|
We also support a mode where the COLDCARD is a multisig co-signer
|
||||||
|
and only performs its signature when a spending policy is met. The
|
||||||
|
other multisig signers are free to sign or not sign as appropriate.
|
||||||
|
|
||||||
|
Multisig mode is more advanced and requires use of multisig addresses,
|
||||||
|
new UTXO, and cooperating multisig on-chain wallets.
|
||||||
|
|
||||||
|
This document will only discuss the "Single signer" version of
|
||||||
|
Spending Policy. Both modes can be active at the same time, but if
|
||||||
|
a transaction would be signed by Multisig policy, then we assume
|
||||||
|
it's also okay to sign your main key as well.
|
||||||
|
|
||||||
|
# Before You Start
|
||||||
|
|
||||||
|
When a Spending Policy is in effect, there are limitations
|
||||||
|
in effect:
|
||||||
|
|
||||||
|
- Firmware updates are blocked.
|
||||||
|
- There is no way to backup the COLDCARD.
|
||||||
|
- Seed vault and Secure Notes are read-only (and can also be hidden).
|
||||||
|
- Settings menu is inaccessible.
|
||||||
|
- BIP-39 passphrases may be blocked (optional).
|
||||||
|
|
||||||
|
We recommend getting the COLDCARD fully configured and setup
|
||||||
|
for typical transactions before enabling the Spending Policy.
|
||||||
|
|
||||||
|
# Setup Spending Policy
|
||||||
|
|
||||||
|
Visit `Advanced / Tools > Spending Policy` menu and choose
|
||||||
|
"Single-Signer". First some background information is shown,
|
||||||
|
then you are prompted to define the "Bypass PIN". This PIN code
|
||||||
|
is only used when you need to disable the spending policy, but is
|
||||||
|
also the only way to do so once enabled... so don't loose it.
|
||||||
|
|
||||||
|
Once the "Bypass PIN" is confirmed, you will arrive at menu for
|
||||||
|
related settings. Use "Edit Policy..." to change the spending policy
|
||||||
|
and define a Max Magnitude (limit number of BTC per transaction),
|
||||||
|
Velocity (minimum time gaps between signed transactions). You can
|
||||||
|
define a whitelist of up to 25 destination addresses (leave empty
|
||||||
|
for any). Finally you can enroll your phone in 2FA (second factor)
|
||||||
|
so that you must open an Authenticator app on your phone before
|
||||||
|
transactions are signed.
|
||||||
|
|
||||||
|
## Other Security Settings
|
||||||
|
|
||||||
|
In addition to policy itself, there are a number of on/off
|
||||||
|
switches which affect operation of the COLDCARD while the Spending
|
||||||
|
Policy is in effect:
|
||||||
|
|
||||||
|
### Word Check
|
||||||
|
|
||||||
|
If enabled, you will have to enter the first and last seed word
|
||||||
|
after the Bypass PIN as an additional security check.
|
||||||
|
|
||||||
|
### Allow Notes
|
||||||
|
|
||||||
|
On the Q, secure notes and passwords may be visible or hidden
|
||||||
|
using this setting. In either case they are strictly readonly.
|
||||||
|
|
||||||
|
### Related Keys
|
||||||
|
|
||||||
|
BIP-39 passphrase entry, Seed Vault usage will be blocked unless this
|
||||||
|
setting is enabled. Even when enabled, the Seed Vault is always readonly
|
||||||
|
and cannot be changed.
|
||||||
|
|
||||||
|
# Other Menu Items
|
||||||
|
|
||||||
|
## Last Violation
|
||||||
|
|
||||||
|
If you have recently tried and failed to sign a transaction, the
|
||||||
|
reason for the transaction being rejected can be viewed and cleared,
|
||||||
|
using menu item "Last Violation". It is shown only if a Spending
|
||||||
|
Policy violation (attempt) has occurred since the last valid signing.
|
||||||
|
|
||||||
|
This is meant as a debugging tool, and the information stored is
|
||||||
|
terse.
|
||||||
|
|
||||||
|
## Remove Policy
|
||||||
|
|
||||||
|
This will remove your spending policy completely and remove
|
||||||
|
the Bypass PIN. Your COLDCARD will be back to normal.
|
||||||
|
|
||||||
|
## Test Drive
|
||||||
|
|
||||||
|
Experiment with how the COLDCARD will function if the Spending
|
||||||
|
Policy was enabled. You can try to sign transactions that should
|
||||||
|
be rejected and view the menus in the new mode without rebooting.
|
||||||
|
|
||||||
|
Choose "EXIT TEST DRIVE" on top menu to return to the Spending
|
||||||
|
Policy menu. Reboot will also restore normal operation without
|
||||||
|
any special challenges.
|
||||||
|
|
||||||
|
## ACTIVATE
|
||||||
|
|
||||||
|
This step will enable the Spending Policy and return to the
|
||||||
|
main menu with it in effect. When you reboot the COLDCARD,
|
||||||
|
the policy will still be in effect. You must use the
|
||||||
|
Bypass PIN, followed by the normal main PIN, possibly
|
||||||
|
followed by entering the first and last words of your seed
|
||||||
|
phrase, before you can disable and change the policy.
|
||||||
|
|
||||||
|
We recommend test-driving the feature before doing that.
|
||||||
|
|
||||||
|
|
||||||
|
# Tips and Tricks
|
||||||
|
|
||||||
|
## Money Manager Mode
|
||||||
|
|
||||||
|
You could setup a Coldcard for another person, perhaps a family member,
|
||||||
|
and enable web 2FA authentication. There does not need to be any
|
||||||
|
other spending policy limits (velocity could be unlimited).
|
||||||
|
|
||||||
|
Then enroll your own phone with the required 2FA values, and
|
||||||
|
keep both that and the spending policy bypass PIN confidential.
|
||||||
|
|
||||||
|
The holder the the Coldcard will need a 2FA code from your phone
|
||||||
|
when they want to spend. They can call you for the 6-digit code
|
||||||
|
from the 2FA app on your phone. This is not hard to provide over a
|
||||||
|
voice call.
|
||||||
|
|
||||||
|
Because a spending policy is in effect, they will not be able to
|
||||||
|
see the seed words, other private key material, so regardless of
|
||||||
|
any spoofing or phishing, they cannot move funds without your help.
|
||||||
|
|
||||||
|
You should record the bypass PIN, so it can be revealed somehow,
|
||||||
|
should you die. You do not need to share the risks associated with
|
||||||
|
holding a copy of the seed words.
|
||||||
|
|
||||||
|
## Passphrase Considerations
|
||||||
|
|
||||||
|
If you are using the same BIP-39 passphrase for everything, you should
|
||||||
|
probably do a "Lock Down Seed" (Advanced/Tools > Danger Zone > Seed
|
||||||
|
Functions) first. This takes your master seed and BIP-39 passphrase
|
||||||
|
and cooks them together into an XPRV which then is stored as your
|
||||||
|
master secret. (Replacing the master seed phrase.) This process
|
||||||
|
cannot be reversed, so other funds you may have on the same seed
|
||||||
|
words are protected. Once you are operating in XPRV mode, you can
|
||||||
|
define a spending policy, and know that it is restricted to only
|
||||||
|
that wallet.
|
||||||
|
|
||||||
|
When operating in XPRV mode, the "Passphrase" menu item is not shown
|
||||||
|
because BIP-39 passwords cannot be applied to XPRV secrets.
|
||||||
|
|
||||||
|
## Trick PIN Thoughts
|
||||||
|
|
||||||
|
When doing your game theory w.r.t to bypass mode and this feature,
|
||||||
|
remember that you should assume the attacker already has your main
|
||||||
|
PIN. That's how they know they cannot spend all your coin, because
|
||||||
|
they either tried to, or noticed the menus are very limited. They also
|
||||||
|
have all your UTXO locations and total wallet balance (because they
|
||||||
|
can export your xpubs to any wallet and load balance from there).
|
||||||
|
|
||||||
|
Therefore, a trick pin that leads to a duress wallet after giving up
|
||||||
|
the bypass unlock PIN, will not fool them. Best would be to provide
|
||||||
|
a false bypass PIN that is in fact a brick/wipe PIN.
|
||||||
|
|
||||||
|
|
||||||
|
## Lock Out Changes to Policy
|
||||||
|
|
||||||
|
In the Trick Pin menu once Spending Policy has been enabled, you will
|
||||||
|
find the Bypass PIN listed. You could delete or "hide" it. Hiding
|
||||||
|
it is pointless since you cannot get to the trick PIN menu while
|
||||||
|
the policy is in effect. Deleting the PIN however, is useful because
|
||||||
|
it assures changes to spending policy are impossible. To recover
|
||||||
|
the COLDCARD when this move is later regretted, under Advanced,
|
||||||
|
there is "Destroy Seed" option which will clear the seed words and
|
||||||
|
all settings, including the spending policy.
|
||||||
|
|
||||||
|
### Unlock Policy & Wipe
|
||||||
|
|
||||||
|
We've provided a new trick PIN that pretends to be the unlock
|
||||||
|
spending policy pin, so the login sequence is correct... but it
|
||||||
|
will wipe the seed in the process. It will be obvious to your
|
||||||
|
attackers that you've wiped the seed because the main PIN will lead
|
||||||
|
to blank wallet now (no seed loaded).
|
||||||
|
|
||||||
|
### Delta Mode and Spending Policy
|
||||||
|
|
||||||
|
If, from the start, you gave your "delta mode PIN" to the attackers,
|
||||||
|
then when they bypass the policy (after also getting the bypass PIN
|
||||||
|
from you), they will still be in Delta Mode.
|
||||||
|
|
||||||
|
They could attempt unlimited spending, but transactions signed will
|
||||||
|
not be valid. If they try to view the seed words or generally export
|
||||||
|
private key material, they will hit many of the "wipe seed if delta
|
||||||
|
mode" cases.
|
||||||
|
|
||||||
|
## Forgotten Bypass PIN Code
|
||||||
|
|
||||||
|
If you've enabled a spending policy and still remember the main PIN,
|
||||||
|
but cannot disable the feature because you've forgotten the Bypass
|
||||||
|
PIN, your only option is to use `Advanced > Destroy Seed`. After
|
||||||
|
some confirmations, this erases the master seed, all settings, seed
|
||||||
|
vault items, secure notes, and trick pins. It's basically a factory
|
||||||
|
reset except for the main PIN code which is unchanged. Once you've
|
||||||
|
done that, you can enter your seed words from backup (or restore a
|
||||||
|
backup file) and continue to use the COLDCARD again.
|
||||||
|
|
||||||
|
|
||||||
122
docs/temporary-seeds.md
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
# Temporary Seeds
|
||||||
|
|
||||||
|
|
||||||
|
[_(new in v5.0.7, requires Mk4, Mk5, or Q)_](upgrade.md)
|
||||||
|
|
||||||
|
|
||||||
|
Temporary seed (renamed in `5.2.0` from Ephemeral seed) is a temporary secret completely separate
|
||||||
|
from the master seed, typically held in **COLDCARD<sup>®</sup>** RAM and
|
||||||
|
not persisted between reboots in the Secure Element.
|
||||||
|
Temporary seeds *completely* defeat the design
|
||||||
|
of Coldcard's security model, based on secure elements.
|
||||||
|
Enable the `Seed Vault` feature to store these secrets longer-term.
|
||||||
|
Read more about `Seed Vault` feature below.
|
||||||
|
|
||||||
|
|
||||||
|
!!! warning "Make sure you know what you're doing!"
|
||||||
|
|
||||||
|
This feature is intended for those one-off signings, like recovering
|
||||||
|
a lost seed from some other system or importing some seed as a
|
||||||
|
balance check. We do not recommend handing unencrypted seed material
|
||||||
|
on a regular basis!
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* if temporary seed is already in use, first home menu option `[<xfp>]` is visible with fingerprint of temporary master secret
|
||||||
|
* go to `Advanced/Tools > Temporary Seed`
|
||||||
|
|
||||||
|
* temporary seed words can be Generated with TRNG
|
||||||
|
- `Advanced/Tools > Temporary Seed > Generate Words`
|
||||||
|
|
||||||
|
* temporary seed words can be imported
|
||||||
|
- `Advanced/Tools > Temporary Seed > Import Words`
|
||||||
|
|
||||||
|
* importing extended private keys
|
||||||
|
- `Advanced/Tools > Temporary Seed > Import XPRV`
|
||||||
|
- `Advanced/Tools > Temporary Seed > Tapsigner Backup`
|
||||||
|
|
||||||
|
* temporary seed can be activated from BIP-85 derived secrets - go to `Advanced/Tools > Derive Seed B85` and pick types of secret. Keep in mind that only word based and xprv based secrets can be used as temporary seed.
|
||||||
|
- `12 words`
|
||||||
|
- `18 words`
|
||||||
|
- `24 words`
|
||||||
|
- `XPRV (BIP-32)`
|
||||||
|
- pick derivation `Index` in next prompt, or just press OK for index 0
|
||||||
|
- Press (0) in next prompt to activate derived secret as a temporary seed
|
||||||
|
|
||||||
|
* temporary seed can be activated from Duress Wallet
|
||||||
|
- go to `Settings -> Login Settings -> Trick Pins`
|
||||||
|
- add new Duress Wallet trick pin and save it
|
||||||
|
- choose newly created trick pin in trick pins menu and use `Activate Wallet` option
|
||||||
|
|
||||||
|
* temporary seed can be obtained from `SeedXOR`
|
||||||
|
- go to `Advanced/Tools -> Danger Zone -> Seed Functions -> SeedXOR`
|
||||||
|
- pick `Restore Seed XOR` option and provide all XOR parts
|
||||||
|
- Press (2) to activate restored seed as temporary seed
|
||||||
|
|
||||||
|
* BIP-39 passphrase is from version `5.2.0` handled internally as temporary seed
|
||||||
|
|
||||||
|
|
||||||
|
Ability to generate and use **Temporary seed** is available on Coldcard when:
|
||||||
|
|
||||||
|
1. no PIN chosen and no secret chosen (newly unpacked Coldcard)
|
||||||
|
2. PIN set up but no secret chosen yet
|
||||||
|
3. with both PIN and secret already picked
|
||||||
|
|
||||||
|
|
||||||
|
# Restore Master
|
||||||
|
|
||||||
|
[_(new in v5.2.0, requires Mk4, Mk5, or Q)_](upgrade.md)
|
||||||
|
|
||||||
|
From version `5.2.0` users no longer need to reboot COLDCARD to return
|
||||||
|
to their "master seed" (one stored in SE2). Once COLDCARD has temporary
|
||||||
|
seed active, first item in home menu is `[xfp]` and is a clone of `Ready To Sign`.
|
||||||
|
Last item in home menu is `Restore Master`.
|
||||||
|
|
||||||
|
`Restore Master` offers two options. First, if user presses OK, COLDCARD wipes temporary seed settings
|
||||||
|
and switches back to master seed and its settings.
|
||||||
|
If user presses (1) temporary seed settings are preserved for later use and COLDCARD only switches
|
||||||
|
back to master seed and its settings.
|
||||||
|
|
||||||
|
If current temporary seed is also saved in Seed Vault, option to wipe settings is not available.
|
||||||
|
Seed Vault entries can only be deleted in Seed Vault menu.
|
||||||
|
|
||||||
|
|
||||||
|
# Seed Vault
|
||||||
|
|
||||||
|
[_(new in v5.2.0, requires Mk4, Mk5, or Q)_](upgrade.md)
|
||||||
|
|
||||||
|
Seed Vault adds the ability to store multiple temporary secrets into encrypted settings for simple
|
||||||
|
recall and later use (AES-256-CTR encrypted with your master seed's key).
|
||||||
|
Users can capture and hold master secret from any temporary seed source, including: TRNG, Dice Rolls,
|
||||||
|
SeedXOR, TAPSIGNER backups, BIP-85 derived values, BIP-39 passphrase wallets.
|
||||||
|
|
||||||
|
## Enable Seed Vault
|
||||||
|
|
||||||
|
Enable this functionality in `Advanced/Tools -> Danger Zone -> Seed Vault -> Enable`.
|
||||||
|
Once seed vault is enabled new menu item is visible in home menu `Seed Vault`.
|
||||||
|
To disable Seed Vault user needs to remove all entries from Seed Vault first.
|
||||||
|
|
||||||
|
|
||||||
|
## Add Seed to Vault
|
||||||
|
|
||||||
|
After `Seed Vault` is enabled, users will see a new prompt, after
|
||||||
|
creation of temporary seed, asking whether to save this temporary
|
||||||
|
seed to Seed Vault. Press (1) to save or any other key to ignore.
|
||||||
|
|
||||||
|
If option to save was chosen, confirmation prompt is shown - `Saved to seed vault.`
|
||||||
|
|
||||||
|
|
||||||
|
## Seed Vault menu
|
||||||
|
|
||||||
|
* if Seed Vault is empty `(none saved yet)` is the first menu item followed by shortcut to `Temporary Seed` menu.
|
||||||
|
* if not empty, saved seeds are listed in menu as `[xfp]`
|
||||||
|
* if current active temporary seed is stored in Seed Vault - it has checkmark next to it
|
||||||
|
* if temporary seed is active - last menu item of Seed Vault menu is `Restore Master`
|
||||||
|
|
||||||
|
## Seed Vault entry submenu
|
||||||
|
|
||||||
|
1. by default `[xfp]` but can be renamed to allow user labeling and leads to additional information about the seed
|
||||||
|
2. `Use This Seed` allows to switch to the saved temporary seed. If it is already active `In Use` is shown instead.
|
||||||
|
3. `Rename` allows to change 1. menu item to something personalized to user (limited to 40 characters)
|
||||||
|
4. `Delete` allows to remove temporary seed from Seed Vault and optionally to completely wipe its settings.
|
||||||
@ -1,11 +1,12 @@
|
|||||||
|
|
||||||
# Firmware Upgrade and Recovery Process
|
# Firmware Upgrade and Recovery Process
|
||||||
|
|
||||||
_This document applies only to the Mk4. Earlier COLDCARDs did not use this approach._
|
_This document applies to the Mk4, Mk5, and Q. Earlier COLDCARDs did not use this approach._
|
||||||
|
|
||||||
On the new Mk4 COLDCARD, we have done away with the slow external
|
On the COLDCARD, we have done away with the slow external SPI flash
|
||||||
SPI flash (serial flash) chip entirely. In it's place we use a much
|
(serial flash) chip entirely (used in Mk1-Mk3). In it's place we
|
||||||
faster and huge 64 Mbit PSRAM chip (quad SPI RAM chip: ESP-PSRAM64H).
|
use a much faster and huge 64 Mbit PSRAM chip (quad SPI RAM chip:
|
||||||
|
ESP-PSRAM64H).
|
||||||
|
|
||||||
This chip is volatile and forgets its contents at power down.
|
This chip is volatile and forgets its contents at power down.
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ can be a problem during firmware upgrades. This document explains
|
|||||||
how we've solved the risks of firmware upgrades and possible bricking
|
how we've solved the risks of firmware upgrades and possible bricking
|
||||||
that can happen with power fails at just the wrong time.
|
that can happen with power fails at just the wrong time.
|
||||||
|
|
||||||
## Firmware Upgrade Process on Mk4
|
## Firmware Upgrade Process
|
||||||
|
|
||||||
Steps:
|
Steps:
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ Steps:
|
|||||||
- a checksum is calculated over the new firmware, and the current contents of
|
- a checksum is calculated over the new firmware, and the current contents of
|
||||||
flash, including the bootloader code, its secrets, unique identity bits
|
flash, including the bootloader code, its secrets, unique identity bits
|
||||||
(for the main chip). We call this the "world checksum".
|
(for the main chip). We call this the "world checksum".
|
||||||
- before anything else happens, we update the main secure element (608B) with
|
- before anything else happens, we update the main secure element (608C) with
|
||||||
the world checksum, and during boot, knowledge of the world checksum is required
|
the world checksum, and during boot, knowledge of the world checksum is required
|
||||||
to light the green genuine light.
|
to light the green genuine light.
|
||||||
- the light stays green at this point, and the system could still boot the old firmware
|
- the light stays green at this point, and the system could still boot the old firmware
|
||||||
@ -79,7 +80,7 @@ to main flash. The PSRAM will forget it's contents, and the COLDCARD
|
|||||||
no longer has a complete copy of firmware anywhere.
|
no longer has a complete copy of firmware anywhere.
|
||||||
|
|
||||||
Most products would be a "brick" at this point, and the docs would
|
Most products would be a "brick" at this point, and the docs would
|
||||||
warn against power fails during upgrade. However, the Mk4 can read
|
warn against power fails during upgrade. However, the COLCARD can read
|
||||||
SD Cards to load replacement firmware. The card does not need to
|
SD Cards to load replacement firmware. The card does not need to
|
||||||
be specially prepared, but we recommend erasing it, formating with
|
be specially prepared, but we recommend erasing it, formating with
|
||||||
FAT32 and then copying just the firmware onto the card.
|
FAT32 and then copying just the firmware onto the card.
|
||||||
@ -91,7 +92,7 @@ Once a card is inserted, a search is made for a suitable firmware file.
|
|||||||
All DFU files will be considered, but you must provide the firmware
|
All DFU files will be considered, but you must provide the firmware
|
||||||
file that you were attempting to upgrade to during the power failure,
|
file that you were attempting to upgrade to during the power failure,
|
||||||
because the "world checksum" is calculated for each image found on
|
because the "world checksum" is calculated for each image found on
|
||||||
the card. You will not be able to substitue a newer version of firmware.
|
the card. You will not be able to substitute a newer version of firmware.
|
||||||
Of course, firmware factory signatures are checked as well.
|
Of course, firmware factory signatures are checked as well.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
97
docs/web2fa.md
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# Web 2FA Authentication
|
||||||
|
|
||||||
|
How to support [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238)
|
||||||
|
TOTP (Time based One Time Password) 2FA check, on our little embedded
|
||||||
|
device without a real-time clock?
|
||||||
|
|
||||||
|
Solution: Store the pre-shared secret in the COLDCARD, and send that
|
||||||
|
securely to a trusted webserver which knows the time and can do a
|
||||||
|
fancy UX. That webserver accepts the time-based-one-time 2FA numeric
|
||||||
|
code from the user, and if correct, reveals a secret
|
||||||
|
that can be used back on the COLDCARD to authorize an action.
|
||||||
|
|
||||||
|
For the Mk4, the secret is 8 digit numeric code to be entered,
|
||||||
|
for the COLDCARD Q, it is a QR code to be scanned.
|
||||||
|
|
||||||
|
### History / Background
|
||||||
|
|
||||||
|
The HSM feature uses HOTP tokens, which do not require a backend,
|
||||||
|
but are not as robust as time-based tokens.
|
||||||
|
|
||||||
|
Web2FA is available to be enabled as part of a Spending Policy,
|
||||||
|
both in Multisig and Single Signer modes. When enabled, you will be
|
||||||
|
prompted complete 2FA authentication after viewing the details of
|
||||||
|
the transaction to be signed. You will not be able to sign without
|
||||||
|
the correct code.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
- Web backend has a ECC keypair, with pubkey known to CC firmware releases.
|
||||||
|
- Usual 2fa base32 secret is picked by CC and stored in CC (so that server is stateless)
|
||||||
|
- CC creates URL encrypted to the pubkey of server, containing args:
|
||||||
|
- shared secret for TOTP (same value as held in user's phone)
|
||||||
|
- the response nonce (32 bytes, shown as 64 hex chars, on Q; or 8 digits on Mk4)
|
||||||
|
to be revealed to the user on successful auth
|
||||||
|
- flag if Q model, so can provide a QR to be scanned in that case (rather than digits)
|
||||||
|
- some text label for what's being approved, which is presented to user so they can pick
|
||||||
|
correct 2fa shared secret.
|
||||||
|
- above is all encrypted in transit, and only the server can decrypt
|
||||||
|
- user is sent to that encrypted URL using NFC tap on the COLDCARD
|
||||||
|
- user arrives at server:
|
||||||
|
- shown label [which also indicates the server can be trusted, since only it could decrypt it]
|
||||||
|
- prompt for 6 digits from authenticator app
|
||||||
|
- does [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) 2FA check using current time
|
||||||
|
- checks using current time and the shared secret provided by CC, fails if wrong.
|
||||||
|
- time based failure: offer retry (they typed too slow / minor clock drift)
|
||||||
|
- can offer to retry, but also do some rate limiting (only one attempt per 30-sec period)
|
||||||
|
- server will store very recent responses so attacker cannot get two codes
|
||||||
|
in any 30sec period (ie. blocks immediate reuse of same URL)
|
||||||
|
- until a valid code is given, user is stuck here
|
||||||
|
- when valid token received:
|
||||||
|
- if Q, show a QR code to be scanned, with the full nonce
|
||||||
|
- for non-Q system, a 8-digit decimal value is given: user has to enter that into the COLDCARD
|
||||||
|
- web site shows instructions about what to do next on product.
|
||||||
|
|
||||||
|
## From COLDCARD PoV
|
||||||
|
|
||||||
|
- makes complex encrypted URL, which contains a nonce it wants, waits for that nonce back (or QR)
|
||||||
|
- it's either the nonce from the URL, or fail
|
||||||
|
- if the right nonce, then we know the server knows the decryption key, and we
|
||||||
|
are trusting it actually verify the 2FA token properly.
|
||||||
|
|
||||||
|
## Encryption - Simple ECDH
|
||||||
|
|
||||||
|
- CC picks a secp256k1 keypair, generates compressed pubkey
|
||||||
|
- multiplies that private key by server's known public key
|
||||||
|
- apply sha256(resulting coordinate) => the session key
|
||||||
|
- apply AES-256-CTR over URL contents (ascii text)
|
||||||
|
- prepend 33 bytes of pubkey, and then base64url encode all of it
|
||||||
|
- full url is: `https://coldcard.com/2fa?{base64 encoded binary}`
|
||||||
|
|
||||||
|
## Trust Issues
|
||||||
|
|
||||||
|
- 2FA enrol happens on the CC, which picks the shared secret and shows QR for mobile
|
||||||
|
app setup. Same TRNG process as picking a seed.
|
||||||
|
- Server knows the shared secret, but only during operation, and we won't store it [sorry,
|
||||||
|
gotta trust us on that, but no help to us to store it].
|
||||||
|
- Only we can run the server, because the private key is company-secret.
|
||||||
|
- MiTM and network snoopers get nothing because HTTPS is used and only your browser
|
||||||
|
can see the nonce, and only after you've given the right digits.
|
||||||
|
- Coinkite server could skip the 2FA checks and just give you the answer
|
||||||
|
you want to type into the COLDCARD. Again, you have to trust us on that.
|
||||||
|
|
||||||
|
## URL Format
|
||||||
|
|
||||||
|
https://coldcard.com/2fa?g={nonce}&ss={shared_secret}&nm={label_text}&q={is_q}
|
||||||
|
|
||||||
|
(the query string is then encrypted to the server's pubkey, so the args above
|
||||||
|
are what is inside the encrypted payload.)
|
||||||
|
|
||||||
|
- `nonce`: text string that is either 8 digits on Mk4, or 64 hex chars on Q
|
||||||
|
- `shared_secret`: 16 chars of Base32-encoded pre-shared secret
|
||||||
|
- `nm`: human readable label for the transaction/purpose
|
||||||
|
- `is_q`: flag indicating use of QR to provide nonce back to user
|
||||||
|
|
||||||
|
Server will accept plaintext arguments as above, but normally everything
|
||||||
|
after the question mark is encrypted.
|
||||||
|
|
||||||
2
external/README.md
vendored
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
## Background on Submodules
|
## Background on Submodules
|
||||||
|
|
||||||
This project uses many submodules, and to build the final produts, you will
|
This project uses many submodules, and to build the final products, you will
|
||||||
have to get all the submodules into place and build them in appropriate orders.
|
have to get all the submodules into place and build them in appropriate orders.
|
||||||
|
|
||||||
A good resource, from an unrelated project, is:
|
A good resource, from an unrelated project, is:
|
||||||
|
|||||||
2
external/ckcc-protocol
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 2216e4db0e2dd17ca16bd8772d09c69f6296f6df
|
Subproject commit 3d1dfa858beb58b8dac37d8c66d7aed2909812f2
|
||||||
2
external/libngu
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 356b9137cf7ddf5de66ec4cdc0a4d757b2e42790
|
Subproject commit 537519a829259622ea6b0334fbafd6cae852852f
|
||||||
2
external/micropython
vendored
@ -1 +1 @@
|
|||||||
Subproject commit abf88c98b6ee9897b6fcc8ffea0276f07447dd48
|
Subproject commit 4107246f8a080807b62c3b4838e71e812ea68b6f
|
||||||
2
external/mpy-qr
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 3ccf19ca142e9059904f0c8e53b6baeccb9c6b79
|
Subproject commit 11347d83f4eb325b10676a4eb8e17deccfe0df44
|
||||||
@ -1,15 +1,16 @@
|
|||||||
# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
|
||||||
all: graphics.py graphics_mk4.py
|
all: graphics_mk4.py graphics_q1.py
|
||||||
|
|
||||||
SOURCES = $(filter-out mk4_%, $(wildcard *.txt) $(wildcard *.png))
|
MK4_SOURCES = $(wildcard mono/*.txt) $(wildcard mono/*.png)
|
||||||
MK4_SOURCES = $(wildcard mk4_*.txt) $(wildcard mk4_*.png)
|
Q1_SOURCES = colour/*.???
|
||||||
|
|
||||||
graphics.py: Makefile $(SOURCES) build.py
|
|
||||||
./build.py graphics.py $(SOURCES)
|
|
||||||
|
|
||||||
graphics_mk4.py: Makefile $(MK4_SOURCES) build.py
|
graphics_mk4.py: Makefile $(MK4_SOURCES) build.py
|
||||||
./build.py graphics_mk4.py $(MK4_SOURCES)
|
./build.py graphics_mk4.py $(MK4_SOURCES)
|
||||||
|
|
||||||
|
graphics_q1.py: Makefile $(Q1_SOURCES) compress.py
|
||||||
|
./compress.py graphics_q1.py $(Q1_SOURCES)
|
||||||
|
|
||||||
up: all
|
up: all
|
||||||
(cd ../shared; make up)
|
(cd ../shared; make up)
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ def read_text(fname):
|
|||||||
def read_img(fn):
|
def read_img(fn):
|
||||||
img = Image.open(fn)
|
img = Image.open(fn)
|
||||||
w,h = img.size
|
w,h = img.size
|
||||||
assert 1 <= w < 128, w
|
assert 1 <= w < 128, (w, fn)
|
||||||
|
|
||||||
img = img.convert('L')
|
img = img.convert('L')
|
||||||
# fix colour issues: assume minority colour is white (1)
|
# fix colour issues: assume minority colour is white (1)
|
||||||
@ -88,7 +88,7 @@ class Graphics:
|
|||||||
assert img.mode == '1'
|
assert img.mode == '1'
|
||||||
#img.show()
|
#img.show()
|
||||||
|
|
||||||
varname = fn.split('.')[0].replace('-', '_')
|
varname = fn.split('/')[-1].split('.')[0].replace('-', '_')
|
||||||
|
|
||||||
w,h = img.size
|
w,h = img.size
|
||||||
raw = img.tobytes()
|
raw = img.tobytes()
|
||||||
|
|||||||
BIN
graphics/colour/nfc_0.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
graphics/colour/nfc_1.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
graphics/colour/scan_1.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/scan_2.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
graphics/colour/scan_3.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/scan_4.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/scan_5.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/splash.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
212
graphics/compress.py
Executable file
@ -0,0 +1,212 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
#
|
||||||
|
# Read in PNG (or even JPG) and output heavily compressed RGB565 data suited to Q1's LCD panel.
|
||||||
|
#
|
||||||
|
# - also renders status bar icons/indicators
|
||||||
|
#
|
||||||
|
import os, sys, pdb
|
||||||
|
from PIL import Image, ImageOps, ImageFont, ImageDraw
|
||||||
|
import zlib
|
||||||
|
from struct import pack
|
||||||
|
|
||||||
|
WBITS = -10
|
||||||
|
|
||||||
|
FONT_PATH = './fonts/'
|
||||||
|
|
||||||
|
def read_img(fn):
|
||||||
|
img = Image.open(fn)
|
||||||
|
w,h = img.size
|
||||||
|
assert 1 <= w <= 320, f'too wide; {w}'
|
||||||
|
assert 1 <= h <= 240, f'too tall: {h}'
|
||||||
|
|
||||||
|
img = img.convert('RGB')
|
||||||
|
|
||||||
|
# maybe: quantitize to a reasonable num colours, so compression
|
||||||
|
# can work better?
|
||||||
|
|
||||||
|
return img
|
||||||
|
|
||||||
|
def compress(n, wbits=WBITS):
|
||||||
|
# NOTE: neg wbits implies no zlib header, and receiver may need to know it?
|
||||||
|
z = zlib.compressobj(wbits=wbits, level=zlib.Z_BEST_COMPRESSION)
|
||||||
|
rv = z.compress(n)
|
||||||
|
rv += z.flush(zlib.Z_FINISH)
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def crunch(n):
|
||||||
|
# try them all... not finding any difference tho.
|
||||||
|
a = [(wb,compress(n, wb)) for wb in range(-9, -15, -1)]
|
||||||
|
|
||||||
|
a.sort(key=lambda i: (-len(i[1]), -i[0]))
|
||||||
|
|
||||||
|
print("Wbit values:")
|
||||||
|
print('\n'.join("%3d => %d" % (wb,len(d)) for wb,d in a))
|
||||||
|
|
||||||
|
return a[0]
|
||||||
|
|
||||||
|
# LCD Display wants RGB565 values, but big endian, so green gets split weird.
|
||||||
|
def swizzle(r,g,b):
|
||||||
|
# from 0-255 per component => two bytes
|
||||||
|
b = (b >> 3)
|
||||||
|
g = (g >> 3) # should be >> 2 for 6 bits; but looks trash?
|
||||||
|
r = (r >> 3)
|
||||||
|
|
||||||
|
return pack('>H', ((r<<11) | (g<<6) | b))
|
||||||
|
|
||||||
|
# these values tested on real hardware
|
||||||
|
assert swizzle(255, 0, 0) == b'\xf8\x00' # red
|
||||||
|
##assert swizzle(0, 255, 0) == b'\xc0\x0f' # green (6 bits)
|
||||||
|
assert swizzle(0, 255, 0) == b'\x07\xc0' # green (5 bits)
|
||||||
|
assert swizzle(0, 0, 255) == b'\x00\x1f' # blue
|
||||||
|
|
||||||
|
|
||||||
|
def into_bgr565(img):
|
||||||
|
# get the raw bytes needed for this specific display
|
||||||
|
rv = bytearray()
|
||||||
|
for y in range(img.height):
|
||||||
|
for x in range(img.width):
|
||||||
|
px = img.getpixel((x, y))
|
||||||
|
assert len(px) == 3
|
||||||
|
r,g,b = px
|
||||||
|
rv.extend(swizzle(r,g,b))
|
||||||
|
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def make_icons():
|
||||||
|
# return list of (varname, img) for each image
|
||||||
|
|
||||||
|
# - see shared/lcd_display.py TOP_MARGIN for this
|
||||||
|
ICON_SIZE = 14
|
||||||
|
MAX_HEIGHT = 14
|
||||||
|
|
||||||
|
# PROBLEM: this file costs money... altho free version looks okay too
|
||||||
|
try:
|
||||||
|
awesome = ImageFont.truetype(FONT_PATH + 'Font Awesome 6 Sharp-Regular-400.otf', ICON_SIZE)
|
||||||
|
except:
|
||||||
|
raise
|
||||||
|
|
||||||
|
# use a bitmap font for best readability
|
||||||
|
sm_font = ImageFont.load('ter-powerline-x12b.pil')
|
||||||
|
|
||||||
|
targets = [
|
||||||
|
#( 'brand', True, 'Q', dict(col='#ffb000') ),
|
||||||
|
( 'shift', True, 'SHIFT', {} ),
|
||||||
|
( 'symbol', True, 'SYM', {} ),
|
||||||
|
( 'caps', True, 'CAPS', {} ),
|
||||||
|
( 'bip39', True, 'PASSPHRASE', dict(col_1='yellow') ),
|
||||||
|
( 'tmp', True, 'TMP.SEED', dict(col_0='black', col_1='red') ),
|
||||||
|
( 'devmode', True, 'DEV', dict(col='#66E6FF') ),
|
||||||
|
( 'edge', True, 'EDGE', dict(col='#66E6FF') ),
|
||||||
|
( 'bat_0', False, '\uf244', dict(col='red', y=-1, pad=1)),
|
||||||
|
( 'bat_1', False, '\uf243', dict(col='yellow', y=-1, pad=1)),
|
||||||
|
( 'bat_2', False, '\uf242', dict(col='amber', y=-1, pad=1)),
|
||||||
|
( 'bat_3', False, '\uf240', dict(col='amber', y=-1, pad=1)),
|
||||||
|
( 'plugged', False, '\uf1e6', dict(col='amber', x=3, w=16, y=-2)), # to match width of bat_*
|
||||||
|
#( 'locked', False, '\uf023', dict(col='green')),
|
||||||
|
#( 'unlocked', False, '\uf3c1', dict(col='green')), # why tho?
|
||||||
|
]
|
||||||
|
|
||||||
|
targets += [ ( 'ch_'+c, True, c.upper(), dict(col='white') ) for c in
|
||||||
|
'0123456789abcdef']
|
||||||
|
|
||||||
|
samples = Image.new('RGB', (320*3, ICON_SIZE+1))
|
||||||
|
s_x = 5
|
||||||
|
|
||||||
|
for basename, is_text, body, opts in targets:
|
||||||
|
for state in [0, 1]:
|
||||||
|
col = opts.get('col', '#fff' if state else '#444')
|
||||||
|
vn = f'{basename}_{state}'
|
||||||
|
|
||||||
|
if 'col' in opts:
|
||||||
|
if state == 0: continue
|
||||||
|
vn = basename
|
||||||
|
|
||||||
|
if state == 0 and 'col_0' in opts:
|
||||||
|
col = opts['col_0']
|
||||||
|
if state == 1 and 'col_1' in opts:
|
||||||
|
col = opts['col_1']
|
||||||
|
|
||||||
|
img = Image.new('RGB', (100,100))
|
||||||
|
d = ImageDraw.Draw(img)
|
||||||
|
f = sm_font if is_text else awesome
|
||||||
|
|
||||||
|
|
||||||
|
x, y = (0, 1 if is_text else 0)
|
||||||
|
y += opts.get('y', 0)
|
||||||
|
x += opts.get('x', 0)
|
||||||
|
|
||||||
|
tl = (x, y)
|
||||||
|
_,_, w,h = d.textbbox(tl, body, font=f)
|
||||||
|
|
||||||
|
w = opts.get('w', w)
|
||||||
|
|
||||||
|
if h > MAX_HEIGHT:
|
||||||
|
h = MAX_HEIGHT
|
||||||
|
print(f'"{vn}" too tall, cropped')
|
||||||
|
elif opts.get('pad'):
|
||||||
|
h = MAX_HEIGHT
|
||||||
|
|
||||||
|
if col == 'amber':
|
||||||
|
# brand colour
|
||||||
|
col = '#ffb000'
|
||||||
|
|
||||||
|
d.text(tl, body, font=f, fill=col)
|
||||||
|
rv = img.crop( (0, 0, w,h) )
|
||||||
|
|
||||||
|
samples.paste(rv, (s_x, 0))
|
||||||
|
s_x += w + 10
|
||||||
|
|
||||||
|
yield (vn, rv)
|
||||||
|
|
||||||
|
samples = samples.crop( (0,0, s_x, samples.height ))
|
||||||
|
samples.save('icon-samples.png')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def doit(outfname, fnames):
|
||||||
|
|
||||||
|
assert outfname.endswith('.py')
|
||||||
|
assert outfname != 'compress.py'
|
||||||
|
assert fnames, "need some files"
|
||||||
|
|
||||||
|
fp = open(outfname, 'wt')
|
||||||
|
|
||||||
|
fp.write("""\
|
||||||
|
# autogenerated; don't edit
|
||||||
|
#
|
||||||
|
# BGR565 pixel data
|
||||||
|
#
|
||||||
|
class Graphics:
|
||||||
|
# (w,h, data)
|
||||||
|
|
||||||
|
""")
|
||||||
|
|
||||||
|
fnames += make_icons()
|
||||||
|
|
||||||
|
for fn in fnames:
|
||||||
|
if isinstance(fn, str):
|
||||||
|
img = read_img(fn)
|
||||||
|
varname = fn.split('/')[-1].split('.')[0].replace('-', '_')
|
||||||
|
else:
|
||||||
|
varname, img = fn
|
||||||
|
|
||||||
|
assert img.mode == 'RGB'
|
||||||
|
|
||||||
|
w,h = img.size
|
||||||
|
raw = into_bgr565(img)
|
||||||
|
comp = compress(raw)
|
||||||
|
#crunch(raw)
|
||||||
|
|
||||||
|
print(" %s = (%d, %d,\n %r\n )\n" % (varname, w, h, comp), file=fp)
|
||||||
|
|
||||||
|
print("done: '%s' (%d x %d) => %d raw => %d compressed bytes" % (
|
||||||
|
varname, w, h, len(raw), len(comp)))
|
||||||
|
|
||||||
|
fp.write("\n# EOF\n")
|
||||||
|
|
||||||
|
if 1:
|
||||||
|
doit(sys.argv[1], sys.argv[2:])
|
||||||
|
|
||||||
|
# EOF
|
||||||
@ -1,4 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Generate some data for hsm_ux.py animation
|
||||||
|
#
|
||||||
from math import sin, pi
|
from math import sin, pi
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
|
|||||||
3
graphics/fonts/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Font Awesome 6*.otf
|
||||||
|
iosevka-*.ttf
|
||||||
|
!iosevka-heavy.ttf
|
||||||
11
graphics/fonts/README.md
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
# Fonts for Q1
|
||||||
|
|
||||||
|
This directory may contain font files from Font Awesome.
|
||||||
|
|
||||||
|
We cannot re-distribute the OTF files themselves due to their license.
|
||||||
|
|
||||||
|
However, once we render and build the compressed graphics file that we need,
|
||||||
|
the font is not required anymore.
|
||||||
|
|
||||||
|
Iosveka is open and can be re-distributed here.
|
||||||
18
graphics/fonts/font-awesome-license.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Font Awesome Pro License
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Font Awesome Pro is commercial software that requires a paid license. Full
|
||||||
|
Font Awesome Pro license: https://fontawesome.com/license.
|
||||||
|
|
||||||
|
# Commercial License
|
||||||
|
The Font Awesome Pro commercial license allows you to pay for FA Pro once, own
|
||||||
|
it, and use it just about everywhere you'd like.
|
||||||
|
|
||||||
|
# Attribution
|
||||||
|
Attribution is not required by the Font Awesome Pro commercial license.
|
||||||
|
|
||||||
|
# Brand Icons
|
||||||
|
All brand icons are trademarks of their respective owners. The use of these
|
||||||
|
trademarks does not indicate endorsement of the trademark holder by Font
|
||||||
|
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||||
|
to represent the company, product, or service to which they refer.**
|
||||||
BIN
graphics/fonts/iosevka-heavy.ttf
Normal file
@ -1,27 +0,0 @@
|
|||||||
# autogenerated; don't edit
|
|
||||||
#
|
|
||||||
class Graphics:
|
|
||||||
# (w,h, w_bytes, wbits, data)
|
|
||||||
|
|
||||||
arrow_down = (7, 11, 1, 0, b'\x10\x10\x10\x10\x10\x10\x10\xfe|8\x10')
|
|
||||||
|
|
||||||
arrow_up = (7, 11, 1, 0, b'\x108|\xfe\x10\x10\x10\x10\x10\x10\x10')
|
|
||||||
|
|
||||||
box = (13, 21, 2, 0, b'?\xe0@\x10\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08@\x10?\xe0')
|
|
||||||
|
|
||||||
scroll = (3, 61, 1, 0, b'@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@@\xe0@')
|
|
||||||
|
|
||||||
selected = (15, 12, 2, 0, b'\x00\x00\x00\x00\x00\x06\x00\x0c\x00\x18\x0000`\x18\xc0\r\x80\x07\x00\x02\x00\x00\x00')
|
|
||||||
|
|
||||||
sm_box = (11, 17, 2, 0, b'\xe4\xe0\x80 \x80 \x80 \x00\x00\x00\x00\x80 \x00\x00\x00\x00\x00\x00\x80 \x00\x00\x00\x00\x80 \x80 \x80 \xe4\xe0')
|
|
||||||
|
|
||||||
space = (9, 2, 2, 0, b'\x80\x80\xff\x80')
|
|
||||||
|
|
||||||
spin = (13, 36, 2, 0, b'\x02\x00\x07\x00\x0f\x80\x1f\xc0\x00\x00\x00\x00\x00\x00\xf2x\x80\x08\x80\x08\x80\x08\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x80\x08\x80\x08\x80\x08\xf2x\x00\x00\x00\x00\x00\x00\x1f\xc0\x0f\x80\x07\x00\x02\x00\x00\x00')
|
|
||||||
|
|
||||||
wedge = (6, 11, 1, 0, b'\x00\x00\xc0\xe0p8\x1c8p\xe0\xc0')
|
|
||||||
|
|
||||||
xbox = (13, 21, 2, 0, b'?\xe0b0\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88b0?\xe0')
|
|
||||||
|
|
||||||
|
|
||||||
# EOF
|
|
||||||
@ -3,6 +3,12 @@
|
|||||||
class Graphics:
|
class Graphics:
|
||||||
# (w,h, w_bytes, wbits, data)
|
# (w,h, w_bytes, wbits, data)
|
||||||
|
|
||||||
|
arrow_down = (7, 11, 1, 0, b'\x10\x10\x10\x10\x10\x10\x10\xfe|8\x10')
|
||||||
|
|
||||||
|
arrow_up = (7, 11, 1, 0, b'\x108|\xfe\x10\x10\x10\x10\x10\x10\x10')
|
||||||
|
|
||||||
|
box = (13, 21, 2, 0, b'?\xe0@\x10\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08@\x10?\xe0')
|
||||||
|
|
||||||
mk4_nfc_1 = (126, 49, 16, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\xfe\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\xfe\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
mk4_nfc_1 = (126, 49, 16, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\xfe\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\xfe\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
mk4_nfc_2 = (118, 49, 15, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
mk4_nfc_2 = (118, 49, 15, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||||
@ -11,5 +17,27 @@ class Graphics:
|
|||||||
|
|
||||||
mk4_nfc_4 = (102, 49, 13, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\x9f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\x8f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00')
|
mk4_nfc_4 = (102, 49, 13, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\x9f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\x8f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
|
mk5_nfc_1 = (126, 49, 16, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\xfe\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\xfe\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
|
mk5_nfc_2 = (118, 49, 15, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
|
mk5_nfc_3 = (110, 49, 14, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x000\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x000\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x000\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
|
mk5_nfc_4 = (102, 49, 13, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\x9f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\x8f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00')
|
||||||
|
|
||||||
|
scroll = (3, 61, 1, 0, b'@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@@\xe0@')
|
||||||
|
|
||||||
|
selected = (9, 12, 2, 0, b'\x00\x00\x00\x00\x00\x80\x01\x80\x01\x00\x03\x00\x82\x00\xc6\x00d\x00<\x00\x18\x00\x00\x00')
|
||||||
|
|
||||||
|
sm_box = (11, 17, 2, 0, b'\xe4\xe0\x80 \x80 \x80 \x00\x00\x00\x00\x80 \x00\x00\x00\x00\x00\x00\x80 \x00\x00\x00\x00\x80 \x80 \x80 \xe4\xe0')
|
||||||
|
|
||||||
|
space = (9, 2, 2, 0, b'\x80\x80\xff\x80')
|
||||||
|
|
||||||
|
spin = (13, 36, 2, 0, b'\x02\x00\x07\x00\x0f\x80\x1f\xc0\x00\x00\x00\x00\x00\x00\xf2x\x80\x08\x80\x08\x80\x08\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x80\x08\x80\x08\x80\x08\xf2x\x00\x00\x00\x00\x00\x00\x1f\xc0\x0f\x80\x07\x00\x02\x00\x00\x00')
|
||||||
|
|
||||||
|
wedge = (6, 11, 1, 0, b'\x00\x00\xc0\xe0p8\x1c8p\xe0\xc0')
|
||||||
|
|
||||||
|
xbox = (13, 21, 2, 0, b'?\xe0b0\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88b0?\xe0')
|
||||||
|
|
||||||
|
|
||||||
# EOF
|
# EOF
|
||||||
|
|||||||
173
graphics/graphics_q1.py
Normal file
BIN
graphics/icon-samples.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
49
graphics/mono/mk5_nfc_1.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxx xxx xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
49
graphics/mono/mk5_nfc_2.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxx xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
49
graphics/mono/mk5_nfc_3.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
49
graphics/mono/mk5_nfc_4.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxx xxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxx
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||||
|
xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx yy n n n f c yyyy yyy
|
||||||
|
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yy yyyyyyyyyyy
|
||||||
|
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||||
|
xxxxxxxxxxxxxxxxx
|
||||||
|
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
12
graphics/mono/selected.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
X
|
||||||
|
XX
|
||||||
|
X
|
||||||
|
XX
|
||||||
|
X X
|
||||||
|
XX XX
|
||||||
|
XX X
|
||||||
|
XXXX
|
||||||
|
XX
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
xx
|
|
||||||
xx
|
|
||||||
xx
|
|
||||||
xx
|
|
||||||
xx xx
|
|
||||||
xx xx
|
|
||||||
xx xx
|
|
||||||
xxx
|
|
||||||
x
|
|
||||||
|
|
||||||
17913
graphics/ter-powerline-x12b.bdf
Normal file
BIN
graphics/ter-powerline-x12b.pbm
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
graphics/ter-powerline-x12b.pil
Normal file
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Coldcard Hardware Details
|
# Coldcard Hardware Details
|
||||||
|
|
||||||
This directory contains enough information for you to be able to
|
This directory contains enough information for you to be able to
|
||||||
@ -6,9 +5,20 @@ build your own Coldcard from off-the-shelf parts.
|
|||||||
We are sharing this information for the benefit of security
|
We are sharing this information for the benefit of security
|
||||||
researchers who wish to analyse the Coldcard more completely.
|
researchers who wish to analyse the Coldcard more completely.
|
||||||
|
|
||||||
|
|
||||||
# Schematic
|
# Schematic
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`schematic-q1d.png`
|
||||||
|
|
||||||
|
This is the Q rev D schematic.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`schematic-mark5f.png`
|
||||||
|
|
||||||
|
This is the Mark4 rev F schematic.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
`schematic-mark4d.png`
|
`schematic-mark4d.png`
|
||||||
@ -24,11 +34,13 @@ This is the Mark3 rev B schematic.
|
|||||||
|
|
||||||
# BOM - Bill of Materials
|
# BOM - Bill of Materials
|
||||||
|
|
||||||
`bom-mark3b.xlsx`
|
The parts used in the Coldcard are detailed in these spreadsheets.
|
||||||
|
Most of them could be bought on Digikey, but some are direct from suppliers.
|
||||||
|
|
||||||
The parts used in the Coldcard are detailed in this spreadsheet file.
|
- BOM for Q rev D: `bom-q1d.xlsx`
|
||||||
All of them could be bought on Digikey, and where we know
|
- BOM for Mk5 rev F: `bom-mark5f.xlsx`
|
||||||
it, we've included the Digikey SKU.
|
- BOM for Mk4 rev D: `bom-mark4d.xlsx`
|
||||||
|
- BOM for Mk3 rev B: `bom-mark3b.xlsx`
|
||||||
|
|
||||||
Not included are these minor bits:
|
Not included are these minor bits:
|
||||||
|
|
||||||
@ -36,14 +48,10 @@ Not included are these minor bits:
|
|||||||
- the secure bag (with barcode serial number)
|
- the secure bag (with barcode serial number)
|
||||||
- pin-recovery card
|
- pin-recovery card
|
||||||
|
|
||||||
`bom-mark4d.xlsx`
|
|
||||||
|
|
||||||
- Same for Mk4 rev D.
|
|
||||||
|
|
||||||
# Important
|
# Important
|
||||||
|
|
||||||
- No promises that these files are 100% current because we do make quality improvements.
|
- No promises that these files are 100% current because we constantly make quality improvements.
|
||||||
- Copyright of these files, and all design elements of the Coldcard remain with Coinkite Inc.
|
- Copyright of these files, and all design elements of the Coldcard remain with Coinkite Inc.
|
||||||
- This information is for research and testing purposes only—no warranties.
|
- This information is for research and testing purposes only—no warranties.
|
||||||
- **Coinkite does not grant license of this information for comercial use.**
|
- **Coinkite does NOT grant license of this information for comercial use.**
|
||||||
|
|
||||||
|
|||||||
BIN
hardware/bom-mark5f.xlsx
Normal file
BIN
hardware/bom-q1d.xlsx
Normal file
BIN
hardware/schematic-mark5f.png
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
hardware/schematic-q1d.png
Normal file
|
After Width: | Height: | Size: 796 KiB |
@ -1,26 +1,28 @@
|
|||||||
diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile
|
diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile
|
||||||
index 971f2f81a..b175c4dc7 100644
|
index 971f2f81a..0c25a11e0 100644
|
||||||
--- a/mpy-cross/Makefile
|
--- a/mpy-cross/Makefile
|
||||||
+++ b/mpy-cross/Makefile
|
+++ b/mpy-cross/Makefile
|
||||||
@@ -17,7 +17,7 @@ INC += -I$(BUILD)
|
@@ -17,7 +17,8 @@ INC += -I$(BUILD)
|
||||||
INC += -I$(TOP)
|
INC += -I$(TOP)
|
||||||
|
|
||||||
# compiler settings
|
# compiler settings
|
||||||
-CWARN = -Wall -Werror
|
-CWARN = -Wall -Werror
|
||||||
+CWARN = -Wall -Werror -Wno-error=unused-but-set-variable -Wno-error=array-bounds
|
+CWARN = -Wall -Werror -Wno-error=unused-but-set-variable -Wno-error=array-bounds
|
||||||
|
+CWARN += -Wno-error=unknown-warning-option
|
||||||
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith
|
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith
|
||||||
CFLAGS = $(INC) $(CWARN) -std=gnu99 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
|
CFLAGS = $(INC) $(CWARN) -std=gnu99 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
|
||||||
CFLAGS += -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables
|
CFLAGS += -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables
|
||||||
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
|
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
|
||||||
index 6a936a242..6b4900561 100644
|
index 6a936a242..43e6bf02a 100644
|
||||||
--- a/ports/unix/Makefile
|
--- a/ports/unix/Makefile
|
||||||
+++ b/ports/unix/Makefile
|
+++ b/ports/unix/Makefile
|
||||||
@@ -38,7 +38,7 @@ INC += -I$(TOP)
|
@@ -38,7 +38,8 @@ INC += -I$(TOP)
|
||||||
INC += -I$(BUILD)
|
INC += -I$(BUILD)
|
||||||
|
|
||||||
# compiler settings
|
# compiler settings
|
||||||
-CWARN = -Wall -Werror
|
-CWARN = -Wall -Werror
|
||||||
+CWARN = -Wall -Werror -Wno-error=unused-but-set-variable -Wno-error=array-bounds
|
+CWARN = -Wall -Werror -Wno-error=unused-but-set-variable -Wno-error=array-bounds
|
||||||
|
+CWARN += -Wno-error=unknown-warning-option -Wno-error=deprecated-non-prototype -Wno-error=bitwise-instead-of-logical
|
||||||
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
|
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
|
||||||
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
|
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ font_files = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# test with:
|
# test with:
|
||||||
#
|
|
||||||
# ./build.py build --portable && ./testit.py --msg "hello→world←\n↳this\n•Bullet\n•Text" -f small
|
# ./build.py build --portable && ./testit.py --msg "hello→world←\n↳this\n•Bullet\n•Text" -f small
|
||||||
#
|
#
|
||||||
special_chars = dict(small=[
|
special_chars = dict(small=[
|
||||||
@ -65,5 +64,19 @@ special_chars = dict(small=[
|
|||||||
|
|
||||||
xxxxx
|
xxxxx
|
||||||
'''),
|
'''),
|
||||||
|
('⋯', dict(y=0), '''\
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
x x x x x
|
||||||
|
'''),
|
||||||
|
|
||||||
|
# thin space
|
||||||
|
('\u2009', dict(y=0, w=5), '''\
|
||||||
|
|
||||||
|
'''),
|
||||||
|
|
||||||
])
|
])
|
||||||
|
|||||||
10
misc/gpu/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
# build products, see Makefile:
|
||||||
|
gpu.lss
|
||||||
|
gpu.sym
|
||||||
|
gpu.bin.tmp
|
||||||
|
|
||||||
|
checksums.txt
|
||||||
|
version-full.txt
|
||||||
|
version.txt
|
||||||
|
|
||||||
184
misc/gpu/Makefile
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
# (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
#
|
||||||
|
# Makefile for Q1's GPU co-processor.
|
||||||
|
#
|
||||||
|
# Targets:
|
||||||
|
# all - make everything, look for dafu.elf inparticular
|
||||||
|
# clean - delete intermediates
|
||||||
|
# clobber - delete all build products
|
||||||
|
#
|
||||||
|
|
||||||
|
# Toolchain
|
||||||
|
TOOLCHAIN = arm-none-eabi-
|
||||||
|
CC = $(TOOLCHAIN)gcc
|
||||||
|
OBJDUMP = $(TOOLCHAIN)objdump
|
||||||
|
OBJCOPY = $(TOOLCHAIN)objcopy
|
||||||
|
NM = $(TOOLCHAIN)nm
|
||||||
|
SIZE = $(TOOLCHAIN)size
|
||||||
|
|
||||||
|
# Basename of all targets
|
||||||
|
TARGET_NAME = gpu
|
||||||
|
|
||||||
|
# Source files, listed here as the object files they will become.
|
||||||
|
OBJS += startup.o
|
||||||
|
OBJS += main.o lcd.o version.o interrupts.o
|
||||||
|
OBJS += stm32c0xx_ll_gpio.o stm32c0xx_ll_spi.o stm32c0xx_ll_i2c.o stm32c0xx_ll_utils.o
|
||||||
|
|
||||||
|
# Have to have copies of these because the DMA and interrupt stuff
|
||||||
|
# needs to be commented-out.
|
||||||
|
#OBJS += stm32l4xx_hal_gpio.o stm32l4xx_hal_spi.o
|
||||||
|
#OBJS += stm32l4xx_hal_rcc.o stm32l4xx_hal_rcc_ex.o
|
||||||
|
|
||||||
|
# Where we will end up in the memory map (at start of flash)
|
||||||
|
GPU_FLASH_BASE = 0x08000000
|
||||||
|
GPU_FLASH_SIZE = 0x4000
|
||||||
|
GPU_FLASH_LAST = 0x08004000
|
||||||
|
|
||||||
|
# Use all of 6k of SRAM...
|
||||||
|
GPU_SRAM_BASE = 0x20000000
|
||||||
|
GPU_SRAM_SIZE = 0x00001800
|
||||||
|
|
||||||
|
# Compiler flags.
|
||||||
|
CFLAGS = -I. -Wall --std=gnu99 -Os -g3 \
|
||||||
|
-mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=soft -mtune=cortex-m0 \
|
||||||
|
-ffunction-sections -fdata-sections \
|
||||||
|
-mcpu=cortex-m0 -DMCU_SERIES_C0 -DSTM32C011xx \
|
||||||
|
-DUSE_FULL_LL_DRIVER
|
||||||
|
#-DUSE_HAL_DRIVER
|
||||||
|
|
||||||
|
# Pass in the locations of stuff
|
||||||
|
CFLAGS += -D GPU_FLASH_BASE=$(GPU_FLASH_BASE) -D GPU_FLASH_SIZE=$(GPU_FLASH_SIZE)
|
||||||
|
CFLAGS += -D GPU_SRAM_BASE=$(GPU_SRAM_BASE) -D GPU_SRAM_SIZE=$(GPU_SRAM_SIZE)
|
||||||
|
|
||||||
|
# Header file search path
|
||||||
|
INC_PATHS = external/cmsis_device_c0/Include \
|
||||||
|
external/stm32c0xx_hal_driver/Inc \
|
||||||
|
../../external/micropython/lib/cmsis/inc
|
||||||
|
|
||||||
|
CFLAGS += $(foreach INC,$(INC_PATHS),-I$(INC))
|
||||||
|
|
||||||
|
# Specialized linker-script here. Not the standard one!
|
||||||
|
#
|
||||||
|
LINKER_SCRIPT = link-script.ld
|
||||||
|
LDFLAGS += -Wl,-T$(LINKER_SCRIPT)
|
||||||
|
|
||||||
|
LDFLAGS += -flto -Wl,--gc-sections --specs=nano.specs
|
||||||
|
LDFLAGS += -Wl,--defsym,GPU_FLASH_BASE=$(GPU_FLASH_BASE)
|
||||||
|
LDFLAGS += -Wl,--defsym,GPU_FLASH_SIZE=$(GPU_FLASH_SIZE)
|
||||||
|
LDFLAGS += -Wl,--defsym,GPU_SRAM_BASE=$(GPU_SRAM_BASE)
|
||||||
|
LDFLAGS += -Wl,--defsym,GPU_SRAM_SIZE=$(GPU_SRAM_SIZE)
|
||||||
|
LDFLAGS += -Wl,-Map=$(TARGET_NAME).map
|
||||||
|
|
||||||
|
ASFLAGS += -Wa,--defsym,GPU_FLASH_BASE=$(GPU_FLASH_BASE) -Wa,--defsym,GPU_FLASH_SIZE=$(GPU_FLASH_SIZE)
|
||||||
|
ASFLAGS += -Wa,--defsym,GPU_SRAM_BASE=$(GPU_SRAM_BASE) -Wa,--defsym,GPU_SRAM_SIZE=$(GPU_SRAM_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
TARGET_ELF = $(TARGET_NAME).elf
|
||||||
|
TARGETS = $(TARGET_NAME).lss $(TARGET_NAME).bin $(TARGET_NAME).sym gpu_binary.py
|
||||||
|
|
||||||
|
all: $(TARGETS)
|
||||||
|
|
||||||
|
# recompile on any Makefile change, because with a small project like this...
|
||||||
|
$(OBJS): Makefile
|
||||||
|
$(TARGETS): $(TARGET_ELF) Makefile
|
||||||
|
|
||||||
|
# link step
|
||||||
|
$(TARGET_ELF): $(OBJS) $(LINKER_SCRIPT) Makefile
|
||||||
|
$(CC) $(CFLAGS) -o $(TARGET_ELF) $(LDFLAGS) $(OBJS)
|
||||||
|
$(SIZE) -Ax $@
|
||||||
|
|
||||||
|
# detailed listing, very handy
|
||||||
|
%.lss: $(TARGET_ELF)
|
||||||
|
$(OBJDUMP) -h -S $< > $@
|
||||||
|
|
||||||
|
# symbol dump, meh
|
||||||
|
%.sym: $(TARGET_ELF)
|
||||||
|
$(NM) -n $< > $@
|
||||||
|
|
||||||
|
# raw binary, forced to right size, pad w/ 0xff
|
||||||
|
%.bin: $(TARGET_ELF)
|
||||||
|
$(OBJCOPY) -O binary --gap-fill 0xff $< $@
|
||||||
|
|
||||||
|
# assumes openocd running from current directory
|
||||||
|
up:
|
||||||
|
echo 'flash write_image $(TARGET_ELF)' | nc localhost 4444
|
||||||
|
|
||||||
|
# make a 'release' build
|
||||||
|
release: code-committed clean all capture
|
||||||
|
release: CFLAGS += -DRELEASE=1 -Werror
|
||||||
|
|
||||||
|
.PHONY: code-committed
|
||||||
|
code-committed:
|
||||||
|
@echo ""
|
||||||
|
@echo "Are all changes commited already?"
|
||||||
|
git diff --stat --exit-code .
|
||||||
|
@echo '... yes'
|
||||||
|
|
||||||
|
# these files are what we capture and store for each release.
|
||||||
|
DELIVERABLES = $(TARGET_NAME).bin $(TARGET_NAME).lss gpu_binary.py
|
||||||
|
|
||||||
|
# package the binary into a mpy file to be frozen/included into main micro code
|
||||||
|
gpu_binary.py: version.txt $(TARGET_NAME).bin repackage.py
|
||||||
|
./repackage.py `cat version.txt` $(TARGET_NAME).bin > $@
|
||||||
|
wc -c $(TARGET_NAME).bin
|
||||||
|
|
||||||
|
checksums.txt: $(DELIVERABLES)
|
||||||
|
shasum -a 256 $(DELIVERABLES) > $@
|
||||||
|
|
||||||
|
lcd.o: barcode.h
|
||||||
|
barcode.h: make_barcode.py Makefile
|
||||||
|
python3 make_barcode.py
|
||||||
|
|
||||||
|
# Track released versions
|
||||||
|
.PHONY: capture
|
||||||
|
capture: version.txt version-full.txt $(DELIVERABLES) checksums.txt
|
||||||
|
V=`cat version.txt` && cat checksums.txt > releases/$$V.txt && cat version-full.txt >> releases/$$V.txt && mkdir -p releases/$$V; cp $(DELIVERABLES) releases/$$V
|
||||||
|
@echo
|
||||||
|
@echo " Version: " `cat version.txt`
|
||||||
|
@echo
|
||||||
|
V=`cat version.txt` && git tag -am "Q1 GPU version $$V" "q1-gpu-"$$V
|
||||||
|
git add -f releases/*/gpu.* releases/*.txt releases/*/*.py
|
||||||
|
|
||||||
|
# Pull out the version string from binary object (already linked in) and
|
||||||
|
# construct a text file (version.txt) with those contents
|
||||||
|
version.txt version-full.txt: version.o Makefile
|
||||||
|
$(OBJCOPY) -O binary -j .rodata.version_string version.o version-tmp.txt
|
||||||
|
cat version-tmp.txt | sed -e 's/ .*//' | sed -e 's/ .*//' > version.txt
|
||||||
|
cat version-tmp.txt | tr '\0' '\n' > version-full.txt
|
||||||
|
@echo
|
||||||
|
@echo "Version string: " `cat version-full.txt`
|
||||||
|
@echo
|
||||||
|
$(RM) version-tmp.txt
|
||||||
|
|
||||||
|
# nice version numbers.
|
||||||
|
BUILD_TIME = $(shell date '+%Y%m%d.%H%M%S')
|
||||||
|
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
SHA_VERSION = $(shell git rev-parse --short HEAD)
|
||||||
|
GIT_HASH = "$(BRANCH)@$(SHA_VERSION)"
|
||||||
|
version.o: CFLAGS += -DBUILD_TIME='"$(BUILD_TIME)"' -DGIT_HASH='$(GIT_HASH)'
|
||||||
|
version.o main.o: Makefile version.h
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJS)
|
||||||
|
|
||||||
|
clobber: clean
|
||||||
|
$(RM) $(TARGETS)
|
||||||
|
|
||||||
|
# In another window:
|
||||||
|
#
|
||||||
|
# openocd-stm -s /usr/local/Cellar/open-ocd/0.12.0/share/openocd/scripts -f openocd-gpu.cfg
|
||||||
|
#
|
||||||
|
# Can do:
|
||||||
|
# - "load" which writes the flash (medium speed, lots of output on st-util)
|
||||||
|
# - "cont" starts/continues system
|
||||||
|
# - "br main" sets breakpoints
|
||||||
|
# - "mon reset" to reset micro
|
||||||
|
# - and so on
|
||||||
|
#
|
||||||
|
debug:
|
||||||
|
arm-none-eabi-gdb $(TARGET_ELF) -x gogo.gdb
|
||||||
|
|
||||||
|
tags:
|
||||||
|
ctags -f .tags *.[ch] -R $(INC_PATHS)
|
||||||
|
|
||||||
|
# EOF
|
||||||
97
misc/gpu/README.md
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# GPU on Q1
|
||||||
|
|
||||||
|
The name is a joke. It's not a GPU, just a very simple and cheap micro that can
|
||||||
|
animate a progress bar. And that's all we want it to do.
|
||||||
|
|
||||||
|
It is field upgradable, but we will remove that and start locking it down in
|
||||||
|
production once it's features are stable.
|
||||||
|
|
||||||
|
|
||||||
|
## Hardware
|
||||||
|
|
||||||
|
It's a STM32C011F4:
|
||||||
|
|
||||||
|
- 16k bytes of Flash
|
||||||
|
- 6k bytes of RAM
|
||||||
|
- 4-48Mhz
|
||||||
|
- 18 GPIO
|
||||||
|
- 20 pins
|
||||||
|
- a newer part, so some challenges there
|
||||||
|
|
||||||
|
Of the two TagConnect spots, the GPU is the inboard one; other is for main micro.
|
||||||
|
|
||||||
|
## OpenOCD
|
||||||
|
|
||||||
|
Version 0.12.0 of OpenOCD, the latest release as of this writing, does not yet support this chip.
|
||||||
|
|
||||||
|
You'll need to compile from ST Micro's fork of OpenOCD. In particular we need
|
||||||
|
this diff:
|
||||||
|
<https://github.com/STMicroelectronics/OpenOCD/commit/21c81a2b2edf5402afbba8c22feaeda6f626554e>
|
||||||
|
|
||||||
|
I am using brew's install of normal 0.12.0 for config files, and
|
||||||
|
a compiled version named `openocd-stm`, so my command line is:
|
||||||
|
|
||||||
|
openocd-stm -s /usr/local/Cellar/open-ocd/0.12.0/share/openocd/scripts -f openocd-gpu.cfg
|
||||||
|
|
||||||
|
Useful commands:
|
||||||
|
|
||||||
|
flash erase_sector 0 0 last
|
||||||
|
|
||||||
|
Set EMPTY bit, so goes into BL:
|
||||||
|
|
||||||
|
> mdw 0x40022000
|
||||||
|
0x40022000: 00040600
|
||||||
|
> mmw 0x40022000 0x10000 0
|
||||||
|
> mdw 0x40022000
|
||||||
|
0x40022000: 00050600
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## In-Circuit Programming
|
||||||
|
|
||||||
|
- AN4221 describes the protocol used to load the flash
|
||||||
|
- timing is sensitive, but more important is where the i2c start/stops fall:
|
||||||
|
|
||||||
|
## First Time Boot
|
||||||
|
|
||||||
|
- on a fresh device, there is an `EMPTY` bit set on power-up (only) if flash looks empty
|
||||||
|
- this causes bootmode to happen, regardless of subsequent flash contents, resets, and `BOOT0` line
|
||||||
|
- so must clear bit 16 of `FLASH_ACR` after loading image: @ `0x40022000`
|
||||||
|
- also, main micro has control over `BOOT0` (PE2) which stop main flash from running too
|
||||||
|
- and the reset line on E6
|
||||||
|
- we use this flag to get into boot mode from working code
|
||||||
|
|
||||||
|
## Getting BOOT0 to work
|
||||||
|
|
||||||
|
- default config in flash bit (option bytes) is to
|
||||||
|
- see `FLASH_OPTR` bit: `nBOOT_SEL` (bit 24) needs to be zero, default is one
|
||||||
|
- `NRST_MODE` should be 0b01 (input only) not default (0b11 = bidirectional)
|
||||||
|
- register `FLASH_OPTR` at 0x40022020 => found as 0xfffffeaa
|
||||||
|
- loads from 0x1FFF7800 at power up
|
||||||
|
- TODO XXX still need this!
|
||||||
|
|
||||||
|
## AN4221 / Bootloader Bugs
|
||||||
|
|
||||||
|
- command 0x00 - 'get' ... returns 19 bytes, but says v1.1 of protocol; clearly v1.2
|
||||||
|
- command 0x02 - 'getid' ... returns 1 byte, but math wrong on length part of response
|
||||||
|
- command 0x01 - 'getversion' ... return 1 byte, and doesn't include length prefix byte
|
||||||
|
- memory read only works from flash, some parts of SRAM... not IO registers
|
||||||
|
- undocumented need for N-1 as length in read/write commands
|
||||||
|
- flash writes need to be 256-aligned, or else they do nothing and don't fail
|
||||||
|
|
||||||
|
## Resource Sharing
|
||||||
|
|
||||||
|
- SPI bus to the display is shared by the GPU and main micro.
|
||||||
|
- Main micro configures its pins as pull-up, open-drain outputs (there is no input except TEAR).
|
||||||
|
- GPU does the same, but no pull-ups (so open drain).
|
||||||
|
- Later turns out we need push-pull I/O to get the SPI speeds involved (rise times too slow
|
||||||
|
with built-in resistors)
|
||||||
|
|
||||||
|
## Other References
|
||||||
|
|
||||||
|
- Ideas, not code: <https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/341cd894516f747f14108de5da593dad99900ae0/tools/macosx/src/stm32flash_serial/src/stm32.c>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
8
misc/gpu/barcode.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// autogen file, see make_barcode.py
|
||||||
|
|
||||||
|
// in python: b'\x00\x00\x00\x00\x00\x00\x00?\x1c\x0e\x00\x1f\x8e\x00\xe0\x0f\xf8\xff\x8f\xc7\xe3\xfe?\xe3\xf1\xf8\xff\xf1\xf8\x03\xfe8\xfc\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
static const uint8_t test_barcode[40] = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x1c, 0x0e, 0x00, 0x1f, 0x8e, 0x00, 0xe0, 0x0f, 0xf8, 0xff, 0x8f, 0xc7, 0xe3, 0xfe, 0x3f, 0xe3, 0xf1, 0xf8, 0xff, 0xf1, 0xf8, 0x03, 0xfe, 0x38, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
// EOF
|
||||||
62
misc/gpu/basics.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
extern void fatal_error(const char *) __attribute__((noreturn));
|
||||||
|
|
||||||
|
// I don't like the ususal assert macro, so here is my replacement,
|
||||||
|
// and BTW: "assert()" is actually a macro, so it should
|
||||||
|
// always be capitalized.
|
||||||
|
//
|
||||||
|
#undef assert
|
||||||
|
#undef ASSERT
|
||||||
|
|
||||||
|
// this does have an impact, but probably doesn't matter.
|
||||||
|
#define __unlikely(x) __builtin_expect((x),0)
|
||||||
|
|
||||||
|
#define ASSERT(x) do { if(__unlikely(!(x))) { fatal_error("assert");} } while(0)
|
||||||
|
|
||||||
|
// Use anywhere. Will just crash on production, but useful in dev.
|
||||||
|
#ifndef RELEASE
|
||||||
|
#define BREAKPOINT asm("BKPT #0")
|
||||||
|
#else
|
||||||
|
#define BREAKPOINT #error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// An assertion that we will be checked at *compile* time. Useful GCC feature.
|
||||||
|
#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)
|
||||||
|
|
||||||
|
// Similarly: for those times when you want to write ASSERT(False),
|
||||||
|
// use this instead to provide a msg and abort. Altho the msg isn't
|
||||||
|
// in the binary, it's still helpful when looking at source via debugger.
|
||||||
|
//
|
||||||
|
// CAUTION: some security checks end up here, so we want to always crash
|
||||||
|
// in those cases.
|
||||||
|
//
|
||||||
|
#define INCONSISTENT(x) fatal_error("incon")
|
||||||
|
|
||||||
|
// Wait for an interrupt which will never happen (ie. die)
|
||||||
|
#define LOCKUP_FOREVER() while(1) { __WFI(); }
|
||||||
|
|
||||||
|
// Like "sizeof()" but works on arrays, and returns the "numberof" elements.
|
||||||
|
//
|
||||||
|
#define numberof(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
|
// This is an old favourite with dangerous programers...
|
||||||
|
//
|
||||||
|
#ifndef offsetof
|
||||||
|
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define msizeof(TYPE, MEMBER) sizeof(((TYPE *)0)->MEMBER)
|
||||||
|
|
||||||
|
// Handy macros.
|
||||||
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#define CLAMP(x,mn,mx) (((x)>(mx))?(mx):( ((x)<(mn)) ? (mn) : (x)))
|
||||||
|
#define SGN(x) (((x)<0)?-1:(((x)>0)?1:0))
|
||||||
|
#define ABS(x) (((x)<0)?-(x):(x))
|
||||||
|
|
||||||
1
misc/gpu/external/cmsis_device_c0
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 7e32bf9d8117ee4c8f6a1d138b814fc24bf4c906
|
||||||
1
misc/gpu/external/stm32c0xx_hal_driver
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4c5e3e45a8478a33decb1f45d663f485f89c459b
|
||||||
22
misc/gpu/gogo.gdb
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
add-symbol-file gpu.elf 0x08000000
|
||||||
|
|
||||||
|
# hex for all numbers
|
||||||
|
set output-radix 16
|
||||||
|
|
||||||
|
# kill X repeats N times, which interfere w/ cut-n-paste into python of dumps
|
||||||
|
set print repeats 128
|
||||||
|
|
||||||
|
# Use ST-Link (st-utils)
|
||||||
|
#target extended-remote :4242
|
||||||
|
|
||||||
|
# Connect to the OpenOCD gdb server (needs to be already running & connected)
|
||||||
|
target extended-remote :3333
|
||||||
|
|
||||||
|
define reset
|
||||||
|
mon reset init
|
||||||
|
end
|
||||||
|
|
||||||
|
define wipe_chip
|
||||||
|
mon flash erase_sector 0 0 last
|
||||||
|
mon reset halt
|
||||||
|
end
|
||||||
118
misc/gpu/gpu_binary.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
# (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
#
|
||||||
|
# Binary for Q1 GPU co-processor
|
||||||
|
#
|
||||||
|
# see misc/gpu for source
|
||||||
|
#
|
||||||
|
VERSION = '1.3.3'
|
||||||
|
|
||||||
|
LENGTH = const(3536) # bytes (after decompression)
|
||||||
|
|
||||||
|
# len(BINARY) = 2618
|
||||||
|
BINARY = (b"x\x9c\x8dW\x7fl\x13\xd7\x1d\xff\xbe\xbbsb;\x8188\xd08?\xcf~\t\x04\x9c\x10'"
|
||||||
|
b'GZ\ne\x1c>j\x12\x1f\xa4\x14J\x051\xdd\x9c\x1f\x853\xa1\xeb\xad\xe9*k\xfdc.'
|
||||||
|
b'\xa8]\xc76\xdabZ\xc0\x866\x90\xfeB\xedF\x16\xc9\x9b\xd6\x11\x95\xb5\xdb\xaa'
|
||||||
|
b'\xb5j\xeb#\xad\xc6\x08ZS\xe8duSWSM\xb5\x81\xc6\xb7\xef\x99P9\x12\x9af\xeb'
|
||||||
|
b'\xeb\xf7\xfd\xf5\xbe\xdf\xcf}\xef\xbd\xef{\x86J\xe0-\x04\xcc\xab,`^\x8d\x04'
|
||||||
|
b"\xff\xe3\xb3\xa6\xc0.!\x7f'\xd2\x16r]g\x8c7\xa3\xff\xc7v#\xe6\xcd\xfc"
|
||||||
|
b'o\xa6/\xc4dK\x14\xad\xa7ap\x17k&\x19\xdcL\x92\xeb\x84)x\x93P\xaa\xda\xc6\xd1'
|
||||||
|
b'\x917|\xfe8\x07\xcc\x9clK\x80\x9bM\xb2]\xd7=l\xe3g|\x86\xad\x14}\x0c{i'
|
||||||
|
b'\xe7\xe3>H\x1f\xbc\x02Nv\xca*\x07\xb6J\x1b\xb96K\xa7U\xf6V\xc6\xbc_OX\xfc'
|
||||||
|
b'\xcc\x14P{\x90k/\x96c\xde+\x13\x90\xfe\xd3\x95\\\n*\xf3\xf1\xf3d\x9e'
|
||||||
|
b'\xa1\xb5Hh\x81t\x824\xfet\xb4\xc2\x85\xf1^\x85\xf4\xb9\xe92y\xb8\xa1g'
|
||||||
|
b'\x90Y\xb4D\xea\xe9\x0f\x0c~fr\x8b$J\xe2\xab)s\x92\x87\xc8B&\xca'
|
||||||
|
b"\x1d\x82\xf4\x85k@\xbf&<0'\x99\xe7\xd8g\xb9CEQH\x9f\xbd\xf6r\x9fe4="
|
||||||
|
b'\x0e6F\xb4%\x98\x06^vv\xf5<\xf0\xe4\xa8U\xec\xb9\xbfg\x10\x9c\xae|'
|
||||||
|
b'\xbcR\x17\x15!\x8a\x99\xe2\x90>1}\x86\x92\xe8\x9b+\xb9(9i\x12\x16t'
|
||||||
|
b'\x16E\x99\x83\x90\xfe\xd5\xb5\x1a\xc4B\x10\xcb\x81\xe9y\xb2}=\x13'
|
||||||
|
b'}\x97\xf2\x80\x1e\x98\xa3m:B\xfb\x948g\x97\xfa\x83\x97\x949~\xbbx\t'
|
||||||
|
b'\xc7\xd2\xfcH\x95\x12\x1c)\x8e\xd6\xfch\x1e\xb5\xe5\xb1\xe8\x1f\xea:'
|
||||||
|
b'p\xb0\xd1\xce\xd9\x00\xee\x01\x91du]\xff1\x92\x9eA\x9a\xd6#\x94\xf5\x07\x98'
|
||||||
|
b'r\xa5D\xb2\x07\xd5uXk\x9e\x11\xcd4\x93\xe8_?\xe0?\x1erxm\xc9OC%R\xc4y\xa9w'
|
||||||
|
b'$\xd4\xc5\x94\x88\x0e\xe8\xac{lM\xb9\nn\xaam\xef*Q\r\xb2\x87\x8f\x87Ht\x9b\\'
|
||||||
|
b"\x1f\xde&\xd7\x86y\xea\xf0\xb6'/\x86\xec\xd2\xa5^\x12\x07w\xb3vO\xb7\xa0"
|
||||||
|
b"\xf6\xb7nK\x96\x9d\xebm\xbd?\xd9\xd7*'\xefm\xadHn\x947\xfa\xab\x82"
|
||||||
|
b'f\xea\x9d\xa2\xca]]%\x88\xf9|\xea\xe1\xd6\xef&\xfd\xf2#\xadBRm\xfd'
|
||||||
|
b'\xb7\xe6\xf7w\xa8\xe81\x05-\xdb\xb5\xce\xce\xb5re\x10\xd2e\xd3\xc4\xe3Q\t'
|
||||||
|
b'=\x81\xf1Gz\xc1\xc5\xd1r8\xea#\xfc\x0e\xdfHH\xf0n\xd0`1I\xde*\xd7\xab\xb0'
|
||||||
|
b'\x84$;\xe4ZU_\x04\x8d\xcc\xc2\xd3>\xa1sY\x17\x1b\xb6*\xe4\x05h]\xafA\x0bI'
|
||||||
|
b'\xb2\xaa5\x98\x19\x87\x96\xa5Z;\xe2(\xa2\x82:\x91\x82\x96E\x9a'
|
||||||
|
b"\x9e\xf9\xa1\xde*7\xf9\xedA\x96\xfe'\xc5\xb6\xd4iM\xfef\xb9<|D\xbd;\xfc7\xd5"
|
||||||
|
b'\xe4<\x10\xeeQ\xab\xc2\xfb\xa4*\xf5\xf7\xe8_\xa6\x11W\x83\xec\x08[Q\xbeO'
|
||||||
|
b'\x1dCM\x91\xc6:y\xd9\xf0(\x07\xc6\xf5Uj\x81\\\x8b\xf1-\xf4\x83T\xff'
|
||||||
|
b'\xae\xc91h-N\x16\xb7\xbcr\xce\xde\xbd\xabfh\xcb\xc7c\x0c\x1cO\xd5\x03'
|
||||||
|
b'\x81\xe7S;}\xaf\xf4\x9dJ\xbd\x12\xba\xcd{*\t\xeeLr~\x98\xac|\xa9'
|
||||||
|
b'\x8f\xb4\x93c\x93c#)\xe3\xdd-\xc55\xdb\x82\xd4\x80\xb4\x0c\xc9\x83\xb4\r\xf7'
|
||||||
|
b'\x84\xae\xe7\xf4F\xe4\x0f"\xbf\x11\xe9^\xa4;P\xee\xc31\xe2\xaa\x92\xe7\x99b'
|
||||||
|
b'\xc1\x88\xcb!o\x02\x87\x828\x91?\x8b\\\xb9\xf7\x9bd\x8fR\xd1U.\xa2L'
|
||||||
|
b'\xacRO\xb0J\x99\x97\x976\x11\xc3+\xa6\x94uY\xc5bg\x0c\xb9}R,\xb8\xdcuD'
|
||||||
|
b'1\x83M,\xf7^\xd5b\x8a\x05m\xb1\xa0E\xb6\xf8{\x82&\xd7\xe1`\x15\xae'
|
||||||
|
b'\x1e\xf8\x02w\xac\xb1\xe6"\xb8\xb4\xdeAJ#=\xa5\xeb\xb6)\x98\xfa\x04\xc1W'
|
||||||
|
b'\xcaC\t\xc7\xee\xca\xce\xe1\x06"9\x06\x1es\x92\x85U\xbb\xbbL\x8cH\x0e\x90'
|
||||||
|
b'\xd8y\xdckV\xe9|\xff\xe4`\t\xee\x10\x88\xeb\x99\xf6\x1c\xa4Og\xf5\xcc\xd6'
|
||||||
|
b'\\\xa9\x7fN\x97])\x11\xedA=\xf3\xeb\x1c\xc5\xf7|U\xe3\x1bi\xc8\xed\xfd'
|
||||||
|
b':\t\xe9\x17\xaf\x18\xdc\xe5\xa4\x9e\x19\xc9]I\x19\xf9\x89\xcd\xd8\xe9'
|
||||||
|
b'\x88\x03\xeb2Lm.\xb3s\xd2dK\xc4z\x8f\xf4\xc5\xfa\xce\xd0\x00\xa9\x01\xb3'
|
||||||
|
b'\xff\x19\xc5!\x1e\xf7^K\xda\x86\x90\xf3~\xa3\x19~\x93\xa6X\xafyE\xac7\xdfs<D'
|
||||||
|
b'\x1c\xa6\x9e\x04\xcen0\xf4G{q\xae\x0b\xa8e\xfd&r\xd8[|aD\xb1\x17\xcc\xf2\x8c'
|
||||||
|
b"\xbf\xa4\xcc\x17\x9f\xc5x\xefo'B\xe3\xd0\x17)c\xfePb.\xd4\x02Y\xb1w,VI^?0V"
|
||||||
|
b'm\xa5jP\xb5[\x97\xf0#\xeaE\x15\x9fEw\x02\xc7\xeb\x99\xf7t\xb2jll\x8b\xe3\x97'
|
||||||
|
b'c\xf3\xac.\xd5\xcd/\xb1\x9ePw\xa8\xff@\x8f\xe1\x19\x8f7\xf4f\xfc=\xa2'
|
||||||
|
b'\x0f\x8d\x0fSu6&\xfa\xc1\xd8\xa7"4\x94\xf8\x03d\x18q\xcd~\x1au\xfcY\xa5V<'
|
||||||
|
b'\x86\xb8\x16\x0c\xdd\xe0\xca\x87\xc8\xb2\xcf\xf3\xf8\xd4D\rp\xaf\xd5=Ia>\xe8'
|
||||||
|
b'\x99Wu\x1e\xda@\x91\xf4\xcc\xfb\xba:nK\xec\x1b\xad\x99\xe9\x8a'
|
||||||
|
b'\x1b\xae\x9d\xa1\xd5\x0cD\xf7\xd0\x00\x90\xe8\x14\x9d\x04&\x1a\xc1J\x84'
|
||||||
|
b'|ql\xaaFgz\xf9\xaaH]\x8a]\xa2AB9\x7fy\x18\xbb\x89j\x1d\xbdQGc-\xa6\x13\x8f'
|
||||||
|
b'\x8fV\x00\x1bu6\xddv\xc1\xb2\xb8\xe3\x82\xa5Q\x91^\xf7\xcd\xe9\xd8 \x95\xd1'
|
||||||
|
b'\xc50o\x91]\xfcsmY\xdb\xc5"\xf8h\xa7\x8f=\xdaWwp\r\xef\x1f\xf0V\x88\xf5'
|
||||||
|
b'\xfe\x17+\x19w\xbd\xb6\x02<@V\xc2A=\xf3\xa2\xbe\x18\x085\xe4\x866['
|
||||||
|
b'\x87\xa1\x89\xeb\x15\x94\xb8\x16\xa3\xc6\x90\x0e\xceHi\x07Yn\xc8?'
|
||||||
|
b'\xd7M\xd8\x97\x89\xdb\x94d\xddW\xb4\x05\x94s\xc1\xc1\xa2)\x16;\x93I3\xcb'
|
||||||
|
b'+\x00\xa2\x0b\xa8\x07\xfe\x99\x02\xc4\x01\xd17\xealmfO\x85p1u\xc6\xc7'
|
||||||
|
b'\xbe\x80\x1d2\x08\x90I\xd4\xca\x9b\x9cp\xea\xd8\xda\xef\xfb\xc0U\xd4'
|
||||||
|
b'P\xd5\xa9\xb7\xd9\x81\x8a\xf7y\x07\xd7Tn\x08xY1\xe0\xd8\x02\xa4}h\xf3'
|
||||||
|
b'>\xefW\x9a\x89\x0e\xbb\xfe\xe5\x04>\xe0\xdd\x84U\x9d\xce\x99\x1al'
|
||||||
|
b'\x1b\x86y\xb7\x12\x81G\x83e\xf4G\n\xb9\xe3HU\x17\xfc\xa0R\xcf|\x98\x83'
|
||||||
|
b'\xe6\xb4\xf6\xa8b\xf1\x13\xc1.r\x1f\xdb\\d\xe5&\xaf]"\xc2\xb8\xcf\x8d\xbd'
|
||||||
|
b'i\xeb\xb4\xae\xdf\xc0 b\r\xcb\x00"\xd9D\x85l \xd9\xed\x8b\xf0.\x00g'
|
||||||
|
b'\x11\x94\xcb\x81\xed\xacX\x0b\x83\x88&\xe0\xb5GDs\x85F\xda\x9a\x16\xdb\xb4a'
|
||||||
|
b'W\x98\x0e/4P\xbc\x91\x0b7\xfe\x06\x9cF\rW\xe9\x99h\x0eZ\xb2\xda\xb8'
|
||||||
|
b'/;\xee\x01\xa6\xfd\xef\xa9\x08\xe6\xd9\x8d\xbdBMD\xe8p\xe3\x13\xa3_\x98&'
|
||||||
|
b'I)\xbe\xfb\xd7z\x8d\xb7\xdf}\x95]XD\x99\x86\x90\xaf\t\xeb\xc3<G\xf0\x94\nd+'
|
||||||
|
b')DoYI\xa2@\r=\xf3\x1c\x17e\xa3\xc6J\xe8\xce:\xbb\x850\xf5r\xb8\x1fO\xea'
|
||||||
|
b'BxD\x12T!<YL>\xd63\x01\xfd\xa10,\xa9K:64+\xd0l\xd3\x84\xf0\xe5p\xa0x'
|
||||||
|
b'\xb2l4\xacg\xbe\xcc\x11\x97\x10\xdeV\xfc\x97\xb2}\x12\xe7<\x00?\x93\xec8'
|
||||||
|
b'\xd3\xe6\xef\xaf1*\xc3\x7f[\x19wp\xb8\xa1b\xe6\x84$W\xeb\xe8g\xa6\x90'
|
||||||
|
b'\x0f\x0fv\xcc\\\x9e\x8d\xd0I2\xd2W4\xaa\xe2\xba3\xd6\xdcr\xa4z\xacY'
|
||||||
|
b'.\x95K\xa9\xeb\x8co:\xf1\x93\xd1\x12\x85y\xa6\xdeE\x9c$j\x02r8`\x06w\x9d\xf6'
|
||||||
|
b'\xb4\xc8\x0b\xd0\xc4`7\xf9\xdd\x95\xb7\xc7\xd8(\x13gc\x01\x05O'
|
||||||
|
b'\xe6\xf8\x84\xb8@\xe3\xe2d%q\x9b\xcf\r*$F\x8eD%&vV\xf1#\xbe\xc1 \xf0'
|
||||||
|
b'\xc5\xb8\xb6j\xf0\xed\x94\x8a\xbcDV\x04\xcc\x7fM\x11\xca\xc6\xc8\xd1\xa8Hb5'
|
||||||
|
b'b\x95\x17\xb4\x89\xa9\x1df\x1e\x04\xa8w\xb5*\xe0V\x0br\xed5r\xb9\x02\x10'
|
||||||
|
b'\x13y8$\x19\x1e\xe0\xdeY`\x1fB;\x173\xec\\\xfc\x16\x89\xacl\r\x12w\xc39&'
|
||||||
|
b'\xceC\\\xa9w\x99\xa2\x02\x9c\xc2\x88[\nf\xf4\xdc$\xe2\xfa\x02'
|
||||||
|
b'\xbb\x1f\xed\xa6|\xc4[\xa4SA#Ru\xe8z\xa4/1\xd2w\n<;n\x12\xa9\xa3\xc0'
|
||||||
|
b'\xde\xf8m$\x03\xdb\x97A\xc6\xfd=m\xe6)\xa7\x88S\x04\x87h\xce\xd7\xe3\xf1'
|
||||||
|
b'T\xa1\xb4\x7f\x964<K:9K\xfa\xed,\xe9\xcc,\tOG\x8d\x89?-\x06B\\\xb4'
|
||||||
|
b'\x03\xb1|\x92-nj\xbb0\x93}\x17\xb8k\x0bpj\xd9\xb7\xc7\xca\\q\xc4YO\x0fI'
|
||||||
|
b'\xb0t\x01\xa2<,\xf2\xf4\xba\xf5\xad\xacQ\xe1x\xbe\x1e\xad}l\x9c\x080+'
|
||||||
|
b'\xd3\xb9\x14\xe1\x07\xc0#rX\xfdG\xcc\x9f\xa4\x16Z\x07\xac\x1e\xa0'
|
||||||
|
b'\x98\xe7A\xccS]\x90\xe7\xd8\xec<\xcd\x15\x9a\xa7 \xcf\xfe\x82<\x0f\xf6\xbd;'
|
||||||
|
b'+\xc7y\xcc\xf1\x08\xf0b\x11\xe6\x180\x7f\x8awRVa@M\x10>P\xd4\xfcQ\xb7R'
|
||||||
|
b'\xa2t\x86\x04\xe9\x03e\xbe"HsC\xa5\xbb\x04i\x7f\x88\x95P\x13\x82RA\xb2uS\xa9'
|
||||||
|
b'Ct\xe3\xedm\xb3\xf2\x0benw\x93$\x88\x95R\x84n\x0cV\x93c^\xeel\x84\xdf\xac'
|
||||||
|
b'\x88\x84\x956\x07#\x14\xf889\xeae4yW|\xcc\xde;\x11b\xf1\xd65\x81g\x84\x08'
|
||||||
|
b'\xba~-}\xfdJH\\\xac\xe2ID%6\xf8\x1e\xc6\xabf8\xc5-Ulh\x16)jd\xc5\xbe\x9e'
|
||||||
|
b'\xede\x959\xa1*\x89\t\xeeU\xf6\x85\xa8\xb8\x17\xc7%\xd2\xa4u\x92\xa9\x92\xf6'
|
||||||
|
b'\x04\xa1\x85KF\xe8\x1e\x9cg\x97\xf6\x06\x19\xc5,W\x89%\x8a\xe1-)~\xf4'
|
||||||
|
b'\xb6K\x12\xee\x19\x0f\xeeO}\xea\xc6=\xf4C\xbd\xc6Ih5w\xd8K&\xa0\xd4v{\xb5'
|
||||||
|
b'5\xcfY\xcd\xb7W[\xf2\x9c\x85\xbb\x9d9a\xdb.V\x1a\xf7S\x8ee\x18\x82'
|
||||||
|
b"\x9f\x1b\xff+X\xd8S\x19\xc5]\xa6\xaes\xa8D\xc0\xf3\x9f\xbe\x85'0,\xb9"
|
||||||
|
b'\xa6m\xad\xc3\x1b\td\x13g|\xd9\xd3\xe6\xd3\xcf\xfb\xd4u\x85|\xdbRa\xa9'
|
||||||
|
b'\x00w\xc9\xe0\xed\x1d\xe0\xfb\x1f\x18X\x9dgz\x1f\xda9\xb4\xfaF\xe8\xd55s'
|
||||||
|
b'\xa1~?L\x95e\xf5\xa7\xde\xb9\x94[}\xe9rV\xbf\x9ces\xcb\xbf\x99q'
|
||||||
|
b'\xc8\xc7\xe0\x1f\x0e=p\xff\xaavO\xfb2O[\xfb\xadK\xdb<\xc2\xad\xed\xed'
|
||||||
|
b'\xfc\xce\xd0\xc3\xab\xee\x16=\xfd;<}\xfd\x1e~\xed\x9d\xf7\xaej\xbb>\xe7s'
|
||||||
|
b'\x00\xf3\x1f\x90\xfe\x0bJ`i=')
|
||||||
|
|
||||||
|
# EOF
|
||||||
107
misc/gpu/interrupts.c
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// from https://github.com/STMicroelectronics/STM32CubeC0/blob/main/Projects/STM32C0116-DK/Templates_LL/Src/stm32c0xx_it.c
|
||||||
|
/* USER CODE BEGIN Header */
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* @file stm32c0xx_it.c
|
||||||
|
* @brief Interrupt Service Routines.
|
||||||
|
******************************************************************************
|
||||||
|
* @attention
|
||||||
|
*
|
||||||
|
* Copyright (c) 2022 STMicroelectronics.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This software is licensed under terms that can be found in the LICENSE file
|
||||||
|
* in the root directory of this software component.
|
||||||
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
/* USER CODE END Header */
|
||||||
|
|
||||||
|
/* Includes ------------------------------------------------------------------*/
|
||||||
|
#include "main.h"
|
||||||
|
#include "interrupts.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* Cortex Processor Interruption and Exception Handlers */
|
||||||
|
/******************************************************************************/
|
||||||
|
/**
|
||||||
|
* @brief This function handles Non maskable interrupt.
|
||||||
|
*/
|
||||||
|
void NMI_Handler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||||
|
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
/* USER CODE END NonMaskableInt_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles Hard fault interrupt.
|
||||||
|
*/
|
||||||
|
void HardFault_Handler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN HardFault_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END HardFault_IRQn 0 */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
||||||
|
/* USER CODE END W1_HardFault_IRQn 0 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles System service call via SWI instruction.
|
||||||
|
*/
|
||||||
|
void SVC_Handler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN SVC_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END SVC_IRQn 0 */
|
||||||
|
/* USER CODE BEGIN SVC_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END SVC_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles Pendable request for system service.
|
||||||
|
*/
|
||||||
|
void PendSV_Handler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN PendSV_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END PendSV_IRQn 0 */
|
||||||
|
/* USER CODE BEGIN PendSV_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END PendSV_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles System tick timer.
|
||||||
|
*/
|
||||||
|
void SysTick_Handler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END SysTick_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||||
|
|
||||||
|
/* USER CODE END SysTick_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
/* STM32C0xx Peripheral Interrupt Handlers */
|
||||||
|
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||||
|
/* For the available peripheral interrupt handler names, */
|
||||||
|
/* please refer to the startup file (startup_stm32c0xx.s). */
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/* USER CODE BEGIN 1 */
|
||||||
|
|
||||||
|
/* USER CODE END 1 */
|
||||||
9
misc/gpu/interrupts.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void NMI_Handler(void);
|
||||||
|
void HardFault_Handler(void);
|
||||||
|
void SVC_Handler(void);
|
||||||
|
void PendSV_Handler(void);
|
||||||
|
void SysTick_Handler(void);
|
||||||
|
|
||||||
450
misc/gpu/lcd.c
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
*
|
||||||
|
* Control the LCD.
|
||||||
|
*
|
||||||
|
* - see <external/stm32c0xx_hal_driver/Inc/stm32c0xx_ll_spi.h> for the API of the SPI
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include "main.h"
|
||||||
|
#include "lcd.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "stm32c0xx_hal_gpio_ex.h"
|
||||||
|
#include "barcode.h"
|
||||||
|
|
||||||
|
lcd_state_t lcd_state;
|
||||||
|
|
||||||
|
const int LCD_WIDTH = 320;
|
||||||
|
const int LCD_HEIGHT = 240;
|
||||||
|
const int NUM_PIXELS = (LCD_WIDTH*LCD_HEIGHT);
|
||||||
|
|
||||||
|
// doing RGB565, but swab16
|
||||||
|
const uint16_t COL_BLACK = 0;
|
||||||
|
const uint16_t COL_WHITE = ~0;
|
||||||
|
const uint16_t COL_RED = 0x00f8; //SWAP16(0xf800);
|
||||||
|
const uint16_t COL_FOREGROUND = 0x60fd; //SWAB16(0xfd60); // brand orange
|
||||||
|
|
||||||
|
// progress bar specs
|
||||||
|
const uint16_t PROG_HEIGHT = 5;
|
||||||
|
const uint16_t PROG_Y = LCD_HEIGHT - PROG_HEIGHT;
|
||||||
|
|
||||||
|
static const int NUM_PHASES = 16;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// memset2()
|
||||||
|
//
|
||||||
|
static inline void
|
||||||
|
memset2(uint16_t *dest, uint16_t value, uint16_t byte_len)
|
||||||
|
{
|
||||||
|
for(; byte_len; byte_len-=2, dest++) {
|
||||||
|
*dest = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wait_vsync(void) {
|
||||||
|
// PA5 is TEAR input: a positive pulse every 60Hz that
|
||||||
|
// corresponds to vertical blanking time
|
||||||
|
uint32_t timeout = 1000000;
|
||||||
|
for(; timeout; timeout--) {
|
||||||
|
if(LL_GPIO_IsInputPinSet(GPIOA, PIN_TEAR)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//puts("TEAR timeout");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// write_byte()
|
||||||
|
//
|
||||||
|
static inline void
|
||||||
|
write_byte(uint8_t b)
|
||||||
|
{
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||||
|
// wait for space
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_SPI_TransmitData8(SPI1, b);
|
||||||
|
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) {
|
||||||
|
// wait for FIFO to drain completely
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write_bytes()
|
||||||
|
//
|
||||||
|
static inline void
|
||||||
|
write_bytes(int len, const uint8_t *buf)
|
||||||
|
{
|
||||||
|
for(int n=0; n<len; n++, buf++) {
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||||
|
// wait for space
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_SPI_TransmitData8(SPI1, *buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) {
|
||||||
|
// wait for FIFO to drain completely
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write_uint16()
|
||||||
|
//
|
||||||
|
static inline void
|
||||||
|
write_uint16(int count, uint16_t val)
|
||||||
|
{
|
||||||
|
uint8_t a = val & 0xff;
|
||||||
|
uint8_t b = val >> 8;
|
||||||
|
|
||||||
|
for(int n=0; n<count; n++) {
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||||
|
// wait for space
|
||||||
|
}
|
||||||
|
LL_SPI_TransmitData8(SPI1, a);
|
||||||
|
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||||
|
// wait for space
|
||||||
|
}
|
||||||
|
LL_SPI_TransmitData8(SPI1, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) {
|
||||||
|
// wait for FIFO to drain completely
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_write_cmd()
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
lcd_write_cmd(uint8_t cmd)
|
||||||
|
{
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||||
|
LL_GPIO_ResetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||||
|
LL_GPIO_ResetOutputPin(GPIOA, PIN_CS);
|
||||||
|
|
||||||
|
write_byte(cmd);
|
||||||
|
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// lcd_write_data()
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_write_data(int len, const uint8_t *pixels)
|
||||||
|
{
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||||
|
LL_GPIO_ResetOutputPin(GPIOA, PIN_CS);
|
||||||
|
|
||||||
|
write_bytes(len, pixels);
|
||||||
|
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_write_constant()
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_write_constant(int len, const uint16_t pixel)
|
||||||
|
{
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||||
|
LL_GPIO_ResetOutputPin(GPIOA, PIN_CS);
|
||||||
|
|
||||||
|
write_uint16(len, pixel);
|
||||||
|
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_write_cmd4()
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
lcd_write_cmd4(uint8_t cmd, uint16_t a, uint16_t b)
|
||||||
|
{
|
||||||
|
uint8_t d[4] = { (a>>8), a&0xff, (b>>8), b&0xff };
|
||||||
|
|
||||||
|
lcd_write_cmd(cmd);
|
||||||
|
lcd_write_data(4, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// lcd_write_data1()
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
lcd_write_data1(uint8_t data)
|
||||||
|
{
|
||||||
|
lcd_write_data(1, &data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// lcd_spi_setup()
|
||||||
|
//
|
||||||
|
// Just setup SPI, do not reset display, etc.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_setup(void)
|
||||||
|
{
|
||||||
|
LL_SPI_InitTypeDef init = { 0 };
|
||||||
|
|
||||||
|
// see SPI_InitTypeDef
|
||||||
|
init.TransferDirection = LL_SPI_HALF_DUPLEX_TX;
|
||||||
|
init.Mode = LL_SPI_MODE_MASTER;
|
||||||
|
init.DataWidth = LL_SPI_DATAWIDTH_8BIT;
|
||||||
|
init.ClockPolarity = LL_SPI_POLARITY_LOW;
|
||||||
|
init.ClockPhase = LL_SPI_PHASE_1EDGE;
|
||||||
|
init.NSS = LL_SPI_NSS_SOFT;
|
||||||
|
init.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2; // measured: 6 Mhz
|
||||||
|
init.BitOrder = LL_SPI_MSB_FIRST;
|
||||||
|
init.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
|
||||||
|
|
||||||
|
LL_SPI_Init(SPI1, &init);
|
||||||
|
LL_SPI_Enable(SPI1);
|
||||||
|
|
||||||
|
// usually want the busy bar
|
||||||
|
lcd_state.activity_bar = true;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// debug values
|
||||||
|
lcd_state.cursor_x = 9;
|
||||||
|
lcd_state.cursor_y = 2;
|
||||||
|
lcd_state.outline_cursor = true;
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
lcd_state.dbl_wide = true;
|
||||||
|
lcd_state.cursor_x = 16;
|
||||||
|
lcd_state.cursor_y = 4;
|
||||||
|
lcd_state.solid_cursor = true;
|
||||||
|
//lcd_state.outline_cursor = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// take_control()
|
||||||
|
//
|
||||||
|
// Make the shared SPI bus ours. All push-pull, because we need the speed.
|
||||||
|
// - force PIN_G_CTRL low while we are in control, so CPU knows we are actively
|
||||||
|
// speaking to the LCD
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
take_control(void)
|
||||||
|
{
|
||||||
|
LL_GPIO_SetOutputPin(GPIOA, PIN_GPU_BUSY);
|
||||||
|
|
||||||
|
LL_GPIO_InitTypeDef init = {0};
|
||||||
|
|
||||||
|
init.Pin = SPI_PINS;
|
||||||
|
init.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||||
|
init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
|
||||||
|
init.Pull = LL_GPIO_PULL_NO;
|
||||||
|
init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||||
|
init.Alternate = GPIO_AF0_SPI1;
|
||||||
|
|
||||||
|
LL_GPIO_Init(GPIOA, &init);
|
||||||
|
|
||||||
|
init.Pin = SPI_CTRL_PINS;
|
||||||
|
init.Mode = LL_GPIO_MODE_OUTPUT;
|
||||||
|
init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
|
||||||
|
init.Pull = LL_GPIO_PULL_NO;
|
||||||
|
init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||||
|
init.Alternate = 0;
|
||||||
|
|
||||||
|
LL_GPIO_Init(GPIOA, &init);
|
||||||
|
}
|
||||||
|
|
||||||
|
// release_control()
|
||||||
|
//
|
||||||
|
// Go back to being a listener only on SPI.
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
release_control(void)
|
||||||
|
{
|
||||||
|
// make all inputs again
|
||||||
|
LL_GPIO_InitTypeDef init = {0};
|
||||||
|
|
||||||
|
init.Pin = SPI_PINS | SPI_CTRL_PINS;
|
||||||
|
init.Mode = LL_GPIO_MODE_INPUT;
|
||||||
|
init.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||||
|
init.Pull = LL_GPIO_PULL_NO;
|
||||||
|
|
||||||
|
LL_GPIO_Init(GPIOA, &init);
|
||||||
|
|
||||||
|
LL_GPIO_ResetOutputPin(GPIOA, PIN_GPU_BUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send_window()
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
send_window(int x, int y, int w, int h, const void *data)
|
||||||
|
{
|
||||||
|
// write inclusive range
|
||||||
|
// note, MADCTL MV/MX/MY setting causes row vs. col swap here
|
||||||
|
lcd_write_cmd4(0x2a, x, x+w-1); // CASET - Column address set range (x)
|
||||||
|
lcd_write_cmd4(0x2b, y, y+h-1); // RASET - Row address set range (y)
|
||||||
|
lcd_write_cmd(0x2c); // RAMWR - memory write
|
||||||
|
|
||||||
|
if(data) {
|
||||||
|
// follow with data write of 2*w*h bytes
|
||||||
|
lcd_write_data(2*w*h, (uint8_t *)data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send_solid()
|
||||||
|
//
|
||||||
|
static void
|
||||||
|
send_solid(int x, int y, int w, int h, uint16_t pixel)
|
||||||
|
{
|
||||||
|
send_window(x, y, w, h, NULL);
|
||||||
|
|
||||||
|
lcd_write_constant(w*h, pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cursor_draw()
|
||||||
|
//
|
||||||
|
void
|
||||||
|
cursor_draw(int char_x, int char_y, uint8_t ctype, bool phase)
|
||||||
|
{
|
||||||
|
// see shared/lcd.py and shared/font_iosevka.py
|
||||||
|
const int LEFT_MARGIN = 7;
|
||||||
|
const int TOP_MARGIN = 15;
|
||||||
|
const int CHARS_W = 34;
|
||||||
|
const int CHARS_H = 10;
|
||||||
|
const int CELL_W = 9;
|
||||||
|
const int CELL_H = 22;
|
||||||
|
|
||||||
|
// no error reporting.. but dont die either
|
||||||
|
if(char_x >= CHARS_W) return;
|
||||||
|
if(char_y >= CHARS_H) return;
|
||||||
|
|
||||||
|
bool dbl_wide = ctype & 0x10;
|
||||||
|
ctype &= 0xf;
|
||||||
|
|
||||||
|
// top left corner, just on edge of character cell
|
||||||
|
int x = LEFT_MARGIN + (char_x * CELL_W);
|
||||||
|
int y = TOP_MARGIN + (char_y * CELL_H);
|
||||||
|
int cell_w = CELL_W + (dbl_wide?CELL_W:0);
|
||||||
|
|
||||||
|
uint16_t colour = phase ? COL_BLACK : COL_FOREGROUND;
|
||||||
|
|
||||||
|
if(ctype == CURSOR_OUTLINE) {
|
||||||
|
// horz
|
||||||
|
send_solid(x,y, cell_w, 1, colour);
|
||||||
|
send_solid(x,y+CELL_H-1, cell_w, 1, colour);
|
||||||
|
|
||||||
|
// vert
|
||||||
|
send_solid(x, y+1, 1, CELL_H-2, colour);
|
||||||
|
send_solid(x+cell_w-1, y+1, 1, CELL_H-2, colour);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctype == CURSOR_SOLID) {
|
||||||
|
if(!phase) {
|
||||||
|
// solid fill -- draw first time
|
||||||
|
send_solid(x,y, cell_w, CELL_H, COL_FOREGROUND);
|
||||||
|
} else {
|
||||||
|
// box shape, blank interior pixels
|
||||||
|
send_solid(x+1,y+1, cell_w-2, CELL_H-2, COL_BLACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ctype == CURSOR_MENU) {
|
||||||
|
// half-block
|
||||||
|
send_solid(x,y, 4, CELL_H, colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_fill_solid()
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_fill_solid(uint16_t pattern)
|
||||||
|
{
|
||||||
|
// whole screen
|
||||||
|
send_window(0, 0, LCD_WIDTH, LCD_HEIGHT, NULL);
|
||||||
|
lcd_write_constant(LCD_WIDTH*LCD_HEIGHT, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_draw_progress()
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_draw_progress(void)
|
||||||
|
{
|
||||||
|
static int phase = 0;
|
||||||
|
|
||||||
|
uint16_t row[LCD_WIDTH + NUM_PHASES + 1];
|
||||||
|
|
||||||
|
for(int i=0; i<numberof(row); i++) {
|
||||||
|
row[i] = ((i % 8) < 2) ? COL_BLACK : COL_FOREGROUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
send_window(0, PROG_Y, LCD_WIDTH, PROG_Y-LCD_HEIGHT, NULL);
|
||||||
|
|
||||||
|
for(int y=0; y<PROG_HEIGHT; y++) {
|
||||||
|
lcd_write_data(LCD_WIDTH*2, (uint8_t *)(&row[NUM_PHASES - phase - 1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
phase = (phase + 1) % NUM_PHASES;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_animate()
|
||||||
|
//
|
||||||
|
// Called at LCD frame rate, when we have control over LCD.
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_animate(void)
|
||||||
|
{
|
||||||
|
take_control();
|
||||||
|
|
||||||
|
if(lcd_state.test_pattern) {
|
||||||
|
lcd_test_pattern();
|
||||||
|
lcd_state.test_pattern = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lcd_state.activity_bar) {
|
||||||
|
lcd_draw_progress();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(lcd_state.cursor_type != NO_CURSOR) {
|
||||||
|
static int cur_phase;
|
||||||
|
|
||||||
|
if(cur_phase == 0) {
|
||||||
|
cursor_draw(lcd_state.cursor_x, lcd_state.cursor_y,
|
||||||
|
lcd_state.cursor_type, lcd_state.cur_flash);
|
||||||
|
|
||||||
|
lcd_state.cur_flash = !lcd_state.cur_flash;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_phase = (cur_phase+1) % 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_control();
|
||||||
|
}
|
||||||
|
|
||||||
|
// lcd_test_pattern()
|
||||||
|
//
|
||||||
|
void
|
||||||
|
lcd_test_pattern(void)
|
||||||
|
{
|
||||||
|
// NOTE: this is very limited so it cannot be abused to show arbitrary things
|
||||||
|
// - take packed pixels in (blk/white)
|
||||||
|
// - draw them centered w/ red side border
|
||||||
|
// - repeat same pattern bunch of times.
|
||||||
|
// - used for a linear barcode in selftest process
|
||||||
|
// - important: this cannot render a QR code, nor misleading text.
|
||||||
|
// - LATER: let's just make fully static instead.
|
||||||
|
|
||||||
|
STATIC_ASSERT(sizeof(test_barcode) == LCD_WIDTH/8);
|
||||||
|
|
||||||
|
uint16_t row[LCD_WIDTH];
|
||||||
|
for(int i=0, x=0; i<sizeof(test_barcode); i++) {
|
||||||
|
for(uint8_t m=0x80; m; m >>= 1) {
|
||||||
|
row[x++] = (test_barcode[i] & m) ? COL_BLACK : COL_WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int y = 40, h = 120;
|
||||||
|
send_window(0, y, LCD_WIDTH, h, NULL);
|
||||||
|
|
||||||
|
for(int i=0; i<h; i++) {
|
||||||
|
lcd_write_data(sizeof(row), (uint8_t *)&row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EOF
|
||||||
30
misc/gpu/lcd.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
static const uint8_t NO_CURSOR = 0;
|
||||||
|
static const uint8_t CURSOR_SOLID = 0x01;
|
||||||
|
static const uint8_t CURSOR_OUTLINE = 0x02;
|
||||||
|
static const uint8_t CURSOR_MENU = 0x03;
|
||||||
|
static const uint8_t CURSOR_DW_OUTLINE = 0x11;
|
||||||
|
static const uint8_t CURSOR_DW_SOLID = 0x12;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool activity_bar:1;
|
||||||
|
bool test_pattern:1; // self clearing
|
||||||
|
|
||||||
|
bool cur_flash:1; // clear when changing pos/type/enable
|
||||||
|
uint8_t cursor_type;
|
||||||
|
|
||||||
|
uint8_t cursor_x, cursor_y;
|
||||||
|
} lcd_state_t;
|
||||||
|
|
||||||
|
extern lcd_state_t lcd_state;
|
||||||
|
|
||||||
|
void lcd_setup(void);
|
||||||
|
void lcd_animate(void);
|
||||||
|
void lcd_test_pattern(void);
|
||||||
|
|
||||||
|
// EOF
|
||||||
213
misc/gpu/link-script.ld
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* a specialized linker script:
|
||||||
|
* - limits itself to just part of the device
|
||||||
|
* - assumes only a small amount of ram is available.
|
||||||
|
* - reference: <https://sourceware.org/binutils/docs/ld/>
|
||||||
|
* - spaces actually matter in expressions in this file
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||||
|
OUTPUT_ARCH(arm)
|
||||||
|
SEARCH_DIR(.)
|
||||||
|
|
||||||
|
/* Memory Spaces Definitions */
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH (rx) : ORIGIN = GPU_FLASH_BASE, LENGTH = GPU_FLASH_SIZE
|
||||||
|
RAM (rwx) : ORIGIN = GPU_SRAM_BASE, LENGTH = GPU_SRAM_SIZE
|
||||||
|
}
|
||||||
|
|
||||||
|
/* from /Applications/ARM/share/gcc-arm-none-eabi/samples/ldscripts/gcc.ld */
|
||||||
|
|
||||||
|
/* Linker script to place sections and symbol values. Should be used together
|
||||||
|
* with other linker script that defines memory regions FLASH and RAM.
|
||||||
|
* It references following symbols, which must be defined in code:
|
||||||
|
* Reset_Handler : Entry of reset handler
|
||||||
|
*
|
||||||
|
* It defines following symbols, which code can use without definition:
|
||||||
|
* __exidx_start
|
||||||
|
* __exidx_end
|
||||||
|
* __copy_table_start__
|
||||||
|
* __copy_table_end__
|
||||||
|
* __zero_table_start__
|
||||||
|
* __zero_table_end__
|
||||||
|
* __etext
|
||||||
|
* __data_start__
|
||||||
|
* __preinit_array_start
|
||||||
|
* __preinit_array_end
|
||||||
|
* __init_array_start
|
||||||
|
* __init_array_end
|
||||||
|
* __fini_array_start
|
||||||
|
* __fini_array_end
|
||||||
|
* __data_end__
|
||||||
|
* __bss_start__
|
||||||
|
* __bss_end__
|
||||||
|
* __end__
|
||||||
|
* end
|
||||||
|
* __HeapLimit
|
||||||
|
* __StackLimit
|
||||||
|
* __StackTop
|
||||||
|
* __stack
|
||||||
|
*/
|
||||||
|
ENTRY(Reset_Handler)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
KEEP(*(.isr_vector))
|
||||||
|
*(.text*)
|
||||||
|
|
||||||
|
KEEP(*(.init))
|
||||||
|
KEEP(*(.fini))
|
||||||
|
|
||||||
|
/* .ctors */
|
||||||
|
*crtbegin.o(.ctors)
|
||||||
|
*crtbegin?.o(.ctors)
|
||||||
|
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||||
|
*(SORT(.ctors.*))
|
||||||
|
*(.ctors)
|
||||||
|
|
||||||
|
/* .dtors */
|
||||||
|
*crtbegin.o(.dtors)
|
||||||
|
*crtbegin?.o(.dtors)
|
||||||
|
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||||
|
*(SORT(.dtors.*))
|
||||||
|
*(.dtors)
|
||||||
|
|
||||||
|
*(.rodata*)
|
||||||
|
|
||||||
|
KEEP(*(.eh_frame*))
|
||||||
|
} > FLASH
|
||||||
|
|
||||||
|
.ARM.extab :
|
||||||
|
{
|
||||||
|
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||||
|
} > FLASH
|
||||||
|
|
||||||
|
__exidx_start = .;
|
||||||
|
.ARM.exidx :
|
||||||
|
{
|
||||||
|
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||||
|
} > FLASH
|
||||||
|
__exidx_end = .;
|
||||||
|
|
||||||
|
/* To copy multiple ROM to RAM sections,
|
||||||
|
* uncomment .copy.table section and,
|
||||||
|
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||||
|
/*
|
||||||
|
.copy.table :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
__copy_table_start__ = .;
|
||||||
|
LONG (__etext)
|
||||||
|
LONG (__data_start__)
|
||||||
|
LONG (__data_end__ - __data_start__)
|
||||||
|
LONG (__etext2)
|
||||||
|
LONG (__data2_start__)
|
||||||
|
LONG (__data2_end__ - __data2_start__)
|
||||||
|
__copy_table_end__ = .;
|
||||||
|
} > FLASH
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* To clear multiple BSS sections,
|
||||||
|
* uncomment .zero.table section and,
|
||||||
|
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||||
|
/*
|
||||||
|
.zero.table :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
__zero_table_start__ = .;
|
||||||
|
LONG (__bss_start__)
|
||||||
|
LONG (__bss_end__ - __bss_start__)
|
||||||
|
LONG (__bss2_start__)
|
||||||
|
LONG (__bss2_end__ - __bss2_start__)
|
||||||
|
__zero_table_end__ = .;
|
||||||
|
} > FLASH
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Location counter can end up 2byte aligned with narrow Thumb code but
|
||||||
|
__etext is assumed by startup code to be the LMA of a section in RAM
|
||||||
|
which must be 4byte aligned */
|
||||||
|
__etext = ALIGN (4);
|
||||||
|
|
||||||
|
.data : AT (__etext)
|
||||||
|
{
|
||||||
|
__data_start__ = .;
|
||||||
|
*(vtable)
|
||||||
|
*(.data*)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* preinit data */
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP(*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* init data */
|
||||||
|
PROVIDE_HIDDEN (__init_array_start = .);
|
||||||
|
KEEP(*(SORT(.init_array.*)))
|
||||||
|
KEEP(*(.init_array))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* finit data */
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP(*(SORT(.fini_array.*)))
|
||||||
|
KEEP(*(.fini_array))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
|
||||||
|
KEEP(*(.jcr*))
|
||||||
|
. = ALIGN(4);
|
||||||
|
/* All data end */
|
||||||
|
__data_end__ = .;
|
||||||
|
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
__bss_start__ = .;
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
__bss_end__ = .;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
.heap (COPY):
|
||||||
|
{
|
||||||
|
__end__ = .;
|
||||||
|
PROVIDE(end = .);
|
||||||
|
*(.heap*)
|
||||||
|
__HeapLimit = .;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||||
|
* used for linker to calculate size of stack sections, and assign
|
||||||
|
* values to stack symbols later */
|
||||||
|
.stack_dummy (COPY):
|
||||||
|
{
|
||||||
|
*(.stack*)
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
/* Set stack top to end of RAM, and stack limit move down by
|
||||||
|
* size of stack_dummy section */
|
||||||
|
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||||
|
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||||
|
PROVIDE(__stack = __StackTop);
|
||||||
|
|
||||||
|
/* Check if data + heap + stack exceeds RAM limit */
|
||||||
|
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||||
|
|
||||||
|
/* my values for startup.S code inhirited */
|
||||||
|
PROVIDE(_estack = __StackTop);
|
||||||
|
PROVIDE(_sidata = __init_array_start); /* start address for the init values of the .data section. */
|
||||||
|
PROVIDE(_sdata = __data_start__); /* start address for the .data section. */
|
||||||
|
PROVIDE(_edata = __data_end__); /* end address for the .data section. */
|
||||||
|
PROVIDE(_sbss = __bss_start__); /* start address for the .bss section. */
|
||||||
|
PROVIDE(_ebss = __bss_end__); /* end address for the .bss section. */
|
||||||
|
|
||||||
|
}
|
||||||