ox 0.8.1 → 0.8.3
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/CHANGELOG.md +20 -0
- package/Ed25519/package.json +6 -0
- package/X25519/package.json +6 -0
- package/_cjs/core/Bls.js +10 -0
- package/_cjs/core/Bls.js.map +1 -1
- package/_cjs/core/Ed25519.js +53 -0
- package/_cjs/core/Ed25519.js.map +1 -0
- package/_cjs/core/P256.js +23 -0
- package/_cjs/core/P256.js.map +1 -1
- package/_cjs/core/Secp256k1.js +20 -0
- package/_cjs/core/Secp256k1.js.map +1 -1
- package/_cjs/core/WebAuthnP256.js +5 -4
- package/_cjs/core/WebAuthnP256.js.map +1 -1
- package/_cjs/core/WebCryptoP256.js +31 -0
- package/_cjs/core/WebCryptoP256.js.map +1 -1
- package/_cjs/core/X25519.js +45 -0
- package/_cjs/core/X25519.js.map +1 -0
- package/_cjs/index.js +4 -2
- package/_cjs/index.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/core/Bls.js +109 -0
- package/_esm/core/Bls.js.map +1 -1
- package/_esm/core/Ed25519.js +121 -0
- package/_esm/core/Ed25519.js.map +1 -0
- package/_esm/core/P256.js +54 -2
- package/_esm/core/P256.js.map +1 -1
- package/_esm/core/Secp256k1.js +50 -0
- package/_esm/core/Secp256k1.js.map +1 -1
- package/_esm/core/WebAuthnP256.js +5 -4
- package/_esm/core/WebAuthnP256.js.map +1 -1
- package/_esm/core/WebCryptoP256.js +72 -0
- package/_esm/core/WebCryptoP256.js.map +1 -1
- package/_esm/core/X25519.js +97 -0
- package/_esm/core/X25519.js.map +1 -0
- package/_esm/index.js +65 -0
- package/_esm/index.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/core/Bls.d.ts +124 -0
- package/_types/core/Bls.d.ts.map +1 -1
- package/_types/core/Ed25519.d.ts +156 -0
- package/_types/core/Ed25519.d.ts.map +1 -0
- package/_types/core/P256.d.ts +68 -2
- package/_types/core/P256.d.ts.map +1 -1
- package/_types/core/Secp256k1.d.ts +67 -0
- package/_types/core/Secp256k1.d.ts.map +1 -1
- package/_types/core/WebAuthnP256.d.ts +2 -0
- package/_types/core/WebAuthnP256.d.ts.map +1 -1
- package/_types/core/WebCryptoP256.d.ts +76 -1
- package/_types/core/WebCryptoP256.d.ts.map +1 -1
- package/_types/core/X25519.d.ts +127 -0
- package/_types/core/X25519.d.ts.map +1 -0
- package/_types/index.d.ts +65 -0
- package/_types/index.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/core/Bls.ts +150 -0
- package/core/Ed25519.ts +237 -0
- package/core/P256.ts +114 -2
- package/core/Secp256k1.ts +110 -0
- package/core/WebAuthnP256.ts +9 -3
- package/core/WebCryptoP256.ts +141 -1
- package/core/X25519.ts +202 -0
- package/index.ts +67 -0
- package/package.json +11 -1
- package/version.ts +1 -1
package/core/Ed25519.ts
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { ed25519 } from '@noble/curves/ed25519'
|
|
2
|
+
import * as Bytes from './Bytes.js'
|
|
3
|
+
import type * as Errors from './Errors.js'
|
|
4
|
+
import * as Hex from './Hex.js'
|
|
5
|
+
|
|
6
|
+
/** Re-export of noble/curves Ed25519 utilities. */
|
|
7
|
+
export const noble = ed25519
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new Ed25519 key pair consisting of a private key and its corresponding public key.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts twoslash
|
|
14
|
+
* import { Ed25519 } from 'ox'
|
|
15
|
+
*
|
|
16
|
+
* const { privateKey, publicKey } = Ed25519.createKeyPair()
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @param options - The options to generate the key pair.
|
|
20
|
+
* @returns The generated key pair containing both private and public keys.
|
|
21
|
+
*/
|
|
22
|
+
export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
23
|
+
options: createKeyPair.Options<as> = {},
|
|
24
|
+
): createKeyPair.ReturnType<as> {
|
|
25
|
+
const { as = 'Hex' } = options
|
|
26
|
+
const privateKey = randomPrivateKey({ as })
|
|
27
|
+
const publicKey = getPublicKey({ privateKey, as })
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
privateKey: privateKey as never,
|
|
31
|
+
publicKey: publicKey as never,
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export declare namespace createKeyPair {
|
|
36
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
37
|
+
/**
|
|
38
|
+
* Format of the returned private and public keys.
|
|
39
|
+
* @default 'Hex'
|
|
40
|
+
*/
|
|
41
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> = {
|
|
45
|
+
privateKey:
|
|
46
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
47
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
48
|
+
publicKey:
|
|
49
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
50
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type ErrorType =
|
|
54
|
+
| Hex.fromBytes.ErrorType
|
|
55
|
+
| randomPrivateKey.ErrorType
|
|
56
|
+
| getPublicKey.ErrorType
|
|
57
|
+
| Errors.GlobalErrorType
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Computes the Ed25519 public key from a provided private key.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts twoslash
|
|
65
|
+
* import { Ed25519 } from 'ox'
|
|
66
|
+
*
|
|
67
|
+
* const publicKey = Ed25519.getPublicKey({ privateKey: '0x...' })
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @param options - The options to compute the public key.
|
|
71
|
+
* @returns The computed public key.
|
|
72
|
+
*/
|
|
73
|
+
export function getPublicKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
74
|
+
options: getPublicKey.Options<as>,
|
|
75
|
+
): getPublicKey.ReturnType<as> {
|
|
76
|
+
const { as = 'Hex', privateKey } = options
|
|
77
|
+
const privateKeyBytes = Bytes.from(privateKey)
|
|
78
|
+
const publicKeyBytes = ed25519.getPublicKey(privateKeyBytes)
|
|
79
|
+
if (as === 'Hex') return Hex.fromBytes(publicKeyBytes) as never
|
|
80
|
+
return publicKeyBytes as never
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export declare namespace getPublicKey {
|
|
84
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
85
|
+
/**
|
|
86
|
+
* Format of the returned public key.
|
|
87
|
+
* @default 'Hex'
|
|
88
|
+
*/
|
|
89
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
90
|
+
/**
|
|
91
|
+
* Private key to compute the public key from.
|
|
92
|
+
*/
|
|
93
|
+
privateKey: Hex.Hex | Bytes.Bytes
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
97
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
98
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
99
|
+
|
|
100
|
+
type ErrorType =
|
|
101
|
+
| Bytes.from.ErrorType
|
|
102
|
+
| Hex.fromBytes.ErrorType
|
|
103
|
+
| Errors.GlobalErrorType
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Generates a random Ed25519 private key.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts twoslash
|
|
111
|
+
* import { Ed25519 } from 'ox'
|
|
112
|
+
*
|
|
113
|
+
* const privateKey = Ed25519.randomPrivateKey()
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @param options - The options to generate the private key.
|
|
117
|
+
* @returns The generated private key.
|
|
118
|
+
*/
|
|
119
|
+
export function randomPrivateKey<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
120
|
+
options: randomPrivateKey.Options<as> = {},
|
|
121
|
+
): randomPrivateKey.ReturnType<as> {
|
|
122
|
+
const { as = 'Hex' } = options
|
|
123
|
+
const bytes = ed25519.utils.randomPrivateKey()
|
|
124
|
+
if (as === 'Hex') return Hex.fromBytes(bytes) as never
|
|
125
|
+
return bytes as never
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export declare namespace randomPrivateKey {
|
|
129
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
130
|
+
/**
|
|
131
|
+
* Format of the returned private key.
|
|
132
|
+
* @default 'Hex'
|
|
133
|
+
*/
|
|
134
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
138
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
139
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
140
|
+
|
|
141
|
+
type ErrorType = Hex.fromBytes.ErrorType | Errors.GlobalErrorType
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Signs the payload with the provided private key and returns an Ed25519 signature.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```ts twoslash
|
|
149
|
+
* import { Ed25519 } from 'ox'
|
|
150
|
+
*
|
|
151
|
+
* const signature = Ed25519.sign({ // [!code focus]
|
|
152
|
+
* payload: '0xdeadbeef', // [!code focus]
|
|
153
|
+
* privateKey: '0x...' // [!code focus]
|
|
154
|
+
* }) // [!code focus]
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* @param options - The signing options.
|
|
158
|
+
* @returns The Ed25519 signature.
|
|
159
|
+
*/
|
|
160
|
+
export function sign<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
161
|
+
options: sign.Options<as>,
|
|
162
|
+
): sign.ReturnType<as> {
|
|
163
|
+
const { as = 'Hex', payload, privateKey } = options
|
|
164
|
+
const payloadBytes = Bytes.from(payload)
|
|
165
|
+
const privateKeyBytes = Bytes.from(privateKey)
|
|
166
|
+
const signatureBytes = ed25519.sign(payloadBytes, privateKeyBytes)
|
|
167
|
+
if (as === 'Hex') return Hex.fromBytes(signatureBytes) as never
|
|
168
|
+
return signatureBytes as never
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export declare namespace sign {
|
|
172
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
173
|
+
/**
|
|
174
|
+
* Format of the returned signature.
|
|
175
|
+
* @default 'Hex'
|
|
176
|
+
*/
|
|
177
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
178
|
+
/**
|
|
179
|
+
* Payload to sign.
|
|
180
|
+
*/
|
|
181
|
+
payload: Hex.Hex | Bytes.Bytes
|
|
182
|
+
/**
|
|
183
|
+
* Ed25519 private key.
|
|
184
|
+
*/
|
|
185
|
+
privateKey: Hex.Hex | Bytes.Bytes
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
189
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
190
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
191
|
+
|
|
192
|
+
type ErrorType =
|
|
193
|
+
| Bytes.from.ErrorType
|
|
194
|
+
| Hex.fromBytes.ErrorType
|
|
195
|
+
| Errors.GlobalErrorType
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Verifies a payload was signed by the provided public key.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts twoslash
|
|
203
|
+
* import { Ed25519 } from 'ox'
|
|
204
|
+
*
|
|
205
|
+
* const { privateKey, publicKey } = Ed25519.createKeyPair()
|
|
206
|
+
* const signature = Ed25519.sign({ payload: '0xdeadbeef', privateKey })
|
|
207
|
+
*
|
|
208
|
+
* const verified = Ed25519.verify({ // [!code focus]
|
|
209
|
+
* publicKey, // [!code focus]
|
|
210
|
+
* payload: '0xdeadbeef', // [!code focus]
|
|
211
|
+
* signature, // [!code focus]
|
|
212
|
+
* }) // [!code focus]
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* @param options - The verification options.
|
|
216
|
+
* @returns Whether the payload was signed by the provided public key.
|
|
217
|
+
*/
|
|
218
|
+
export function verify(options: verify.Options): boolean {
|
|
219
|
+
const { payload, publicKey, signature } = options
|
|
220
|
+
const payloadBytes = Bytes.from(payload)
|
|
221
|
+
const publicKeyBytes = Bytes.from(publicKey)
|
|
222
|
+
const signatureBytes = Bytes.from(signature)
|
|
223
|
+
return ed25519.verify(signatureBytes, payloadBytes, publicKeyBytes)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export declare namespace verify {
|
|
227
|
+
type Options = {
|
|
228
|
+
/** Payload that was signed. */
|
|
229
|
+
payload: Hex.Hex | Bytes.Bytes
|
|
230
|
+
/** Public key that signed the payload. */
|
|
231
|
+
publicKey: Hex.Hex | Bytes.Bytes
|
|
232
|
+
/** Signature of the payload. */
|
|
233
|
+
signature: Hex.Hex | Bytes.Bytes
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
type ErrorType = Bytes.from.ErrorType | Errors.GlobalErrorType
|
|
237
|
+
}
|
package/core/P256.ts
CHANGED
|
@@ -9,6 +9,54 @@ import * as Entropy from './internal/entropy.js'
|
|
|
9
9
|
/** Re-export of noble/curves P256 utilities. */
|
|
10
10
|
export const noble = secp256r1
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new P256 ECDSA key pair consisting of a private key and its corresponding public key.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts twoslash
|
|
17
|
+
* import { P256 } from 'ox'
|
|
18
|
+
*
|
|
19
|
+
* const { privateKey, publicKey } = P256.createKeyPair()
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @param options - The options to generate the key pair.
|
|
23
|
+
* @returns The generated key pair containing both private and public keys.
|
|
24
|
+
*/
|
|
25
|
+
export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
26
|
+
options: createKeyPair.Options<as> = {},
|
|
27
|
+
): createKeyPair.ReturnType<as> {
|
|
28
|
+
const { as = 'Hex' } = options
|
|
29
|
+
const privateKey = randomPrivateKey({ as })
|
|
30
|
+
const publicKey = getPublicKey({ privateKey })
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
privateKey: privateKey as never,
|
|
34
|
+
publicKey,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export declare namespace createKeyPair {
|
|
39
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
40
|
+
/**
|
|
41
|
+
* Format of the returned private key.
|
|
42
|
+
* @default 'Hex'
|
|
43
|
+
*/
|
|
44
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> = {
|
|
48
|
+
privateKey:
|
|
49
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
50
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
51
|
+
publicKey: PublicKey.PublicKey
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type ErrorType =
|
|
55
|
+
| Hex.fromBytes.ErrorType
|
|
56
|
+
| PublicKey.from.ErrorType
|
|
57
|
+
| Errors.GlobalErrorType
|
|
58
|
+
}
|
|
59
|
+
|
|
12
60
|
/**
|
|
13
61
|
* Computes the P256 ECDSA public key from a provided private key.
|
|
14
62
|
*
|
|
@@ -45,6 +93,71 @@ export declare namespace getPublicKey {
|
|
|
45
93
|
type ErrorType = Errors.GlobalErrorType
|
|
46
94
|
}
|
|
47
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Computes a shared secret using ECDH (Elliptic Curve Diffie-Hellman) between a private key and a public key.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts twoslash
|
|
101
|
+
* import { P256 } from 'ox'
|
|
102
|
+
*
|
|
103
|
+
* const { privateKey: privateKeyA } = P256.createKeyPair()
|
|
104
|
+
* const { publicKey: publicKeyB } = P256.createKeyPair()
|
|
105
|
+
*
|
|
106
|
+
* const sharedSecret = P256.getSharedSecret({
|
|
107
|
+
* privateKey: privateKeyA,
|
|
108
|
+
* publicKey: publicKeyB
|
|
109
|
+
* })
|
|
110
|
+
* ```
|
|
111
|
+
*
|
|
112
|
+
* @param options - The options to compute the shared secret.
|
|
113
|
+
* @returns The computed shared secret.
|
|
114
|
+
*/
|
|
115
|
+
export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
116
|
+
options: getSharedSecret.Options<as>,
|
|
117
|
+
): getSharedSecret.ReturnType<as> {
|
|
118
|
+
const { as = 'Hex', privateKey, publicKey } = options
|
|
119
|
+
const point = secp256r1.ProjectivePoint.fromHex(
|
|
120
|
+
PublicKey.toHex(publicKey).slice(2),
|
|
121
|
+
)
|
|
122
|
+
const privateKeyHex =
|
|
123
|
+
typeof privateKey === 'string'
|
|
124
|
+
? privateKey.slice(2)
|
|
125
|
+
: Hex.fromBytes(privateKey).slice(2)
|
|
126
|
+
const sharedPoint = point.multiply(
|
|
127
|
+
secp256r1.utils.normPrivateKeyToScalar(privateKeyHex),
|
|
128
|
+
)
|
|
129
|
+
const sharedSecret = sharedPoint.toRawBytes(true) // compressed format
|
|
130
|
+
if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
|
|
131
|
+
return sharedSecret as never
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export declare namespace getSharedSecret {
|
|
135
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
136
|
+
/**
|
|
137
|
+
* Format of the returned shared secret.
|
|
138
|
+
* @default 'Hex'
|
|
139
|
+
*/
|
|
140
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
141
|
+
/**
|
|
142
|
+
* Private key to use for the shared secret computation.
|
|
143
|
+
*/
|
|
144
|
+
privateKey: Hex.Hex | Bytes.Bytes
|
|
145
|
+
/**
|
|
146
|
+
* Public key to use for the shared secret computation.
|
|
147
|
+
*/
|
|
148
|
+
publicKey: PublicKey.PublicKey<boolean>
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
152
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
153
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
154
|
+
|
|
155
|
+
type ErrorType =
|
|
156
|
+
| Hex.fromBytes.ErrorType
|
|
157
|
+
| PublicKey.toHex.ErrorType
|
|
158
|
+
| Errors.GlobalErrorType
|
|
159
|
+
}
|
|
160
|
+
|
|
48
161
|
/**
|
|
49
162
|
* Generates a random P256 ECDSA private key.
|
|
50
163
|
*
|
|
@@ -204,8 +317,7 @@ export declare namespace sign {
|
|
|
204
317
|
* ```ts twoslash
|
|
205
318
|
* import { P256 } from 'ox'
|
|
206
319
|
*
|
|
207
|
-
* const privateKey = P256.
|
|
208
|
-
* const publicKey = P256.getPublicKey({ privateKey })
|
|
320
|
+
* const { privateKey, publicKey } = P256.createKeyPair()
|
|
209
321
|
* const signature = P256.sign({ payload: '0xdeadbeef', privateKey })
|
|
210
322
|
*
|
|
211
323
|
* const verified = P256.verify({ // [!code focus]
|
package/core/Secp256k1.ts
CHANGED
|
@@ -11,6 +11,54 @@ import type { OneOf } from './internal/types.js'
|
|
|
11
11
|
/** Re-export of noble/curves secp256k1 utilities. */
|
|
12
12
|
export const noble = secp256k1
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new secp256k1 ECDSA key pair consisting of a private key and its corresponding public key.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts twoslash
|
|
19
|
+
* import { Secp256k1 } from 'ox'
|
|
20
|
+
*
|
|
21
|
+
* const { privateKey, publicKey } = Secp256k1.createKeyPair()
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param options - The options to generate the key pair.
|
|
25
|
+
* @returns The generated key pair containing both private and public keys.
|
|
26
|
+
*/
|
|
27
|
+
export function createKeyPair<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
28
|
+
options: createKeyPair.Options<as> = {},
|
|
29
|
+
): createKeyPair.ReturnType<as> {
|
|
30
|
+
const { as = 'Hex' } = options
|
|
31
|
+
const privateKey = randomPrivateKey({ as })
|
|
32
|
+
const publicKey = getPublicKey({ privateKey })
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
privateKey: privateKey as never,
|
|
36
|
+
publicKey,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export declare namespace createKeyPair {
|
|
41
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
42
|
+
/**
|
|
43
|
+
* Format of the returned private key.
|
|
44
|
+
* @default 'Hex'
|
|
45
|
+
*/
|
|
46
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> = {
|
|
50
|
+
privateKey:
|
|
51
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
52
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
53
|
+
publicKey: PublicKey.PublicKey
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
type ErrorType =
|
|
57
|
+
| Hex.fromBytes.ErrorType
|
|
58
|
+
| PublicKey.from.ErrorType
|
|
59
|
+
| Errors.GlobalErrorType
|
|
60
|
+
}
|
|
61
|
+
|
|
14
62
|
/**
|
|
15
63
|
* Computes the secp256k1 ECDSA public key from a provided private key.
|
|
16
64
|
*
|
|
@@ -48,6 +96,68 @@ export declare namespace getPublicKey {
|
|
|
48
96
|
| Errors.GlobalErrorType
|
|
49
97
|
}
|
|
50
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Computes a shared secret using ECDH (Elliptic Curve Diffie-Hellman) between a private key and a public key.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts twoslash
|
|
104
|
+
* import { Secp256k1 } from 'ox'
|
|
105
|
+
*
|
|
106
|
+
* const { privateKey: privateKeyA } = Secp256k1.createKeyPair()
|
|
107
|
+
* const { publicKey: publicKeyB } = Secp256k1.createKeyPair()
|
|
108
|
+
*
|
|
109
|
+
* const sharedSecret = Secp256k1.getSharedSecret({
|
|
110
|
+
* privateKey: privateKeyA,
|
|
111
|
+
* publicKey: publicKeyB
|
|
112
|
+
* })
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* @param options - The options to compute the shared secret.
|
|
116
|
+
* @returns The computed shared secret.
|
|
117
|
+
*/
|
|
118
|
+
export function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
119
|
+
options: getSharedSecret.Options<as>,
|
|
120
|
+
): getSharedSecret.ReturnType<as> {
|
|
121
|
+
const { as = 'Hex', privateKey, publicKey } = options
|
|
122
|
+
const point = secp256k1.ProjectivePoint.fromHex(
|
|
123
|
+
PublicKey.toHex(publicKey).slice(2),
|
|
124
|
+
)
|
|
125
|
+
const sharedPoint = point.multiply(
|
|
126
|
+
secp256k1.utils.normPrivateKeyToScalar(Hex.from(privateKey).slice(2)),
|
|
127
|
+
)
|
|
128
|
+
const sharedSecret = sharedPoint.toRawBytes(true) // compressed format
|
|
129
|
+
if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
|
|
130
|
+
return sharedSecret as never
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export declare namespace getSharedSecret {
|
|
134
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
135
|
+
/**
|
|
136
|
+
* Format of the returned shared secret.
|
|
137
|
+
* @default 'Hex'
|
|
138
|
+
*/
|
|
139
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
140
|
+
/**
|
|
141
|
+
* Private key to use for the shared secret computation.
|
|
142
|
+
*/
|
|
143
|
+
privateKey: Hex.Hex | Bytes.Bytes
|
|
144
|
+
/**
|
|
145
|
+
* Public key to use for the shared secret computation.
|
|
146
|
+
*/
|
|
147
|
+
publicKey: PublicKey.PublicKey<boolean>
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
151
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
152
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
153
|
+
|
|
154
|
+
type ErrorType =
|
|
155
|
+
| Hex.from.ErrorType
|
|
156
|
+
| PublicKey.toHex.ErrorType
|
|
157
|
+
| Hex.fromBytes.ErrorType
|
|
158
|
+
| Errors.GlobalErrorType
|
|
159
|
+
}
|
|
160
|
+
|
|
51
161
|
/**
|
|
52
162
|
* Generates a random ECDSA private key on the secp256k1 curve.
|
|
53
163
|
*
|
package/core/WebAuthnP256.ts
CHANGED
|
@@ -241,13 +241,13 @@ export function getCredentialCreationOptions(
|
|
|
241
241
|
},
|
|
242
242
|
challenge = createChallenge,
|
|
243
243
|
excludeCredentialIds,
|
|
244
|
+
extensions,
|
|
244
245
|
name: name_,
|
|
245
246
|
rp = {
|
|
246
247
|
id: window.location.hostname,
|
|
247
248
|
name: window.document.title,
|
|
248
249
|
},
|
|
249
250
|
user,
|
|
250
|
-
extensions,
|
|
251
251
|
} = options
|
|
252
252
|
const name = (user?.name ?? name_)!
|
|
253
253
|
return {
|
|
@@ -269,15 +269,15 @@ export function getCredentialCreationOptions(
|
|
|
269
269
|
alg: -7, // p256
|
|
270
270
|
},
|
|
271
271
|
],
|
|
272
|
+
...(extensions && { extensions }),
|
|
272
273
|
rp,
|
|
273
274
|
user: {
|
|
274
275
|
id: user?.id ?? Hash.keccak256(Bytes.fromString(name), { as: 'Bytes' }),
|
|
275
276
|
name,
|
|
276
277
|
displayName: user?.displayName ?? name,
|
|
277
278
|
},
|
|
278
|
-
extensions,
|
|
279
279
|
},
|
|
280
|
-
}
|
|
280
|
+
}
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
export declare namespace getCredentialCreationOptions {
|
|
@@ -374,6 +374,7 @@ export function getCredentialRequestOptions(
|
|
|
374
374
|
const {
|
|
375
375
|
credentialId,
|
|
376
376
|
challenge,
|
|
377
|
+
extensions,
|
|
377
378
|
rpId = window.location.hostname,
|
|
378
379
|
userVerification = 'required',
|
|
379
380
|
} = options
|
|
@@ -395,6 +396,7 @@ export function getCredentialRequestOptions(
|
|
|
395
396
|
}
|
|
396
397
|
: {}),
|
|
397
398
|
challenge: Bytes.fromHex(challenge),
|
|
399
|
+
...(extensions && { extensions }),
|
|
398
400
|
rpId,
|
|
399
401
|
userVerification,
|
|
400
402
|
},
|
|
@@ -407,6 +409,10 @@ export declare namespace getCredentialRequestOptions {
|
|
|
407
409
|
credentialId?: string | string[] | undefined
|
|
408
410
|
/** The challenge to sign. */
|
|
409
411
|
challenge: Hex.Hex
|
|
412
|
+
/** List of Web Authentication API credentials to use during creation or authentication. */
|
|
413
|
+
extensions?:
|
|
414
|
+
| internal.PublicKeyCredentialRequestOptions['extensions']
|
|
415
|
+
| undefined
|
|
410
416
|
/** The relying party identifier to use. */
|
|
411
417
|
rpId?: internal.PublicKeyCredentialRequestOptions['rpId'] | undefined
|
|
412
418
|
/** The user verification requirement. */
|
package/core/WebCryptoP256.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { p256 } from '@noble/curves/p256'
|
|
2
2
|
import * as Bytes from './Bytes.js'
|
|
3
3
|
import type * as Errors from './Errors.js'
|
|
4
|
-
import
|
|
4
|
+
import * as Hex from './Hex.js'
|
|
5
5
|
import * as PublicKey from './PublicKey.js'
|
|
6
6
|
import type * as Signature from './Signature.js'
|
|
7
7
|
import type { Compute } from './internal/types.js'
|
|
@@ -68,6 +68,146 @@ export declare namespace createKeyPair {
|
|
|
68
68
|
type ErrorType = PublicKey.from.ErrorType | Errors.GlobalErrorType
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Generates an ECDH P256 key pair for key agreement that includes:
|
|
73
|
+
*
|
|
74
|
+
* - a `privateKey` of type [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey)
|
|
75
|
+
* - a `publicKey` of type {@link ox#PublicKey.PublicKey}
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts twoslash
|
|
79
|
+
* import { WebCryptoP256 } from 'ox'
|
|
80
|
+
*
|
|
81
|
+
* const { publicKey, privateKey } = await WebCryptoP256.createKeyPairECDH()
|
|
82
|
+
* // @log: {
|
|
83
|
+
* // @log: privateKey: CryptoKey {},
|
|
84
|
+
* // @log: publicKey: {
|
|
85
|
+
* // @log: x: 59295962801117472859457908919941473389380284132224861839820747729565200149877n,
|
|
86
|
+
* // @log: y: 24099691209996290925259367678540227198235484593389470330605641003500238088869n,
|
|
87
|
+
* // @log: prefix: 4,
|
|
88
|
+
* // @log: },
|
|
89
|
+
* // @log: }
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @param options - Options for creating the key pair.
|
|
93
|
+
* @returns The key pair.
|
|
94
|
+
*/
|
|
95
|
+
export async function createKeyPairECDH(
|
|
96
|
+
options: createKeyPairECDH.Options = {},
|
|
97
|
+
): Promise<createKeyPairECDH.ReturnType> {
|
|
98
|
+
const { extractable = false } = options
|
|
99
|
+
const keypair = await globalThis.crypto.subtle.generateKey(
|
|
100
|
+
{
|
|
101
|
+
name: 'ECDH',
|
|
102
|
+
namedCurve: 'P-256',
|
|
103
|
+
},
|
|
104
|
+
extractable,
|
|
105
|
+
['deriveKey', 'deriveBits'],
|
|
106
|
+
)
|
|
107
|
+
const publicKey_raw = await globalThis.crypto.subtle.exportKey(
|
|
108
|
+
'raw',
|
|
109
|
+
keypair.publicKey,
|
|
110
|
+
)
|
|
111
|
+
const publicKey = PublicKey.from(new Uint8Array(publicKey_raw))
|
|
112
|
+
return {
|
|
113
|
+
privateKey: keypair.privateKey,
|
|
114
|
+
publicKey,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export declare namespace createKeyPairECDH {
|
|
119
|
+
type Options = {
|
|
120
|
+
/** A boolean value indicating whether it will be possible to export the private key using `globalThis.crypto.subtle.exportKey()`. */
|
|
121
|
+
extractable?: boolean | undefined
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
type ReturnType = Compute<{
|
|
125
|
+
privateKey: CryptoKey
|
|
126
|
+
publicKey: PublicKey.PublicKey
|
|
127
|
+
}>
|
|
128
|
+
|
|
129
|
+
type ErrorType = PublicKey.from.ErrorType | Errors.GlobalErrorType
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Computes a shared secret using ECDH (Elliptic Curve Diffie-Hellman) between a private key and a public key using Web Crypto APIs.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts twoslash
|
|
137
|
+
* import { WebCryptoP256 } from 'ox'
|
|
138
|
+
*
|
|
139
|
+
* const { privateKey: privateKeyA } = await WebCryptoP256.createKeyPairECDH()
|
|
140
|
+
* const { publicKey: publicKeyB } = await WebCryptoP256.createKeyPairECDH()
|
|
141
|
+
*
|
|
142
|
+
* const sharedSecret = await WebCryptoP256.getSharedSecret({
|
|
143
|
+
* privateKey: privateKeyA,
|
|
144
|
+
* publicKey: publicKeyB
|
|
145
|
+
* })
|
|
146
|
+
* ```
|
|
147
|
+
*
|
|
148
|
+
* @param options - The options to compute the shared secret.
|
|
149
|
+
* @returns The computed shared secret.
|
|
150
|
+
*/
|
|
151
|
+
export async function getSharedSecret<as extends 'Hex' | 'Bytes' = 'Hex'>(
|
|
152
|
+
options: getSharedSecret.Options<as>,
|
|
153
|
+
): Promise<getSharedSecret.ReturnType<as>> {
|
|
154
|
+
const { as = 'Hex', privateKey, publicKey } = options
|
|
155
|
+
|
|
156
|
+
if (privateKey.algorithm.name === 'ECDSA') {
|
|
157
|
+
throw new Error(
|
|
158
|
+
'privateKey is not compatible with ECDH. please use `createKeyPairECDH` to create an ECDH key.',
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const publicKeyCrypto = await globalThis.crypto.subtle.importKey(
|
|
163
|
+
'raw',
|
|
164
|
+
PublicKey.toBytes(publicKey),
|
|
165
|
+
{ name: 'ECDH', namedCurve: 'P-256' },
|
|
166
|
+
false,
|
|
167
|
+
[],
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
const sharedSecretBuffer = await globalThis.crypto.subtle.deriveBits(
|
|
171
|
+
{
|
|
172
|
+
name: 'ECDH',
|
|
173
|
+
public: publicKeyCrypto,
|
|
174
|
+
},
|
|
175
|
+
privateKey,
|
|
176
|
+
256, // 32 bytes * 8 bits/byte
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
const sharedSecret = new Uint8Array(sharedSecretBuffer)
|
|
180
|
+
if (as === 'Hex') return Hex.fromBytes(sharedSecret) as never
|
|
181
|
+
return sharedSecret as never
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export declare namespace getSharedSecret {
|
|
185
|
+
type Options<as extends 'Hex' | 'Bytes' = 'Hex'> = {
|
|
186
|
+
/**
|
|
187
|
+
* Format of the returned shared secret.
|
|
188
|
+
* @default 'Hex'
|
|
189
|
+
*/
|
|
190
|
+
as?: as | 'Hex' | 'Bytes' | undefined
|
|
191
|
+
/**
|
|
192
|
+
* Private key to use for the shared secret computation (must be a CryptoKey for ECDH).
|
|
193
|
+
*/
|
|
194
|
+
privateKey: CryptoKey
|
|
195
|
+
/**
|
|
196
|
+
* Public key to use for the shared secret computation.
|
|
197
|
+
*/
|
|
198
|
+
publicKey: PublicKey.PublicKey<boolean>
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
type ReturnType<as extends 'Hex' | 'Bytes'> =
|
|
202
|
+
| (as extends 'Bytes' ? Bytes.Bytes : never)
|
|
203
|
+
| (as extends 'Hex' ? Hex.Hex : never)
|
|
204
|
+
|
|
205
|
+
type ErrorType =
|
|
206
|
+
| PublicKey.toBytes.ErrorType
|
|
207
|
+
| Hex.fromBytes.ErrorType
|
|
208
|
+
| Errors.GlobalErrorType
|
|
209
|
+
}
|
|
210
|
+
|
|
71
211
|
/**
|
|
72
212
|
* Signs a payload with the provided `CryptoKey` private key and returns a P256 signature.
|
|
73
213
|
*
|