@optimystic/quereus-plugin-crypto 0.3.0 → 0.3.1

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/package.json CHANGED
@@ -1,71 +1,83 @@
1
1
  {
2
- "name": "@optimystic/quereus-plugin-crypto",
3
- "version": "0.3.0",
4
- "description": "Quereus plugin providing cryptographic functions (digest, sign, verify)",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- },
13
- "./plugin": {
14
- "import": "./dist/plugin.js",
15
- "types": "./dist/plugin.d.ts"
16
- }
17
- },
18
- "files": [
19
- "dist",
20
- "src",
21
- "README.md"
22
- ],
23
- "scripts": {
24
- "build": "tsup",
25
- "dev": "tsup --watch",
26
- "clean": "rm -rf dist",
27
- "typecheck": "tsc --noEmit"
28
- },
29
- "devDependencies": {
30
- "@quereus/quereus": "^0.6.1",
31
- "@types/node": "^24.0.12",
32
- "aegir": "^47.0.20",
33
- "tsup": "^8.5.0",
34
- "typescript": "^5.8.3"
35
- },
36
- "dependencies": {
37
- "@noble/curves": "^1.9.6",
38
- "@noble/hashes": "^1.8.0",
39
- "uint8arrays": "^5.1.0"
40
- },
41
- "peerDependencies": {
42
- "@quereus/quereus": "^0.6.1"
43
- },
44
- "engines": {
45
- "quereus": "^0.6.1"
46
- },
47
- "keywords": [
48
- "quereus-plugin",
49
- "quereus",
50
- "crypto",
51
- "cryptography",
52
- "digest",
53
- "hash",
54
- "signature",
55
- "sign",
56
- "verify",
57
- "secp256k1",
58
- "ed25519",
59
- "p256"
60
- ],
61
- "author": "Optimystic Team",
62
- "license": "MIT",
63
- "quereus": {
64
- "provides": {
65
- "functions": ["digest", "sign", "verify", "hash_mod", "random_bytes"],
66
- "vtables": [],
67
- "collations": []
68
- },
69
- "settings": []
70
- }
71
- }
2
+ "name": "@optimystic/quereus-plugin-crypto",
3
+ "version": "0.3.1",
4
+ "description": "Quereus plugin providing cryptographic functions (digest, sign, verify)",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./plugin": {
14
+ "import": "./dist/plugin.js",
15
+ "types": "./dist/plugin.d.ts"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "tsup",
25
+ "dev": "tsup --watch",
26
+ "clean": "rimraf dist",
27
+ "typecheck": "tsc --noEmit"
28
+ },
29
+ "devDependencies": {
30
+ "@quereus/quereus": "^0.16.2",
31
+ "@types/node": "^25.2.0",
32
+ "aegir": "^47.0.26",
33
+ "rimraf": "^6.1.2",
34
+ "tsup": "^8.5.1",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "dependencies": {
38
+ "@noble/curves": "^2.0.1",
39
+ "@noble/hashes": "^2.0.1",
40
+ "uint8arrays": "^5.1.0"
41
+ },
42
+ "peerDependencies": {
43
+ "@quereus/quereus": "^0.16.2"
44
+ },
45
+ "engines": {
46
+ "quereus": "^0.16.2"
47
+ },
48
+ "keywords": [
49
+ "quereus-plugin",
50
+ "quereus",
51
+ "crypto",
52
+ "cryptography",
53
+ "digest",
54
+ "hash",
55
+ "signature",
56
+ "sign",
57
+ "verify",
58
+ "secp256k1",
59
+ "ed25519",
60
+ "p256"
61
+ ],
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "https://github.com/gotchoices/optimystic.git",
65
+ "directory": "packages/quereus-plugin-crypto"
66
+ },
67
+ "author": "Got Choices Foundation",
68
+ "license": "MIT",
69
+ "quereus": {
70
+ "provides": {
71
+ "functions": [
72
+ "digest",
73
+ "sign",
74
+ "verify",
75
+ "hash_mod",
76
+ "random_bytes"
77
+ ],
78
+ "vtables": [],
79
+ "collations": []
80
+ },
81
+ "settings": []
82
+ }
83
+ }
package/src/crypto.ts CHANGED
@@ -5,13 +5,13 @@
5
5
  * All functions accept and return base64url strings by default for SQL compatibility.
6
6
  */
7
7
 
8
- import { sha256, sha512 } from '@noble/hashes/sha2';
9
- import { blake3 } from '@noble/hashes/blake3';
10
- import { concatBytes, utf8ToBytes } from '@noble/hashes/utils';
11
- import { secp256k1 } from '@noble/curves/secp256k1';
12
- import { p256 } from '@noble/curves/nist';
13
- import { ed25519 } from '@noble/curves/ed25519';
14
- import { hexToBytes, bytesToHex } from '@noble/curves/abstract/utils';
8
+ import { sha256, sha512 } from '@noble/hashes/sha2.js';
9
+ import { blake3 } from '@noble/hashes/blake3.js';
10
+ import { concatBytes, utf8ToBytes } from '@noble/hashes/utils.js';
11
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
12
+ import { p256 } from '@noble/curves/nist.js';
13
+ import { ed25519 } from '@noble/curves/ed25519.js';
14
+ import { hexToBytes, bytesToHex } from '@noble/curves/utils.js';
15
15
  import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays';
16
16
 
17
17
  // Type definitions
@@ -192,20 +192,15 @@ export function sign(
192
192
  let sigBytes: Uint8Array;
193
193
 
194
194
  switch (curve) {
195
- case 'secp256k1': {
196
- const sig = secp256k1.sign(dataBytes, keyBytes, { lowS: true });
197
- sigBytes = sig.toCompactRawBytes();
195
+ case 'secp256k1':
196
+ sigBytes = secp256k1.sign(dataBytes, keyBytes, { lowS: true });
198
197
  break;
199
- }
200
- case 'p256': {
201
- const sig = p256.sign(dataBytes, keyBytes, { lowS: true });
202
- sigBytes = sig.toCompactRawBytes();
198
+ case 'p256':
199
+ sigBytes = p256.sign(dataBytes, keyBytes, { lowS: true });
203
200
  break;
204
- }
205
- case 'ed25519': {
201
+ case 'ed25519':
206
202
  sigBytes = ed25519.sign(dataBytes, keyBytes);
207
203
  break;
208
- }
209
204
  default:
210
205
  throw new Error(`Unsupported curve: ${curve}`);
211
206
  }
@@ -288,13 +283,13 @@ export function generatePrivateKey(curve: CurveType = 'secp256k1', encoding: Enc
288
283
 
289
284
  switch (curve) {
290
285
  case 'secp256k1':
291
- keyBytes = secp256k1.utils.randomPrivateKey();
286
+ keyBytes = secp256k1.utils.randomSecretKey();
292
287
  break;
293
288
  case 'p256':
294
- keyBytes = p256.utils.randomPrivateKey();
289
+ keyBytes = p256.utils.randomSecretKey();
295
290
  break;
296
291
  case 'ed25519':
297
- keyBytes = ed25519.utils.randomPrivateKey();
292
+ keyBytes = ed25519.utils.randomSecretKey();
298
293
  break;
299
294
  default:
300
295
  throw new Error(`Unsupported curve: ${curve}`);
package/src/digest.ts CHANGED
@@ -6,10 +6,10 @@
6
6
  * Compatible with React Native and all JS environments.
7
7
  */
8
8
 
9
- import { sha256 } from '@noble/hashes/sha2';
10
- import { sha512 } from '@noble/hashes/sha2';
11
- import { blake3 } from '@noble/hashes/blake3';
12
- import { concatBytes, utf8ToBytes } from '@noble/hashes/utils';
9
+ import { sha256 } from '@noble/hashes/sha2.js';
10
+ import { sha512 } from '@noble/hashes/sha2.js';
11
+ import { blake3 } from '@noble/hashes/blake3.js';
12
+ import { concatBytes, utf8ToBytes } from '@noble/hashes/utils.js';
13
13
 
14
14
  /**
15
15
  * Hash algorithm options
package/src/plugin.ts CHANGED
@@ -1,88 +1,93 @@
1
- /**
2
- * Quereus Plugin Entry Point for Crypto Functions
3
- *
4
- * This module provides the plugin registration following Quereus 0.4.5 format.
5
- * All metadata is in package.json - no manifest export needed.
6
- */
7
-
8
- import type { Database, FunctionFlags, SqlValue } from '@quereus/quereus';
9
- import { TEXT_TYPE, INTEGER_TYPE, BOOLEAN_TYPE } from '@quereus/quereus';
10
- import { digest, sign, verify, hashMod, randomBytes } from './crypto.js';
11
-
12
- /**
13
- * Plugin registration function
14
- * This is called by Quereus when the plugin is loaded
15
- */
16
- export default function register(_db: Database, _config: Record<string, SqlValue> = {}) {
17
- // Register crypto functions with Quereus
18
- const functions = [
19
- {
20
- schema: {
21
- name: 'digest',
22
- numArgs: -1, // Variable arguments: data, algorithm?, inputEncoding?, outputEncoding?
23
- flags: 1 as FunctionFlags, // UTF8
24
- returnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },
25
- implementation: (...args: SqlValue[]) => {
26
- const [data, algorithm = 'sha256', inputEncoding = 'base64url', outputEncoding = 'base64url'] = args;
27
- return digest(data as string, algorithm as any, inputEncoding as any, outputEncoding as any);
28
- },
29
- },
30
- },
31
- {
32
- schema: {
33
- name: 'sign',
34
- numArgs: -1, // Variable arguments: data, privateKey, curve?, inputEncoding?, keyEncoding?, outputEncoding?
35
- flags: 1 as FunctionFlags,
36
- returnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },
37
- implementation: (...args: SqlValue[]) => {
38
- const [data, privateKey, curve = 'secp256k1', inputEncoding = 'base64url', keyEncoding = 'base64url', outputEncoding = 'base64url'] = args;
39
- return sign(data as string, privateKey as string, curve as any, inputEncoding as any, keyEncoding as any, outputEncoding as any);
40
- },
41
- },
42
- },
43
- {
44
- schema: {
45
- name: 'verify',
46
- numArgs: -1, // Variable arguments: data, signature, publicKey, curve?, inputEncoding?, sigEncoding?, keyEncoding?
47
- flags: 1 as FunctionFlags,
48
- returnType: { typeClass: 'scalar' as const, logicalType: BOOLEAN_TYPE, nullable: false },
49
- implementation: (...args: SqlValue[]) => {
50
- const [data, signature, publicKey, curve = 'secp256k1', inputEncoding = 'base64url', sigEncoding = 'base64url', keyEncoding = 'base64url'] = args;
51
- const result = verify(data as string, signature as string, publicKey as string, curve as any, inputEncoding as any, sigEncoding as any, keyEncoding as any);
52
- return result;
53
- },
54
- },
55
- },
56
- {
57
- schema: {
58
- name: 'hash_mod',
59
- numArgs: -1, // Variable arguments: data, bits, algorithm?, inputEncoding?
60
- flags: 1 as FunctionFlags,
61
- returnType: { typeClass: 'scalar' as const, logicalType: INTEGER_TYPE, nullable: false },
62
- implementation: (...args: SqlValue[]) => {
63
- const [data, bits, algorithm = 'sha256', inputEncoding = 'base64url'] = args;
64
- return hashMod(data as string, bits as number, algorithm as any, inputEncoding as any);
65
- },
66
- },
67
- },
68
- {
69
- schema: {
70
- name: 'random_bytes',
71
- numArgs: -1, // Variable arguments: bits?, encoding?
72
- flags: 1 as FunctionFlags,
73
- returnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },
74
- implementation: (...args: SqlValue[]) => {
75
- const [bits = 256, encoding = 'base64url'] = args;
76
- return randomBytes(bits as number, encoding as any);
77
- },
78
- },
79
- },
80
- ];
81
-
82
- return {
83
- functions,
84
- vtables: [],
85
- collations: [],
86
- };
87
- }
88
-
1
+ /**
2
+ * Quereus Plugin Entry Point for Crypto Functions
3
+ *
4
+ * This module provides the plugin registration following Quereus 0.4.5 format.
5
+ * All metadata is in package.json - no manifest export needed.
6
+ */
7
+
8
+ import type { Database, SqlValue } from '@quereus/quereus';
9
+ import { FunctionFlags, TEXT_TYPE, INTEGER_TYPE, BOOLEAN_TYPE } from '@quereus/quereus';
10
+ import { digest, sign, verify, hashMod, randomBytes } from './crypto.js';
11
+
12
+ // Flags for deterministic functions (UTF8 + DETERMINISTIC)
13
+ const DETERMINISTIC_FLAGS = FunctionFlags.UTF8 | FunctionFlags.DETERMINISTIC;
14
+ // Flags for non-deterministic functions (UTF8 only)
15
+ const NON_DETERMINISTIC_FLAGS = FunctionFlags.UTF8;
16
+
17
+ /**
18
+ * Plugin registration function
19
+ * This is called by Quereus when the plugin is loaded
20
+ */
21
+ export default function register(_db: Database, _config: Record<string, SqlValue> = {}) {
22
+ // Register crypto functions with Quereus
23
+ const functions = [
24
+ {
25
+ schema: {
26
+ name: 'digest',
27
+ numArgs: -1, // Variable arguments: data, algorithm?, inputEncoding?, outputEncoding?
28
+ flags: DETERMINISTIC_FLAGS, // digest is deterministic
29
+ returnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },
30
+ implementation: (...args: SqlValue[]) => {
31
+ const [data, algorithm = 'sha256', inputEncoding = 'base64url', outputEncoding = 'base64url'] = args;
32
+ return digest(data as string, algorithm as any, inputEncoding as any, outputEncoding as any);
33
+ },
34
+ },
35
+ },
36
+ {
37
+ schema: {
38
+ name: 'sign',
39
+ numArgs: -1, // Variable arguments: data, privateKey, curve?, inputEncoding?, keyEncoding?, outputEncoding?
40
+ flags: DETERMINISTIC_FLAGS, // sign is deterministic (same key + data = same signature)
41
+ returnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },
42
+ implementation: (...args: SqlValue[]) => {
43
+ const [data, privateKey, curve = 'secp256k1', inputEncoding = 'base64url', keyEncoding = 'base64url', outputEncoding = 'base64url'] = args;
44
+ return sign(data as string, privateKey as string, curve as any, inputEncoding as any, keyEncoding as any, outputEncoding as any);
45
+ },
46
+ },
47
+ },
48
+ {
49
+ schema: {
50
+ name: 'verify',
51
+ numArgs: -1, // Variable arguments: data, signature, publicKey, curve?, inputEncoding?, sigEncoding?, keyEncoding?
52
+ flags: DETERMINISTIC_FLAGS, // verify is deterministic
53
+ returnType: { typeClass: 'scalar' as const, logicalType: BOOLEAN_TYPE, nullable: false },
54
+ implementation: (...args: SqlValue[]) => {
55
+ const [data, signature, publicKey, curve = 'secp256k1', inputEncoding = 'base64url', sigEncoding = 'base64url', keyEncoding = 'base64url'] = args;
56
+ const result = verify(data as string, signature as string, publicKey as string, curve as any, inputEncoding as any, sigEncoding as any, keyEncoding as any);
57
+ return result;
58
+ },
59
+ },
60
+ },
61
+ {
62
+ schema: {
63
+ name: 'hash_mod',
64
+ numArgs: -1, // Variable arguments: data, bits, algorithm?, inputEncoding?
65
+ flags: DETERMINISTIC_FLAGS, // hash_mod is deterministic
66
+ returnType: { typeClass: 'scalar' as const, logicalType: INTEGER_TYPE, nullable: false },
67
+ implementation: (...args: SqlValue[]) => {
68
+ const [data, bits, algorithm = 'sha256', inputEncoding = 'base64url'] = args;
69
+ return hashMod(data as string, bits as number, algorithm as any, inputEncoding as any);
70
+ },
71
+ },
72
+ },
73
+ {
74
+ schema: {
75
+ name: 'random_bytes',
76
+ numArgs: -1, // Variable arguments: bits?, encoding?
77
+ flags: NON_DETERMINISTIC_FLAGS, // random_bytes is NOT deterministic
78
+ returnType: { typeClass: 'scalar' as const, logicalType: TEXT_TYPE, nullable: false },
79
+ implementation: (...args: SqlValue[]) => {
80
+ const [bits = 256, encoding = 'base64url'] = args;
81
+ return randomBytes(bits as number, encoding as any);
82
+ },
83
+ },
84
+ },
85
+ ];
86
+
87
+ return {
88
+ functions,
89
+ vtables: [],
90
+ collations: [],
91
+ };
92
+ }
93
+
package/src/sign.ts CHANGED
@@ -6,10 +6,10 @@
6
6
  * Compatible with React Native and all JS environments.
7
7
  */
8
8
 
9
- import { secp256k1 } from '@noble/curves/secp256k1';
10
- import { p256 } from '@noble/curves/nist';
11
- import { ed25519 } from '@noble/curves/ed25519';
12
- import { bytesToHex, hexToBytes } from '@noble/curves/abstract/utils';
9
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
10
+ import { p256 } from '@noble/curves/nist.js';
11
+ import { ed25519 } from '@noble/curves/ed25519.js';
12
+ import { bytesToHex, hexToBytes } from '@noble/curves/utils.js';
13
13
 
14
14
  /**
15
15
  * Supported elliptic curve types
@@ -83,35 +83,25 @@ function normalizeDigest(digest: DigestInput): Uint8Array {
83
83
  }
84
84
 
85
85
  /**
86
- * Format signature based on requested format
86
+ * Format signature based on requested format.
87
+ * In @noble/curves v2.0.1, sign() returns Uint8Array directly.
87
88
  */
88
- function formatSignature(signature: any, format: SignatureFormat, curve: CurveType): Uint8Array | string {
89
+ function formatSignature(signature: Uint8Array, format: SignatureFormat, curve: CurveType): Uint8Array | string {
89
90
  switch (format) {
90
91
  case 'uint8array':
91
- if (curve === 'ed25519') {
92
- return signature;
93
- }
94
- return signature.toCompactRawBytes();
92
+ case 'compact':
93
+ return signature;
95
94
 
96
95
  case 'hex':
97
- if (curve === 'ed25519') {
98
- return bytesToHex(signature);
99
- }
100
- return signature.toCompactHex();
101
-
102
- case 'compact':
103
- if (curve === 'ed25519') {
104
- return signature;
105
- }
106
- return signature.toCompactRawBytes();
96
+ return bytesToHex(signature);
107
97
 
108
98
  case 'der':
109
99
  if (curve === 'ed25519') {
110
100
  throw new Error('DER format not supported for ed25519');
111
101
  }
112
- // Note: DER encoding would require additional implementation
113
- // For now, fall back to compact
114
- return signature.toCompactRawBytes();
102
+ // DER format requires the sign() call to request it via format option
103
+ // For now, return compact format as fallback
104
+ return signature;
115
105
 
116
106
  default:
117
107
  throw new Error(`Unsupported signature format: ${format}`);
@@ -214,11 +204,11 @@ Sign.ed25519 = (digest: DigestInput, privateKey: PrivateKeyInput, options: Omit<
214
204
  Sign.generatePrivateKey = (curve: CurveType = 'secp256k1'): Uint8Array => {
215
205
  switch (curve) {
216
206
  case 'secp256k1':
217
- return secp256k1.utils.randomPrivateKey();
207
+ return secp256k1.utils.randomSecretKey();
218
208
  case 'p256':
219
- return p256.utils.randomPrivateKey();
209
+ return p256.utils.randomSecretKey();
220
210
  case 'ed25519':
221
- return ed25519.utils.randomPrivateKey();
211
+ return ed25519.utils.randomSecretKey();
222
212
  default:
223
213
  throw new Error(`Unsupported curve: ${curve}`);
224
214
  }
@@ -6,10 +6,10 @@
6
6
  * Compatible with React Native and all JS environments.
7
7
  */
8
8
 
9
- import { secp256k1 } from '@noble/curves/secp256k1';
10
- import { p256 } from '@noble/curves/nist';
11
- import { ed25519 } from '@noble/curves/ed25519';
12
- import { hexToBytes } from '@noble/curves/abstract/utils';
9
+ import { secp256k1 } from '@noble/curves/secp256k1.js';
10
+ import { p256 } from '@noble/curves/nist.js';
11
+ import { ed25519 } from '@noble/curves/ed25519.js';
12
+ import { hexToBytes } from '@noble/curves/utils.js';
13
13
 
14
14
  /**
15
15
  * Supported elliptic curve types
@@ -72,40 +72,23 @@ function detectSignatureFormat(signature: Uint8Array, curve: CurveType): 'compac
72
72
  }
73
73
 
74
74
  /**
75
- * Parse signature based on format and curve
75
+ * Parse signature based on format and curve.
76
+ * In @noble/curves v2.0.1, uses Signature.fromBytes(bytes, format).
76
77
  */
77
- function parseSignature(signature: Uint8Array, format: 'compact' | 'der' | 'raw', curve: CurveType): any {
78
+ function parseSignature(signature: Uint8Array, format: 'compact' | 'der' | 'raw', curve: CurveType): Uint8Array {
78
79
  if (curve === 'ed25519') {
79
80
  // Ed25519 signatures are always raw 64-byte format
80
81
  return signature;
81
82
  }
82
83
 
83
- // For ECDSA curves
84
- switch (format) {
85
- case 'compact':
86
- if (curve === 'secp256k1') {
87
- return secp256k1.Signature.fromCompact(signature);
88
- } else if (curve === 'p256') {
89
- return p256.Signature.fromCompact(signature);
90
- }
91
- break;
92
-
93
- case 'der':
94
- if (curve === 'secp256k1') {
95
- return secp256k1.Signature.fromDER(signature);
96
- } else if (curve === 'p256') {
97
- return p256.Signature.fromDER(signature);
98
- }
99
- break;
100
-
101
- case 'raw':
102
- // Treat as compact for ECDSA
103
- if (curve === 'secp256k1') {
104
- return secp256k1.Signature.fromCompact(signature);
105
- } else if (curve === 'p256') {
106
- return p256.Signature.fromCompact(signature);
107
- }
108
- break;
84
+ // For ECDSA curves in v2.0.1, verify() accepts raw bytes directly
85
+ // The format parameter is used to parse signature bytes into the expected format
86
+ const sigFormat = format === 'raw' ? 'compact' : format;
87
+
88
+ if (curve === 'secp256k1') {
89
+ return secp256k1.Signature.fromBytes(signature, sigFormat).toBytes();
90
+ } else if (curve === 'p256') {
91
+ return p256.Signature.fromBytes(signature, sigFormat).toBytes();
109
92
  }
110
93
 
111
94
  throw new Error(`Failed to parse signature for curve ${curve} with format ${format}`);