Create derive-public-key.post.ts

This commit is contained in:
Pas 2025-08-20 13:42:34 -06:00
parent a24f27679e
commit fa64d49f25

View file

@ -0,0 +1,46 @@
import { z } from 'zod';
import { pbkdf2 } from 'crypto';
import nacl from 'tweetnacl';
const requestSchema = z.object({
mnemonic: z.string().min(1),
});
function toBase64Url(input: Uint8Array): string {
const base64 = Buffer.from(input).toString('base64');
return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
function pbkdf2Async(password: string, salt: string, iterations: number, keyLen: number, digest: string): Promise<Uint8Array> {
return new Promise((resolve, reject) => {
pbkdf2(password, salt, iterations, keyLen, digest, (err, derivedKey) => {
if (err) return reject(err);
resolve(new Uint8Array(derivedKey));
});
});
}
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const parsed = requestSchema.safeParse(body);
if (!parsed.success) {
throw createError({
statusCode: 400,
message: 'Invalid request body',
});
}
const { mnemonic } = parsed.data;
// PBKDF2 (HMAC-SHA256) -> 32-byte seed, iterations = 2048, salt = "mnemonic"
const seed = await pbkdf2Async(mnemonic, 'mnemonic', 2048, 32, 'sha256');
// Deterministic Ed25519 keypair from seed
const keyPair = nacl.sign.keyPair.fromSeed(seed);
const publicKeyBase64Url = toBase64Url(keyPair.publicKey);
return { publicKey: publicKeyBase64Url };
});