From c699b2d9bed5957ccbfff13dc318713f378bc769 Mon Sep 17 00:00:00 2001 From: mikeplotean Date: Thu, 6 Feb 2025 18:07:24 +0200 Subject: [PATCH] fix: wallet-api encoded list decoding - consider bit order left-to-right --- .../kotlin/id/walt/webwallet/utils/Utils.kt | 42 +++++++++++++------ .../webwallet/utils/BitstringUtilsTest.kt | 2 +- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/Utils.kt b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/Utils.kt index 6bdba4b59..9a4b49ccd 100644 --- a/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/Utils.kt +++ b/waltid-services/waltid-wallet-api/src/main/kotlin/id/walt/webwallet/utils/Utils.kt @@ -5,7 +5,6 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.json.jsonObject import java.io.InputStream import java.util.Base64 -import java.util.BitSet @OptIn(ExperimentalStdlibApi::class) object StringUtils { @@ -37,30 +36,47 @@ object Base64Utils { object BitstringUtils { private val logger = KotlinLogging.logger {} + private const val BITS_PER_BYTE_UNSIGNED = 8u + fun getBitValue(inputStream: InputStream, index: ULong, bitSize: Int): List = inputStream.use { stream -> + if (stream.markSupported()) { + stream.mark(Int.MAX_VALUE) + logger.debug { "available bytes: ${bitmap(stream.readAllBytes())}" } + inputStream.reset() + } //TODO: bitSize constraints val bitStartPosition = index * bitSize.toUInt() - logger.debug { "bitStartPosition: $bitStartPosition" } - val byteStart = bitStartPosition / 8u + logger.debug { "bitStartPosition overall: $bitStartPosition" } + val byteStart = bitStartPosition / BITS_PER_BYTE_UNSIGNED logger.debug { "skipping: $byteStart bytes" } stream.skip(byteStart.toLong()) logger.debug { "available: ${stream.available()} bytes" } - val bytesToRead = (bitSize - 1) / 8 + 1 + val bytesToRead = (bitSize - 1) / BITS_PER_BYTE_UNSIGNED.toInt() + 1 logger.debug { "readingNext: $bytesToRead bytes" } extractBitValue(stream.readNBytes(bytesToRead), index, bitSize.toUInt()) } private fun extractBitValue(bytes: ByteArray, index: ULong, bitSize: UInt): List { - val bitSet = BitSet.valueOf(bytes) - logger.debug { "bits set: ${bitSet.length()}" } - val bitStart = index * bitSize % 8u - logger.debug { "startingFromBit: $bitStart" } - val result = mutableListOf() - for (i in bitStart..() + var b = 0u + while (b++ < bitSize) { + result.add(bitSet.next()) } - return result + return result.map { if (it) '1' else '0' } + } + + fun ByteArray.toBitSequence(): Sequence = this.fold(emptySequence()) { acc, byte -> + acc + (7 downTo 0).map { i -> (byte.toUInt() shr i) and 1u == 1u }.asSequence() + } + + fun bitmap(byteArray: ByteArray) = byteArray.map { byte -> + // Convert byte to binary string + String.format("%8s", Integer.toBinaryString(byte.toInt() and 0xFF)).replace(' ', '0') } } diff --git a/waltid-services/waltid-wallet-api/src/test/kotlin/id/walt/webwallet/utils/BitstringUtilsTest.kt b/waltid-services/waltid-wallet-api/src/test/kotlin/id/walt/webwallet/utils/BitstringUtilsTest.kt index 6c2511294..4858e11da 100644 --- a/waltid-services/waltid-wallet-api/src/test/kotlin/id/walt/webwallet/utils/BitstringUtilsTest.kt +++ b/waltid-services/waltid-wallet-api/src/test/kotlin/id/walt/webwallet/utils/BitstringUtilsTest.kt @@ -4,7 +4,7 @@ import id.walt.webwallet.utils.StringUtils.hexToByteArray import kotlin.test.* class BitstringUtilsTest { - private val bitString = hexToByteArray("5AA5")//0b01011010_10100101 + private val bitString = hexToByteArray("A265")//0b10100010_01100101 @Test fun `test unit bitsize, no overflow`() {