@did-btcr2/keypair 0.7.2 → 0.8.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.
- package/dist/cjs/pair.js +34 -32
- package/dist/cjs/pair.js.map +1 -1
- package/dist/cjs/public.js +79 -64
- package/dist/cjs/public.js.map +1 -1
- package/dist/cjs/secret.js +4 -4
- package/dist/cjs/secret.js.map +1 -1
- package/dist/esm/pair.js +34 -32
- package/dist/esm/pair.js.map +1 -1
- package/dist/esm/public.js +79 -64
- package/dist/esm/public.js.map +1 -1
- package/dist/esm/secret.js +4 -4
- package/dist/esm/secret.js.map +1 -1
- package/dist/types/pair.d.ts +9 -20
- package/dist/types/pair.d.ts.map +1 -1
- package/dist/types/public.d.ts +27 -21
- package/dist/types/public.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/pair.ts +43 -46
- package/src/public.ts +99 -84
- package/src/secret.ts +4 -4
package/src/pair.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Hex,
|
|
3
|
+
HexString,
|
|
3
4
|
KeyBytes,
|
|
4
5
|
KeyPairError,
|
|
5
6
|
SchnorrKeyPairObject
|
|
6
7
|
} from '@did-btcr2/common';
|
|
7
|
-
import { CompressedSecp256k1PublicKey } from './public.js';
|
|
8
|
-
import { Secp256k1SecretKey } from './secret.js';
|
|
8
|
+
import { CompressedSecp256k1PublicKey, PublicKey } from './public.js';
|
|
9
|
+
import { Secp256k1SecretKey, SecretKey } from './secret.js';
|
|
9
10
|
import { HexSchnorrKeyPair, MultibaseKeys, RawSchnorrKeyPair, SchnorrKeyPairParams } from './types.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -15,21 +16,15 @@ import { HexSchnorrKeyPair, MultibaseKeys, RawSchnorrKeyPair, SchnorrKeyPairPara
|
|
|
15
16
|
*/
|
|
16
17
|
export interface KeyPair {
|
|
17
18
|
/**
|
|
18
|
-
* @type {
|
|
19
|
+
* @type {PublicKey} The public key associated with the SchnorrKeyPair (required).
|
|
19
20
|
*/
|
|
20
|
-
readonly publicKey:
|
|
21
|
+
readonly publicKey: PublicKey;
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
* @type {
|
|
24
|
+
* @type {SecretKey} The secret key associated with the SchnorrKeyPair (optional).
|
|
24
25
|
* @throws {KeyPairError} If the secret key is not available.
|
|
25
26
|
*/
|
|
26
|
-
readonly secretKey?:
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* JSON representation of the SchnorrKeyPair object.
|
|
30
|
-
* @returns {SchnorrKeyPairObject} The SchnorrKeyPair as a JSON object.
|
|
31
|
-
*/
|
|
32
|
-
json(): SchnorrKeyPairObject;
|
|
27
|
+
readonly secretKey?: SecretKey;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
/**
|
|
@@ -39,16 +34,16 @@ export interface KeyPair {
|
|
|
39
34
|
*/
|
|
40
35
|
export class SchnorrKeyPair implements KeyPair {
|
|
41
36
|
/** @type {Secp256k1SecretKey} The secret key object */
|
|
42
|
-
|
|
37
|
+
#secretKey?: Secp256k1SecretKey;
|
|
43
38
|
|
|
44
39
|
/** @type {CompressedSecp256k1PublicKey} The public key object */;
|
|
45
|
-
|
|
40
|
+
#publicKey: CompressedSecp256k1PublicKey;
|
|
46
41
|
|
|
47
42
|
/** @type {string} The public key in multibase format */
|
|
48
|
-
|
|
43
|
+
#publicKeyMultibase: string;
|
|
49
44
|
|
|
50
45
|
/** @type {string} The secret key in multibase format */
|
|
51
|
-
|
|
46
|
+
#secretKeyMultibase: string;
|
|
52
47
|
|
|
53
48
|
/**
|
|
54
49
|
* Creates an instance of Keys. Must provide a at least a secret key.
|
|
@@ -67,22 +62,22 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
67
62
|
|
|
68
63
|
// Set the secretKey
|
|
69
64
|
if(params.secretKey instanceof Uint8Array) {
|
|
70
|
-
this
|
|
65
|
+
this.#secretKey = new Secp256k1SecretKey(params.secretKey);
|
|
71
66
|
} else if (params.secretKey instanceof Secp256k1SecretKey) {
|
|
72
|
-
this
|
|
67
|
+
this.#secretKey = params.secretKey;
|
|
73
68
|
}
|
|
74
69
|
|
|
75
70
|
// Set the publicKey
|
|
76
71
|
if(params.publicKey instanceof CompressedSecp256k1PublicKey) {
|
|
77
|
-
this
|
|
72
|
+
this.#publicKey = params.publicKey;
|
|
78
73
|
} else if (params.publicKey instanceof Uint8Array) {
|
|
79
|
-
this
|
|
74
|
+
this.#publicKey = new CompressedSecp256k1PublicKey(params.publicKey);
|
|
80
75
|
} else {
|
|
81
|
-
this
|
|
76
|
+
this.#publicKey = this.#secretKey!.computePublicKey();
|
|
82
77
|
}
|
|
83
78
|
|
|
84
|
-
this
|
|
85
|
-
this
|
|
79
|
+
this.#publicKeyMultibase = this.#publicKey.multibase.encoded;
|
|
80
|
+
this.#secretKeyMultibase = this.#secretKey ? this.#secretKey.multibase : '';
|
|
86
81
|
}
|
|
87
82
|
|
|
88
83
|
/**
|
|
@@ -92,15 +87,15 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
92
87
|
*/
|
|
93
88
|
get secretKey(): Secp256k1SecretKey {
|
|
94
89
|
// If the secret key is not available, throw an error
|
|
95
|
-
if(!this
|
|
90
|
+
if(!this.#secretKey) {
|
|
96
91
|
throw new KeyPairError('Secret key not available', 'SECRET_KEY_ERROR');
|
|
97
92
|
}
|
|
98
93
|
// If the secret key is not valid, throw an error
|
|
99
|
-
if(!this.
|
|
94
|
+
if(!this.#secretKey.isValid()) {
|
|
100
95
|
throw new KeyPairError('Secret key is not valid', 'SECRET_KEY_ERROR');
|
|
101
96
|
}
|
|
102
97
|
// Return a copy of the secret key
|
|
103
|
-
const secret = this
|
|
98
|
+
const secret = this.#secretKey;
|
|
104
99
|
return secret;
|
|
105
100
|
}
|
|
106
101
|
|
|
@@ -119,9 +114,9 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
119
114
|
if(!publicKey.equals(cPk))
|
|
120
115
|
throw new KeyPairError('Public key is not a valid pair with the secret key', 'PUBLIC_KEY_ERROR');
|
|
121
116
|
}
|
|
122
|
-
this
|
|
123
|
-
this
|
|
124
|
-
this
|
|
117
|
+
this.#publicKey = publicKey;
|
|
118
|
+
this.#publicKeyMultibase = publicKey.multibase.encoded;
|
|
119
|
+
this.#secretKeyMultibase = this.#secretKey ? this.#secretKey.multibase : '';
|
|
125
120
|
}
|
|
126
121
|
|
|
127
122
|
/**
|
|
@@ -129,7 +124,7 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
129
124
|
* @returns {CompressedSecp256k1PublicKey} The CompressedSecp256k1PublicKey object
|
|
130
125
|
*/
|
|
131
126
|
get publicKey(): CompressedSecp256k1PublicKey {
|
|
132
|
-
const publicKey = this
|
|
127
|
+
const publicKey = this.#publicKey;
|
|
133
128
|
return publicKey;
|
|
134
129
|
}
|
|
135
130
|
|
|
@@ -151,7 +146,7 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
151
146
|
get hex(): HexSchnorrKeyPair {
|
|
152
147
|
return {
|
|
153
148
|
public : this.publicKey.hex,
|
|
154
|
-
secret : this
|
|
149
|
+
secret : this.#secretKey ? this.secretKey.hex : undefined
|
|
155
150
|
};
|
|
156
151
|
}
|
|
157
152
|
|
|
@@ -161,8 +156,8 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
161
156
|
*/
|
|
162
157
|
get multibase(): MultibaseKeys {
|
|
163
158
|
return {
|
|
164
|
-
publicKeyMultibase
|
|
165
|
-
secretKeyMultibase : this
|
|
159
|
+
publicKeyMultibase : this.#publicKeyMultibase,
|
|
160
|
+
secretKeyMultibase : this.#secretKeyMultibase,
|
|
166
161
|
};
|
|
167
162
|
}
|
|
168
163
|
|
|
@@ -194,24 +189,26 @@ export class SchnorrKeyPair implements KeyPair {
|
|
|
194
189
|
* @param {Secp256k1SecretKey | KeyBytes} data The secret key bytes
|
|
195
190
|
* @returns {SchnorrKeyPair} A new SchnorrKeyPair object
|
|
196
191
|
*/
|
|
197
|
-
public static
|
|
198
|
-
|
|
199
|
-
// If the
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
192
|
+
public static fromSecret(data: KeyBytes | HexString): SchnorrKeyPair {
|
|
193
|
+
|
|
194
|
+
// If the data is Secp256k1SecretKey object, get the raw bytes
|
|
195
|
+
// Else if data is string, convert to byte array
|
|
196
|
+
// Else must be bytes, use them
|
|
197
|
+
const secret = typeof data === 'string'
|
|
198
|
+
? Buffer.from(data, 'hex')
|
|
199
|
+
: data;
|
|
200
|
+
|
|
201
|
+
// Check the lenth
|
|
202
|
+
if(secret.length !== 32) {
|
|
203
|
+
throw new KeyPairError('Invalid arg: must be 32 byte secret key', 'FROM_SECRET_KEY_ERROR');
|
|
205
204
|
}
|
|
206
205
|
|
|
207
206
|
// If pk Uint8Array, construct Secp256k1SecretKey object else use the object
|
|
208
|
-
const
|
|
207
|
+
const secretKey = new Secp256k1SecretKey(secret);
|
|
208
|
+
const publicKey = secretKey.computePublicKey();
|
|
209
209
|
|
|
210
210
|
// Return a new Keys object
|
|
211
|
-
return new SchnorrKeyPair({
|
|
212
|
-
secretKey : data instanceof Uint8Array ? new Secp256k1SecretKey(data) : data,
|
|
213
|
-
publicKey : secret.computePublicKey()
|
|
214
|
-
});
|
|
211
|
+
return new SchnorrKeyPair({ secretKey, publicKey });
|
|
215
212
|
}
|
|
216
213
|
|
|
217
214
|
/**
|
package/src/public.ts
CHANGED
|
@@ -137,31 +137,32 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
139
|
* Creates a CompressedSecp256k1PublicKey instance.
|
|
140
|
-
* @param {Hex}
|
|
140
|
+
* @param {Hex} initialBytes The public key byte array.
|
|
141
141
|
* @throws {PublicKeyError} if the byte length is not 32 (x-only) or 33 (compressed)
|
|
142
142
|
*/
|
|
143
|
-
constructor(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
constructor(initialBytes: Hex) {
|
|
144
|
+
// Convert hex string to Uint8Array if necessary
|
|
145
|
+
const keyBytes = initialBytes instanceof Uint8Array
|
|
146
|
+
? initialBytes
|
|
147
|
+
: Uint8Array.from(Buffer.from(initialBytes, 'hex'));
|
|
147
148
|
|
|
148
149
|
// If the byte length is not 33, throw an error
|
|
149
|
-
if(!
|
|
150
|
+
if(!keyBytes || keyBytes.length !== 33) {
|
|
150
151
|
throw new PublicKeyError(
|
|
151
152
|
'Invalid argument: byte length must be 33 (compressed)',
|
|
152
|
-
'CONSTRUCTOR_ERROR', {
|
|
153
|
+
'CONSTRUCTOR_ERROR', { keyBytes }
|
|
153
154
|
);
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
// Validate the point is on curve and in compressed form
|
|
157
|
-
if (!tinysecp.isPoint(
|
|
158
|
+
if (!tinysecp.isPoint(keyBytes)) {
|
|
158
159
|
throw new PublicKeyError(
|
|
159
160
|
'Invalid argument: not a valid secp256k1 compressed point',
|
|
160
|
-
'CONSTRUCTOR_ERROR', {
|
|
161
|
+
'CONSTRUCTOR_ERROR', { keyBytes }
|
|
161
162
|
);
|
|
162
163
|
}
|
|
163
164
|
// Set the bytes
|
|
164
|
-
this.#bytes =
|
|
165
|
+
this.#bytes = keyBytes;
|
|
165
166
|
|
|
166
167
|
// Set multibase
|
|
167
168
|
this.#multibase.encoded = this.encode();
|
|
@@ -269,41 +270,15 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
269
270
|
* Returns the BIP-340 (x-only) representation of this key.
|
|
270
271
|
* @returns {KeyBytes} The BIP-340 (x-only) representation of the public key.
|
|
271
272
|
*/
|
|
272
|
-
|
|
273
|
+
bip340(): KeyBytes {
|
|
273
274
|
return this.xOnly;
|
|
274
275
|
}
|
|
275
276
|
|
|
276
|
-
/**
|
|
277
|
-
* Returns the point of the public key.
|
|
278
|
-
* @param {Hex} pk The public key in hex (Uint8Array or string) format.
|
|
279
|
-
* @returns {Point} The point of the public key.
|
|
280
|
-
* @throws {PublicKeyError} If the public key is not a valid hex string or byte array.
|
|
281
|
-
*/
|
|
282
|
-
public static point(pk: Hex): Point {
|
|
283
|
-
// If the public key is a hex string, convert it to a CompressedSecp256k1PublicKey object and return the point
|
|
284
|
-
if(typeof pk === 'string' && /^[0-9a-fA-F]+$/.test(pk)) {
|
|
285
|
-
const publicKey = new CompressedSecp256k1PublicKey(Buffer.fromHex(pk));
|
|
286
|
-
return publicKey.point;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// If the public key is a byte array or ArrayBuffer, convert it to a CompressedSecp256k1PublicKey object and return the point
|
|
290
|
-
if(pk instanceof Uint8Array || ArrayBuffer.isView(pk)) {
|
|
291
|
-
const publicKey = new CompressedSecp256k1PublicKey(pk as KeyBytes);
|
|
292
|
-
return publicKey.point;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// If the public key is neither a hex string nor a byte array, throw an error
|
|
296
|
-
throw new PublicKeyError(
|
|
297
|
-
'Invalid publicKey: must be a hex string or byte array',
|
|
298
|
-
'POINT_ERROR', { publicKey: pk }
|
|
299
|
-
);
|
|
300
|
-
}
|
|
301
|
-
|
|
302
277
|
/**
|
|
303
278
|
* Decodes the multibase string to the 35-byte corresponding public key (2 byte prefix + 32 byte public key).
|
|
304
279
|
* @returns {KeyBytes} The decoded public key: prefix and public key bytes
|
|
305
280
|
*/
|
|
306
|
-
|
|
281
|
+
decode(): KeyBytes {
|
|
307
282
|
// Decode the public key multibase string
|
|
308
283
|
const decoded = base58btc.decode(this.multibase.encoded);
|
|
309
284
|
|
|
@@ -337,9 +312,9 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
337
312
|
* Encodes compressed secp256k1 public key from bytes to BIP340 multibase format.
|
|
338
313
|
* @returns {string} The public key encoded in base-58-btc multibase format.
|
|
339
314
|
*/
|
|
340
|
-
|
|
315
|
+
encode(): string {
|
|
341
316
|
// Convert public key bytes to an array
|
|
342
|
-
const pk = this.compressed
|
|
317
|
+
const pk = Array.from(this.compressed);
|
|
343
318
|
|
|
344
319
|
// Ensure the public key is 33-byte secp256k1 compressed public key
|
|
345
320
|
if (pk.length !== 33) {
|
|
@@ -350,13 +325,13 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
350
325
|
}
|
|
351
326
|
|
|
352
327
|
// Convert prefix to an array
|
|
353
|
-
const publicKeyMultibase =
|
|
328
|
+
const publicKeyMultibase = Array.from(BIP340_PUBLIC_KEY_MULTIBASE_PREFIX);
|
|
354
329
|
|
|
355
330
|
// Push the public key bytes at the end of the prefix
|
|
356
331
|
publicKeyMultibase.push(...pk);
|
|
357
332
|
|
|
358
333
|
// Encode the bytes in base58btc format and return
|
|
359
|
-
return base58btc.encode(
|
|
334
|
+
return base58btc.encode(Uint8Array.from(publicKeyMultibase));
|
|
360
335
|
}
|
|
361
336
|
|
|
362
337
|
/**
|
|
@@ -367,7 +342,7 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
367
342
|
* @param {('ecdsa' | 'schnorr')} opts.scheme The signature scheme to use. Default is 'schnorr'.
|
|
368
343
|
* @returns {boolean} If the signature is valid against the public key.
|
|
369
344
|
*/
|
|
370
|
-
|
|
345
|
+
verify(signature: Bytes, data: Bytes, opts?: CryptoOptions): boolean {
|
|
371
346
|
opts ??= { scheme: 'schnorr' };
|
|
372
347
|
// Verify the signature depending on the scheme and return the result
|
|
373
348
|
if(opts.scheme === 'ecdsa') {
|
|
@@ -384,7 +359,7 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
384
359
|
* @param {CompressedSecp256k1PublicKey} other The other public key to compare
|
|
385
360
|
* @returns {boolean} True if the public keys are equal, false otherwise.
|
|
386
361
|
*/
|
|
387
|
-
|
|
362
|
+
equals(other: CompressedSecp256k1PublicKey): boolean {
|
|
388
363
|
return this.hex === other.hex;
|
|
389
364
|
}
|
|
390
365
|
|
|
@@ -392,51 +367,18 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
392
367
|
* JSON representation of a CompressedSecp256k1PublicKey object.
|
|
393
368
|
* @returns {PublicKeyObject} The CompressedSecp256k1PublicKey as a JSON object.
|
|
394
369
|
*/
|
|
395
|
-
|
|
370
|
+
json(): PublicKeyObject {
|
|
396
371
|
return {
|
|
397
372
|
hex : this.hex,
|
|
398
373
|
multibase : this.multibase,
|
|
399
374
|
point : {
|
|
400
|
-
x : this.x
|
|
401
|
-
y : this.y
|
|
375
|
+
x : Array.from(this.x),
|
|
376
|
+
y : Array.from(this.y),
|
|
402
377
|
parity : this.parity,
|
|
403
378
|
},
|
|
404
379
|
};
|
|
405
380
|
}
|
|
406
381
|
|
|
407
|
-
/**
|
|
408
|
-
* Creates a CompressedSecp256k1PublicKey object from a JSON representation.
|
|
409
|
-
* @param {PublicKeyObject} json The JSON object to initialize the CompressedSecp256k1PublicKey.
|
|
410
|
-
* @returns {CompressedSecp256k1PublicKey} The initialized CompressedSecp256k1PublicKey object.
|
|
411
|
-
*/
|
|
412
|
-
public static fromJSON(json: PublicKeyObject): CompressedSecp256k1PublicKey {
|
|
413
|
-
json.point.x.unshift(json.point.parity);
|
|
414
|
-
return new CompressedSecp256k1PublicKey(json.point.x.toUint8Array());
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Computes the deterministic public key for a given secret key.
|
|
419
|
-
* @param {Secp256k1SecretKey | KeyBytes} sk The Secp256k1SecretKey object or the secret key bytes
|
|
420
|
-
* @returns {CompressedSecp256k1PublicKey} A new CompressedSecp256k1PublicKey object
|
|
421
|
-
*/
|
|
422
|
-
public static fromSecretKey(sk: Secp256k1SecretKey | KeyBytes): CompressedSecp256k1PublicKey {
|
|
423
|
-
// If the secret key is a Secp256k1SecretKey object, get the raw bytes else use the bytes
|
|
424
|
-
const bytes = sk instanceof Secp256k1SecretKey ? sk.bytes : sk;
|
|
425
|
-
|
|
426
|
-
// Throw error if the secret key is not 32 bytes
|
|
427
|
-
if(bytes.length !== 32) {
|
|
428
|
-
throw new PublicKeyError('Invalid arg: must be 32 byte secret key', 'FROM_SECRET_KEY_ERROR');
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
// Compute the public key from the secret key
|
|
432
|
-
const secret = sk instanceof Secp256k1SecretKey
|
|
433
|
-
? sk
|
|
434
|
-
: new Secp256k1SecretKey(sk);
|
|
435
|
-
|
|
436
|
-
// Return a new CompressedSecp256k1PublicKey object
|
|
437
|
-
return secret.computePublicKey();
|
|
438
|
-
}
|
|
439
|
-
|
|
440
382
|
/**
|
|
441
383
|
* Computes modular exponentiation: (base^exp) % mod.
|
|
442
384
|
* Used for computing modular square roots.
|
|
@@ -445,7 +387,7 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
445
387
|
* @param {bigint} mod The modulus value
|
|
446
388
|
* @returns {bigint} The result of the modular exponentiation
|
|
447
389
|
*/
|
|
448
|
-
|
|
390
|
+
modPow(base: bigint, exp: bigint, mod: bigint): bigint {
|
|
449
391
|
let result = 1n;
|
|
450
392
|
while (exp > 0n) {
|
|
451
393
|
if (exp & 1n) result = (result * base) % mod;
|
|
@@ -462,7 +404,7 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
462
404
|
* @param {bigint} p The prime modulus
|
|
463
405
|
* @returns {bigint} The square root of `a` mod `p`
|
|
464
406
|
*/
|
|
465
|
-
|
|
407
|
+
sqrtMod(a: bigint, p: bigint): bigint {
|
|
466
408
|
return this.modPow(a, (p + 1n) >> 2n, p);
|
|
467
409
|
};
|
|
468
410
|
|
|
@@ -471,7 +413,7 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
471
413
|
* @param xBytes 32-byte x-coordinate
|
|
472
414
|
* @returns {Uint8Array} 65-byte uncompressed public key (starts with `0x04`)
|
|
473
415
|
*/
|
|
474
|
-
|
|
416
|
+
liftX(): Uint8Array {
|
|
475
417
|
// Ensure x-coordinate is 32 bytes
|
|
476
418
|
if (this.x.length !== 32) {
|
|
477
419
|
throw new PublicKeyError('Invalid argument: x-coordinate length must be 32 bytes', 'LIFT_X_ERROR');
|
|
@@ -490,9 +432,82 @@ export class CompressedSecp256k1PublicKey implements PublicKey {
|
|
|
490
432
|
const y = this.sqrtMod(ySquared, CURVE.p);
|
|
491
433
|
|
|
492
434
|
// Convert x and y to Uint8Array
|
|
493
|
-
const yBytes = Buffer.
|
|
435
|
+
const yBytes = Buffer.from(y.toString(16).padStart(64, '0'), 'hex');
|
|
494
436
|
|
|
495
437
|
// Return 65-byte uncompressed public key: `0x04 || x || y`
|
|
496
438
|
return new Uint8Array(Buffer.concat([Buffer.from([0x04]), Buffer.from(this.x), yBytes]));
|
|
497
439
|
};
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Static method to validate a public key.
|
|
443
|
+
* @param {Hex} pk The public key in hex (Uint8Array or string) format.
|
|
444
|
+
* @returns {boolean} True if the public key is valid, false otherwise.
|
|
445
|
+
*/
|
|
446
|
+
static isValid(pk: Hex): boolean {
|
|
447
|
+
try {
|
|
448
|
+
new CompressedSecp256k1PublicKey(pk);
|
|
449
|
+
return true;
|
|
450
|
+
} catch {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* Returns the point of the public key.
|
|
457
|
+
* @param {Hex} pk The public key in hex (Uint8Array or string) format.
|
|
458
|
+
* @returns {Point} The point of the public key.
|
|
459
|
+
* @throws {PublicKeyError} If the public key is not a valid hex string or byte array.
|
|
460
|
+
*/
|
|
461
|
+
static point(pk: Hex): Point {
|
|
462
|
+
// If the public key is a hex string, convert it to a CompressedSecp256k1PublicKey object and return the point
|
|
463
|
+
if(typeof pk === 'string' && /^[0-9a-fA-F]+$/.test(pk)) {
|
|
464
|
+
const publicKey = new CompressedSecp256k1PublicKey(Buffer.from(pk, 'hex'));
|
|
465
|
+
return publicKey.point;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// If the public key is a byte array or ArrayBuffer, convert it to a CompressedSecp256k1PublicKey object and return the point
|
|
469
|
+
if(pk instanceof Uint8Array || ArrayBuffer.isView(pk)) {
|
|
470
|
+
const publicKey = new CompressedSecp256k1PublicKey(pk as KeyBytes);
|
|
471
|
+
return publicKey.point;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// If the public key is neither a hex string nor a byte array, throw an error
|
|
475
|
+
throw new PublicKeyError(
|
|
476
|
+
'Invalid publicKey: must be a hex string or byte array',
|
|
477
|
+
'POINT_ERROR', { publicKey: pk }
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Creates a CompressedSecp256k1PublicKey object from a JSON representation.
|
|
483
|
+
* @param {PublicKeyObject} json The JSON object to initialize the CompressedSecp256k1PublicKey.
|
|
484
|
+
* @returns {CompressedSecp256k1PublicKey} The initialized CompressedSecp256k1PublicKey object.
|
|
485
|
+
*/
|
|
486
|
+
static fromJSON(json: PublicKeyObject): CompressedSecp256k1PublicKey {
|
|
487
|
+
json.point.x.unshift(json.point.parity);
|
|
488
|
+
return new CompressedSecp256k1PublicKey(Uint8Array.from(json.point.x));
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Computes the deterministic public key for a given secret key.
|
|
493
|
+
* @param {Secp256k1SecretKey | KeyBytes} sk The Secp256k1SecretKey object or the secret key bytes
|
|
494
|
+
* @returns {CompressedSecp256k1PublicKey} A new CompressedSecp256k1PublicKey object
|
|
495
|
+
*/
|
|
496
|
+
static fromSecretKey(sk: Secp256k1SecretKey | KeyBytes): CompressedSecp256k1PublicKey {
|
|
497
|
+
// If the secret key is a Secp256k1SecretKey object, get the raw bytes else use the bytes
|
|
498
|
+
const bytes = sk instanceof Secp256k1SecretKey ? sk.bytes : sk;
|
|
499
|
+
|
|
500
|
+
// Throw error if the secret key is not 32 bytes
|
|
501
|
+
if(bytes.length !== 32) {
|
|
502
|
+
throw new PublicKeyError('Invalid arg: must be 32 byte secret key', 'FROM_SECRET_KEY_ERROR');
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Compute the public key from the secret key
|
|
506
|
+
const secret = sk instanceof Secp256k1SecretKey
|
|
507
|
+
? sk
|
|
508
|
+
: new Secp256k1SecretKey(sk);
|
|
509
|
+
|
|
510
|
+
// Return a new CompressedSecp256k1PublicKey object
|
|
511
|
+
return secret.computePublicKey();
|
|
512
|
+
}
|
|
498
513
|
}
|
package/src/secret.ts
CHANGED
|
@@ -178,7 +178,7 @@ export class Secp256k1SecretKey implements SecretKey {
|
|
|
178
178
|
*/
|
|
179
179
|
public encode(): string {
|
|
180
180
|
// Convert Uint8Array bytes to an Array
|
|
181
|
-
const secretKeyBytes = this.bytes
|
|
181
|
+
const secretKeyBytes = Array.from(this.bytes);
|
|
182
182
|
|
|
183
183
|
if(secretKeyBytes.length !== 32) {
|
|
184
184
|
throw new SecretKeyError(
|
|
@@ -187,13 +187,13 @@ export class Secp256k1SecretKey implements SecretKey {
|
|
|
187
187
|
);
|
|
188
188
|
}
|
|
189
189
|
// Convert prefix to an array
|
|
190
|
-
const mbaseBytes =
|
|
190
|
+
const mbaseBytes = Array.from(BIP340_SECRET_KEY_MULTIBASE_PREFIX);
|
|
191
191
|
|
|
192
192
|
// Push the secret key bytes at the end of the prefix
|
|
193
193
|
mbaseBytes.push(...secretKeyBytes);
|
|
194
194
|
|
|
195
195
|
// Encode the bytes in base58btc format and return
|
|
196
|
-
return base58btc.encode(
|
|
196
|
+
return base58btc.encode(Uint8Array.from(mbaseBytes));
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
/**
|
|
@@ -239,7 +239,7 @@ export class Secp256k1SecretKey implements SecretKey {
|
|
|
239
239
|
*/
|
|
240
240
|
public json(): SecretKeyObject {
|
|
241
241
|
return {
|
|
242
|
-
bytes : this.bytes
|
|
242
|
+
bytes : Array.from(this.bytes),
|
|
243
243
|
seed : this.seed.toString(),
|
|
244
244
|
hex : this.hex,
|
|
245
245
|
};
|