Skip to content

Commit

Permalink
account APDU docs + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jleni committed May 12, 2024
1 parent 74f5a6c commit 5006bbd
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 244 deletions.
283 changes: 141 additions & 142 deletions docs/APDUSPEC.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions js/jest.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['/node_modules/', '/dist/']
}
2 changes: 1 addition & 1 deletion js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"format:check": "FORCE_COLOR=1 prettier --check .",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"test": "yarn build && ts-jest",
"test": "yarn build && jest",
"upgrade": "bunx npm-check-updates -i"
},
"dependencies": {
Expand Down
46 changes: 27 additions & 19 deletions js/src/app.test.ts → js/src/__test__/addr.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,49 @@
/* eslint-disable no-console */
import { MockTransport } from '@ledgerhq/hw-transport-mocker'

import { CLA, INS, P1_VALUES, SAPLING_NF_LEN } from './consts'
import ZCashApp from './index'
import {
SAPLING_ADDR_LEN,
SAPLING_AK_LEN,
SAPLING_DIV_LEN,
SAPLING_IVK_LEN,
SAPLING_NK_LEN,
SAPLING_OVK_LEN,
} from '../consts'
import ZCashApp from '../index'

describe('ZCashApp', () => {
describe('getNullifier', () => {
it('should correctly handle the getNullifier command', async () => {

describe('getAddressSamplingFromDiversifier', () => {
it('should correctly handle the getAddrDiv command', async () => {
const mockResponse = Buffer.concat([
Buffer.from([0x01, 0x02, 0x03, 0x04]), // Example nullifier data
Buffer.alloc(SAPLING_ADDR_LEN), // empty address
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const pos = Buffer.from([0x00, 0x01, 0x02, 0x03])
const cm = Buffer.from([0x04, 0x05, 0x06, 0x07])

const response = await app.getNullifier(zip32Account, pos, cm)
const div = Buffer.alloc(SAPLING_DIV_LEN)
const response = await app.getAddressSamplingFromDiversifier(zip32Account, div)

expect(response.nfRaw).toEqual('01020304')
expect(transport.send).toHaveBeenCalledWith(CLA, INS.GET_NF_SAPLING, P1_VALUES.SHOW_ADDRESS_IN_DEVICE, 0, expect.any(Buffer), [
0x9000,
])
expect(response.addressRaw).toEqual(Buffer.alloc(SAPLING_ADDR_LEN))
})
})

it('should throw an error if the device returns an error status', async () => {
const errorResponse = Buffer.from([0x69, 0x85]) // Example error SW
const transport = new MockTransport(errorResponse)
describe('getAddressSapling', () => {
it('should correctly handle the getAddressSapling command', async () => {
const mockResponse = Buffer.concat([
Buffer.alloc(SAPLING_ADDR_LEN), // empty address
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const pos = Buffer.from([0x00, 0x01, 0x02, 0x03])
const cm = Buffer.from([0x04, 0x05, 0x06, 0x07])
const response = await app.getAddressSapling(zip32Account)

await expect(app.getNullifier(zip32Account, pos, cm)).rejects.toThrow()
expect(response.addressRaw).toEqual(Buffer.alloc(SAPLING_ADDR_LEN))
})
})

})
128 changes: 128 additions & 0 deletions js/src/__test__/keys.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/******************************************************************************
* (c) 2018 - 2024 Zondax AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/

/* eslint-disable no-console */
import { MockTransport } from '@ledgerhq/hw-transport-mocker'

import {
SAPLING_ADDR_LEN,
SAPLING_AK_LEN,
SAPLING_DIV_LEN,
SAPLING_IVK_LEN,
SAPLING_NK_LEN,
SAPLING_OVK_LEN,
} from '../consts'
import ZCashApp from '../index'

describe('ZCashApp', () => {
describe('getNullifier', () => {
it('should correctly handle the getNullifier command', async () => {
const mockResponse = Buffer.concat([
Buffer.alloc(32), // empty nullifier
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const pos: bigint = BigInt(12345)
const cm = Buffer.alloc(32)

const response = await app.getNullifierSapling(zip32Account, pos, cm)

expect(response.nfRaw).toEqual(Buffer.alloc(32))
})

it('should throw an error if the device returns an error status', async () => {
const errorResponse = Buffer.from([0x69, 0x85]) // Example error SW
const transport = new MockTransport(errorResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const pos: bigint = BigInt(12345)
const cm = Buffer.alloc(32)

await expect(app.getNullifierSapling(zip32Account, pos, cm)).rejects.toThrow()
})
})

describe('getIvkSapling', () => {
it('should correctly handle the getIvkSapling command', async () => {
const mockResponse = Buffer.concat([
Buffer.alloc(SAPLING_IVK_LEN + SAPLING_DIV_LEN), // empty ivk + div
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const response = await app.getIvkSapling(zip32Account)

expect(response.ivkRaw).toEqual(Buffer.alloc(SAPLING_IVK_LEN))
})
})

describe('getOvkSapling', () => {
it('should correctly handle the getOvkSapling command', async () => {
const mockResponse = Buffer.concat([
Buffer.alloc(SAPLING_OVK_LEN), // empty ovk
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const response = await app.getOvkSapling(zip32Account)

expect(response.ovkRaw).toEqual(Buffer.alloc(SAPLING_OVK_LEN))
})
})

describe('getFvkSapling', () => {
it('should correctly handle the getFvkSapling command', async () => {
const mockResponse = Buffer.concat([
Buffer.alloc(SAPLING_AK_LEN + SAPLING_NK_LEN + SAPLING_OVK_LEN), // empty fvk
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const response = await app.getFvkSapling(zip32Account)

expect(response.akRaw).toEqual(Buffer.alloc(SAPLING_AK_LEN))
expect(response.nkRaw).toEqual(Buffer.alloc(SAPLING_NK_LEN))
expect(response.ovkRaw).toEqual(Buffer.alloc(SAPLING_OVK_LEN))
})
})

describe('getDiversifierList', () => {
it('should correctly handle the getDiversifierList command', async () => {
const mockResponse = Buffer.concat([
Buffer.alloc( 11 * 20 ).fill(0x01),
Buffer.from([0x90, 0x00]), // Status word (SW) for success
])
const transport = new MockTransport(mockResponse)
const app = new ZCashApp(transport)

const zip32Account = 0x01
const startingDiversifier = Buffer.alloc(11)
const response = await app.getDiversifierList(zip32Account, startingDiversifier)

expect(response.diversifiers.length).toBeGreaterThan(0)
})
})
})

0 comments on commit 5006bbd

Please sign in to comment.