BCW_API bool hd_private_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_private_prefix && prefix != testnet_private_prefix) return false; valid_ = true; lineage_.testnet = prefix == testnet_private_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>(); ds.read_byte(); k_ = ds.read_bytes<ec_secret_size>(); K_ = secret_to_public_key(k_); return true; }
script parse_script(const data_chunk& raw_script) { script script_object; for (auto it = raw_script.begin(); it != raw_script.end(); ++it) { byte raw_byte = *it; operation op; op.code = static_cast<opcode>(raw_byte); // raw_byte is unsigned so it's always >= 0 if (raw_byte <= 75) op.code = opcode::special; size_t read_n_bytes = number_of_bytes_from_opcode(op.code, raw_byte); for (size_t byte_count = 0; byte_count < read_n_bytes; ++byte_count) { ++it; if (it == raw_script.cend()) { log_warning() << "Premature end of script."; return script(); } op.data.push_back(*it); } script_object.push_operation(op); } return script_object; }
BC_API void obelisk_codec::message(const data_chunk& data, bool more) { switch (next_part_) { case command_part: wip_message_.command = std::string(data.begin(), data.end()); break; case id_part: if (4 != data.size()) { next_part_ = error_part; break; } wip_message_.id = from_little_endian<uint32_t>(data.begin(), data.end()); break; case payload_part: wip_message_.payload = data; break; case error_part: break; } if (!more) { if (next_part_ == payload_part) receive(wip_message_); else on_unknown_(wip_message_.command); next_part_ = command_part; } else if (next_part_ < error_part) next_part_ = static_cast<message_part>(next_part_ + 1); }
std::string encode_base58(const data_chunk& unencoded) { size_t leading_zeros = count_leading_zeros(unencoded); // size = log(256) / log(58), rounded up. const size_t number_nonzero = unencoded.size() - leading_zeros; const size_t indexes_size = number_nonzero * 138 / 100 + 1; // Allocate enough space in big-endian base58 representation. data_chunk indexes(indexes_size); // Process the bytes. for (auto it = unencoded.begin() + leading_zeros; it != unencoded.end(); ++it) { pack_value(indexes, *it); } // Skip leading zeroes in base58 result. auto first_nonzero = search_first_nonzero(indexes); // Translate the result into a string. std::string encoded; const size_t estimated_size = leading_zeros + (indexes.end() - first_nonzero); encoded.reserve(estimated_size); encoded.assign(leading_zeros, '1'); // Set actual main bytes. for (auto it = first_nonzero; it != indexes.end(); ++it) { const size_t index = *it; encoded += base58_chars[index]; } return encoded; }
void wrap_fetch_transaction_args(data_chunk& data, const hash_digest& tx_hash) { data.resize(hash_digest_size); auto serial = make_serializer(data.begin()); serial.write_hash(tx_hash); BITCOIN_ASSERT(serial.iterator() == data.end()); }
bool validate_block::coinbase_height_match() { // There are old blocks with version incorrectly set to 2. Ignore them. if (height_ < max_version1_height) return true; // Checks whether the block height is in the coinbase tx input script. // Version 2 blocks and onwards. BITCOIN_ASSERT(current_block_.header.version >= 2); BITCOIN_ASSERT(current_block_.transactions.size() > 0); BITCOIN_ASSERT(current_block_.transactions[0].inputs.size() > 0); // First get the serialized coinbase input script as a series of bytes. const auto& coinbase_tx = current_block_.transactions[0]; const auto& coinbase_script = coinbase_tx.inputs[0].script; const auto raw_coinbase = save_script(coinbase_script); // Try to recreate the expected bytes. script_type expect_coinbase; script_number expect_number(height_); expect_coinbase.push_operation({opcode::special, expect_number.data()}); // Save the expected coinbase script. const data_chunk expect = save_script(expect_coinbase); // Perform comparison of the first bytes with raw_coinbase. BITCOIN_ASSERT(expect.size() <= raw_coinbase.size()); return std::equal(expect.begin(), expect.end(), raw_coinbase.begin()); }
unsigned int BIO::doWrite(const data_chunk& data_to_write, int offset) const { int written = 0; int num2wr = data_to_write.size() - offset; assert(num2wr > 0); DBG << "Writing " << num2wr << "B - " << Utils::DataToString(data_to_write) << std::endl; if (num2wr == 0) { return 0; } for (;;) { written = BIO_write(itsBIO, &data_to_write.at(offset), num2wr); if (written <= 0) { if (this->ShouldRetry()) { std::string s("Recoverable error when writing to BIO"); if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { throw RecoverableException(s); } } std::string s("Fatal error when writing to BIO; "); s += Utils::getLastErrorSSL(); throw RemoteDiedException(s); } break; } DBG << "Written " << written << "B" << std::endl; return written; }
// Accepts only strings bounded to 5 characters. bool decode_base85(data_chunk& out, const std::string& in) { const size_t length = in.size(); if (length % 5 != 0) return false; const size_t decoded_size = length * 4 / 5; data_chunk decoded; decoded.reserve(decoded_size); size_t char_index = 0; uint32_t accumulator = 0; for (const uint8_t encoded_character: in) { const auto position = encoded_character - 32; if (position < 0 || position > 96) return false; accumulator = accumulator * 85 + decoder[position]; if (++char_index % 5 == 0) { for (uint32_t divise = 256 * 256 * 256; divise > 0; divise /= 256) decoded.push_back(accumulator / divise % 256); accumulator = 0; } } out.assign(decoded.begin(), decoded.end()); BITCOIN_ASSERT(out.size() == decoded_size); return true; }
data_chunk read_ephemkey(const data_chunk& stealth_data) { // Read ephemkey BITCOIN_ASSERT(stealth_data.size() == 1 + 4 + 33); data_chunk ephemkey(stealth_data.begin() + 5, stealth_data.end()); BITCOIN_ASSERT(ephemkey.size() == 33); return ephemkey; }
long_hash hmac_sha512_hash(const data_chunk& chunk, const data_chunk& key) { long_hash hash; HMACSHA512(chunk.data(), chunk.size(), key.data(), key.size(), hash.data()); return hash; }
long_hash single_sha512_hash(const data_chunk& chunk) { long_hash digest; SHA512_CTX ctx; SHA512_Init(&ctx); SHA512_Update(&ctx, chunk.data(), chunk.size()); SHA512_Final(digest.data(), &ctx); return digest; }
bool VerifyChecksum(const data_chunk& data) { if (data.size() < 4) return false; uint32_t checksum = from_little_endian<uint32_t>(data.end() - 4); return BitcoinChecksum((uint8_t*)&data[0], data.size()-4) == checksum; };
void BIO::Write(const data_chunk& data2wr) const { unsigned int written = 0; do { data_chunk tmp; tmp.insert(tmp.end(), data2wr.begin() + written, data2wr.end()); written += doWrite(tmp, written); } while(written < data2wr.size()); }
bool read_hash(hash_digest& hash, const data_chunk& raw_hash) { if (raw_hash.size() != hash.size()) { log_warning(LOG_SUBSCRIBER) << "Wrong size for hash. Dropping."; return false; } std::copy(raw_hash.begin(), raw_hash.end(), hash.begin()); return true; }
short_hash bitcoin_short_hash(const data_chunk& chunk) { hash_digest sha_hash; SHA256__(chunk.data(), chunk.size(), sha_hash.data()); short_hash ripemd_hash; RMD160(sha_hash.data(), sha_hash.size(), ripemd_hash.data()); return ripemd_hash; }
void unpack_char(data_chunk& data, int carry) { for (auto it = data.rbegin(); it != data.rend(); it++) { carry += 58 * (*it); *it = carry % 256; carry /= 256; } BITCOIN_ASSERT(carry == 0); }
void wrap_fetch_history_args(data_chunk& data, const payment_address& address, size_t from_height) { data.resize(1 + short_hash_size + 4); auto serial = make_serializer(data.begin()); serial.write_byte(address.version()); serial.write_short_hash(address.hash()); serial.write_4_bytes(from_height); BITCOIN_ASSERT(serial.iterator() == data.end()); }
record_type get_record(htdb_record_header& header, record_allocator& alloc, const data_chunk& key_data) { typedef byte_array<N> hash_type; htdb_record<hash_type> ht(header, alloc, "test"); hash_type key; BITCOIN_ASSERT(key.size() == key_data.size()); std::copy(key_data.begin(), key_data.end(), key.begin()); return ht.get(key); }
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; }
bool elliptic_curve_key::set_public_key(const data_chunk& pubkey) { if (!initialize()) return false; const unsigned char* pubkey_bytes = pubkey.data(); if (!o2i_ECPublicKey(&key_, &pubkey_bytes, pubkey.size())) return false; if (pubkey.size() == 33) use_compressed(); return true; }
bool elliptic_curve_key::verify(hash_digest hash, const data_chunk& signature) { BITCOIN_ASSERT(key_ != nullptr); // SSL likes a reversed hash std::reverse(hash.begin(), hash.end()); // -1 = error, 0 = bad sig, 1 = good if (ECDSA_verify(0, hash.data(), hash.size(), signature.data(), signature.size(), key_) == 1) return true; return false; }
bool verify_signature(const ec_point& public_key, hash_digest hash, const data_chunk& signature) { std::reverse(hash.begin(), hash.end()); init.init(); return 1 == secp256k1_ecdsa_verify( hash.data(), hash.size(), signature.data(), signature.size(), public_key.data(), public_key.size() ); }
void pack_value(data_chunk& indexes, int carry) { // Apply "b58 = b58 * 256 + ch". for (auto it = indexes.rbegin(); it != indexes.rend(); ++it) { carry += 256 * (*it); *it = carry % 58; carry /= 58; } BITCOIN_ASSERT(carry == 0); }
void receive_transaction_result(const data_chunk& data, blockchain::fetch_handler_transaction handle_fetch) { std::error_code ec; auto deserial = make_deserializer(data.begin(), data.end()); if (!read_error_code(deserial, data.size(), ec)) return; BITCOIN_ASSERT(deserial.iterator() == data.begin() + 4); transaction_type tx; satoshi_load(deserial.iterator(), data.end(), tx); handle_fetch(ec, tx); }
void address_subscriber::decode_reply( const data_chunk& data, const worker_uuid& worker, subscribe_handler handle_subscribe) { std::error_code ec; BITCOIN_ASSERT(data.size() == 4); auto deserial = make_deserializer(data.begin(), data.end()); if (!read_error_code(deserial, data.size(), ec)) return; BITCOIN_ASSERT(deserial.iterator() == data.end()); handle_subscribe(ec, worker); }
hash_digest bitcoin_hash(const data_chunk& chunk) { hash_digest first_hash; SHA256__(chunk.data(), chunk.size(), first_hash.data()); hash_digest second_hash; SHA256__(first_hash.data(), first_hash.size(), second_hash.data()); // The hash is in the reverse of the expected order. std::reverse(second_hash.begin(), second_hash.end()); return second_hash; }
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 attempt_load(const data_chunk& stream) const { Message result; try { satoshi_load(stream.begin(), stream.end(), result); handle_load_(std::error_code(), result); } catch (end_of_stream) { handle_load_(error::bad_stream, Message()); } }
hash_digest sha256_hash(const data_chunk& first_chunk, const data_chunk& second_chunk) { hash_digest hash; SHA256CTX context; SHA256Init(&context); SHA256Update(&context, first_chunk.data(), first_chunk.size()); SHA256Update(&context, second_chunk.data(), second_chunk.size()); SHA256Final(&context, hash.data()); return hash; }
bool validsig(transaction_type& tx, size_t input_index, elliptic_curve_key& key, const script_type& script_code, data_chunk signature) { uint32_t hash_type = 0; hash_type = signature.back(); signature.pop_back(); hash_digest tx_hash = script_type::generate_signature_hash( tx, input_index, script_code, hash_type); return key.verify(tx_hash, signature); }