Converted sign module.
This commit is contained in:
@@ -1,2 +1,22 @@
|
|||||||
import { test } from "vitest";
|
import { describe, test, expect } from "vitest";
|
||||||
test("placeholder", () => {});
|
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 { test } from "vitest";
|
||||||
|
import type { Event } from "./types";
|
||||||
|
|
||||||
|
test("placeholder", () => {});
|
||||||
|
|
||||||
export const testSK =
|
export const testSK =
|
||||||
"f43a0435f69529f310bbd1d6263d2fbf0977f54bfe2310cc37ae5904b83bb167";
|
"f43a0435f69529f310bbd1d6263d2fbf0977f54bfe2310cc37ae5904b83bb167";
|
||||||
export const testPK =
|
export const testPK =
|
||||||
"cfa87f35acbde29ba1ab3ee42de527b2cad33ac487e80cf2d6405ea0042c8fef";
|
"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