@neuraiproject/neurai-message 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,140 @@
1
+ import { Buffer } from "buffer";
2
+ import { hmac } from "@noble/hashes/hmac.js";
3
+ import { sha256 as nobleSha256 } from "@noble/hashes/sha2.js";
4
+ import * as secp256k1 from "@noble/secp256k1";
5
+ import { bech32 } from "bech32";
6
+ import bs58check from "bs58check";
7
+ import createHash from "create-hash";
8
+ import varuint from "varuint-bitcoin";
9
+
10
+ secp256k1.hashes.hmacSha256 = (key, msg) => hmac(nobleSha256, key, msg);
11
+ secp256k1.hashes.sha256 = nobleSha256;
12
+
13
+ function sha256(bytes: Uint8Array) {
14
+ return createHash("sha256").update(bytes).digest();
15
+ }
16
+
17
+ function hash256(bytes: Uint8Array) {
18
+ return sha256(sha256(bytes));
19
+ }
20
+
21
+ function hash160(bytes: Uint8Array) {
22
+ return createHash("ripemd160").update(sha256(bytes)).digest();
23
+ }
24
+
25
+ function encodeCompactSignature(
26
+ signature: Uint8Array,
27
+ recovery: number,
28
+ compressed: boolean
29
+ ) {
30
+ let header = recovery + 27;
31
+ if (compressed) {
32
+ header += 4;
33
+ }
34
+ return Buffer.concat([Buffer.from([header]), Buffer.from(signature)]);
35
+ }
36
+
37
+ function decodeCompactSignature(buffer: Buffer) {
38
+ if (buffer.length !== 65) {
39
+ throw new Error("Invalid signature length");
40
+ }
41
+
42
+ const flagByte = buffer.readUInt8(0) - 27;
43
+ if (flagByte < 0 || flagByte > 15) {
44
+ throw new Error("Invalid signature parameter");
45
+ }
46
+
47
+ return {
48
+ compressed: !!(flagByte & 12),
49
+ recovery: flagByte & 3,
50
+ signature: buffer.subarray(1),
51
+ segwitType: !(flagByte & 8)
52
+ ? null
53
+ : !(flagByte & 4)
54
+ ? "p2sh(p2wpkh)"
55
+ : "p2wpkh",
56
+ };
57
+ }
58
+
59
+ function decodeBech32Address(address: string) {
60
+ const result = bech32.decode(address);
61
+ return Buffer.from(bech32.fromWords(result.words.slice(1)));
62
+ }
63
+
64
+ function segwitRedeemHash(publicKeyHash: Uint8Array) {
65
+ const redeemScript = Buffer.concat([
66
+ Buffer.from("0014", "hex"),
67
+ Buffer.from(publicKeyHash),
68
+ ]);
69
+ return hash160(redeemScript);
70
+ }
71
+
72
+ export function magicHash(message: string | Buffer, messagePrefix: string | Buffer) {
73
+ const prefix = Buffer.isBuffer(messagePrefix)
74
+ ? messagePrefix
75
+ : Buffer.from(messagePrefix, "utf8");
76
+ const payload = Buffer.isBuffer(message)
77
+ ? message
78
+ : Buffer.from(message, "utf8");
79
+ const messageVISize = varuint.encodingLength(payload.length);
80
+ const buffer = Buffer.allocUnsafe(prefix.length + messageVISize + payload.length);
81
+
82
+ prefix.copy(buffer, 0);
83
+ varuint.encode(payload.length, buffer, prefix.length);
84
+ payload.copy(buffer, prefix.length + messageVISize);
85
+
86
+ return hash256(buffer);
87
+ }
88
+
89
+ export function signLegacyMessage(
90
+ message: string,
91
+ privateKey: Uint8Array,
92
+ compressed: boolean,
93
+ messagePrefix: string | Buffer
94
+ ) {
95
+ const hash = magicHash(message, messagePrefix);
96
+ const recoveredSignature = secp256k1.sign(hash, Buffer.from(privateKey), {
97
+ prehash: false,
98
+ format: "recovered",
99
+ });
100
+ return encodeCompactSignature(
101
+ recoveredSignature.subarray(1),
102
+ recoveredSignature[0],
103
+ compressed
104
+ );
105
+ }
106
+
107
+ export function verifyLegacyCompactMessage(
108
+ message: string,
109
+ address: string,
110
+ signature: Uint8Array,
111
+ messagePrefix: string | Buffer
112
+ ) {
113
+ const parsed = decodeCompactSignature(Buffer.from(signature));
114
+ const hash = magicHash(message, messagePrefix);
115
+ const recoveredSignature = Buffer.concat([
116
+ Buffer.from([parsed.recovery]),
117
+ Buffer.from(parsed.signature),
118
+ ]);
119
+ const publicKey = Buffer.from(
120
+ secp256k1.recoverPublicKey(recoveredSignature, hash, {
121
+ prehash: false,
122
+ })
123
+ );
124
+ const normalizedPublicKey = parsed.compressed
125
+ ? publicKey
126
+ : Buffer.from(secp256k1.Point.fromBytes(publicKey).toBytes(false));
127
+ const publicKeyHash = hash160(normalizedPublicKey);
128
+
129
+ if (parsed.segwitType === "p2sh(p2wpkh)") {
130
+ return segwitRedeemHash(publicKeyHash).equals(
131
+ Buffer.from(bs58check.decode(address).slice(1))
132
+ );
133
+ }
134
+
135
+ if (parsed.segwitType === "p2wpkh") {
136
+ return publicKeyHash.equals(decodeBech32Address(address));
137
+ }
138
+
139
+ return publicKeyHash.equals(Buffer.from(bs58check.decode(address).slice(1)));
140
+ }
@@ -5,7 +5,7 @@ const {
5
5
  signPQMessage,
6
6
  verifyMessage,
7
7
  verifyPQMessage,
8
- } = require("./dist/main");
8
+ } = require("./dist/index.cjs");
9
9
 
10
10
  const compressed = true;
11
11
  const privateKey = Buffer.from(
@@ -31,8 +31,8 @@ test("Verify unvalid message signature", () => {
31
31
  expect(result).toBe(false);
32
32
  });
33
33
 
34
- test("Verify valid PQ message signature", () => {
35
- return import("@noble/post-quantum/ml-dsa.js").then(({ ml_dsa44 }) => {
34
+ test("Verify valid PQ message signature", async () => {
35
+ const { ml_dsa44 } = await import("@noble/post-quantum/ml-dsa.js");
36
36
  const seed = Buffer.alloc(32, 7);
37
37
  const keys = ml_dsa44.keygen(seed);
38
38
  const serializedPublicKey = Buffer.concat([
@@ -50,11 +50,10 @@ test("Verify valid PQ message signature", () => {
50
50
 
51
51
  expect(verifyPQMessage(pqMessage, pqAddress, pqSignature)).toBe(true);
52
52
  expect(verifyMessage(pqMessage, pqAddress, pqSignature)).toBe(true);
53
- });
54
53
  });
55
54
 
56
- test("Reject invalid PQ message signature", () => {
57
- return import("@noble/post-quantum/ml-dsa.js").then(({ ml_dsa44 }) => {
55
+ test("Reject invalid PQ message signature", async () => {
56
+ const { ml_dsa44 } = await import("@noble/post-quantum/ml-dsa.js");
58
57
  const seed = Buffer.alloc(32, 9);
59
58
  const keys = ml_dsa44.keygen(seed);
60
59
  const serializedPublicKey = Buffer.concat([
@@ -73,5 +72,4 @@ test("Reject invalid PQ message signature", () => {
73
72
  expect(verifyMessage(pqMessage + " changed", pqAddress, pqSignature)).toBe(
74
73
  false
75
74
  );
76
- });
77
75
  });
package/tsconfig.json CHANGED
@@ -7,7 +7,10 @@
7
7
  "types": ["node"],
8
8
  "strict": false,
9
9
  "esModuleInterop": true,
10
- "skipLibCheck": true
10
+ "skipLibCheck": true,
11
+ "declaration": true,
12
+ "emitDeclarationOnly": true,
13
+ "outDir": "dist"
11
14
  },
12
- "include": ["index.ts"]
13
- }
15
+ "include": ["index.ts", "src/**/*.ts"]
16
+ }
@@ -0,0 +1,7 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ },
7
+ });