~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
72 lines · 2.2 KB Raw History
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
import { LTHASH_STATE_BYTES, LtHash } from '../src/lthash.js';

const vectors = JSON.parse(
  readFileSync(
    new URL('../../../test/fixtures/space-vectors.json', import.meta.url),
    'utf8',
  ),
);

const toHex = (/** @type {Uint8Array} */ bytes) =>
  Array.from(bytes)
    .map((b) => b.toString(16).padStart(2, '0'))
    .join('');

describe('LtHash', () => {
  it('starts as 2048 zero bytes', () => {
    const h = new LtHash();
    expect(h.state()).toEqual(new Uint8Array(LTHASH_STATE_BYTES));
    expect(h.isEmpty()).toBe(true);
  });

  it('rejects a state of the wrong length', () => {
    expect(() => new LtHash(new Uint8Array(10))).toThrow(/2048/);
  });

  it('add then remove returns to the zero state', () => {
    const h = new LtHash().add('a');
    expect(h.isEmpty()).toBe(false);
    h.remove('a');
    expect(h.isEmpty()).toBe(true);
  });

  it('is order-independent', async () => {
    const a = new LtHash().add('a').add('b');
    const b = new LtHash().add('b').add('a');
    expect(a.equals(b)).toBe(true);
    expect(await a.digest()).toEqual(await b.digest());
  });

  it('distinguishes different elements', () => {
    expect(new LtHash().add('a').equals(new LtHash().add('b'))).toBe(false);
  });

  it('round-trips through state()', () => {
    const h = new LtHash().add('a').add('b');
    expect(new LtHash(h.state()).equals(h)).toBe(true);
  });

  it('matches the reference empty state', async () => {
    const h = new LtHash();
    expect(toHex(h.state())).toBe(vectors.lthash.empty.stateHex);
    expect(toHex(await h.digest())).toBe(vectors.lthash.empty.digestHex);
  });

  it('matches the reference for single elements', async () => {
    for (const c of vectors.lthash.single) {
      const h = new LtHash().add(c.element);
      expect(toHex(h.state()), c.element).toBe(c.stateHex);
      expect(toHex(await h.digest()), c.element).toBe(c.digestHex);
    }
  });

  it('matches the reference for element sets', async () => {
    for (const c of vectors.lthash.sets) {
      const h = new LtHash();
      for (const e of c.elements) h.add(e);
      expect(toHex(await h.digest()), c.elements.join(',')).toBe(c.digestHex);
    }
  });
});