Skip to content

OreEncrypt for u128/i128 panics on OreAes128 (never worked, no tests) #105

Open

Description

@coderdan

Bug

OreEncrypt is implemented for u128 and i128 against OreAes128, and the README and crate docs list them as supported, but every encryption panics:

let ore: OreAes128ChaCha20 = OreCipher::init(&k1, &k2).unwrap();
5u128.encrypt(&ore); // panics
thread 'probe' panicked at packages/ore-rs/src/scheme/bit2.rs:200:13:
index out of bounds: the len is 16 but the index is 16

Cause

The legacy scheme writes the block index at byte N of the 16-byte left-tag (PRF₁) input (left.f[n][N] = n as u8). With one block per byte, this limits it to 15 bytes. u128/i128 encode to 16 bytes. encrypt_left fails the same way.

History

Options

  • Remove the u128/i128 impls (breaking), or make them fail at compile time.
  • Add typed u128/i128 support on the chained scheme.
  • At minimum, return an OreError instead of panicking, and add tests.

#82 already corrects the docs so they no longer recommend OreAes128 for these types.

Activity

  1. coderdan commented on Oct 12, 2026

    @coderdan
    ContributorAuthor

    Why this was missed, and how to stop it recurring

    A coverage or CRAP gate would not have caught this.

    • CRAP is complexity² × (1 − coverage)³ + complexity. The u128/i128 impls are one-line, macro-generated functions with complexity 1. Even at 0% coverage they score 2, well below the usual threshold of about 30.
    • The panic is in OreAes128::encrypt<N> (bit2.rs), which the u64 tests already cover line for line. It fails only for one value of a const generic (N = 16), and line and branch coverage don't record which values of N were tried.
    • This is from how the metric is defined; it hasn't been confirmed by running cargo-llvm-cov.

    The real gap: each type's support is declared in one place (the impl macro invocations) and tested somewhere else, and nothing checks that the two lists match.

    Proposed guards (alongside the fix itself):

    1. Compile-time bound on N in the legacy scheme. Bit6 already has one: impl_ore_encrypt_bit6! asserts $blocks_const <= MAX_BLOCKS, so an out-of-range type doesn't compile. Adding the equivalent N <= 15 check to the OreAes128 impls would have stopped the u128 impl building on the day it was added (ad90f0b).
    2. Generate a test with each impl. Have the impl macro also emit a round-trip and ordering test for the type it implements, so a type can't be added without a test.
    3. (Unverified) A coverage gate that reports unused generic functions as zero-hit might flag impls that are never called. Check this before relying on it.
  2. added a commit that references this issue on Oct 16, 2026
    434f79b
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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions