@did-btcr2/keypair 0.7.2 → 0.9.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/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} pk The public key byte array.
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(pk: Hex) {
144
- pk = pk instanceof Uint8Array
145
- ? pk
146
- : Buffer.fromHex(pk);
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(!pk || pk.length !== 33) {
150
+ if(!keyBytes || keyBytes.length !== 33) {
150
151
  throw new PublicKeyError(
151
152
  'Invalid argument: byte length must be 33 (compressed)',
152
- 'CONSTRUCTOR_ERROR', { pk }
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(pk)) {
158
+ if (!tinysecp.isPoint(keyBytes)) {
158
159
  throw new PublicKeyError(
159
160
  'Invalid argument: not a valid secp256k1 compressed point',
160
- 'CONSTRUCTOR_ERROR', { pk }
161
+ 'CONSTRUCTOR_ERROR', { keyBytes }
161
162
  );
162
163
  }
163
164
  // Set the bytes
164
- this.#bytes = pk;
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
- public bip340(): KeyBytes {
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
- public decode(): KeyBytes {
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
- public encode(): string {
315
+ encode(): string {
341
316
  // Convert public key bytes to an array
342
- const pk = this.compressed.toArray();
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 = BIP340_PUBLIC_KEY_MULTIBASE_PREFIX.toArray();
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(publicKeyMultibase.toUint8Array());
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
- public verify(signature: Bytes, data: Bytes, opts?: CryptoOptions): boolean {
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
- public equals(other: CompressedSecp256k1PublicKey): boolean {
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
- public json(): PublicKeyObject {
370
+ json(): PublicKeyObject {
396
371
  return {
397
372
  hex : this.hex,
398
373
  multibase : this.multibase,
399
374
  point : {
400
- x : this.x.toArray(),
401
- y : this.y.toArray(),
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
- public modPow(base: bigint, exp: bigint, mod: bigint): bigint {
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
- public sqrtMod(a: bigint, p: bigint): bigint {
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
- public liftX(): Uint8Array {
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.fromHex(y.toString(16).padStart(64, '0'));
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
@@ -3,7 +3,6 @@ import {
3
3
  BIP340_SECRET_KEY_MULTIBASE_PREFIX_HASH,
4
4
  Bytes,
5
5
  CURVE,
6
- Entropy,
7
6
  Hex,
8
7
  KeyBytes,
9
8
  SecretKeyError,
@@ -89,10 +88,10 @@ export class Secp256k1SecretKey implements SecretKey {
89
88
 
90
89
  /**
91
90
  * Instantiates an instance of Secp256k1SecretKey.
92
- * @param {Entropy} entropy bytes (Uint8Array) or secret (bigint)
91
+ * @param {Bytes | bigint} entropy bytes (Uint8Array) or secret (bigint)
93
92
  * @throws {SecretKeyError} If entropy is not provided, not a valid 32-byte secret key or not a valid bigint seed
94
93
  */
95
- constructor(entropy: Entropy) {
94
+ constructor(entropy: Bytes | bigint) {
96
95
  // If entropy not valid bytes or bigint seed, throw an error
97
96
  const isBytes = entropy instanceof Uint8Array;
98
97
  const isSecret = typeof entropy === 'bigint';
@@ -178,7 +177,7 @@ export class Secp256k1SecretKey implements SecretKey {
178
177
  */
179
178
  public encode(): string {
180
179
  // Convert Uint8Array bytes to an Array
181
- const secretKeyBytes = this.bytes.toArray();
180
+ const secretKeyBytes = Array.from(this.bytes);
182
181
 
183
182
  if(secretKeyBytes.length !== 32) {
184
183
  throw new SecretKeyError(
@@ -187,13 +186,13 @@ export class Secp256k1SecretKey implements SecretKey {
187
186
  );
188
187
  }
189
188
  // Convert prefix to an array
190
- const mbaseBytes = BIP340_SECRET_KEY_MULTIBASE_PREFIX.toArray();
189
+ const mbaseBytes = Array.from(BIP340_SECRET_KEY_MULTIBASE_PREFIX);
191
190
 
192
191
  // Push the secret key bytes at the end of the prefix
193
192
  mbaseBytes.push(...secretKeyBytes);
194
193
 
195
194
  // Encode the bytes in base58btc format and return
196
- return base58btc.encode(mbaseBytes.toUint8Array());
195
+ return base58btc.encode(Uint8Array.from(mbaseBytes));
197
196
  }
198
197
 
199
198
  /**
@@ -239,7 +238,7 @@ export class Secp256k1SecretKey implements SecretKey {
239
238
  */
240
239
  public json(): SecretKeyObject {
241
240
  return {
242
- bytes : this.bytes.toArray(),
241
+ bytes : Array.from(this.bytes),
243
242
  seed : this.seed.toString(),
244
243
  hex : this.hex,
245
244
  };
@@ -387,18 +386,28 @@ export class Secp256k1SecretKey implements SecretKey {
387
386
  return new Uint8Array(bytes);
388
387
  }
389
388
 
389
+ /**
390
+ * Creates a new Secp256k1SecretKey object from random bytes.
391
+ * @param {KeyBytes} bytes The secret key bytes
392
+ * @returns {Secp256k1SecretKey} A new Secp256k1SecretKey object
393
+ */
394
+ public static fromBytes(bytes: KeyBytes): Secp256k1SecretKey {
395
+ // Return a new Secp256k1SecretKey object
396
+ return new Secp256k1SecretKey(bytes);
397
+ }
398
+
390
399
  /**
391
400
  * Creates a new Secp256k1SecretKey object from a bigint secret.
392
- * @param {bigint} entropy The secret bigint
401
+ * @param {bigint} bint The secret bigint
393
402
  * @returns {Secp256k1SecretKey} A new Secp256k1SecretKey object
394
403
  */
395
- public static fromEntropy(entropy: bigint): Secp256k1SecretKey {
404
+ public static fromBigInt(bint: bigint): Secp256k1SecretKey {
396
405
  // Convert the secret bigint to a hex string
397
- const hexsecret = entropy.toString(16).padStart(64, '0');
406
+ const hexsecret = bint.toString(16).padStart(64, '0');
398
407
  // Convert the hex string to a Uint8Array
399
- const privateKeyBytes = new Uint8Array(hexsecret.match(/.{2}/g)!.map(byte => parseInt(byte, 16)));
408
+ const bytes = new Uint8Array(hexsecret.match(/.{2}/g)!.map(byte => parseInt(byte, 16)));
400
409
  // Return a new Secp256k1SecretKey object
401
- return new Secp256k1SecretKey(privateKeyBytes);
410
+ return new Secp256k1SecretKey(bytes);
402
411
  }
403
412
 
404
413
  /**