RuView WiFi Veil × openwifi:在 Zynq-7000 + AD9361 开放 PHY 上实现按键空间映射旋转的隐私屏蔽
RuView WiFi Veil × openwifi:在 Zynq-7000 + AD9361 开放 PHY 上实现按键空间映射旋转的隐私屏蔽
本文基于 wifi-veil/firmware/openwifi/README.md 及其配套的 HDL_NOTES.md、veil_openwifi.c、MEASUREMENT.md 与便携核心 veil_shield.c 展开。该目录是 RuView WiFi Veil 隐私屏蔽(ADR-288,硬件路线 ADR-290)在 openwifi——目前全树唯一暴露完整开源 PHY/MAC 的 FPGA SDR 平台——上的实现落点。读完本文,你将掌握:为什么 openwifi 是端到端按键旋转"正变换 + 逆变换"唯一物理可达的平台、
veil_rot/veil_unrot两个 HDL 块的精确插入位置与 AXI-Lite 寄存器契约、驱动侧 C shim 的编程流程,以及通往首个MEASURED硬件证据的 P5 双节点测量协议。注意:该目录当前全部为 SYNTHETIC / L0 构建脚手架,未在任何硅片上运行过,文中所有数字均需在硬件日志出现后才能升级为 MEASURED。
一、背景:WiFi Veil 要解决的问题与 openwifi 的定位
WiFi Veil(代号 VEIL,Verifiable Emission-shaping for Identity-Leakage prevention)对抗的是"未经授权的 WiFi 感知":自 802.11ac/ax 起,客户端会通过明文、未加密的波束成形反馈(BFI)告诉 AP 如何瞄准信号,任何处于监听模式的设备都能被动截获这些报告,并从中提取稳定的"射频指纹"实现穿墙的个体再识别(re-ID)、占用检测甚至动作识别。IEEE 802.11bf-2025 标准化了被滥用的感知测量面,却没有配套隐私保护。WiFi Veil 的思路是给节点自身发出的反馈加一个按会话轮换的密钥化"扭转":自己的 AP 持有共享密钥可即时逆转(链路几乎无损),外部监听者则看到每次会话都不同的旋转,无法把多次抓包平均成稳定指纹,re-ID 坍缩到随机水平。由于旋转是正交变换(能量输入 = 能量输出),它只重塑自身符合标准的发射波形,从不干扰其他站点——不是干扰/压制。
在 wifi-veil/firmware/README.md 的可行性矩阵中,各提供方(openwifi / openwrt / nexmon / esp32)按"能否真正塑造波束成形反馈面"分级。openwifi 是唯一一个拿到能力天花板 A 的平台:它把完整 PHY/MAC 暴露在 FPGA 上(openofdm_tx/openofdm_rx、tx_intf/rx_intf、side_ch,全部可由 Linux 驱动通过 AXI-Lite 编程),因此按键旋转及其逆变换在物理上都能落地。这也是本文档被定为可行性等级 **B(能力上限 A,工作量等级 D)**的原因——能力可达,代价最大。
二、可行性评估:为什么是 B 而不是 A
原文档给出了两条诚实的理由,说明 openwifi 是"最高工作量"的路径:
- openwifi 没有原生的显式发送波束成形。它出厂即为 802.11a/g/n **单空间流(SISO)**设计:不运行 NDP sounding、不计算 SVD
V矩阵、不生成压缩波束成形报告。其双天线应用笔记只是 RX-only 相干采集(side_ch_ctl wh3h11),并非 MIMO 发送空间映射。因此没有现成的压缩 BF 报告可混淆、也没有现成的空间映射矩阵Q可左乘——两者都必须在 HDL 中新增。 - 达到真正的双流演示需要第二条 TX 链路(fmcomms2/3 上的 AD9361 有两个 DAC)、一段新的空间映射 RTL 级以及一次 Vivado 重建——这是数天到数周的 FPGA 工作量,而不是一次驱动补丁。
基于第 1 点,在 openwifi 上 WiFi Veil 的实现形态不是"混淆硬件从不生成的压缩 BF 报告",而是客户端透明的逐包密钥化酉变换(LeakyBeam 家族):在 TX 空间映射级施加,由共享密钥的合法 STA(第二个 openwifi 节点)求逆。这样保持声明的诚实:旋转的是发射的空间映射,使嗅探者估计到的每子载波信道 H·Q(key) 被打乱,而密钥化接收端在信道估计前应用 Q(key)^H。
三、精确插入点:veil_rot 与 veil_unrot
旋转矩阵是便携核心(veil_shield.c)按 SplitMix64 调度计算出的密钥化正交(酉)矩阵 Q(key, session),全树各处使用同一调度,因此两端能从共享密钥派生出完全一致的 Q——矩阵本身从不通过空中传输。
TX(保护方)—— 新块 veil_rot
插入在基带 IQ AXI-Stream 路径上,介于 openofdm_tx(IFFT 之后、加 CP 之后)与 tx_intf(馈送 AD9361 DAC)之间。veil_rot 对每子载波/每流样本向量左乘 Q(key)。其系数(或密钥种子 + 片上调度的派生逻辑)由驱动 shim 通过标准 openwifi iowrite32(value, base_addr + reg) 惯用法经 AXI-Lite 写入(参照 tx_intf 驱动 中封装的 MMIO 层)。RTL 细节见 HDL_NOTES.md。
RX(合法 STA)—— 新块 veil_unrot
插入在 rx_intf(AD9361 ADC)与 openofdm_rx 之间;也可以放在频域——FFT 之后、信道估计之前——应用 Q(key)^H。AXI-Lite 编程路径与 TX 相同,只是通过 CTRL.inverse 位选择逆变换。
驱动/控制面 —— veil_openwifi.c
C shim veil_openwifi.c 通过核心计算会话密钥调度并编程两个块。它采用真实的 openwifi 控制惯用法:内核驱动的 AXI-Lite MMIO,以及 sdrctl nl80211-testmode 工具 / side_ch_ctl 寄存器 poke(用于 bring-up)。偏移量与位域未最终确定的处以 TODO(hw) 标注,RTL 细节在 HDL 笔记中以 TODO(hdl) 标注。
把旋转做在 HDL 而非 DMA 后的载荷上是刻意的:它让帧在线路上保持标准合规,并保持发射能量不变——即核心通过正交性 Q 在构造上保证的"非干扰"不变量。
四、HDL 设计笔记:AXI-Stream 数据路径与寄存器契约
HDL_NOTES.md 给出了两个新块的完整设计。openwifi 的基带 IQ 以 AXI-Stream 在块间流动,控制面为 AXI-Lite;veil_rot/veil_unrot 是带 AXI-Lite 从口(用于密钥调度)的 AXI-Stream 直通滤波器:
TX (protector):
openofdm_tx ──AXI-S(IQ)──► [ veil_rot ] ──AXI-S(IQ)──► tx_intf ──► AD9361 DAC
▲ AXI-Lite (key, coeff RAM)
└── veil_openwifi.c
RX (legitimate STA, shares key):
AD9361 ADC ──► rx_intf ──AXI-S──► [ veil_unrot ] ──AXI-S──► openofdm_rx (FFT → chan est)
▲ AXI-Lite
└── veil_openwifi.c
为什么必须新增块(诚实性)
openwifi 是 SISO 802.11a/g/n,没有显式波束成形/空间映射级,也不生成压缩 BF 报告(双天线应用笔记仅 RX 采集)。因此没有现成的 Q 矩阵可修改,veil_rot/veil_unrot 是引入空间映射级。有两种可实现 RTL 范围:
- Scope A —— 1×1 每子载波相位/旋转(较低工作量):把旋转作用于由逐包子载波响应的精细子空间构成的合成向量(块缓冲的
N个 IQ 元素流),施加核心的 Givens 调度。单 TX 链、无需换板,足以打乱嗅探器估计的 CSI 并演示 RX 端密钥化求逆,但不是真正的空间 MIMO。 - Scope B —— 2×2 真实空间映射(更高工作量,A 级能力演示):启用第二条 TX 链(fmcomms2/3 的 AD9361 有 2 个 DAC),跨两流施加密钥化 2×2 酉矩阵——标准标注为"不受限制"的真正的发射空间映射。需要 Vivado 顶层重建以接入第 2 个 DAC 与额外的 AXI-S 通道。
TODO(hdl)。
veil_rot 数据路径与定标
核心对向量应用 passes 次 Givens 旋转 G(i,j,θ) 组合成 Q;硬件对空口样本向量应用同一调度,因此两端从共享密钥派生出完全一致的系数——不传输任何矩阵。每次 Givens 运算作用于元素 (i, j),系数以 Q1.15 格式编程:
v_i' = cos*v_i - sin*v_j
v_j' = sin*v_i + cos*v_j // 复数 IQ:对 I 与 Q 两路分别应用
- 系数从
veil_openwifi.c以打包的(i, j, cos, sin)调度到达(每次 2 个 AXI-Lite 字;打包约定定义在 shim 中)。 veil_unrot逆序应用调度并将 sin 取负(sin → -sin,即Gᵀ),与veil_shield_recover一致;由CTRL.inverse位选择。- 定点:openwifi 基带 IQ 为 16 位 I / 16 位 Q;系数为有符号 Q1.15。
TODO(hdl):需要保护位/舍入保证组合旋转按规格保持范数不变且绝不削波(削波会破坏能量保持不变量——必须验证而非假设)。
AXI-Lite 寄存器映射(必须与 veil_openwifi.c 一致)
| 偏移 | 名称 | 含义 |
|---|---|---|
0x00 |
CTRL |
bit0 使能,bit1 求逆(veil_unrot),bit2 加载 |
0x04 |
KEY_LO |
会话密钥 [31:0] |
0x08 |
KEY_HI |
会话密钥 [63:32] |
0x0C |
NDIM |
空口精细块维度 N(≤ 64) |
0x10 |
PASSES |
Givens 轮数(默认 96) |
0x14 |
COEFF_ADDR |
系数 RAM 的写索引 |
0x18 |
COEFF_DATA |
打包 {j,i} 再 {sin,cos}(每次 2 字) |
0x1C |
STATUS |
bit0 ready,bit1 applied,bit2 err |
TODO(hdl):待 veil_rot 的 *_s_axi.v 写出后由它重新生成此表(参照 openofdm_tx 在 ip/openofdm_tx/src/openofdm_tx_s_axi.v 的 6 个 AXI-Lite 寄存器),并将偏移量的任何变化回写进 veil_openwifi.c。
时序与集成风险(点名而不回避)
- 802.11 SIFS 预算:块在 IFFT 与 DAC 之间增加流水线延迟,不得违反 openwifi 在
tx_intf中维持的紧张 TX 时序。TODO(hdl):测量新增周期,保持在预算内或吸收进现有 FIFO 余量。 - 片上调度 vs. 逐包系数加载:对逐包密钥化,要么在 FPGA 上从
(key, packet_counter)计算 SplitMix64 调度,要么对系数 RAM 做双缓冲。TODO(hdl)。 - 与核心的位精确一致:片上(或 shim 喂入)的
(cos, sin)必须复现核心调度,使veil_unrot精确求逆。第一道关卡是 自环回 IQ 测试(veil_rot → veil_unrot,断言恢复 == 输入,误差在 Q1.15 舍入内),利用 openwifi 现有的 packet/IQ 自环回设施。环回通过是正确性关卡,不是防御 MEASURED 声明。
构建方面,TODO(hdl):把两个块作为 openwifi-hw IP 添加、在板级 block design 中例化并按 openwifi-hw 构建流程用 Vivado 重建比特流;本目录不产出任何比特流。
五、驱动侧 C shim:veil_openwifi.c 源码级解析
veil_openwifi.c 把便携核心绑定到 openwifi FPGA TX/RX 数据路径,设计为两种编译模式:
- Host/CI(默认):
__KERNEL__未定义,MMIO 桩到本地影子寄存器文件(VEIL_SHADOW_REGS 256),使密钥调度 + 量化逻辑无需硬件即可单元测试——这是目前唯一被实际运行的路径。 - 内核树构建:定义
VEIL_OPENWIFI_KERNEL拉取真实linux/io.h访问器(iowrite32/ioread32),未测试,TODO(hw)。
寄存器与定点约定
偏移宏与 HDL 笔记中的寄存器表一一对应(VEIL_ROT_REG_CTRL 0x00u … VEIL_ROT_REG_STATUS 0x1Cu),控制位为 ENABLE(1<<0) / INVERSE(1<<1) / LOAD(1<<2)。定点约定 VEIL_ROT_FRAC 15:openwifi 基带 IQ 是 16 位,旋转系数按有符号 Q1.15 编程(cos/sin ∈ [-1,1] 可干净映射)。默认参数与核心/Rust crate 字节一致:VEIL_OW_DEFAULT_PASSES 96、VEIL_OW_MAX_NDIM 64(有界系数 RAM,保持无 malloc)。
系数生成:镜像核心调度
veil_ow_build_schedule 用与 veil_shield.c 相同的抽取顺序从 SplitMix64 重新生成 (i, j, θ) 调度,保证 shim 与(未来的)RTL 与参考 crate 位对位一致:
veil_rng_seed(&r, key);
for (p = 0; p < passes; p++) {
i = veil_rng_next_u64(&r) % n;
j = veil_rng_next_u64(&r) % n;
if (j == i) j = (j + 1) % n; /* 避免对角自旋 */
theta = veil_rng_next_f32(&r) * VEIL_OW_TAU; /* 2π,与核心一致 */
out[p] = {i, j, veil_q15(cosf(theta)), veil_q15(sinf(theta))};
}
注意:调度在 shim 中刻意重复实现而非导出(核心保持纯内存变换、ABI 稳定,适配器拥有硬件侧序列化)。TODO(hw):任何 MEASURED 声明前,必须用片上捕获的系数转储验证一致性。veil_q15 是饱和的 float→Q1.15 转换(限幅到 ±32767/±32768,用 lrintf 取整)。
编程流程:veil_ow_program_session
- 边界检查(最小权限):
ndim < 2 || ndim > 64直接返回 -1;passes缺省 96、上限 96(有界栈上调度)。 - 构建调度后写入头寄存器:
KEY_LO/KEY_HI/NDIM/PASSES。 - 流式写入系数 RAM:每次 2 个字——字 A =
{j[15:0], i[15:0]},字 B ={sin_q15[15:0], cos_q15[15:0]}(COEFF_ADDR递增 p2 / p2+1)。TODO(hdl):veil_rot系数 RAM 写 FSM 必须匹配此打包;TODO(hw):确认 AXI-Lite 从口端序。 - 合法 RX 角色(
VEIL_OW_ROLE_LEGIT_RX)置CTRL_INVERSE,最后写CTRL(含LOAD)。 - 真实硅片上需轮询
STATUS的 READY 位并超时(spins = 100000,超时返回 -2,"绝不把未就绪当成功");Host 影子路径无 FSM,直接返回成功——不声明硬件已接受。
veil_ow_set_enabled 通过读改写 CTRL 的 bit0 使能/去使能,保留 inverse 位。控制面 bring-up 备选(文档化惯用法,未接线):sdrctl(nl80211 testmode)添加 "veil" 子命令镜像现有 reg poke;side_ch_ctl 风格的十六进制寄存器 poke(如 ./side_ch_ctl whXXdY)重定向到 veil_rot 从口。TODO(hw):选定并文档化实际动词。
Host 自测(当前唯一实际路径)
VEIL_OPENWIFI_SELFTEST 下提供无硬件冒烟测试,构建命令为:
cc -DVEIL_OPENWIFI_SELFTEST veil_openwifi.c ../core/veil_shield.c -lm
它用 key = 0x0123456789ABCDEF、ndim = 16 编程影子寄存器,断言 program_session/set_enabled 成功、NDIM 被写入 16、CTRL 的 enable 位已置位,输出 OK (SYNTHETIC/L0 host shadow only — NOT hardware-validated)。
六、便携核心:SplitMix64 调度、Givens 旋转与三大不变量
veil_shield.h 声明了共享的硬件无关核心:veil_rng_seed/next_u64/next_f32、veil_shield_apply(正变换)、veil_shield_recover(逆变换)、veil_l2_norm。它满足 no_std-友好的 C99:无 malloc、无 libc I/O,仅 <math.h>。
- SplitMix64 确定性:种子异或
0x9E3779B97F4A7C15,状态递增同一常量,两次混合乘法0xBF58476D1CE4E5B9/0x94D049BB133111EB,与 Rust crateprng::Rng常量完全相同;next_f32取next_u64 >> 40除以 2^24(24 位尾数),匹配 Rustnext_f32。这是"给定(key, passes, n)两端得到完全相同的旋转"从而可求逆的基础。 - Givens 旋转:
givens(v, i, j, θ)用cos/sin做v_i' = c·v_i − s·v_j、v_j' = s·v_i + c·v_j,是标准正交变换。 - 求逆策略:
apply_schedule(..., inverse)在前向时逐轮抽取调度;逆变换时逆序应用、角度取负(givens(fine, ci[p], cj[p], -ct[p])),与 HDL 中sin → -sin的Gᵀ对应。调度缓存上限CACHE 256(默认 96 轮以内无 malloc);超限时退化为每轮重生成第 k 个操作的 O(passes²) 路径,仍无 malloc 且正确。
三大不变量(host 测试验证)
test_veil_shield.c 验证三个承重不变量,配合 Makefile(cc -std=c99 -Wall -Wextra -Werror -O2,make test)运行:
- 能量守恒(正交 ⇒ ‖v‖ 不变):
fabs(n1 - n0) < 1e-3—— 即"非干扰"; - 可逆性:
apply后recover,误差< 1e-3—— 合法接收端; - 跨语言确定性:
seed(42)流确定且非退化,CI 中与 Rust 流做对等校验; - 附加:错误密钥不可恢复(
key ^ 0x1后误差 > 0.5)——没有共享密钥就没有求逆。
七、双节点测量计划(P5 路径)与所需见证物
原文档定义了三类角色以产生首个 MEASURED / P5 结果(完整协议与见证日志要求见 MEASUREMENT.md):
- Protector AP —— openwifi 节点 A,
veil_rot启用,TX 空间映射以会话密钥键控; - Legitimate STA —— openwifi 节点 B,共享密钥,
veil_unrot启用,应看到接近基线的吞吐(旋转被抵消); - Attacker sniffer —— 运行 Wi-BFI / monitor 抓包的商用 Wi-Fi NIC,提取每子载波 CSI / 波束成形反馈并运行 re-ID 模型。
头条指标:攻击者侧的再识别准确率(开启 vs 关闭,目标坍缩到随机),同时 iperf 吞吐 A↔B 保持接近基线、每帧能量不变。在捕获到片上日志之前,这里没有任何数字是真实的。
前置门槛与拓扑
P5 的前置门槛(全在真实硅片上、目前均未满足):含 veil_rot/veil_unrot 的比特流(HDL_NOTES.md)、能加载 veil_openwifi.c 的驱动、以及通过的片上自环回正确性测试。拓扑中攻击者完全被动(仅 monitor 抓包),本测试不发射任何干扰站点的信号:
[ Protector AP ] over the air [ Legitimate STA ]
openwifi node A ───────────────────────────────────► openwifi node B
veil_rot: Q(key) engaged │ veil_unrot: Q^H(key)
│ (shares key with A)
▼
[ Attacker sniffer ]
commodity NIC, monitor mode
Wi-BFI CSI/BF-feedback extraction
+ re-ID model
硬件清单
| 角色 | 硬件 | 软件 |
|---|---|---|
| Protector AP (A) | Zynq-7000 + AD9361 FMC(ZC706+fmcomms2/3,或 ADRV9361-Z7035) | openwifi 镜像 + veil_rot 比特流 + veil_openwifi.c |
| Legitimate STA (B) | 第二个同款 openwifi 节点 | openwifi 镜像 + veil_unrot 比特流 + veil_openwifi.c,与 A 同密钥 |
| Attacker | 支持 Wi-BFI 的商用 Wi-Fi NIC(monitor 模式) | Wi-BFI + re-ID 模型 |
| Bench | 首选屏蔽室或有线衰减路径 | iperf3、功率计 / 板级 rail 采样 |
A↔B 密钥协商演示中走带外预共享会话密钥;逐包密钥化使用 (key, packet_counter)。
测量流程与指标表
每个条件跑两遍:WiFi Veil OFF(基线) 与 ON,保持位置、MCS、时长、攻击者模型种子一致。流程为:① 正确性前置(自环回恢复 + A→B 链路可用,捕获控制台日志,不是防御声明)→ ② 攻击者抓包(固定流量模式 OFF/ON,保存 pcap + Wi-BFI 输出)→ ③ re-ID 指标(同一模型跑 OFF/ON,报告相对随机/均值基线的准确率与混淆,绝不裸报准确率)→ ④ 吞吐(iperf3 A↔B 双向 OFF/ON,保存 --json)→ ⑤ 能量/合规(每帧 TX 能量 + 频谱掩码一致性)。
| 指标 | OFF | ON | 通过要求 |
|---|---|---|---|
| 攻击者 re-ID 准确率 vs. 随机 | 基线 | — | ON 时坍缩向随机 |
| iperf3 吞吐 A↔B | 基线 | — | ON 与 OFF 相差数个百分点内 |
| 每帧 TX 能量 | 基线 | — | ON ≈ OFF(空口正交性成立) |
| 频谱掩码一致性 | pass | — | ON 时仍合规 |
所需见证物(CLAUDE.md 关卡)
任何 MEASURED 声明前,本目录必须包含真实硅片捕获日志(非构建或仿真输出):双节点 boot/运行时控制台日志(显示比特流加载与 shim 编程会话的寄存器写/STATUS ready,含时间戳与板卡标识)、自环回正确性日志、OFF/ON 原始攻击者抓包(pcap + Wi-BFI 输出)与 re-ID 可复现命令及输出、iperf3 --json 与能量轨迹、以及把每个工件关联到所用 RTL/驱动/shim git 提交的清单。只有全部从真实硬件捕获才能标注 MEASURED;成功的 Vivado 构建、Verilator/QEMU 运行或 host 自测都不是硬件证据,必须保持 SYNTHETIC。当前仓库没有任何此类日志——不要伪造。
八、物料清单(目标,未采购)
- 2× Xilinx Zynq-7000 + AD9361 FMC 板(如 ZC706 + fmcomms2/3,或 ADRV9361-Z7035 / Antenna-SDR),openwifi 镜像按 openwifi 构建文档制作;
- 1× 攻击者主机 + 支持 Wi-BFI 的 NIC(按 Wi-BFI 支持列表);
- Vivado,用于添加
veil_rot/veil_unrot的 FPGA 重建。
九、文件清单
| 文件 | 内容 |
|---|---|
| wifi-veil/firmware/openwifi/README.md | 本主题:可行性、插入点、测量计划 |
| wifi-veil/firmware/openwifi/veil_openwifi.c | 驱动侧 C shim:核心 → 会话 Q → AXI-Lite 编程(脚手架,TODO(hw)) |
| wifi-veil/firmware/openwifi/HDL_NOTES.md | veil_rot / veil_unrot Verilog 块设计笔记(TODO(hdl)) |
| wifi-veil/firmware/openwifi/MEASUREMENT.md | 精确 P5 协议、指标与所需见证物 |
| wifi-veil/firmware/core/veil_shield.h / veil_shield.c | 便携核心(已验证 host 测试) |
| wifi-veil/firmware/core/test/test_veil_shield.c + Makefile | 能量守恒/可逆性/PRNG 奇偶校验 |
更广的上下文:WiFi Veil 的威胁模型、合规论证(47 U.S.C. §333/§302a 下的"非干扰")与 SOTA 依据见 ADR-288,硬件路线与可行性矩阵见 firmware README,P4/P5 路线图位置见 07-implementation-and-roadmap.md。
十、证据边界与阅读须知
- 本目录全部为 SYNTHETIC / L0 构建脚手架:无硬件、无烧录、无抓包,没有任何东西在硅片上运行过。文件是带真实 openwifi 惯用法与
TODO(hw)/TODO(hdl)标记的诚实骨架,不是已验证固件或完整 HDL。 - 仅合规波形控制:按键旋转是正交(能量保持)的,只塑造本节点自身标准合规的发射,绝不干扰。
- 设计上区分两类变体:密钥可逆(保护方旋转、关联接收方用共享密钥求逆——约 98% 吞吐设计,需要两端改动 + 密钥协商,只有 openwifi 这类开放 PHY 能做真正演示)与客户端透明逐包酉变换(仅 AP 侧改动,客户端不变,借用标准标注为"不受限制"的 802.11 空间映射机制)。
- 关于 openwifi 平台的能力结论(SISO、无原生显式波束成形、无双天线 TX 空间映射)来自 openwifi 官方文档(FPGA 模块设计、overview、双天线 IQ 应用笔记、tx_intf 驱动寄存器惯用法等),读者可直接在上述仓库内的 HDL 笔记与 shim 注释中核对引用;本文不转载外部链接。
