bool parse_token(data_chunk& raw_script, std::string token) { boost::algorithm::trim(token); // skip this if (token.empty()) return true; static data_chunk hex_raw; if (token == "ENDING" || !is_hex_data(token)) { if (!hex_raw.empty()) { extend_data(raw_script, hex_raw); hex_raw.resize(0); } } if (token == "ENDING") { // Do nothing... } else if (is_number(token)) { int64_t value = boost::lexical_cast<int64_t>(token); if (is_opx(value)) push_literal(raw_script, value); else { script_number bignum(value); push_data(raw_script, bignum.data()); } } else if (is_hex_data(token)) { std::string hex_part(token.begin() + 2, token.end()); data_chunk raw_data; if (!decode_base16(raw_data, hex_part)) return false; extend_data(hex_raw, raw_data); } else if (is_quoted_string(token)) { data_chunk inner_value(token.begin() + 1, token.end() - 1); push_data(raw_script, inner_value); } else if (is_opcode(token)) { opcode tokenized_opcode = token_to_opcode(token); raw_script.push_back(static_cast<uint8_t>(tokenized_opcode)); } else { log_error() << "Token parsing failed with: " << token; return false; } return true; }
int main(int argc, char** argv) { if (argc != 4) { std::cerr << "Usage: pp_unlock CHUNKFILE BLOCK_HASH PUBKEY" << std::endl; return -1; } const std::string chunk_filename = argv[1]; const data_chunk hash = decode_hex(argv[2]); if (hash.empty() || hash.size() != hash_size) { std::cerr << "pp_unlock: not a valid BLOCK_HASH." << std::endl; return -1; } const ec_point pubkey = decode_hex(argv[3]); if (pubkey.empty() || pubkey.size() != ec_compressed_size) { std::cerr << "pp_unlock: not a valid PUBKEY." << std::endl; return -1; } std::ifstream infile(chunk_filename, std::ifstream::binary); infile.seekg(0, std::ifstream::end); size_t file_size = infile.tellg(); BITCOIN_ASSERT(file_size % 16 == 0); infile.seekg(0, std::ifstream::beg); // Read entire file in. data_chunk cipher(file_size); // Copy chunk to public chunk file. char* data = reinterpret_cast<char*>(cipher.data()); infile.read(data, file_size); infile.close(); // Get seed. payment_address bid_addr = bidding_address(pubkey); hash_digest seed = derive_seed(pubkey); // Decrypt chunk. aes256_context ctx; BITCOIN_ASSERT(seed.size() == 32); aes256_init(&ctx, seed.data()); BITCOIN_ASSERT(cipher.size() % 16 == 0); for (size_t i = 0; i < cipher.size(); i += 16) aes256_decrypt_ecb(&ctx, cipher.data() + i); aes256_done(&ctx); // Write out. const fs::path new_chunk_filename = (chunk_filename + ".decrypted"); std::ofstream outfile(new_chunk_filename.native(), std::ifstream::binary); char* dec_data = reinterpret_cast<char*>(cipher.data()); outfile.write(dec_data, cipher.size()); return 0; }
bool parse_token(data_chunk& raw_script, const std::string& token) { static data_chunk hex_raw; if (token == "ENDING" || !is_hex_data(token)) { if (!hex_raw.empty()) { extend_data(raw_script, hex_raw); hex_raw.resize(0); } } if (token == "ENDING") { // Do nothing... } else if (is_number(token)) { int64_t value = boost::lexical_cast<int64_t>(token); if (is_opx(value)) push_literal(raw_script, value); else { big_number bignum; bignum.set_int64(value); push_data(raw_script, bignum.data()); } } else if (is_hex_data(token)) { std::string hex_part(token.begin() + 2, token.end()); data_chunk raw_data = bytes_from_pretty(hex_part); extend_data(hex_raw, raw_data); } else if (is_quoted_string(token)) { data_chunk inner_value(token.begin() + 1, token.end() - 1); push_data(raw_script, inner_value); } else if (is_opcode(token)) { opcode tokenized_opcode = token_to_opcode(token); raw_script.push_back(static_cast<byte>(tokenized_opcode)); } else { log_error() << "Token parsing failed with: " << token; return false; } return true; }
void push_data(data_chunk& raw_script, const data_chunk& data) { operation op; // pushdata1 = 76 if (data.empty()) op.code = opcode::zero; else if (data.size() < 76) op.code = opcode::special; else if (data.size() <= 0xff) op.code = opcode::pushdata1; else if (data.size() <= 0xffff) op.code = opcode::pushdata2; else { BOOST_REQUIRE_LE(data.size(), 0xffffffffu); op.code = opcode::pushdata4; } op.data = data; script_type tmp_script; tmp_script.push_operation(op); extend_data(raw_script, save_script(tmp_script)); }
int main(int argc, char** argv) { if (argc != 5) { std::cerr << "Usage: pp_prove DOCUMENT CHUNKS BLOCK_HASH REVEAL" << std::endl; return -1; } const fs::path doc_path = argv[1]; const std::string chunks_str = argv[2]; const std::string reveal_str = argv[4]; size_t chunks = 0, reveal = 0; try { chunks = boost::lexical_cast<size_t>(chunks_str); reveal = boost::lexical_cast<size_t>(reveal_str); } catch (const boost::bad_lexical_cast&) { std::cerr << "pp_start: bad CHUNKS or REVEAL provided." << std::endl; return -1; } const data_chunk hash = decode_hex(argv[3]); if (hash.empty() || hash.size() != hash_size) { std::cerr << "pp_prove: not a valid BLOCK_HASH." << std::endl; return -1; } std::ifstream infile(doc_path.native(), std::ifstream::binary); infile.seekg(0, std::ifstream::end); size_t file_size = infile.tellg(); infile.seekg(0, std::ifstream::beg); size_t chunk_size = file_size / chunks; // AES works on blocks of 16 bytes. Round up to nearest multiple. chunk_size += 16 - (chunk_size % 16); BITCOIN_ASSERT(chunk_size % 16 == 0); //std::cout << "Creating chunks of " // << chunk_size << " bytes each." << std::endl; ec_point_list all_pubkeys; while (infile) { data_chunk buffer(chunk_size); // Copy chunk to public chunk file. char* data = reinterpret_cast<char*>(buffer.data()); infile.read(data, chunk_size); // Create a seed. BITCOIN_ASSERT(ec_secret_size == hash_size); ec_secret secret = bitcoin_hash(buffer); ec_point pubkey = secret_to_public_key(secret); // Once we spend funds, we reveal the decryption pubkey. all_pubkeys.push_back(pubkey); } // Beginning bytes of block hash are zero, so use end bytes. std::seed_seq seq(hash.rbegin(), hash.rend()); index_list random_values(reveal); seq.generate(random_values.begin(), random_values.end()); for (size_t value: random_values) { size_t index = value % all_pubkeys.size(); std::cout << (index + 1) << " " << all_pubkeys[index] << std::endl; } return 0; }