Skip to content
Closed
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
13 changes: 11 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,14 @@
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"typescript.enablePromptUseWorkspaceTsdk": true
}
"typescript.enablePromptUseWorkspaceTsdk": true,
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[jsonc]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
34 changes: 34 additions & 0 deletions benchmark-scripts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# dependencies (bun install)
node_modules

# output
out
dist
*.tgz

# code coverage
coverage
*.lcov

# logs
logs
_.log
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# caches
.eslintcache
.cache
*.tsbuildinfo

# IntelliJ based IDEs
.idea

# Finder (MacOS) folder config
.DS_Store
15 changes: 15 additions & 0 deletions benchmark-scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# benchmark-scripts

To install dependencies:

```bash
bun install
```

To run:

```bash
bun run index.ts
```

This project was created using `bun init` in bun v1.2.15. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
187 changes: 187 additions & 0 deletions benchmark-scripts/bun.lock

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions benchmark-scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "benchmark-scripts",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest",
"@types/express": "^5.0.3",
"express": "^5.1.0"
},
"peerDependencies": {
"typescript": "^5"
},
"scripts": {
"crypto": "bun run ./signing-and-verifications/server.ts"
}
}
Comment on lines +1 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Add missing dependency and tidy package fields.

  • benchmark server imports tweetnacl but it’s not declared. Add it to dependencies.
  • Optional: “module” isn’t generally used by Bun/Node here; prefer “main” or remove.

Suggested patch:

 {
   "name": "benchmark-scripts",
-  "module": "index.ts",
+  "main": "index.ts",
   "type": "module",
   "private": true,
+  "dependencies": {
+    "tweetnacl": "^1.0.3"
+  },
   "devDependencies": {
     "@types/bun": "latest",
     "@types/express": "^5.0.3",
     "express": "^5.1.0"
   },
   "peerDependencies": {
     "typescript": "^5"
   },

Quick check:


🏁 Script executed:

#!/bin/bash
jq -r '.dependencies, .devDependencies' benchmark-scripts/package.json | rg -n 'tweetnacl' || echo "tweetnacl missing"

Length of output: 17


Add missing runtime dependency (tweetnacl) to benchmark-scripts/package.json

Confirmed: quick-check shows tweetnacl is missing — add it to "dependencies". Optional: replace "module" with "main" (or remove) if you want a conventional entry field.

File: benchmark-scripts/package.json (lines 1-17)

 {
   "name": "benchmark-scripts",
-  "module": "index.ts",
+  "main": "index.ts",
   "type": "module",
   "private": true,
+  "dependencies": {
+    "tweetnacl": "^1.0.3"
+  },
   "devDependencies": {
     "@types/bun": "latest",
     "@types/express": "^5.0.3",
     "express": "^5.1.0"
   },
   "peerDependencies": {
     "typescript": "^5"
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
"name": "benchmark-scripts",
"module": "index.ts",
"type": "module",
"private": true,
"devDependencies": {
"@types/bun": "latest",
"@types/express": "^5.0.3",
"express": "^5.1.0"
},
"peerDependencies": {
"typescript": "^5"
},
"scripts": {
"crypto": "bun run ./signing-and-verifications/server.ts"
}
}
{
"name": "benchmark-scripts",
"main": "index.ts",
"type": "module",
"private": true,
"dependencies": {
"tweetnacl": "^1.0.3"
},
"devDependencies": {
"@types/bun": "latest",
"@types/express": "^5.0.3",
"express": "^5.1.0"
},
"peerDependencies": {
"typescript": "^5"
},
"scripts": {
"crypto": "bun run ./signing-and-verifications/server.ts"
}
}
🤖 Prompt for AI Agents
In benchmark-scripts/package.json around lines 1 to 17, the package is missing
the runtime dependency "tweetnacl" which is required by the benchmark scripts;
add a "dependencies" section (or extend it if present) with "tweetnacl":
"latest" (or a specific semver) so the runtime can install it, and optionally
replace the nonstandard "module" field with "main" (or remove it) to use a
conventional entry field.

28 changes: 28 additions & 0 deletions benchmark-scripts/signing-and-verifications/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import http from 'k6/http';

function _payload() {
const messagelength = __ENV.MESSAGE_LENGTH || '1024';
const engine = __ENV.ENGINE || 'tweetnacl';

const stream = !!__ENV.STREAM;

return JSON.stringify({
message: messagelength,
api: {
engine,
stream,
},
});
Comment on lines +4 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix env parsing and generate actual payload size.

  • STREAM parsing treats "false" as true.
  • message currently equals the string "1024", not a payload of that size.
-  const messagelength = __ENV.MESSAGE_LENGTH || '1024';
-  const engine = __ENV.ENGINE || 'tweetnacl';
-  const stream = !!__ENV.STREAM;
+  const messagelength = parseInt(__ENV.MESSAGE_LENGTH || '1024', 10);
+  const engine = __ENV.ENGINE || 'tweetnacl';
+  const stream = String(__ENV.STREAM || '').toLowerCase() === 'true';
@@
-  return JSON.stringify({
-    message: messagelength,
+  const message = 'a'.repeat(Number.isFinite(messagelength) ? messagelength : 1024);
+  return JSON.stringify({
+    message,
     api: {
       engine,
       stream,
     },
   });

Also applies to: 22-27

🤖 Prompt for AI Agents
In benchmark-scripts/signing-and-verifications/script.js around lines 4-15 (and
similarly lines 22-27), ENV parsing is wrong: STREAM treats the string "false"
as truthy and MESSAGE_LENGTH is left as a string instead of generating a payload
of that size; update parsing so STREAM is converted to a proper boolean (e.g.,
treat 'false', '0', '' as false, otherwise true) and parse MESSAGE_LENGTH as an
integer (use parseInt with a numeric default like 1024), then generate an actual
message payload of that length (for example repeat a single character or
generate a buffer/string of the parsed size) and return that payload rather than
the length string; apply the same fixes to the code block at lines 22-27.

}

const payload = _payload();

console.log('payload:', payload);

export default function () {
http.post(`http://localhost:${__ENV.PORT || 8080}/signAndVerify`, payload, {
headers: {
'content-type': 'application/json',
},
});
}
83 changes: 83 additions & 0 deletions benchmark-scripts/signing-and-verifications/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import express from 'express';
import nacl from 'tweetnacl';

import { encodeCanonicalJson } from '../../packages/crypto/src';
import { loadEd25519SignerFromSeed } from '../../packages/crypto/src/utils/keys';

const app = express();

app.use(express.json());

type SignAndVerifyRequest = {
message: string | object; // allow big payloads
api: {
engine: 'native' | 'tweetnacl'; // sodium
stream: boolean; // whether to use streaming API or not
};
};

const seedBytes = new Uint8Array(32).fill(1); // for testing, should be random in real world
const tweetKeyPair = nacl.sign.keyPair.fromSeed(seedBytes);

function handleTweetnaclSignAndVerify(message: Uint8Array) {
const signature = nacl.sign.detached(message, tweetKeyPair.secretKey);

nacl.sign.detached.verify(message, signature, tweetKeyPair.publicKey);
}
Comment on lines +22 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Check the result of tweetnacl.verify.

tweetnacl’s verify returns a boolean; currently ignored.

 function handleTweetnaclSignAndVerify(message: Uint8Array) {
   const signature = nacl.sign.detached(message, tweetKeyPair.secretKey);
-
-  nacl.sign.detached.verify(message, signature, tweetKeyPair.publicKey);
+  const ok = nacl.sign.detached.verify(message, signature, tweetKeyPair.publicKey);
+  if (!ok) throw new Error('Invalid signature');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function handleTweetnaclSignAndVerify(message: Uint8Array) {
const signature = nacl.sign.detached(message, tweetKeyPair.secretKey);
nacl.sign.detached.verify(message, signature, tweetKeyPair.publicKey);
}
function handleTweetnaclSignAndVerify(message: Uint8Array) {
const signature = nacl.sign.detached(message, tweetKeyPair.secretKey);
const ok = nacl.sign.detached.verify(message, signature, tweetKeyPair.publicKey);
if (!ok) throw new Error('Invalid signature');
}
🤖 Prompt for AI Agents
In benchmark-scripts/signing-and-verifications/server.ts around lines 22 to 26,
the boolean return value of nacl.sign.detached.verify is currently ignored;
capture the result into a variable and handle the failure path (e.g., if verify
returns false, throw an Error or return a failure indicator and/or log the
verification failure) so callers can react to a bad signature. Ensure the
function returns an explicit success/failure value or throws on verification
failure and include a clear error message when verification fails.


const nativeSigner = await loadEd25519SignerFromSeed(seedBytes);

async function handleNativeSignAndVerify(message: Uint8Array, stream: boolean) {
if (!stream) {
const signature = await nativeSigner.sign(message);
await nativeSigner.verify(message, signature);
return;
}
}

// @ts-ignore
app.post('/signAndVerify', async (req, res) => {
const { message, api } = req.body as SignAndVerifyRequest;
if (!message) {
return res.status(400).json({ error: 'Message cannot be empty' });
}

const { engine, stream = false } = api;

// encode should mimick copy of memory that we'll experience in real world, json -> string
const encodedMessage = new TextEncoder().encode(
typeof message === 'string' ? message : encodeCanonicalJson(message),
);

if (engine === 'tweetnacl') {
if (stream) {
return res
.status(400)
.json({ error: 'Stream not supported for tweetnacl' });
}

try {
handleTweetnaclSignAndVerify(encodedMessage);
return res.json({ success: true });
} catch (e) {
console.error('Tweetnacl sign/verify error', e);
return res.status(500).json({ error: 'Signing or verification failed' });
}
}

if (engine === 'native') {
try {
await handleNativeSignAndVerify(encodedMessage, stream);
return res.json({ success: true });
} catch (e) {
console.error('Native sign/verify error', e);
return res.status(500).json({ error: 'Signing or verification failed' });
}
}

return res.status(400).json({ error: 'Invalid engine' });
});

const port = Number.parseInt(process.env.PORT || '', 10) || 8080;

app.listen(port, '127.0.0.1', () => console.log(`Listening on ${port}`));
27 changes: 27 additions & 0 deletions benchmark-scripts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
// Environment setup & latest features
"lib": ["ESNext"],
"outDir": "dist",
"sourceMap": false,
"target": "ESNext",
"module": "Preserve",
"moduleDetection": "force",
"allowJs": true,
// Bundler mode
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}
Loading
Loading