Skip to content

ILNP nonce builders size with floor division: math.ceil(bit_length() // 8) at hopopt.py:1889 and ipv6_opts.py:1892 #601

Description

@JarryShaw

The ILNP nonce builders size their option with math.ceil(nonce.bit_length() // 8), which is floor division — math.ceil on an int is a no-op — so the declared length is wrong for every nonce whose bit length is not a multiple of 8.

The two sites

pcapkit/protocols/internet/hopopt.py:1889      len=math.ceil(nonce.bit_length() // 8),
pcapkit/protocols/internet/ipv6_opts.py:1892   len=math.ceil(nonce.bit_length() // 8),

Both are the ILNP Nonce option builder.

The codebase already knows the correct form, in eight other places

pcapkit/protocols/internet/hip.py:3156    len=4 + math.ceil(random.bit_length() / 8),
pcapkit/protocols/internet/hip.py:3334    pub_len = math.ceil(pub_val.bit_length() / 8)
pcapkit/protocols/internet/hip.py:4276    len=math.ceil(id.bit_length() / 8),
pcapkit/protocols/internet/hip.py:4302    len=math.ceil(id.bit_length() / 8),
pcapkit/protocols/internet/mh.py:7947     id_len = max(1, math.ceil(identifier.bit_length() / 8))

and pcapkit/protocols/internet/mh.py:7936 carries a comment that states the distinction outright:

id_len = math.ceil(identifier.bit_length() / 8) was the right …

So this is a two-site typo against an established convention, not an unresolved design question.

Measured

math.ceil(n // 8) versus math.ceil(n / 8), executed on origin/main (13a75dfcd):

value=1         bit_length=1   floor=0  correct=1  WRONG
value=2         bit_length=2   floor=0  correct=1  WRONG
value=42        bit_length=6   floor=0  correct=1  WRONG
value=127       bit_length=7   floor=0  correct=1  WRONG
value=255       bit_length=8   floor=1  correct=1
value=256       bit_length=9   floor=1  correct=2  WRONG
value=65536     bit_length=17  floor=2  correct=3  WRONG

Small nonces are the worst case, not boundary values: any nonce below 256 is sized at zero octets. Only a bit length that is an exact multiple of 8 gives the right answer.

Why the test suite does not catch it

There is no ILNP entry in EXPECTED_FAILURES in tests/protocols/test_option_roundtrip_unit.py — confirmed by importing it rather than grepping, since it is built with ** unpacking; 45 entries, none ILNP-related. So the round-trip case passes, which means it is landing on a nonce whose bit length happens to divide by 8.

That is the same blind spot that hid the identical defect in pcapkit/corekit/fields/numbers.py: #591's repair-path suite used 0xFF, 0xFFFF, 0xFFFFFFFF, 0xFFFFFFFFFFFFFFFF and 0x800001 — bit lengths 8, 16, 32, 64 and 24, every one an exact multiple of 8, precisely where floor division and the ceiling agree. A fix here needs a nonce whose bit length is not a multiple of 8, and ideally one below 256.

Notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions