@optimystic/quereus-plugin-crypto 0.13.5 → 0.16.2

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.
@@ -1,262 +0,0 @@
1
- /**
2
- * SignatureValid Function for Quereus
3
- *
4
- * Returns true if the ECC signature is valid for the given digest and public key.
5
- * Uses @noble/curves for portable implementation.
6
- * Compatible with React Native and all JS environments.
7
- */
8
-
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
-
14
- /**
15
- * Supported elliptic curve types
16
- */
17
- export type CurveType = 'secp256k1' | 'p256' | 'ed25519';
18
-
19
- /**
20
- * Input types that can be Uint8Array or hex string
21
- */
22
- export type BytesInput = Uint8Array | string;
23
-
24
- /**
25
- * Options for signature verification
26
- */
27
- export interface VerifyOptions {
28
- /** Elliptic curve to use (default: secp256k1) */
29
- curve?: CurveType;
30
- /** Signature format (default: auto-detect) */
31
- signatureFormat?: 'compact' | 'der' | 'raw';
32
- /** Allow malleable signatures (default: false for ECDSA, true for EdDSA) */
33
- allowMalleableSignatures?: boolean;
34
- }
35
-
36
- /**
37
- * Normalize input to Uint8Array
38
- */
39
- function normalizeBytes(input: BytesInput): Uint8Array {
40
- if (input instanceof Uint8Array) {
41
- return input;
42
- }
43
-
44
- if (typeof input === 'string') {
45
- return hexToBytes(input);
46
- }
47
-
48
- throw new Error('Invalid input format - expected Uint8Array or hex string');
49
- }
50
-
51
- /**
52
- * Auto-detect signature format based on length and curve
53
- */
54
- function detectSignatureFormat(signature: Uint8Array, curve: CurveType): 'compact' | 'der' | 'raw' {
55
- const length = signature.length;
56
-
57
- if (curve === 'ed25519') {
58
- return 'raw'; // Ed25519 signatures are always 64 bytes
59
- }
60
-
61
- // For ECDSA curves (secp256k1, p256)
62
- if (length === 64) {
63
- return 'compact'; // r + s concatenated (32 + 32 bytes)
64
- }
65
-
66
- if (length >= 70 && length <= 72 && signature[0] === 0x30) {
67
- return 'der'; // DER encoding starts with 0x30
68
- }
69
-
70
- // Default to compact for shorter signatures
71
- return 'compact';
72
- }
73
-
74
- /**
75
- * Parse signature based on format and curve.
76
- * In @noble/curves v2.0.1, uses Signature.fromBytes(bytes, format).
77
- */
78
- function parseSignature(signature: Uint8Array, format: 'compact' | 'der' | 'raw', curve: CurveType): Uint8Array {
79
- if (curve === 'ed25519') {
80
- // Ed25519 signatures are always raw 64-byte format
81
- return signature;
82
- }
83
-
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();
92
- }
93
-
94
- throw new Error(`Failed to parse signature for curve ${curve} with format ${format}`);
95
- }
96
-
97
- /**
98
- * Verify if an ECC signature is valid
99
- *
100
- * @param {BytesInput} digest - The digest/hash that was signed
101
- * @param {BytesInput} signature - The signature to verify
102
- * @param {BytesInput} publicKey - The public key to verify against
103
- * @param {VerifyOptions} [options] - Optional verification parameters
104
- * @returns {boolean} True if the signature is valid, false otherwise
105
- *
106
- * @example
107
- * ```typescript
108
- * // Basic usage with secp256k1
109
- * const isValid = SignatureValid(digest, signature, publicKey);
110
- *
111
- * // With specific curve
112
- * const isValid = SignatureValid(digest, signature, publicKey, {
113
- * curve: 'p256'
114
- * });
115
- *
116
- * // With specific signature format
117
- * const isValid = SignatureValid(digest, signature, publicKey, {
118
- * curve: 'secp256k1',
119
- * signatureFormat: 'der'
120
- * });
121
- *
122
- * // Allow malleable signatures
123
- * const isValid = SignatureValid(digest, signature, publicKey, {
124
- * allowMalleableSignatures: true
125
- * });
126
- * ```
127
- */
128
- export function SignatureValid(
129
- digest: BytesInput,
130
- signature: BytesInput,
131
- publicKey: BytesInput,
132
- options: VerifyOptions = {}
133
- ): boolean {
134
- try {
135
- const {
136
- curve = 'secp256k1',
137
- signatureFormat,
138
- allowMalleableSignatures,
139
- } = options;
140
-
141
- const normalizedDigest = normalizeBytes(digest);
142
- const normalizedSignature = normalizeBytes(signature);
143
- const normalizedPublicKey = normalizeBytes(publicKey);
144
-
145
- // Auto-detect signature format if not specified
146
- const detectedFormat = signatureFormat || detectSignatureFormat(normalizedSignature, curve);
147
-
148
- // Parse the signature
149
- const parsedSignature = parseSignature(normalizedSignature, detectedFormat, curve);
150
-
151
- // Set up verification options
152
- const verifyOptions: any = {};
153
-
154
- // Handle malleable signatures for ECDSA curves
155
- if (curve !== 'ed25519' && allowMalleableSignatures !== undefined) {
156
- verifyOptions.lowS = !allowMalleableSignatures;
157
- }
158
-
159
- // Verify the signature
160
- switch (curve) {
161
- case 'secp256k1':
162
- return secp256k1.verify(parsedSignature, normalizedDigest, normalizedPublicKey, verifyOptions);
163
-
164
- case 'p256':
165
- return p256.verify(parsedSignature, normalizedDigest, normalizedPublicKey, verifyOptions);
166
-
167
- case 'ed25519':
168
- return ed25519.verify(parsedSignature, normalizedDigest, normalizedPublicKey);
169
-
170
- default:
171
- throw new Error(`Unsupported curve: ${curve}`);
172
- }
173
- } catch (error) {
174
- // If any error occurs during verification, the signature is invalid
175
- return false;
176
- }
177
- }
178
-
179
- /**
180
- * Convenience functions for specific curves
181
- */
182
- SignatureValid.secp256k1 = (
183
- digest: BytesInput,
184
- signature: BytesInput,
185
- publicKey: BytesInput,
186
- options: Omit<VerifyOptions, 'curve'> = {}
187
- ): boolean => {
188
- return SignatureValid(digest, signature, publicKey, { ...options, curve: 'secp256k1' });
189
- };
190
-
191
- SignatureValid.p256 = (
192
- digest: BytesInput,
193
- signature: BytesInput,
194
- publicKey: BytesInput,
195
- options: Omit<VerifyOptions, 'curve'> = {}
196
- ): boolean => {
197
- return SignatureValid(digest, signature, publicKey, { ...options, curve: 'p256' });
198
- };
199
-
200
- SignatureValid.ed25519 = (
201
- digest: BytesInput,
202
- signature: BytesInput,
203
- publicKey: BytesInput,
204
- options: Omit<VerifyOptions, 'curve'> = {}
205
- ): boolean => {
206
- return SignatureValid(digest, signature, publicKey, { ...options, curve: 'ed25519' });
207
- };
208
-
209
- /**
210
- * Batch verify multiple signatures (more efficient for multiple verifications)
211
- */
212
- SignatureValid.batch = (
213
- verifications: Array<{
214
- digest: BytesInput;
215
- signature: BytesInput;
216
- publicKey: BytesInput;
217
- options?: VerifyOptions;
218
- }>
219
- ): boolean[] => {
220
- return verifications.map(({ digest, signature, publicKey, options }) =>
221
- SignatureValid(digest, signature, publicKey, options)
222
- );
223
- };
224
-
225
- /**
226
- * Verify and return detailed information about the verification
227
- */
228
- SignatureValid.detailed = (
229
- digest: BytesInput,
230
- signature: BytesInput,
231
- publicKey: BytesInput,
232
- options: VerifyOptions = {}
233
- ): {
234
- valid: boolean;
235
- curve: CurveType;
236
- signatureFormat: string;
237
- error?: string;
238
- } => {
239
- const curve = options.curve || 'secp256k1';
240
-
241
- try {
242
- const normalizedSignature = normalizeBytes(signature);
243
- const detectedFormat = options.signatureFormat || detectSignatureFormat(normalizedSignature, curve);
244
-
245
- const valid = SignatureValid(digest, signature, publicKey, options);
246
-
247
- return {
248
- valid,
249
- curve,
250
- signatureFormat: detectedFormat,
251
- };
252
- } catch (error) {
253
- return {
254
- valid: false,
255
- curve,
256
- signatureFormat: 'unknown',
257
- error: error instanceof Error ? error.message : 'Unknown error',
258
- };
259
- }
260
- };
261
-
262
- export default SignatureValid;