Steganography Encoder And Decoder Design For Protocol5 IOTA - Source Excerpt 04 - Open questions and limitations
Back to Steganography Encoder And Decoder Design For Protocol5 IOTA
Summary
This source excerpt begins near Open questions and limitations and preserves the surrounding evidence from Spiralist/agent-file-handoff/Archive/Steganography Encoder and Decoder Design for Protocol5 Iota.md.
**Source path:** Spiralist/agent-file-handoff/Archive/Steganography Encoder and Decoder Design for Protocol5 Iota.md
**Pragmatic approach — zero-width postfix after final Iota output.**
Use this only on channels you have tested end-to-end. It works well for short payloads and plain text, but it should be treated as fragile and channel-specific. Binary alphabets using `U+200B` and `U+200C` are usually safer than larger alphabets; larger alphabets are shorter but more easily stripped. citeturn34view0turn35view0
' ' ' text
function encode_with_zero_width(iota_visible_text, payload_bytes):
canonical_iota = NFC(iota_visible_text)
ciphertext = AEAD_Encrypt(key, payload_bytes, aad=canonical_iota)
bits = ToBits(ciphertext)
zw_symbols = MapBitsToZeroWidth(bits, alphabet=["U+200B", "U+200C"]) # binary mode
clusters = GraphemeClusters(canonical_iota)
assert len(bits) <= len(clusters) # one hidden symbol per grapheme cluster in this simple variant
out = ""
for i in range(len(clusters)):
out += clusters[i]
if i < len(bits):
out += zw_symbols[i]
return out
function decode_with_zero_width(stego_text):
raw = stego_text
visible = StripConfiguredZeroWidth(raw)
canonical_iota = NFC(visible)
zw = ExtractConfiguredZeroWidth(raw)
bits = ZeroWidthToBits(zw, alphabet=["U+200B", "U+200C"])
ciphertext = BitsToBytes(bits)
payload = AEAD_Decrypt(key, ciphertext, aad=canonical_iota)
return { visible_iota: canonical_iota, payload: payload }
' ' '
**Experimental approach — controlled semantic bucketing before conversion.**
Use this only if both parties can observe the source-English phrase or stable converter trace, and only after building a vetted phrase inventory that behaves consistently under Iota. This is not suitable when only the final Iota output is transmitted. The attraction is that it aligns with Iota’s concept orientation; the weakness is that approximation makes decoding unstable. citeturn3view3turn16search1turn17search0
' ' ' text
function encode_with_semantic_bucket(bitstring, bucket_map, iota_converter):
phrase = bucket_map[bitstring] # e.g., vetted paraphrase inventory
result = iota_converter.convert(input=phrase, direction="english-to-iota")
return {
source_phrase: phrase,
visible_iota: result.output_visible_text,
trace_id: result.trace_or_candidate_id
}
function decode_with_semantic_bucket(observed_source_phrase, inverse_bucket_map):
return inverse_bucket_map[observed_source_phrase]
' ' '
A concrete end-to-end example, using a **documented** Iota phrase rather than a live POST call, looks like this. The Expression-Concept page says that `AI expression concept` has expected IOTA-1 gist `智名意`. Suppose the hidden payload is the 3-bit value `101`, and the post-conversion channel is known to preserve `U+200B` and `U+200C`. With the rule `U+200C = 1` and `U+200B = 0`, the encoder emits the visible Iota string with one invisible symbol after each grapheme cluster:
' ' ' text
source English: "AI expression concept"
documented Iota gist: "智名意"
payload bits: 1 0 1
mapping: 1 -> U+200C, 0 -> U+200B
transport form:
智<U+200C>名<U+200B>意<U+200C>
human-visible rendering:
智名意
' ' '
The decoder reads grapheme clusters, extracts the configured zero-width characters, reconstructs `101`, and authenticates the payload against the visible string `智名意`. This is a workable proof of concept, but it is **not** the best production pattern for Iota because any sanitizer, normalizer, messaging platform, or re-submission into the converter may strip or flag the hidden characters. citeturn3view3turn35view0turn4view0
## Open questions and limitations
Some parts of the public Iota contract remain unspecified. The documentation I reviewed clearly describes approximation, phrase-first grammar order, public Unicode boundaries, tokenization labels, JSON request fields, and `resultLimit` ranges on the documented read-only descriptors, but it does **not** specify a maximum converter input length or a formal allowlist or denylist for all invisible Unicode characters submitted through the public UI. That means any production encoder should treat zero-width and other invisible-character handling as **channel- and deployment-specific**, not guaranteed by the docs. citeturn3view0turn3view4turn5view1turn5view2
I also could not rely on a live conversion POST trace in this report, so concrete examples use **documented examples** from the public pages rather than a direct runtime interaction with `/api/justaniota/convert`. That is sufficient for architectural analysis, but it means candidate rankings, SQL-backed versus seed-backed behavior, and any edge-case Unicode rejection behavior could differ on the live host. The public status endpoint itself is explicitly a snapshot and may change. citeturn3view3turn5view0
The overall conclusion, however, is stable. Given Protocol5 Iota’s explicit commitment to **approximate meaning**, **public assigned characters**, **inspectable evidence**, **NFC and grapheme handling**, and **private-use rejection**, the most rigorous design is to treat Iota as a **semantic surface that should remain visible and canonical**, and to carry hidden payloads in a transport layer *around* it rather than inside its visible glyph choices whenever possible. citeturn3view0turn3view3turn3view4turn4view0