static bool create_token(encrypted_token& out_token, const std::string& passphrase, data_slice owner_salt, const ek_entropy& owner_entropy, const byte_array<parse_encrypted_token::prefix_size>& prefix) { BITCOIN_ASSERT(owner_salt.size() == ek_salt_size || owner_salt.size() == ek_entropy_size); const auto lot_sequence = owner_salt.size() == ek_salt_size; auto factor = scrypt_token(normal(passphrase), owner_salt); if (lot_sequence) factor = bitcoin_hash(splice(factor, owner_entropy)); ec_compressed point; if (!secret_to_public(point, factor)) return false; return build_checked_array(out_token, { prefix, owner_entropy, point }); }
hash_digest hmac_sha256_hash(data_slice data, data_slice key) { hash_digest hash; HMACSHA256(data.data(), data.size(), key.data(), key.size(), hash.data()); return hash; }
long_hash hmac_sha512_hash(data_slice data, data_slice key) { long_hash hash; HMACSHA512(data.data(), data.size(), key.data(), key.size(), hash.data()); return hash; }
bool verify_checksum(data_slice data) { if (data.size() < checksum_size) return false; data_slice body(data.begin(), data.end() - checksum_size); auto checksum = from_little_endian_unsafe<uint32_t>(data.end() - checksum_size); return bitcoin_checksum(body) == checksum; }
data_chunk scrypt(data_slice data, data_slice salt, uint64_t N, uint32_t p, uint32_t r, size_t length) { data_chunk output(length); const auto result = crypto_scrypt(data.data(), data.size(), salt.data(), salt.size(), N, r, p, output.data(), output.size()); handle_script_result(result); return output; }
bool is_uncompressed_key(data_slice point) { const auto size = point.size(); if (size != ec_uncompressed_size) return false; const auto first = point.data()[0]; return first == uncompressed; }
binary_type::binary_type(size_type size, data_slice blocks) { // Copy blocks blocks_.resize(blocks.size()); std::copy(blocks.begin(), blocks.end(), blocks_.begin()); // Pad with 00 for safety. while (blocks_.size() * bits_per_block < size) blocks_.push_back(0x00); resize(size); }
hash_digest sha256_hash(data_slice first, data_slice second) { hash_digest hash; SHA256CTX context; SHA256Init(&context); SHA256Update(&context, first.data(), first.size()); SHA256Update(&context, second.data(), second.size()); SHA256Final(&context, hash.data()); return hash; }
long_hash pkcs5_pbkdf2_hmac_sha512(data_slice passphrase, data_slice salt, size_t iterations) { long_hash hash; const auto result = pkcs5_pbkdf2(passphrase.data(), passphrase.size(), salt.data(), salt.size(), hash.data(), hash.size(), iterations); if (result != 0) throw std::bad_alloc(); return hash; }
// Accepts only byte arrays bounded to 4 bytes. bool encode_base85(std::string& out, data_slice in) { const size_t size = in.size(); if (size % 4 != 0) return false; const size_t encoded_size = size * 5 / 4; std::string encoded; encoded.reserve(encoded_size + 1); size_t byte_index = 0; uint32_t accumulator = 0; for (const uint8_t unencoded_byte: in) { accumulator = accumulator * 256 + unencoded_byte; if (++byte_index % 4 == 0) { for (uint32_t divise = 85 * 85 * 85 * 85; divise > 0; divise /= 85) encoded.push_back(encoder[accumulator / divise % 85]); accumulator = 0; } } out.assign(encoded.begin(), encoded.end()); BITCOIN_ASSERT(out.size() == encoded_size); return true; }
operation::stack operation::to_null_data_pattern(data_slice data) { if (data.size() > max_null_data_size) return operation::stack(); return operation::stack { operation{ opcode::return_, data_chunk() }, operation{ opcode::special, to_chunk(data) } }; }
bool verify_signature(data_slice point, const hash_digest& hash, const ec_signature& signature) { // Copy to avoid exposing external types. secp256k1_ecdsa_signature parsed; std::copy(signature.begin(), signature.end(), std::begin(parsed.data)); // secp256k1_ecdsa_verify rejects non-normalized (low-s) signatures, but // bitcoin does not have such a limitation, so we always normalize. secp256k1_ecdsa_signature normal; const auto context = verification.context(); secp256k1_ecdsa_signature_normalize(context, &normal, &parsed); // This uses a data slice and calls secp256k1_ec_pubkey_parse() in place of // parse() so that we can support the der_verify data_chunk optimization. secp256k1_pubkey pubkey; const auto size = point.size(); return secp256k1_ec_pubkey_parse(context, &pubkey, point.data(), size) == 1 && secp256k1_ecdsa_verify(context, &normal, hash.data(), &pubkey) == 1; }
// This verifies the checksum. bool unwrap(wallet::wrapped_data& data, data_slice wrapped) { if (!verify_checksum(wrapped)) return false; data.version = wrapped.data()[0]; const auto payload_begin = std::begin(wrapped) + 1; const auto checksum_begin = std::end(wrapped) - checksum_size; data.payload.resize(checksum_begin - payload_begin); std::copy(payload_begin, checksum_begin, data.payload.begin()); data.checksum = from_little_endian_unsafe<uint32_t>(checksum_begin); return true; }
word_list create_mnemonic(data_slice entropy, const dictionary &lexicon) { if ((entropy.size() % mnemonic_seed_multiple) != 0) return word_list(); const size_t entropy_bits = (entropy.size() * byte_bits); const size_t check_bits = (entropy_bits / entropy_bit_divisor); const size_t total_bits = (entropy_bits + check_bits); const size_t word_count = (total_bits / bits_per_word); BITCOIN_ASSERT((total_bits % bits_per_word) == 0); BITCOIN_ASSERT((word_count % mnemonic_word_multiple) == 0); const auto data = build_chunk({entropy, sha256_hash(entropy)}); size_t bit = 0; word_list words; for (size_t word = 0; word < word_count; word++) { size_t position = 0; for (size_t loop = 0; loop < bits_per_word; loop++) { bit = (word * bits_per_word + loop); position <<= 1; const auto byte = bit / byte_bits; if ((data[byte] & bip39_shift(bit)) > 0) position++; } BITCOIN_ASSERT(position < dictionary_size); words.push_back(lexicon[position]); } BITCOIN_ASSERT(words.size() == ((bit + 1) / bits_per_word)); return words; }
inline data_chunk operator +(data_slice a, data_slice b) { data_chunk out; out.reserve(a.size() + b.size()); out.insert(out.end(), a.begin(), a.end()); out.insert(out.end(), b.begin(), b.end()); return out; }
std::string encode_base58(data_slice 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; }
bool unwrap(uint8_t& version, data_chunk& payload, uint32_t& checksum, data_slice wrapped) { constexpr size_t version_length = sizeof(version); constexpr size_t checksum_length = sizeof(checksum); // guard against insufficient buffer length if (wrapped.size() < version_length + checksum_length) return false; if (!verify_checksum(wrapped)) return false; // set return values version = wrapped.data()[0]; payload = data_chunk(wrapped.begin() + version_length, wrapped.end() - checksum_length); const auto checksum_start = wrapped.end() - checksum_length; auto deserial = make_deserializer(checksum_start, wrapped.end()); checksum = deserial.read_4_bytes(); return true; }
/** * Shoves data into a std::string object. */ std::string to_string(data_slice data) { return std::string(data.begin(), data.end()); }
long_hash sha512_hash(data_slice data) { long_hash hash; SHA512_(data.data(), data.size(), hash.data()); return hash; }
hash_digest sha256_hash(data_slice data) { hash_digest hash; SHA256_(data.data(), data.size(), hash.data()); return hash; }
short_hash sha1_hash(data_slice data) { short_hash hash; SHA1_(data.data(), data.size(), hash.data()); return hash; }
short_hash ripemd160_hash(data_slice data) { short_hash hash; RMD160(data.data(), data.size(), hash.data()); return hash; }
data_chunk ripemd160_hash_chunk(data_slice data) { data_chunk hash(short_hash_size); RMD160(data.data(), data.size(), hash.data()); return hash; }
data_chunk sha1_hash_chunk(data_slice data) { data_chunk hash(short_hash_size); SHA1_(data.data(), data.size(), hash.data()); return hash; }
data_chunk sha256_hash_chunk(data_slice data) { data_chunk hash(hash_size); SHA256_(data.data(), data.size(), hash.data()); return hash; }