1 | import { ed25519 } from '@noble/curves/ed25519'
|
2 | import type { Signer } from '../JWT.js'
|
3 | import { bytesToBase64url, stringToBytes } from '../util.js'
|
4 |
|
5 | /**
|
6 | * Creates a configured signer function for signing data using the EdDSA (Ed25519) algorithm.
|
7 | *
|
8 | * The private key is expected to be a `Uint8Array` of 32 bytes, but for compatibility 64 bytes are also acceptable.
|
9 | * Users of `@stablelib/ed25519` or `tweetnacl` will be able to use the 64 byte secret keys that library generates.
|
10 | * These libraries precompute the public key and append it as the last 32 bytes of the secretKey, to speed up later
|
11 | * signing operations.
|
12 | *
|
13 | * The signing function itself takes the data as a `Uint8Array` or utf8 `string` and returns a `base64Url`-encoded
|
14 | * signature
|
15 | *
|
16 | * @example
|
17 | * ```typescript
|
18 | * const sign: Signer = EdDSASigner(process.env.PRIVATE_KEY)
|
19 | * const signature: string = await sign(data)
|
20 | * ```
|
21 | *
|
22 | * @param {String} secretKey a 32 or 64 byte secret key as `Uint8Array`
|
23 | * @return {Function} a configured signer function `(data: string | Uint8Array): Promise<string>`
|
24 | */
|
25 | export function EdDSASigner(secretKey: Uint8Array): Signer {
|
26 | const privateKeyBytes: Uint8Array = secretKey
|
27 | if (![32, 64].includes(privateKeyBytes.length)) {
|
28 | throw new Error(`bad_key: Invalid private key format. Expecting 32 or 64 bytes, but got ${privateKeyBytes.length}`)
|
29 | }
|
30 | return async (data: string | Uint8Array): Promise<string> => {
|
31 | const dataBytes: Uint8Array = typeof data === 'string' ? stringToBytes(data) : data
|
32 | const signature = ed25519.sign(dataBytes, privateKeyBytes.slice(0, 32))
|
33 | return bytesToBase64url(signature)
|
34 | }
|
35 | }
|