|
1 | 1 | package org.vonderheidt.hips.utils |
2 | 2 |
|
3 | | -import kotlinx.coroutines.delay |
4 | 3 | import org.vonderheidt.hips.data.Settings |
5 | 4 |
|
6 | 5 | /** |
@@ -101,13 +100,51 @@ object Huffman { |
101 | 100 | * Function to decode a cover text into (the encrypted binary representation of) the secret message using Huffman decoding. |
102 | 101 | * |
103 | 102 | * Corresponds to Stegasuras method `decode_huffman` in `huffman_baseline.py`. |
| 103 | + * |
| 104 | + * @param context The context to decode the cover text with. |
| 105 | + * @param coverText The cover text containing a secret message. |
| 106 | + * @return The encrypted binary representation of the secret message. |
104 | 107 | */ |
105 | | - suspend fun decode(context: String, coverText: String, bitsPerToken: Int = Settings.bitsPerToken): ByteArray { |
106 | | - // Wait 5 seconds |
107 | | - delay(5000) |
| 108 | + fun decode(context: String, coverText: String): ByteArray { |
| 109 | + // Tokenize context and cover text |
| 110 | + val contextTokens = LlamaCpp.tokenize(context) |
| 111 | + val coverTextTokens = LlamaCpp.tokenize(coverText) |
| 112 | + |
| 113 | + // Initialize string to store cipher bits |
| 114 | + var cipherBitString = "" |
| 115 | + |
| 116 | + // Initialize variables and flags for loop (similar to encode) |
| 117 | + var i = 0 |
| 118 | + |
| 119 | + var isFirstRun = true |
| 120 | + var coverTextToken = -1 // Will always be overwritten with last cover text token |
| 121 | + |
| 122 | + // Decode every cover text token into bitsPerToken bits |
| 123 | + while (i < coverTextTokens.size) { |
| 124 | + // Calculate the logit matrix again initially from context tokens, then from last cover text token, and get last row |
| 125 | + val logits = LlamaCpp.getLogits(if (isFirstRun) contextTokens else intArrayOf(coverTextToken)).last() |
| 126 | + |
| 127 | + // Get top 2^bitsPerToken logits |
| 128 | + val topLogits = getTopLogits(logits) |
| 129 | + |
| 130 | + // Construct Huffman tree |
| 131 | + val huffmanCoding = HuffmanCoding() |
| 132 | + huffmanCoding.buildHuffmanTree(topLogits) |
| 133 | + huffmanCoding.mergeHuffmanNodes() |
| 134 | + huffmanCoding.generateHuffmanCodes() // Return value (root) is not needed here as Huffman tree is not traversed manually |
| 135 | + |
| 136 | + // Querying Huffman tree for the path to the current cover text token decodes the encoded information |
| 137 | + cipherBitString += huffmanCoding.huffmanCodes[coverTextTokens[i]] |
| 138 | + |
| 139 | + // Update loop variables and flags |
| 140 | + coverTextToken = coverTextTokens[i] |
| 141 | + isFirstRun = false |
| 142 | + |
| 143 | + i++ |
| 144 | + } |
108 | 145 |
|
109 | | - // Return placeholder |
110 | | - val cipherBits = ByteArray(size = 0) |
| 146 | + // Create ByteArray from bit string to return cipher bits |
| 147 | + val cipherBits = Format.asByteArray(cipherBitString) |
111 | 148 |
|
112 | 149 | return cipherBits |
113 | 150 | } |
|
0 commit comments