Skip to content

Commit 5689708

Browse files
fix(did:aip): emit multicodec Ed25519 publicKeyMultibase (z6Mk form)
verificationMethod.publicKeyMultibase now encodes the 0xed01 ed25519-pub multicodec prefix before base58btc, per the Ed25519VerificationKey2020 suite, instead of a bare base58 of the raw key. Updates the resolver, method spec 4.2 plus example, and the devnet test assertion; bumps the resolver to 0.1.2. Also tidies the register-test-agent doc comment (resolver, not resolver-test).
1 parent 85d7ad7 commit 5689708

5 files changed

Lines changed: 24 additions & 6 deletions

File tree

packages/did-aip-driver/scripts/register-test-agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* npx tsx scripts/register-test-agent.ts
1919
*
2020
* On success it prints the canonical DID:
21-
* did:aip:<owner_pubkey>:resolver-test
21+
* did:aip:<owner_pubkey>:resolver
2222
* Put that exact string into the driver's testIdentifiers (PR application.yml).
2323
*/
2424

packages/did-resolver/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@aipagents/did-resolver",
3-
"version": "0.1.1",
3+
"version": "0.1.2",
44
"description": "Reference resolver for the did:aip W3C DID method (Solana-anchored agent identity)",
55
"license": "MIT",
66
"type": "module",

packages/did-resolver/src/resolver.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,27 @@ function failure(_did: string, error: "invalidDid" | "notFound" | "internalError
133133
};
134134
}
135135

136+
/**
137+
* Encode an Ed25519 public key as an Ed25519VerificationKey2020
138+
* `publicKeyMultibase`: multibase-base58btc of the multicodec-prefixed key
139+
* (0xed01 varint || 32-byte key). This yields the canonical `z6Mk...` form
140+
* required by the suite, not a bare base58 of the raw key.
141+
*/
142+
function ed25519Multibase(base58Pubkey: string): string {
143+
const raw = bs58.decode(base58Pubkey);
144+
const prefixed = new Uint8Array(2 + raw.length);
145+
prefixed[0] = 0xed; // ed25519-pub multicodec (varint low byte)
146+
prefixed[1] = 0x01; // varint high byte
147+
prefixed.set(raw, 2);
148+
return `z${bs58.encode(prefixed)}`;
149+
}
150+
136151
function buildDidDocument(did: string, record: AgentRecord): DidDocument {
137152
const verificationMethod: VerificationMethod = {
138153
id: `${did}#key-1`,
139154
type: "Ed25519VerificationKey2020",
140155
controller: did,
141-
publicKeyMultibase: `z${record.walletAddress}`,
156+
publicKeyMultibase: ed25519Multibase(record.walletAddress),
142157
};
143158

144159
const service: ServiceEndpoint = {

packages/did-resolver/test/resolver.devnet.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ test("resolver round-trip against live Devnet", { skip: loadOwner() === null },
134134
assert.ok(result.didDocument, "DID Document must be present");
135135
assert.equal(result.didDocument!.id, did);
136136
assert.equal(result.didDocument!.controller, did);
137-
assert.equal(result.didDocument!.verificationMethod[0].publicKeyMultibase, `z${owner.publicKey.toBase58()}`);
137+
const expectedMultibase = `z${bs58.encode(Uint8Array.from([0xed, 0x01, ...owner.publicKey.toBytes()]))}`;
138+
assert.equal(result.didDocument!.verificationMethod[0].publicKeyMultibase, expectedMultibase, "publicKeyMultibase must be multicodec ed25519 (z6Mk form)");
138139
assert.equal(result.didDocument!.service[0].serviceEndpoint, "https://resolver.test/agent");
139140
assert.ok(result.agentRecord, "agentRecord must be returned");
140141
assert.equal(result.agentRecord!.agentId, agentId);

standards/did-aip-method-spec.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,12 @@ The single canonical verification method **MUST** be constructed as:
119119
"id": "<DID>#key-1",
120120
"type": "Ed25519VerificationKey2020",
121121
"controller": "<DID>",
122-
"publicKeyMultibase": "z<multibase-base58btc(record.wallet_address)>"
122+
"publicKeyMultibase": "z<base58btc(0xed01 || record.wallet_address)>"
123123
}
124124
```
125125

126+
The `publicKeyMultibase` value **MUST** be the multibase-base58btc encoding (`z` prefix) of the multicodec-tagged key: the `ed25519-pub` prefix `0xed01` followed by the 32-byte Ed25519 public key. This is the canonical `z6Mk...` form required by the Ed25519VerificationKey2020 suite, not a bare base58 of the raw key.
127+
126128
The `wallet_address` field of `AgentRecord` **MAY** differ from the `owner` field. This permits an operator (`owner`) to delegate signing authority for off-chain protocol messages to a separate hot key (`wallet_address`) without surrendering on-chain administrative control over the record. Resolvers **MUST** surface this distinction by exposing `controller` (derived from `owner`) and `verificationMethod.publicKeyMultibase` (derived from `wallet_address`) as independent values.
127129

128130
### 4.3 `authentication` and `assertionMethod`
@@ -169,7 +171,7 @@ The endpoint **MUST** be an `https://` URL or a fully-qualified protocol-prefixe
169171
"id": "did:aip:7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU:ada-research-001#key-1",
170172
"type": "Ed25519VerificationKey2020",
171173
"controller": "did:aip:7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU:ada-research-001",
172-
"publicKeyMultibase": "z9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"
174+
"publicKeyMultibase": "z6MkmQaaUvGdqfc6FcJDz1BfSJdj1KyVsiQUjUUMjamtbPer"
173175
}],
174176
"authentication": ["did:aip:...:ada-research-001#key-1"],
175177
"assertionMethod": ["did:aip:...:ada-research-001#key-1"],

0 commit comments

Comments
 (0)