//! §3.4: the load-time interval check and the per-frame cost, at their boundaries, and //! review A's attack payloads refused with the codes §2.7 gives. use wai_vector::bounds::{COST_CEILING, DEVICE_MAX, DEVICE_MIN}; use wai_vector::place::{self, fill_cost, origin, point_offset, linear_map}; use wai_vector::refuse::Code; use wai_vector::track::eval; use wai_vector::vectors::{corpus_store, find}; use wai_vector::wvg1::{self, NoSets}; fn load(group: &str, name: &str) -> Result { let v = find(group, name).unwrap_or_else(|| panic!("no vector {group}/{name}")); wvg1::load(&v.bytes, &mut corpus_store()) } #[test] fn interval_check_boundary() { for name in ["x-high-edge", "x-low-edge", "y-high-edge", "empty-glyph-edge"] { assert!(load("geometry", name).is_ok(), "{name}: an end at the range's edge is accepted"); } for name in ["x-high-over", "x-low-over", "y-high-over", "second-size-over", "inactive-item-over", "clip-over", "groups-sum-over", "empty-glyph-over"] { assert_eq!(load("geometry", name).unwrap_err().code, Code::GeometryRange, "{name}"); } } /// The rule is the interval computation, not the true range: this document's device /// x reaches exactly 2^22 − 1 at every tick, and it is refused. #[test] fn interval_not_true_range() { let v = find("geometry", "true-range-fits").unwrap(); let d = wvg1::parse(&v.bytes).unwrap(); // The true range, evaluated at every tick of the item's window and every corner. let it = &d.items[0]; let (w, dw) = (i64::from(d.sizes[0].w), i64::from(d.header.design_w)); let track = |s: usize| d.track_keys(it.slots[s] as usize); let bx = d.paths[0].bbox; let (mut lo, mut hi) = (i64::MAX, i64::MIN); for tau in i64::from(it.t_on)..i64::from(it.t_off) { let m = [eval(track(0), &d.tables, tau), eval(track(1), &d.tables, tau), 0, 65_536]; let l = linear_map(m, i64::from(it.unit_scale), w, dw); let t = origin([eval(track(4), &d.tables, tau), 0], m, [0, 0], w, dw); for px in [bx[0], bx[2]] { for py in [bx[1], bx[3]] { let x = t[0] + point_offset(l, [i64::from(px), i64::from(py)])[0]; lo = lo.min(x); hi = hi.max(x); } } } assert!(DEVICE_MIN <= lo && hi == DEVICE_MAX, "the true range [{lo}, {hi}] fits, its end at 2^22 - 1"); assert_eq!(load("geometry", "true-range-fits").unwrap_err().code, Code::GeometryRange); } #[test] fn cost_ceiling_boundary() { let l = load("cost", "ceiling").expect("a cost of exactly 2^32 - 1 is accepted"); assert_eq!(l.costs, vec![COST_CEILING]); assert_eq!(load("cost", "ceiling-plus-one").unwrap_err().code, Code::TooLarge); let e = load("cost", "ceiling-stated-low").unwrap_err(); assert_eq!((e.code, e.step), (Code::PayloadMalformed, "9"), "a stated cost off by one"); let e = load("cost", "reused-path-stated-high").unwrap_err(); assert_eq!((e.code, e.step), (Code::PayloadMalformed, "9")); } /// Each use of a reused path counts: three fills of one 4-point path whose box is /// 11 × 11 pixels at 640 × 360. #[test] fn cost_counts_a_reused_path_per_use() { let one = 4 * (1024 + 11 + 11) + 11 * 11; assert_eq!(fill_cost(4, 11, 11), one); assert_eq!(load("cost", "reused-path").unwrap().costs, vec![640 * 360 + 3 * one]); assert_eq!(load("cost", "touching-windows").unwrap().costs, vec![640 * 360 + one], "touching windows count once"); // A group: w·h, plus its clip (101 × 51 pixels, 4 points), plus its child. let clip = fill_cost(4, 101, 51); assert_eq!(load("cost", "group").unwrap().costs, vec![2 * 640 * 360 + clip + one]); } #[test] fn review_a_attack_payloads_are_refused() { for name in ["attack-a-reused-full-canvas", "attack-b-reused-cubic-path", "attack-c-full-canvas-glyphs"] { let e = load("cost", name).unwrap_err(); assert_eq!((e.code, e.step), (Code::TooLarge, "9"), "{name}: the cost exceeds the ceiling"); } let one = load("cost", "attack-b-one-item").expect("one heavy item alone is accepted"); assert_eq!(one.costs, vec![4096 * 4096 + fill_cost(16_381, 4096, 4096)]); for name in ["attack-d-64-held-sets", "attack-d-3-held-sets"] { let e = load("refusals", name).unwrap_err(); assert_eq!((e.code, e.step), (Code::TooLarge, "2"), "{name}: held_len past 2^26 before anything is fetched"); } assert_eq!(load("refusals", "attack-d-2-held-sets").unwrap_err().code, Code::OutlineNotHeld); let e = load("refusals", "attack-e-duplicate-tracks").unwrap_err(); assert_eq!((e.code, e.step), (Code::PayloadMalformed, "5g")); // The cost needs nothing but the payload and its sets: computed again here. let v = find("cost", "attack-a-reused-full-canvas").unwrap(); let d = wvg1::parse(&v.bytes).unwrap(); let sets = wvg1::load_sets(&d, &mut NoSets).unwrap(); assert_eq!(place::costs(&d, &sets), vec![4096 * 4096 + 260 * fill_cost(4, 4096, 4096)]); } /// Review A's three shapes at full scale, built in memory: the cost reproduces the /// figures RC2 recomputed for the design (A: 65,536 fills of a full-canvas /// rectangle; C: 2^20 full-canvas glyph records in 256 runs of 4,096, with each run's /// hull term), and B's from its formula. #[test] fn review_a_full_scale_costs() { let cost_of = |d: &wvg1::Doc| { let d = wvg1::parse(&d.write()).expect("steps 1-5"); let sets = wvg1::load_sets(&d, &mut NoSets).expect("inline sets"); place::costs(&d, &sets) }; let mut a = wvg1::parse(&find("cost", "attack-a-reused-full-canvas").unwrap().bytes).unwrap(); let item = a.items[0]; a.items = vec![item; 65_536]; a.sync_counts(); assert_eq!(cost_of(&a), vec![1_101_944_324_096]); let mut b = wvg1::parse(&find("cost", "attack-b-reused-cubic-path").unwrap().bytes).unwrap(); let item = b.items[0]; b.items = vec![item; 65_536]; b.sync_counts(); // RC2 counted 5,460 cubics as 16,380 points (10,992,717,135,872); the path stores // the start point too, 16,381. assert_eq!(cost_of(&b), vec![4096 * 4096 + 65_536 * fill_cost(16_381, 4096, 4096)]); assert_eq!(4096 * 4096 + 65_536 * fill_cost(16_380, 4096, 4096), 10_992_717_135_872); let mut c = wvg1::parse(&find("cost", "attack-c-full-canvas-glyphs").unwrap().bytes).unwrap(); let mut run = c.items[0]; run.n_glyphs = 4096; let g = c.glyphs[0]; let mut cl = c.clusters[0]; cl.glyph_count = 4096; c.items = vec![run; 256]; c.glyphs = vec![g; 1 << 20]; c.clusters = vec![cl; 256]; c.sync_counts(); assert_eq!(cost_of(&c), vec![17_635_152_494_592]); }