Skip to main content

px_native/cipher/
offsets.rs

1//! `vN(target, lenBound, secret)` — offsets PRNG. See
2//! `r3-sensor-grammar-2026-05-20.md` for the un-flattened VM trace.
3//!
4//! Produces the sorted offsets array consumed by `vQ` to splice salt
5//! characters into the payload.
6
7use crate::cipher::b64::h_p;
8use crate::cipher::remap::v_m;
9use crate::cipher::xor::{VJ, jw};
10
11pub fn v_n(target_len: usize, len_bound: usize, secret: &[u8]) -> Vec<i64> {
12    let a_f = jw(h_p(secret).as_bytes(), VJ);
13    if a_f.is_empty() {
14        return Vec::new();
15    }
16    let len_bound_i = len_bound as i64;
17    let a_h = max_product(&a_f, target_len);
18    let mut a_g: Vec<i64> = Vec::with_capacity(target_len);
19    for a_m in 0..target_len {
20        let a_n = (a_m / a_f.len()) + 1;
21        let a_o = a_m % a_f.len();
22        let mut a_p = i64::from(a_f[a_o]) * i64::from(a_f[a_n]);
23        if a_p >= len_bound_i {
24            a_p = v_m(a_p, 0, a_h, 0, len_bound_i - 1);
25        }
26        while a_g.contains(&a_p) {
27            a_p += 1;
28        }
29        a_g.push(a_p);
30    }
31    a_g.sort_unstable();
32    a_g
33}
34
35fn max_product(a_f: &[u8], target_len: usize) -> i64 {
36    let mut a_h: i64 = -1;
37    for a_i in 0..target_len {
38        // JS: aJ = floor(aI / aF.length + 1) — the +1 is INSIDE the
39        // division before floor(), matching the first VM arm.
40        let a_j = ((a_i as f64) / (a_f.len() as f64) + 1.0).floor() as usize;
41        let a_k = if a_i >= a_f.len() {
42            a_i % a_f.len()
43        } else {
44            a_i
45        };
46        let a_l = i64::from(a_f[a_k]) * i64::from(a_f[a_j]);
47        if a_l > a_h {
48            a_h = a_l;
49        }
50    }
51    a_h
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn output_is_sorted_and_sized() {
60        let offsets = v_n(50, 50, b"some-secret");
61        assert_eq!(offsets.len(), 50);
62        for w in offsets.windows(2) {
63            assert!(w[0] <= w[1]);
64        }
65    }
66
67    #[test]
68    fn empty_secret_returns_empty() {
69        assert!(v_n(10, 10, b"").is_empty());
70    }
71}