Converted sign module.

This commit is contained in:
Jay
2025-10-24 10:34:48 -04:00
parent 60a5c86b2b
commit 8371df4d8a
3 changed files with 72 additions and 3 deletions

View File

@@ -1,2 +1,22 @@
import { test } from "vitest";
test("placeholder", () => {});
import { describe, test, expect } from "vitest";
import { Sign } from "./sign";
import { testSK, testEvent } from "./util.test";
describe("Sign.sign", () => {
test("produces correct signature", () => {
const signature = Sign.sign(testEvent.id, testSK);
expect(signature).toBe(testEvent.sig);
});
test("throws on invalid event ID", () => {
expect(() => Sign.sign("thisisabadeventid", testSK)).toThrow(
"event id must be 64 hex characters",
);
});
test("throws on invalid private key", () => {
expect(() => Sign.sign(testEvent.id, "thisisabadsecretkey")).toThrow(
"private key must be 64 lowercase hex characters",
);
});
});

View File

@@ -0,0 +1,36 @@
import * as secp from "@noble/secp256k1";
import { schnorr } from "@noble/secp256k1";
import { hmac } from "@noble/hashes/hmac.js";
import { sha256 } from "@noble/hashes/sha2.js";
import { MalformedIDError, MalformedPrivKeyError } from "./errors";
secp.hashes.hmacSha256 = (key, msg) => hmac(sha256, key, msg);
secp.hashes.sha256 = sha256;
/**
* Generates a Schnorr signature for the given event ID using the provided private key.
* @param eventID - 64-character lowercase hexadecimal event ID
* @param privateKey - 64-character lowercase hexadecimal private key
* @returns 128-character lowercase hexadecimal signature
* @throws {MalformedIDError} If event ID is not 64 hex characters
* @throws {MalformedPrivKeyError} If private key is not 64 lowercase hex characters
*/
function sign(eventID: string, privateKey: string): string {
const privateKeyBytes = Buffer.from(privateKey, "hex");
if (privateKeyBytes.length !== 32) {
throw new MalformedPrivKeyError();
}
const idBytes = Buffer.from(eventID, "hex");
if (idBytes.length !== 32) {
throw new MalformedIDError();
}
const auxRand = sha256(privateKeyBytes);
const signature = schnorr.sign(idBytes, privateKeyBytes, auxRand);
return Buffer.from(signature).toString("hex");
}
export const Sign = {
sign,
};

View File

@@ -1,8 +1,21 @@
import { test } from "vitest";
import type { Event } from "./types";
test("placeholder", () => {});
export const testSK =
"f43a0435f69529f310bbd1d6263d2fbf0977f54bfe2310cc37ae5904b83bb167";
export const testPK =
"cfa87f35acbde29ba1ab3ee42de527b2cad33ac487e80cf2d6405ea0042c8fef";
test("placeholder", () => {});
export const testEvent: Event = {
id: "c7a702e6158744ca03508bbb4c90f9dbb0d6e88fefbfaa511d5ab24b4e3c48ad",
pubkey: testPK,
created_at: 1760740551,
kind: 1,
tags: [],
content: "hello world",
sig: "0fb7c1eaa867c4d16000587f2fb26c0b67e7e069f35d1acbb2d385a7813eb342418714a4c4fd4c04b9d7e2477e7a2208102ef536df09b79b84b8f3c41e8e5708",
};
export const testEventJSON = `{"id":"c7a702e6158744ca03508bbb4c90f9dbb0d6e88fefbfaa511d5ab24b4e3c48ad","pubkey":"cfa87f35acbde29ba1ab3ee42de527b2cad33ac487e80cf2d6405ea0042c8fef","created_at":1760740551,"kind":1,"tags":[],"content":"hello world","sig":"0fb7c1eaa867c4d16000587f2fb26c0b67e7e069f35d1acbb2d385a7813eb342418714a4c4fd4c04b9d7e2477e7a2208102ef536df09b79b84b8f3c41e8e5708"}`;