void build_light_cache(hash512* cache, int num_items, const hash256& seed) noexcept { hash512 item = keccak512(seed.bytes, sizeof(seed)); cache[0] = item; for (int i = 1; i < num_items; ++i) { item = keccak512(item); cache[i] = item; } for (int q = 0; q < light_cache_rounds; ++q) { for (int i = 0; i < num_items; ++i) { const uint32_t index_limit = static_cast<uint32_t>(num_items); // Fist index: 4 first bytes of the item as little-endian integer. uint32_t t = fix_endianness(cache[i].half_words[0]); uint32_t v = t % index_limit; // Second index. uint32_t w = static_cast<uint32_t>(num_items + (i - 1)) % index_limit; // Pipelining functions returning structs gives small performance boost. cache[i] = keccak512(bitwise_xor(cache[v], cache[w])); } } }
/// Calculates a full dataset item /// /// This consist of two 512-bit items produced by calculate_dataset_item_partial(). /// Here the computation is done interleaved for better performance. hash1024 calculate_dataset_item(const epoch_context& context, uint32_t index) noexcept { const hash512* const cache = context.light_cache; static constexpr size_t num_half_words = sizeof(hash512) / sizeof(uint32_t); const int64_t num_cache_items = context.light_cache_num_items; const int64_t index0 = int64_t(index) * 2; const int64_t index1 = int64_t(index) * 2 + 1; const uint32_t init0 = static_cast<uint32_t>(index0); const uint32_t init1 = static_cast<uint32_t>(index1); hash512 mix0 = cache[index0 % num_cache_items]; hash512 mix1 = cache[index1 % num_cache_items]; mix0.half_words[0] ^= fix_endianness(init0); mix1.half_words[0] ^= fix_endianness(init1); // Hash and convert to little-endian 32-bit words. mix0 = fix_endianness32(keccak512(mix0)); mix1 = fix_endianness32(keccak512(mix1)); for (uint32_t j = 0; j < full_dataset_item_parents; ++j) { uint32_t t0 = fnv(init0 ^ j, mix0.half_words[j % num_half_words]); int64_t parent_index0 = t0 % num_cache_items; mix0 = fnv(mix0, fix_endianness32(cache[parent_index0])); uint32_t t1 = fnv(init1 ^ j, mix1.half_words[j % num_half_words]); int64_t parent_index1 = t1 % num_cache_items; mix1 = fnv(mix1, fix_endianness32(cache[parent_index1])); } // Covert 32-bit words back to bytes and hash. mix0 = keccak512(fix_endianness32(mix0)); mix1 = keccak512(fix_endianness32(mix1)); return hash1024{{mix0, mix1}}; }
bool handler__set(globals_t * vars, char **argv, unsigned argc) { unsigned block, seconds = 1; char *delay = NULL; char *end; bool cont = false; struct setting { char *matchids; char *value; unsigned seconds; } *settings = NULL; assert(argc != 0); assert(argv != NULL); assert(vars != NULL); if (argc < 2) { show_error("expected an argument, type `help set` for details.\n"); return false; } /* supporting `set` for bytearray will cause annoying syntax problems... */ if ((vars->options.scan_data_type == BYTEARRAY) ||(vars->options.scan_data_type == STRING)) { show_error("`set` is not supported for bytearray or string, use `write` instead.\n"); return false; } /* check if there are any matches */ if (vars->num_matches == 0) { show_error("no matches are known.\n"); return false; } /* --- parse arguments into settings structs --- */ settings = calloca(argc - 1, sizeof(struct setting)); /* parse every block into a settings struct */ for (block = 0; block < argc - 1; block++) { /* first seperate the block into matches and value, which are separated by '=' */ if ((settings[block].value = strchr(argv[block + 1], '=')) == NULL) { /* no '=' found, whole string must be the value */ settings[block].value = argv[block + 1]; } else { /* there is a '=', value+1 points to value string. */ /* use strndupa() to copy the matchids into a new buffer */ settings[block].matchids = strndupa(argv[block + 1], (size_t) (settings[block].value++ - argv[block + 1])); } /* value points to the value string, possibly with a delay suffix */ /* matchids points to the match-ids (possibly multiple) or NULL */ /* now check for a delay suffix (meaning continuous mode), eg 0xff/10 */ if ((delay = strchr(settings[block].value, '/')) != NULL) { char *end = NULL; /* parse delay count */ settings[block].seconds = strtoul(delay + 1, &end, 10); if (*(delay + 1) == '\0') { /* empty delay count, eg: 12=32/ */ show_error("you specified an empty delay count, `%s`, see `help set`.\n", settings[block].value); return false; } else if (*end != '\0') { /* parse failed before end, probably trailing garbage, eg 34=9/16foo */ show_error("trailing garbage after delay count, `%s`.\n", settings[block].value); return false; } else if (settings[block].seconds == 0) { /* 10=24/0 disables continous mode */ show_info("you specified a zero delay, disabling continuous mode.\n"); } else { /* valid delay count seen and understood */ show_info("setting %s every %u seconds until interrupted...\n", settings[block].matchids ? settings[block]. matchids : "all", settings[block].seconds); /* continuous mode on */ cont = true; } /* remove any delay suffix from the value */ settings[block].value = strndupa(settings[block].value, (size_t) (delay - settings[block].value)); } /* if (strchr('/')) */ } /* for(block...) */ /* --- setup a longjmp to handle interrupt --- */ if (INTERRUPTABLE()) { /* control returns here when interrupted */ // settings is allocated with alloca, do not free it // free(settings); detach(vars->target); ENDINTERRUPTABLE(); return true; } /* --- execute the parsed setting structs --- */ while (true) { uservalue_t userval; /* for every settings struct */ for (block = 0; block < argc - 1; block++) { /* check if this block has anything to do this iteration */ if (seconds != 1) { /* not the first iteration (all blocks get executed first iteration) */ /* if settings.seconds is zero, then this block is only executed once */ /* if seconds % settings.seconds is zero, then this block must be executed */ if (settings[block].seconds == 0 || (seconds % settings[block].seconds) != 0) continue; } /* convert value */ if (!parse_uservalue_number(settings[block].value, &userval)) { show_error("bad number `%s` provided\n", settings[block].value); goto fail; } /* check if specific match(s) were specified */ if (settings[block].matchids != NULL) { char *id, *lmatches = NULL; unsigned num = 0; /* create local copy of the matchids for strtok() to modify */ lmatches = strdupa(settings[block].matchids); /* now seperate each match, spearated by commas */ while ((id = strtok(lmatches, ",")) != NULL) { match_location loc; /* set to NULL for strtok() */ lmatches = NULL; /* parse this id */ num = strtoul(id, &end, 0x00); /* check that succeeded */ if (*id == '\0' || *end != '\0') { show_error("could not parse match id `%s`\n", id); goto fail; } /* check this is a valid match-id */ loc = nth_match(vars->matches, num); if (loc.swath) { value_t v; value_t old; void *address = remote_address_of_nth_element(loc.swath, loc.index /* ,MATCHES_AND_VALUES */); /* copy val onto v */ /* XXX: valcmp? make sure the sizes match */ old = data_to_val(loc.swath, loc.index /* ,MATCHES_AND_VALUES */); zero_value(&v); v.flags = old.flags = loc.swath->data[loc.index].match_info; uservalue2value(&v, &userval); show_info("setting *%p to %#"PRIx64"...\n", address, v.int64_value); /* set the value specified */ fix_endianness(vars, &v); if (setaddr(vars->target, address, &v) == false) { show_error("failed to set a value.\n"); goto fail; } } else { /* match-id > than number of matches */ show_error("found an invalid match-id `%s`\n", id); goto fail; } } } else { matches_and_old_values_swath *reading_swath_index = (matches_and_old_values_swath *)vars->matches->swaths; int reading_iterator = 0; /* user wants to set all matches */ while (reading_swath_index->first_byte_in_child) { /* Only actual matches are considered */ if (flags_to_max_width_in_bytes(reading_swath_index->data[reading_iterator].match_info) > 0) { void *address = remote_address_of_nth_element(reading_swath_index, reading_iterator /* ,MATCHES_AND_VALUES */); /* XXX: as above : make sure the sizes match */ value_t old = data_to_val(reading_swath_index, reading_iterator /* ,MATCHES_AND_VALUES */); value_t v; zero_value(&v); v.flags = old.flags = reading_swath_index->data[reading_iterator].match_info; uservalue2value(&v, &userval); show_info("setting *%p to %#"PRIx64"...\n", address, v.int64_value); fix_endianness(vars, &v); if (setaddr(vars->target, address, &v) == false) { show_error("failed to set a value.\n"); goto fail; } } /* Go on to the next one... */ ++reading_iterator; if (reading_iterator >= reading_swath_index->number_of_bytes) { reading_swath_index = local_address_beyond_last_element(reading_swath_index /* ,MATCHES_AND_VALUES */); reading_iterator = 0; } } } /* if (matchid != NULL) else ... */ } /* for(block) */ if (cont) { sleep(1); } else { break; } seconds++; } /* while(true) */ ENDINTERRUPTABLE(); return true; fail: ENDINTERRUPTABLE(); return false; }