1 // Copyright 2018 Chia Network Inc
2
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <set>
16 #include <ctime>
17
18 #include "../lib/include/picosha2.hpp"
19 #include "../lib/include/cxxopts.hpp"
20
21 #include "plotter_disk.hpp"
22 #include "prover_disk.hpp"
23 #include "verifier.hpp"
24
HexToBytes(const string & hex,uint8_t * result)25 void HexToBytes(const string& hex, uint8_t* result) {
26 for (uint32_t i = 0; i < hex.length(); i += 2) {
27 string byteString = hex.substr(i, 2);
28 uint8_t byte = (uint8_t) strtol(byteString.c_str(), NULL, 16);
29 result[i/2] = byte;
30 }
31 }
32
intToBytes(uint32_t paramInt,uint32_t numBytes)33 vector<unsigned char> intToBytes(uint32_t paramInt, uint32_t numBytes) {
34 vector<unsigned char> arrayOfByte(numBytes, 0);
35 for (uint32_t i = 0; paramInt > 0; i++) {
36 arrayOfByte[numBytes - i - 1] = paramInt & 0xff;
37 paramInt >>= 8;
38 }
39 return arrayOfByte;
40 }
41
Strip0x(const string & hex)42 string Strip0x(const string& hex) {
43 if (hex.substr(0, 2) == "0x" || hex.substr(0, 2) == "0X") {
44 return hex.substr(2);
45 }
46 return hex;
47 }
48
HelpAndQuit(cxxopts::Options options)49 void HelpAndQuit(cxxopts::Options options) {
50 cout << options.help({""}) << endl;
51 cout << "./ProofOfSpace generate" << endl;
52 cout << "./ProofOfSpace prove <challenge>" << endl;
53 cout << "./ProofOfSpace verify <challenge> <proof>" << endl;
54 cout << "./ProofOfSpace check" << endl;
55 exit(0);
56 }
57
main(int argc,char * argv[])58 int main(int argc, char *argv[]) {
59 try {
60 cxxopts::Options options("ProofOfSpace", "Utility for plotting, generating and verifying proofs of space.");
61 options.positional_help("(generate/prove/verify/check) param1 param2 ")
62 .show_positional_help();
63
64 // Default values
65 uint8_t k = 20;
66 string filename = "plot.dat";
67 string operation = "help";
68 string memo = "0102030405";
69 string id = "022fb42c08c12de3a6af053880199806532e79515f94e83461612101f9412f9e";
70
71 options.allow_unrecognised_options()
72 .add_options()
73 ("k, size", "Plot size", cxxopts::value<uint8_t>(k))
74 ("f, file", "Filename", cxxopts::value<string>(filename))
75 ("m, memo", "Memo to insert into the plot", cxxopts::value<string>(memo))
76 ("i, id", "Unique 32-byte id for the plot", cxxopts::value<string>(id))
77 ("help", "Print help");
78
79 auto result = options.parse(argc, argv);
80
81 if (result.count("help") || argc < 2) {
82 HelpAndQuit(options);
83 }
84 operation = argv[1];
85
86 if (operation == "help") {
87 HelpAndQuit(options);
88 } else if (operation == "generate") {
89 cout << "Generating plot for k=" << static_cast<int>(k) << " filename="
90 << filename << " id=" << id << endl << endl;
91 if (id.size() != 64) {
92 cout << "Invalid ID, should be 32 bytes" << endl;
93 exit(1);
94 }
95 memo = Strip0x(memo);
96 id = Strip0x(id);
97 uint8_t memo_bytes[memo.size() / 2];
98 uint8_t id_bytes[32];
99
100 HexToBytes(memo, memo_bytes);
101 HexToBytes(id, id_bytes);
102
103 DiskPlotter plotter = DiskPlotter();
104 plotter.CreatePlotDisk(filename, k, memo_bytes, 5, id_bytes, 32);
105 } else if (operation == "prove") {
106 if (argc < 3) {
107 HelpAndQuit(options);
108 }
109 cout << "Proving using filename=" << filename << " challenge=" << argv[2] << endl << endl;
110 string challenge = Strip0x(argv[2]);
111 if (challenge.size() != 64) {
112 cout << "Invalid challenge, should be 32 bytes" << endl;
113 exit(1);
114 }
115 uint8_t challenge_bytes[32];
116 HexToBytes(challenge, challenge_bytes);
117
118 DiskProver prover(filename);
119 vector<LargeBits> qualities = prover.GetQualitiesForChallenge(challenge_bytes);
120 for (uint32_t i = 0; i < qualities.size(); i++) {
121 k = qualities[i].GetSize() / 2;
122 uint8_t proof_data[8 * k];
123 LargeBits proof = prover.GetFullProof(challenge_bytes, i);
124 proof.ToBytes(proof_data);
125 cout << "Proof: 0x" << Util::HexStr(proof_data, k * 8) << endl;
126 }
127 if (qualities.empty()) {
128 cout << "No proofs found." << endl;
129 exit(1);
130 }
131 } else if (operation == "verify") {
132 if (argc < 4) {
133 HelpAndQuit(options);
134 }
135 cout << "Verifying proof=" << argv[2] << " for challenge=" << argv[3] << " and k="
136 << static_cast<int>(k) << endl << endl;
137 Verifier verifier = Verifier();
138
139 id = Strip0x(id);
140 string proof = Strip0x(argv[2]);
141 string challenge = Strip0x(argv[3]);
142 if (id.size() != 64) {
143 cout << "Invalid ID, should be 32 bytes" << endl;
144 exit(1);
145 }
146 if (challenge.size() != 64) {
147 cout << "Invalid challenge, should be 32 bytes" << endl;
148 exit(1);
149 }
150 uint8_t id_bytes[32];
151 uint8_t challenge_bytes[32];
152 uint8_t proof_bytes[proof.size() / 2];
153 HexToBytes(id, id_bytes);
154 HexToBytes(challenge, challenge_bytes);
155 HexToBytes(proof, proof_bytes);
156
157 LargeBits quality = verifier.ValidateProof(id_bytes, k, challenge_bytes, proof_bytes, k*8);
158 if (quality.GetSize() == 2*k) {
159 cout << "Proof verification suceeded. Quality: " << quality << endl;
160 } else {
161 cout << "Proof verification failed." << endl;
162 exit(1);
163 }
164 } else if (operation == "check") {
165 uint32_t iterations = 1000;
166 if (argc == 3) {
167 iterations = stoi(argv[2]);
168 }
169
170 DiskProver prover(filename);
171 Verifier verifier = Verifier();
172
173 uint32_t success = 0;
174 id = Strip0x(id);
175 uint8_t id_bytes[32];
176 HexToBytes(id, id_bytes);
177
178 for (uint32_t num = 0; num < iterations; num++) {
179 vector<unsigned char> hash_input = intToBytes(num, 4);
180 vector<unsigned char> hash(picosha2::k_digest_size);
181 picosha2::hash256(hash_input.begin(), hash_input.end(), hash.begin(), hash.end());
182
183 vector<LargeBits> qualities = prover.GetQualitiesForChallenge(hash.data());
184 for (uint32_t i = 0; i < qualities.size(); i++) {
185 k = qualities[i].GetSize() / 2;
186 LargeBits proof = prover.GetFullProof(hash.data(), i);
187 uint8_t proof_data[proof.GetSize() / 8];
188 proof.ToBytes(proof_data);
189 cout << "i: " << num << " Proof: 0x" << Util::HexStr(proof_data, k * 8) << endl;
190 LargeBits quality = verifier.ValidateProof(id_bytes, k, hash.data(), proof_data, k*8);
191 if (quality.GetSize() == 2*k) {
192 cout << "Proof verification suceeded. k = " << static_cast<int>(k)
193 << " Quality: " << quality << endl;
194 success++;
195 } else {
196 cout << "Proof verification failed." << endl;
197 exit(1);
198 }
199 }
200 }
201 std::cout << "Total success: " << success << "/" << iterations << ", " <<
202 (success/static_cast<double>(iterations)) << "%." << std::endl;
203 } else {
204 cout << "Invalid operation. Use generate/prove/verify/check" << endl;
205 }
206 exit(0);
207 } catch (const cxxopts::OptionException& e) {
208 cout << "error parsing options: " << e.what() << endl;
209 exit(1);
210 }
211 }
212