2

A program I am trying to improve has the following code to add 1 to a 16-byte number in a byterray:

for k in range(15, -1, -1):
    payload[k] = (payload[k] + 1) & 0x0ff
    if payload[k]:
        break

So, it adds 1 to the last byte, handling overflow, and if the result is falseish (0x00), it proceeds and adds 1 to the byte before it, and otherwise it stops.

This seems like a kludge to me, and I'm trying to come up with something better, if not for performance or reliability, then at least for how it looks.

So far, I've got this, which yields the same results in my tests:

hi,lo = struct.unpack('>QQ', payload)
payload = struct.pack('>QQ', hi, lo + 1)

I know that my code will fail after running at most 2^64 times, but I'm quite sure the code won't have to run more than a few hundred times for a single number, so the chance of anything more than the last couple of bytes changing is small.

Any suggestions about my intended improvement, of other/better ways to get the same result? Of course, if there is an easy fix for the 2^64 limitation, I'd love to see it!

Thank you.

4
  • I would say it's relatively safe to assume that you won't be limited by 2^64 haha Commented May 17, 2018 at 10:56
  • 16 bytes is 16 * 8 is 128 bits, so the upper limit is 2^128, not 2^64. Commented May 17, 2018 at 11:07
  • @MartijnPieters My code only handles the bottom 8 bytes, 64 bits, because that is the biggest chunk struct.unpack can handle. At some point, the addition (lo + 1) will yield a 9 byte result and the call to struct.pack will fail. Commented May 17, 2018 at 11:20
  • @TinuzZ: right, you could work around that by testing lo: struct.pack('>QQ', hi + (lo == (2**64) - 1), lo + (lo < (2**64) - 1)). Not that you need to use that at all, not with int.from_bytes() and int.to_bytes(). Commented May 17, 2018 at 11:25

1 Answer 1

6

You can convert a bytearray directly to an integer with the int.from_bytes() method, and back to a bytes object with int.to_bytes():

incremented = int.from_bytes(payload, 'big') + 1
try:
    payload = bytearray(incremented.to_bytes(len(payload), 'big'))
except OverflowError:
    # value won't fit into the payload, wrap round to 0
    payload = bytearray(len(payload))

I'm not sure what should happen when you hit the upper limit; you could revert to 0 (bytearray(len(payload))), sticking to the old (2 ** 128) - 1 value, or doing something else.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. Wrapping to 0 would probably the sanest thing to do, but this will never happen in practice.
I tested this, and it seems to work. It's just that my bytearray is big endian (hence the range(15, -1, -1) in the original code), so I changed that.
@TinuzZ: oops, of course it is! Sorry about that, corrected.
Great. The biggest thing I learned here is that Python ints are not bound in size. I knew about int.from_bytes() before, but I incorrectly assumed that it wouldn't work on 128 bit values. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.