nostr-crypto-utils 0.1.4

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Human Java Enterprises
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # @humanjavaenterprises/nostr-crypto-utils
2
+
3
+ A comprehensive cryptographic utilities package for NOSTR applications, designed to work seamlessly with [@humanjavaenterprises/nostr-nsec-seedphrase](https://github.com/humanjavaenterprises/nostr-nsec-seedphrase).
4
+
5
+ ⚠️ **Important Security Notice**
6
+
7
+ This library handles cryptographic keys and seed phrases that are critical for securing your Nostr identity and data. Just like Bitcoin, any seed phrase or private key (`nsec`) generated by this library must be stored with the utmost security and care.
8
+
9
+ Developers using this library must inform their users about the critical nature of managing seed phrases, `nsec`, and hex keys. It is the user's responsibility to securely store and manage these keys. The library and its authors disclaim any responsibility or liability for lost keys, seed phrases, or data resulting from mismanagement.
10
+
11
+ ## Features
12
+
13
+ - 🔑 Complete key pair management (generation, validation, public key derivation)
14
+ - 📝 Event signing and verification
15
+ - 🔒 NIP-04 encryption and decryption
16
+ - 🌱 Seed phrase support via integration with nostr-nsec-seedphrase
17
+ - 📦 Modern ESM package with full TypeScript support
18
+ - ⚡️ Built on established crypto libraries (noble-curves, noble-hashes)
19
+ - 🤝 Compatible with nostr-tools as a peer dependency
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @humanjavaenterprises/nostr-crypto-utils @humanjavaenterprises/nostr-nsec-seedphrase nostr-tools
25
+ ```
26
+
27
+ ## Architecture Overview
28
+
29
+ This library serves as a crucial middleware layer in NOSTR applications:
30
+
31
+ ```
32
+ ┌─────────────────────────────────────────────────────┐
33
+ │ Your NOSTR App │
34
+ └───────────────────────┬─────────────────────────────┘
35
+
36
+ ┌───────────────────────▼─────────────────────────────┐
37
+ │ @humanjavaenterprises/nostr-crypto-utils │
38
+ │ │
39
+ │ ┌─────────────────┐ ┌──────────────────┐ │
40
+ │ │ Key Manager │ │ Event Handler │ │
41
+ │ └────────┬────────┘ └────────┬─────────┘ │
42
+ │ │ │ │
43
+ │ ┌────────▼────────┐ ┌───────▼─────────┐ │
44
+ │ │ nostr-nsec- │ │ nostr-tools │ │
45
+ │ │ seedphrase │ │ │ │
46
+ │ └─────────────────┘ └─────────────────┘ │
47
+ └─────────────────────────────────────────────────────┘
48
+
49
+ ┌───────────────────────▼─────────────────────────────┐
50
+ │ NOSTR Protocol / Relays │
51
+ └─────────────────────────────────────────────────────┘
52
+ ```
53
+
54
+ ## Usage Examples
55
+
56
+ ### Key Management
57
+
58
+ ```typescript
59
+ import { generateKeyPair, derivePublicKey, validateKeyPair } from '@humanjavaenterprises/nostr-crypto-utils';
60
+
61
+ // Generate a new key pair
62
+ const keyPair = await generateKeyPair();
63
+ console.log(keyPair);
64
+ // { privateKey: '...', publicKey: '...' }
65
+
66
+ // Generate from seed phrase
67
+ const seedPhrase = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about';
68
+ const keyPairFromSeed = await generateKeyPair(seedPhrase);
69
+
70
+ // Derive public key from private key
71
+ const publicKey = await derivePublicKey(keyPair.privateKey);
72
+
73
+ // Validate a key pair
74
+ const validation = await validateKeyPair(keyPair.publicKey, keyPair.privateKey);
75
+ console.log(validation);
76
+ // { isValid: true, error: undefined }
77
+ ```
78
+
79
+ ### Event Operations
80
+
81
+ ```typescript
82
+ import { signEvent, verifySignature } from '@humanjavaenterprises/nostr-crypto-utils';
83
+
84
+ // Create and sign a NOSTR event
85
+ const event = {
86
+ kind: 1,
87
+ created_at: Math.floor(Date.now() / 1000),
88
+ tags: [],
89
+ content: 'Hello NOSTR!'
90
+ };
91
+
92
+ const signedEvent = await signEvent(event, keyPair.privateKey);
93
+ console.log(signedEvent);
94
+ // { id: '...', pubkey: '...', sig: '...', ...event }
95
+
96
+ // Verify an event signature
97
+ const isValid = await verifySignature(signedEvent);
98
+ console.log(isValid); // true
99
+ ```
100
+
101
+ ### Encryption (NIP-04)
102
+
103
+ ```typescript
104
+ import { encrypt, decrypt } from '@humanjavaenterprises/nostr-crypto-utils';
105
+
106
+ // Encrypt a message
107
+ const encrypted = await encrypt(
108
+ 'Secret message',
109
+ recipientPublicKey,
110
+ senderPrivateKey
111
+ );
112
+
113
+ // Decrypt a message
114
+ const decrypted = await decrypt(
115
+ encrypted,
116
+ senderPublicKey,
117
+ recipientPrivateKey
118
+ );
119
+ ```
120
+
121
+ ## Integration Examples
122
+
123
+ ### Authentication Flow
124
+
125
+ ```typescript
126
+ import { generateKeyPair, signEvent } from '@humanjavaenterprises/nostr-crypto-utils';
127
+
128
+ async function authenticateUser(seedPhrase?: string) {
129
+ // Generate or recover keys
130
+ const keyPair = await generateKeyPair(seedPhrase);
131
+
132
+ // Create auth event
133
+ const authEvent = {
134
+ kind: 22242,
135
+ created_at: Math.floor(Date.now() / 1000),
136
+ tags: [['challenge', 'authentication-challenge']],
137
+ content: 'Authenticating...'
138
+ };
139
+
140
+ // Sign the event
141
+ const signedAuthEvent = await signEvent(authEvent, keyPair.privateKey);
142
+
143
+ return signedAuthEvent;
144
+ }
145
+ ```
146
+
147
+ ### Secure Messaging
148
+
149
+ ```typescript
150
+ import { generateKeyPair, encrypt, decrypt } from '@humanjavaenterprises/nostr-crypto-utils';
151
+
152
+ async function secureMessaging() {
153
+ // Generate keys for both parties
154
+ const alice = await generateKeyPair();
155
+ const bob = await generateKeyPair();
156
+
157
+ // Alice encrypts a message for Bob
158
+ const encrypted = await encrypt(
159
+ 'Hey Bob!',
160
+ bob.publicKey,
161
+ alice.privateKey
162
+ );
163
+
164
+ // Bob decrypts Alice's message
165
+ const decrypted = await decrypt(
166
+ encrypted,
167
+ alice.publicKey,
168
+ bob.privateKey
169
+ );
170
+ }
171
+ ```
172
+
173
+ ## Contributing
174
+
175
+ Contributions are welcome! Please feel free to submit a Pull Request.
176
+
177
+ ## License
178
+
179
+ MIT
180
+
181
+ ## Related Projects
182
+
183
+ - [@humanjavaenterprises/nostr-nsec-seedphrase](https://github.com/humanjavaenterprises/nostr-nsec-seedphrase) - Seed phrase management for NOSTR
184
+ - [nostr-tools](https://github.com/nbd-wtf/nostr-tools) - Core NOSTR functionality
@@ -0,0 +1,37 @@
1
+ import type { KeyPair, NostrEvent, SignedNostrEvent, ValidationResult } from './types';
2
+ /**
3
+ * Generate a private key for use with NOSTR
4
+ */
5
+ export declare function generatePrivateKey(): string;
6
+ /**
7
+ * Get a public key from a private key
8
+ */
9
+ export declare function getPublicKey(privateKey: string): string;
10
+ /**
11
+ * Generate a new key pair
12
+ */
13
+ export declare function generateKeyPair(): KeyPair;
14
+ /**
15
+ * Get the hash of a NOSTR event
16
+ */
17
+ export declare function getEventHash(event: NostrEvent): string;
18
+ /**
19
+ * Sign a NOSTR event
20
+ */
21
+ export declare function signEvent(event: NostrEvent, privateKey: string): Promise<SignedNostrEvent>;
22
+ /**
23
+ * Verify a signature
24
+ */
25
+ export declare function verifySignature(event: SignedNostrEvent): boolean;
26
+ /**
27
+ * Validate a key pair
28
+ */
29
+ export declare function validateKeyPair(publicKey: string, privateKey: string): ValidationResult;
30
+ /**
31
+ * Encrypt a message using NIP-04
32
+ */
33
+ export declare function encrypt(message: string, recipientPubKey: string, senderPrivKey: string): Promise<string>;
34
+ /**
35
+ * Decrypt a message using NIP-04
36
+ */
37
+ export declare function decrypt(encryptedMessage: string, senderPubKey: string, recipientPrivKey: string): Promise<string>;
package/dist/index.js ADDED
@@ -0,0 +1,104 @@
1
+ import { schnorr } from '@noble/curves/secp256k1';
2
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils';
3
+ import { sha256 } from '@noble/hashes/sha256';
4
+ import { randomBytes } from '@noble/hashes/utils';
5
+ import * as secp256k1 from '@noble/secp256k1';
6
+ import { generateSecretKey, getPublicKey as getNostrPublicKey } from 'nostr-tools';
7
+ /**
8
+ * Generate a private key for use with NOSTR
9
+ */
10
+ export function generatePrivateKey() {
11
+ return bytesToHex(generateSecretKey());
12
+ }
13
+ /**
14
+ * Get a public key from a private key
15
+ */
16
+ export function getPublicKey(privateKey) {
17
+ return getNostrPublicKey(hexToBytes(privateKey));
18
+ }
19
+ /**
20
+ * Generate a new key pair
21
+ */
22
+ export function generateKeyPair() {
23
+ const privateKey = generatePrivateKey();
24
+ const publicKey = getPublicKey(privateKey);
25
+ return { privateKey, publicKey };
26
+ }
27
+ /**
28
+ * Get the hash of a NOSTR event
29
+ */
30
+ export function getEventHash(event) {
31
+ const serialized = JSON.stringify([
32
+ 0,
33
+ event.pubkey,
34
+ event.created_at,
35
+ event.kind,
36
+ event.tags,
37
+ event.content,
38
+ ]);
39
+ const hash = sha256(new TextEncoder().encode(serialized));
40
+ return bytesToHex(hash);
41
+ }
42
+ /**
43
+ * Sign a NOSTR event
44
+ */
45
+ export async function signEvent(event, privateKey) {
46
+ const hash = getEventHash(event);
47
+ const signature = bytesToHex(await schnorr.sign(hexToBytes(hash), hexToBytes(privateKey)));
48
+ return {
49
+ ...event,
50
+ id: hash,
51
+ sig: signature,
52
+ pubkey: getPublicKey(privateKey)
53
+ };
54
+ }
55
+ /**
56
+ * Verify a signature
57
+ */
58
+ export function verifySignature(event) {
59
+ const hash = getEventHash(event);
60
+ return schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey));
61
+ }
62
+ /**
63
+ * Validate a key pair
64
+ */
65
+ export function validateKeyPair(publicKey, privateKey) {
66
+ try {
67
+ const derivedPubKey = getPublicKey(privateKey);
68
+ return {
69
+ isValid: derivedPubKey === publicKey,
70
+ error: derivedPubKey !== publicKey ? 'Public key does not match derived key' : undefined
71
+ };
72
+ }
73
+ catch (error) {
74
+ return {
75
+ isValid: false,
76
+ error: error instanceof Error ? error.message : 'Unknown error occurred'
77
+ };
78
+ }
79
+ }
80
+ /**
81
+ * Encrypt a message using NIP-04
82
+ */
83
+ export async function encrypt(message, recipientPubKey, senderPrivKey) {
84
+ const sharedSecret = secp256k1.getSharedSecret(senderPrivKey, '02' + recipientPubKey);
85
+ const iv = randomBytes(16);
86
+ const key = sha256(sharedSecret);
87
+ const textEncoder = new TextEncoder();
88
+ const cryptoKey = await crypto.subtle.importKey('raw', key, { name: 'AES-CBC' }, false, ['encrypt']);
89
+ const encrypted = await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, cryptoKey, textEncoder.encode(message));
90
+ return bytesToHex(iv) + bytesToHex(new Uint8Array(encrypted));
91
+ }
92
+ /**
93
+ * Decrypt a message using NIP-04
94
+ */
95
+ export async function decrypt(encryptedMessage, senderPubKey, recipientPrivKey) {
96
+ const sharedSecret = secp256k1.getSharedSecret(recipientPrivKey, '02' + senderPubKey);
97
+ const key = sha256(sharedSecret);
98
+ const iv = hexToBytes(encryptedMessage.slice(0, 32));
99
+ const ciphertext = hexToBytes(encryptedMessage.slice(32));
100
+ const textDecoder = new TextDecoder();
101
+ const cryptoKey = await crypto.subtle.importKey('raw', key, { name: 'AES-CBC' }, false, ['decrypt']);
102
+ const decrypted = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, cryptoKey, ciphertext);
103
+ return textDecoder.decode(new Uint8Array(decrypted));
104
+ }
@@ -0,0 +1,24 @@
1
+ export interface KeyPair {
2
+ privateKey: string;
3
+ publicKey: string;
4
+ }
5
+ export interface NostrEvent {
6
+ kind: number;
7
+ created_at: number;
8
+ content: string;
9
+ tags: string[][];
10
+ pubkey?: string;
11
+ }
12
+ export interface SignedNostrEvent extends NostrEvent {
13
+ id: string;
14
+ sig: string;
15
+ pubkey: string;
16
+ }
17
+ export interface EncryptionResult {
18
+ ciphertext: string;
19
+ iv: string;
20
+ }
21
+ export interface ValidationResult {
22
+ isValid: boolean;
23
+ error?: string;
24
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "nostr-crypto-utils",
3
+ "version": "0.1.4",
4
+ "description": "Cryptographic utilities for NOSTR",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
14
+ "prepublishOnly": "npm run build"
15
+ },
16
+ "keywords": [
17
+ "nostr",
18
+ "crypto",
19
+ "utilities"
20
+ ],
21
+ "author": "Human Java Enterprises",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@noble/curves": "^1.2.0",
25
+ "@noble/hashes": "^1.3.2",
26
+ "@noble/secp256k1": "^2.0.0",
27
+ "@humanjavaenterprises/nostr-nsec-seedphrase": "^0.1.0",
28
+ "nostr-tools": "^2.1.4"
29
+ },
30
+ "peerDependencies": {
31
+ "nostr-tools": "^2.1.4"
32
+ },
33
+ "devDependencies": {
34
+ "@types/jest": "^29.5.5",
35
+ "@types/node": "^20.8.0",
36
+ "jest": "^29.7.0",
37
+ "ts-jest": "^29.1.1",
38
+ "typescript": "^5.2.2"
39
+ }
40
+ }