# Методическое пособие: FoxHunter — охота на лис на LoRa

Стенд: три роли на одинаковом железе **E77-900MBL** (STM32WLE5), выбираются
прошивкой. **Лиса** — маяк-передатчик, шлёт компактный 9-байтовый пакет каждые
300 мс. **Охотник** — приёмник с зуммером «горячо-холодно» (громкость по
усреднённому RSSI) и опциональным OLED. **Фальшлиса** — учебный «атакующий» на
СВОЁМ железе, который показывает три классические слабости беспроводной связи.

Это спортивная радиопеленгация (ARDF — Amateur Radio Direction Finding, «охота на
лис»), в которую играют десятилетиями. Проект соединяет два разных курса: сначала
**физика поиска** (ребёнок находит спрятанный передатчик руками, по громкости),
затем **безопасность протокола** (почему сигналу нельзя верить слепо и зачем нужна
настоящая криптография). Полная методика преподавания — в `METODIKA.md`, железо и
сборка — в `README.md`. Python-стенд `foxhunt_sim.py` даёт понять «горячо-холодно»
до выхода на охоту — карта зон громкости на этаже, физика RSSI и та же логика
усреднения и порогов, что в прошивке охотника.

Порядок уроков строгий: **сначала найти лису руками, и только потом лезть внутрь.**
Магия — в находке, а не в CMAC.

## Кто чем пользуется

1. **Инженер** отвечает за стенд: прошивки ролей, приглушение лисы под площадку,
   зуммер через резистор 100 Ом, замер шума эфира (`[NOISE]` в мониторе).
2. **Учитель** прячет лису и ведёт три урока по сценарию.
3. **Методист** привязывает физику пеленгации и слабости протокола к программе.

---

## Модуль 1. Физика пеленгации: «горячо-холодно»

### Урок 1. Громкость вместо направления: почему в здании ищут так

* Тема: логарифмическая шкала (дБм), затухание сигнала с расстоянием.
* Стенд: `foxhunt_sim.py`. Параметры: `ZONES[]`, `rssi_at`, показатель n.

**Ход работы.** Запустите `uv run foxhunt_sim.py`. Двигайте мышь над картой этажа —
это «ходьба с охотником». Внизу справа — «зуммер»: зона RYADOM/GORYACHO/TEPLO/
HOLODNO и частота пиков. Найдите спрятанную лису, ориентируясь только на зону.

**На графике:**
```
 Зоны громкости на этаже       Профиль RSSI(расстояние)
  RYADOM ▓ (сплошной тон)        RSSI│╲
  GORYACHO ▒ (частые пики)           │ ╲___ RYADOM  −55
  TEPLO   ░ (редкие)                 │     ╲___ TEPLO −85
  HOLODNO · (очень редкие)           │         ╲___
                                     └──────────────► расстояние
```

**Разбор.** В здании радиоволна отражается от стен и арматуры — приходит со всех
сторон, поэтому направление по антенне работает плохо, а **дальность по громкости**
— отлично: ближе к лисе → выше RSSI → чаще пики зуммера. RSSI падает по
лог-дистанционной модели `RSSI(d) = P_tx − PL(d0) − 10·n·lg(d/d0)`, где n≈3 в
здании. Прошивка охотника делит эту непрерывную величину на зоны (`ZONES[]`) и
озвучивает их разной частотой пиков. Это игра «горячо-холодно» — и она честная:
за ней стоит настоящая физика затухания.

**Практическое задание.** По профилю RSSI в стенде определите, на каком расстоянии
проходит граница RYADOM (−55 дБм) при мощности лисы 2 дБм. Сверьте с реальной
охотой: в какой примерно комнате зуммер перейдёт на сплошной тон?

---

### Урок 2. Приглушить лису: почему мощная лиса ломает охоту

* Тема: динамический диапазон, насыщение, соотношение сигнал/масштаб.
* Стенд: `foxhunt_sim.py` (ползунок мощности). Параметр: `FOX_TX_PWR_DBM`.

**Ход работы.** В стенде поставьте мощность лисы 14 дБм и походите по этажу: почти
везде горит RYADOM — искать нечем. Теперь убавьте до 2 дБм: зоны стали
контрастными, к лисе ведёт явный градиент.

**На графике:**
```
 Лиса 14 дБм                    Лиса 2 дБм
  RYADOM почти на весь этаж       RYADOM ▓ у самой лисы
  (96% площади — «горячо везде»)  GORYACHO ▒ вокруг, дальше TEPLO/HOLODNO
  искать нечем                    явный градиент к цели
```

**Разбор.** Чувствительность зуммера-«градусника» ограничена: если лиса мощная, её
RSSI насыщает зону RYADOM уже в соседней комнате — весь этаж «горячий», разницы
нет. Приглушив лису до 2 дБм, мы сжимаем зоны до масштаба этажа, и «горячо-холодно»
снова различимо. Это общий инженерный принцип: **измеритель полезен только в своём
динамическом диапазоне** — под масштаб задачи подстраивают не прибор, а источник.
То же в фотографии (экспозиция), в звуке (усиление), в АЦП (диапазон входа).

**Практическое задание.** В стенде найдите минимальную мощность лисы, при которой
на 40-метровом этаже ещё нет зоны тишины (сигнал добивает в углы), но RYADOM не
разливается шире одной «комнаты» (~8 м). Это и есть оптимум под площадку.

---

### Урок 3. Несколько лис по очереди: расписание ARDF и усреднение

* Тема: разделение времени (TDMA), скользящее среднее, robustность.
* Параметры: `FOX_COUNT`/`SLOT_MS`, `RSSI_AVG_N`, «проговор» ID.

**Ход работы.** По коду лисы и охотника: лисы делят цикл на слоты (`SLOT_MS`),
вещают по очереди (`FOX_ID`), охотник «проговаривает» номер активной лисы пиками
(лиса 1 — один пик, лиса 2 — два). В стенде поменяйте окно усреднения `RSSI_AVG_N`
и посмотрите, как «зуммер» становится плавнее (7) или отзывчивее (3).

**Разбор.** Несколько передатчиков на одной частоте не мешают друг другу, потому
что **разделены во времени** (аналог TDMA): каждая лиса вещает свой слот и молчит в
чужой. Позывные MOE/MOI/MOS настоящего ARDF здесь заменены «проговором» числа
пиков. Сырой RSSI LoRa скачет на ±3-5 дБ от пакета к пакету — поэтому охотник
усредняет по окну из `RSSI_AVG_N` пакетов: среднее гасит скачки и даёт плавную
громкость. Меньше окно — отзывчивее (но дёрганее), больше — плавнее (но ленивее):
тот же компромисс, что в любом сглаживающем фильтре.

**Практическое задание.** Почему при смене активной лисы охотник СБРАСЫВАЕТ буфер
усреднения (`rssiReset()`), а не продолжает среднее? Что было бы со стрелкой
громкости в первые секунды после переключения, если бы буфер не сбрасывался?

---

## Модуль 2. Безопасность протокола: почему сигналу нельзя верить

Только после того, как дети уверенно ищут лис. Нужна прошивка `FoxHunt_FakeFox` —
учебный «атакующий» на СВОЁМ железе в классе. Кнопка переключает три атаки.

### Урок 4. Подпись против подмены (spoofing)

* Тема: аутентификация сообщений, контрольная подпись, целостность.
* Параметры: `foxCalcSignature()`, атака ATK_SPOOF.

**Ход работы.** Фальшлиса (атака 1) шлёт пакет с верным `fox_id` и растущим `fcnt`,
но НАМЕРЕННО испорченной подписью. Охотник печатает `[SEC] REJECT ... SIG:FAIL`,
на экране `[FAKE]`, зуммер молчит.

**Разбор.** Каждый пакет несёт **подпись** — байт, вычисленный из всех полей и
секретного ключа (`foxCalcSignature`). Кто не знает ключа, не подделает подпись под
свои данные. Охотник пересчитывает подпись сам и сравнивает: не сошлось — пакет
отвергнут, «лиса» признана фальшивой. Так приёмник отличает подделку, **не видя
отправителя** — только по математике. Это и есть аутентификация сообщения, основа
защиты любого протокола.

**Практическое задание.** Вопрос классу: охотник понял, что пакет поддельный, хотя
`fox_id` был правильный и `fcnt` рос. Какое единственное поле его выдало и почему
атакующий не смог его подделать?

---

### Урок 5. Счётчик кадров: replay-атака против ребута лисы

* Тема: защита от повтора, монотонность, различение схожих причин.
* Параметры: `fcnt`, логика RESYNC vs REPLAY в `processBeacon`.

**Ход работы.** Учитель заранее ловит реальный пакет лисы (строка `[RAW]` в
мониторе охотника → байты в `CAPTURED_PACKET`). Фальшлиса (атака 2) шлёт этот
пакет снова и снова БЕЗ ИЗМЕНЕНИЙ. Подпись верна, но `fcnt` СТОИТ. Охотник:
`[SEC] REJECT ... SIG:OK FCNT:REPLAY`. Затем перезагрузите настоящую лису — её
`fcnt` тоже низкий, но РАСТЁТ, и охотник сам ресинхронизируется (`[RESYNC]`).

**На графике:**
```
 Настоящая лиса (ребут)          Replay-атака
  fcnt: 1,2,3,... (растёт)        fcnt: 127,127,127,... (застыл)
  → RESYNC, лиса принята          → REJECT, атака отбита
```

**Разбор.** Подпись ловит подделку, но НЕ ловит повтор: атакующий может записать
чужой валидный пакет и переиграть его. Защита — **монотонный счётчик кадров**
`fcnt`: охотник помнит последний и принимает только больший. Красивый момент: и
у replay-атаки, и у перезагруженной лисы `fcnt` низкий — но у атаки он ЗАСТЫЛ, а у
ребута РАСТЁТ. Один и тот же механизм (динамика счётчика) отличает «честная лиса
перезагрузилась» от «злоумышленник переигрывает старое»: три растущих подряд →
ребут (ресинк), застывший → атака (отказ). Так работает защита от replay в реальных
протоколах (LoRaWAN, TLS, IPsec).

**Практическое задание.** Почему нельзя просто «принимать любой fcnt, если подпись
верна»? И почему одного растущего пакета мало для ресинка — зачем требовать три
подряд (`RESYNC_N`)?

---

### Урок 6. Брутфорс подписи: почему 1 байт — не защита, а 4 байта — защита

* Тема: пространство ключей, вычислительная стойкость, экспонента.
* Параметры: атака ATK_BRUTE, мостик к AES-CMAC (4-байтовый MIC).

**Ход работы.** Фальшлиса (атака 3) перебирает все 256 значений однобайтовой
подписи для одного пакета, раз в секунду шлёт следующее. Рано или поздно совпадёт —
и охотник примет фальшивку как настоящий `[RX]`! Наблюдайте счётчик перебора в
мониторе фальшлисы.

**На графике:**
```
 Подпись 1 байт = 256 вариантов        Подпись 4 байта (MIC) = 2³² вариантов
  перебор за ~минуты на 1 Гц             ~4.3 млрд — перебор нереален
  █ пробита                              🔒 держит
```

**Разбор.** Наша подпись — **намеренно слабая**: 1 байт = всего 256 вариантов,
перебор совпадёт в среднем за 128 попыток. Это не баг, а учебный материал: он
показывает, ЗАЧЕМ настоящие системы берут 4-байтовый MIC (Message Integrity Code)
на базе **AES-CMAC** — 2³² ≈ 4.3 млрд вариантов, перебор физически нереален. Каждый
добавленный байт умножает стойкость на 256 (экспонента) — вот почему длина ключа
решает. Это прямой мостик к «взрослой» LoRaWAN-ветке курса, где подпись честная.

**Практическое задание.** Если однобайтовую подпись перебирают за ~2 минуты (1 Гц),
сколько времени займёт перебор 4-байтового MIC при той же скорости? (Ответ в годах
переведите в понятную величину.) Почему в реальности атакующий не может слать
«быстрее» без ограничений?

---

## Приложение: таблица переноса концепций в индустрию

| Концепция из проекта | Где встречается за пределами лаборатории |
|---|---|
| Лог-дистанционная модель RSSI | Site survey, планирование покрытия, локализация |
| Динамический диапазон измерителя | Фотография, АЦП, аудио, любые сенсоры |
| Скользящее среднее (сглаживание) | Обработка сигналов, датчики, финансы |
| Разделение времени (TDMA) | Сотовые сети, промышленные шины, ARDF |
| Аутентификация сообщения (подпись/MIC) | TLS, LoRaWAN, банковские протоколы |
| Защита от replay (счётчик кадров) | LoRaWAN, TLS, IPsec, платёжные системы |
| Стойкость ключа, пространство перебора | Вся криптография; выбор длины ключа |

## Заключение

FoxHunter ведёт ученика от осязаемого к абстрактному: сначала он находит спрятанный
передатчик руками, по громкости зуммера, — и физика затухания перестаёт быть
формулой, становится игрой «горячо-холодно». Затем на том же железе он видит, как
легко подделать сигнал, если протокол наивен, и как три механизма (подпись, счётчик
кадров, длина ключа) по очереди эту наивность лечат — вплоть до понимания, зачем
существует настоящая криптография. Python-стенд `foxhunt_sim.py` даёт прожить первую
половину — почему мощную лису не найти и как приглушение возвращает контраст, — а
фальшлиса на своём железе честно, безопасно и наглядно показывает вторую. Главный
принцип курса тут звучит буквально: сигналу нельзя верить слепо — ни его громкости
(мощная лиса «горячо везде»), ни его содержимому (подделка и повтор).
