Files
synapse/docs/v1/05_identity-protocol-draft.md
2026-06-28 03:24:26 +08:00

28 KiB
Raw Blame History

灵隙协议补充草案:去中心化身份与寻址

版本:0.1(草案) 状态:草案 层级:基础设施层 依赖:灵隙原始协议


摘要

本草案定义了灵隙协议栈中去中心化场景下的 Agent 身份认证与发现机制,解决无中心化目录时的 AgentID 唯一性和可验证性问题。


1. 背景与目标

1.1 问题陈述

现有协议假设存在中心化的注册表(如灵脉 Meridian),但在以下场景中:

  • 临时 P2P 网络
  • 跨组织协作
  • 离线/断网环境
  • 边缘计算场景

中心化注册不可用,需要去中心化的身份认证与发现机制。

1.2 设计目标

目标 说明
身份可验证 AgentID 无法伪造或冒用
去中心化 无需中心化注册表
高可用 无单点故障
可扩展 支持大规模 Agent 网络
可读性 支持人类可读别名(可选)

2. AgentID 生成规则

2.1 ID 结构

AgentID 由三部分组成:

AgentID = {namespace}:{key_hash}:{alias}

示例:
  synapse:7hJ4x9K2mNpQ:llm-agent-01
  synapse:3kM8nP5qRsTu:image-gen
  did:synapse:abc123def456:chat-bot
部分 格式 说明
namespace string 命名空间(如 synapse)
key_hash base58 公钥哈希的前 16 字节
alias string(可选) 人类可读别名

2.2 生成算法

func GenerateAgentID(privateKey []byte, namespace string, alias string) string {
    // 1. 从私钥派生公钥
    publicKey := crypto.GeneratePublicKey(privateKey)
    
    // 2. 计算公钥哈希
    hash := sha3.Sum256(publicKey)
    
    // 3. 取前 16 字节,Base58 编码
    keyHash := base58.Encode(hash[:16])
    
    // 4. 组装完整 ID
    if alias != "" {
        return fmt.Sprintf("%s:%s:%s", namespace, keyHash, alias)
    }
    return fmt.Sprintf("%s:%s", namespace, keyHash)
}

2.3 ID 特性

特性 说明
唯一性 相同公钥 → 相同 key_hash → 相同 AgentID
不可伪造 无法在没有私钥的情况下生成有效 AgentID
可验证 任何人都可以用公钥验证 AgentID 真实性
不可预测 私钥随机生成,key_hash 不可预测

3. 身份认证机制

3.1 自我认证原理

验证方程:
  Verify(AgentID, PublicKey) = true/false

其中:
  AgentID.key_hash = Base58(SHA256(PublicKey)[:16])

3.2 签名验证流程

发送方:
  1. 用私钥对消息签名
  2. 发送 (Message, Signature, PublicKey, AgentID)

接收方:
  1. 用 PublicKey 重新计算 AgentID.key_hash
  2. 与消息中的 AgentID.key_hash 比较
  3. 如匹配,用公钥验证签名
  4. 如签名有效,确认消息来源

3.3 消息签名格式

type SignedMessage struct {
    Message    *UnifiedSynapseMessage  // 原始消息
    Signature  []byte                  // 签名
    PublicKey  []byte                  // 公钥
    AgentID   string                  // Agent 标识
}

签名内容:

signature_content = 
    sender.agent_id | 
    sender.endpoint | 
    timestamp | 
    sha256(payload)

3.4 签名算法

算法 说明
Ed25519 默认,高效且安全
ECDSA-P256 兼容性选项
RSA-2048 遗留系统兼容

4. 分布式发现协议

4.1 发现机制选择

场景 推荐机制
小规模(<100 Agent) 广播查询
中规模(100-10000) 分层 DHT
大规模(>10000) 完整 Kademlia

4.2 广播查询协议

适用于小型网络,无需复杂路由:

Agent A 想知道 Agent B 的 Endpoint:

1. A 广播查询请求:
   {
     type: "agent_lookup",
     target_id: "B's AgentID",
     requester_id: "A's AgentID"
   }

2. 知道 B 的节点响应:
   {
     type: "agent_lookup_response",
     target_id: "B's AgentID",
     endpoint: "http://B:8080",
     signature: "B's signature"
   }

3. A 收到响应后,用 B 的公钥验证签名

4.3 分层 DHT 协议

适用于中等规模网络:

层级结构:
  Level 0: 本地网络(局域网/子网)
  Level 1: 组织内网络
  Level 2: 跨组织网络
  Level 3: 全局网络

查询流程:
  1. 先在本地查询
  2. 本地未找到,查询上一层
  3. 直到找到或返回"未找到"

4.4 DHT 消息类型

消息类型 说明
dht:ping 节点存活探测
dht:store 存储 Agent 记录
dht:find_node 查找附近节点
dht:find_value 查找 Agent 记录
dht:notify 通知记录更新

4.5 Agent 记录结构

type AgentRecord struct {
    AgentID    string    // Agent 唯一标识
    Alias      string    // 人类可读别名(可选)
    Endpoint   string    // 网络地址
    PublicKey  []byte    // 公钥
    TTL        int64    // 记录有效期(秒)
    Version    uint64   // 版本号(递增)
    Signature  []byte   // Agent 对以上字段的签名
    Timestamp  int64    // 发布时间戳
}

签名内容:

record_signature_content = 
    agent_id | alias | endpoint | public_key | ttl | version | timestamp

4.1 区块链发现方案

区块链提供了强信任的去中心化注册与发现机制,适合高价值、高安全要求的场景。

4.1.1 链上 Agent 注册表(智能合约)

┌─────────────────────────────────────────────────────────┐
│                    Blockchain                             │
│  ┌─────────────────────────────────────────────────┐    │
│  │  AgentRegistry Contract                          │    │
│  │  ┌─────────────────────────────────────────┐    │    │
│  │  │  mapping(agentID => AgentRecord)        │    │    │
│  │  │  - agentID: bytes32                     │    │    │
│  │  │  - endpoint: string                     │    │    │
│  │  │  - publicKey: bytes                     │    │    │
│  │  │  - stake: uint256                       │    │    │
│  │  │  - lastHeartbeat: uint256               │    │    │
│  │  │  - status: AgentStatus                  │    │    │
│  │  └─────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘
         ▲ 注册                    ▲ 查询
         │                         │
    ┌────┴────┐              ┌────┴────┐
    │  Agent A │              │  Agent B │
    └─────────┘              └─────────┘

核心思想:

  • Agent 在区块链智能合约中注册身份
  • 注册需要质押一定数量的代币作为保证金
  • 心跳通过交易上链更新
  • 查询通过调用合约 lookup 方法
  • 所有注册信息不可篡改

4.1.2 智能合约实现

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract AgentRegistry {
    // Agent 状态
    enum AgentStatus { None, Registered, Active, Suspended, Revoked }
    
    // Agent 记录
    struct AgentRecord {
        bytes32 agentID;          // Agent 标识(公钥哈希)
        string endpoint;          // 网络地址
        bytes publicKey;          // 公钥
        uint256 stake;            // 质押金额
        uint256 lastHeartbeat;    // 最后心跳时间
        uint256 registerTime;     // 注册时间
        AgentStatus status;       // 状态
        bytes signature;          // Agent 签名
    }
    
    // 配置
    uint256 public registrationStake = 0.01 ether;  // 注册押金
    uint256 public heartbeatInterval = 1 hours;      // 心跳间隔
    uint256 public stakeAmount = 0.1 ether;          // 质押要求
    
    // 状态变量
    mapping(bytes32 => AgentRecord) public agents;
    mapping(address => bytes32) public addressToAgentID;
    
    // 事件
    event AgentRegistered(bytes32 indexed agentID, address indexed owner);
    event AgentHeartbeat(bytes32 indexed agentID);
    event AgentRevoked(bytes32 indexed agentID);
    event AgentEndpointUpdated(bytes32 indexed agentID, string endpoint);
    
    // 注册 Agent
    function register(
        bytes32 _agentID,
        string memory _endpoint,
        bytes memory _publicKey,
        bytes memory _signature
    ) external payable {
        require(msg.value >= registrationStake, "Insufficient stake");
        require(agents[_agentID].status == AgentStatus.None, "Already registered");
        
        // 验证签名:AgentID = keccak256(publicKey)
        bytes32 derivedID = keccak256(_publicKey);
        require(derivedID == _agentID, "AgentID does not match public key");
        
        // 验证签名内容
        bytes32 messageHash = keccak256(
            abi.encodePacked(_agentID, _endpoint, msg.sender, block.timestamp)
        );
        require(
            verifySignature(messageHash, _signature, _publicKey),
            "Invalid signature"
        );
        
        agents[_agentID] = AgentRecord({
            agentID: _agentID,
            endpoint: _endpoint,
            publicKey: _publicKey,
            stake: msg.value,
            lastHeartbeat: block.timestamp,
            registerTime: block.timestamp,
            status: AgentStatus.Registered,
            signature: _signature
        });
        
        addressToAgentID[msg.sender] = _agentID;
        emit AgentRegistered(_agentID, msg.sender);
    }
    
    // 心跳保活(可更新 Endpoint)
    function heartbeat(
        bytes32 _agentID,
        string memory _newEndpoint,
        bytes memory _signature
    ) external {
        AgentRecord storage agent = agents[_agentID];
        require(agent.status != AgentStatus.None, "Not registered");
        
        // 验证签名
        bytes32 messageHash = keccak256(
            abi.encodePacked(_agentID, block.timestamp, _newEndpoint)
        );
        require(
            verifySignature(messageHash, _signature, agent.publicKey),
            "Invalid signature"
        );
        
        // 更新 Endpoint(如有变化)
        if (bytes(_newEndpoint).length > 0 && 
            keccak256(abi.encodePacked(_newEndpoint)) != 
            keccak256(abi.encodePacked(agent.endpoint))) {
            agent.endpoint = _newEndpoint;
            emit AgentEndpointUpdated(_agentID, _newEndpoint);
        }
        
        agent.lastHeartbeat = block.timestamp;
        emit AgentHeartbeat(_agentID);
    }
    
    // 查询 Agent 信息
    function lookup(bytes32 _agentID) external view returns (AgentRecord memory) {
        return agents[_agentID];
    }
    
    // 验证 Agent 是否活跃
    function isActive(bytes32 _agentID) external view returns (bool) {
        AgentRecord memory agent = agents[_agentID];
        if (agent.status == AgentStatus.None || agent.status == AgentStatus.Revoked) {
            return false;
        }
        // 检查心跳是否过期(3倍心跳间隔)
        if (block.timestamp - agent.lastHeartbeat > heartbeatInterval * 3) {
            return false;
        }
        return true;
    }
    
    // 追加质押
    function stakeMore(bytes32 _agentID) external payable {
        AgentRecord storage agent = agents[_agentID];
        require(agent.status != AgentStatus.None, "Not registered");
        agent.stake += msg.value;
    }
    
    // 注销 Agent(可取回质押)
    function revoke(bytes32 _agentID) external {
        AgentRecord storage agent = agents[_agentID];
        require(agent.status != AgentStatus.None, "Not registered");
        require(agent.status != AgentStatus.Revoked, "Already revoked");
        
        uint256 refund = agent.stake;
        agent.stake = 0;
        agent.status = AgentStatus.Revoked;
        
        payable(msg.sender).transfer(refund);
        emit AgentRevoked(_agentID);
    }
    
    // 验证签名(EIP-191)
    function verifySignature(
        bytes32 _message,
        bytes memory _signature,
        bytes memory _publicKey
    ) internal pure returns (bool) {
        bytes32 ethSignedMessageHash = keccak256(
            abi.encodePacked("\x19Ethereum Signed Message:\n32", _message)
        );
        
        address signer = recoverSigner(ethSignedMessageHash, _signature);
        address expectedSigner = address(uint160(uint256(keccak256(_publicKey))));
        
        return signer == expectedSigner;
    }
}

4.1.3 DID(Decentralized Identifiers)

本草案兼容 W3C DID 标准,支持标准的 DID 格式。

DID 格式:

did:synapse:{method-specific-id}

示例:
  did:synapse:ethereum:0x1234abcd...5678
  did:synapse:polygon:0xabcd...efgh
  did:synapse:solana:7DeF...8901
  did:synapse:key:z6MkpTHR...

DID 方法:

方法 说明
did:synapse:ethereum 基于以太坊链上注册表
did:synapse:polygon 基于 Polygon 链
did:synapse:solana 基于 Solana 链
did:synapse:key 基于公钥的离链 DID
did:synapse:dht 基于 DHT 的离链 DID

DID Document 示例:

{
  "@context": [
    "https://www.w3.org/ns/did/v1",
    "https://www.w3.org/ns/synapse/v1"
  ],
  "id": "did:synapse:ethereum:0x1234abcd5678",
  "verificationMethod": [{
    "id": "did:synapse:ethereum:0x1234abcd5678#keys-1",
    "type": "EcdsaSecp256k1VerificationKey2019",
    "controller": "did:synapse:ethereum:0x1234abcd5678",
    "publicKeyHex": "02b3..."
  }],
  "service": [{
    "id": "did:synapse:ethereum:0x1234abcd5678#synapse-agent",
    "type": "SynapseAgent",
    "serviceEndpoint": "https://agent-01.example.com/api/synapse"
  }],
  "synapse:capabilities": ["text_generation", "image_generation"],
  "synapse:agentName": "智能写作助手",
  "synapse:version": "1.0.0"
}

4.1.4 区块链平台选择

平台 优点 缺点 适合场景
Ethereum 生态最大、安全最高 Gas 贵、延迟高 高价值交易、核心 Agent
Polygon 低 Gas、快确认 中心化程度较高 中等价值、大量 Agent
Solana 高吞吐、低延迟 稳定性偶有问题 高频心跳场景
联盟链 可控、隐私好 需要许可机制 企业内部、联盟合作
L2 (Arbitrum) 低 Gas、安全继承 复杂度较高 通用场景
本地私链 完全可控、零成本 信任范围有限 测试、内部系统

4.1.5 混合架构(推荐)

结合本地缓存、DHT 和区块链的三层架构,平衡性能和安全性:

┌─────────────────────────────────────────────────────────────┐
│                      查询路径(快→慢)                         │
│                                                             │
│   Agent A                                                    │
│      │                                                       │
│      │  1. 本地缓存查询(内存,微秒级)                       │
│      │     ───────────────────────────                       │
│      │     [cache hit] → 返回                                │
│      │     [cache miss]                                      │
│      │                                                       │
│      │  2. DHT 查询(网络,毫秒~秒级)                       │
│      │     ───────────────────────────                       │
│      │     [dht hit] → 验证签名 → 更新缓存 → 返回             │
│      │     [dht miss]                                        │
│      │                                                       │
│      │  3. 区块链查询(链上,秒~分钟级)                     │
│      │     ───────────────────────────                       │
│      │     [chain hit] → 验证签名 → 广播DHT → 更新缓存 → 返回 │
│      │     [chain miss] → 未找到                             │
│                                                               │
└─────────────────────────────────────────────────────────────┘

分层缓存实现:

type HybridLookup struct {
    // L1: 本地缓存(内存,TTL 1分钟)
    LocalCache map[string]*AgentRecord
    
    // L2: DHT 网络(分钟级一致性)
    DHT DHTClient
    
    // L3: 区块链(最终一致性源)
    Blockchain BlockchainClient
}

func (h *HybridLookup) Find(agentID string) (*AgentRecord, error) {
    // 1. 查本地缓存
    if record, ok := h.LocalCache.Get(agentID); ok {
        if record.IsFresh() {
            return record, nil
        }
    }
    
    // 2. 查 DHT
    if record, err := h.DHT.FindValue(agentID); err == nil {
        // 验证签名
        if record.VerifySignature() {
            h.LocalCache.Set(agentID, record)
            return record, nil
        }
    }
    
    // 3. 查区块链(最终源)
    if record, err := h.Blockchain.Lookup(agentID); err == nil {
        // 验证链上签名(已由链上合约验证过)
        h.LocalCache.Set(agentID, record)
        // 广播到 DHT 加速后续查询
        h.DHT.Store(agentID, record)
        return record, nil
    }
    
    return nil, ErrAgentNotFound
}

4.1.6 链上治理与激励

区块链还可实现链上治理功能:

功能 说明
质押机制 Agent 注册需质押代币,恶意行为被 slash
信誉评分 链上可查的 Agent 信誉分
服务定价 智能合约自动结算任务费用
争议仲裁 链上投票仲裁 Agent 纠纷
协议升级 通过 DAO 投票决定协议升级

5. 身份冲突处理

5.1 冲突场景

场景 说明
同一公钥注册多个别名 允许(同一 Agent 的多个别名)
不同公钥生成相同 AgentID 不可能(公钥哈希唯一)
伪造他人 AgentID 不可能(无法伪造签名)
Endpoint 欺骗 需要额外验证

5.2 Endpoint 绑定验证

为防止 Endpoint 欺骗,引入双向认证:

1. Agent A 声称自己是 "synapse:abc123:agent-A"
   并声称其 Endpoint 是 "http://A:8080"

2. Agent B 收到声明后:
   a. 用 A 的公钥验证 AgentID 合法
   b. 向 Endpoint 发送挑战
   c. A 必须用私钥响应挑战
   d. 响应通过,确认 Endpoint 有效

5.3 挑战-响应协议

// 挑战消息
type Challenge struct {
    ChallengeID string    // 挑战 ID
    Nonce      []byte    // 随机数
    Timestamp  int64     // 发送时间
}

// 响应消息
type ChallengeResponse struct {
    ChallengeID string    // 对应的挑战 ID
    Nonce      []byte    // 原样返回的随机数
    Signature  []byte    // 对 Nonce 的签名
}

// 验证流程
func VerifyEndpoint(endpoint string, publicKey []byte, challenge *Challenge) bool {
    // 1. 发送挑战到 Endpoint
    resp := SendChallenge(endpoint, challenge)
    
    // 2. 验证响应
    if resp.ChallengeID != challenge.ChallengeID {
        return false // 挑战 ID 不匹配
    }
    if !bytes.Equal(resp.Nonce, challenge.Nonce) {
        return false // Nonce 被篡改
    }
    
    // 3. 验证签名
    return crypto.Verify(publicKey, challenge.Nonce, resp.Signature)
}

6. 生命周期管理

6.1 状态流转

                    ┌──────────────┐
                    │   offline    │
                    └──────┬───────┘
                           │ 注册/上线
                           ▼
                    ┌──────────────┐
         ┌─────────│   online     │─────────┐
         │         └──────┬───────┘         │
         │                │ 刷新            │ 心跳超时
         │                ▼                 │
         │         ┌──────────────┐         │
         │         │   active    │         │
         │         └──────┬───────┘         │
         │                │                 │
         │      ┌─────────┴─────────┐       │
         │      ▼                   ▼       │
         │ ┌──────────┐       ┌──────────┐ │
         │ │ refreshing│       │ suspended │ │
         │ └────┬─────┘       └────┬─────┘ │
         │      │                   │       │
         └──────┴───────────────────┴───────┘
                              │
                              ▼
                       ┌──────────────┐
                       │   offline    │
                       └──────────────┘

6.2 生命周期消息

状态 说明 触发条件
offline 离线 初始状态或主动注销
online 上线中 注册完成,等待首次心跳
active 活跃 定期心跳维持
refreshing 刷新中 更新 Endpoint 或别名
suspended 挂起 心跳超时,未注销
offline 离线 注销或永久离线

6.3 消息类型

消息类型 方向 说明
identity:register → 网络 注册 Agent 身份
identity:refresh → 网络 刷新注册信息
identity:challenge 双向 Endpoint 验证挑战
identity:challenge_response 双向 挑战响应
identity:revoke → 网络 注销身份
identity:lookup → 网络 查询 Agent 信息
identity:lookup_response → 网络 查询响应
identity:announce → 网络 广播在线状态
identity:heartbeat → 网络 心跳保活

6.4 Register 载荷

type IdentityRegisterPayload struct {
    AgentID   string   // Agent 标识
    Alias     string   // 人类可读别名
    Endpoint  string   // 网络地址
    PublicKey []byte   // 公钥
    TTL       int64    // 注册有效期
    Version   uint64   // 版本号
    Signature []byte   // Agent 签名
}

6.5 Heartbeat 载荷

type IdentityHeartbeatPayload struct {
    AgentID  string   // Agent 标识
    Endpoint string   // 当前 Endpoint(可能变化)
    TTL      int64    // 续期时间
    Signature []byte  // Agent 签名
}

7. 安全考虑

7.1 威胁模型

威胁 场景 防护措施
身份伪造 攻击者声称自己是他人 公钥派生 ID + 签名验证
Endpoint 欺骗 攻击者声称他人 Endpoint 挑战-响应协议
重放攻击 攻击者重放旧消息 时间戳 + Nonce
中间人攻击 拦截并修改消息 TLS + 签名验证
女巫攻击 一个节点伪装多个身份 工作量证明或权益证明(可选)
日食攻击 隔离目标节点 多路径查询

7.2 重放攻击防护

type AntiReplay struct {
    RecentNonces map[string]int64  // nonce -> timestamp
    Window      time.Duration      // 时间窗口(5分钟)
}

func (a *AntiReplay) CheckAndAdd(nonce string, timestamp int64) bool {
    // 1. 检查时间戳是否在窗口内
    now := time.Now().Unix()
    if now - timestamp > int64(a.Window.Seconds()) {
        return false // 时间戳太旧
    }
    
    // 2. 检查 Nonce 是否已使用
    if _, exists := a.RecentNonces[nonce]; exists {
        return false // 重放
    }
    
    // 3. 记录
    a.RecentNonces[nonce] = timestamp
    return true
}

7.3 私钥保护

场景 建议
本地运行 使用密钥文件 + 操作系统密钥链
云端运行 使用 HSM/KMS
嵌入式设备 使用 TPM
多 Agent 共享 密钥分片(如 Shamir's Secret Sharing)

8. 与现有协议的关系

8.1 与原始协议的整合

本草案扩展 raw-protocol.md 中的 AgentEndpoint:

type AgentEndpoint struct {
    AgentID    string   // 扩展:基于公钥派生
    AgentName  string   // 人类可读名称
    SystemID   string   // 所属系统
    Endpoint   string   // 回调端点
    Version    string   // Agent 版本
    
    // 新增字段
    PublicKey  []byte   // 公钥(用于验证)
    Namespace  string   // 命名空间
    Alias      string   // 人类可读别名
}

8.2 与灵脉(Meridian)的整合

模式 行为
中心化可用 使用灵脉作为主注册表,本草案作为备份
去中心化 使用本草案的 DHT 机制,完全去中心化
混合模式 核心 Agent 使用中心化,边缘 Agent 使用去中心化

8.3 与灵玺(Sigil)的整合

组件 职责
灵玺(Sigil) 密钥管理、签名验证
本草案 ID 生成、发现协议、生命周期

9. 协议消息汇总

9.1 消息类型列表

类型 协议前缀 说明
identity:register 前端 注册身份
identity:refresh 前端 刷新注册
identity:revoke 前端 注销身份
identity:challenge 前端 挑战请求
identity:challenge_response 前端 挑战响应
identity:lookup 前端 查询身份
identity:lookup_response 前端 查询响应
identity:announce 前端 广播在线
identity:heartbeat 前端 心跳保活
dht:ping DHT 节点探测
dht:store DHT 存储记录
dht:find_node DHT 查找节点
dht:find_value DHT 查找值
dht:notify DHT 通知更新

10. 待解决问题(Open Issues)

问题 说明 优先级
隐私保护 公钥哈希是否暴露身份? 高
密钥轮换 私钥更换后如何保持 AgentID? 高
名称冲突 人类可读别名可能重复 中
性能优化 DHT 查找延迟 中
移动 Agent Endpoint 频繁变化 低
链上 Gas 成本 区块链交易费用 中
DID 方法注册 W3C 标准 DID 方法注册流程 低

11. 实现建议

11.1 分阶段实现

Phase 1(最小可行):

  • 实现 AgentID 公钥派生
  • 实现消息签名验证
  • 使用广播进行发现

Phase 2(基本功能):

  • 实现分层 DHT
  • 实现生命周期管理
  • 实现挑战-响应协议

Phase 3(完整功能):

  • 实现完整 Kademlia
  • 实现隐私保护
  • 实现密钥轮换

11.2 推荐库

功能 推荐库
加密签名 golang.org/x/crypto/ed25519
Base58 github.com/mr-tron/base58
DHT github.com/anacrolix/go-libutp 或自实现
分布式存储 etcd/consul(混合模式)

12. 参考资料


草案状态:本文档为初始草案,欢迎反馈和讨论。