// node --test web/webrtc/attest.test.mjs // javascript/src/attest with secp256k1 from node:crypto (no npm deps): the live RFP vector, and // signatures OpenSSL verifies. The page injects @noble/curves instead. import assert from "node:assert/strict"; import { createECDH, createPrivateKey, createPublicKey, randomBytes, sign, verify } from "node:crypto"; import { test } from "node:test"; import { attestHost, attestationCid, didKey } from "../../../atlibs/javascript/src/attest/index.js"; const N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n; const b64u = (bytes) => Buffer.from(bytes).toString("base64url"); const big = (bytes) => BigInt(`0x${Buffer.from(bytes).toString("hex")}`); const jwk = (uncompressed, d) => ({ kty: "EC", crv: "secp256k1", x: b64u(uncompressed.subarray(1, 33)), y: b64u(uncompressed.subarray(33)), ...(d && { d: b64u(d) }) }); const uncompress = (publicKey) => createECDH("secp256k1").constructor.convertKey(publicKey, "secp256k1", undefined, undefined, "uncompressed"); // The slice of @noble/curves 2.x secp256k1 that attest uses: compact r||s, low-S, sha256 prehash. const secp256k1 = { utils: { randomSecretKey: () => new Uint8Array(randomBytes(32)) }, getPublicKey(secretKey, compressed) { const ecdh = createECDH("secp256k1"); ecdh.setPrivateKey(secretKey); return new Uint8Array(ecdh.getPublicKey(null, compressed ? "compressed" : "uncompressed")); }, sign(message, secretKey) { const key = createPrivateKey({ key: jwk(this.getPublicKey(secretKey, false), secretKey), format: "jwk" }); const rs = new Uint8Array(sign("sha256", message, { key, dsaEncoding: "ieee-p1363" })); const s = big(rs.subarray(32)); if (s > N / 2n) rs.set(Buffer.from((N - s).toString(16).padStart(64, "0"), "hex"), 32); return rs; }, }; const verifies = (signature, message, didkey) => { const publicKey = Buffer.from(base58decode(didkey.slice("did:key:z".length))).subarray(2); const key = createPublicKey({ key: jwk(uncompress(publicKey)), format: "jwk" }); return verify("sha256", message, { key, dsaEncoding: "ieee-p1363" }, Buffer.from(signature, "base64")); }; function base58decode(text) { let n = 0n; for (const c of text) n = n * 58n + BigInt("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".indexOf(c)); const hex = n.toString(16); return Buffer.from(hex.padStart(hex.length + (hex.length % 2), "0"), "hex"); } // The signed RFP the live bidders accepted (at://did:plc:lpfuqerea3deuoyrn7ojser4/com.publicdomainrelay.temp.market.rfp/3mzof3sr6ez2e). const RFP_REPO = "did:plc:lpfuqerea3deuoyrn7ojser4"; const RFP = { $type: "com.publicdomainrelay.temp.market.rfp", domain: "compute", payload: { cid: "bafyreigh3k4lw4txsk4ojkx3b3x7i32umdi26vmzo2vw3oxyxkfyfckvja", uri: "at://did:plc:lpfuqerea3deuoyrn7ojser4/com.publicdomainrelay.temp.compute.vm/3mzof3sah7v2t", $type: "com.atproto.repo.strongRef", }, policies: [ { cid: "bafyreigr27gkscq2otmv5xfmyx3t2s32ga63xcwp2amafubjyxfd4oky5y", uri: "at://did:plc:lpfuqerea3deuoyrn7ojser4/computer.socialweb.temp.policy.ghalite/3mzof3sjie32i", $type: "com.atproto.repo.strongRef", }, ], createdAt: "2026-11-06T22:02:10.263Z", signatures: [ { cid: "bafyreifxbegxhn5nds47mb74segtp75sdtm5iva45l7tphfykkeliax3ca", key: "did:key:zQ3shXLEhJWkcH5M1dceCTRkkPajiZ7sAxAbvPMLbtNSLLxaP", $type: "network.attested.signature", issuer: "did:plc:lpfuqerea3deuoyrn7ojser4", signature: { $bytes: "W1NmGCHM1MwpsXEgt2x8N4ZPpwFIunGzzAm5AxaqWoYelO+UH2zp8ZUitHRgv/4itLteOKEePEhvKF4OdLUS6g" }, }, ], }; test("the RFP the bidders accepted: same CID, and its signature verifies", async () => { const entry = RFP.signatures[0]; const { bytes, cid } = await attestationCid(RFP, entry, RFP_REPO); assert.equal(cid, entry.cid); assert.ok(verifies(entry.signature.$bytes, bytes, entry.key)); assert.notEqual((await attestationCid({ ...RFP, domain: "other" }, entry, RFP_REPO)).cid, entry.cid); assert.notEqual((await attestationCid(RFP, entry, "did:plc:other")).cid, entry.cid); }); test("attestHost: one stored key per DID, output = input + signatures, repository must be the session DID", async () => { const store = new Map(); const ctx = { settings: { get: async (k) => store.get(k), set: async (k, v) => store.set(k, v) } }; const attest = attestHost(ctx, secp256k1, RFP_REPO); const { key } = await attest({ repository: RFP_REPO }); assert.match(key, /^did:key:zQ3s/); assert.equal(key, didKey(secp256k1.getPublicKey(Buffer.from(store.get("attestKeys")[RFP_REPO], "hex"), true))); const { signatures: _, ...unsigned } = RFP; const out = await attest({ repository: RFP_REPO, record: unsigned }); assert.equal(out.key, key); const { signatures: [entry], ...rest } = out.record; assert.deepEqual(rest, unsigned); assert.deepEqual(Object.keys(entry).sort(), ["$type", "cid", "issuer", "key", "signature"]); assert.equal(entry.issuer, RFP_REPO); const { bytes, cid } = await attestationCid(out.record, entry, RFP_REPO); assert.equal(entry.cid, cid); assert.ok(verifies(entry.signature.$bytes, bytes, key)); assert.equal((await attest({ repository: RFP_REPO, record: out.record })).record.signatures.length, 2); await assert.rejects(attest({ repository: "did:plc:someoneelse", record: unsigned }), /session DID/); await assert.rejects(attestHost(ctx, secp256k1, undefined)({ repository: undefined }), /session DID/); await assert.rejects(attest({ repository: RFP_REPO, record: [] }), /object/); assert.notEqual((await attestHost(ctx, secp256k1, "did:plc:two")({ repository: "did:plc:two" })).key, key); });