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 async function generateKeypair(): Promise<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 let binary = ""; 39 for (let i = 0; i < bytes.length; i++) { 40 binary += String.fromCharCode(bytes[i]); 41 } 42 return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); 43} 44 45export async function createServiceJwt( 46 privateKey: Uint8Array, 47 issuerDid: string, 48 audienceDid: string, 49 lxm: string, 50): Promise<string> { 51 const header = { 52 alg: "ES256K", 53 typ: "JWT", 54 }; 55 56 const now = Math.floor(Date.now() / 1000); 57 const payload = { 58 iss: issuerDid, 59 sub: issuerDid, 60 aud: audienceDid, 61 exp: now + 180, 62 iat: now, 63 lxm: lxm, 64 }; 65 66 const headerEncoded = base64UrlEncode(JSON.stringify(header)); 67 const payloadEncoded = base64UrlEncode(JSON.stringify(payload)); 68 const message = `${headerEncoded}.${payloadEncoded}`; 69 70 const msgBytes = new TextEncoder().encode(message); 71 const hashBuffer = await crypto.subtle.digest("SHA-256", msgBytes); 72 const msgHash = new Uint8Array(hashBuffer); 73 const signature = await secp.signAsync(msgHash, privateKey); 74 const sigBytes = signature.toCompactRawBytes(); 75 const signatureEncoded = base64UrlEncode(sigBytes); 76 77 return `${message}.${signatureEncoded}`; 78} 79 80export function generateDidDocument( 81 did: string, 82 publicKeyMultibase: string, 83 handle: string, 84 pdsEndpoint: string, 85): object { 86 return { 87 "@context": [ 88 "https://www.w3.org/ns/did/v1", 89 "https://w3id.org/security/multikey/v1", 90 "https://w3id.org/security/suites/secp256k1-2019/v1", 91 ], 92 id: did, 93 alsoKnownAs: [`at://${handle}`], 94 verificationMethod: [ 95 { 96 id: `${did}#atproto`, 97 type: "Multikey", 98 controller: did, 99 publicKeyMultibase: publicKeyMultibase, 100 }, 101 ], 102 service: [ 103 { 104 id: "#atproto_pds", 105 type: "AtprotoPersonalDataServer", 106 serviceEndpoint: pdsEndpoint, 107 }, 108 ], 109 }; 110}