// Optimize reads by short-circuiting what is unnecessary. // Invalid returns are conflated with skipped, but are store only. bool stealth_record::from_data(reader& source, size_t start_height, const binary& filter) { height_ = source.read_4_bytes_little_endian(); if (height_ < start_height) { reset(); source.skip(serialized_size(false) - sizeof(uint32_t)); return false; } prefix_ = source.read_4_bytes_little_endian(); if (!filter.is_prefix_of(prefix_)) { reset(); source.skip(serialized_size(false) - 2 * sizeof(uint32_t)); return false; } unsigned_ephemeral_ = source.read_hash(); public_key_hash_ = source.read_short_hash(); transaction_hash_ = source.read_hash(); if (!source) reset(); return source; }
// Mine a filter into the leftmost bytes of sha256(sha256(output-script)). bool create_stealth_data(data_chunk& out_stealth_data, ec_secret& out_secret, const binary& filter, const data_chunk& seed) { // Create a valid ephemeral key pair. ec_secret secret; ec_compressed point; if (!create_ephemeral_keys(secret, point, seed)) return false; // [ephemeral-public-key-hash:32][pad:0-44][nonce:4] static const size_t max_pad_size = operation::max_null_data_size - hash_size - sizeof(uint32_t); // Derive our initial nonce data from the provided seed. const auto bytes = sha512_hash(seed); // Create a pad size of 0-44 using the last of bytes (avoiding pad/nonce). const auto pad_size = bytes.back() % max_pad_size; // Allocate data of target size (36-80 bytes) data_chunk data(hash_size + pad_size + sizeof(uint32_t)); // Copy the unsigned portion of the ephemeral public key into data. std::copy(point.begin() + 1, point.end(), data.begin()); // Copy arbitrary pad bytes into data. const auto pad_begin = data.begin() + hash_size; std::copy(bytes.begin(), bytes.begin() + pad_size, pad_begin); // Create an initial 32 bit nonce value from last byte (avoiding pad). const auto start = from_little_endian_unsafe<uint32_t>(bytes.begin() + max_pad_size); // Mine a prefix into the double sha256 hash of the stealth script. // This will iterate up to 2^32 times before giving up. for (uint32_t nonce = start + 1; nonce != start; ++nonce) { // Create the stealth script with the current data. const auto ops = operation::to_null_data_pattern(data); const auto stealth_script = script{ ops }; // Test for match of filter to stealth script hash prefix. uint32_t field; if (to_stealth_prefix(field, stealth_script) && filter.is_prefix_of(field)) { out_stealth_data = data; out_secret = secret; return true; } } return false; }