Skip to content

Commit

Permalink
feat: add signature verify for tx & auth signing
Browse files Browse the repository at this point in the history
  • Loading branch information
dawidsowardx committed May 23, 2023
1 parent ede5246 commit a742862
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 39 deletions.
6 changes: 3 additions & 3 deletions src/chrome/dev-tools/components/LedgerSimulator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { createMessage } from 'chrome/messages/create-message'
import { compiledTxHex } from '../example'
import { curve25519 } from 'crypto/curve25519'
import { secp256k1 } from 'crypto/secp256k1'
import { blakeHashBase64 } from 'crypto/blake2b'
import { blakeHashHexSync } from 'crypto/blake2b'

export const LedgerSimulator = () => {
const [seed, setSeed] = useState<string>(
Expand Down Expand Up @@ -134,7 +134,7 @@ export const LedgerSimulator = () => {
const signTx = async () => {
const wallet = createRadixWallet({ seed, curve })
const { privateKey, publicKey } = wallet.deriveFullPath(derivationPath)
const hash = blakeHashBase64(txIntent)
const hash = blakeHashHexSync(txIntent)

logger.debug('TX intent blake hash', hash)

Expand Down Expand Up @@ -264,7 +264,7 @@ export const LedgerSimulator = () => {
<Text bold css={{ minWidth: '160px' }}>
Blake Intent Hash
</Text>
<Text>{blakeHashBase64(txIntent)}</Text>
<Text>{blakeHashHexSync(txIntent)}</Text>
</Box>
<Box flex="row">
<Box>
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/blake2b.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { blake2b, blakeHashBase64 } from './blake2b'
import { blake2b, blakeHashHexSync } from './blake2b'
import { Buffer } from 'buffer'

describe('blake2b', () => {
Expand All @@ -13,7 +13,7 @@ describe('blake2b', () => {
})

it('should hash base64 string synchronously', () => {
const hash = blakeHashBase64('dGVzdA==')
const hash = blakeHashHexSync('74657374')
expect(hash).toBe(
'928b20366943e2afd11ebc0eae2e53a93bf177a4fcf35bcc64d503704e65e202'
)
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/blake2b.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const blake2b = (input: Buffer): ResultAsync<Buffer, Error> => {
}
}

export const blakeHashBase64 = (data: string) =>
export const blakeHashHexSync = (data: string) =>
blake2bHash(32)
.update(new Uint8Array(Buffer.from(data, 'base64')))
.update(new Uint8Array(Buffer.from(data, 'hex')))
.digest('hex')
62 changes: 39 additions & 23 deletions src/ledger/wrapper/ledger-wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,23 @@ const createLedgerWrapperWithMockedTransport = (
})
}

const getExpectedTransactionSigningExchanges = (
instructionCode: string,
finalOutput: string,
const getExpectedTransactionSigningExchanges = ({
instructionCode,
p1,
encodedDerivationPath,
finalOutput,
}: {
instructionCode: string
finalOutput: string
p1: string
) => [
encodedDerivationPath: string
}) => [
{
input: 'aa120000',
output: '305495ba9000',
},
{
input: `aa${instructionCode}${p1}0019068000002c800003fe8000000a8000020d80000000800004d6`,
input: `aa${instructionCode}${p1}00${encodedDerivationPath}`,
output: '9000',
},
{
Expand Down Expand Up @@ -322,16 +328,24 @@ describe('Ledger Babylon Wrapper', () => {

it('should sign verbose TX using curve25519', async () => {
const ledger = createLedgerWrapperWithMockedTransport(
getExpectedTransactionSigningExchanges(
LedgerInstructionCode.SignTxEd255519,
'5ad8cd006761aa698ea77f271c421a7ea9e34da45b4e827d2fce1b5205933b77e852261381cfaa0a8ecfba52622d5c1560462db70df08fc905111e2a9a5fa601cffce054df51fb4072e7faf627e0f64f168fd8811f749d34720ac8da264bac06aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9000',
'00'
)
getExpectedTransactionSigningExchanges({
p1: '00',
instructionCode: LedgerInstructionCode.SignTxEd255519,
encodedDerivationPath:
'19068000002c800003fe8000000a8000020d800005b480000001',
finalOutput:
'b6d6f0ddd426dbce9af6dd6480c3e116823aa6ad05c97faef2c3b2ee678620d2e7f6a4887b54d9d7a0114fb1e8c359ed77c1d9db84d8acb0ffc518b90974ba01152fb698abd4a5aa588514bb217cbb20878c118588762bfbd3c3937d394a67915cb98b84f9fba860c2d91580c95b875736342050aa139be941927584908daf689000',
})
)

const result = await ledger.signTransaction({
ledgerDevice,
signers: keysParameters,
signers: [
{
curve: 'curve25519',
derivationPath: 'm/44H/1022H/10H/525H/1460H/1H',
},
],
displayHash: false,
compiledTransactionIntent: compiledTxHex.setMetadata,
mode: 'verbose',
Expand All @@ -343,30 +357,32 @@ describe('Ledger Babylon Wrapper', () => {
{
derivedPublicKey: {
curve: 'curve25519',
derivationPath: `m/44'/1022'/10'/525'/0'/1238'`,
derivationPath: `m/44H/1022H/10H/525H/1460H/1H`,
publicKey:
'cffce054df51fb4072e7faf627e0f64f168fd8811f749d34720ac8da264bac06',
'152fb698abd4a5aa588514bb217cbb20878c118588762bfbd3c3937d394a6791',
},
signature:
'5ad8cd006761aa698ea77f271c421a7ea9e34da45b4e827d2fce1b5205933b77e852261381cfaa0a8ecfba52622d5c1560462db70df08fc905111e2a9a5fa601',
'b6d6f0ddd426dbce9af6dd6480c3e116823aa6ad05c97faef2c3b2ee678620d2e7f6a4887b54d9d7a0114fb1e8c359ed77c1d9db84d8acb0ffc518b90974ba01',
},
])
})

it('should sign summary TX using secp256k1', async () => {
const ledger = createLedgerWrapperWithMockedTransport(
getExpectedTransactionSigningExchanges(
LedgerInstructionCode.SignTxSecp256k1Smart,
'5adadad8cd006761aa698ea77f271c421a7ea9e34da45b4e827d2fce1b5205933b77e852261381cfaa0a8ecfba52622d5c1560462db70df08fc905111e2a9a5fa601cffce054df51fb4072e7faf627e0f64f168fd8811f749d34720ac8da264bac06aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9000',
'01'
)
getExpectedTransactionSigningExchanges({
instructionCode: LedgerInstructionCode.SignTxSecp256k1Smart,
p1: '01',
encodedDerivationPath: '15058000002c800003fe8000000a8000020d800004d6',
finalOutput:
'016c5f7dd77eb25825c814b11f2657b9ffd906dc9be187ff931c841cadb53570ef193a4c6041e615e5c547e171c309402be0e339882109ddd0479201272f52fcdb024483ba4e13195ed3b50b103c502a7799749261ae22a5b20950dd8815f65686455cb98b84f9fba860c2d91580c95b875736342050aa139be941927584908daf689000',
})
)

const result = await ledger.signTransaction({
ledgerDevice,
signers: [
{
derivationPath: `m/44'/1022'/10'/525'/0'/1238'`,
derivationPath: `m/44H/1022H/10H/525H/1238H`,
curve: 'secp256k1',
},
],
Expand All @@ -381,12 +397,12 @@ describe('Ledger Babylon Wrapper', () => {
{
derivedPublicKey: {
curve: 'secp256k1',
derivationPath: `m/44'/1022'/10'/525'/0'/1238'`,
derivationPath: `m/44H/1022H/10H/525H/1238H`,
publicKey:
'01cffce054df51fb4072e7faf627e0f64f168fd8811f749d34720ac8da264bac06',
'024483ba4e13195ed3b50b103c502a7799749261ae22a5b20950dd8815f6568645',
},
signature:
'5adadad8cd006761aa698ea77f271c421a7ea9e34da45b4e827d2fce1b5205933b77e852261381cfaa0a8ecfba52622d5c1560462db70df08fc905111e2a9a5fa6',
'016c5f7dd77eb25825c814b11f2657b9ffd906dc9be187ff931c841cadb53570ef193a4c6041e615e5c547e171c309402be0e339882109ddd0479201272f52fcdb',
},
])
})
Expand Down
56 changes: 47 additions & 9 deletions src/ledger/wrapper/ledger-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { getDataLength } from './utils'
import { LedgerSubjects } from './subjects'
import { curve25519 } from 'crypto/curve25519'
import { secp256k1 } from 'crypto/secp256k1'
import { blakeHashHexSync } from 'crypto/blake2b'

export type LedgerOptions = Partial<{
transport: typeof TransportWebHID
Expand Down Expand Up @@ -287,15 +288,21 @@ export const LedgerWrapper = ({
>
) =>
() => {
const addresLength = params.dAppDefinitionAddress.length.toString(16)

const addressLength = params.dAppDefinitionAddress.length.toString(16)
const encodedDappAddress = Buffer.from(
params.dAppDefinitionAddress,
'utf-8'
).toString('hex')
const encodedOrigin = Buffer.from(params.origin, 'utf-8').toString('hex')
const data =
params.challenge +
addresLength +
Buffer.from(params.dAppDefinitionAddress, 'utf-8').toString('hex') +
Buffer.from(params.origin, 'utf-8').toString('hex')
params.challenge + addressLength + encodedDappAddress + encodedOrigin
const dataLength = getDataLength(data)
return ok({ challengeData: `${dataLength}${data}` })
return ok({
challengeData: `${dataLength}${data}`,
signedMessage: blakeHashHexSync(
`${params.challenge}${addressLength}${encodedDappAddress}${encodedOrigin}`
),
})
}

const getOlympiaDeviceInfo = ({
Expand Down Expand Up @@ -390,7 +397,7 @@ export const LedgerWrapper = ({
exchange(LedgerInstructionCode.GetDeviceId)
.andThen(ensureCorrectDeviceId(params.ledgerDevice.id))
.andThen(parseSignAuthParams(params))
.andThen(({ challengeData }) =>
.andThen(({ challengeData, signedMessage }) =>
params.signers.reduce(
(acc: ResultAsync<SignatureOfSigner[], string>, signer, index) =>
acc.andThen((signatures) => {
Expand All @@ -401,6 +408,7 @@ export const LedgerWrapper = ({
)

const {
verifySignature,
signAuthCommand,
signatureByteCount,
publicKeyByteCount,
Expand All @@ -413,13 +421,30 @@ export const LedgerWrapper = ({
instructionClass: LedgerInstructionClass.ac,
})
)
.map((result) => {
.andThen((result) => {
const publicKey = result.slice(
signatureByteCount * 2,
signatureByteCount * 2 + publicKeyByteCount * 2
)

const signature = result.slice(0, signatureByteCount * 2)

const isValid = verifySignature({
message: signedMessage,
publicKey,
signature,
})

if (isValid.isErr()) {
return err(isValid.error)
}

return ok({
signature,
publicKey,
})
})
.map(({ signature, publicKey }) => {
const entry: SignatureOfSigner = {
derivedPublicKey: {
...signer,
Expand Down Expand Up @@ -457,6 +482,7 @@ export const LedgerWrapper = ({
signatureByteCount,
publicKeyByteCount,
encodedDerivationPath,
verifySignature,
} = parseSignerParams(signer, params)
const digestLength = 32 * 2
return signersAcc.andThen((previousValue) => {
Expand Down Expand Up @@ -501,6 +527,18 @@ export const LedgerWrapper = ({
sigOffset + 2 * publicKeyByteCount
)

const isValid = verifySignature({
message: blakeHashHexSync(
params.compiledTransactionIntent
),
publicKey,
signature,
})

if (isValid.isErr()) {
return err(isValid.error)
}

if (signature.length !== signatureByteCount * 2) {
logger.error(
`Signature length is ${signature.length} whereas it should be ${signatureByteCount} bytes * 2`
Expand Down

0 comments on commit a742862

Please sign in to comment.