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