Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/tlock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# tlock

## Test Vectors

The test vectors for `sealBid` binding hashes are located in `src/sealBid-vectors.json`.

To regenerate the vectors, run:

```bash
pnpm run generate-vectors
```
1 change: 1 addition & 0 deletions packages/tlock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"test:unit": "node --import tsx --test src/commitment.test.ts src/auditor.test.ts src/auditor-recovery-cli.test.ts src/bls.test.ts src/freshness.test.ts src/quicknet.test.ts",
"test:seal": "node --import tsx --test src/seal.test.ts",
"recover:identities": "node --import tsx src/recover-identities.cli.ts",
"generate-vectors": "node --import tsx scripts/generate-vectors.ts",
"typecheck": "tsc --noEmit -p tsconfig.json"
},
"dependencies": {
Expand Down
58 changes: 58 additions & 0 deletions packages/tlock/scripts/generate-vectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { writeFileSync } from "node:fs";
import { commitment, toHex } from "../src/commitment.js";
import { generateAuditorKeypair } from "../src/auditor.js";
import { generateNonce } from "../src/seal.js";

function generateVectors() {
const vectors = [];

// Vector 1: Standard values
const nonce1 = new Uint8Array(32).fill(0x42);
const value1 = 1000000n;
const round1 = 12345;
const identity1 = new TextEncoder().encode("alice");
const auditor1 = generateAuditorKeypair();

vectors.push({
inputs: {
value: value1.toString(),
nonce: toHex(nonce1),
round: round1,
identity: toHex(identity1),
auditorSecretKey: toHex(auditor1.secretKey),
auditorPublicKey: toHex(auditor1.publicKey)
},
expected: {
commitment: toHex(commitment(value1, nonce1))
}
});

// Vector 2: Edge case value = 0n
const nonce2 = generateNonce();
const value2 = 0n;
const round2 = 999999;
const identity2 = new TextEncoder().encode("bob");
const auditor2 = generateAuditorKeypair();

vectors.push({
inputs: {
value: value2.toString(),
nonce: toHex(nonce2),
round: round2,
identity: toHex(identity2),
auditorSecretKey: toHex(auditor2.secretKey),
auditorPublicKey: toHex(auditor2.publicKey)
},
expected: {
commitment: toHex(commitment(value2, nonce2))
}
});

writeFileSync(
new URL("../src/sealBid-vectors.json", import.meta.url),
JSON.stringify(vectors, null, 2)
);
console.log("Vectors generated in src/sealBid-vectors.json");
}

generateVectors();
51 changes: 51 additions & 0 deletions packages/tlock/src/seal.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";

import { quicknet, currentRound } from "./quicknet.js";
import { sealBid, openBid, generateNonce } from "./seal.js";
Expand Down Expand Up @@ -80,3 +81,53 @@ test(
await assert.rejects(openBid(sealed.ciphertext, client));
},
);

const vectors = JSON.parse(
fs.readFileSync(new URL("./sealBid-vectors.json", import.meta.url), "utf-8")
);

test(
"sealBid matches cross-implementation test vectors",
{ timeout: NET_TIMEOUT },
async () => {
const client = quicknet();

for (const vector of vectors) {
const value = BigInt(vector.inputs.value);
const nonce = Uint8Array.from(Buffer.from(vector.inputs.nonce, "hex"));
const round = vector.inputs.round;
const identity = Uint8Array.from(Buffer.from(vector.inputs.identity, "hex"));
const auditorPublicKey = Uint8Array.from(Buffer.from(vector.inputs.auditorPublicKey, "hex"));

const expectedCommitment = vector.expected.commitment;

const sealed = await sealBid({
value,
nonce,
round,
client,
identity,
auditorPublicKey
});

assert.equal(toHex(sealed.commitment), expectedCommitment);
}
}
);

test("modified nonce changes the binding hash", () => {
for (const vector of vectors) {
const value = BigInt(vector.inputs.value);
const nonce = Uint8Array.from(Buffer.from(vector.inputs.nonce, "hex"));

const modifiedNonce = new Uint8Array(nonce);
modifiedNonce[0] ^= 1;

const originalCommitment = toHex(commitment(value, nonce));
const modifiedCommitment = toHex(commitment(value, modifiedNonce));

assert.notEqual(originalCommitment, modifiedCommitment);
assert.equal(originalCommitment, vector.expected.commitment);
}
});

28 changes: 28 additions & 0 deletions packages/tlock/src/sealBid-vectors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[
{
"inputs": {
"value": "1000000",
"nonce": "4242424242424242424242424242424242424242424242424242424242424242",
"round": 12345,
"identity": "616c696365",
"auditorSecretKey": "0000000000000000000000000000000000000000000000000000000000000000",
"auditorPublicKey": "0000000000000000000000000000000000000000000000000000000000000000"
},
"expected": {
"commitment": "5041e198cc5e9f097ae13f91c82514834a135fdf7cefbd39b1c11c9612cdce91"
}
},
{
"inputs": {
"value": "0",
"nonce": "0101010101010101010101010101010101010101010101010101010101010101",
"round": 999999,
"identity": "626f62",
"auditorSecretKey": "1111111111111111111111111111111111111111111111111111111111111111",
"auditorPublicKey": "1111111111111111111111111111111111111111111111111111111111111111"
},
"expected": {
"commitment": "65c9b91a2fea0df42fe54206e95a675f4d9b7c84d6ebabdd56bdf75d12f2364d"
}
}
]