@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/README.md +279 -279
- package/dist/index.js +27 -59
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +4 -4
- package/dist/plugin.js +25 -24
- package/dist/plugin.js.map +1 -1
- package/package.json +82 -70
- package/src/crypto.ts +15 -20
- package/src/digest.ts +4 -4
- package/src/plugin.ts +93 -88
- package/src/sign.ts +16 -26
- package/src/signature-valid.ts +15 -32
package/package.json
CHANGED
|
@@ -1,71 +1,83 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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/
|
|
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
|
-
|
|
197
|
-
sigBytes = sig.toCompactRawBytes();
|
|
195
|
+
case 'secp256k1':
|
|
196
|
+
sigBytes = secp256k1.sign(dataBytes, keyBytes, { lowS: true });
|
|
198
197
|
break;
|
|
199
|
-
|
|
200
|
-
|
|
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.
|
|
286
|
+
keyBytes = secp256k1.utils.randomSecretKey();
|
|
292
287
|
break;
|
|
293
288
|
case 'p256':
|
|
294
|
-
keyBytes = p256.utils.
|
|
289
|
+
keyBytes = p256.utils.randomSecretKey();
|
|
295
290
|
break;
|
|
296
291
|
case 'ed25519':
|
|
297
|
-
keyBytes = ed25519.utils.
|
|
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,
|
|
9
|
-
import { TEXT_TYPE, INTEGER_TYPE, BOOLEAN_TYPE } from '@quereus/quereus';
|
|
10
|
-
import { digest, sign, verify, hashMod, randomBytes } from './crypto.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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/
|
|
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:
|
|
89
|
+
function formatSignature(signature: Uint8Array, format: SignatureFormat, curve: CurveType): Uint8Array | string {
|
|
89
90
|
switch (format) {
|
|
90
91
|
case 'uint8array':
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
return signature.toCompactRawBytes();
|
|
92
|
+
case 'compact':
|
|
93
|
+
return signature;
|
|
95
94
|
|
|
96
95
|
case 'hex':
|
|
97
|
-
|
|
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
|
-
//
|
|
113
|
-
// For now,
|
|
114
|
-
return signature
|
|
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.
|
|
207
|
+
return secp256k1.utils.randomSecretKey();
|
|
218
208
|
case 'p256':
|
|
219
|
-
return p256.utils.
|
|
209
|
+
return p256.utils.randomSecretKey();
|
|
220
210
|
case 'ed25519':
|
|
221
|
-
return ed25519.utils.
|
|
211
|
+
return ed25519.utils.randomSecretKey();
|
|
222
212
|
default:
|
|
223
213
|
throw new Error(`Unsupported curve: ${curve}`);
|
|
224
214
|
}
|
package/src/signature-valid.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 { hexToBytes } from '@noble/curves/
|
|
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):
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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}`);
|