refactor(protocol): encode ThpAck **only** from ThpState

This commit is contained in:
Szymon Lesisz
2025-11-19 17:13:37 +01:00
committed by Szymon Lesisz
parent 10c54bd35d
commit a43bdb2945
3 changed files with 6 additions and 30 deletions

View File

@@ -11,7 +11,7 @@ import {
} from './constants';
import { aesgcm, crc32 } from './crypto';
import { getIvFromNonce } from './crypto/tools';
import { addAckBit, addSequenceBit, getControlBit, isThpMessageName } from './utils';
import { addAckBit, addSequenceBit, isThpMessageName } from './utils';
// @trezor/protobuf encodeMessage without direct reference to protobuf root
type ProtobufEncoder = (
@@ -191,34 +191,17 @@ export const encodeProtobufMessage = (
// example: 2012340004d9fcce58
// [magic | channel | len | crc ]
// [20 | 1234 | 0004 | d9fcce58]
const encodeReadAck = (channel: Buffer, syncBit: number) => {
export const encodeAck = (state: ThpState) => {
const length = Buffer.alloc(2);
length.writeUInt16BE(CRC_LENGTH);
const magic = addAckBit(THP_READ_ACK_HEADER_BYTE, syncBit);
const message = Buffer.concat([magic, channel, length]);
const magic = addAckBit(THP_READ_ACK_HEADER_BYTE, state.recvAckBit);
const message = Buffer.concat([magic, state.channel, length]);
const crc = crc32(message);
return Buffer.concat([message, crc]);
};
export const encodeAck = (bytesOrState: Buffer | ThpState) => {
if (Buffer.isBuffer(bytesOrState)) {
// 1 byte
const magic = bytesOrState.readUInt8();
// sequence bit
const { ackBit } = getControlBit(magic);
// 2 bytes channel id
const channel = bytesOrState.subarray(1, 3);
return encodeReadAck(channel, ackBit);
}
const { channel, recvBit } = bytesOrState;
return encodeReadAck(channel, recvBit);
};
// Encode protocol-v2 message
export const encode = (options: {
messageName: string;

View File

@@ -66,20 +66,13 @@ describe('protocol-thp', () => {
it('encode/decode ThpAck', () => {
thpState.setChannel(Buffer.from('1234', 'hex'));
const encodeAsBytes1 = encodeAck(Buffer.from('201234', 'hex')); // ackByte: 0
expect(encodeAsBytes1.toString('hex')).toEqual('2012340004d9fcce58');
const encodeAsBytes2 = encodeAck(Buffer.from('281234', 'hex')); // ackByte: 1
expect(encodeAsBytes2.toString('hex')).toEqual('2812340004e98c8599');
const encodeAsState1 = encodeAck(thpState); // ackByte: 0
expect(encodeAsState1.toString('hex')).toEqual('2012340004d9fcce58');
thpState.updateSyncBit('recv');
thpState.sync('recv', 'ThpAck');
const encodeAsState2 = encodeAck(thpState); // ackByte: 1
expect(encodeAsState2.toString('hex')).toEqual('2812340004e98c8599');
expect(decode(decodeV2(encodeAsBytes1), protobufDecoder, thpState).type).toBe('ThpAck');
expect(decode(decodeV2(encodeAsBytes2), protobufDecoder, thpState).type).toBe('ThpAck');
expect(decode(decodeV2(encodeAsState1), protobufDecoder, thpState).type).toBe('ThpAck');
expect(decode(decodeV2(encodeAsState2), protobufDecoder, thpState).type).toBe('ThpAck');
});

View File

@@ -47,7 +47,7 @@ export const receiveThpMessage = async ({
const isAckExpected = protocolThp.isAckExpected(thpState.expectedResponses || []);
if (!skipAck && isAckExpected) {
const chunk = protocolThp.encodeAck(message.payload.header);
const chunk = protocolThp.encodeAck(thpState);
logger?.debug(`receiveThpMessage send ThpAck`);