Skip to content

Commit

Permalink
feat: add secp256k1 auth signing
Browse files Browse the repository at this point in the history
  • Loading branch information
dawidsowardx committed May 17, 2023
1 parent 196b313 commit 92fa045
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 45 deletions.
6 changes: 4 additions & 2 deletions src/chrome/dev-tools/components/WalletSimulator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { Box, Button, Header, Text } from 'components'
import {
getDerivePublicKeyPayload,
getDeviceInfoPayload,
getSignChallengePayload,
getSignEd222519ChallengePayload,
getSignSecp256k1ChallengePayload,
getImportFromOlympiaPayload,
getSignEd25519TransactionPayload,
getSignSecp256k1TransactionPayload,
Expand All @@ -26,7 +27,8 @@ export const WalletSimulator = () => {
'Get Public Key': getDerivePublicKeyPayload(),
'Sign TX (Secp256k1)': getSignSecp256k1TransactionPayload(),
'Sign TX (Curve25519)': getSignEd25519TransactionPayload(),
'Sign Auth': getSignChallengePayload(),
'Sign Auth (Curve25519)': getSignEd222519ChallengePayload(),
'Sign Auth (Secp256k1)': getSignSecp256k1ChallengePayload(),
}

useEffect(() => {
Expand Down
29 changes: 24 additions & 5 deletions src/chrome/dev-tools/example.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
KeyParameters,
LedgerDeviceIdRequest,
LedgerImportOlympiaDeviceRequest,
LedgerPublicKeyRequest,
Expand Down Expand Up @@ -91,17 +92,35 @@ export const getSignSecp256k1TransactionPayload =
mode: 'verbose',
})

export const getSignChallengePayload = (): LedgerSignChallengeRequest => ({
const getSignChallengePayload = (
signers: KeyParameters[]
): LedgerSignChallengeRequest => ({
interactionId: crypto.randomUUID(),
discriminator: 'signChallenge',
derivationPaths: ['m/44H/1022H/10H/525H/1460H/0H'],
signers,
ledgerDevice: {
name: 'My Ledger Device',
model: 'nanoS',
id: '41ac202687326a4fc6cb677e9fd92d08b91ce46c669950d58790d4d5e583adc0',
},
challenge: '140100298edb9cadd80423c1e15e2521d44f51be8b6a7953c9f03d83a8220071',
origin: 'https://rola.xrd',
challenge: '17f3cb369f2632454f7f22c24e72b0adf7b95e36f2297467d3ff04010b2967e1',
origin: 'https://dashboard.rdx.works',
dAppDefinitionAddress:
'account_tdx_b_1p8ahenyznrqy2w0tyg00r82rwuxys6z8kmrhh37c7maqpydx7p',
'account_tdx_b_1p9dkged3rpzy860ampt5jpmvv3yl4y6f5yppp4tnscdslvt9v3',
})

export const getSignEd222519ChallengePayload = () =>
getSignChallengePayload([
{
curve: 'curve25519',
derivationPath: 'm/44H/1022H/12H/525H/1460H/0H',
},
])

export const getSignSecp256k1ChallengePayload = () =>
getSignChallengePayload([
{
curve: 'secp256k1',
derivationPath: 'm/44H/1022H/10H/525H/1238H',
},
])
2 changes: 1 addition & 1 deletion src/ledger/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export type LedgerSignTransactionRequest = z.infer<
export const LedgerSignChallengeRequestSchema = object({
interactionId: string(),
discriminator: literal('signChallenge'),
derivationPaths: string().array(),
signers: KeyParametersSchema.array(),
ledgerDevice: LedgerDeviceSchema,
challenge: string(),
origin: string(),
Expand Down
1 change: 1 addition & 0 deletions src/ledger/wrapper/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export const LedgerInstructionCode = {
SignTxSecp256k1: '51',
SignTxSecp256k1Smart: '52',
SignAuthEd25519: '61',
SignAuthSecp256k1: '71',
} as const

export type LedgerError = Values<typeof LedgerErrorCode>
Expand Down
8 changes: 8 additions & 0 deletions src/ledger/wrapper/encode-derivation-path.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ describe('encode derivation path', () => {
`m/44H/1022H/10H/525H/0H/1238H`,
'19068000002c800003fe8000000a8000020d80000000800004d6',
],
[
'm/44H/1022H/10H/525H/1238H',
'15058000002c800003fe8000000a8000020d800004d6',
],
[
'm/44H/1022H/12H/525H/1460H/0H',
'19068000002c800003fe8000000c8000020d800005b480000000',
],
[
`m/44'/1022'/10'/618'/1'/1211'`,
'19068000002c800003fe8000000a8000026a80000001800004bb',
Expand Down
28 changes: 17 additions & 11 deletions src/ledger/wrapper/ledger-wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ describe('Ledger Babylon Wrapper', () => {
})

describe('auth signing', () => {
it('should sign challange using curve25519', async () => {
it('should sign challange using different curves', async () => {
const ledger = createLedgerWrapperWithMockedTransport([
{
input: 'aa120000',
Expand All @@ -389,22 +389,28 @@ describe('Ledger Babylon Wrapper', () => {
'5015423efc3ee29338df1877b7c9eaf563e894e89a327da9d5b5abbb7c2cda6ad36a66d6219d3817dba61737c0df398b7f5ae2df5b04a85c5f6985542684d80d451152a1cef7be603205086d4ebac0a0b78fda2ff4684b9dea5ca9ef003d4e7dc05cd851c0ff9d3d6022a23072640d4863b99c68d56ba1796dc0a75c32c46cef9000',
},
{
input: 'aa61000019068000002c800003fe8000000c8000020d800005b480000001',
input: 'aa71000015058000002c800003fe8000000c8000020d800004d6',
output: '9000',
},
{
input:
'ac6100007d17f3cb369f2632454f7f22c24e72b0adf7b95e36f2297467d3ff04010b2967e1416163636f756e745f7464785f625f317039646b6765643372707a79383630616d7074356a706d767633796c34793666357970707034746e736364736c767439763368747470733a2f2f64617368626f6172642e7264782e776f726b73',
'ac7100007d17f3cb369f2632454f7f22c24e72b0adf7b95e36f2297467d3ff04010b2967e1416163636f756e745f7464785f625f317039646b6765643372707a79383630616d7074356a706d767633796c34793666357970707034746e736364736c767439763368747470733a2f2f64617368626f6172642e7264782e776f726b73',
output:
'5015423efc3ee29338df1877b7c9eaf563e894e89a327da9d5b5abbb7c2cda6ad36a66d6219d3817dba61737c0df398b7f5ae2df5b04a85c5f6985542684d80d451152a1cef7be603205086d4ebac0a0b78fda2ff4684b9dea5ca9ef003d4e7dc05cd851c0ff9d3d6022a23072640d4863b99c68d56ba1796dc0a75c32c46cef9000',
'011c38168b1071585ccef652471beac0efcce58176c5ec24cd6e1af45058ec057e2990bdd899d24ea12c745c6c58819b86891998e2d7e1374eadca1ac2920ac187024483ba4e13195ed3b50b103c502a7799749261ae22a5b20950dd8815f6568645c05cd851c0ff9d3d6022a23072640d4863b99c68d56ba1796dc0a75c32c46cef9000',
},
])

const result = await ledger.signAuth({
ledgerDevice,
derivationPaths: [
`m/44H/1022H/12H/525H/1460H/0H`,
`m/44H/1022H/12H/525H/1460H/1H`,
signers: [
{
curve: 'curve25519',
derivationPath: `m/44H/1022H/12H/525H/1460H/0H`,
},
{
curve: 'secp256k1',
derivationPath: `m/44H/1022H/12H/525H/1238H`,
},
],
challenge:
'17f3cb369f2632454f7f22c24e72b0adf7b95e36f2297467d3ff04010b2967e1',
Expand All @@ -424,12 +430,12 @@ describe('Ledger Babylon Wrapper', () => {
'5015423efc3ee29338df1877b7c9eaf563e894e89a327da9d5b5abbb7c2cda6ad36a66d6219d3817dba61737c0df398b7f5ae2df5b04a85c5f6985542684d80d',
},
{
curve: 'curve25519',
derivationPath: `m/44H/1022H/12H/525H/1460H/1H`,
curve: 'secp256k1',
derivationPath: `m/44H/1022H/12H/525H/1238H`,
publicKey:
'451152a1cef7be603205086d4ebac0a0b78fda2ff4684b9dea5ca9ef003d4e7d',
'024483ba4e13195ed3b50b103c502a7799749261ae22a5b20950dd8815f6568645',
signature:
'5015423efc3ee29338df1877b7c9eaf563e894e89a327da9d5b5abbb7c2cda6ad36a66d6219d3817dba61737c0df398b7f5ae2df5b04a85c5f6985542684d80d',
'011c38168b1071585ccef652471beac0efcce58176c5ec24cd6e1af45058ec057e2990bdd899d24ea12c745c6c58819b86891998e2d7e1374eadca1ac2920ac187',
},
])
})
Expand Down
63 changes: 37 additions & 26 deletions src/ledger/wrapper/ledger-wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ const getCurveConfig = ({ curve }: KeyParameters) =>
publicKeyByteCount: 32,
signatureByteCount: 64,
signTx: LedgerInstructionCode.SignTxEd255519,
signAuth: LedgerInstructionCode.SignAuthEd25519,
getPublicKey: LedgerInstructionCode.GetPubKeyEd25519,
signTxSmart: LedgerInstructionCode.SignTxEd255519Smart,
},
secp256k1: {
publicKeyByteCount: 33,
signatureByteCount: 65,
signTx: LedgerInstructionCode.SignTxSecp256k1,
signAuth: LedgerInstructionCode.SignAuthSecp256k1,
getPublicKey: LedgerInstructionCode.GetPubKeySecp256k1,
signTxSmart: LedgerInstructionCode.SignTxSecp256k1Smart,
},
Expand All @@ -67,6 +69,12 @@ export const LedgerWrapper = ({
() => LedgerErrorCode.FailedToListLedgerDevices
)
.andThen((devices) => {
logger.debug(
'Found Ledger devices',
devices.map(
({ productName, productId }) => `${productId}, ${productName}`
)
)
if (devices.length > 1) {
return err(LedgerErrorCode.MultipleLedgerConnected)
}
Expand Down Expand Up @@ -157,18 +165,24 @@ export const LedgerWrapper = ({

const parseSignerParams = (
signer: KeyParameters,
params: Omit<
params?: Omit<
LedgerSignTransactionRequest,
'discriminator' | 'interactionId'
>
) => {
const { signTx, signTxSmart, signatureByteCount, publicKeyByteCount } =
getCurveConfig(signer)
const command = params.mode === 'summary' ? signTxSmart : signTx
const {
signTx,
signTxSmart,
signatureByteCount,
publicKeyByteCount,
signAuth: signAuthCommand,
} = getCurveConfig(signer)
const command = params?.mode === 'summary' ? signTxSmart : signTx

const encodedDerivationPath = encodeDerivationPath(signer.derivationPath)
return {
command,
signAuthCommand,
encodedDerivationPath,
signatureByteCount,
publicKeyByteCount,
Expand Down Expand Up @@ -303,39 +317,36 @@ export const LedgerWrapper = ({
.andThen(ensureCorrectDeviceId(params.ledgerDevice.id))
.andThen(parseSignAuthParams(params))
.andThen(({ challengeData }) =>
params.derivationPaths.reduce(
(
acc: ResultAsync<SignatureOfSigner[], string>,
derivationPath,
index
) =>
params.signers.reduce(
(acc: ResultAsync<SignatureOfSigner[], string>, signer, index) =>
acc.andThen((signatures) => {
setProgressMessage(
`Gathering ${index + 1} out of ${
params.derivationPaths.length
params.signers.length
} signatures`
)

const encodedDerivationPath =
encodeDerivationPath(derivationPath)
const {
signAuthCommand,
signatureByteCount,
publicKeyByteCount,
encodedDerivationPath,
} = parseSignerParams(signer)

return exchange(
LedgerInstructionCode.SignAuthEd25519,
encodedDerivationPath
)
return exchange(signAuthCommand, encodedDerivationPath)
.andThen(() =>
exchange(
LedgerInstructionCode.SignAuthEd25519,
challengeData,
{ instructionClass: LedgerInstructionClass.ac }
)
exchange(signAuthCommand, challengeData, {
instructionClass: LedgerInstructionClass.ac,
})
)
.map((result) => {
const entry: SignatureOfSigner = {
curve: 'curve25519',
derivationPath,
signature: result.slice(0, 128),
publicKey: result.slice(128, 192),
...signer,
signature: result.slice(0, signatureByteCount * 2),
publicKey: result.slice(
signatureByteCount * 2,
signatureByteCount * 2 + publicKeyByteCount * 2
),
}
return [...signatures, entry]
})
Expand Down

0 comments on commit 92fa045

Please sign in to comment.