this repo has no description
1import { test, describe } from 'node:test' 2import assert from 'node:assert' 3import { 4 cborEncode, createCid, cidToString, base32Encode, createTid, 5 generateKeyPair, importPrivateKey, sign, bytesToHex, hexToBytes 6} from '../src/pds.js' 7 8describe('CBOR Encoding', () => { 9 test('encodes simple map', () => { 10 const encoded = cborEncode({ hello: 'world', num: 42 }) 11 // Expected: a2 65 68 65 6c 6c 6f 65 77 6f 72 6c 64 63 6e 75 6d 18 2a 12 const expected = new Uint8Array([ 13 0xa2, 0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x65, 0x77, 0x6f, 0x72, 0x6c, 0x64, 14 0x63, 0x6e, 0x75, 0x6d, 0x18, 0x2a 15 ]) 16 assert.deepStrictEqual(encoded, expected) 17 }) 18 19 test('encodes null', () => { 20 const encoded = cborEncode(null) 21 assert.deepStrictEqual(encoded, new Uint8Array([0xf6])) 22 }) 23 24 test('encodes booleans', () => { 25 assert.deepStrictEqual(cborEncode(true), new Uint8Array([0xf5])) 26 assert.deepStrictEqual(cborEncode(false), new Uint8Array([0xf4])) 27 }) 28 29 test('encodes small integers', () => { 30 assert.deepStrictEqual(cborEncode(0), new Uint8Array([0x00])) 31 assert.deepStrictEqual(cborEncode(1), new Uint8Array([0x01])) 32 assert.deepStrictEqual(cborEncode(23), new Uint8Array([0x17])) 33 }) 34 35 test('encodes integers >= 24', () => { 36 assert.deepStrictEqual(cborEncode(24), new Uint8Array([0x18, 0x18])) 37 assert.deepStrictEqual(cborEncode(255), new Uint8Array([0x18, 0xff])) 38 }) 39 40 test('encodes negative integers', () => { 41 assert.deepStrictEqual(cborEncode(-1), new Uint8Array([0x20])) 42 assert.deepStrictEqual(cborEncode(-10), new Uint8Array([0x29])) 43 }) 44 45 test('encodes strings', () => { 46 const encoded = cborEncode('hello') 47 // 0x65 = text string of length 5 48 assert.deepStrictEqual(encoded, new Uint8Array([0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f])) 49 }) 50 51 test('encodes byte strings', () => { 52 const bytes = new Uint8Array([1, 2, 3]) 53 const encoded = cborEncode(bytes) 54 // 0x43 = byte string of length 3 55 assert.deepStrictEqual(encoded, new Uint8Array([0x43, 1, 2, 3])) 56 }) 57 58 test('encodes arrays', () => { 59 const encoded = cborEncode([1, 2, 3]) 60 // 0x83 = array of length 3 61 assert.deepStrictEqual(encoded, new Uint8Array([0x83, 0x01, 0x02, 0x03])) 62 }) 63 64 test('sorts map keys deterministically', () => { 65 const encoded1 = cborEncode({ z: 1, a: 2 }) 66 const encoded2 = cborEncode({ a: 2, z: 1 }) 67 assert.deepStrictEqual(encoded1, encoded2) 68 // First key should be 'a' (0x61) 69 assert.strictEqual(encoded1[1], 0x61) 70 }) 71}) 72 73describe('Base32 Encoding', () => { 74 test('encodes bytes to base32lower', () => { 75 const bytes = new Uint8Array([0x01, 0x71, 0x12, 0x20]) 76 const encoded = base32Encode(bytes) 77 assert.strictEqual(typeof encoded, 'string') 78 assert.match(encoded, /^[a-z2-7]+$/) 79 }) 80}) 81 82describe('CID Generation', () => { 83 test('creates CIDv1 with dag-cbor codec', async () => { 84 const data = cborEncode({ test: 'data' }) 85 const cid = await createCid(data) 86 87 assert.strictEqual(cid.length, 36) // 2 prefix + 2 multihash header + 32 hash 88 assert.strictEqual(cid[0], 0x01) // CIDv1 89 assert.strictEqual(cid[1], 0x71) // dag-cbor 90 assert.strictEqual(cid[2], 0x12) // sha-256 91 assert.strictEqual(cid[3], 0x20) // 32 bytes 92 }) 93 94 test('cidToString returns base32lower with b prefix', async () => { 95 const data = cborEncode({ test: 'data' }) 96 const cid = await createCid(data) 97 const cidStr = cidToString(cid) 98 99 assert.strictEqual(cidStr[0], 'b') 100 assert.match(cidStr, /^b[a-z2-7]+$/) 101 }) 102 103 test('same input produces same CID', async () => { 104 const data1 = cborEncode({ test: 'data' }) 105 const data2 = cborEncode({ test: 'data' }) 106 const cid1 = cidToString(await createCid(data1)) 107 const cid2 = cidToString(await createCid(data2)) 108 109 assert.strictEqual(cid1, cid2) 110 }) 111 112 test('different input produces different CID', async () => { 113 const cid1 = cidToString(await createCid(cborEncode({ a: 1 }))) 114 const cid2 = cidToString(await createCid(cborEncode({ a: 2 }))) 115 116 assert.notStrictEqual(cid1, cid2) 117 }) 118}) 119 120describe('TID Generation', () => { 121 test('creates 13-character TIDs', () => { 122 const tid = createTid() 123 assert.strictEqual(tid.length, 13) 124 }) 125 126 test('uses valid base32-sort characters', () => { 127 const tid = createTid() 128 assert.match(tid, /^[234567abcdefghijklmnopqrstuvwxyz]+$/) 129 }) 130 131 test('generates monotonically increasing TIDs', () => { 132 const tid1 = createTid() 133 const tid2 = createTid() 134 const tid3 = createTid() 135 136 assert.ok(tid1 < tid2, `${tid1} should be less than ${tid2}`) 137 assert.ok(tid2 < tid3, `${tid2} should be less than ${tid3}`) 138 }) 139 140 test('generates unique TIDs', () => { 141 const tids = new Set() 142 for (let i = 0; i < 100; i++) { 143 tids.add(createTid()) 144 } 145 assert.strictEqual(tids.size, 100) 146 }) 147}) 148 149describe('P-256 Signing', () => { 150 test('generates key pair with correct sizes', async () => { 151 const kp = await generateKeyPair() 152 153 assert.strictEqual(kp.privateKey.length, 32) 154 assert.strictEqual(kp.publicKey.length, 33) // compressed 155 assert.ok(kp.publicKey[0] === 0x02 || kp.publicKey[0] === 0x03) 156 }) 157 158 test('can sign data with generated key', async () => { 159 const kp = await generateKeyPair() 160 const key = await importPrivateKey(kp.privateKey) 161 const data = new TextEncoder().encode('test message') 162 const sig = await sign(key, data) 163 164 assert.strictEqual(sig.length, 64) // r (32) + s (32) 165 }) 166 167 test('different messages produce different signatures', async () => { 168 const kp = await generateKeyPair() 169 const key = await importPrivateKey(kp.privateKey) 170 171 const sig1 = await sign(key, new TextEncoder().encode('message 1')) 172 const sig2 = await sign(key, new TextEncoder().encode('message 2')) 173 174 assert.notDeepStrictEqual(sig1, sig2) 175 }) 176 177 test('bytesToHex and hexToBytes roundtrip', () => { 178 const original = new Uint8Array([0x00, 0x0f, 0xf0, 0xff, 0xab, 0xcd]) 179 const hex = bytesToHex(original) 180 const back = hexToBytes(hex) 181 182 assert.strictEqual(hex, '000ff0ffabcd') 183 assert.deepStrictEqual(back, original) 184 }) 185})