diff --git a/src/chrome/dev-tools/components/WalletSimulator.tsx b/src/chrome/dev-tools/components/WalletSimulator.tsx index 4f3a8c99..4cb98a21 100644 --- a/src/chrome/dev-tools/components/WalletSimulator.tsx +++ b/src/chrome/dev-tools/components/WalletSimulator.tsx @@ -6,7 +6,8 @@ import { Box, Button, Header, Text } from 'components' import { getDerivePublicKeyPayload, getDeviceInfoPayload, - getSignChallengePayload, + getSignEd222519ChallengePayload, + getSignSecp256k1ChallengePayload, getImportFromOlympiaPayload, getSignEd25519TransactionPayload, getSignSecp256k1TransactionPayload, @@ -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(() => { diff --git a/src/chrome/dev-tools/example.ts b/src/chrome/dev-tools/example.ts index 6c2f68b1..5aeb337c 100644 --- a/src/chrome/dev-tools/example.ts +++ b/src/chrome/dev-tools/example.ts @@ -1,4 +1,5 @@ import { + KeyParameters, LedgerDeviceIdRequest, LedgerImportOlympiaDeviceRequest, LedgerPublicKeyRequest, @@ -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', + }, + ]) diff --git a/src/ledger/schemas.ts b/src/ledger/schemas.ts index 690dbfa9..d632782f 100644 --- a/src/ledger/schemas.ts +++ b/src/ledger/schemas.ts @@ -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(), diff --git a/src/ledger/wrapper/constants.ts b/src/ledger/wrapper/constants.ts index 1b5b819b..c12a4cc8 100644 --- a/src/ledger/wrapper/constants.ts +++ b/src/ledger/wrapper/constants.ts @@ -87,6 +87,7 @@ export const LedgerInstructionCode = { SignTxSecp256k1: '51', SignTxSecp256k1Smart: '52', SignAuthEd25519: '61', + SignAuthSecp256k1: '71', } as const export type LedgerError = Values diff --git a/src/ledger/wrapper/encode-derivation-path.test.ts b/src/ledger/wrapper/encode-derivation-path.test.ts index d3a79e30..7ffb8dac 100644 --- a/src/ledger/wrapper/encode-derivation-path.test.ts +++ b/src/ledger/wrapper/encode-derivation-path.test.ts @@ -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', diff --git a/src/ledger/wrapper/ledger-wrapper.test.ts b/src/ledger/wrapper/ledger-wrapper.test.ts index b8384c7c..8d587a53 100644 --- a/src/ledger/wrapper/ledger-wrapper.test.ts +++ b/src/ledger/wrapper/ledger-wrapper.test.ts @@ -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', @@ -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', @@ -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', }, ]) }) diff --git a/src/ledger/wrapper/ledger-wrapper.ts b/src/ledger/wrapper/ledger-wrapper.ts index 901512a7..67106b6a 100644 --- a/src/ledger/wrapper/ledger-wrapper.ts +++ b/src/ledger/wrapper/ledger-wrapper.ts @@ -42,6 +42,7 @@ const getCurveConfig = ({ curve }: KeyParameters) => publicKeyByteCount: 32, signatureByteCount: 64, signTx: LedgerInstructionCode.SignTxEd255519, + signAuth: LedgerInstructionCode.SignAuthEd25519, getPublicKey: LedgerInstructionCode.GetPubKeyEd25519, signTxSmart: LedgerInstructionCode.SignTxEd255519Smart, }, @@ -49,6 +50,7 @@ const getCurveConfig = ({ curve }: KeyParameters) => publicKeyByteCount: 33, signatureByteCount: 65, signTx: LedgerInstructionCode.SignTxSecp256k1, + signAuth: LedgerInstructionCode.SignAuthSecp256k1, getPublicKey: LedgerInstructionCode.GetPubKeySecp256k1, signTxSmart: LedgerInstructionCode.SignTxSecp256k1Smart, }, @@ -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) } @@ -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, @@ -303,39 +317,36 @@ export const LedgerWrapper = ({ .andThen(ensureCorrectDeviceId(params.ledgerDevice.id)) .andThen(parseSignAuthParams(params)) .andThen(({ challengeData }) => - params.derivationPaths.reduce( - ( - acc: ResultAsync, - derivationPath, - index - ) => + params.signers.reduce( + (acc: ResultAsync, 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] })