1 | import { leftpad, toJose } from '../util.js'
|
2 | import { Signer } from '../JWT.js'
|
3 | import { sha256 } from '../Digest.js'
|
4 | import { secp256k1 } from '@noble/curves/secp256k1'
|
5 |
|
6 | /**
|
7 | * Creates a configured signer function for signing data using the ES256K (secp256k1 + sha256) algorithm.
|
8 | *
|
9 | * The signing function itself takes the data as a `Uint8Array` or `string` and returns a `base64Url`-encoded signature
|
10 | *
|
11 | * @example
|
12 | * ```typescript
|
13 | * const sign: Signer = ES256KSigner(process.env.PRIVATE_KEY)
|
14 | * const signature: string = await sign(data)
|
15 | * ```
|
16 | *
|
17 | * @param {String} privateKey a private key as `Uint8Array`
|
18 | * @param {Boolean} recoverable an optional flag to add the recovery param to the generated signatures
|
19 | * @return {Function} a configured signer function `(data: string | Uint8Array): Promise<string>`
|
20 | */
|
21 | export function ES256KSigner(privateKey: Uint8Array, recoverable = false): Signer {
|
22 | const privateKeyBytes: Uint8Array = privateKey
|
23 | if (privateKeyBytes.length !== 32) {
|
24 | throw new Error(`bad_key: Invalid private key format. Expecting 32 bytes, but got ${privateKeyBytes.length}`)
|
25 | }
|
26 |
|
27 | return async (data: string | Uint8Array): Promise<string> => {
|
28 | const signature = secp256k1.sign(sha256(data), privateKeyBytes)
|
29 | return toJose(
|
30 | {
|
31 | r: leftpad(signature.r.toString(16)),
|
32 | s: leftpad(signature.s.toString(16)),
|
33 | recoveryParam: signature.recovery,
|
34 | },
|
35 | recoverable
|
36 | )
|
37 | }
|
38 | }
|