HashType generate_hmac(const data_chunk& key, const data_chunk& data, std::function<HashType (const data_chunk&)> hash_func) { typedef typename HashType::value_type hash_char; std::array<hash_char, block_size> fixed_key; // Zero out std::fill(fixed_key.begin(), fixed_key.end(), 0); // Now copy key or hash into zeroed out buffer if (key.size() <= block_size) { std::copy(key.begin(), key.end(), fixed_key.begin()); } else { HashType fixed_key_digest = hash_func(key); BITCOIN_ASSERT(fixed_key.size() >= fixed_key_digest.size()); std::copy(fixed_key_digest.begin(), fixed_key_digest.end(), fixed_key.begin()); } // hash(o_key_pad + hash(i_key_pad + data)) // Work on inner section first data_chunk inner_data(fixed_key.size() + data.size()); // xor each digit of key... std::transform(fixed_key.begin(), fixed_key.end(), inner_data.begin(), [](hash_char digit) { return digit ^ 0x36; }); // ... and append the data. std::copy(data.begin(), data.end(), inner_data.begin() + fixed_key.size()); HashType inner_hash = hash_func(inner_data); // Work on outer section data_chunk outer_data(fixed_key.size() + inner_hash.size()); // xor each digit of key... std::transform(fixed_key.begin(), fixed_key.end(), outer_data.begin(), [](hash_char digit) { return digit ^ 0x5c; }); // ... and combine with inner_hash to get outer_data. std::copy(inner_hash.begin(), inner_hash.end(), outer_data.begin() + fixed_key.size()); return hash_func(outer_data); }
void BIO::WriteWithRetry(const data_chunk& data2wr) const { unsigned int written = 0; do { try { data_chunk tmp; tmp.insert(tmp.end(), data2wr.begin() + written, data2wr.end()); written += doWrite(tmp, written); } catch (RecoverableException& ex) { } } while (written < data2wr.size()); }
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 { BITCOIN_ASSERT(data.size() <= 0xffffffff); op.code = opcode::pushdata4; } op.data = data; script tmp_script; tmp_script.push_operation(op); extend_data(raw_script, save_script(tmp_script)); }
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; }
int mmr_lookup(const data_chunk& key_data, const size_t value_size, const std::string& map_filename, const std::string& rows_filename) { typedef byte_array<KeySize> hash_type; hash_type key; BITCOIN_ASSERT(key.size() == key_data.size()); std::copy(key_data.begin(), key_data.end(), key.begin()); memory_map ht_file(map_filename); BITCOIN_ASSERT(ht_file.open()); record_hash_table_header header(ht_file, buckets); auto result = header.start(); BITCOIN_ASSERT(result); const auto record_size = hash_table_multimap_record_size<hash_type>(); BITCOIN_ASSERT(record_size == KeySize + 4 + 4); const auto header_size = record_hash_table_header_size(header.size()); const file_offset records_start = header_size; record_manager ht_manager(ht_file, records_start, record_size); result = ht_manager.start(); BITCOIN_ASSERT(result); memory_map lrs_file(rows_filename); BITCOIN_ASSERT(lrs_file.open()); const auto lrs_record_size = record_list_offset + value_size; record_manager lrs_manager(lrs_file, 0, lrs_record_size); result = lrs_manager.start(); BITCOIN_ASSERT(result); record_list lrs(lrs_manager); record_hash_table<hash_type> ht(header, ht_manager); record_multimap<hash_type> multimap(ht, lrs); record_multimap_iterable container(lrs, multimap.lookup(key)); for (const array_index index: container) { std::cout << "Index: " << index << std::endl; const auto memory = lrs_manager.get(index); const auto record = REMAP_ADDRESS(memory) + record_list_offset; const data_chunk data(record, record + value_size); std::cout << encode_base16(data) << std::endl; std::cout << std::endl; } return 0; }
bool payment_address::set_encoded(const std::string& encoded_address) { if (!is_base58(encoded_address)) return false; const data_chunk decoded_address = decode_base58(encoded_address); // version + 20 bytes short hash + 4 bytes checksum if (decoded_address.size() != 25) return false; if (!verify_checksum(decoded_address)) return false; version_ = decoded_address[0]; std::copy_n(decoded_address.begin() + 1, hash_.size(), hash_.begin()); return true; }
std::string encode_base58(const data_chunk& unencoded_data) { std::string encoded_data; // Expected size increase from base58 conversion is approximately 137% // use 138% to be safe encoded_data.reserve((unencoded_data.size() - 1) * 138 / 100 + 1); // Convert big endian data to little endian // Extra zero at the end make sure bignum will interpret // as a positive number data_chunk tmp_data(unencoded_data.size() + 1, 0); std::reverse_copy(unencoded_data.begin(), unencoded_data.end(), tmp_data.begin()); big_number long_value; long_value.set_data(tmp_data); while (long_value > 0) { auto result = divmod(long_value, 58); long_value = result.first; size_t remainder = result.second.uint32(); encoded_data += base58_chars[remainder]; } // Leading zeroes encoded as base58 zeros for (const uint8_t unencoded_byte: unencoded_data) { if (unencoded_byte != 0) break; encoded_data += base58_chars[0]; } // Convert little endian std::string to big endian reverse(encoded_data.begin(), encoded_data.end()); return encoded_data; }
void AppendChecksum(data_chunk& data) { uint32_t checksum = BitcoinChecksum(&data[0], data.size()); // -- to_little_endian std::vector<uint8_t> tmp(4); //memcpy(&tmp[0], &checksum, 4); for (int i = 0; i < 4; ++i) { tmp[i] = checksum & 0xFF; checksum >>= 8; }; data.insert(data.end(), tmp.begin(), tmp.end()); };
short_hash generate_ripemd_hash(const data_chunk& chunk) { hash_digest sha_hash; SHA256_CTX sha_ctx; SHA256_Init(&sha_ctx); SHA256_Update(&sha_ctx, &chunk[0], chunk.size()); SHA256_Final(sha_hash.data(), &sha_ctx); short_hash ripemd_hash; RIPEMD160_CTX ripemd_ctx; RIPEMD160_Init(&ripemd_ctx); RIPEMD160_Update(&ripemd_ctx, sha_hash.data(), SHA256_DIGEST_LENGTH); RIPEMD160_Final(ripemd_hash.data(), &ripemd_ctx); return ripemd_hash; }
void proxy::do_send(const data_chunk& message, handler handler, const std::string& command) { if (stopped()) { handler(error::channel_stopped); return; } log_debug(LOG_NETWORK) << "Send " << command << " [" << address() << "] (" << message.size() << " bytes)"; const shared_const_buffer buffer(message); async_write(*socket_, buffer, std::bind(&proxy::call_handle_send, shared_from_this(), _1, handler)); }
bool payment_address::set_encoded(const std::string& encoded_address) { const data_chunk decoded_address = decode_base58(encoded_address); // version + 20 bytes short hash + 4 bytes checksum if (decoded_address.size() != 25) return false; const uint8_t version = decoded_address[0]; if (!set_version(version)) return false; const data_chunk checksum_bytes( decoded_address.end() - 4, decoded_address.end()); // version + short hash const data_chunk main_body( decoded_address.begin(), decoded_address.end() - 4); // verify checksum bytes if (generate_sha256_checksum(main_body) != cast_chunk<uint32_t>(checksum_bytes)) return false; std::copy(main_body.begin() + 1, main_body.end(), hash_.begin()); return true; }
BCW_API bool hd_public_key::set_serialized(std::string encoded) { if (!is_base58(encoded)) return false; const data_chunk decoded = decode_base58(encoded); if (decoded.size() != serialized_length) return false; if (!verify_checksum(decoded)) return false; auto ds = make_deserializer(decoded.begin(), decoded.end()); auto prefix = ds.read_big_endian<uint32_t>(); if (prefix != mainnet_public_prefix && prefix != testnet_public_prefix) return false; valid_ = true; lineage_.testnet = prefix == testnet_public_prefix; lineage_.depth = ds.read_byte(); lineage_.parent_fingerprint = ds.read_little_endian<uint32_t>(); lineage_.child_number = ds.read_big_endian<uint32_t>(); c_ = ds.read_bytes<chain_code_size>(); K_ = ds.read_data(33); return true; }
long_hash sha512_hash(const data_chunk& chunk) { long_hash hash; SHA512__(chunk.data(), chunk.size(), hash.data()); return hash; }
hash_digest sha256_hash(const data_chunk& chunk) { hash_digest hash; SHA256__(chunk.data(), chunk.size(), hash.data()); return hash; }
short_hash sha1_hash(const data_chunk& chunk) { short_hash hash; SHA1(chunk.data(), chunk.size(), hash.data()); return hash; }
short_hash ripemd160_hash(const data_chunk& chunk) { short_hash hash; RMD160(chunk.data(), chunk.size(), hash.data()); return hash; }
int verifyRingSignatureAB(data_chunk &keyImage, uint256 &txnHash, int nRingSize, const uint8_t *pPubkeys, const data_chunk &sigC, const uint8_t *pSigS) { // https://bitcointalk.org/index.php?topic=972541.msg10619684 // forall_{i=1..n} compute e_i=s_i*G+c_i*P_i and E_i=s_i*H(P_i)+c_i*I_j and c_{i+1}=h(P_1,...,P_n,e_i,E_i) // check c_{n+1}=c_1 if (fDebugRingSig) { //LogPrintf("%s size %d\n", __func__, nRingSize); // happens often }; if (sigC.size() != EC_SECRET_SIZE) return errorN(1, "%s: sigC size != EC_SECRET_SIZE.", __func__); if (keyImage.size() != EC_COMPRESSED_SIZE) return errorN(1, "%s: keyImage size != EC_COMPRESSED_SIZE.", __func__); int rv = 0; uint256 tmpPkHash; uint256 tmpHash; uint8_t tempData[66]; // hold raw point data to hash CHashWriter ssPkHash(SER_GETHASH, PROTOCOL_VERSION); CHashWriter ssCjHash(SER_GETHASH, PROTOCOL_VERSION); for (int i = 0; i < nRingSize; ++i) { ssPkHash.write((const char*)&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE); }; tmpPkHash = ssPkHash.GetHash(); BN_CTX_start(bnCtx); BIGNUM *bnC = BN_CTX_get(bnCtx); BIGNUM *bnC1 = BN_CTX_get(bnCtx); BIGNUM *bnT = BN_CTX_get(bnCtx); BIGNUM *bnS = BN_CTX_get(bnCtx); EC_POINT *ptKi = NULL; EC_POINT *ptT1 = NULL; EC_POINT *ptT2 = NULL; EC_POINT *ptT3 = NULL; EC_POINT *ptPk = NULL; EC_POINT *ptSi = NULL; if ( !(ptKi = EC_POINT_new(ecGrp)) || !(ptT1 = EC_POINT_new(ecGrp)) || !(ptT2 = EC_POINT_new(ecGrp)) || !(ptT3 = EC_POINT_new(ecGrp)) || !(ptPk = EC_POINT_new(ecGrp)) || !(ptSi = EC_POINT_new(ecGrp))) { LogPrintf("%s: EC_POINT_new failed.\n", __func__); rv = 1; goto End; }; // get keyimage as point if (!EC_POINT_oct2point(ecGrp, ptKi, &keyImage[0], EC_COMPRESSED_SIZE, bnCtx)) { LogPrintf("%s: extract ptKi failed.\n", __func__); rv = 1; goto End; }; if (!bnC1 || !BN_bin2bn(&sigC[0], EC_SECRET_SIZE, bnC1)) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; if (!BN_copy(bnC, bnC1)) { LogPrintf("%s: BN_copy failed.\n", __func__); rv = 1; goto End; }; for (int i = 0; i < nRingSize; ++i) { if (!bnS || !(BN_bin2bn(&pSigS[i * EC_SECRET_SIZE], EC_SECRET_SIZE, bnS))) { LogPrintf("%s: BN_bin2bn failed.\n", __func__); rv = 1; goto End; }; // ptT2 <- pk if (!EC_POINT_oct2point(ecGrp, ptPk, &pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnCtx)) { LogPrintf("%s: EC_POINT_oct2point failed.\n", __func__); rv = 1; goto End; }; // ptT1 = e_i=s_i*G+c_i*P_i if (!EC_POINT_mul(ecGrp, ptT1, bnS, ptPk, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; if (!(EC_POINT_point2oct(ecGrp, ptT1, POINT_CONVERSION_COMPRESSED, &tempData[0], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptT1 failed.\n", __func__); rv = 1; goto End; }; // ptT2 =E_i=s_i*H(P_i)+c_i*I_j // ptT2 =H(P_i) if (hashToEC(&pPubkeys[i * EC_COMPRESSED_SIZE], EC_COMPRESSED_SIZE, bnT, ptT2) != 0) { LogPrintf("%s: hashToEC failed.\n", __func__); rv = 1; goto End; }; // DEBUGGING: ------- check if we can find the signer... // ptSi = Pi * bnT if ((!EC_POINT_mul(ecGrp, ptSi, NULL, ptPk, bnT, bnCtx) || false) && (rv = errorN(1, "%s: EC_POINT_mul failed.", __func__))) goto End; if (0 == EC_POINT_cmp(ecGrp, ptSi, ptKi, bnCtx) ) LogPrintf("signer is index %d\n", i); // DEBUGGING: - End - check if we can find the signer... // ptT3 = s_i*ptT2 if (!EC_POINT_mul(ecGrp, ptT3, NULL, ptT2, bnS, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT1 = c_i*I_j if (!EC_POINT_mul(ecGrp, ptT1, NULL, ptKi, bnC, bnCtx)) { LogPrintf("%s: EC_POINT_mul failed.\n", __func__); rv = 1; goto End; }; // ptT2 = ptT3 + ptT1 if (!EC_POINT_add(ecGrp, ptT2, ptT3, ptT1, bnCtx)) { LogPrintf("%s: EC_POINT_add failed.\n", __func__); rv = 1; goto End; }; if (!(EC_POINT_point2oct(ecGrp, ptT2, POINT_CONVERSION_COMPRESSED, &tempData[33], 33, bnCtx) == (int) EC_COMPRESSED_SIZE)) { LogPrintf("%s: extract ptT2 failed.\n", __func__); rv = 1; goto End; }; CHashWriter ssCHash(SER_GETHASH, PROTOCOL_VERSION); ssCHash.write((const char*)tmpPkHash.begin(), 32); ssCHash.write((const char*)&tempData[0], 66); tmpHash = ssCHash.GetHash(); if (!bnC || !(BN_bin2bn(tmpHash.begin(), EC_SECRET_SIZE, bnC)) || !BN_mod(bnC, bnC, bnOrder, bnCtx)) { LogPrintf("%s: tmpHash -> bnC failed.\n", __func__); rv = 1; goto End; }; }; // bnT = (bnC - bnC1) % N if (!BN_mod_sub(bnT, bnC, bnC1, bnOrder, bnCtx)) { LogPrintf("%s: BN_mod_sub failed.\n", __func__); rv = 1; goto End; }; // test bnT == 0 (bnC == bnC1) if (!BN_is_zero(bnT)) { LogPrintf("%s: signature does not verify.\n", __func__); rv = 2; }; End: BN_CTX_end(bnCtx); EC_POINT_free(ptKi); EC_POINT_free(ptT1); EC_POINT_free(ptT2); EC_POINT_free(ptT3); EC_POINT_free(ptPk); EC_POINT_free(ptSi); return rv; };
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; }