@did-btcr2/keypair 0.5.1 → 0.7.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/pair.ts CHANGED
@@ -4,25 +4,26 @@ import {
4
4
  KeyPairError,
5
5
  SchnorrKeyPairObject
6
6
  } from '@did-btcr2/common';
7
- import { PublicKey } from './public.js';
8
- import { SecretKey } from './secret.js';
7
+ import { CompressedSecp256k1PublicKey } from './public.js';
8
+ import { Secp256k1SecretKey } from './secret.js';
9
+ import { MultibaseKeys, RawSchnorrKeyPair, SchnorrKeyPairParams } from './types.js';
9
10
 
10
11
  /**
11
- * Interface for KeyPair class.
12
+ * General KeyPair interface used by SchnorrKeyPair class.
12
13
  * @interface KeyPair
13
14
  * @type {KeyPair}
14
15
  */
15
16
  export interface KeyPair {
16
17
  /**
17
- * @type {PublicKey} The PublicKey associated with the SchnorrKeyPair (required).
18
+ * @type {CompressedSecp256k1PublicKey} The public key associated with the SchnorrKeyPair (required).
18
19
  */
19
- readonly publicKey: PublicKey;
20
+ readonly publicKey: CompressedSecp256k1PublicKey;
20
21
 
21
22
  /**
22
- * @type {SecretKey} The SecretKey associated with the SchnorrKeyPair (optional).
23
+ * @type {Secp256k1SecretKey} The secret key associated with the SchnorrKeyPair (optional).
23
24
  * @throws {KeyPairError} If the secret key is not available.
24
25
  */
25
- readonly secretKey?: SecretKey;
26
+ readonly secretKey?: Secp256k1SecretKey;
26
27
 
27
28
  /**
28
29
  * JSON representation of the SchnorrKeyPair object.
@@ -31,32 +32,17 @@ export interface KeyPair {
31
32
  json(): SchnorrKeyPairObject;
32
33
  }
33
34
 
34
- type RawKeyPair = {
35
- public: KeyBytes;
36
- secret?: KeyBytes
37
- }
38
-
39
- /** Params for the {@link SchnorrKeyPair} constructor */
40
- interface KeyParams {
41
- secretKey?: SecretKey | KeyBytes;
42
- publicKey?: PublicKey | KeyBytes;
43
- }
44
-
45
- interface MultibaseKeys {
46
- publicKeyMultibase: string;
47
- secretKeyMultibase: string
48
- }
49
35
  /**
50
- * Encapsulates a PublicKey and a SecretKey object as a single Keys object.
36
+ * Encapsulates a CompressedSecp256k1PublicKey and a Secp256k1SecretKey object as a single SchnorrKeyPair object.
51
37
  * @class SchnorrKeyPair
52
38
  * @type {SchnorrKeyPair}
53
39
  */
54
40
  export class SchnorrKeyPair implements KeyPair {
55
- /** @type {SecretKey} The secret key object */
56
- private _secretKey?: SecretKey;
41
+ /** @type {Secp256k1SecretKey} The secret key object */
42
+ private _secretKey?: Secp256k1SecretKey;
57
43
 
58
- /** @type {PublicKey} The public key object */;
59
- private _publicKey: PublicKey;
44
+ /** @type {CompressedSecp256k1PublicKey} The public key object */;
45
+ private _publicKey: CompressedSecp256k1PublicKey;
60
46
 
61
47
  /** @type {string} The public key in multibase format */
62
48
  private _publicKeyMultibase: string;
@@ -66,41 +52,45 @@ export class SchnorrKeyPair implements KeyPair {
66
52
 
67
53
  /**
68
54
  * Creates an instance of Keys. Must provide a at least a secret key.
69
- * Can optionally provide both a private and public key, but must be a valid pair.
70
- * @param {SecretKey} secretKey The secret key object
55
+ * Can optionally provide both a secret and public key, but must be a valid pair.
56
+ * @param {SchnorrKeyPairParams} params The parameters to initialize the Keys object.
57
+ * @param {CompressedSecp256k1PublicKey | KeyBytes} params.publicKey The public key object or bytes
58
+ * @param {Secp256k1SecretKey | KeyBytes} [params.secret] The secret key object or bytes
59
+ * @throws {KeyPairError} If neither a public key or secret key is provided.
60
+ * @throws {KeyPairError} If the public key is not a valid pair with the secret key.
71
61
  */
72
- constructor({ secretKey, publicKey }: KeyParams = {}) {
62
+ constructor(params: SchnorrKeyPairParams = {}) {
73
63
  // If no secret key or public key, throw an error
74
- if (!publicKey && !secretKey) {
64
+ if (!params.publicKey && !params.secretKey) {
75
65
  throw new KeyPairError('Argument missing: must at least provide a publicKey', 'CONSTRUCTOR_ERROR');
76
66
  }
77
67
 
78
- // Set the secret key
79
- if(secretKey instanceof Uint8Array) {
80
- this._secretKey = new SecretKey(secretKey);
81
- } else if (secretKey instanceof SecretKey) {
82
- this._secretKey = secretKey;
68
+ // Set the secretKey
69
+ if(params.secretKey instanceof Uint8Array) {
70
+ this._secretKey = new Secp256k1SecretKey(params.secretKey);
71
+ } else if (params.secretKey instanceof Secp256k1SecretKey) {
72
+ this._secretKey = params.secretKey;
83
73
  }
84
74
 
85
- // Set the public key
86
- if(publicKey instanceof PublicKey) {
87
- this._publicKey = publicKey;
88
- } else if (publicKey instanceof Uint8Array) {
89
- this._publicKey = new PublicKey(publicKey);
75
+ // Set the publicKey
76
+ if(params.publicKey instanceof CompressedSecp256k1PublicKey) {
77
+ this._publicKey = params.publicKey;
78
+ } else if (params.publicKey instanceof Uint8Array) {
79
+ this._publicKey = new CompressedSecp256k1PublicKey(params.publicKey);
90
80
  } else {
91
- this._publicKey = new PublicKey(this._secretKey!.computePublicKey());
81
+ this._publicKey = this._secretKey!.computePublicKey();
92
82
  }
93
83
 
94
- this._publicKeyMultibase = this._publicKey.multibase.address;
84
+ this._publicKeyMultibase = this._publicKey.multibase.encoded;
95
85
  this._secretKeyMultibase = this._secretKey ? this._secretKey.multibase : '';
96
86
  }
97
87
 
98
88
  /**
99
- * Get the SecretKey.
100
- * @returns {SecretKey} The SecretKey object
89
+ * Get the Secp256k1SecretKey.
90
+ * @returns {Secp256k1SecretKey} The Secp256k1SecretKey object
101
91
  * @throws {KeyPairError} If the secret key is not available
102
92
  */
103
- get secretKey(): SecretKey {
93
+ get secretKey(): Secp256k1SecretKey {
104
94
  // If the secret key is not available, throw an error
105
95
  if(!this._secretKey) {
106
96
  throw new KeyPairError('Secret key not available', 'SECRET_KEY_ERROR');
@@ -110,39 +100,44 @@ export class SchnorrKeyPair implements KeyPair {
110
100
  throw new KeyPairError('Secret key is not valid', 'SECRET_KEY_ERROR');
111
101
  }
112
102
  // Return a copy of the secret key
113
- const secretKey = this._secretKey;
114
- return secretKey;
103
+ const secret = this._secretKey;
104
+ return secret;
115
105
  }
116
106
 
117
107
  /**
118
- * Set the PublicKey.
119
- * @param {PublicKey} publicKey The PublicKey object
108
+ * Set the CompressedSecp256k1PublicKey.
109
+ * @param {CompressedSecp256k1PublicKey} publicKey The CompressedSecp256k1PublicKey object
120
110
  * @throws {KeyPairError} If the public key is not a valid pair with the secret key.
121
111
  */
122
- set publicKey(publicKey: PublicKey) {
112
+ set publicKey(publicKey: CompressedSecp256k1PublicKey) {
123
113
  // If the public key is not a valid pair with the secret key, throw an error
124
- if(this.secretKey && !this.secretKey.isValidPair(publicKey)) {
125
- throw new KeyPairError('Public key is not a valid pair with the secret key', 'PUBLIC_KEY_ERROR');
114
+ if(this.secretKey) {
115
+ if(!this.secretKey.hasValidPublicKey()) {
116
+ throw new KeyPairError('Secret key is not valid', 'SECRET_KEY_ERROR');
117
+ }
118
+ const cPk = this.secretKey.computePublicKey();
119
+ if(!publicKey.equals(cPk))
120
+ throw new KeyPairError('Public key is not a valid pair with the secret key', 'PUBLIC_KEY_ERROR');
126
121
  }
127
122
  this._publicKey = publicKey;
128
- this._publicKeyMultibase = publicKey.multibase.address;
123
+ this._publicKeyMultibase = publicKey.multibase.encoded;
129
124
  this._secretKeyMultibase = this._secretKey ? this._secretKey.multibase : '';
130
125
  }
131
126
 
132
127
  /**
133
- * Get the PublicKey.
134
- * @returns {PublicKey} The PublicKey object
128
+ * Get the CompressedSecp256k1PublicKey.
129
+ * @returns {CompressedSecp256k1PublicKey} The CompressedSecp256k1PublicKey object
135
130
  */
136
- get publicKey(): PublicKey {
131
+ get publicKey(): CompressedSecp256k1PublicKey {
137
132
  const publicKey = this._publicKey;
138
133
  return publicKey;
139
134
  }
140
135
 
141
136
  /**
142
- * Get the Keys as a raw key pair.
143
- * @returns {RawKeyPair} The Keys as a raw key pair
137
+ * Get the raw bytes of each key in the SchnorrKeyPair.
138
+ * @returns {RawSchnorrKeyPair} JSON object with the SchnorrKeyPair raw bytes.
144
139
  */
145
- get raw(): RawKeyPair {
140
+ get raw(): RawSchnorrKeyPair {
146
141
  return {
147
142
  public : this.publicKey.x,
148
143
  secret : this.secretKey ? this.secretKey.bytes : undefined
@@ -151,7 +146,7 @@ export class SchnorrKeyPair implements KeyPair {
151
146
 
152
147
  /**
153
148
  * Get the Keys in multibase format.
154
- * @returns {MultibaseKeys} The SecretKey in multibase format
149
+ * @returns {MultibaseKeys} The Secp256k1SecretKey in multibase format
155
150
  */
156
151
  get multibase(): MultibaseKeys {
157
152
  return {
@@ -177,50 +172,51 @@ export class SchnorrKeyPair implements KeyPair {
177
172
  * @returns {SchnorrKeyPair} The initialized Keys object.
178
173
  */
179
174
  public static fromJSON(keys: SchnorrKeyPairObject): SchnorrKeyPair {
180
- const secretKey = SecretKey.fromJSON(keys.secretKey);
181
- const publicKey = PublicKey.fromJSON(keys.publicKey);
182
- return new SchnorrKeyPair({ secretKey, publicKey });
175
+ return new SchnorrKeyPair({
176
+ secretKey : Secp256k1SecretKey.fromJSON(keys.secretKey),
177
+ publicKey : CompressedSecp256k1PublicKey.fromJSON(keys.publicKey)
178
+ });
183
179
  }
184
180
 
185
181
  /**
186
- * Static method creates a new SchnorrKeyPair from a SecretKey object or secret key bytes.
187
- * @param {SecretKey | KeyBytes} data The secret key bytes
182
+ * Static method creates a new SchnorrKeyPair from a Secp256k1SecretKey object or secret key bytes.
183
+ * @param {Secp256k1SecretKey | KeyBytes} data The secret key bytes
188
184
  * @returns {SchnorrKeyPair} A new SchnorrKeyPair object
189
185
  */
190
- public static fromPrivateKey(data: SecretKey | KeyBytes): SchnorrKeyPair {
186
+ public static fromPrivateKey(data: Secp256k1SecretKey | KeyBytes): SchnorrKeyPair {
191
187
 
192
- // If the secret key is a SecretKey object, get the raw bytes else use the bytes
193
- const bytes = data instanceof SecretKey ? data.bytes : data;
188
+ // If the secret key is a Secp256k1SecretKey object, get the raw bytes else use the bytes
189
+ const bytes = data instanceof Secp256k1SecretKey ? data.bytes : data;
194
190
 
195
191
  // Throw error if the secret key is not 32 bytes
196
192
  if(bytes.length !== 32) {
197
193
  throw new KeyPairError('Invalid arg: must be 32 byte secret key', 'FROM_PRIVATE_KEY_ERROR');
198
194
  }
199
195
 
200
- // If pk Uint8Array, construct SecretKey object else use the object
201
- const secretKey = data instanceof Uint8Array ? new SecretKey(data) : data;
202
-
203
- // Compute the public key from the secret key
204
- const publicKey = secretKey.computePublicKey();
196
+ // If pk Uint8Array, construct Secp256k1SecretKey object else use the object
197
+ const secret = data instanceof Uint8Array ? new Secp256k1SecretKey(data) : data;
205
198
 
206
199
  // Return a new Keys object
207
- return new SchnorrKeyPair({ secretKey, publicKey });
200
+ return new SchnorrKeyPair({
201
+ secretKey : data instanceof Uint8Array ? new Secp256k1SecretKey(data) : data,
202
+ publicKey : secret.computePublicKey()
203
+ });
208
204
  }
209
205
 
210
206
  /**
211
- * Static method creates a new Keys (SecretKey/PublicKey) bigint secret.
212
- * @param {bigint} secret The secret key secret
213
- * @returns {Keys} A new Keys object
207
+ * Static method creates a new Keys (Secp256k1SecretKey/CompressedSecp256k1PublicKey) from bigint entropy.
208
+ * @param {bigint} entropy The entropy in bigint form
209
+ * @returns {SchnorrKeyPair} A new SchnorrKeyPair object
214
210
  */
215
- public static fromSecret(secret: bigint): SchnorrKeyPair {
216
- const secretKey = SecretKey.fromSecret(secret);
211
+ public static fromEntropy(entropy: bigint): SchnorrKeyPair {
212
+ const secretKey = Secp256k1SecretKey.fromEntropy(entropy);
217
213
  const publicKey = secretKey.computePublicKey();
218
214
  return new SchnorrKeyPair({ secretKey, publicKey });
219
215
  }
220
216
 
221
217
  /**
222
218
  * Converts key bytes to a hex string.
223
- * @param {KeyBytes} keyBytes The key bytes (private or public).
219
+ * @param {KeyBytes} keyBytes The key bytes (secret or public).
224
220
  * @returns {Hex} The key bytes as a hex string.
225
221
  */
226
222
  public static toHex(keyBytes: KeyBytes): Hex {
@@ -229,23 +225,23 @@ export class SchnorrKeyPair implements KeyPair {
229
225
 
230
226
  /**
231
227
  * Compares two Keys objects for equality.
232
- * @param {SchnorrKeyPair} keys The main keys.
233
- * @param {SchnorrKeyPair} otherKeys The other keys to compare.
228
+ * @param {SchnorrKeyPair} kp The main keys.
229
+ * @param {SchnorrKeyPair} otherKp The other keys to compare.
234
230
  * @returns {boolean} True if the public key and secret key are equal, false otherwise.
235
231
  */
236
- public static equals(keys: SchnorrKeyPair, otherKeys: SchnorrKeyPair): boolean {
232
+ public static equals(kp: SchnorrKeyPair, otherKp: SchnorrKeyPair): boolean {
237
233
  // Deconstruct the public keys from the key pairs
238
- const pk = keys.publicKey;
239
- const otherPk = otherKeys.publicKey;
234
+ const pk = kp.publicKey;
235
+ const otherPk = otherKp.publicKey;
240
236
 
241
237
  // If publicKeys present, use to compare as hex strings.
242
238
  if(pk && otherPk) {
243
239
  return pk.hex === otherPk.hex;
244
240
  }
245
241
 
246
- // Deconstruct the private keys from the key pairs
247
- const sk = keys.secretKey;
248
- const otherSk = otherKeys.secretKey;
242
+ // Deconstruct the secret keys from the key pairs
243
+ const sk = kp.secretKey;
244
+ const otherSk = otherKp.secretKey;
249
245
  if(sk && otherSk) {
250
246
  // Get the public key hex strings for both key pair publicKeys
251
247
  return sk.hex === otherSk.hex;
@@ -256,14 +252,14 @@ export class SchnorrKeyPair implements KeyPair {
256
252
 
257
253
  /**
258
254
  * Static method to generate a new random SchnorrKeyPair instance.
259
- * @returns {SchnorrKeyPair} A new SecretKey object.
255
+ * @returns {SchnorrKeyPair} A new Secp256k1SecretKey object.
260
256
  */
261
257
  public static generate(): SchnorrKeyPair {
262
258
  // Generate random secret key bytes
263
- const skBytes = SecretKey.random();
259
+ const sk = Secp256k1SecretKey.random();
264
260
 
265
- // Construct a new SecretKey object
266
- const secretKey = new SecretKey(skBytes);
261
+ // Construct a new Secp256k1SecretKey object
262
+ const secretKey = new Secp256k1SecretKey(sk);
267
263
 
268
264
  // Compute the public key from the secret key
269
265
  const publicKey = secretKey.computePublicKey();
package/src/public.ts CHANGED
@@ -11,7 +11,8 @@ import {
11
11
  } from '@did-btcr2/common';
12
12
  import { sha256 } from '@noble/hashes/sha2';
13
13
  import { base58btc } from 'multiformats/bases/base58';
14
- import { SecretKey } from './secret.js';
14
+ import * as tinysecp from 'tiny-secp256k1';
15
+ import { Secp256k1SecretKey } from './secret.js';
15
16
 
16
17
  export interface Point {
17
18
  x: KeyBytes;
@@ -19,11 +20,17 @@ export interface Point {
19
20
  }
20
21
 
21
22
  /**
22
- * Interface for the PublicKey class.
23
- * @interface IPublicKey
24
- * @type {IPublicKey}
23
+ * General PublicKey Interface used by CompressedSecp256k1PublicKey.
24
+ * @interface PublicKey
25
+ * @type {PublicKey}
25
26
  */
26
- export interface IPublicKey {
27
+ export interface PublicKey {
28
+ /**
29
+ * Compressed public key getter.
30
+ * @readonly @type {KeyBytes} The 33 byte compressed public key [parity, x-coord].
31
+ */
32
+ compressed: KeyBytes;
33
+
27
34
  /**
28
35
  * Uncompressed public key getter.
29
36
  * @readonly @type {KeyBytes} The 65 byte uncompressed public key [0x04, x-coord, y-coord].
@@ -31,41 +38,53 @@ export interface IPublicKey {
31
38
  uncompressed: KeyBytes;
32
39
 
33
40
  /**
34
- * Compressed public key getter.
35
- * @readonly @type {KeyBytes} The 33 byte compressed public key [parity, x-coord].
41
+ * X-only public key getter.
42
+ * @readonly @type {KeyBytes} The 32 byte x-only public key [x-coord].
36
43
  */
37
- compressed: KeyBytes;
44
+ xOnly: KeyBytes;
38
45
 
39
46
  /**
40
- * PublicKey parity getter.
47
+ * CompressedSecp256k1PublicKey parity getter.
41
48
  * @readonly @type {number} The 1 byte parity (0x02 if even, 0x03 if odd).
42
49
  */
43
50
  parity: number;
44
51
 
45
52
  /**
46
- * PublicKey x-coordinate getter.
53
+ * CompressedSecp256k1PublicKey isEven getter.
54
+ * @readonly @type {boolean} True if the public key is even, false if odd.
55
+ */
56
+ isEven: boolean;
57
+
58
+ /**
59
+ * CompressedSecp256k1PublicKey x-coordinate getter.
47
60
  * @readonly @type {KeyBytes} The 32 byte x-coordinate of the public key.
48
61
  */
49
62
  x: KeyBytes;
50
63
 
51
64
  /**
52
- * PublicKey y-coordinate getter.
65
+ * CompressedSecp256k1PublicKey y-coordinate getter.
53
66
  * @readonly @type {KeyBytes} The 32 byte y-coordinate of the public key.
54
67
  */
55
68
  y: KeyBytes;
56
69
 
57
70
  /**
58
- * PublicKey multibase getter.
71
+ * CompressedSecp256k1PublicKey multibase getter.
59
72
  * @readonly @returns {MultibaseObject} The public key as MultibaseObject as a address string, key and prefix bytes.
60
73
  */
61
74
  multibase: MultibaseObject;
62
75
 
63
76
  /**
64
- * PublicKey hex string getter.
77
+ * CompressedSecp256k1PublicKey hex string getter.
65
78
  * @readonly @type {Hex} The public key as a hex string.
66
79
  */
67
80
  hex: Hex;
68
81
 
82
+ /**
83
+ * CompressedSecp256k1PublicKey point getter.
84
+ * @readonly @type {Point} The public key as a point (x, y).
85
+ */
86
+ point: Point;
87
+
69
88
  /**
70
89
  * Decode the base58btc multibase string to the compressed public key prefixed with 0x02.
71
90
  * @returns {KeyBytes} The public key as a 33-byte compressed public key with header.
@@ -73,21 +92,21 @@ export interface IPublicKey {
73
92
  decode(): KeyBytes;
74
93
 
75
94
  /**
76
- * Encode the PublicKey as an x-only base58btc multibase public key.
95
+ * Encode the CompressedSecp256k1PublicKey as an x-only base58btc multibase public key.
77
96
  * @returns {string} The public key formatted a base58btc multibase string.
78
97
  */
79
98
  encode(): string;
80
99
 
81
100
  /**
82
- * PublicKey key equality check. Checks if `this` public key is equal to `other` public key.
83
- * @param {PublicKey} other The public key to compare.
101
+ * CompressedSecp256k1PublicKey key equality check. Checks if `this` public key is equal to `other` public key.
102
+ * @param {CompressedSecp256k1PublicKey} other The public key to compare.
84
103
  * @returns {boolean} True if the public keys are equal.
85
104
  */
86
- equals(other: PublicKey): boolean;
105
+ equals(other: CompressedSecp256k1PublicKey): boolean;
87
106
 
88
107
  /**
89
- * JSON representation of a PublicKey object.
90
- * @returns {PublicKeyObject} The PublicKey as a JSON object.
108
+ * JSON representation of a CompressedSecp256k1PublicKey object.
109
+ * @returns {PublicKeyObject} The CompressedSecp256k1PublicKey as a JSON object.
91
110
  */
92
111
  json(): PublicKeyObject;
93
112
  }
@@ -96,10 +115,10 @@ export interface IPublicKey {
96
115
  * Encapsulates a secp256k1 public key compliant to BIP-340 BIP schnorr signature scheme.
97
116
  * Provides get methods for different formats (compressed, x-only, multibase).
98
117
  * Provides helpers methods for comparison and serialization.
99
- * @class PublicKey
100
- * @type {PublicKey}
118
+ * @class CompressedSecp256k1PublicKey
119
+ * @type {CompressedSecp256k1PublicKey}
101
120
  */
102
- export class PublicKey implements PublicKey {
121
+ export class CompressedSecp256k1PublicKey implements PublicKey {
103
122
  /** @type {KeyBytes} The public key bytes */
104
123
  private readonly _bytes: KeyBytes;
105
124
 
@@ -107,11 +126,11 @@ export class PublicKey implements PublicKey {
107
126
  private _multibase: MultibaseObject = {
108
127
  prefix : BIP340_PUBLIC_KEY_MULTIBASE_PREFIX,
109
128
  key : [],
110
- address : ''
129
+ encoded : ''
111
130
  };
112
131
 
113
132
  /**
114
- * Creates a PublicKey instance.
133
+ * Creates a CompressedSecp256k1PublicKey instance.
115
134
  * @param {KeyBytes} bytes The public key byte array.
116
135
  * @throws {PublicKeyError} if the byte length is not 32 (x-only) or 33 (compressed)
117
136
  */
@@ -123,11 +142,19 @@ export class PublicKey implements PublicKey {
123
142
  'CONSTRUCTOR_ERROR', { bytes }
124
143
  );
125
144
  }
145
+
146
+ // Validate the point is on curve and in compressed form
147
+ if (!tinysecp.isPoint(bytes)) {
148
+ throw new PublicKeyError(
149
+ 'Invalid argument: bytes are not a valid secp256k1 compressed point',
150
+ 'CONSTRUCTOR_ERROR', { bytes }
151
+ );
152
+ }
126
153
  // Set the bytes
127
154
  this._bytes = bytes;
128
155
 
129
156
  // Set multibase
130
- this._multibase.address = this.encode();
157
+ this._multibase.encoded = this.encode();
131
158
  this._multibase.key = [...this._multibase.prefix, ...this.compressed];
132
159
  }
133
160
 
@@ -150,12 +177,34 @@ export class PublicKey implements PublicKey {
150
177
  }
151
178
 
152
179
  /**
153
- * Get the parity byte of the public key.
154
- * @returns {number} The parity byte of the public key.
180
+ * X-only (32-byte) view of the public key per BIP-340.
181
+ */
182
+ get xOnly(): KeyBytes {
183
+ return this._bytes.slice(1);
184
+ }
185
+
186
+ /**
187
+ * Parity of the SEC compressed public key.
188
+ * @returns {0x02 | 0x03} The parity byte (0x02 if even, 0x03 if odd).
189
+ * @throws {PublicKeyError} If the parity byte is not 0x02 or 0x03.
190
+ */
191
+ get parity(): 0x02 | 0x03 {
192
+ const parity = this._bytes[0];
193
+ if(![0x02, 0x03].includes(parity)) {
194
+ throw new PublicKeyError(
195
+ 'Invalid state: parity byte must be 2 or 3',
196
+ 'PARITY_ERROR', { parity }
197
+ );
198
+ }
199
+ return parity as 0x02 | 0x03;
200
+ }
201
+
202
+ /**
203
+ * Whether the SEC compressed public key has even Y.
204
+ * @returns {boolean} True if the public key has even Y.
155
205
  */
156
- get parity(): number {
157
- const parity = this.compressed[0];
158
- return parity;
206
+ get isEven(): boolean {
207
+ return this._bytes[0] === 0x02;
159
208
  }
160
209
 
161
210
  /**
@@ -205,6 +254,14 @@ export class PublicKey implements PublicKey {
205
254
  };
206
255
  }
207
256
 
257
+ /**
258
+ * Returns the BIP-340 (x-only) representation of this key.
259
+ * @returns {KeyBytes} The BIP-340 (x-only) representation of the public key.
260
+ */
261
+ public bip340(): KeyBytes {
262
+ return this.xOnly;
263
+ }
264
+
208
265
  /**
209
266
  * Returns the point of the public key.
210
267
  * @param {Hex} pk The public key in hex (Uint8Array or string) format.
@@ -212,15 +269,15 @@ export class PublicKey implements PublicKey {
212
269
  * @throws {PublicKeyError} If the public key is not a valid hex string or byte array.
213
270
  */
214
271
  static point(pk: Hex): Point {
215
- // If the public key is a hex string, convert it to a PublicKey object and return the point
272
+ // If the public key is a hex string, convert it to a CompressedSecp256k1PublicKey object and return the point
216
273
  if(typeof pk === 'string' && /^[0-9a-fA-F]+$/.test(pk)) {
217
- const publicKey = new PublicKey(Buffer.fromHex(pk));
274
+ const publicKey = new CompressedSecp256k1PublicKey(Buffer.fromHex(pk));
218
275
  return publicKey.point;
219
276
  }
220
277
 
221
- // If the public key is a byte array or ArrayBuffer, convert it to a PublicKey object and return the point
278
+ // If the public key is a byte array or ArrayBuffer, convert it to a CompressedSecp256k1PublicKey object and return the point
222
279
  if(pk instanceof Uint8Array || ArrayBuffer.isView(pk)) {
223
- const publicKey = new PublicKey(pk as KeyBytes);
280
+ const publicKey = new CompressedSecp256k1PublicKey(pk as KeyBytes);
224
281
  return publicKey.point;
225
282
  }
226
283
 
@@ -237,7 +294,7 @@ export class PublicKey implements PublicKey {
237
294
  */
238
295
  public decode(): KeyBytes {
239
296
  // Decode the public key multibase string
240
- const decoded = base58btc.decode(this.multibase.address);
297
+ const decoded = base58btc.decode(this.multibase.encoded);
241
298
 
242
299
  // If the public key bytes are not 35 bytes, throw an error
243
300
  if(decoded.length !== 35) {
@@ -293,16 +350,16 @@ export class PublicKey implements PublicKey {
293
350
 
294
351
  /**
295
352
  * Compares this public key to another public key.
296
- * @param {PublicKey} other The other public key to compare
353
+ * @param {CompressedSecp256k1PublicKey} other The other public key to compare
297
354
  * @returns {boolean} True if the public keys are equal, false otherwise.
298
355
  */
299
- public equals(other: PublicKey): boolean {
356
+ public equals(other: CompressedSecp256k1PublicKey): boolean {
300
357
  return this.hex === other.hex;
301
358
  }
302
359
 
303
360
  /**
304
- * JSON representation of a PublicKey object.
305
- * @returns {PublicKeyObject} The PublicKey as a JSON object.
361
+ * JSON representation of a CompressedSecp256k1PublicKey object.
362
+ * @returns {PublicKeyObject} The CompressedSecp256k1PublicKey as a JSON object.
306
363
  */
307
364
  public json(): PublicKeyObject {
308
365
  return {
@@ -317,34 +374,36 @@ export class PublicKey implements PublicKey {
317
374
  }
318
375
 
319
376
  /**
320
- * Creates a PublicKey object from a JSON representation.
321
- * @param {PublicKeyObject} json The JSON object to initialize the PublicKey.
322
- * @returns {PublicKey} The initialized PublicKey object.
377
+ * Creates a CompressedSecp256k1PublicKey object from a JSON representation.
378
+ * @param {PublicKeyObject} json The JSON object to initialize the CompressedSecp256k1PublicKey.
379
+ * @returns {CompressedSecp256k1PublicKey} The initialized CompressedSecp256k1PublicKey object.
323
380
  */
324
- public static fromJSON(json: Maybe<PublicKeyObject>): PublicKey {
381
+ public static fromJSON(json: Maybe<PublicKeyObject>): CompressedSecp256k1PublicKey {
325
382
  json.x.unshift(json.parity);
326
- return new PublicKey(json.x.toUint8Array());
383
+ return new CompressedSecp256k1PublicKey(json.x.toUint8Array());
327
384
  }
328
385
 
329
386
  /**
330
- * Computes the deterministic public key for a given private key.
331
- * @param {PrivateKey | KeyBytes} sk The PrivateKey object or the private key bytes
332
- * @returns {PublicKey} A new PublicKey object
387
+ * Computes the deterministic public key for a given secret key.
388
+ * @param {Secp256k1SecretKey | KeyBytes} sk The Secp256k1SecretKey object or the secret key bytes
389
+ * @returns {CompressedSecp256k1PublicKey} A new CompressedSecp256k1PublicKey object
333
390
  */
334
- public static fromSecretKey(sk: SecretKey | KeyBytes): PublicKey {
335
- // If the private key is a PrivateKey object, get the raw bytes else use the bytes
336
- const bytes = sk instanceof SecretKey ? sk.bytes : sk;
391
+ public static fromSecretKey(sk: Secp256k1SecretKey | KeyBytes): CompressedSecp256k1PublicKey {
392
+ // If the secret key is a Secp256k1SecretKey object, get the raw bytes else use the bytes
393
+ const bytes = sk instanceof Secp256k1SecretKey ? sk.bytes : sk;
337
394
 
338
- // Throw error if the private key is not 32 bytes
395
+ // Throw error if the secret key is not 32 bytes
339
396
  if(bytes.length !== 32) {
340
- throw new PublicKeyError('Invalid arg: must be 32 byte private key', 'FROM_PRIVATE_KEY_ERROR');
397
+ throw new PublicKeyError('Invalid arg: must be 32 byte secret key', 'FROM_SECRET_KEY_ERROR');
341
398
  }
342
399
 
343
- // Compute the public key from the private key
344
- const privateKey = sk instanceof SecretKey ? sk : new SecretKey(sk);
400
+ // Compute the public key from the secret key
401
+ const secret = sk instanceof Secp256k1SecretKey
402
+ ? sk
403
+ : new Secp256k1SecretKey(sk);
345
404
 
346
- // Return a new PublicKey object
347
- return new PublicKey(privateKey.computePublicKey());
405
+ // Return a new CompressedSecp256k1PublicKey object
406
+ return secret.computePublicKey();
348
407
  }
349
408
 
350
409
  /**
@@ -405,20 +464,4 @@ export class PublicKey implements PublicKey {
405
464
  // Return 65-byte uncompressed public key: `0x04 || x || y`
406
465
  return new Uint8Array(Buffer.concat([Buffer.from([0x04]), Buffer.from(this.x), yBytes]));
407
466
  };
408
-
409
- /**
410
- * Static version of liftX method.
411
- * @param {KeyBytes} x The 32-byte x-coordinate to lift.
412
- * @returns {Uint8Array} The 65-byte uncompressed public key (0x04, x, y).
413
- */
414
- public static xOnly(x: KeyBytes): Uint8Array {
415
- // Ensure x-coordinate is 32 bytes
416
- if (x.length !== 32) {
417
- throw new PublicKeyError('Invalid argument: x-coordinate length must be 32 bytes', 'LIFT_X_ERROR');
418
- }
419
-
420
- // Create a PublicKey instance and lift the x-coordinate
421
- const publicKey = new PublicKey(x);
422
- return publicKey.x;
423
- }
424
467
  }