this repo has no description
1import * as secp from "@noble/secp256k1"; 2import { base58btc } from "multiformats/bases/base58"; 3 4const SECP256K1_MULTICODEC_PREFIX = new Uint8Array([0xe7, 0x01]); 5 6export interface Keypair { 7 privateKey: Uint8Array; 8 publicKey: Uint8Array; 9 publicKeyMultibase: string; 10 publicKeyDidKey: string; 11} 12 13export function generateKeypair(): Keypair { 14 const privateKey = secp.utils.randomPrivateKey(); 15 const publicKey = secp.getPublicKey(privateKey, true); 16 17 const multicodecKey = new Uint8Array( 18 SECP256K1_MULTICODEC_PREFIX.length + publicKey.length, 19 ); 20 multicodecKey.set(SECP256K1_MULTICODEC_PREFIX, 0); 21 multicodecKey.set(publicKey, SECP256K1_MULTICODEC_PREFIX.length); 22 23 const publicKeyMultibase = base58btc.encode(multicodecKey); 24 const publicKeyDidKey = `did:key:${publicKeyMultibase}`; 25 26 return { 27 privateKey, 28 publicKey, 29 publicKeyMultibase, 30 publicKeyDidKey, 31 }; 32} 33 34function base64UrlEncode(data: Uint8Array | string): string { 35 const bytes = typeof data === "string" 36 ? new TextEncoder().encode(data) 37 : data; 38 const binary = Array.from(bytes, (byte) => String.fromCharCode(byte)).join('') 39 return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); 40} 41 42export async function createServiceJwt( 43 privateKey: Uint8Array, 44 issuerDid: string, 45 audienceDid: string, 46 lxm: string, 47): Promise<string> { 48 const header = { 49 alg: "ES256K", 50 typ: "JWT", 51 }; 52 53 const now = Math.floor(Date.now() / 1000); 54 const payload = { 55 iss: issuerDid, 56 sub: issuerDid, 57 aud: audienceDid, 58 exp: now + 180, 59 iat: now, 60 lxm: lxm, 61 }; 62 63 const headerEncoded = base64UrlEncode(JSON.stringify(header)); 64 const payloadEncoded = base64UrlEncode(JSON.stringify(payload)); 65 const message = `${headerEncoded}.${payloadEncoded}`; 66 67 const msgBytes = new TextEncoder().encode(message); 68 const hashBuffer = await crypto.subtle.digest("SHA-256", msgBytes); 69 const msgHash = new Uint8Array(hashBuffer); 70 const signature = await secp.signAsync(msgHash, privateKey); 71 const sigBytes = signature.toCompactRawBytes(); 72 const signatureEncoded = base64UrlEncode(sigBytes); 73 74 return `${message}.${signatureEncoded}`; 75} 76 77export function generateDidDocument( 78 did: string, 79 publicKeyMultibase: string, 80 handle: string, 81 pdsEndpoint: string, 82): object { 83 return { 84 "@context": [ 85 "https://www.w3.org/ns/did/v1", 86 "https://w3id.org/security/multikey/v1", 87 "https://w3id.org/security/suites/secp256k1-2019/v1", 88 ], 89 id: did, 90 alsoKnownAs: [`at://${handle}`], 91 verificationMethod: [ 92 { 93 id: `${did}#atproto`, 94 type: "Multikey", 95 controller: did, 96 publicKeyMultibase: publicKeyMultibase, 97 }, 98 ], 99 service: [ 100 { 101 id: "#atproto_pds", 102 type: "AtprotoPersonalDataServer", 103 serviceEndpoint: pdsEndpoint, 104 }, 105 ], 106 }; 107}