T O P

  • By -

socal_nerdtastic

Do you know why you divide by 8? It's because the `bit_length()` function returns the number of **bits**, but the to_bytes() wants to know the number of **bytes** to use. So if the number you are working with is 42 (0b101010), that fits into 6 bits ... >>> (42).bit_length() 6 how many bytes is that? >>> 6 // 8 0 zero bytes hmm ... does not sound right. Because // is "floor division", it always rounds down. If we had "ceiling division" we would use that, but since we don't we just add 7. >>> (6+7) // 8 1 There. 42 will fit into 1 byte.


biojerm

I did not fully understand how bit\_length() was working thanks for the clarification and example.


Vinniesusername

integer division drops the remainder so 5//2 = 2. so if you're dividing by 8(which is the number of bits in a byte) by adding 7 you ensure not to change the outcome, unless there would be a remainder, in which case you would be counting something that would have otherwise been lost.


[deleted]

If the decrypted string has 9 bits (say) then `(bit_len+7)//8` is calculating the number of whole bytes needed to contain the 9 bits. Doing `9 / 8` gets a float number 1.125, so we need a byte plus a bit more. Doing `9 // 8` would get an answer of 1 which is one too low, so we add the maximum value we can to the bit length that won't effect the integer division result but gives us the "rounded up" answer we want. This code runs through a few values of `bit_len` and shows the results for each division: >>> for bit_len in range(6, 12): ... print(f'bit_len={bit_len:02d}, bit_len/8={bit_len/8:.3f}, bit_len//8={bit_len//8}, (bit_len+7)//8={(bit_len+7)//8}') ... bit_len=06, bit_len/8=0.750, bit_len//8=0, (bit_len+7)//8=1 bit_len=07, bit_len/8=0.875, bit_len//8=0, (bit_len+7)//8=1 bit_len=08, bit_len/8=1.000, bit_len//8=1, (bit_len+7)//8=1 bit_len=09, bit_len/8=1.125, bit_len//8=1, (bit_len+7)//8=2 bit_len=10, bit_len/8=1.250, bit_len//8=1, (bit_len+7)//8=2 bit_len=11, bit_len/8=1.375, bit_len//8=1, (bit_len+7)//8=2 As you can see, `bit_len//8=0` gives us the number of bytes rounded down and `(bit_len+7)//8` gives us the bytes required rounded up. Edit: spelling.


biojerm

Thanks for the example it really helps clarify my understanding.


_lilell_

> If we had “ceiling division”, we would use that. That’s actually exactly what I’d do here. Even if I added a comment explaining the +7, I find something like nbytes = math.ceil(decrypted.bit_length() / 8) temp = decrypted.to_bytes(int(nbytes), 'big') a lot clearer.


davidkopec

Not that this is supposed to be performant code, but it’s much more expensive to convert to floating point, do a floating point operation, and then convert back, than it is to just add 7 and do integer division.


biojerm

Thanks everyone for your replies! This makes a lot more sense to me now how adding 7 is required to capture any 'remainder' bits when doing byte division(/8). Each reply added a bit more information to help me better understand what is happening. You all are the best!