RuView BFLD 隐私分级与 BLAKE3 哈希轮换机制解析:从 `privacy_class` 字节到跨站点不可关联的架构级实现
导读
本文是 RuView 项目 BFLD(Beamforming Feedback Layer for Detection,基于 802.11ac/ax 波束赋形反馈信息 BFI 的无线感知层)中隐私分级(privacy class)与身份哈希轮换(hash rotation)技术方案 ADR-120 的完整解读。BFLD 通过普通 WiFi 信号实现存在感知、人数统计与生物特征级身份信号分析,而 ADR-120 解决的核心问题,是如何让"同一物理个体在不同站点、不同日期产生不同的 rf_signature_hash",使跨站点身份关联在密码学层面不可计算。读完本文,你将掌握 BFLD 四档隐私分级(raw/derived/anonymous/restricted)的字段暴露规则、sink marker trait 的静态强制机制、基于 BLAKE3 密钥哈希的 site_salt + day_epoch 轮换算法,以及 identity_embedding 从生成、驻留到零化销毁的完整生命周期,并可在 v2/crates/wifi-densepose-bfld/ 中对照源码逐行验证。
1. 背景:BFLD 的三条结构不变量与隐私缺口
BFLD 框架(见 ADR-118)为其数据面声明了三条结构性不变量:
- I1:原始 BFI 永不离开节点(raw BFI never exits the node);
- I2:身份嵌入向量(identity embedding)仅存于内存(in-RAM-only);
- I3:跨站点身份关联在密码学上不可实现(cross-site identity correlation is cryptographically impossible)。
I1/I2 由 sink 类型化与模块可见性约束强制(见 ADR-119 第 2.3 节)。而 I3 需要一个哈希轮换方案:让同一个物理个体在跨站点、跨日边界时产生不同的 rf_signature_hash,且站点之间无需任何带外协调(out-of-band coordination)。
在此之前的 ADR-115 中已有 HA-PRIVACY 模式,可在"full"与"anonymous"两种表面之间切换,但那是事件粒度(per-event),而非字节字段粒度(per-byte-field)。BFLD 之所以需要后者,是因为其 BfldFrame 载荷在同一结构体中混装了"可发布"的感知数据(presence、motion)与"不可发布"的身份衍生数据(identity embedding、rf_signature_hash)。
ADR-120 同时引用了学术界证据作为动机:KIT 的 BFId 论文(ACM CCS 2025)表明,在同一站点仅需数分钟 BFI 采集即可构建持久性生物特征(persistent biometric);NDSS LeakyBeam(2025)研究亦佐证了该风险面。因此缓解手段必须是结构性的(structural),而非仅靠策略或约定(policy-dependent)。
2. 核心决策一:四档 privacy_class 分级体系
2.1 分级表与默认值
BfldFrame 头部的单个 privacy_class: u8 字节(位置见 ADR-119 第 2.1 节)从四档中选择其一,crate 通过 marker 类型在编译期强制字段可用性。在源码中该枚举定义于 v2/crates/wifi-densepose-bfld/src/lib.rs#L106-L119,并配套 #[repr(u8)] 与 TryFrom<u8> 反序列化(非法字节返回 BfldError::InvalidPrivacyClass)。
| Class | 名称 | 使用场景 | 可用字段 |
|---|---|---|---|
| 0 | raw |
仅本地研究,永不联网 | 全部字段:全精度 BFI 矩阵、身份嵌入向量 |
| 1 | derived |
操作者确认后的局域网研究 | 降采样角度矩阵、完整特征、identity_risk_score、identity_embedding |
| 2 | anonymous(默认) |
生产部署 | 仅聚合感知:presence、motion、person_count、zone_id、confidence |
| 3 | restricted |
养老院 / 受监管部署 | Class 2 再减去 identity_risk_score 与 rf_signature_hash |
新 RuView 节点的默认档位为 2。操作者必须通过 ADR-115 第 7 节所述的既有
--research-mode标志显式"降级"到 class 1;class 0 仅保留给cargo test,从wifi-densepose-sensing-server不可达。
关于 class 数值序的语义,源码有精确定义:数字越大信息密度越低,PrivacyClass::allows_network()(class 0 之外)与 allows_matter()(仅 class 2/3)这两个关联函数分别编码了网络边界与 Matter 边界(ADR-122)的准入规则。
各档位逐字段的发布/抑制明细可进一步对照 docs/research/BFLD/04-privacy-gating.md 第 1 节的数据暴露表,其中逐字段标注了哪个档位零化/删除哪一块载荷区。
2.2 借助 marker trait 的静态强制
ADR-120 给出如下关键设计——sink 按可承载的信息密度分层,class 0 帧无法传入网络 sink:
pub trait Sink {}
pub trait LocalSink: Sink {} // Allowed: classes 0,1,2,3
pub trait NetworkSink: Sink {} // Allowed: classes 1,2,3 (NOT class 0)
pub trait MatterSink: NetworkSink {} // Allowed: class 2,3 + cluster-filter (ADR-122)
impl Emitter {
pub fn publish<S: NetworkSink>(&self, sink: &S, frame: BfldFrame)
-> Result<(), BfldError>
{
if frame.header.privacy_class == 0 {
return Err(BfldError::PrivacyViolation {
reason: "class 0 to NetworkSink",
});
}
// ... serialize and write
}
}
实际实现位于 v2/crates/wifi-densepose-bfld/src/sink.rs,与 ADR 文档的 trait 继承略有演化但意图一致:每个 sink 都实现 Sink 并声明 const MIN_CLASS: PrivacyClass 与 const KIND: &'static str;LocalSink、NetworkSink、MatterSink 逐层收窄。运行时闸门 check_class<S: Sink>(class) 用一次简单的 >= 字节比较完成判定(class 数值越大越安全,因而接受更高数值即接受更低信息密度),不通过则返回携带 sink 种类的 BfldError::PrivacyViolation。仓库同时提供了三个零尺寸"kind tag"(LocalKind/NetworkKind/MatterKind)作为默认 sink 类型,供单元测试与编译期表使用。
2.3 档位与 sink 的映射表(源码确认)
| Sink trait | MIN_CLASS |
接受的档位 |
|---|---|---|
LocalSink |
PrivacyClass::Raw |
0, 1, 2, 3 |
NetworkSink |
PrivacyClass::Derived |
1, 2, 3 |
MatterSink |
PrivacyClass::Anonymous |
2, 3 |
且 MatterSink: NetworkSink——每个 Matter sink 同时是网络 sink。
3. 核心决策二:rf_signature_hash 的 BLAKE3 密钥哈希轮换
3.1 算法与源码逐行对照
ADR-120 给出的参考实现如下:
pub fn rf_signature_hash(
site_salt: &[u8; 32], // generated on first boot, persisted in TPM/KMS
day_epoch: u32, // floor(unix_time_utc / 86400)
features: &IdentityFeatures,
) -> Hash {
let mut hasher = blake3::Hasher::new_keyed(site_salt);
hasher.update(&day_epoch.to_le_bytes());
hasher.update(&features.canonical_bytes());
hasher.finalize()
}
其落地代码在 v2/crates/wifi-densepose-bfld/src/signature_hasher.rs,以 SignatureHasher 结构体封装:
- 常量:
SECONDS_PER_DAY = 86_400(轮换模数)、SITE_SALT_LEN = 32(BLAKE3 keyed 模式固定密钥长度)、RF_SIGNATURE_LEN = 32(BLAKE3 默认输出长度); SignatureHasher::new(site_salt):从持久秘密存储(TPM/KMS 或严格权限文件)读取盐后构建,盐从此永不传输;day_epoch_from_unix_secs(unix_secs) -> u32:unix_secs / 86_400,UTC 午夜翻转;compute(day_epoch, features_bytes):Hasher::new_keyed(&site_salt)→update(day_epoch.to_le_bytes())→update(features)→finalize(),与 ADR 伪代码完全一致;- 便捷方法
compute_at(unix_secs, features)免去手动换算。
其中"确定性序列化"由 v2/crates/wifi-densepose-bfld/src/identity_features.rs 的 IdentityFeatures 枚举负责,它把两种特征源统一到一个规范字节路径之下:
- 首选:
IdentityFeatures::Embedding(&IdentityEmbedding)——借用的 AETHER 嵌入向量,直接承载聚类身份,输出EMBEDDING_DIM × 4 = 512字节(全部 little-endian f32); - 回退:
IdentityFeatures::RiskFactors { sep, stab, consist, conf }——四元风险因子,输出固定 16 字节(RISK_FACTOR_BYTES),在编码器离线时仍可用。
在 v2/crates/wifi-densepose-bfld/src/emitter.rs 的 BfldEmitter::emit_with_oracle 中,哈希在把嵌入向量移入环形缓冲之前先行计算(timestamp_ns / NS_PER_SEC 换算 unix 秒再求 day_epoch),随后通过 BfldEvent::with_privacy_gating(...) 构造事件;class 3 会在事件构造器内再次剥离风险分与哈希,形成纵深防御。
3.2 跨站点隔离为什么是"结构性"的
site_salt 是一个每节点唯一、256-bit 随机、永不在网络上传输的秘密。因此站点 A 与站点 B 即使观测到同一个物理个体,产出的 rf_signature_hash 也是互不相关的——不存在操作者(或攻破单个节点的攻击者)能用来跨站关联的"桥接密钥"。
这里要强调的是:BLAKE3 keyed 模式是一个伪随机函数族(PRF,pseudorandom function family),当且仅当 site_salt 保密时成立。这与"策略上禁止分享"有本质区别——桥接在计算上不可能(the bridge cannot be computed),正如 docs/research/BFLD/04-privacy-gating.md 第 2 节所论证:攻破单站无法推断 hash_A 与 hash_B 是否对应同一人。
3.3 站内、日内跟踪为何安全
站内同一天内,同一人的两帧会产生相似但不相同的临时特征摘要,从而形成同一 (site, day) 范围内的"会话内可聚类、身份不可恢复"的假名(pseudonym)。这是刻意设计:它允许操作者聚合同一会话的事件,而不泄露身份。rf_signature_hash 不是身份——它是限定在 (站点, 日期) 作用域内的假名;同一个人连续两天访问同一站点,将得到两个不同的假名。
3.4 日轮换节奏
轮换以 UTC 午夜为界(epoch k 对应 k * 86_400_000_000_000 纳秒)。一旦轮换发生,此前所有 rf_signature_hash 与未来值在密码学上断开关联——轮换前的日志与轮换后的日志即使由节点操作者本人也无法关联。这与 ADR-120 选型一节互相印证(见第 6 节 Alt 3/Alt 4)。
4. 核心决策三:PrivacyGate 单向降级转换器
BfldFrame 载荷中混装了感知数据与身份衍生数据,因此仅有"事件级"开关不够,必须提供唯一合法的降级通道:PrivacyGate::demote(frame, target_class)。其语义(ADR-120 第 2.4 节)为:
- 断言目标档位的数值严格大于或等于输入档位(数字越大信息越少);
- 用
subtle::Zeroize语义零化该档位禁止的字段; - 重算
payload_crc32; - 返回新帧。
不存在 promote 操作——class-2 帧不可能变回 class-1 帧,因为被丢弃的字段在闸门可达的范围内没有被保留。
源码实现在 v2/crates/wifi-densepose-bfld/src/privacy_gate.rs。需要说明,实际实现为追求跨平台与 no_std 兼容,采用了"手工零化循环 + core::hint::black_box"而非 subtle crate 调用(zeroize_then_clear 先逐字节覆写再截断,black_box(v.as_ptr()) 阻止编译器死存储消除 DCE 吞掉写操作),并额外处理了载荷段:
- 目标 ≥ class 2(Anonymous):丢弃
compressed_angle_matrix(身份表面),若存在可选csi_delta段一并零化后置None(from_payload会依据csi_delta.is_some()反推 flag 位,保证HAS_CSI_DELTA位同步清除); - 目标 ≥ class 3(Restricted):再丢弃
amplitude_proxy与phase_proxy; - 帧头
privacy_class与payload_crc32统一重同步;对无法干净解析的畸形载荷,类字节与 CRC 仍会更新(帧字节原样保留)。
逆向调用会返回 BfldError::InvalidDemote { from, to }(见 lib.rs 的 BfldError 枚举)。此外,事件侧也有对应实现:BfldEvent::with_privacy_gating(...) 在构造时按 privacy_class 剥离身份字段,与帧级闸门形成纵深防御。
5. 核心决策四:identity_embedding 的内存生命周期
5.1 类型系统的三重锁
身份嵌入是 AETHER 对比学习编码器(ADR-024)的输出。在 v2/crates/wifi-densepose-bfld/src/embedding.rs 中,IdentityEmbedding 被刻意实现为"不可逃逸"类型:
- 无
Serializeimpl:对任何 MQTT/磁盘/网络 I/O sink 均不可序列化;Debug只输出维度与 L2 范数(values显示为<redacted>); - 无
Copy、无Clone:唯一取值通道是借用的as_slice(),生命周期绑定&self; Drop零化:析构时用0.0覆写全部[f32; 128]存储,并以black_box阻止 DCE。
这些约束被编译期断言固化:static_assertions::assert_impl_all!(IdentityEmbedding: Drop) 与 assert_not_impl_any!(IdentityEmbedding: Copy, Clone)——一旦未来某次 PR 误加派生,构建直接失败,这正是 I2"结构性而非文档化"的落地方式。此外文档还提到 #[forbid(serde::Serialize)] lint 作为纵深防线。
5.2 FIFO 环形缓冲
嵌入向量存放于 EmbeddingRing(embedding_ring.rs):固定容量 RING_CAPACITY = 64(ADR-120 第 2.5 节"约 30KB"与 64×128×f32 相符),采用无堆分配的 no_std 环形数组实现。行为:
- 编码器在每个采集窗口写入(
push); - 供
identity_risk_score计算(ADR-121)消费——注意文档说明实际在emitter.rs中嵌入向量先于风险门评估被推入环形缓冲; - 永不写盘、永不发 MQTT;
- FIFO 溢出时逐出最旧条目,其
Drop随即运行、零化 f32 存储。
drain() 是 coherence-gate 的 Recalibrate 动作触发的显式清空钩子(ADR-121 第 2.4 节),一次性 drop 所有槽位。注意 docs/research/BFLD/04-privacy-gating.md 第 3 节的早期版本描述为"600 帧默认容量",当前仓库源码以 64 为准——本文以实际实现为准。
6. 工程护栏:#[must_classify] 默认拒绝式字段分类
ADR-120 的默认拒绝(default-deny)机制针对一个常见事故模式——"新字段先上线,六个月后才被发现身份泄漏"。其设计为:
- 每个新增到
BfldFrame/BfldEvent的字段必须标注#[must_classify](自定义属性宏); - 若字段未出现在逐档允许列表中,编译失败;
- 文档描述的落地形态是属性注解(如
#[privacy_class(minimum = N)])加上 CI 阶段"PR 无分类注解即不能通过"的强制;对字段分类流程的运行时半对应物,可见 privacy_gate.rs 中按target.as_u8()阈值分段的零化逻辑。
它强制未来每一位贡献者在新增字段时做出显式隐私决策。
7. 双 ID 空间契约:Soul Signature 部署模式
Soul Signature(见 docs/research/soul/)是一个基于同意(consent-based)的生物特征系统,其刻意为已登记人员产出长期持久的个人身份。因此它无法运行在默认 class 2 下——它所需的 identity_embedding 在该档位上结构性缺失。ADR-120 第 2.7 节定义了契约:
| 部署模式 | privacy_class |
未登记旁观者的 ID 空间 | 已登记人员的 ID 空间 |
|---|---|---|---|
| 默认 BFLD-only | 2 (anonymous) | 日轮换 rf_signature_hash |
不适用——无登记 |
| Soul Signature 显式选择 | 1 (derived) | 日轮换 rf_signature_hash(不变) |
来自 Soul Signature 图的长期不透明 person_id |
| Restricted / 养老院 | 3 (restricted) | 抑制 | 不适用——class 3 下 Soul Signature 禁用 |
两个 ID 空间无碰撞地共存:轮换哈希是"不在同意名册上所有人"的隐私保护标识;稳定 person_id 仅在本人 GDPR/HIPAA 模式下为已登记受试者保留。Soul Signature 的 match_against_enrolled() 只消费内存中的 identity_embedding(I2 依然成立),输出 person_id 加一个校准后的相似度分数,永不把嵌入写盘或上线。class-1 要求在编译期强制:匹配 API 接受 &IdentityEmbedding 参数,该类型只有在 BFLD crate 以 --features soul-signature 编译并针对 class-1 帧时方可构造。仓库中相关实现可查 soul_match.rs 与 soul_channels.rs 模块及对应测试,模块注释明确标注了身份锁定的数据门控状态(真实 AETHER 登记 + 体共振通道数据尚未供给前,仅凭心肺通道身份不可分离)。
8. 方案权衡与后果分析
8.1 备选方案与拒绝理由
- Alt 1:单一布尔
privacy_mode标志(ADR-115 现状)——拒绝。粒度不足:帧内混装可发布感知数据与不可发布身份数据,闸门必须工作在字段级而非事件级。 - Alt 2:SHA-256 替代 BLAKE3——拒绝。BLAKE3 keyed-hash 模式在 ESP32-S3 / Cortex-M 核心上约快 5 倍,且对本场景安全余量相当;SHA-256 无密钥模式(须退而求其次用 HMAC-SHA256,可用但更慢)。
- Alt 3:按小时而非按天轮换——拒绝。小时级轮换会破坏操作者可能需要"此人早上来过、下午又来了"的合法用例。日边界是折中。
- Alt 4:每事件 nonce 替代日 epoch——拒绝。每事件 nonce 会迫使消费方跟踪会话内哪些事件来自同一人,反而按结构泄漏身份信息;日 epoch 保留粗粒度时间分组却不泄漏更细粒度身份。
8.2 积极后果
- 跨站点身份关联计算上不可能,而不仅仅是"策略上禁止"——这是无 TEE 前提下可获得的最强隐私保证形式;
#[must_classify]默认拒绝机制截断了"字段上线数月后才暴露泄漏"的常见事故链;identity_embedding不会被意外序列化——类型系统承载该约束(compile-timeassert_not_impl_any);- 类转换器让数据生命周期显式化、可审计。
8.3 消极后果
site_salt存储依赖 TPM(rvCSI 平台特性缺口见 ADR-095/ADR-096)或严格权限的秘密文件;丢失site_salt将导致历史 witness 比较不可能——这是设计使然,却构成文档性隐患;#[must_classify]是自定义 proc-macro,是构建中的又一个活动部件;- 需要多日分析的运维只能工作在聚合层,而非个体签名层。
8.4 中性后果
class 0 仅供 cargo test;部分 CI runner 可能需要显式 feature flag 才能编译 class-0 路径。
9. 验收标准(AC)与源码/测试对照
ADR-120 列出七条验收标准,绝大多数可在仓库中找到对应实现或测试锚点:
- AC1:
Emitter::publish在NetworkSink上遇到privacy_class = 0帧返回BfldError::PrivacyViolation。源码锚点:sink.rs 的check_class与BfldError::PrivacyViolation变体; - AC2:不同
site_salt的两个节点对同一模拟人产出的rf_signature_hash在 100 次试验中 Hamming 距离 ≥ 120 bits。signature_hasher.rs模块注释指明由tests/signature_hasher.rs直接覆盖; - AC3:
privacy_class = 3帧的序列化载荷中identity_risk_score与rf_signature_hash均缺席。由 privacy_gate.rs 的阈值零化与事件构造器双重保证; - AC4:
PrivacyGate::demote(class_1_frame, target=0)编译失败(compile-fail test)。对应运行时拒绝为BfldError::InvalidDemote; - AC5:向
BfldEvent新增字段而不加#[must_classify]即构建失败(CI 强制); - AC6:
IdentityEmbedding无任何公开可达的Serializeimpl。源码锚点:embedding.rs 的assert_not_impl_any; - AC7:drop 一个
IdentityEmbedding会零化其内存(cargo test --features zeroize-validation下的可调试验证)。对应Drop实现的black_box可观测零化。
测试目录位于 v2/crates/wifi-densepose-bfld/tests/,其中 event_gating_irreversibility.rs、event_privacy_gating.rs、identity_embedding.rs、frame_roundtrip.rs 等直接围绕本 ADR 的分级、不可逆性与零化语义。
10. 参考与延伸阅读
- ADR-118(总纲,三条不变量)
- ADR-119(帧格式;
privacy_class字节位置) - ADR-121(
identity_risk_score评分) - ADR-122(Matter 暴露面与 cluster-filter)
- ADR-141(隐私控制面的演进)
- docs/research/BFLD/04-privacy-gating.md(逐字段暴露表、tcpdump/自检审计流程)
- docs/research/BFLD/03-security-threat-model.md、docs/research/BFLD/README.md
- 核心 crate:v2/crates/wifi-densepose-bfld/src/lib.rs
- 学术引用:KIT BFId(ACM CCS 2025)、NDSS LeakyBeam(2025)、BLAKE3 keyed-hash 规范
注:ADR 状态为 Proposed(2026-05-24,决策者 ruv),本文所述能力均以当前仓库中 wifi-densepose-bfld crate 的实际实现为准;运行
cargo test -p wifi-densepose-bfld可在本地验证各隐私测试用例。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00