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.randomSecretKey(); 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 "", 40 ); 41 return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); 42} 43 44export async function createServiceJwt( 45 privateKey: Uint8Array, 46 issuerDid: string, 47 audienceDid: string, 48 lxm: string, 49): Promise<string> { 50 const header = { 51 alg: "ES256K", 52 typ: "JWT", 53 }; 54 55 const now = Math.floor(Date.now() / 1000); 56 const payload = { 57 iss: issuerDid, 58 sub: issuerDid, 59 aud: audienceDid, 60 exp: now + 180, 61 iat: now, 62 lxm: lxm, 63 }; 64 65 const headerEncoded = base64UrlEncode(JSON.stringify(header)); 66 const payloadEncoded = base64UrlEncode(JSON.stringify(payload)); 67 const message = `${headerEncoded}.${payloadEncoded}`; 68 69 const msgBytes = new TextEncoder().encode(message); 70 const hashBuffer = await crypto.subtle.digest("SHA-256", msgBytes); 71 const msgHash = new Uint8Array(hashBuffer); 72 const sigBytes = await secp.signAsync(msgHash, privateKey, { 73 prehash: false, 74 }); 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}