From a89bbe5cf2de0de0fe9660313ed7bf6f2c0dee97 Mon Sep 17 00:00:00 2001 From: Rot127 <45763064+Rot127@users.noreply.github.com> Date: Wed, 7 Jan 2026 04:26:06 +0000 Subject: [PATCH] librz/util: implement inplace rz_bv_div and rz_bv_mod. (#5742) --- librz/include/rz_util/rz_bitvector.h | 2 + librz/util/bitvector.c | 152 +++++++++++++++++++-------- 2 files changed, 109 insertions(+), 45 deletions(-) diff --git a/librz/include/rz_util/rz_bitvector.h b/librz/include/rz_util/rz_bitvector.h index d7b3646235..302b5cc190 100644 --- a/librz/include/rz_util/rz_bitvector.h +++ b/librz/include/rz_util/rz_bitvector.h @@ -86,7 +86,9 @@ RZ_API bool rz_bv_sub_inplace(RZ_INOUT RZ_NONNULL RzBitVector *x, RZ_INOUT RZ_NO RZ_API RZ_OWN RzBitVector *rz_bv_mul(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y); RZ_API bool rz_bv_mul_inplace(RZ_NONNULL RZ_INOUT RzBitVector *x, const RZ_NONNULL RzBitVector *y); RZ_API RZ_OWN RzBitVector *rz_bv_div(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y); +RZ_API bool rz_bv_div_inplace(RZ_NONNULL RZ_INOUT RzBitVector *x, const RZ_NONNULL RzBitVector *y); RZ_API RZ_OWN RzBitVector *rz_bv_mod(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y); +RZ_API bool rz_bv_mod_inplace(RZ_NONNULL RZ_INOUT RzBitVector *x, const RZ_NONNULL RzBitVector *y); RZ_API RZ_OWN RzBitVector *rz_bv_sdiv(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y); RZ_API RZ_OWN RzBitVector *rz_bv_smod(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y); diff --git a/librz/util/bitvector.c b/librz/util/bitvector.c index 62aad734ba..6361c59bcc 100644 --- a/librz/util/bitvector.c +++ b/librz/util/bitvector.c @@ -1173,7 +1173,7 @@ RZ_API RZ_OWN RzBitVector *rz_bv_mul(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBit * if x == y return 0 * if x > y return positive (+1) */ -int bv_unsigned_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) { +int bv_unsigned_cmp(const RZ_NONNULL RzBitVector *x, const RZ_NONNULL RzBitVector *y) { rz_return_val_if_fail(x && y, 0); if (x->len != y->len) { @@ -1197,6 +1197,75 @@ int bv_unsigned_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) { return 0; } +/** + * Result of x = (x / y) mod 2^length + * Both operands must have the same length. + * If \p y is a zero vector, the result defined as a vector of all ones. + * + * \param x dividend + * \param y divisor + * \return True in case of success, false otherwise. + */ +RZ_API bool rz_bv_div_inplace(RZ_NONNULL RZ_INOUT RzBitVector *x, const RZ_NONNULL RzBitVector *y) { + rz_return_val_if_fail(x && y && x->len == y->len, false); + + if (rz_bv_is_zero_vector(y)) { + rz_bv_set_all(x, true); + return true; + } + + if (x->len <= 64) { + rz_bv_set_from_ut64(x, rz_bv_to_ut64(x) / rz_bv_to_ut64(y)); + return true; + } + + int compare_result = bv_unsigned_cmp(x, y); + // dividend < divisor + // remainder = dividend, quotient = 0 + if (compare_result < 0) { + rz_bv_set_from_ut64(x, 0); + return true; + } + // dividend == divisor + // remainder = 0, quotient = 1 + if (compare_result == 0) { + rz_bv_set_from_ut64(x, 1); + return true; + } + + // dividend > divisor + // do typical division by shift and subtract + RzBitVector dend; + rz_bv_init(&dend, x->len); + rz_bv_copy(x, &dend); + RzBitVector sor; + rz_bv_init(&sor, y->len); + rz_bv_copy(y, &sor); + + // shift the divisor left to align both highest bits + ut32 sorlz = rz_bv_clz(&sor); + ut32 shift = sorlz - rz_bv_clz(&dend); + rz_bv_lshift(&sor, shift); + + rz_bv_set_from_ut64(x, 0); + for (ut32 b = shift + 1; b; b--) { + if (rz_bv_ule(&sor, &dend)) { + rz_bv_set(x, b - 1, true); + + // sub_inplace() negates sor_cpy + RzBitVector sor_cpy; + rz_bv_init(&sor_cpy, y->len); + rz_bv_copy(&sor, &sor_cpy); + rz_bv_sub_inplace(&dend, &sor_cpy, NULL); + rz_bv_fini(&sor_cpy); + } + rz_bv_rshift(&sor, 1); + } + rz_bv_fini(&dend); + rz_bv_fini(&sor); + return true; +} + /** * Result of (x / y) mod 2^length * Both operands must have the same length. @@ -1208,50 +1277,46 @@ int bv_unsigned_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) { */ RZ_API RZ_OWN RzBitVector *rz_bv_div(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) { rz_return_val_if_fail(x && y && x->len == y->len, NULL); + RzBitVector *res = rz_bv_dup(x); + if (!rz_bv_div_inplace(res, y)) { + rz_bv_free(res); + return NULL; + } + return res; +} +/** + * Result of x = (x mod y) mod 2^length + * Both operands must have the same length. + * If \p y == 0, the result is \p x + * + * \param x dividend + * \param y divisor + * \return True in case of success, false otherwise. + */ +RZ_API bool rz_bv_mod_inplace(RZ_NONNULL RZ_INOUT RzBitVector *x, const RZ_NONNULL RzBitVector *y) { + rz_return_val_if_fail(x && y && x->len == y->len, false); if (rz_bv_is_zero_vector(y)) { - RzBitVector *ret = rz_bv_new(y->len); - rz_bv_set_all(ret, true); - return ret; + return true; } + RzBitVector remul; + rz_bv_init(&remul, rz_bv_len(x)); + rz_bv_copy(x, &remul); - if (x->len <= 64) { - return rz_bv_new_from_ut64(x->len, rz_bv_to_ut64(x) / rz_bv_to_ut64(y)); + if (!rz_bv_div_inplace(&remul, y)) { + rz_bv_fini(&remul); + return false; } - - int compare_result = bv_unsigned_cmp(x, y); - // dividend < divisor - // remainder = dividend, quotient = 0 - if (compare_result < 0) { - return rz_bv_new(x->len); + if (!rz_bv_mul_inplace(&remul, y)) { + rz_bv_fini(&remul); + return false; } - // dividend == divisor - // remainder = 0, quotient = 1 - if (compare_result == 0) { - return rz_bv_new_one(rz_bv_len(x)); + if (!rz_bv_sub_inplace(x, &remul, NULL)) { + rz_bv_fini(&remul); + return false; } - - // dividend > divisor - // do typical division by shift and subtract - RzBitVector *dend = rz_bv_dup(x); - RzBitVector *sor = rz_bv_dup(y); - // shift the divisor left to align both highest bits - ut32 sorlz = rz_bv_clz(sor); - ut32 shift = sorlz - rz_bv_clz(dend); - rz_bv_lshift(sor, shift); - RzBitVector *quot = rz_bv_new_zero(rz_bv_len(x)); - for (ut32 b = shift + 1; b; b--) { - if (rz_bv_ule(sor, dend)) { - rz_bv_set(quot, b - 1, true); - RzBitVector *tmp = rz_bv_sub(dend, sor, NULL); - rz_bv_free(dend); - dend = tmp; - } - rz_bv_rshift(sor, 1); - } - rz_bv_free(dend); - rz_bv_free(sor); - return quot; + rz_bv_fini(&remul); + return true; } /** @@ -1265,14 +1330,11 @@ RZ_API RZ_OWN RzBitVector *rz_bv_div(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBit */ RZ_API RZ_OWN RzBitVector *rz_bv_mod(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) { rz_return_val_if_fail(x && y && x->len == y->len, NULL); - if (rz_bv_is_zero_vector(y)) { - return rz_bv_dup(x); + RzBitVector *r = rz_bv_dup(x); + if (!rz_bv_mod_inplace(r, y)) { + rz_bv_free(r); + return NULL; } - RzBitVector *quot = rz_bv_div(x, y); - RzBitVector *remul = rz_bv_mul(quot, y); - RzBitVector *r = rz_bv_sub(x, remul, NULL); - rz_bv_free(quot); - rz_bv_free(remul); return r; }