Kevin Crutt commited on
Commit
ce80562
·
1 Parent(s): f8ee7f1

Apply rustfmt attack-verify fix

Browse files
Files changed (1) hide show
  1. src/lib.rs +316 -82
src/lib.rs CHANGED
@@ -34,29 +34,60 @@ pub enum Held {
34
  }
35
 
36
  fn blocks(d: &[u8]) -> Vec<u128> {
37
- d.chunks(BLOCK).map(|c| {
38
- let mut v = 0u128;
39
- for &b in c { v = (v << 8) | b as u128; }
40
- if c.len() < BLOCK { v <<= 8 * (BLOCK - c.len()) as u32; }
41
- v
42
- }).collect()
 
 
 
 
 
 
43
  }
44
  fn mod_inv(a: u128, m: u128) -> Option<u128> {
45
- fn e(a: i128, b: i128) -> (i128, i128, i128) { if a == 0 { (b, 0, 1) } else { let (g, x, y) = e(b % a, a); (g, y - (b / a) * x, x) } }
46
- if m == 0 { return None; }
 
 
 
 
 
 
 
 
 
47
  let (g, x, _) = e((a % m) as i128, m as i128);
48
- if g != 1 { return None; }
 
 
49
  Some((((x % m as i128) + m as i128) % m as i128) as u128)
50
  }
51
  /// The K shadow projections of a slice: residues of each block on each cylinder (the tomographic
52
  /// projections at K "angles"). Each shadow alone is lossy; enough of them reconstruct the slice.
53
  pub fn project_shadows(slice: &[u8]) -> Vec<Vec<u64>> {
54
- CYLINDERS.iter().map(|&p| blocks(slice).iter().map(|&b| (b % p as u128) as u64).collect()).collect()
 
 
 
 
 
 
 
 
55
  }
56
  /// Reconstruct the exact slice from a SUBSET of shadows (the inverse Radon / CRT). `Held` if the
57
  /// subset's joint modulus doesn't cover a block (under-sampled angles -> ill-posed).
58
- pub fn reconstruct(shadows: &[Vec<u64>], subset: &[usize], orig_len: usize) -> Result<Vec<u8>, Held> {
59
- if subset.is_empty() { return Err(Held::InsufficientShadows); }
 
 
 
 
 
 
60
  let range = 1u128 << (8 * BLOCK as u32);
61
  let nb = shadows[subset[0]].len();
62
  let mut out = Vec::with_capacity(nb * BLOCK);
@@ -69,10 +100,16 @@ pub fn reconstruct(shadows: &[Vec<u64>], subset: &[usize], orig_len: usize) -> R
69
  let diff = (((s as i128 - r as i128) % p as i128) + p as i128) % p as i128;
70
  r += m * ((diff as u128 * inv) % p);
71
  m *= p;
72
- if m >= range { break; }
 
 
 
 
 
 
 
 
73
  }
74
- if m < range { return Err(Held::InsufficientShadows); }
75
- for i in (0..BLOCK).rev() { out.push(((r >> (8 * i as u32)) & 0xFF) as u8); }
76
  }
77
  out.truncate(orig_len);
78
  Ok(out)
@@ -81,13 +118,23 @@ pub fn reconstruct(shadows: &[Vec<u64>], subset: &[usize], orig_len: usize) -> R
81
  // ---------------------------------------------------------------- metatagged deterministic sim
82
  /// A metatagged particle on the bounded torus grid.
83
  #[derive(Debug, Clone, PartialEq, Eq)]
84
- pub struct Particle { pub x: u16, pub y: u16, pub vx: i16, pub vy: i16, pub tag: u32 }
 
 
 
 
 
 
85
 
86
  /// The simulated-universe STATE = a bounded grid of metatagged particles. Its serialization is the
87
  /// "slice"; the transition rule is constant-velocity torus drift (deterministic + REVERSIBLE, so
88
  /// retrodiction and extrapolation are the same operation at +/-t).
89
  #[derive(Debug, Clone, PartialEq, Eq)]
90
- pub struct SimState { pub w: u16, pub h: u16, pub particles: Vec<Particle> }
 
 
 
 
91
 
92
  impl SimState {
93
  /// Canonical serialization (particles sorted by tag) -> the slice bytes.
@@ -108,15 +155,21 @@ impl SimState {
108
  out
109
  }
110
  pub fn deserialize(bytes: &[u8]) -> Option<SimState> {
111
- if bytes.len() < 6 { return None; }
 
 
112
  let w = u16::from_be_bytes([bytes[0], bytes[1]]);
113
  let h = u16::from_be_bytes([bytes[2], bytes[3]]);
114
  let n = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
115
- if w == 0 || h == 0 { return None; }
 
 
116
  let mut particles = Vec::with_capacity(n);
117
  for i in 0..n {
118
  let o = 6 + i * 12;
119
- if o + 12 > bytes.len() { return None; }
 
 
120
  particles.push(Particle {
121
  x: u16::from_be_bytes([bytes[o], bytes[o + 1]]),
122
  y: u16::from_be_bytes([bytes[o + 2], bytes[o + 3]]),
@@ -129,34 +182,76 @@ impl SimState {
129
  }
130
  /// Deterministic, reversible transition by `dt` steps (constant-velocity torus drift).
131
  pub fn at(&self, dt: i64) -> SimState {
132
- let particles = self.particles.iter().map(|p| Particle {
133
- x: (p.x as i64 + dt * p.vx as i64).rem_euclid(self.w as i64) as u16,
134
- y: (p.y as i64 + dt * p.vy as i64).rem_euclid(self.h as i64) as u16,
135
- vx: p.vx, vy: p.vy, tag: p.tag,
136
- }).collect();
137
- SimState { w: self.w, h: self.h, particles }
138
- }
139
- pub fn step_forward(&self) -> SimState { self.at(1) }
140
- pub fn step_backward(&self) -> SimState { self.at(-1) }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  /// An IRREVERSIBLE step (the arrow of time): a particle that would leave the grid is CLAMPED to
142
  /// the edge and its velocity ZEROED - the pre-collision velocity is LOST. Once this happens,
143
  /// reverse-propagation cannot uniquely recover the past (many pasts map to this present).
144
  pub fn clamp_step(&self) -> SimState {
145
- let particles = self.particles.iter().map(|p| {
146
- let nx = p.x as i32 + p.vx as i32;
147
- let ny = p.y as i32 + p.vy as i32;
148
- let (x, vx) = if nx < 0 || nx >= self.w as i32 { (p.x, 0i16) } else { (nx as u16, p.vx) };
149
- let (y, vy) = if ny < 0 || ny >= self.h as i32 { (p.y, 0i16) } else { (ny as u16, p.vy) };
150
- Particle { x, y, vx, vy, tag: p.tag }
151
- }).collect();
152
- SimState { w: self.w, h: self.h, particles }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
  }
155
 
156
  // ---------------------------------------------------------------- MTP movement matrix (the "time-travel" lens)
157
  fn torus_delta(from: u16, to: u16, m: u16) -> i32 {
158
  let (d, m) = (to as i32 - from as i32, m as i32);
159
- if d > m / 2 { d - m } else if d < -m / 2 { d + m } else { d } // shortest signed torus delta
 
 
 
 
 
 
160
  }
161
  /// The total movement matrix the MTP-1/2/3 supervisors measure between two slices: per metatag,
162
  /// MTP1 = pixel delta (dx,dy), MTP2 = frequency/shell (speed), MTP3 = cylinder/residue (tag identity).
@@ -174,8 +269,14 @@ impl MtpMovementMatrix {
174
  for pa in &a.particles {
175
  match b.particles.iter().find(|pb| pb.tag == pa.tag) {
176
  Some(pb) => {
177
- if pb.vx != pa.vx || pb.vy != pa.vy { reversible = false; } // velocity lost -> irreversible
178
- moves.push((pa.tag, torus_delta(pa.x, pb.x, a.w), torus_delta(pa.y, pb.y, a.h)));
 
 
 
 
 
 
179
  }
180
  None => reversible = false,
181
  }
@@ -183,20 +284,39 @@ impl MtpMovementMatrix {
183
  MtpMovementMatrix { moves, reversible }
184
  }
185
  fn apply(&self, state: &SimState, dir: i32) -> SimState {
186
- let particles = state.particles.iter().map(|p| {
187
- let (dx, dy) = self.moves.iter().find(|(t, _, _)| *t == p.tag).map(|(_, dx, dy)| (*dx, *dy)).unwrap_or((0, 0));
188
- Particle {
189
- x: (p.x as i32 + dir * dx).rem_euclid(state.w as i32) as u16,
190
- y: (p.y as i32 + dir * dy).rem_euclid(state.h as i32) as u16,
191
- vx: p.vx, vy: p.vy, tag: p.tag,
192
- }
193
- }).collect();
194
- SimState { w: state.w, h: state.h, particles }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  }
196
  /// Reverse LeWorld through the lens: project the slice one tick into the PAST (retrodiction).
197
- pub fn project_reverse(&self, state: &SimState) -> SimState { self.apply(state, -1) }
 
 
198
  /// Forward LeWorld: project the slice one tick into the FUTURE.
199
- pub fn project_forward(&self, state: &SimState) -> SimState { self.apply(state, 1) }
 
 
200
  pub fn hbp(&self) -> String {
201
  format!("MTPMATRIX|moves={}|mtp1=pixel_delta|mtp2=frequency_shell|mtp3=cylinder_residue|reversible={}|lens=reverse_leworld_projection|body_in_row=0|json=0",
202
  self.moves.len(), self.reversible)
@@ -235,7 +355,11 @@ impl SliceTimeReport {
235
  /// The deterministic regime (steps 1-6): reconstruct t0 from shadows (multi-cylinder / Q-PRISM),
236
  /// extrapolate the KNOWN rule forward and backward, and compare each predicted slice byte-for-byte
237
  /// against generated truth. Exact in the determined regime; `Held` if shadows are insufficient.
238
- pub fn run_deterministic(truth0: &SimState, horizon: i64, subset: &[usize]) -> Result<SliceTimeReport, Held> {
 
 
 
 
239
  let slice0 = truth0.serialize();
240
  let shadows = project_shadows(&slice0);
241
  let recon = reconstruct(&shadows, subset, slice0.len())?;
@@ -246,13 +370,21 @@ pub fn run_deterministic(truth0: &SimState, horizon: i64, subset: &[usize]) -> R
246
  forward_exact.push((k, state0.at(k).serialize() == truth0.at(k).serialize()));
247
  backward_exact.push((-k, state0.at(-k).serialize() == truth0.at(-k).serialize()));
248
  }
249
- Ok(SliceTimeReport { reconstructed_ok, forward_exact, backward_exact })
 
 
 
 
250
  }
251
 
252
  /// The HONEST BOUNDARY (step 6): given a truth slice that GAINED entropy the rule cannot fix (an
253
  /// injected particle, an external input), the deterministic prediction from `state0` will NOT match.
254
  /// Returns Err(PredictionDivergedNewEntropy) - the break is DETECTED, never silently "predicted".
255
- pub fn verify_or_detect_entropy(state0: &SimState, observed_future: &SimState, dt: i64) -> Result<(), Held> {
 
 
 
 
256
  if state0.at(dt).serialize() == observed_future.serialize() {
257
  Ok(()) // determined: 0-loss
258
  } else {
@@ -271,20 +403,36 @@ pub fn verify_or_detect_entropy(state0: &SimState, observed_future: &SimState, d
271
  // - no claim this IS the universe engine.
272
 
273
  #[derive(Debug, Clone, PartialEq, Eq)]
274
- pub enum Verdict { VerifiedClone(Vec<u8>), Held(HeldReason) }
 
 
 
275
  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
276
- pub enum HeldReason { InsufficientShadows, WatcherDisagreement }
 
 
 
277
 
278
  /// The watcher gate: reconstruct from `sufficient`; then every `cross` cylinder must agree with the
279
  /// reconstruction (catches a corrupted / hallucinated shadow). All agree -> verified classical clone.
280
- pub fn watcher_gate(shadows: &[Vec<u64>], sufficient: &[usize], cross: &[usize], orig_len: usize) -> Verdict {
 
 
 
 
 
281
  let recon = match reconstruct(shadows, sufficient, orig_len) {
282
  Ok(r) => r,
283
  Err(_) => return Verdict::Held(HeldReason::InsufficientShadows),
284
  };
285
  for &ci in cross {
286
- let recomputed: Vec<u64> = blocks(&recon).iter().map(|&b| (b % CYLINDERS[ci] as u128) as u64).collect();
287
- if recomputed != shadows[ci] { return Verdict::Held(HeldReason::WatcherDisagreement); }
 
 
 
 
 
288
  }
289
  Verdict::VerifiedClone(recon)
290
  }
@@ -292,10 +440,14 @@ pub fn watcher_gate(shadows: &[Vec<u64>], sufficient: &[usize], cross: &[usize],
292
  /// FNV-1a 64-bit fold -> an 8-byte addressing digest (NOT a crypto hash).
293
  fn digest8(slice: &[u8]) -> [u8; 8] {
294
  let mut h = 0xcbf29ce484222325u64;
295
- for &b in slice { h = (h ^ b as u64).wrapping_mul(0x100000001b3); }
 
 
296
  h.to_be_bytes()
297
  }
298
- fn hex8(b: &[u8; 8]) -> String { b.iter().map(|x| format!("{:02x}", x)).collect() }
 
 
299
 
300
  /// The OMNIBIT PIXEL - one pixel carrying the representation STACK as SELECTORS + CHECKS, not raw
301
  /// payload: position/tick/frequency, an 8-byte fold digest, the residual selector bits, the signed
@@ -304,18 +456,33 @@ fn hex8(b: &[u8; 8]) -> String { b.iter().map(|x| format!("{:02x}", x)).collect(
304
  /// checks against the shared atlas. Not a magical all-information bit.
305
  #[derive(Debug, Clone, PartialEq, Eq)]
306
  pub struct OmnibitPixel {
307
- pub x: u16, pub y: u16, pub tick: u32, pub freq: u16,
 
 
 
308
  pub digest8: [u8; 8],
309
  pub residual_bits: u8,
310
  pub capacity_margin_bits: i32,
311
  pub watcher_bound: u8,
312
  }
313
  impl OmnibitPixel {
314
- pub fn of(slice: &[u8], x: u16, y: u16, tick: u32, freq: u16, n_cylinders: usize, watcher_bound: u8) -> Self {
 
 
 
 
 
 
 
 
315
  let roof = (n_cylinders.min(CYLINDERS.len()) as f64) * 25.0; // ~log2(2^25) per cylinder
316
  let block_bits = (8 * BLOCK) as f64;
317
  OmnibitPixel {
318
- x, y, tick, freq, digest8: digest8(slice),
 
 
 
 
319
  residual_bits: (block_bits - roof).max(0.0).ceil() as u8,
320
  capacity_margin_bits: (roof - block_bits) as i32,
321
  watcher_bound,
@@ -334,12 +501,37 @@ mod tests {
334
 
335
  fn sample_state() -> SimState {
336
  SimState {
337
- w: 64, h: 48,
 
338
  particles: vec![
339
- Particle { x: 3, y: 5, vx: 2, vy: -1, tag: 1 },
340
- Particle { x: 60, y: 1, vx: -3, vy: 4, tag: 2 },
341
- Particle { x: 31, y: 24, vx: 1, vy: 1, tag: 3 },
342
- Particle { x: 0, y: 47, vx: 5, vy: -2, tag: 4 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  ],
344
  }
345
  }
@@ -348,7 +540,9 @@ mod tests {
348
  fn serialize_roundtrips() {
349
  let s = sample_state();
350
  assert_eq!(SimState::deserialize(&s.serialize()).unwrap(), {
351
- let mut c = s.clone(); c.particles.sort_by_key(|p| p.tag); c
 
 
352
  });
353
  }
354
 
@@ -356,7 +550,11 @@ mod tests {
356
  fn rule_is_reversible() {
357
  let s = sample_state();
358
  for k in 1..=20 {
359
- assert_eq!(s.at(k).at(-k).serialize(), s.serialize(), "at(+{k}).at(-{k}) must be identity");
 
 
 
 
360
  }
361
  }
362
 
@@ -366,7 +564,10 @@ mod tests {
366
  // enough shadows (all 4 cylinders) -> full state reconstructed -> every slice exact both ways
367
  let report = run_deterministic(&s, 25, &[0, 1, 2, 3]).unwrap();
368
  assert!(report.reconstructed_ok);
369
- assert!(report.all_exact(), "determined regime: past AND future slices are 0-loss");
 
 
 
370
  assert_eq!(report.forward_exact.len(), 25);
371
  assert_eq!(report.backward_exact.len(), 25);
372
  }
@@ -375,7 +576,10 @@ mod tests {
375
  fn two_shadows_already_suffice_one_holds() {
376
  let s = sample_state();
377
  assert!(run_deterministic(&s, 5, &[0, 1]).unwrap().all_exact()); // 2 cylinders cover a 48-bit block
378
- assert!(matches!(run_deterministic(&s, 5, &[0]), Err(Held::InsufficientShadows))); // 1 -> Shannon Held
 
 
 
379
  }
380
 
381
  #[test]
@@ -385,8 +589,17 @@ mod tests {
385
  assert!(verify_or_detect_entropy(&s, &s.at(7), 7).is_ok());
386
  // but a future that GAINED entropy (an injected particle) is DETECTED, never manufactured:
387
  let mut injected = s.at(7);
388
- injected.particles.push(Particle { x: 9, y: 9, vx: 0, vy: 0, tag: 9999 });
389
- assert_eq!(verify_or_detect_entropy(&s, &injected, 7), Err(Held::PredictionDivergedNewEntropy));
 
 
 
 
 
 
 
 
 
390
  }
391
 
392
  #[test]
@@ -402,13 +615,22 @@ mod tests {
402
  let slice = b"the yin-yang watcher: black-absorb, white-emit, round-trip or Held";
403
  let shadows = project_shadows(slice);
404
  // clean: reconstruct from [0,1], cross-check [2,3] -> verified classical clone
405
- assert_eq!(watcher_gate(&shadows, &[0, 1], &[2, 3], slice.len()), Verdict::VerifiedClone(slice.to_vec()));
 
 
 
406
  // tamper a sufficient shadow -> the cross cylinders catch the hallucination -> Held
407
  let mut tampered = shadows.clone();
408
  tampered[0][0] = tampered[0][0].wrapping_add(1);
409
- assert_eq!(watcher_gate(&tampered, &[0, 1], &[2, 3], slice.len()), Verdict::Held(HeldReason::WatcherDisagreement));
 
 
 
410
  // too few -> Held (Shannon)
411
- assert_eq!(watcher_gate(&shadows, &[0], &[], slice.len()), Verdict::Held(HeldReason::InsufficientShadows));
 
 
 
412
  }
413
 
414
  #[test]
@@ -419,7 +641,9 @@ mod tests {
419
  assert!(px2.capacity_margin_bits >= 0); // over-determination margin, never negative storage
420
  let px1 = OmnibitPixel::of(slice, 3, 5, 7, 440, 1, 0);
421
  assert!(px1.residual_bits > 0); // 1 cylinder under-covers -> residual selector remains
422
- assert!(px2.to_hbp().contains("payload=selector-not-raw") && px2.to_hbp().ends_with("json=0"));
 
 
423
  }
424
 
425
  #[test]
@@ -429,7 +653,7 @@ mod tests {
429
  // MTP-1/2/3 measure the total movement matrix s0 -> s1
430
  let mtp = MtpMovementMatrix::measure(&s0, &s1);
431
  assert!(mtp.reversible); // constant-velocity drift is reversible
432
- // "time travel": from s1, the lens projects the reverse slice -> s0 byte-identical (retrodiction)
433
  assert_eq!(mtp.project_reverse(&s1).serialize(), s0.serialize());
434
  // and forward -> s2 byte-identical (the same matrix runs both ways)
435
  assert_eq!(mtp.project_forward(&s1).serialize(), s0.at(2).serialize());
@@ -439,11 +663,21 @@ mod tests {
439
  #[test]
440
  fn arrow_of_time_irreversible_step_cannot_be_retrodicted() {
441
  // a particle heading off the edge is CLAMPED (velocity zeroed = information lost)
442
- let s = SimState { w: 10, h: 10, particles: vec![Particle { x: 9, y: 5, vx: 3, vy: 0, tag: 1 }] };
 
 
 
 
 
 
 
 
 
 
443
  let clamped = s.clamp_step();
444
  let mtp = MtpMovementMatrix::measure(&s, &clamped);
445
  assert!(!mtp.reversible); // the velocity changed -> the movement lost information
446
- // reverse-propagating the clamped present does NOT recover the true past -> the arrow of time bites
447
  assert_ne!(mtp.project_reverse(&clamped).serialize(), s.serialize());
448
  }
449
  }
 
34
  }
35
 
36
  fn blocks(d: &[u8]) -> Vec<u128> {
37
+ d.chunks(BLOCK)
38
+ .map(|c| {
39
+ let mut v = 0u128;
40
+ for &b in c {
41
+ v = (v << 8) | b as u128;
42
+ }
43
+ if c.len() < BLOCK {
44
+ v <<= 8 * (BLOCK - c.len()) as u32;
45
+ }
46
+ v
47
+ })
48
+ .collect()
49
  }
50
  fn mod_inv(a: u128, m: u128) -> Option<u128> {
51
+ fn e(a: i128, b: i128) -> (i128, i128, i128) {
52
+ if a == 0 {
53
+ (b, 0, 1)
54
+ } else {
55
+ let (g, x, y) = e(b % a, a);
56
+ (g, y - (b / a) * x, x)
57
+ }
58
+ }
59
+ if m == 0 {
60
+ return None;
61
+ }
62
  let (g, x, _) = e((a % m) as i128, m as i128);
63
+ if g != 1 {
64
+ return None;
65
+ }
66
  Some((((x % m as i128) + m as i128) % m as i128) as u128)
67
  }
68
  /// The K shadow projections of a slice: residues of each block on each cylinder (the tomographic
69
  /// projections at K "angles"). Each shadow alone is lossy; enough of them reconstruct the slice.
70
  pub fn project_shadows(slice: &[u8]) -> Vec<Vec<u64>> {
71
+ CYLINDERS
72
+ .iter()
73
+ .map(|&p| {
74
+ blocks(slice)
75
+ .iter()
76
+ .map(|&b| (b % p as u128) as u64)
77
+ .collect()
78
+ })
79
+ .collect()
80
  }
81
  /// Reconstruct the exact slice from a SUBSET of shadows (the inverse Radon / CRT). `Held` if the
82
  /// subset's joint modulus doesn't cover a block (under-sampled angles -> ill-posed).
83
+ pub fn reconstruct(
84
+ shadows: &[Vec<u64>],
85
+ subset: &[usize],
86
+ orig_len: usize,
87
+ ) -> Result<Vec<u8>, Held> {
88
+ if subset.is_empty() {
89
+ return Err(Held::InsufficientShadows);
90
+ }
91
  let range = 1u128 << (8 * BLOCK as u32);
92
  let nb = shadows[subset[0]].len();
93
  let mut out = Vec::with_capacity(nb * BLOCK);
 
100
  let diff = (((s as i128 - r as i128) % p as i128) + p as i128) % p as i128;
101
  r += m * ((diff as u128 * inv) % p);
102
  m *= p;
103
+ if m >= range {
104
+ break;
105
+ }
106
+ }
107
+ if m < range {
108
+ return Err(Held::InsufficientShadows);
109
+ }
110
+ for i in (0..BLOCK).rev() {
111
+ out.push(((r >> (8 * i as u32)) & 0xFF) as u8);
112
  }
 
 
113
  }
114
  out.truncate(orig_len);
115
  Ok(out)
 
118
  // ---------------------------------------------------------------- metatagged deterministic sim
119
  /// A metatagged particle on the bounded torus grid.
120
  #[derive(Debug, Clone, PartialEq, Eq)]
121
+ pub struct Particle {
122
+ pub x: u16,
123
+ pub y: u16,
124
+ pub vx: i16,
125
+ pub vy: i16,
126
+ pub tag: u32,
127
+ }
128
 
129
  /// The simulated-universe STATE = a bounded grid of metatagged particles. Its serialization is the
130
  /// "slice"; the transition rule is constant-velocity torus drift (deterministic + REVERSIBLE, so
131
  /// retrodiction and extrapolation are the same operation at +/-t).
132
  #[derive(Debug, Clone, PartialEq, Eq)]
133
+ pub struct SimState {
134
+ pub w: u16,
135
+ pub h: u16,
136
+ pub particles: Vec<Particle>,
137
+ }
138
 
139
  impl SimState {
140
  /// Canonical serialization (particles sorted by tag) -> the slice bytes.
 
155
  out
156
  }
157
  pub fn deserialize(bytes: &[u8]) -> Option<SimState> {
158
+ if bytes.len() < 6 {
159
+ return None;
160
+ }
161
  let w = u16::from_be_bytes([bytes[0], bytes[1]]);
162
  let h = u16::from_be_bytes([bytes[2], bytes[3]]);
163
  let n = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
164
+ if w == 0 || h == 0 {
165
+ return None;
166
+ }
167
  let mut particles = Vec::with_capacity(n);
168
  for i in 0..n {
169
  let o = 6 + i * 12;
170
+ if o + 12 > bytes.len() {
171
+ return None;
172
+ }
173
  particles.push(Particle {
174
  x: u16::from_be_bytes([bytes[o], bytes[o + 1]]),
175
  y: u16::from_be_bytes([bytes[o + 2], bytes[o + 3]]),
 
182
  }
183
  /// Deterministic, reversible transition by `dt` steps (constant-velocity torus drift).
184
  pub fn at(&self, dt: i64) -> SimState {
185
+ let particles = self
186
+ .particles
187
+ .iter()
188
+ .map(|p| Particle {
189
+ x: (p.x as i64 + dt * p.vx as i64).rem_euclid(self.w as i64) as u16,
190
+ y: (p.y as i64 + dt * p.vy as i64).rem_euclid(self.h as i64) as u16,
191
+ vx: p.vx,
192
+ vy: p.vy,
193
+ tag: p.tag,
194
+ })
195
+ .collect();
196
+ SimState {
197
+ w: self.w,
198
+ h: self.h,
199
+ particles,
200
+ }
201
+ }
202
+ pub fn step_forward(&self) -> SimState {
203
+ self.at(1)
204
+ }
205
+ pub fn step_backward(&self) -> SimState {
206
+ self.at(-1)
207
+ }
208
  /// An IRREVERSIBLE step (the arrow of time): a particle that would leave the grid is CLAMPED to
209
  /// the edge and its velocity ZEROED - the pre-collision velocity is LOST. Once this happens,
210
  /// reverse-propagation cannot uniquely recover the past (many pasts map to this present).
211
  pub fn clamp_step(&self) -> SimState {
212
+ let particles = self
213
+ .particles
214
+ .iter()
215
+ .map(|p| {
216
+ let nx = p.x as i32 + p.vx as i32;
217
+ let ny = p.y as i32 + p.vy as i32;
218
+ let (x, vx) = if nx < 0 || nx >= self.w as i32 {
219
+ (p.x, 0i16)
220
+ } else {
221
+ (nx as u16, p.vx)
222
+ };
223
+ let (y, vy) = if ny < 0 || ny >= self.h as i32 {
224
+ (p.y, 0i16)
225
+ } else {
226
+ (ny as u16, p.vy)
227
+ };
228
+ Particle {
229
+ x,
230
+ y,
231
+ vx,
232
+ vy,
233
+ tag: p.tag,
234
+ }
235
+ })
236
+ .collect();
237
+ SimState {
238
+ w: self.w,
239
+ h: self.h,
240
+ particles,
241
+ }
242
  }
243
  }
244
 
245
  // ---------------------------------------------------------------- MTP movement matrix (the "time-travel" lens)
246
  fn torus_delta(from: u16, to: u16, m: u16) -> i32 {
247
  let (d, m) = (to as i32 - from as i32, m as i32);
248
+ if d > m / 2 {
249
+ d - m
250
+ } else if d < -m / 2 {
251
+ d + m
252
+ } else {
253
+ d
254
+ } // shortest signed torus delta
255
  }
256
  /// The total movement matrix the MTP-1/2/3 supervisors measure between two slices: per metatag,
257
  /// MTP1 = pixel delta (dx,dy), MTP2 = frequency/shell (speed), MTP3 = cylinder/residue (tag identity).
 
269
  for pa in &a.particles {
270
  match b.particles.iter().find(|pb| pb.tag == pa.tag) {
271
  Some(pb) => {
272
+ if pb.vx != pa.vx || pb.vy != pa.vy {
273
+ reversible = false;
274
+ } // velocity lost -> irreversible
275
+ moves.push((
276
+ pa.tag,
277
+ torus_delta(pa.x, pb.x, a.w),
278
+ torus_delta(pa.y, pb.y, a.h),
279
+ ));
280
  }
281
  None => reversible = false,
282
  }
 
284
  MtpMovementMatrix { moves, reversible }
285
  }
286
  fn apply(&self, state: &SimState, dir: i32) -> SimState {
287
+ let particles = state
288
+ .particles
289
+ .iter()
290
+ .map(|p| {
291
+ let (dx, dy) = self
292
+ .moves
293
+ .iter()
294
+ .find(|(t, _, _)| *t == p.tag)
295
+ .map(|(_, dx, dy)| (*dx, *dy))
296
+ .unwrap_or((0, 0));
297
+ Particle {
298
+ x: (p.x as i32 + dir * dx).rem_euclid(state.w as i32) as u16,
299
+ y: (p.y as i32 + dir * dy).rem_euclid(state.h as i32) as u16,
300
+ vx: p.vx,
301
+ vy: p.vy,
302
+ tag: p.tag,
303
+ }
304
+ })
305
+ .collect();
306
+ SimState {
307
+ w: state.w,
308
+ h: state.h,
309
+ particles,
310
+ }
311
  }
312
  /// Reverse LeWorld through the lens: project the slice one tick into the PAST (retrodiction).
313
+ pub fn project_reverse(&self, state: &SimState) -> SimState {
314
+ self.apply(state, -1)
315
+ }
316
  /// Forward LeWorld: project the slice one tick into the FUTURE.
317
+ pub fn project_forward(&self, state: &SimState) -> SimState {
318
+ self.apply(state, 1)
319
+ }
320
  pub fn hbp(&self) -> String {
321
  format!("MTPMATRIX|moves={}|mtp1=pixel_delta|mtp2=frequency_shell|mtp3=cylinder_residue|reversible={}|lens=reverse_leworld_projection|body_in_row=0|json=0",
322
  self.moves.len(), self.reversible)
 
355
  /// The deterministic regime (steps 1-6): reconstruct t0 from shadows (multi-cylinder / Q-PRISM),
356
  /// extrapolate the KNOWN rule forward and backward, and compare each predicted slice byte-for-byte
357
  /// against generated truth. Exact in the determined regime; `Held` if shadows are insufficient.
358
+ pub fn run_deterministic(
359
+ truth0: &SimState,
360
+ horizon: i64,
361
+ subset: &[usize],
362
+ ) -> Result<SliceTimeReport, Held> {
363
  let slice0 = truth0.serialize();
364
  let shadows = project_shadows(&slice0);
365
  let recon = reconstruct(&shadows, subset, slice0.len())?;
 
370
  forward_exact.push((k, state0.at(k).serialize() == truth0.at(k).serialize()));
371
  backward_exact.push((-k, state0.at(-k).serialize() == truth0.at(-k).serialize()));
372
  }
373
+ Ok(SliceTimeReport {
374
+ reconstructed_ok,
375
+ forward_exact,
376
+ backward_exact,
377
+ })
378
  }
379
 
380
  /// The HONEST BOUNDARY (step 6): given a truth slice that GAINED entropy the rule cannot fix (an
381
  /// injected particle, an external input), the deterministic prediction from `state0` will NOT match.
382
  /// Returns Err(PredictionDivergedNewEntropy) - the break is DETECTED, never silently "predicted".
383
+ pub fn verify_or_detect_entropy(
384
+ state0: &SimState,
385
+ observed_future: &SimState,
386
+ dt: i64,
387
+ ) -> Result<(), Held> {
388
  if state0.at(dt).serialize() == observed_future.serialize() {
389
  Ok(()) // determined: 0-loss
390
  } else {
 
403
  // - no claim this IS the universe engine.
404
 
405
  #[derive(Debug, Clone, PartialEq, Eq)]
406
+ pub enum Verdict {
407
+ VerifiedClone(Vec<u8>),
408
+ Held(HeldReason),
409
+ }
410
  #[derive(Debug, Clone, Copy, PartialEq, Eq)]
411
+ pub enum HeldReason {
412
+ InsufficientShadows,
413
+ WatcherDisagreement,
414
+ }
415
 
416
  /// The watcher gate: reconstruct from `sufficient`; then every `cross` cylinder must agree with the
417
  /// reconstruction (catches a corrupted / hallucinated shadow). All agree -> verified classical clone.
418
+ pub fn watcher_gate(
419
+ shadows: &[Vec<u64>],
420
+ sufficient: &[usize],
421
+ cross: &[usize],
422
+ orig_len: usize,
423
+ ) -> Verdict {
424
  let recon = match reconstruct(shadows, sufficient, orig_len) {
425
  Ok(r) => r,
426
  Err(_) => return Verdict::Held(HeldReason::InsufficientShadows),
427
  };
428
  for &ci in cross {
429
+ let recomputed: Vec<u64> = blocks(&recon)
430
+ .iter()
431
+ .map(|&b| (b % CYLINDERS[ci] as u128) as u64)
432
+ .collect();
433
+ if recomputed != shadows[ci] {
434
+ return Verdict::Held(HeldReason::WatcherDisagreement);
435
+ }
436
  }
437
  Verdict::VerifiedClone(recon)
438
  }
 
440
  /// FNV-1a 64-bit fold -> an 8-byte addressing digest (NOT a crypto hash).
441
  fn digest8(slice: &[u8]) -> [u8; 8] {
442
  let mut h = 0xcbf29ce484222325u64;
443
+ for &b in slice {
444
+ h = (h ^ b as u64).wrapping_mul(0x100000001b3);
445
+ }
446
  h.to_be_bytes()
447
  }
448
+ fn hex8(b: &[u8; 8]) -> String {
449
+ b.iter().map(|x| format!("{:02x}", x)).collect()
450
+ }
451
 
452
  /// The OMNIBIT PIXEL - one pixel carrying the representation STACK as SELECTORS + CHECKS, not raw
453
  /// payload: position/tick/frequency, an 8-byte fold digest, the residual selector bits, the signed
 
456
  /// checks against the shared atlas. Not a magical all-information bit.
457
  #[derive(Debug, Clone, PartialEq, Eq)]
458
  pub struct OmnibitPixel {
459
+ pub x: u16,
460
+ pub y: u16,
461
+ pub tick: u32,
462
+ pub freq: u16,
463
  pub digest8: [u8; 8],
464
  pub residual_bits: u8,
465
  pub capacity_margin_bits: i32,
466
  pub watcher_bound: u8,
467
  }
468
  impl OmnibitPixel {
469
+ pub fn of(
470
+ slice: &[u8],
471
+ x: u16,
472
+ y: u16,
473
+ tick: u32,
474
+ freq: u16,
475
+ n_cylinders: usize,
476
+ watcher_bound: u8,
477
+ ) -> Self {
478
  let roof = (n_cylinders.min(CYLINDERS.len()) as f64) * 25.0; // ~log2(2^25) per cylinder
479
  let block_bits = (8 * BLOCK) as f64;
480
  OmnibitPixel {
481
+ x,
482
+ y,
483
+ tick,
484
+ freq,
485
+ digest8: digest8(slice),
486
  residual_bits: (block_bits - roof).max(0.0).ceil() as u8,
487
  capacity_margin_bits: (roof - block_bits) as i32,
488
  watcher_bound,
 
501
 
502
  fn sample_state() -> SimState {
503
  SimState {
504
+ w: 64,
505
+ h: 48,
506
  particles: vec![
507
+ Particle {
508
+ x: 3,
509
+ y: 5,
510
+ vx: 2,
511
+ vy: -1,
512
+ tag: 1,
513
+ },
514
+ Particle {
515
+ x: 60,
516
+ y: 1,
517
+ vx: -3,
518
+ vy: 4,
519
+ tag: 2,
520
+ },
521
+ Particle {
522
+ x: 31,
523
+ y: 24,
524
+ vx: 1,
525
+ vy: 1,
526
+ tag: 3,
527
+ },
528
+ Particle {
529
+ x: 0,
530
+ y: 47,
531
+ vx: 5,
532
+ vy: -2,
533
+ tag: 4,
534
+ },
535
  ],
536
  }
537
  }
 
540
  fn serialize_roundtrips() {
541
  let s = sample_state();
542
  assert_eq!(SimState::deserialize(&s.serialize()).unwrap(), {
543
+ let mut c = s.clone();
544
+ c.particles.sort_by_key(|p| p.tag);
545
+ c
546
  });
547
  }
548
 
 
550
  fn rule_is_reversible() {
551
  let s = sample_state();
552
  for k in 1..=20 {
553
+ assert_eq!(
554
+ s.at(k).at(-k).serialize(),
555
+ s.serialize(),
556
+ "at(+{k}).at(-{k}) must be identity"
557
+ );
558
  }
559
  }
560
 
 
564
  // enough shadows (all 4 cylinders) -> full state reconstructed -> every slice exact both ways
565
  let report = run_deterministic(&s, 25, &[0, 1, 2, 3]).unwrap();
566
  assert!(report.reconstructed_ok);
567
+ assert!(
568
+ report.all_exact(),
569
+ "determined regime: past AND future slices are 0-loss"
570
+ );
571
  assert_eq!(report.forward_exact.len(), 25);
572
  assert_eq!(report.backward_exact.len(), 25);
573
  }
 
576
  fn two_shadows_already_suffice_one_holds() {
577
  let s = sample_state();
578
  assert!(run_deterministic(&s, 5, &[0, 1]).unwrap().all_exact()); // 2 cylinders cover a 48-bit block
579
+ assert!(matches!(
580
+ run_deterministic(&s, 5, &[0]),
581
+ Err(Held::InsufficientShadows)
582
+ )); // 1 -> Shannon Held
583
  }
584
 
585
  #[test]
 
589
  assert!(verify_or_detect_entropy(&s, &s.at(7), 7).is_ok());
590
  // but a future that GAINED entropy (an injected particle) is DETECTED, never manufactured:
591
  let mut injected = s.at(7);
592
+ injected.particles.push(Particle {
593
+ x: 9,
594
+ y: 9,
595
+ vx: 0,
596
+ vy: 0,
597
+ tag: 9999,
598
+ });
599
+ assert_eq!(
600
+ verify_or_detect_entropy(&s, &injected, 7),
601
+ Err(Held::PredictionDivergedNewEntropy)
602
+ );
603
  }
604
 
605
  #[test]
 
615
  let slice = b"the yin-yang watcher: black-absorb, white-emit, round-trip or Held";
616
  let shadows = project_shadows(slice);
617
  // clean: reconstruct from [0,1], cross-check [2,3] -> verified classical clone
618
+ assert_eq!(
619
+ watcher_gate(&shadows, &[0, 1], &[2, 3], slice.len()),
620
+ Verdict::VerifiedClone(slice.to_vec())
621
+ );
622
  // tamper a sufficient shadow -> the cross cylinders catch the hallucination -> Held
623
  let mut tampered = shadows.clone();
624
  tampered[0][0] = tampered[0][0].wrapping_add(1);
625
+ assert_eq!(
626
+ watcher_gate(&tampered, &[0, 1], &[2, 3], slice.len()),
627
+ Verdict::Held(HeldReason::WatcherDisagreement)
628
+ );
629
  // too few -> Held (Shannon)
630
+ assert_eq!(
631
+ watcher_gate(&shadows, &[0], &[], slice.len()),
632
+ Verdict::Held(HeldReason::InsufficientShadows)
633
+ );
634
  }
635
 
636
  #[test]
 
641
  assert!(px2.capacity_margin_bits >= 0); // over-determination margin, never negative storage
642
  let px1 = OmnibitPixel::of(slice, 3, 5, 7, 440, 1, 0);
643
  assert!(px1.residual_bits > 0); // 1 cylinder under-covers -> residual selector remains
644
+ assert!(
645
+ px2.to_hbp().contains("payload=selector-not-raw") && px2.to_hbp().ends_with("json=0")
646
+ );
647
  }
648
 
649
  #[test]
 
653
  // MTP-1/2/3 measure the total movement matrix s0 -> s1
654
  let mtp = MtpMovementMatrix::measure(&s0, &s1);
655
  assert!(mtp.reversible); // constant-velocity drift is reversible
656
+ // "time travel": from s1, the lens projects the reverse slice -> s0 byte-identical (retrodiction)
657
  assert_eq!(mtp.project_reverse(&s1).serialize(), s0.serialize());
658
  // and forward -> s2 byte-identical (the same matrix runs both ways)
659
  assert_eq!(mtp.project_forward(&s1).serialize(), s0.at(2).serialize());
 
663
  #[test]
664
  fn arrow_of_time_irreversible_step_cannot_be_retrodicted() {
665
  // a particle heading off the edge is CLAMPED (velocity zeroed = information lost)
666
+ let s = SimState {
667
+ w: 10,
668
+ h: 10,
669
+ particles: vec![Particle {
670
+ x: 9,
671
+ y: 5,
672
+ vx: 3,
673
+ vy: 0,
674
+ tag: 1,
675
+ }],
676
+ };
677
  let clamped = s.clamp_step();
678
  let mtp = MtpMovementMatrix::measure(&s, &clamped);
679
  assert!(!mtp.reversible); // the velocity changed -> the movement lost information
680
+ // reverse-propagating the clamped present does NOT recover the true past -> the arrow of time bites
681
  assert_ne!(mtp.project_reverse(&clamped).serialize(), s.serialize());
682
  }
683
  }