Skip to content

Commit

Permalink
Recover pubkey from signature (#6)
Browse files Browse the repository at this point in the history
* Feat: Recover pubkey from signature

* Refact: Move all functions to lib/utils

* Fix: Remove unused console.log

* Fix: Remove CryptoJS lib dependency

* Fix: Set pubkey from state management

* Fix: Remove hardcode from signature recover id

Co-authored-by: João Dias <7918067+jaonoctus@users.noreply.github.com>

---------

Co-authored-by: João Dias <7918067+jaonoctus@users.noreply.github.com>
  • Loading branch information
TheMhv and jaonoctus authored Dec 12, 2024
1 parent ff9e9a2 commit ac237e2
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 4 deletions.
31 changes: 28 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"lucide-vue-next": "^0.468.0",
"luxon": "^3.5.0",
"radix-vue": "^1.9.11",
"secp256k1": "^5.0.1",
"tailwind-merge": "^2.5.5",
"tailwindcss-animate": "^1.0.7",
"vee-validate": "^4.14.7",
Expand All @@ -40,6 +41,7 @@
"@types/jsdom": "^21.1.7",
"@types/luxon": "^3.4.2",
"@types/node": "^22.9.3",
"@types/secp256k1": "^4.0.6",
"@vitejs/plugin-vue": "^5.2.1",
"@vitest/eslint-plugin": "1.1.10",
"@vue/eslint-config-prettier": "^10.1.0",
Expand Down
94 changes: 94 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import * as secp256k1 from 'secp256k1'

import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'

import { onBeforeMount, reactive } from 'vue'
import { useClipboard } from '@vueuse/core'

import type { LightningReceipt } from '@/types/index'
import type { DecodedInvoice } from 'light-bolt11-decoder'

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
Expand Down Expand Up @@ -49,3 +52,94 @@ export function useForm() {
form,
}
}

export function strToHex(str: string) {
return str
.split('')
.map((x) => x.charCodeAt(0).toString(16))
.join('')
}

const hexToArrayBuffer = (hexString: string) => {
const bytes = new Uint8Array(hexString.length / 2)
for (let i = 0; i < bytes.length; i++) {
bytes[i] = parseInt(hexString.substr(i * 2, 2), 16)
}
return bytes.buffer
}

export function byteArrayToHexString(byteArray: Uint8Array) {
return Array.prototype.map
.call(byteArray, function (byte) {
return ('0' + (byte & 0xff).toString(16)).slice(-2)
})
.join('')
}

export function bech32To8BitArray(str: string) {
const bech32CharValues = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l'
const int5Array = str.split('').map((char) => bech32CharValues.indexOf(char))

let count = 0
let buffer = 0
const byteArray = []

int5Array.forEach((value) => {
buffer = (buffer << 5) + value
count += 5

while (count >= 8) {
byteArray.push((buffer >> (count - 8)) & 255)
count -= 8
}
})

if (count > 0) {
byteArray.push((buffer << (8 - count)) & 255)
}

return Uint8Array.from(byteArray)
}

export async function getPubkeyFromSignature(decoded: DecodedInvoice) {
const signature = decoded.sections.find((section) => section.name === 'signature')

if (!signature || !signature.letters || !signature.value) {
return null
}

const prefixSections = ['lightning_network', 'coin_network', 'amount']

const prefix = decoded.sections
.filter((section) => prefixSections.includes(section.name))
.map((section) => {
if ('letters' in section) return section.letters
})
.join('')

if (!prefix) {
return null
}

const separator = decoded.sections.find((section) => section.name === 'separator')?.letters

if (!separator) {
return null
}

const splitInvoice = decoded.paymentRequest.split(prefix + separator)

const data = splitInvoice[1].split(signature.letters)[0]

const signingData = strToHex(prefix) + byteArrayToHexString(bech32To8BitArray(data))

const hash = await crypto.subtle.digest('SHA-256', hexToArrayBuffer(signingData))

const recoveryId = parseInt(signature.value.slice(-2), 16);
const signatureValue = signature.value.slice(0, -2)
const sigParsed = hexToArrayBuffer(signatureValue)

const sigPubkey = secp256k1.ecdsaRecover(new Uint8Array(sigParsed), recoveryId, new Uint8Array(hash), true)

return byteArrayToHexString(sigPubkey)
}
24 changes: 23 additions & 1 deletion src/pages/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import bolt11 from 'light-bolt11-decoder'
// import { Duration } from 'luxon'
import { Icon } from '@iconify/vue'
import { useForm } from '@/lib/utils'
import { useForm, getPubkeyFromSignature } from '@/lib/utils'
import {
Card,
CardHeader,
Expand Down Expand Up @@ -33,6 +33,8 @@ const isVerified = ref(false)
const { form } = useForm()
const payeePubKey = ref("");
const decodedInvoice = computed(() => {
try {
const decoded = bolt11.decode(form.invoice)
Expand All @@ -55,10 +57,12 @@ const decodedInvoice = computed(() => {
amount: Math.floor(Number(amount) / 1000),
description,
paymentHash,
decoded
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
console.error(error)
return null
}
})
Expand All @@ -68,6 +72,7 @@ watchEffect(async () => {
if (decodedInvoice.value) {
isPaid.value = await checkPaymentProof()
isVerified.value = true
payeePubKey.value = await getPubkeyFromSignature(decodedInvoice.value.decoded) || "";
}
})
Expand Down Expand Up @@ -156,6 +161,23 @@ function formatLong(text: string) {
<CopyButton title="payment hash" :value="decodedInvoice.paymentHash" />
</TableCell>
</TableRow>
<TableRow v-if="payeePubKey">
<TableCell class="font-medium"> Payee Pub Key </TableCell>
<TableCell class="text-right">
<span>{{ formatLong(payeePubKey) }}</span>

<a
:href="`https://amboss.space/node/${payeePubKey}`"
target="_blank"
>
<Button variant="ghost"
class="m-0 mx-3 p-0 hover:bg-transparent"
>
<Icon icon="lucide:external-link" />
</Button>
</a>
</TableCell>
</TableRow>
<TableRow>
<TableCell class="font-medium"> Status </TableCell>
<TableCell class="text-right font-medium">
Expand Down

0 comments on commit ac237e2

Please sign in to comment.