Faying Protocol/1.0 — §3 Components and Interfaces
§3 Components and Interfaces
协议层有六个核心组件:Mandate Service(MS)/ Presence Channel(PC)/ Attestation Chain(AC)/ Revocation Registry(RR)/ Liveness Channel(LC)/ Behavior Baseline Service(BBS)。每个组件下面分三部分讲:
- 职责:组件在协议中的位置与边界;
- TypeScript 接口骨架:人读视图(Non-normative),权威定义见 §4 Data Models 与 §5 Protocol Messages;
- 不变式:协议层必须始终满足的硬约束,每条不变式都可追溯到 §Requirements 中的至少一条 EARS 子条款。
EARS 追溯说明:本章每条不变式后以
Trace:列出其对应的 EARS 子条款编号(出处见本规范需求基线),形式为R<requirement>.<criterion>.<clause>。
§3.0 共享类型前向声明(Non-normative)
为使本章 TypeScript 接口块可独立通过 tsc --noEmit 编译,下方代码块以最小骨架形式前向声明本章引用的支撑类型;这些类型的权威定义见 §4 Data Models。
// §3.0 — Non-normative forward declarations.
// Authoritative definitions live in §4 Data Models.
export type IsoTime = string;
export type MandateId = string;
export type FayID = string;
export type HumanPrimeID = string;
export type DeviceId = string;
export type AuthorizationGrade = "G0" | "G1" | "G2" | "G3" | "G4";
export interface Scope {
readonly domains: readonly string[];
readonly actions: readonly string[];
readonly terminals?: readonly string[];
readonly budget?: ResourceBudget;
}
export interface ResourceBudget {
readonly max_calls_per_minute?: number;
readonly max_bytes_per_call?: number;
}
export interface Grade {
readonly value: AuthorizationGrade;
readonly autonomy: number; // 数值越大自主性越高(G0 最低,G4 最高)
}
export interface PresenceRequirement {
readonly signal_types: readonly PresenceSignalType[];
readonly max_staleness_ms: number;
readonly on_loss: "downgrade" | "suspend";
}
export type PresenceSignalType =
| "webauthn-uv-fresh"
| "face-continuous"
| "fingerprint-tap"
| "presence-heartbeat-only"
| "intent-ticket";
export interface SignatureBundle {
readonly alg: string;
readonly hash: string;
readonly sig: Uint8Array;
readonly chain?: readonly SignatureBundle[];
}
export interface Endorsement {
readonly enabled: boolean;
readonly endorsed_scope: Scope;
readonly endorsed_grade: Grade;
readonly endorsed_lifetime_ms: number;
readonly offline_revocation_policy:
| "stop-and-audit"
| "stop-only"
| "graceful-stop";
readonly start_at?: IsoTime;
}
export interface Mandate {
readonly mandate_id: MandateId;
readonly issuer: HumanPrimeID;
readonly subject: FayID;
readonly scope: Scope;
readonly grade: Grade;
readonly presence_req: PresenceRequirement;
readonly device_id?: DeviceId;
readonly not_before: IsoTime;
readonly not_after: IsoTime;
readonly parent?: MandateId;
readonly endorsement?: Endorsement;
readonly signature_bundle: SignatureBundle;
}
export interface PresenceSignal {
readonly mandate_id: MandateId;
readonly signal_type: PresenceSignalType;
readonly nonce: Uint8Array;
readonly produced_at: IsoTime;
readonly device_attestation: Uint8Array;
readonly challenge?: Uint8Array;
readonly challenge_response?: Uint8Array;
readonly signature_bundle: SignatureBundle;
}
export interface PresenceVerdict {
readonly accepted: boolean;
readonly verdict: "ok" | "stale" | "replay" | "attestation-invalid";
readonly recommended_next_grade?: AuthorizationGrade;
}
export interface PresenceAck {
readonly accepted: boolean;
readonly mandate_id: MandateId;
readonly observed_at: IsoTime;
}
export interface PresenceState {
readonly mandate_id: MandateId;
readonly last_freshness: IsoTime;
readonly stale: boolean;
readonly active_signal_types: readonly PresenceSignalType[];
}
export interface BootstrapRequest {
readonly subject: FayID;
readonly scope: Scope;
readonly grade: Grade;
readonly presence_req: PresenceRequirement;
readonly not_before: IsoTime;
readonly not_after: IsoTime;
readonly human_witness: Uint8Array; // WebAuthn assertion
readonly endorsement?: Endorsement;
readonly faying_request_ref?: string;
}
export interface GradeSwitchRequest {
readonly mandate_id: MandateId;
readonly target_grade: Grade;
readonly current_grade: Grade;
readonly human_witness?: Uint8Array;
readonly reason: string;
}
export interface DelegateRequest {
readonly parent_mandate_id: MandateId;
readonly child_subject: FayID;
readonly child_scope: Scope;
readonly child_grade: Grade;
readonly device_id?: DeviceId;
readonly not_before: IsoTime;
readonly not_after: IsoTime;
}
export type RevokeReason =
| "human-initiated"
| "expiry"
| "task-completed"
| "human-prime-unreachable"
| "ego-deviation"
| "fay-credential-invalid"
| "human-prime-credential-invalid"
| "regulatory-order"
| "terminal-disconnected";
export interface RevokeRequest {
readonly mandate_id: MandateId;
readonly reason: RevokeReason;
readonly cascade: boolean;
readonly human_witness?: Uint8Array;
}
export interface RevokeReceipt {
readonly mandate_id: MandateId;
readonly reason: RevokeReason;
readonly revoked_at: IsoTime;
readonly cascade_targets: readonly MandateId[];
readonly signature_bundle: SignatureBundle;
}
export interface RevocationStatus {
readonly mandate_id: MandateId;
readonly revoked: boolean;
readonly revoked_at?: IsoTime;
readonly reason?: RevokeReason;
readonly observed_at: IsoTime;
}
export interface ScopeFilter {
readonly subjects?: readonly FayID[];
readonly issuers?: readonly HumanPrimeID[];
}
export interface Subscription {
readonly subscription_id: string;
readonly close: () => void;
}
export interface AtomicAction {
readonly action: string;
readonly target?: string;
readonly sensitivity: "low" | "normal" | "high" | "critical";
}
§3.1 Mandate Service(MS)
职责:代表 Human Prime 进行 Mandate 全生命周期管理(颁发 / 续期 / 降级 / 撤销);是 Faying Action 的唯一合法入口。
接口(Non-normative):
export interface MandateService {
/** Faying Action 的唯一合法入口 */
bootstrap(req: BootstrapRequest): Promise<Mandate>;
/** 在场信号校准;返回当前 Mandate 是否仍有效 / 应否降级 */
verifyPresence(
mandateId: MandateId,
signal: PresenceSignal
): Promise<PresenceVerdict>;
/** 等级切换:升级必须 HP 见证;降级可由协议自动触发 */
switchGrade(req: GradeSwitchRequest): Promise<Mandate>;
/** 跨设备派生:从父 Mandate 派生子 Mandate,scope ⊆ 父 scope,grade ≤ 父 grade */
delegate(req: DelegateRequest): Promise<Mandate>;
/** 对称撤销:可达性必须 ≥ bootstrap */
revoke(req: RevokeRequest): Promise<RevokeReceipt>;
}
关键不变式:
-
I-MS-1(HP 锚定的 Bootstrap):
bootstrap()的请求方必须携带可验证的 HP attestation(默认形态为 WebAuthn 用户在场断言);不存在"MS 自我决定 bootstrap"或由 IF / SA 替代 HP 完成认可确认的合法路径。- Trace:
R1.3.1(HP 主动发起须出示可验证的明确认可确认)、R1.3.5(不提供任何由 IF / MS / SA 替代 HP 完成 Faying 认可确认的路径)。
- Trace:
-
I-MS-2(升级方向的 HP 见证强制):
switchGrade()当且仅当target.autonomy > current.autonomy时必须携带可验证的human_witness;缺失或验签失败一律E_HUMAN_WITNESS_REQUIRED,且 IF 不得自主发起 grade 升级。- Trace:
R7.1.1(child.scope ⊆ parent.scope收敛——隐含等级升降语义中的非扩张约束,与降级单调性原则一致)、R5.1.1(基于presence_req的接受前置条件,是switchGrade写入presence_req字段后被 RP 校验的依据)。 - 备注:本不变式还由 R6.1(升级必带 HP 见证)权威覆盖;本章列举的 EARS 追溯仅取本任务声明的 Requirement 集合内的相关条款。
- Trace:
-
I-MS-3(撤销可见性预算):
revoke()一旦由 RR publish,对所有后续 RP 的 query 在不超过RevocationVisibilityBudget(默认 1s,按 grade 收紧;详见 §6 / 附录 B)内必须返回revoked;MS 不得提供"乐观放行"路径。- Trace:
R4.2.1(撤销可见性预算 ≤RevocationVisibilityBudget)、R4.2.4(StaleBudget内未确认 → Default-Deny)。
- Trace:
-
I-MS-4(派生 scope / grade 严格收敛):
delegate()颁发的子 Mandate 必须满足child.scope ⊆ parent.scope∧child.grade.autonomy ≤ parent.grade.autonomy;任何方向上的扩张以E_PROTOCOL拒绝,且子 Mandate 的signature_bundle.chain必须携带父 Mandate 副签。- Trace:
R7.1.1(子 scope ⊆ 父 scope)、R7.1.2(子 autonomy ≤ 父 autonomy)。
- Trace:
§3.2 Presence Channel(PC)
职责:把 Presence Device 产生的物理在场信号,安全、低延迟、抗重放地送达 MS,并由 MS 转化为对当前 Mandate 的"持续校准"判定。
信号类型(与 §7 等级对齐):
| 类型 | 强度 | 适用等级 | 失败时降级路径 |
|---|---|---|---|
webauthn-uv-fresh | 强 | G1 Strict | 失败 → Suspended |
face-continuous | 强 | G1 Strict | 失败 → 降为 G2 Moderate |
fingerprint-tap | 中 | G2 Moderate | 失败 → 降为 G3 Loose |
presence-heartbeat-only | 弱 | G3 Loose / G4 Autonomous | 失败 → Suspended |
intent-ticket | 一次性 | 跨等级补充 | 一次性消耗,不影响主等级 |
接口(Non-normative):
export interface PresenceChannel {
/** PD 发起;MS 校验后写入对应 Mandate 的 PresenceState */
push(signal: PresenceSignal): Promise<PresenceAck>;
/** RP 在调用前查询当前 Presence 是否新鲜 */
query(mandateId: MandateId): Promise<PresenceState>;
}
关键不变式:
-
I-PC-1(信号强制三元组 + Mandate 侧新鲜度窗口):每个
PresenceSignal必须显式携带nonce + produced_at + device_attestation,并由 Presence_Device 签名;新鲜度窗口不由信号自带,而由其对应 Mandate 的presence_req.max_staleness_ms给定(绑定 grade、由 HP 在 BOOTSTRAP 锚定、受LivenessDetectionBudget按 grade 收紧)。produced_at + presence_req.max_staleness_ms < now的信号一律视为 stale。- Trace:
R5.1.3(nonce / produced_at / device_attestation字段强制)、R5.1.4(PC 在校验阶段拒绝过期信号)。
- Trace:
-
I-PC-2(同 nonce 单次消费):同一
(subject, nonce)在2 × max_message_lifetimeTTL 窗口内至多被接受一次;重复消费 →E_REPLAY拒绝。- Trace:
R5.1.1(last_freshness必须满足新鲜度——隐含 nonce + 时间戳的抗重放语义在 PC 层落地)、R5.1.3(nonce字段是抗重放的协议级抓手)。
- Trace:
-
I-PC-3(在场新鲜度自动收紧):
PresenceState.last_freshness必须 ≥now − presence_req.max_staleness_ms;不满足时 PC 必须使下一次状态转换迁移到Degraded(grade')(grade'.autonomy < current.autonomy)或Suspended,禁止维持原 grade,禁止切换到自主性更高的方向。- Trace:
R5.1.1(接受前置条件last_freshness ≥ t − max_staleness_ms)、R12.2.2(以新鲜度而非心跳轮询周期作为放行依据)。
- Trace:
§3.3 Attestation Chain(AC)
职责:把 HP → MS → IF → 派生 IF 的全部签发动作组织为一条可逆向追溯的签名链,使任意一个 Mandate 都可被独立第三方还原其授权来源。
链结构(示意):
Root: HP-Public-Key(自托管 / 锚定到 WebAuthn 凭据)
└─ MS-Cert(HP 签名,绑定 MS 公钥与权限)
└─ Mandate M1(MS 签名)
├─ Mandate M2(M1 派生,MS 副签 + 父 Mandate 副签)
└─ Mandate M3(M1 派生)
接口(Non-normative):
export interface AttestationChain {
/** 校验自叶到根的完整链 */
verify(mandate: Mandate): Promise<AttestationVerifyResult>;
/** 追加一条链上事件(Bootstrap / GradeSwitch / Delegate / Revoke) */
append(event: AttestationEvent): Promise<void>;
/** 还原指定 Mandate 的责任承接端 */
resolveAccountableParty(mandateId: MandateId): Promise<HumanPrimeID>;
}
export interface AttestationVerifyResult {
readonly verified: boolean;
readonly root: HumanPrimeID;
readonly invalid_node?: string;
}
export interface AttestationEvent {
readonly event_type: "bootstrap" | "grade-switch" | "delegate" | "revoke";
readonly mandate_id: MandateId;
readonly issuer: HumanPrimeID;
readonly subject: FayID;
readonly ts: IsoTime;
readonly signature_bundle: SignatureBundle;
}
关键不变式:
-
I-AC-1(父签名 + validity window 双重约束):链上每一节点都必须由其父节点签名,且签名时间戳必须落在父节点的 validity window(
[parent.not_before, parent.not_after])内;任一不满足即E_ATTESTATION_INVALID并触发对应 Mandate 的 Revoke。- Trace:
R3.1.2(自叶到根校验,父节点 validity window 内时间戳)、R3.1.3(任一节点失效以E_ATTESTATION_INVALID拒绝并触发 Revoke)。
- Trace:
-
I-AC-2(链完整性,缺一不可):链验证必须自叶到根全部通过;任一节点缺失或签名无效即视为不可信,整条链返回
verified = false。- Trace:
R3.1.1(Bootstrap / GradeSwitch / Delegate / Revoke四类事件必须入链)、R3.1.2(链式校验在所有节点均有效时方返回verify = true)。
- Trace:
-
I-AC-3(派生收敛在链路上不可逆向放宽):在派生过程中,子节点
scope与grade.autonomy必须单调收敛;任何放宽 scope 或抬高 autonomy 的派生节点都不存在合法的链上签名路径。- Trace:
R7.1.1(子 scope ⊆ 父 scope)、R7.1.2(子 autonomy ≤ 父 autonomy)。
- Trace:
§3.4 Revocation Registry(RR)
职责:实时撤销状态服务。承担"撤销可达性 ≥ 建立可达性"这一对称性原则的工程支点。
双轨设计:
- 拉:RP 在每次接受调用时执行短轮询(OCSP-like,建议 stapling);
- 推:MS 撤销后向所有已订阅 RP 发起推送(WebSocket / SSE / MQTT);
- 保守 fallback:若 RP 在
StaleBudget(默认 5s,按 grade 收紧)内未能确认 RR 状态,必须按 Default-Deny 拒绝该次调用。
接口(Non-normative):
export interface RevocationRegistry {
publish(receipt: RevokeReceipt): Promise<void>;
query(mandateId: MandateId): Promise<RevocationStatus>;
subscribe(rpId: string, scope: ScopeFilter): Subscription;
}
关键不变式:
-
I-RR-1(撤销发布即刻可见):撤销一旦
publish()完成,对所有后续query()在RevocationVisibilityBudget(默认 1s,按 grade 收紧)内必须立即返回revoked = true,呈现强一致语义。- Trace:
R4.2.1(RevocationVisibilityBudget内 query 返回revoked)。
- Trace:
-
I-RR-2(不可达 → Default-Deny):当 RR 在
StaleBudget内不可达,RP 必须以E_RR_UNAVAILABLE拒绝调用,禁止"乐观放行"。- Trace:
R2.1.4(StaleBudget内不可达 → Default-Deny +E_RR_UNAVAILABLE)、R4.2.4(RP 在状态确认失败时按 Default-Deny 处理)。
- Trace:
语义边界:RR 不可达 ≠ iFay 自身失联。RR 不可达仅表示"无法判定 Mandate 是否被撤销",触发
E_RR_UNAVAILABLE拒绝;iFay 失联(含 Actually-Disconnected / Perceived-Disconnected)由 §3.5 Liveness Channel 与 PresenceState 单独刻画。两类失联事件互不替代——存在"iFay 在线但 RR 不可达"以及"RR 在线但 iFay 失联"两种正交组合,协议层均按 Default-Deny 收敛。
§3.5 Liveness Channel(LC)
职责:以低开销的心跳 + 在场新鲜度联合判定 iFay_Instance 在 MS / RP / HP 视角下的"感知活性",并把"真实活性"与"感知活性"之间的不一致窗口显式刻画为协议层一等公民。
双语义定义:
- Actually-Disconnected(真实失联):iFay_Instance 进程 / 网络 / 设备已停止工作或不可被任何外部主体到达。客观物理事实,不可被协议层直接观测。
- Perceived-Disconnected(感知失联):在 MS / RP / HP 视角下,依据最近的 Presence_Signal、心跳与 RR 推送状态,判定 iFay_Instance 已失联。协议层唯一可作为决策依据的语义。
两类不一致窗口:
- 窗口 A — Actually-Disconnected ∧ Perceived-Connected:iFay 实际已断,但最近一次 Presence_Signal 仍在
max_staleness_ms内 → 心跳间隔内的"观察盲区"; - 窗口 B — Actually-Connected ∧ Perceived-Disconnected:iFay 实际在线,但最近一次 Presence_Signal 已超过
max_staleness_ms(网络抖动 / 心跳丢包)→ 协议层以悲观推定收敛。
悲观推定原则(统一收敛规则):
协议层仅以 Perceived-Disconnected 作为决策依据;任意"真实在线但被感知为失联"的 iFay_Instance 不得据此豁免协议层的判定后果。在两类不一致窗口内,协议必须按"更严格的那一侧"处理;不存在"按更宽松的状态处理"的合法路径。
接口(Non-normative,与 §3.2 PC 共享底层信号):
export interface LivenessChannel {
/** 当前感知活性快照 */
perceived(mandateId: MandateId): PerceivedLiveness;
/** 显式触发悲观判定(如检测到心跳丢失) */
declareStale(mandateId: MandateId, reason: string): Promise<void>;
}
export interface PerceivedLiveness {
readonly is_perceived_connected: boolean;
readonly last_freshness: IsoTime;
readonly staleness_ms: number;
readonly decided_by: "presence-signal" | "heartbeat" | "explicit-declare";
}
关键不变式:
-
I-LC-1(新鲜度判定,禁止以心跳轮询周期放行):感知失联判定必须基于
last_freshness ≥ now − max_staleness_ms;禁止以"心跳轮询周期未到"为由继续放行调用。- Trace:
R12.2.2(以新鲜度判定而非心跳轮询周期作为放行依据)。
- Trace:
-
I-LC-2(进入 Disconnected 的状态机迁移):一旦判定为 Perceived-Disconnected,下一次状态转换必须按 §4.3 状态机迁移(Active → Disconnected / Active → Suspended,依据是否为有效 Endorsed_Mandate);不存在维持原状态或切换到更宽松状态的合法路径。
- Trace:
R12.1.3(仅以感知失联作为协议层判定依据,不豁免协议层后果)。
- Trace:
-
I-LC-3(恢复必须经过事务性对账):从 Perceived-Disconnected 恢复到 Perceived-Connected 必须经过 §8.4 重连对账(Reconciliation)事务;禁止自动恢复。
- Trace:
R12.1.3(感知失联期间不豁免协议层后果——蕴含"恢复需显式事务性确认",与 R12.4.1 / R12.4.3 的对账事务一致;本任务声明的 Requirement 集合内由 12.1 锚定)。
- Trace:
§3.6 Behavior Baseline Service(BBS)
职责:维护针对每对 (Human_Prime, iFay_Instance) 的累积行为画像;用于检测高敏感动作对基线的显著偏离,并在偏离时触发额外的人类见证(详见 §9.10.6 T5 防护)。
接口(Non-normative):
export interface BehaviorBaselineService {
/** 累积一条新动作样本 */
record(sample: BehaviorSample): Promise<void>;
/** 评估当前动作相对基线的偏离度 */
evaluate(
hp: HumanPrimeID,
fay: FayID,
action: AtomicAction
): BaselineDeviation;
/** 应用 reputation decay(信任分衰减) */
decay(hp: HumanPrimeID, fay: FayID): Promise<void>;
}
export interface BehaviorSample {
readonly hp: HumanPrimeID;
readonly fay: FayID;
readonly action: AtomicAction;
readonly scope_used: Scope;
readonly risk_level: "low" | "normal" | "high" | "critical";
readonly affected_resources: readonly string[];
readonly ts: IsoTime;
}
export interface BaselineDeviation {
readonly exceeds_threshold: boolean;
readonly dimensions: readonly (
| "risk_level"
| "scope_used"
| "affected_resources"
)[];
readonly recommended_action:
| "allow"
| "require-extra-witness"
| "downgrade"
| "suspend";
}
关键不变式:
-
I-BBS-1(信任分必衰减且有上限):每对 (HP, IF) 的"信任分"必须随时间衰减且存在显式上限,禁止无限累积以稀释未来高敏感动作所需的人类见证强度。
- Trace:
R13.5.3(Action Reputation Decay:信任分必衰减且存在显式上限)。
- Trace:
-
I-BBS-2(超基线见证事件入链 + 推 HP 视野):每次"超基线触发额外见证"的事件必须写入 Attestation_Chain 并推送至 Human_Prime 视野通道;未获额外见证前以
E_HUMAN_WITNESS_REQUIRED拒绝该次调用。- Trace:
R13.5.4("超基线触发额外见证"事件写入 AC + 推送 HP 视野)、R13.5.2(未获额外见证前以E_HUMAN_WITNESS_REQUIRED拒绝)。
- Trace:
-
I-BBS-3(口径变更也是审计事件):基线计算口径本身一旦确定即写入 Attestation_Chain;口径变更视为一类独立审计事件,由协议委员会按既定流程审批。
- Trace:
R13.5.1(MS 维护 Behavior_Baseline)、R3.1.1(任一审计事件被处理时 AC 必须包含其签名节点;本章列举的 EARS 追溯仅取本任务声明的 Requirement 集合内的相关条款)。
- Trace:
