@solana/keys 6.3.1 → 6.3.2-canary-20260313143218

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/keys",
3
- "version": "6.3.1",
3
+ "version": "6.3.2-canary-20260313143218",
4
4
  "description": "Helpers for generating and transforming key material",
5
5
  "homepage": "https://www.solanakit.com/api#solanakeys",
6
6
  "exports": {
@@ -33,7 +33,8 @@
33
33
  "types": "./dist/types/index.d.ts",
34
34
  "type": "commonjs",
35
35
  "files": [
36
- "./dist/"
36
+ "./dist/",
37
+ "./src/"
37
38
  ],
38
39
  "sideEffects": false,
39
40
  "keywords": [
@@ -55,11 +56,11 @@
55
56
  "maintained node versions"
56
57
  ],
57
58
  "dependencies": {
58
- "@solana/assertions": "6.3.1",
59
- "@solana/codecs-strings": "6.3.1",
60
- "@solana/errors": "6.3.1",
61
- "@solana/nominal-types": "6.3.1",
62
- "@solana/codecs-core": "6.3.1"
59
+ "@solana/assertions": "6.3.2-canary-20260313143218",
60
+ "@solana/codecs-strings": "6.3.2-canary-20260313143218",
61
+ "@solana/codecs-core": "6.3.2-canary-20260313143218",
62
+ "@solana/nominal-types": "6.3.2-canary-20260313143218",
63
+ "@solana/errors": "6.3.2-canary-20260313143218"
63
64
  },
64
65
  "peerDependencies": {
65
66
  "typescript": "^5.0.0"
@@ -0,0 +1,4 @@
1
+ export const ED25519_ALGORITHM_IDENTIFIER =
2
+ // Resist the temptation to convert this to a simple string; As of version 133.0.3, Firefox
3
+ // requires the object form of `AlgorithmIdentifier` and will throw a `DOMException` otherwise.
4
+ Object.freeze({ name: 'Ed25519' });
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * This package contains utilities for validating, generating, and manipulating addresses and key
3
+ * material. It can be used standalone, but it is also exported as part of Kit
4
+ * [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
5
+ * @packageDocumentation
6
+ */
7
+ export * from './key-pair';
8
+ export * from './private-key';
9
+ export * from './public-key';
10
+ export * from './signatures';
@@ -0,0 +1,140 @@
1
+ import { assertKeyGenerationIsAvailable, assertPRNGIsAvailable } from '@solana/assertions';
2
+ import { ReadonlyUint8Array } from '@solana/codecs-core';
3
+ import {
4
+ SOLANA_ERROR__KEYS__INVALID_KEY_PAIR_BYTE_LENGTH,
5
+ SOLANA_ERROR__KEYS__PUBLIC_KEY_MUST_MATCH_PRIVATE_KEY,
6
+ SolanaError,
7
+ } from '@solana/errors';
8
+
9
+ import { ED25519_ALGORITHM_IDENTIFIER } from './algorithm';
10
+ import { createPrivateKeyFromBytes } from './private-key';
11
+ import { getPublicKeyFromPrivateKey } from './public-key';
12
+ import { signBytes, verifySignature } from './signatures';
13
+
14
+ /**
15
+ * Generates an Ed25519 public/private key pair for use with other methods in this package that
16
+ * accept [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) objects.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { generateKeyPair } from '@solana/keys';
21
+ *
22
+ * const { privateKey, publicKey } = await generateKeyPair();
23
+ * ```
24
+ */
25
+ export async function generateKeyPair(): Promise<CryptoKeyPair> {
26
+ await assertKeyGenerationIsAvailable();
27
+ const keyPair = await crypto.subtle.generateKey(
28
+ /* algorithm */ ED25519_ALGORITHM_IDENTIFIER, // Native implementation status: https://github.com/WICG/webcrypto-secure-curves/issues/20
29
+ /* extractable */ false, // Prevents the bytes of the private key from being visible to JS.
30
+ /* allowed uses */ ['sign', 'verify'],
31
+ );
32
+ return keyPair;
33
+ }
34
+
35
+ /**
36
+ * Given a 64-byte `Uint8Array` secret key, creates an Ed25519 public/private key pair for use with
37
+ * other methods in this package that accept [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
38
+ * objects.
39
+ *
40
+ * @param bytes 64 bytes, the first 32 of which represent the private key and the last 32 of which
41
+ * represent its associated public key
42
+ * @param extractable Setting this to `true` makes it possible to extract the bytes of the private
43
+ * key using the [`crypto.subtle.exportKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey)
44
+ * API. Defaults to `false`.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * import fs from 'fs';
49
+ * import { createKeyPairFromBytes } from '@solana/keys';
50
+ *
51
+ * // Get bytes from local keypair file.
52
+ * const keypairFile = fs.readFileSync('~/.config/solana/id.json');
53
+ * const keypairBytes = new Uint8Array(JSON.parse(keypairFile.toString()));
54
+ *
55
+ * // Create a CryptoKeyPair from the bytes.
56
+ * const { privateKey, publicKey } = await createKeyPairFromBytes(keypairBytes);
57
+ * ```
58
+ */
59
+ export async function createKeyPairFromBytes(
60
+ bytes: ReadonlyUint8Array,
61
+ extractable: boolean = false,
62
+ ): Promise<CryptoKeyPair> {
63
+ assertPRNGIsAvailable();
64
+
65
+ if (bytes.byteLength !== 64) {
66
+ throw new SolanaError(SOLANA_ERROR__KEYS__INVALID_KEY_PAIR_BYTE_LENGTH, { byteLength: bytes.byteLength });
67
+ }
68
+ const [publicKey, privateKey] = await Promise.all([
69
+ crypto.subtle.importKey('raw', bytes.slice(32), ED25519_ALGORITHM_IDENTIFIER, /* extractable */ true, [
70
+ 'verify',
71
+ ]),
72
+ createPrivateKeyFromBytes(bytes.slice(0, 32), extractable),
73
+ ]);
74
+
75
+ // Verify the key pair
76
+ const randomBytes = new Uint8Array(32);
77
+ crypto.getRandomValues(randomBytes);
78
+ const signedData = await signBytes(privateKey, randomBytes);
79
+ const isValid = await verifySignature(publicKey, signedData, randomBytes);
80
+ if (!isValid) {
81
+ throw new SolanaError(SOLANA_ERROR__KEYS__PUBLIC_KEY_MUST_MATCH_PRIVATE_KEY);
82
+ }
83
+
84
+ return { privateKey, publicKey } as CryptoKeyPair;
85
+ }
86
+
87
+ /**
88
+ * Given a private key represented as a 32-byte `Uint8Array`, creates an Ed25519 public/private key
89
+ * pair for use with other methods in this package that accept [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
90
+ * objects.
91
+ *
92
+ * @param bytes 32 bytes that represent the private key
93
+ * @param extractable Setting this to `true` makes it possible to extract the bytes of the private
94
+ * key using the [`crypto.subtle.exportKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey)
95
+ * API. Defaults to `false`.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * import { createKeyPairFromPrivateKeyBytes } from '@solana/keys';
100
+ *
101
+ * const { privateKey, publicKey } = await createKeyPairFromPrivateKeyBytes(new Uint8Array([...]));
102
+ * ```
103
+ *
104
+ * This can be useful when you have a private key but not the corresponding public key or when you
105
+ * need to derive key pairs from seeds. For instance, the following code snippet derives a key pair
106
+ * from the hash of a message.
107
+ *
108
+ * ```ts
109
+ * import { getUtf8Encoder } from '@solana/codecs-strings';
110
+ * import { createKeyPairFromPrivateKeyBytes } from '@solana/keys';
111
+ *
112
+ * const message = getUtf8Encoder().encode('Hello, World!');
113
+ * const seed = new Uint8Array(await crypto.subtle.digest('SHA-256', message));
114
+ *
115
+ * const derivedKeypair = await createKeyPairFromPrivateKeyBytes(seed);
116
+ * ```
117
+ */
118
+ export async function createKeyPairFromPrivateKeyBytes(
119
+ bytes: ReadonlyUint8Array,
120
+ extractable: boolean = false,
121
+ ): Promise<CryptoKeyPair> {
122
+ const privateKeyPromise = createPrivateKeyFromBytes(bytes, extractable);
123
+
124
+ // Here we need the private key to be extractable in order to export
125
+ // it as a public key. Therefore, if the `extractable` parameter
126
+ // is `false`, we need to create two private keys such that:
127
+ // - The extractable one is used to create the public key and
128
+ // - The non-extractable one is the one we will return.
129
+ const [publicKey, privateKey] = await Promise.all([
130
+ // This nested promise makes things efficient by
131
+ // creating the public key in parallel with the
132
+ // second private key creation, if it is needed.
133
+ (extractable ? privateKeyPromise : createPrivateKeyFromBytes(bytes, true /* extractable */)).then(
134
+ async privateKey => await getPublicKeyFromPrivateKey(privateKey, true /* extractable */),
135
+ ),
136
+ privateKeyPromise,
137
+ ]);
138
+
139
+ return { privateKey, publicKey };
140
+ }
@@ -0,0 +1,75 @@
1
+ import { ReadonlyUint8Array } from '@solana/codecs-core';
2
+ import { SOLANA_ERROR__KEYS__INVALID_PRIVATE_KEY_BYTE_LENGTH, SolanaError } from '@solana/errors';
3
+
4
+ import { ED25519_ALGORITHM_IDENTIFIER } from './algorithm';
5
+
6
+ function addPkcs8Header(bytes: ReadonlyUint8Array): ReadonlyUint8Array<ArrayBuffer> {
7
+ // prettier-ignore
8
+ return new Uint8Array([
9
+ /**
10
+ * PKCS#8 header
11
+ */
12
+ 0x30, // ASN.1 sequence tag
13
+ 0x2e, // Length of sequence (46 more bytes)
14
+
15
+ 0x02, // ASN.1 integer tag
16
+ 0x01, // Length of integer
17
+ 0x00, // Version number
18
+
19
+ 0x30, // ASN.1 sequence tag
20
+ 0x05, // Length of sequence
21
+ 0x06, // ASN.1 object identifier tag
22
+ 0x03, // Length of object identifier
23
+ // Edwards curve algorithms identifier https://oid-rep.orange-labs.fr/get/1.3.101.112
24
+ 0x2b, // iso(1) / identified-organization(3) (The first node is multiplied by the decimal 40 and the result is added to the value of the second node)
25
+ 0x65, // thawte(101)
26
+ // Ed25519 identifier
27
+ 0x70, // id-Ed25519(112)
28
+
29
+ /**
30
+ * Private key payload
31
+ */
32
+ 0x04, // ASN.1 octet string tag
33
+ 0x22, // String length (34 more bytes)
34
+
35
+ // Private key bytes as octet string
36
+ 0x04, // ASN.1 octet string tag
37
+ 0x20, // String length (32 bytes)
38
+
39
+ ...bytes
40
+ ]);
41
+ }
42
+
43
+ /**
44
+ * Given a private key represented as a 32-byte `Uint8Array`, creates an Ed25519 private key for use
45
+ * with other methods in this package that accept
46
+ * [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) objects.
47
+ *
48
+ * @param bytes 32 bytes that represent the private key
49
+ * @param extractable Setting this to `true` makes it possible to extract the bytes of the private
50
+ * key using the [`crypto.subtle.exportKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey)
51
+ * API. Defaults to `false`.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * import { createPrivateKeyFromBytes } from '@solana/keys';
56
+ *
57
+ * const privateKey = await createPrivateKeyFromBytes(new Uint8Array([...]));
58
+ * const extractablePrivateKey = await createPrivateKeyFromBytes(new Uint8Array([...]), true);
59
+ * ```
60
+ */
61
+ export async function createPrivateKeyFromBytes(
62
+ bytes: ReadonlyUint8Array,
63
+ extractable: boolean = false,
64
+ ): Promise<CryptoKey> {
65
+ const actualLength = bytes.byteLength;
66
+ if (actualLength !== 32) {
67
+ throw new SolanaError(SOLANA_ERROR__KEYS__INVALID_PRIVATE_KEY_BYTE_LENGTH, {
68
+ actualLength,
69
+ });
70
+ }
71
+ const privateKeyBytesPkcs8 = addPkcs8Header(bytes);
72
+ return await crypto.subtle.importKey('pkcs8', privateKeyBytesPkcs8, ED25519_ALGORITHM_IDENTIFIER, extractable, [
73
+ 'sign',
74
+ ]);
75
+ }
@@ -0,0 +1,50 @@
1
+ import { assertKeyExporterIsAvailable } from '@solana/assertions';
2
+ import { SOLANA_ERROR__SUBTLE_CRYPTO__CANNOT_EXPORT_NON_EXTRACTABLE_KEY, SolanaError } from '@solana/errors';
3
+
4
+ /**
5
+ * Given an extractable [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
6
+ * private key, gets the corresponding public key as a
7
+ * [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey).
8
+ *
9
+ * @param extractable Setting this to `true` makes it possible to extract the bytes of the public
10
+ * key using the [`crypto.subtle.exportKey()`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/exportKey)
11
+ * API. Defaults to `false`.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { createPrivateKeyFromBytes, getPublicKeyFromPrivateKey } from '@solana/keys';
16
+ *
17
+ * const privateKey = await createPrivateKeyFromBytes(new Uint8Array([...]), true);
18
+ *
19
+ * const publicKey = await getPublicKeyFromPrivateKey(privateKey);
20
+ * const extractablePublicKey = await getPublicKeyFromPrivateKey(privateKey, true);
21
+ * ```
22
+ */
23
+ export async function getPublicKeyFromPrivateKey(
24
+ privateKey: CryptoKey,
25
+ extractable: boolean = false,
26
+ ): Promise<CryptoKey> {
27
+ assertKeyExporterIsAvailable();
28
+
29
+ if (privateKey.extractable === false) {
30
+ throw new SolanaError(SOLANA_ERROR__SUBTLE_CRYPTO__CANNOT_EXPORT_NON_EXTRACTABLE_KEY, { key: privateKey });
31
+ }
32
+
33
+ // Export private key.
34
+ const jwk = await crypto.subtle.exportKey('jwk', privateKey);
35
+
36
+ // Import public key.
37
+ return await crypto.subtle.importKey(
38
+ 'jwk',
39
+ {
40
+ crv /* curve */: 'Ed25519',
41
+ ext /* extractable */: extractable,
42
+ key_ops /* key operations */: ['verify'],
43
+ kty /* key type */: 'OKP' /* octet key pair */,
44
+ x /* public key x-coordinate */: jwk.x,
45
+ },
46
+ 'Ed25519',
47
+ extractable,
48
+ ['verify'],
49
+ );
50
+ }
@@ -0,0 +1,253 @@
1
+ import { assertSigningCapabilityIsAvailable, assertVerificationCapabilityIsAvailable } from '@solana/assertions';
2
+ import { Encoder, ReadonlyUint8Array, toArrayBuffer } from '@solana/codecs-core';
3
+ import { getBase58Encoder } from '@solana/codecs-strings';
4
+ import {
5
+ SOLANA_ERROR__KEYS__INVALID_SIGNATURE_BYTE_LENGTH,
6
+ SOLANA_ERROR__KEYS__SIGNATURE_STRING_LENGTH_OUT_OF_RANGE,
7
+ SolanaError,
8
+ } from '@solana/errors';
9
+ import { Brand, EncodedString } from '@solana/nominal-types';
10
+
11
+ import { ED25519_ALGORITHM_IDENTIFIER } from './algorithm';
12
+
13
+ /**
14
+ * A 64-byte Ed25519 signature as a base58-encoded string.
15
+ */
16
+ export type Signature = Brand<EncodedString<string, 'base58'>, 'Signature'>;
17
+ /**
18
+ * A 64-byte Ed25519 signature.
19
+ *
20
+ * Whenever you need to verify that a particular signature is, in fact, the one that would have been
21
+ * produced by signing some known bytes using the private key associated with some known public key,
22
+ * use the {@link verifySignature} function in this package.
23
+ */
24
+ export type SignatureBytes = Brand<Uint8Array, 'SignatureBytes'>;
25
+
26
+ let base58Encoder: Encoder<string> | undefined;
27
+
28
+ /**
29
+ * Asserts that an arbitrary string is a base58-encoded Ed25519 signature.
30
+ *
31
+ * Useful when you receive a string from user input or an untrusted network API that you expect to
32
+ * represent an Ed25519 signature (eg. of a transaction).
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { assertIsSignature } from '@solana/keys';
37
+ *
38
+ * // Imagine a function that asserts whether a user-supplied signature is valid or not.
39
+ * function handleSubmit() {
40
+ * // We know only that what the user typed conforms to the `string` type.
41
+ * const signature: string = signatureInput.value;
42
+ * try {
43
+ * // If this type assertion function doesn't throw, then
44
+ * // Typescript will upcast `signature` to `Signature`.
45
+ * assertIsSignature(signature);
46
+ * // At this point, `signature` is a `Signature` that can be used with the RPC.
47
+ * const {
48
+ * value: [status],
49
+ * } = await rpc.getSignatureStatuses([signature]).send();
50
+ * } catch (e) {
51
+ * // `signature` turned out not to be a base58-encoded signature
52
+ * }
53
+ * }
54
+ * ```
55
+ */
56
+ export function assertIsSignature(putativeSignature: string): asserts putativeSignature is Signature {
57
+ if (!base58Encoder) base58Encoder = getBase58Encoder();
58
+ // Fast-path; see if the input string is of an acceptable length.
59
+ if (
60
+ // Lowest value (64 bytes of zeroes)
61
+ putativeSignature.length < 64 ||
62
+ // Highest value (64 bytes of 255)
63
+ putativeSignature.length > 88
64
+ ) {
65
+ throw new SolanaError(SOLANA_ERROR__KEYS__SIGNATURE_STRING_LENGTH_OUT_OF_RANGE, {
66
+ actualLength: putativeSignature.length,
67
+ });
68
+ }
69
+ // Slow-path; actually attempt to decode the input string.
70
+ const bytes = base58Encoder.encode(putativeSignature);
71
+ assertIsSignatureBytes(bytes);
72
+ }
73
+
74
+ /**
75
+ * Asserts that an arbitrary `ReadonlyUint8Array` is an Ed25519 signature.
76
+ *
77
+ * Useful when you receive a `ReadonlyUint8Array` from an external interface (like the browser wallets' `signMessage` API) that you expect to
78
+ * represent an Ed25519 signature.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * import { assertIsSignatureBytes } from '@solana/keys';
83
+ *
84
+ * // Imagine a function that verifies a signature.
85
+ * function verifySignature() {
86
+ * // We know only that the input conforms to the `ReadonlyUint8Array` type.
87
+ * const signatureBytes: ReadonlyUint8Array = signatureBytesInput;
88
+ * try {
89
+ * // If this type assertion function doesn't throw, then
90
+ * // Typescript will upcast `signatureBytes` to `SignatureBytes`.
91
+ * assertIsSignatureBytes(signatureBytes);
92
+ * // At this point, `signatureBytes` is a `SignatureBytes` that can be used with `verifySignature`.
93
+ * if (!(await verifySignature(publicKey, signatureBytes, data))) {
94
+ * throw new Error('The data were *not* signed by the private key associated with `publicKey`');
95
+ * }
96
+ * } catch (e) {
97
+ * // `signatureBytes` turned out not to be a 64-byte Ed25519 signature
98
+ * }
99
+ * }
100
+ * ```
101
+ */
102
+ export function assertIsSignatureBytes(
103
+ putativeSignatureBytes: ReadonlyUint8Array,
104
+ ): asserts putativeSignatureBytes is SignatureBytes {
105
+ const numBytes = putativeSignatureBytes.byteLength;
106
+ if (numBytes !== 64) {
107
+ throw new SolanaError(SOLANA_ERROR__KEYS__INVALID_SIGNATURE_BYTE_LENGTH, {
108
+ actualLength: numBytes,
109
+ });
110
+ }
111
+ }
112
+
113
+ /**
114
+ * A type guard that accepts a string as input. It will both return `true` if the string conforms to
115
+ * the {@link Signature} type and will refine the type for use in your program.
116
+ *
117
+ * @example
118
+ * ```ts
119
+ * import { isSignature } from '@solana/keys';
120
+ *
121
+ * if (isSignature(signature)) {
122
+ * // At this point, `signature` has been refined to a
123
+ * // `Signature` that can be used with the RPC.
124
+ * const {
125
+ * value: [status],
126
+ * } = await rpc.getSignatureStatuses([signature]).send();
127
+ * setSignatureStatus(status);
128
+ * } else {
129
+ * setError(`${signature} is not a transaction signature`);
130
+ * }
131
+ * ```
132
+ */
133
+ export function isSignature(putativeSignature: string): putativeSignature is Signature {
134
+ if (!base58Encoder) base58Encoder = getBase58Encoder();
135
+
136
+ // Fast-path; see if the input string is of an acceptable length.
137
+ if (
138
+ // Lowest value (64 bytes of zeroes)
139
+ putativeSignature.length < 64 ||
140
+ // Highest value (64 bytes of 255)
141
+ putativeSignature.length > 88
142
+ ) {
143
+ return false;
144
+ }
145
+ // Slow-path; actually attempt to decode the input string.
146
+ const bytes = base58Encoder.encode(putativeSignature);
147
+ return isSignatureBytes(bytes);
148
+ }
149
+
150
+ /**
151
+ * A type guard that accepts a `ReadonlyUint8Array` as input. It will both return `true` if the `ReadonlyUint8Array` conforms to
152
+ * the {@link SignatureBytes} type and will refine the type for use in your program.
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * import { isSignatureBytes } from '@solana/keys';
157
+ *
158
+ * if (isSignatureBytes(signatureBytes)) {
159
+ * // At this point, `signatureBytes` has been refined to a
160
+ * // `SignatureBytes` that can be used with `verifySignature`.
161
+ * if (!(await verifySignature(publicKey, signatureBytes, data))) {
162
+ * throw new Error('The data were *not* signed by the private key associated with `publicKey`');
163
+ * }
164
+ * } else {
165
+ * setError(`${signatureBytes} is not a 64-byte Ed25519 signature`);
166
+ * }
167
+ * ```
168
+ */
169
+ export function isSignatureBytes(putativeSignatureBytes: ReadonlyUint8Array): putativeSignatureBytes is SignatureBytes {
170
+ return putativeSignatureBytes.byteLength === 64;
171
+ }
172
+
173
+ /**
174
+ * Given a private [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) and a
175
+ * `Uint8Array` of bytes, this method will return the 64-byte Ed25519 signature of that data as a
176
+ * `Uint8Array`.
177
+ *
178
+ * @example
179
+ * ```ts
180
+ * import { signBytes } from '@solana/keys';
181
+ *
182
+ * const data = new Uint8Array([1, 2, 3]);
183
+ * const signature = await signBytes(privateKey, data);
184
+ * ```
185
+ */
186
+ export async function signBytes(key: CryptoKey, data: ReadonlyUint8Array): Promise<SignatureBytes> {
187
+ assertSigningCapabilityIsAvailable();
188
+ const signedData = await crypto.subtle.sign(ED25519_ALGORITHM_IDENTIFIER, key, toArrayBuffer(data));
189
+ return new Uint8Array(signedData) as SignatureBytes;
190
+ }
191
+
192
+ /**
193
+ * This helper combines _asserting_ that a string is an Ed25519 signature with _coercing_ it to the
194
+ * {@link Signature} type. It's best used with untrusted input.
195
+ *
196
+ * @example
197
+ * ```ts
198
+ * import { signature } from '@solana/keys';
199
+ *
200
+ * const signature = signature(userSuppliedSignature);
201
+ * const {
202
+ * value: [status],
203
+ * } = await rpc.getSignatureStatuses([signature]).send();
204
+ * ```
205
+ */
206
+ export function signature(putativeSignature: string): Signature {
207
+ assertIsSignature(putativeSignature);
208
+ return putativeSignature;
209
+ }
210
+
211
+ /**
212
+ * This helper combines _asserting_ that a `ReadonlyUint8Array` is an Ed25519 signature with _coercing_ it to the
213
+ * {@link SignatureBytes} type. It's best used with untrusted input.
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * import { signatureBytes } from '@solana/keys';
218
+ *
219
+ * const signature = signatureBytes(userSuppliedSignatureBytes);
220
+ * if (!(await verifySignature(publicKey, signature, data))) {
221
+ * throw new Error('The data were *not* signed by the private key associated with `publicKey`');
222
+ * }
223
+ * ```
224
+ */
225
+ export function signatureBytes(putativeSignatureBytes: ReadonlyUint8Array): SignatureBytes {
226
+ assertIsSignatureBytes(putativeSignatureBytes);
227
+ return putativeSignatureBytes;
228
+ }
229
+
230
+ /**
231
+ * Given a public [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey), some
232
+ * {@link SignatureBytes}, and a `Uint8Array` of data, this method will return `true` if the
233
+ * signature was produced by signing the data using the private key associated with the public key,
234
+ * and `false` otherwise.
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * import { verifySignature } from '@solana/keys';
239
+ *
240
+ * const data = new Uint8Array([1, 2, 3]);
241
+ * if (!(await verifySignature(publicKey, signature, data))) {
242
+ * throw new Error('The data were *not* signed by the private key associated with `publicKey`');
243
+ * }
244
+ * ```
245
+ */
246
+ export async function verifySignature(
247
+ key: CryptoKey,
248
+ signature: SignatureBytes,
249
+ data: ReadonlyUint8Array,
250
+ ): Promise<boolean> {
251
+ assertVerificationCapabilityIsAvailable();
252
+ return await crypto.subtle.verify(ED25519_ALGORITHM_IDENTIFIER, key, toArrayBuffer(signature), toArrayBuffer(data));
253
+ }