OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-base / test / deterministic-key.test.mjs

62 lines · javascript ref:
// PHASE 0 — DETERMINISTIC BASE KEY. Two co-owners holding the same members-only `roomSeed` derive the
// IDENTICAL autobase base key independently (no shared bootstrap), open the SAME base, and converge —
// the lowest-key admin is the bootstrap creator; the other joins via admission. This is what lets a
// co-owned DID exist without one peer handing the other a bootstrap key out-of-band.

import test from 'brittle'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import crypto from 'hypercore-crypto'
import { deriveAtprotoKey, createAtprotoIdentity } from 'atproto-identity'
import { AtprotoBase } from '../lib/base.js'

const MNEMONIC = 'test test test test test test test test test test test junk'
const ID = createAtprotoIdentity(MNEMONIC, { handle: 'x.7rnx.net', pdsUrl: 'https://pds.7rnx.net' })
const KEY = deriveAtprotoKey(MNEMONIC)
const post = (text) => ({ $type: 'app.bsky.feed.post', text, createdAt: '2026-07-23T00:00:00.000Z', langs: ['en'] })
const hex = (b) => b.toString('hex')
const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
function mk (opts) { const dir = mkdtempSync(join(tmpdir(), 'detkey-')); const base = new AtprotoBase({ path: dir, did: ID.did, privateKey: KEY.privateKey, ackInterval: 100, ...opts }); return { base, dir, close: async () => { await base.close(); rmSync(dir, { recursive: true, force: true }) } } }
const pipe = (a, b) => { const s1 = a.base.base.replicate(true); const s2 = b.base.base.replicate(false); s1.pipe(s2).pipe(s1); return () => { try { s1.destroy() } catch {} ; try { s2.destroy() } catch {} } }
async function settle (...ws) { for (let i = 0; i < 20; i++) { for (const w of ws) { try { await w.base.base.update() } catch {} } await sleep(60) } }

test('deterministic base key: same roomSeed → same base key, no shared bootstrap, converges', async (t) => {
  const roomSeed = Buffer.alloc(32, 7) // the members-only secret both hold
  const idA = crypto.keyPair(); const idB = crypto.keyPair()
  const roster = [{ key: hex(idA.publicKey), role: 1 }, { key: hex(idB.publicKey), role: 1 }] // both admins

  // Both open with ONLY the roomSeed + roster — NO bootstrap passed between them.
  const A = mk({ roomSeed, identity: idA, members: roster })
  const B = mk({ roomSeed, identity: idB, members: roster })
  await A.base.ready(); await B.base.ready()
  const unpipe = pipe(A, B)
  t.teardown(async () => { unpipe(); await A.close(); await B.close() })

  t.is(A.base.base.key.toString('hex'), B.base.base.key.toString('hex'), 'both independently derived the IDENTICAL base key from the roomSeed')
  t.is([A, B].filter((x) => x.base.writable).length, 1, 'exactly ONE is the bootstrap creator (lowest-key admin) at boot')

  const creator = A.base.writable ? A : B
  const joiner = A.base.writable ? B : A
  await creator.base.projectMembers(roster); await settle(A, B)

  // Both post: creator directly; joiner via block-until-admitted (its record is still finalized).
  await creator.base.putRecord('app.bsky.feed.post', '3c', post('creator'))
  await joiner.base.putRecord('app.bsky.feed.post', '3j', post('joiner'))
  await settle(A, B); await A.base.settled(); await B.base.settled()

  t.ok(joiner.base.writable, 'the joiner was admitted onto the shared base (derived, not bootstrapped)')
  const hA = await A.base.head(); const hB = await B.base.head()
  t.is(hA.commitCid.toString(), hB.commitCid.toString(), 'co-owners converge to the identical finalized head')
})

test('deterministic base key: a DIFFERENT roomSeed yields a different base (isolation)', async (t) => {
  const idA = crypto.keyPair()
  const roster = [{ key: hex(idA.publicKey), role: 1 }]
  const A = mk({ roomSeed: Buffer.alloc(32, 1), identity: idA, members: roster })
  const B = mk({ roomSeed: Buffer.alloc(32, 2), identity: idA, members: roster })
  await A.base.ready(); await B.base.ready()
  t.teardown(async () => { await A.close(); await B.close() })
  t.not(A.base.base.key.toString('hex'), B.base.base.key.toString('hex'), 'different roomSeed → different base key')
})