You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
OreEncrypt for u128/i128 panics on OreAes128 (never worked, no tests) #105
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
The impls were added in ad90f0b (2026-05-05, "impl OreEncrypt for all primitives via ToOrderableBytes"), so they have never worked on main.
No test or benchmark encrypts a u128 or i128, which is why nobody noticed.
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):
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).
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.
(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.
Activity
coderdan commentedon Oct 12, 2026
Why this was missed, and how to stop it recurring
A coverage or CRAP gate would not have caught this.
complexity² × (1 − coverage)³ + complexity. Theu128/i128impls are one-line, macro-generated functions with complexity 1. Even at 0% coverage they score 2, well below the usual threshold of about 30.OreAes128::encrypt<N>(bit2.rs), which theu64tests 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 ofNwere tried.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):
Nin 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 equivalentN <= 15check to theOreAes128impls would have stopped theu128impl building on the day it was added (ad90f0b).feat(chained): encrypt u128/i128 on the chained scheme; drop the pani…