Files
zeekayandHanzo Dev 416b8c92e8 Go 1.27.1, and the code it can say more simply
Modules declare go 1.27.1 and the build images follow. go fix applied the
modernizers: min, range over int, and the last // +build line is gone.
go.mod lists the versions the build already selects.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 19:14:52 -07:00

92 lines
2.3 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// APDU wrapper adapted from github.com/zondax/ledger-go
// Licensed under the Apache License, Version 2.0
package ledger
import (
"encoding/binary"
"errors"
)
// WrapCommandAPDU turns the command into a sequence of 64 byte packets for HID transport
func WrapCommandAPDU(channel uint16, command []byte, packetSize int) ([][]byte, error) {
if packetSize < 3 {
return nil, errors.New("packet size must be at least 3")
}
var chunks [][]byte
header := make([]byte, 5)
binary.BigEndian.PutUint16(header[0:2], channel)
header[2] = 0x05 // TAG_APDU
binary.BigEndian.PutUint16(header[3:5], uint16(len(command)))
// First packet includes total length
firstPacket := make([]byte, packetSize)
copy(firstPacket[0:5], header)
remainingInFirst := packetSize - 5
commandOffset := 0
if len(command) <= remainingInFirst {
copy(firstPacket[5:], command)
chunks = append(chunks, firstPacket)
return chunks, nil
}
copy(firstPacket[5:], command[:remainingInFirst])
chunks = append(chunks, firstPacket)
commandOffset = remainingInFirst
// Subsequent packets
seqNum := uint16(0)
for commandOffset < len(command) {
packet := make([]byte, packetSize)
binary.BigEndian.PutUint16(packet[0:2], channel)
packet[2] = 0x05 // TAG_APDU
binary.BigEndian.PutUint16(packet[3:5], seqNum)
seqNum++
remaining := len(command) - commandOffset
copyLen := min(remaining, packetSize-5)
copy(packet[5:], command[commandOffset:commandOffset+copyLen])
commandOffset += copyLen
chunks = append(chunks, packet)
}
return chunks, nil
}
// UnwrapResponseAPDU processes a packet from HID transport and returns the payload
func UnwrapResponseAPDU(channel uint16, packet []byte, packetSize int) ([]byte, bool) {
if len(packet) < 5 {
return nil, false
}
receivedChannel := binary.BigEndian.Uint16(packet[0:2])
if receivedChannel != channel {
return nil, false
}
if packet[2] != 0x05 { // TAG_APDU
return nil, false
}
seqOrLen := binary.BigEndian.Uint16(packet[3:5])
dataStart := 5
dataEnd := min(len(packet), packetSize)
data := packet[dataStart:dataEnd]
// Trim trailing zeros (padding)
lastNonZero := len(data)
for lastNonZero > 0 && data[lastNonZero-1] == 0 {
lastNonZero--
}
needMore := seqOrLen > 0 && len(data) > 0
return data[:lastNonZero], needMore
}