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:
