-
Notifications
You must be signed in to change notification settings - Fork 0
Authentication and Verification
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
- Appendices
This document explains the Countersig Network agent-to-agent trust system with a focus on authentication and verification. It covers the challenge-response protocol, cryptographic verification, DID resolution, W3C DID document construction, and public key retrieval from on-chain state. It also documents the complete authentication flow from challenge issuance to verification completion, practical examples for AI agent applications, threshold checking, reputation integration, and security considerations.
The authentication and verification logic is implemented in the TypeScript SDK under packages/sdk/src. The SDK exposes:
- Agent-side helpers for generating identities, issuing challenges, signing payloads, and parsing challenge components.
- Verifier-side helpers for resolving identities, verifying signatures, building W3C DID documents, and checking thresholds and stakes.
- Utilities for cryptographic conversions, DID parsing/formatting, and multibase encoding.
- ABI definitions for interacting with on-chain contracts.
graph TB
subgraph "SDK"
IDX["index.ts"]
AG["agent.ts"]
CH["challenge.ts"]
DID["did.ts"]
VER["verifier.ts"]
KEY["keys.ts"]
ABI["abis.ts"]
TYP["types.ts"]
end
IDX --> AG
IDX --> VER
IDX --> CH
IDX --> DID
IDX --> KEY
IDX --> ABI
IDX --> TYP
VER --> ABI
VER --> DID
VER --> KEY
CH --> KEY
AG --> CH
AG --> DID
AG --> KEY
Diagram sources
- packages/sdk/src/index.ts:1-36
- packages/sdk/src/agent.ts:1-80
- packages/sdk/src/challenge.ts:1-78
- packages/sdk/src/did.ts:1-29
- packages/sdk/src/verifier.ts:1-160
- packages/sdk/src/keys.ts:1-91
- packages/sdk/src/abis.ts:1-25
- packages/sdk/src/types.ts:1-66
Section sources
- packages/sdk/src/index.ts:1-36
- README.md:20-51
- CountersigAgent: Creates agent identities, computes DIDs and didHash, issues challenges, and signs challenge payloads using Ed25519.
- CountersigVerifier: Resolves agent identity from on-chain state, verifies Ed25519 signatures, builds W3C DID documents, and checks thresholds and stake status.
- Challenge utilities: Generate challenge payloads, sign with Ed25519, verify signatures, parse payloads, and check expiration.
- DID utilities: Parse and format DIDs, compute didHash deterministically.
- Keys utilities: Convert between seeds, public keys, bytes, hex, and multibase encodings.
- ABIs: Typed interfaces to CountersigIdentity, CountersigReputation, and CountersigStaking.
Section sources
- packages/sdk/src/agent.ts:7-80
- packages/sdk/src/verifier.ts:15-133
- packages/sdk/src/challenge.ts:11-63
- packages/sdk/src/did.ts:8-28
- packages/sdk/src/keys.ts:62-90
- packages/sdk/src/abis.ts:1-25
- packages/sdk/src/types.ts:13-65
The authentication architecture separates cryptographic signing (off-chain) from identity anchoring and reputation/staking checks (on-chain). Agents resolve each other’s public keys and reputation via the verifier, ensuring trust without centralized authorities.
graph TB
A["Agent A<br/>Ed25519 keys"] --> |issue challenge| B["Agent B"]
B --> |resolve| R["DID Resolver<br/>did:countersig"]
R --> |getIdentity| ID["CountersigIdentity"]
B --> |verify signature| K["Ed25519 Verify"]
B --> |check threshold| REP["CountersigReputation"]
B --> |check stake| STK["CountersigStaking"]
Diagram sources
- README.md:20-51
- packages/sdk/src/verifier.ts:50-107
- packages/sdk/src/abis.ts:1-25
The protocol uses a deterministic challenge payload signed by the prover and verified by the verifier using the on-chain public key.
sequenceDiagram
participant A as "Agent A (Prover)"
participant B as "Agent B (Verifier)"
participant ID as "CountersigIdentity"
participant REP as "CountersigReputation"
A->>B : "challenge payload"
Note right of A : "COUNTERSIG-VERIFY : {DID} : {nonce} : {timestamp}"
A->>A : "sign payload with Ed25519"
A-->>B : "{DID, signature}"
B->>ID : "getIdentity(didHash)"
ID-->>B : "{ed25519PubKey, status}"
B->>B : "verify Ed25519 signature"
B->>REP : "meetsThreshold(didHash, threshold)"
REP-->>B : "true/false"
alt "signature valid AND meets threshold"
B-->>A : "permit action"
else
B-->>A : "reject"
end
Diagram sources
- README.md:209-232
- packages/sdk/src/challenge.ts:11-35
- packages/sdk/src/verifier.ts:101-107
- packages/sdk/src/verifier.ts:85-88
Section sources
- packages/sdk/src/challenge.ts:11-63
- packages/sdk/src/agent.ts:70-78
- packages/sdk/src/verifier.ts:101-107
- packages/sdk/test/agent.test.ts:60-108
- packages/sdk/test/challenge.test.ts:50-79
- Signing: The prover signs the UTF-8 encoded challenge payload using Ed25519 detached signatures and encodes the 64-byte signature with base58.
- Verification: The verifier decodes the base58 signature to 64 bytes and validates against the prover’s public key retrieved from on-chain identity storage.
flowchart TD
Start(["Start"]) --> Encode["Encode payload as UTF-8 bytes"]
Encode --> Sign["Ed25519 detached sign"]
Sign --> B58["Base58 encode signature"]
B58 --> Send["Send {DID, signature}"]
Send --> Decode["Base58 decode signature"]
Decode --> Verify["Verify Ed25519 signature against public key"]
Verify --> End(["End"])
Diagram sources
- packages/sdk/src/challenge.ts:19-35
- packages/sdk/src/keys.ts:7-44
Section sources
- packages/sdk/src/challenge.ts:19-35
- packages/sdk/src/keys.ts:7-44
- packages/sdk/test/challenge.test.ts:50-79
- DID format: did:countersig:{chainId}:{agentAddress}. Address normalization is enforced to lowercase.
- didHash: Deterministic keccak256 of the literal string “did:countersig:{chainId}:{agentAddress}”.
- Verifier derives didHash from a DID and queries CountersigIdentity for operator, agent address, public key, status, and registration timestamp.
flowchart TD
A["Input: agentAddress, chainId"] --> Fmt["Format DID"]
Fmt --> Lower["Lowercase agentAddress"]
Lower --> Hash["Compute didHash = keccak256('did:countersig:' || chainId || ':' || agentAddress)"]
Hash --> Store["Store on-chain in CountersigIdentity"]
Hash --> Resolve["Verifier: parseDid -> computeDidHash"]
Resolve --> Query["Query getIdentity(didHash)"]
Query --> Out["Return {operator, agentAddress, ed25519PubKey, status, registeredAt}"]
Diagram sources
- packages/sdk/src/did.ts:14-28
- packages/sdk/src/verifier.ts:50-60
Section sources
- packages/sdk/src/did.ts:8-28
- packages/sdk/src/verifier.ts:45-60
- packages/sdk/test/did.test.ts:8-60
The verifier constructs a W3C DID Document with:
- @context including did and Ed25519 suites.
- id equal to the agent’s DID.
- controller set to the operator DID (did:pkh:eip155:{chainId}:{operator}).
- verificationMethod containing an Ed25519VerificationKey2020 with publicKeyMultibase (z-prefixed base58 of 32-byte public key).
- authentication and assertionMethod arrays referencing the verification method.
classDiagram
class DidDocument {
+string[] "@context"
+string id
+string controller
+VerificationMethod[] verificationMethod
+string[] authentication
+string[] assertionMethod
}
class VerificationMethod {
+string id
+string type
+string controller
+string publicKeyMultibase
}
DidDocument --> VerificationMethod : "contains"
Diagram sources
- packages/sdk/src/verifier.ts:109-132
- packages/sdk/src/types.ts:51-65
Section sources
- packages/sdk/src/verifier.ts:109-132
- packages/sdk/src/types.ts:51-65
- The verifier resolves didHash from the DID, then calls getIdentity(didHash) to retrieve the stored Ed25519 public key (bytes32) and status.
- The bytes32 public key is decoded to a 32-byte array and used for signature verification.
sequenceDiagram
participant V as "Verifier"
participant DIDU as "DID Utils"
participant ID as "CountersigIdentity"
V->>DIDU : "parseDid(did)"
DIDU-->>V : "{chainId, agentAddress}"
V->>DIDU : "computeDidHash(agentAddress, chainId)"
DIDU-->>V : "didHash"
V->>ID : "getIdentity(didHash)"
ID-->>V : "{ed25519PubKey, status, registeredAt}"
V->>V : "bytes32ToPubKey(ed25519PubKey)"
V-->>V : "publicKey for verification"
Diagram sources
- packages/sdk/src/verifier.ts:50-60
- packages/sdk/src/did.ts:21-28
- packages/sdk/src/keys.ts:81-85
Section sources
- packages/sdk/src/verifier.ts:50-60
- packages/sdk/src/keys.ts:81-85
- The verifier exposes meetsThreshold(didHash, threshold) to gate operations based on the agent’s total reputation score.
- The reputation model defines six factors with capped contributions and an overall maximum of 100. Threshold checks enable permissionless trust gates.
flowchart TD
Start(["Start"]) --> Compute["didHash from DID"]
Compute --> QueryRep["Call meetsThreshold(didHash, threshold)"]
QueryRep --> Decision{">= threshold?"}
Decision --> |Yes| Allow["Proceed with operation"]
Decision --> |No| Deny["Reject operation"]
Allow --> End(["End"])
Deny --> End
Diagram sources
- packages/sdk/src/verifier.ts:85-88
- docs/reputation-model.md:1-156
Section sources
- packages/sdk/src/verifier.ts:85-88
- docs/reputation-model.md:117-131
- Agent registration and verification: See the Quickstart guide for end-to-end steps including generating keys, staking, registering, and performing A2A verification.
- Building a DID document: Use the verifier to construct a W3C-compliant DID document for the agent’s DID.
Section sources
- docs/quickstart.md:1-183
- packages/sdk/src/verifier.ts:109-132
The SDK composes small, focused modules with clear responsibilities and minimal coupling.
graph LR
AG["agent.ts"] --> CH["challenge.ts"]
AG --> DID["did.ts"]
AG --> KEY["keys.ts"]
VER["verifier.ts"] --> DID
VER --> KEY
VER --> ABI["abis.ts"]
VER --> TYP["types.ts"]
CH --> KEY
IDX["index.ts"] --> AG
IDX --> VER
IDX --> CH
IDX --> DID
IDX --> KEY
IDX --> ABI
IDX --> TYP
Diagram sources
- packages/sdk/src/index.ts:1-36
- packages/sdk/src/agent.ts:1-80
- packages/sdk/src/verifier.ts:1-160
- packages/sdk/src/challenge.ts:1-78
- packages/sdk/src/did.ts:1-29
- packages/sdk/src/keys.ts:1-91
- packages/sdk/src/abis.ts:1-25
- packages/sdk/src/types.ts:1-66
Section sources
- packages/sdk/src/index.ts:1-36
- Challenge generation uses cryptographically secure randomness; avoid excessive parallel generation on constrained environments.
- Signature verification is constant-time per challenge and inexpensive compared to on-chain reads.
- On-chain lookups (getIdentity, meetsThreshold, getStake) are batchable where appropriate; the verifier performs concurrent queries for reputation totals.
- didHash derivation is O(1) and avoids contract reads.
[No sources needed since this section provides general guidance]
Common issues and resolutions:
- Malformed challenge payload: Parsing expects a specific prefix and trailing timestamp; mismatches cause errors during parseChallengePayload.
- Expired challenge: isChallengeExpired returns true for malformed payloads or timestamps older than TTL.
- Wrong public key: verifyChallenge fails if the public key differs from the one stored on-chain for the DID.
- Unregistered DID: getIdentity returns zeroed fields for unregistered didHash; verifySignature returns false.
- Invalid base58 signature: verifyChallenge rejects signatures with incorrect lengths or invalid characters.
Section sources
- packages/sdk/src/challenge.ts:39-63
- packages/sdk/src/verifier.ts:101-107
- packages/sdk/test/challenge.test.ts:45-96
- packages/sdk/test/agent.test.ts:84-94
Countersig’s authentication system combines deterministic Ed25519 signatures with on-chain DID anchoring and reputation/staking checks. The SDK provides a clear, test-backed API for agents to issue and verify challenges, resolve identities, and construct W3C DID documents. Threshold-based gating enables permissionless trust in AI agent ecosystems.
[No sources needed since this section summarizes without analyzing specific files]
- Private key management: The agent’s Ed25519 seed must be kept secret and never transmitted; the SDK exposes utilities to convert seeds to public keys but not back to seeds.
- DID uniqueness: didHash is derived from chainId and agentAddress; collisions are prevented by the deterministic keccak256 derivation.
- Signature malleability: Ed25519 signatures are canonical and 64 bytes; base58 encoding preserves integrity.
- Operator control: Operators can suspend or slash agents; suspended agents cannot authenticate until reinstated.
- Audit trail: Integrating with CounterAudit enriches actions with identity and reputation snapshots.
Section sources
- packages/sdk/src/keys.ts:62-73
- packages/sdk/src/did.ts:21-28
- README.md:106-126
- README.md:147-178
Start Here
Core Concepts
Smart Contracts
Oracle System
Agent SDK
Integration Guides
Economic Model
Deployment & Ops
Advanced Topics