mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-10-04 05:37:10 +00:00
feat(ans): implement @logicsrc/ans M1 — resolver + offline verifier
M1 of the ANS SDK (docs/ans-sdk.md): - name: parse/format ans://v<semver>.<agent>.<domain> - cbor: minimal RFC 8949 codec for the COSE_Sign1 subset - verify/merkle: RFC 6962 leaf/node hashing, tree build, inclusion-proof generation + verification - verify/es256 + cose: COSE_Sign1 build/parse, Sig_structure, ES256 (WebCrypto) - verify/rootkeys: kid -> verifier key (JWKS entries; sumdb-note is M2) - verify: verifyReceipt() + verifyResolution() (signature + inclusion proof + name binding), pure and offline - client: AnsClient resolve/rootKeys/register/status over injectable fetch, with a DnsApplier hook for verify-dns Tests (24) cover name parsing, CBOR round-trips/vectors, RFC 6962 proofs, a full ES256+Merkle receipt round-trip with positive/negative cases, and the client against mocked fetch. Wired into the root build script. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0ae24719e3
commit
29975b2df7
20 changed files with 1009 additions and 28 deletions
38
packages/ans/src/verify/merkle.test.ts
Normal file
38
packages/ans/src/verify/merkle.test.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { inclusionProof, leafHash, merkleRoot, nodeHash, verifyInclusion } from './merkle.js';
|
||||
import { utf8, toHex } from '../bytes.js';
|
||||
|
||||
const leaves = ['a', 'b', 'c', 'd'].map(utf8);
|
||||
|
||||
describe('RFC 6962 merkle tree', () => {
|
||||
it('computes the root as node(node(la,lb), node(lc,ld)) for 4 leaves', async () => {
|
||||
const [la, lb, lc, ld] = await Promise.all(leaves.map(leafHash));
|
||||
const expected = await nodeHash(await nodeHash(la, lb), await nodeHash(lc, ld));
|
||||
expect(toHex(await merkleRoot(leaves))).toBe(toHex(expected));
|
||||
});
|
||||
|
||||
it('verifies inclusion proofs for every leaf', async () => {
|
||||
const root = await merkleRoot(leaves);
|
||||
for (let i = 0; i < leaves.length; i++) {
|
||||
const auditPath = await inclusionProof(leaves, i);
|
||||
const ok = await verifyInclusion({ index: i, size: leaves.length, leafHash: await leafHash(leaves[i]), auditPath, root });
|
||||
expect(ok).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('verifies inclusion for an odd-sized (5-leaf) tree', async () => {
|
||||
const five = ['a', 'b', 'c', 'd', 'e'].map(utf8);
|
||||
const root = await merkleRoot(five);
|
||||
const auditPath = await inclusionProof(five, 4);
|
||||
expect(await verifyInclusion({ index: 4, size: 5, leafHash: await leafHash(five[4]), auditPath, root })).toBe(true);
|
||||
});
|
||||
|
||||
it('rejects a tampered proof, wrong index, and out-of-range index', async () => {
|
||||
const root = await merkleRoot(leaves);
|
||||
const auditPath = await inclusionProof(leaves, 1);
|
||||
const lb = await leafHash(leaves[1]);
|
||||
expect(await verifyInclusion({ index: 1, size: 4, leafHash: await leafHash(utf8('x')), auditPath, root })).toBe(false);
|
||||
expect(await verifyInclusion({ index: 2, size: 4, leafHash: lb, auditPath, root })).toBe(false);
|
||||
expect(await verifyInclusion({ index: 9, size: 4, leafHash: lb, auditPath, root })).toBe(false);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue