Converted sign module.
This commit is contained in:
@@ -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",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
36
src/sign.ts
36
src/sign.ts
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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"}`;
|
||||
|
||||
Reference in New Issue
Block a user