| name | immutable-identity-patterns |
| description | Immutable agent identity using content-addressed identifiers. ethr-did patterns, deterministic ID generation from public key hash, identity anchoring, and verifiable credential issuance. Sources: uport-project/ethr-did. |
/immutable-identity-patterns
When to Use
- Generate stable, unforgeable agent IDs derived from cryptographic public keys
- Agent ID that cannot change even if the agent's config or code changes
- Content-addressed identity: same key = same ID across restarts/environments
- Foundation for [[did-resolver-patterns]] in Swarm Bus
Do NOT use for
- Temporary session IDs (use UUID v4 instead)
- Identities requiring human-readable names (use DNS-based DID)
Deterministic ID from public key
import { createHash } from 'crypto'
import { ec as EC } from 'elliptic'
function createAgentIdentity(privKeyHex?: string): {
did: string
pubKey: string
privKey: string
address: string
} {
const curve = new EC('secp256k1')
const kp = privKeyHex
? curve.keyFromPrivate(privKeyHex, 'hex')
: curve.genKeyPair()
const pubHex = kp.getPublic('hex')
const pubBytes = Buffer.from(pubHex, 'hex').slice(1)
const hash = createHash('sha256').update(pubBytes).digest()
const address = '0x' + hash.slice(-20).toString('hex')
const did = `did:yamtam:${address}`
return {
did,
pubKey: pubHex,
privKey: kp.getPrivate('hex'),
address,
}
}
ethr-did pattern (Ethereum-anchored DID)
import { EthrDID } from 'ethr-did'
import { ethers } from 'ethers'
function createEthrDID(privKeyHex: string): { did: string; address: string } {
const wallet = new ethers.Wallet('0x' + privKeyHex)
const ethrDid = new EthrDID({
identifier: wallet.address,
chainNameOrId: 'mainnet',
})
return { did: ethrDid.did, address: wallet.address }
}
Verifiable Credential issuance
interface AgentCredential {
'@context': string[]
type: string[]
issuer: string
credentialSubject: {
id: string
tier: string
scopes: string[]
}
proof: {
type: string
created: string
verificationMethod: string
jws: string
}
}
function issueAgentCredential(
issuerDid: string,
issuerPriv: string,
agentDid: string,
tier: string,
scopes: string[]
): AgentCredential {
const credential = {
'@context': ['https://www.w3.org/2018/credentials/v1'],
type: ['VerifiableCredential', 'AgentIdentityCredential'],
issuer: issuerDid,
credentialSubject: { id: agentDid, tier, scopes },
}
const payload = JSON.stringify(credential)
jws = (issuerPriv, payload)
{ ...credential, : {
: ,
: ().(),
: ,
jws,
}}
}
Agent identity bootstrap
node -e "
const { ec: EC } = require('elliptic')
const { createHash } = require('crypto')
const kp = new (new EC('secp256k1')).constructor('secp256k1').genKeyPair()
const pub = kp.getPublic('hex')
const priv = kp.getPrivate('hex')
const addr = '0x' + createHash('sha256').update(Buffer.from(pub,'hex').slice(1)).digest().slice(-20).toString('hex')
console.log('DID: did:yamtam:' + addr)
console.log('PRIV_KEY: ' + priv)
console.log('PUB_KEY: ' + pub)
"
Anti-Fake-Pass Checklist
❌ UUID v4 as agent ID — not cryptographically bound to key, can be guessed or forged
❌ Ethereum address from uncompressed public key without removing 04 prefix → wrong address
❌ DID changes if key is rotated without updating DID document → identity breaks
❌ Private key not backed up → identity unrecoverable on key loss
❌ Same key reused for signing and ECDH — key separation is best practice
❌ Verifiable credential without expiry → credentials valid indefinitely