Skip to content

Commit

Permalink
Optimized getBytesFromString
Browse files Browse the repository at this point in the history
  • Loading branch information
SakiTakamachi committed Jul 10, 2024
1 parent df6d85a commit 4e92056
Showing 1 changed file with 22 additions and 12 deletions.
34 changes: 22 additions & 12 deletions ext/random/randomizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,6 @@ PHP_METHOD(Random_Randomizer, getBytesFromString)

zend_long user_length;
zend_string *source, *retval;
size_t total_size = 0;

ZEND_PARSE_PARAMETERS_START(2, 2);
Z_PARAM_STR(source)
Expand All @@ -410,17 +409,21 @@ PHP_METHOD(Random_Randomizer, getBytesFromString)

size_t length = (size_t)user_length;
retval = zend_string_alloc(length, 0);
char *rptr = ZSTR_VAL(retval);
char *sptr = ZSTR_VAL(source);

size_t to_read = length;
if (max_offset > 0xff) {
while (total_size < length) {
while (to_read > 0) {
uint64_t offset = engine.algo->range(engine.state, 0, max_offset);

if (EG(exception)) {
zend_string_free(retval);
RETURN_THROWS();
}

ZSTR_VAL(retval)[total_size++] = ZSTR_VAL(source)[offset];
*rptr++ = sptr[offset];
to_read--;
}
} else {
uint64_t mask = max_offset;
Expand All @@ -432,31 +435,38 @@ PHP_METHOD(Random_Randomizer, getBytesFromString)
mask |= mask >> 2;
mask |= mask >> 4;

/* Example: if mask is 0xAB, will be 0xABABABABABABABAB */
uint64_t mask_repeat = (~((uint64_t) 0) / 0xFF) * mask;
int failures = 0;
while (total_size < length) {
while (to_read > 0) {
php_random_result result = engine.algo->generate(engine.state);
if (EG(exception)) {
zend_string_free(retval);
RETURN_THROWS();
}

for (size_t i = 0; i < result.size; i++) {
uint64_t offset = (result.result >> (i * 8)) & mask;

uint64_t offsets = result.result & mask_repeat;
size_t ret_size = result.size;
while (ret_size > 0) {
ret_size--;
uint64_t offset = offsets & 0xff;
offsets >>= 8;
if (offset > max_offset) {
if (++failures > PHP_RANDOM_RANGE_ATTEMPTS) {
if (failures == PHP_RANDOM_RANGE_ATTEMPTS) {
zend_string_free(retval);
zend_throw_error(random_ce_Random_BrokenRandomEngineError, "Failed to generate an acceptable random number in %d attempts", PHP_RANDOM_RANGE_ATTEMPTS);
RETURN_THROWS();
} else {
failures++;
continue;
}

continue;
}

failures = 0;

ZSTR_VAL(retval)[total_size++] = ZSTR_VAL(source)[offset];
if (total_size >= length) {
*rptr++ = sptr[offset];
to_read--;
if (to_read == 0) {
break;
}
}
Expand Down

0 comments on commit 4e92056

Please sign in to comment.