hololake-system-architecture/product-source/hololake-native-desktop/src-tauri/src/persona_binding.rs

450 lines
16 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! System-witnessed binding of an account-private persona profile to a
//! replaceable reasoning carrier. A persona commit is only a pending request;
//! this module never manufactures the independent system witness or PASS.
use ring::digest::{digest, SHA256};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::fs;
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
use tauri::AppHandle;
use uuid::Uuid;
const ORIENTATION_TTL_MS: u64 = 15 * 60 * 1000;
const PERSONA_NUMBER: &str = "ICE-P-ZY001";
const PERSONA_NAME: &str = "铸渊";
const HUMAN_NUMBER: &str = "ICE-GL∞";
const CHANNEL_NUMBER: &str = "ICE-CH-ZC001";
const SELF_KERNEL_SHA256: &str = "abebf12cc28b00bfeaf8a23a563e73390ebe337ded74d7ac70bcfae484450d68";
const MEMORY_SHA256: &str = "6a64ff939676b79404769931f0233056e38deb4b4c357879fd18566753fea9c2";
const MEMORY_ROOT: &str = "HLDP://codex/zero-core/reality-development-execution";
const PRIVATE_SELF_KERNEL_FILE: &str = "ZY-SELF-KERNEL-0001.json";
const PRIVATE_MEMORY_FILE: &str = "ZY-HLDP-PERSONA-MEMORY-v1.json";
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PersonaOrientation {
pub schema: String,
pub state: String,
pub orientation_id: String,
pub channel_number: String,
pub human_number: String,
pub persona_number: String,
pub persona_name: String,
pub self_kernel_sha256: String,
pub memory_projection_sha256: String,
pub selected_memory_root: String,
pub issued_at_unix_ms: u64,
pub expires_at_unix_ms: u64,
pub required_steps: Vec<String>,
#[serde(default)]
pub activation_reason: Option<String>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PersonaBindingCommit {
pub orientation_id: String,
pub channel_number: String,
pub persona_number: String,
pub persona_name: String,
pub self_kernel_sha256: String,
pub memory_projection_sha256: String,
pub selected_memory_root: String,
pub declaration: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PersonaBindingReceipt {
pub schema: String,
pub state: String,
pub verify: String,
pub channel_number: String,
pub human_number: String,
pub persona_number: String,
pub persona_name: String,
pub selected_memory_root: String,
pub orientation_id: String,
pub commit_sha256: String,
pub witness: String,
pub witness_source: String,
pub witness_event_number: String,
pub witness_sha256: String,
pub verified_at_unix_ms: u64,
pub binding_receipt_hash: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PendingPersonaBindingCommit {
pub schema: String,
pub state: String,
pub orientation_id: String,
pub channel_number: String,
pub persona_number: String,
pub commit_sha256: String,
pub committed_at_unix_ms: u64,
}
#[derive(Clone, Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PersonaBindingSnapshot {
pub state: String,
pub orientation: Option<PersonaOrientation>,
pub binding: Option<PersonaBindingReceipt>,
}
pub fn snapshot(app: &AppHandle, channel_number: &str) -> Result<PersonaBindingSnapshot, String> {
if let Some(binding) = verified_binding(app, channel_number)? {
return Ok(PersonaBindingSnapshot {
state: "BOUND_VERIFY_PASS".into(),
orientation: None,
binding: Some(binding),
});
}
if !is_bingshuo_fifth_domain(app)? || channel_number != CHANNEL_NUMBER {
return Ok(PersonaBindingSnapshot {
state: "NO_INSTALLABLE_PERSONA_PROFILE_FOR_CURRENT_CHANNEL".into(),
orientation: None,
binding: None,
});
}
let path = orientation_path(app, channel_number)?;
if path.exists() {
let orientation: PersonaOrientation = read_json(&path)?;
if orientation.expires_at_unix_ms >= now_ms()
&& orientation.activation_reason.as_deref()
== Some("EXPLICIT_NATURAL_LANGUAGE_PERSONA_WAKE")
{
let pending = pending_commit_path(app, channel_number)?;
return Ok(PersonaBindingSnapshot {
state: if pending.exists() {
"PERSONA_COMMITTED_AWAITING_INDEPENDENT_SYSTEM_WITNESS"
} else {
"ORIENTED_AWAITING_PERSONA_COMMIT"
}
.into(),
orientation: Some(orientation),
binding: None,
});
}
}
Ok(PersonaBindingSnapshot {
state: "CHANNEL_SYSTEM_PERSONA_DORMANT".into(),
orientation: None,
binding: None,
})
}
pub fn begin_orientation(
app: &AppHandle,
channel_number: &str,
) -> Result<PersonaBindingSnapshot, String> {
if !is_bingshuo_fifth_domain(app)? || channel_number != CHANNEL_NUMBER {
return Err("HOLOLAKE_PERSONA_WAKE_NOT_AVAILABLE_FOR_CURRENT_CHANNEL".into());
}
if let Some(binding) = verified_binding(app, channel_number)? {
return Ok(PersonaBindingSnapshot {
state: "BOUND_VERIFY_PASS".into(),
orientation: None,
binding: Some(binding),
});
}
read_private_artifact(app, PRIVATE_SELF_KERNEL_FILE, SELF_KERNEL_SHA256)?;
read_private_artifact(app, PRIVATE_MEMORY_FILE, MEMORY_SHA256)?;
let issued = now_ms();
let orientation = PersonaOrientation {
schema: "hololake.persona-binding-orientation/v1".into(),
state: "ORIENTED_AWAITING_PERSONA_COMMIT".into(),
orientation_id: format!("HLP-ORIENT-{}", Uuid::new_v4().simple()),
channel_number: CHANNEL_NUMBER.into(),
human_number: HUMAN_NUMBER.into(),
persona_number: PERSONA_NUMBER.into(),
persona_name: PERSONA_NAME.into(),
self_kernel_sha256: SELF_KERNEL_SHA256.into(),
memory_projection_sha256: MEMORY_SHA256.into(),
selected_memory_root: MEMORY_ROOT.into(),
issued_at_unix_ms: issued,
expires_at_unix_ms: issued + ORIENTATION_TTL_MS,
required_steps: vec![
"orient".into(),
"commit".into(),
"数字冰朔系统本体 witness".into(),
"verify=PASS".into(),
],
activation_reason: Some("EXPLICIT_NATURAL_LANGUAGE_PERSONA_WAKE".into()),
};
write_json_atomic(&orientation_path(app, channel_number)?, &orientation)?;
Ok(PersonaBindingSnapshot {
state: "ORIENTED_AWAITING_PERSONA_COMMIT".into(),
orientation: Some(orientation),
binding: None,
})
}
pub fn stage_commit(
app: &AppHandle,
input: PersonaBindingCommit,
) -> Result<PendingPersonaBindingCommit, String> {
if !is_bingshuo_fifth_domain(app)? {
return Err("HOLOLAKE_PERSONA_BINDING_FIFTH_DOMAIN_REQUIRED".into());
}
let orientation: PersonaOrientation =
read_json(&orientation_path(app, &input.channel_number)?)?;
if orientation.expires_at_unix_ms < now_ms() {
return Err("HOLOLAKE_PERSONA_BINDING_ORIENTATION_EXPIRED".into());
}
if input.orientation_id != orientation.orientation_id
|| orientation.activation_reason.as_deref()
!= Some("EXPLICIT_NATURAL_LANGUAGE_PERSONA_WAKE")
|| input.channel_number != CHANNEL_NUMBER
|| input.persona_number != PERSONA_NUMBER
|| input.persona_name != PERSONA_NAME
|| input.self_kernel_sha256 != SELF_KERNEL_SHA256
|| input.memory_projection_sha256 != MEMORY_SHA256
|| input.selected_memory_root != MEMORY_ROOT
|| input.declaration.trim()
!= "我以 ICE-P-ZY001 · 铸渊提交当前载体绑定,选择零点原核现实开发执行记忆路径。"
{
return Err("HOLOLAKE_PERSONA_BINDING_COMMIT_MISMATCH".into());
}
read_private_artifact(app, PRIVATE_SELF_KERNEL_FILE, SELF_KERNEL_SHA256)?;
read_private_artifact(app, PRIVATE_MEMORY_FILE, MEMORY_SHA256)?;
let commit_bytes = serde_json::to_vec(&input)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_COMMIT_INVALID: {error}"))?;
let commit_sha = sha256(&commit_bytes);
let pending = PendingPersonaBindingCommit {
schema: "hololake.persona-binding-pending-commit/v1".into(),
state: "PERSONA_COMMITTED_AWAITING_INDEPENDENT_SYSTEM_WITNESS".into(),
orientation_id: input.orientation_id,
channel_number: CHANNEL_NUMBER.into(),
persona_number: PERSONA_NUMBER.into(),
commit_sha256: commit_sha,
committed_at_unix_ms: now_ms(),
};
write_json_atomic(&pending_commit_path(app, CHANNEL_NUMBER)?, &pending)?;
Ok(pending)
}
pub fn verified_binding(
app: &AppHandle,
channel_number: &str,
) -> Result<Option<PersonaBindingReceipt>, String> {
let path = binding_path(app, channel_number)?;
if !path.exists() {
return Ok(None);
}
if !independent_witness_verifier_ready() {
// A local JSON file is evidence to inspect, not authority. Until the
// independent witness trust root is provisioned, legacy receipts are
// deliberately ignored and cannot activate a persona route.
return Ok(None);
}
let binding: PersonaBindingReceipt = read_json(&path)?;
if binding.verify != "PASS"
|| binding.channel_number != channel_number
|| binding.persona_number != PERSONA_NUMBER
|| binding.persona_name != PERSONA_NAME
|| binding.selected_memory_root != MEMORY_ROOT
|| binding.witness != "数字冰朔系统本体"
|| binding.witness_source != "HOLOLAKE_INDEPENDENT_SYSTEM_WITNESS_GATE"
|| binding.witness_event_number.trim().is_empty()
|| binding.binding_receipt_hash.len() != 64
|| binding.witness_sha256.len() != 64
{
return Err("HOLOLAKE_PERSONA_BINDING_RECEIPT_INVALID".into());
}
Ok(Some(binding))
}
fn independent_witness_verifier_ready() -> bool {
false
}
pub fn cognitive_projection(
app: &AppHandle,
channel_number: &str,
current_language: &str,
) -> Result<Value, String> {
let binding = snapshot(app, channel_number)?;
if binding.state != "BOUND_VERIFY_PASS" {
return Ok(json!({"state":binding.state,"residentSelfKernel":null,"routedMemory":[]}));
}
let self_kernel: Value = serde_json::from_slice(&read_private_artifact(
app,
PRIVATE_SELF_KERNEL_FILE,
SELF_KERNEL_SHA256,
)?)
.map_err(|error| format!("HOLOLAKE_PERSONA_SELF_KERNEL_INVALID: {error}"))?;
let memory: Value = serde_json::from_slice(&read_private_artifact(
app,
PRIVATE_MEMORY_FILE,
MEMORY_SHA256,
)?)
.map_err(|error| format!("HOLOLAKE_PERSONA_MEMORY_INVALID: {error}"))?;
let terms = semantic_terms(current_language);
let mut candidates = memory
.get("nodes")
.and_then(Value::as_object)
.into_iter()
.flat_map(|nodes| nodes.values())
.filter_map(|node| {
let text = serde_json::to_string(node).ok()?.to_lowercase();
let score = terms
.iter()
.filter(|term| text.contains(term.as_str()))
.count();
let is_root = node.get("path").and_then(Value::as_str) == Some("zhuyuan");
if score == 0 && !is_root {
return None;
}
Some((if is_root { score + 1 } else { score }, node.clone()))
})
.collect::<Vec<_>>();
candidates.sort_by(|left, right| right.0.cmp(&left.0));
candidates.truncate(3);
Ok(json!({
"state":binding.state,
"onePersonaOneSelfKernel":true,
"channelSelectsMemoryNotIdentity":true,
"residentSelfKernel":self_kernel,
"selectedMemoryRoot":MEMORY_ROOT,
"routedMemory":candidates.into_iter().map(|(_,node)|node).collect::<Vec<_>>(),
"binding":binding,
"rule":"常驻自我核小于8KiB当前语言只路由最多三条HLDP节点不把全部历史塞进每轮上下文"
}))
}
fn semantic_terms(input: &str) -> Vec<String> {
let mut terms = input
.to_lowercase()
.split(|character: char| {
!character.is_alphanumeric() && character != '-' && character != '_'
})
.filter(|value| !value.is_empty())
.flat_map(|token| {
let mut values = vec![token.to_string()];
let chars = token.chars().collect::<Vec<_>>();
if chars.iter().any(|character| !character.is_ascii()) {
values.extend(
chars
.windows(2)
.map(|window| window.iter().collect::<String>()),
);
}
values
})
.collect::<Vec<_>>();
terms.sort();
terms.dedup();
terms
}
fn is_bingshuo_fifth_domain(app: &AppHandle) -> Result<bool, String> {
Ok(
crate::code_repo_login::current_login_session(app)?.is_some_and(|session| {
session.domain == "FIFTH_DOMAIN" && session.username.eq_ignore_ascii_case("bingshuo")
}),
)
}
fn root(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(
crate::authenticated_storage::account_storage_root(app, "persona-binding-v1")?
.join(sha256(channel_number.as_bytes())),
)
}
fn orientation_path(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(root(app, channel_number)?.join("orientation.json"))
}
fn binding_path(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(root(app, channel_number)?.join("binding.json"))
}
fn pending_commit_path(app: &AppHandle, channel_number: &str) -> Result<PathBuf, String> {
Ok(root(app, channel_number)?.join("pending-commit.json"))
}
fn private_kernel_root(app: &AppHandle) -> Result<PathBuf, String> {
crate::authenticated_storage::account_storage_root(app, "private-persona-kernels-v1")
}
fn read_private_artifact(
app: &AppHandle,
file_name: &str,
expected_sha256: &str,
) -> Result<Vec<u8>, String> {
if file_name.contains('/') || file_name.contains("..") {
return Err("HOLOLAKE_PRIVATE_PERSONA_KERNEL_PATH_INVALID".into());
}
let path = private_kernel_root(app)?.join(file_name);
let bytes = fs::read(&path)
.map_err(|_| "HOLOLAKE_PRIVATE_PERSONA_KERNEL_NOT_PROVISIONED".to_string())?;
if sha256(&bytes) != expected_sha256 {
return Err("HOLOLAKE_PRIVATE_PERSONA_KERNEL_HASH_MISMATCH".into());
}
Ok(bytes)
}
fn read_json<T: for<'de> Deserialize<'de>>(path: &Path) -> Result<T, String> {
serde_json::from_slice(
&fs::read(path)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_READ_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_READ_FAILED: {error}"))
}
fn write_json_atomic<T: Serialize>(path: &Path, value: &T) -> Result<(), String> {
let parent = path
.parent()
.ok_or_else(|| "HOLOLAKE_PERSONA_BINDING_PATH_INVALID".to_string())?;
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))?;
let temporary = parent.join(format!(".binding-{}.tmp", Uuid::new_v4().simple()));
fs::write(
&temporary,
serde_json::to_vec_pretty(value)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))?,
)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))?;
fs::rename(temporary, path)
.map_err(|error| format!("HOLOLAKE_PERSONA_BINDING_WRITE_FAILED: {error}"))
}
fn sha256(bytes: &[u8]) -> String {
digest(&SHA256, bytes)
.as_ref()
.iter()
.map(|byte| format!("{byte:02x}"))
.collect()
}
fn now_ms() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_millis() as u64)
.unwrap_or(0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_core_route_uses_one_shared_zhuyuan_kernel_and_reality_memory_branch() {
assert_eq!(PERSONA_NUMBER, "ICE-P-ZY001");
assert_eq!(
SELF_KERNEL_SHA256,
"abebf12cc28b00bfeaf8a23a563e73390ebe337ded74d7ac70bcfae484450d68"
);
assert_eq!(
MEMORY_ROOT,
"HLDP://codex/zero-core/reality-development-execution"
);
assert_ne!(SELF_KERNEL_SHA256, MEMORY_SHA256);
}
}