@claude-flow/embeddings
Version:
V3 Embedding Service - OpenAI, Transformers.js, Agentic-Flow (ONNX), Mock providers with hyperbolic embeddings, normalization, and chunking
239 lines (214 loc) • 9.97 kB
text/typescript
/**
* ADR-121 Phase 24 — Multi-signer ledger tests.
*
* Covers:
* - Backward compat: existing single-signer entries still verify at minSignatures=1
* - coSign() doesn't change contentHash (chain integrity preserved)
* - Multiple co-signatures accumulate
* - Threshold verification (1-of-N, 2-of-N, M-of-N)
* - Invalid cosignature detected (forged signature, mismatched key)
* - verifyCosignatureAgainst standalone helper
* - Backward compat at ledger level: 9-entry single-sig ledger still verifies
*/
import { describe, it, expect } from 'vitest';
import {
appendToLedger,
verifyEntry,
verifyLedger,
generateLedgerKeypair,
coSign,
verifyCosignatureAgainst,
type BenchmarkLedger,
} from '../witness-ledger.js';
function input(name: string, ts: string, results: unknown) {
return {
benchmark: name,
timestamp: ts,
commit: 'commit-abc',
model: 'test-model',
corpus: { id: 'fp-corpus', size: 10 },
queries: { id: 'fp-queries', count: 3 },
results,
};
}
describe('coSign — chain integrity', () => {
it('does not change the entry contentHash', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigner = generateLedgerKeypair();
const cosigned = coSign(entry, cosigner, { signerLabel: 'third-party-verifier' });
expect(cosigned.contentHash).toBe(entry.contentHash);
});
it('does not change the primary signature', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigner = generateLedgerKeypair();
const cosigned = coSign(entry, cosigner);
expect(cosigned.signature).toBe(entry.signature);
expect(cosigned.publicKey).toBe(entry.publicKey);
});
it('appends to cosignatures array', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
expect(entry.cosignatures).toBeUndefined();
const c1 = coSign(entry, generateLedgerKeypair());
expect(c1.cosignatures?.length).toBe(1);
const c2 = coSign(c1, generateLedgerKeypair());
expect(c2.cosignatures?.length).toBe(2);
});
it('preserves signerLabel when provided', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigned = coSign(entry, generateLedgerKeypair(), { signerLabel: 'auditor-1' });
expect(cosigned.cosignatures![0]!.signerLabel).toBe('auditor-1');
});
it('records signedAt timestamp', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigned = coSign(entry, generateLedgerKeypair(), { signedAt: '2026-02-01T00:00:00.000Z' });
expect(cosigned.cosignatures![0]!.signedAt).toBe('2026-02-01T00:00:00.000Z');
});
});
describe('verifyEntry — threshold semantics', () => {
it('default (minSignatures=1) verifies single-signer entries (backward compat)', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
expect(verifyEntry(entry)).toBe(true);
});
it('minSignatures=1 verifies entry with 0 cosignatures', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
expect(verifyEntry(entry, { minSignatures: 1 })).toBe(true);
});
it('minSignatures=2 FAILS on single-signer entry', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
expect(verifyEntry(entry, { minSignatures: 2 })).toBe(false);
});
it('minSignatures=2 PASSES on entry with 1 valid cosignature (2 total)', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigned = coSign(entry, generateLedgerKeypair(), { signerLabel: 'auditor' });
expect(verifyEntry(cosigned, { minSignatures: 2 })).toBe(true);
});
it('minSignatures=3 PASSES on entry with 2 valid cosignatures (3 total)', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const c1 = coSign(entry, generateLedgerKeypair(), { signerLabel: 'auditor-A' });
const c2 = coSign(c1, generateLedgerKeypair(), { signerLabel: 'auditor-B' });
expect(verifyEntry(c2, { minSignatures: 3 })).toBe(true);
expect(verifyEntry(c2, { minSignatures: 4 })).toBe(false);
});
it('minSignatures=0 trivially passes', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
expect(verifyEntry(entry, { minSignatures: 0 })).toBe(true);
});
});
describe('verifyEntry — tampered cosignatures', () => {
it('detects a forged cosignature (random bytes)', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigner = generateLedgerKeypair();
const cosigned = coSign(entry, cosigner);
// Tamper the cosignature bytes
const cs = cosigned.cosignatures![0]!;
const tamperedSig = Buffer.from(cs.signature, 'hex');
tamperedSig[0] = tamperedSig[0]! ^ 0xff;
const tampered = {
...cosigned,
cosignatures: [{ ...cs, signature: tamperedSig.toString('hex') }],
};
// Primary still valid (1 sig); cosignature invalid (0 sigs from cosig).
// Total valid = 1.
expect(verifyEntry(tampered, { minSignatures: 1 })).toBe(true); // primary still OK
expect(verifyEntry(tampered, { minSignatures: 2 })).toBe(false); // cosig forged
});
it('detects mismatched public key on cosignature', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosignerA = generateLedgerKeypair();
const cosignerB = generateLedgerKeypair();
const cosigned = coSign(entry, cosignerA);
// Swap in B's public key while keeping A's signature
const cs = cosigned.cosignatures![0]!;
const bPubKey = cosignerB.publicKey.export({ type: 'spki', format: 'der' }).toString('hex');
const swapped = {
...cosigned,
cosignatures: [{ ...cs, publicKey: bPubKey }],
};
expect(verifyEntry(swapped, { minSignatures: 2 })).toBe(false);
});
it('partial validity: 2 valid + 1 forged cosig, minSignatures=3 → fails', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
let cur = entry;
cur = coSign(cur, generateLedgerKeypair()); // valid
cur = coSign(cur, generateLedgerKeypair()); // valid
// Add a forged third
const fake = generateLedgerKeypair();
cur = coSign(cur, fake);
// Tamper its signature
const tail = cur.cosignatures!.slice();
const forged = tail[tail.length - 1]!;
const sigBytes = Buffer.from(forged.signature, 'hex');
sigBytes[0] = sigBytes[0]! ^ 0xff;
tail[tail.length - 1] = { ...forged, signature: sigBytes.toString('hex') };
const tampered = { ...cur, cosignatures: tail };
// Primary + 2 valid cosigs = 3 valid
expect(verifyEntry(tampered, { minSignatures: 3 })).toBe(true);
expect(verifyEntry(tampered, { minSignatures: 4 })).toBe(false);
});
});
describe('verifyCosignatureAgainst — standalone helper', () => {
it('returns true for valid cosignature against the right hash', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigner = generateLedgerKeypair();
const cosigned = coSign(entry, cosigner);
expect(verifyCosignatureAgainst(entry.contentHash, cosigned.cosignatures![0]!)).toBe(true);
});
it('returns false against a different contentHash', () => {
const { entry } = appendToLedger(undefined, input('b1', '2026-01-01T00:00:00Z', { r: 1 }));
const cosigner = generateLedgerKeypair();
const cosigned = coSign(entry, cosigner);
expect(verifyCosignatureAgainst('ff'.repeat(32), cosigned.cosignatures![0]!)).toBe(false);
});
it('returns false on malformed inputs (does not throw)', () => {
const bad = { signature: 'not-hex', publicKey: 'also-not-hex', signedAt: '' };
expect(verifyCosignatureAgainst('ff'.repeat(32), bad)).toBe(false);
});
});
describe('verifyLedger — threshold over the chain', () => {
function makeChain(n: number): BenchmarkLedger {
const kp = generateLedgerKeypair();
let ledger: BenchmarkLedger | undefined;
for (let i = 0; i < n; i++) {
ledger = appendToLedger(ledger, input(`b${i}`, `2026-01-0${i + 1}T00:00:00Z`, { i }), kp).ledger;
}
return ledger!;
}
it('minSignatures=1 (default) verifies a single-signer chain (backward compat)', () => {
const ledger = makeChain(3);
const r = verifyLedger(ledger);
expect(r.valid).toBe(true);
});
it('minSignatures=2 fails when no entries have cosignatures', () => {
const ledger = makeChain(3);
const r = verifyLedger(ledger, { minSignatures: 2 });
expect(r.valid).toBe(false);
expect(r.firstFailureAt).toBe(0);
expect(r.reason).toMatch(/minSignatures=2/);
});
it('minSignatures=2 passes when every entry is cosigned', () => {
const ledger = makeChain(3);
const cosigner = generateLedgerKeypair();
const cosigned: BenchmarkLedger = {
...ledger,
entries: ledger.entries.map(e => coSign(e, cosigner, { signerLabel: 'auditor' })),
};
const r = verifyLedger(cosigned, { minSignatures: 2 });
expect(r.valid).toBe(true);
});
it('reports the first entry that fails the threshold', () => {
const ledger = makeChain(3);
const cosigner = generateLedgerKeypair();
// Only entries 0 and 2 are co-signed; entry 1 has just the primary.
const cosigned: BenchmarkLedger = {
...ledger,
entries: [
coSign(ledger.entries[0]!, cosigner),
ledger.entries[1]!,
coSign(ledger.entries[2]!, cosigner),
],
};
const r = verifyLedger(cosigned, { minSignatures: 2 });
expect(r.valid).toBe(false);
expect(r.firstFailureAt).toBe(1);
});
});