JAVANESE CIPHER PROTOCOL
JCP — A Cryptosystem Based on Aksara Jawa and Tembang Macapat
Preface
"Ana catur mungkur" — turn your back on idle talk.
A Javanese proverb on discretion. This book is about the difference between keeping a secret because no one is listening, and keeping a secret because no one can listen. Cryptography is only ever the second thing.
This book describes the Javanese Cipher Protocol (JCP), a cryptosystem that draws its structure from two artifacts of Javanese civilization: Aksara Jawa, the traditional Brahmic script of the Javanese language, and Tembang Macapat, a family of sung poetic meters defined by strict syllabic and tonal rules.
The book has an unusual obligation. Most cryptography texts describe systems that are believed secure and explain why. JCP is presented here partly as a design exercise and partly as a cautionary study. Some of its proposed mechanisms are cryptographically sound; others are examples of a seductive and recurring error — the belief that cultural inaccessibility is the same thing as cryptographic hardness. Rather than hide that tension, this book makes it the central theme.
We therefore do two things at once. First, we build the strongest honest version of JCP we can: one in which the Javanese layers serve as encodings, domain separators, and key-derivation personalization on top of standard, peer-reviewed primitives. Second, we dismantle the weak version: the romantic "the algorithm cannot be understood without the soul of Java" version, which fails the moment a competent adversary stops being charmed and starts counting symbols.
A reader who finishes this book should be able to (a) implement a usable variant of JCP, (b) explain precisely where its security actually comes from, and (c) recognize "security through cultural obscurity" wherever it appears in the wild, under whatever flag it happens to be flying.
The intended audience is practitioners and students with some exposure to classical and modern cryptography. No knowledge of Javanese is assumed; all necessary linguistic material is introduced as needed.
Foundations
Introduction to Aksara Jawa
1.1 What Aksara Jawa Is
Aksara Jawa (also called Carakan, or Hanacaraka after its first five letters) is a Brahmic abugida: a writing system in which each base consonant carries an inherent vowel — by default the open vowel /a/ (realized as [ɔ] in many contexts) — which is then modified or suppressed by diacritics. It is a cousin of the scripts of South and Southeast Asia (Devanagari, Balinese, Sundanese, Batak), all descended from the Brahmi script and ultimately structured around the phonology of the languages they serve.
The script was, until the twentieth century, the standard medium for writing Javanese, used for everything from royal chronicles (babad), wayang lakon, and serat (treatises) to letters and account books. Romanization and, later, nationalization of the Latin alphabet displaced it from daily use, but it remains culturally central, taught in schools in Central and East Java and Yogyakarta, and carried by a substantial digital revival.
For cryptographic purposes, the important facts are these:
- The script is an abugida, not an alphabet. The unit of writing is the aksara (roughly, a consonant-plus-vowel syllable), not the phoneme. This matters because it changes what "a character" means when we count symbols and compute frequencies.
- The script has a modest base inventory but a large effective inventory once diacritics and conjuncts are combined.
- The script has a canonical ordering (the hanacaraka sequence) that is culturally fixed and therefore usable as a deterministic permutation.
1.2 The Carakan: Base Consonants
The twenty base letters (aksara nglegena / aksara wanda) in their traditional order form a pangram — a perfect sentence using each letter exactly once, attributed in legend to the myth of Aji Saka:
| # | Aksara | Latin | Gloss fragment |
|---|---|---|---|
| 1 | ꦲ | ha | Hana caraka — "There were (two) messengers" |
| 2 | ꦤ | na | |
| 3 | ꦕ | ca | |
| 4 | ꦫ | ra | |
| 5 | ꦏ | ka | |
| 6 | ꦢ | da | Data sawala — "who fell into dispute" |
| 7 | ꦠ | ta | |
| 8 | ꦱ | sa | |
| 9 | ꦮ | wa | |
| 10 | ꦭ | la | |
| 11 | ꦥ | pa | Padha jayanya — "equal in their valor" |
| 12 | ꦝ | dha | |
| 13 | ꦗ | ja | |
| 14 | ꦪ | ya | |
| 15 | ꦚ | nya | |
| 16 | ꦩ | ma | Maga bathanga — "both became corpses" |
| 17 | ꦒ | ga | |
| 18 | ꦧ | ba | |
| 19 | ꦛ | tha | |
| 20 | ꦔ | nga |
The legend is itself instructive for a cryptographer: the hanacaraka is a mnemonic carrying a tragic narrative of two loyal messengers who, each obeying contradictory instructions from their master, kill each other. The story is a lesson about the ambiguity of instructions in the absence of shared context — which is, not incidentally, the exact failure mode of a poorly specified protocol. We will return to this.
1.3 Sandhangan: The Diacritics
The inherent /a/ of each base letter is altered by sandhangan (diacritics). The principal ones:
Vowel-changing (sandhangan swara):
| Name | Function | Resulting vowel |
|---|---|---|
| Wulu | superscript curl | i |
| Suku | subscript hook | u |
| Taling | prescript mark | é / è |
| Taling-tarung | bracketing marks | o |
| Pepet | superscript ring | ê (schwa) |
Final-consonant (sandhangan panyigeg wanda):
| Name | Function | Adds |
|---|---|---|
| Layar | superscript | final -r |
| Wignyan | postscript | final -h |
| Cecak | superscript dot | final -ng |
| Pangkon (paten) | virama | suppresses inherent vowel |
1.4 Pasangan: Conjunct Forms
Javanese, like other Brahmic scripts, dislikes writing a "naked" consonant with its inherent vowel suppressed in the middle of a word. Instead, when a syllable ends in a consonant that begins the next syllable's onset, the second consonant is written as a pasangan — a conjunct form, typically attached below or beside the first. Thus mangan ("to eat") and manga are written differently not by spelling out a pangkon but by the shape of the cluster.
Each of the twenty base letters has a pasangan form. From an information-theoretic standpoint, pasangan roughly double the glyph inventory (a letter in base position and the same letter in pasangan position are visually and codepoint-distinct), while carrying no additional linguistic information beyond positional context. This redundancy is a gift to a cryptanalyst and a problem for a naive cipher, as we discuss in Chapter 7.
1.5 Pada: Punctuation and Structural Marks
The script's punctuation (pada) includes pada lingsa (꧈, comma-like), pada lungsi (꧉, full stop), pada pangkat (꧇), and ornate verse markers such as pada andhap, pada luhur, and purwapada / wasanapada that open and close poetic texts. In manuscripts these marks also encode metrical boundaries — which line of a tembang has ended — and thus they carry exactly the structural information that the JCP key schedule will exploit.
1.6 Unicode Encoding
Aksara Jawa was added to Unicode in version 5.2 (2009) in the block U+A980–U+A9DF (Javanese). The block contains 91 assigned code points, including:
- Base consonants: U+A98F (ꦏ KA) through the set, with the nglegena letters scattered across U+A98x–U+A9Ax.
- Sandhangan: e.g. U+A9B6 (PANGKON / virama), U+A9BC (PEPET), etc.
- Digits: U+A9D0–U+A9D9 (Javanese digits 0–9).
- Punctuation (pada): U+A9C0–U+A9DF.
Two encoding facts dominate the cryptographic discussion:
- Variable-length UTF-8. Every code point in the Javanese block lies in the range U+A980–U+A9DF, which UTF-8 encodes in three bytes each. A JCP ciphertext rendered as UTF-8 is therefore roughly three times the byte length of an equivalent ASCII text. This is a transport property, not a security property.
- Multiple code-point sequences can render identically. This means the mapping from glyph to byte sequence is not canonical unless we impose a normalization. An unspecified normalization is a latent correctness and security bug (§9.1).
We adopt the rule: all JCP plaintext and key material is normalized to Unicode NFC and then to a canonical aksara ordering before any cryptographic operation.
1.7 Why a Script Is Not a Cipher
It must be said plainly at the outset: writing a message in Aksara Jawa is not encryption. It is transliteration — a public, reversible, well-documented re-encoding. Anyone with a Unicode table inverts it in linear time. A script is a code in the old telegraphic sense (a fixed symbol substitution), and a code with a published codebook offers zero confidentiality.
This is the first and most important honest statement in the book. Everything that follows is an attempt to find what, if anything, beyond transliteration the Javanese tradition can contribute to a real cryptosystem. The answer is: quite a lot as engineering ergonomics and key structure, and almost nothing as a substitute for a cipher.
Tembang Macapat as Mathematical Structure
2.1 What Macapat Is
Tembang macapat is a genre of traditional Javanese sung poetry. Each poem is composed in one of eleven named meters (metrum), and each meter is defined by three numerical/phonological constraints:
- Guru gatra — the number of lines (gatra) in one stanza (pada).
- Guru wilangan — the number of syllables (wanda) in each line.
- Guru lagu — the obligatory final vowel sound of each line.
A meter is thus a fixed template: a sequence of (syllable-count, final-vowel) pairs, one per line. A poet composing in that meter must hit every count exactly and end every line on the prescribed vowel. The constraints are strict; a line with the wrong syllable count or wrong final vowel is simply wrong, not merely inelegant.
2.2 The Eleven Meters
We write each meter as a sequence of N⟨vowel⟩ tokens, where N is the guru wilangan and ⟨vowel⟩ the guru lagu of that line.
| Meter | Guru gatra | Pattern (guru wilangan + guru lagu) |
|---|---|---|
| Maskumambang | 4 | 12i · 6a · 8i · 8a |
| Mijil | 6 | 10i · 6o · 10e · 10i · 6i · 6u |
| Sinom | 9 | 8a · 8i · 8a · 8i · 7i · 8u · 7a · 8i · 12a |
| Kinanthi | 6 | 8u · 8i · 8a · 8i · 8a · 8i |
| Asmarandana | 7 | 8i · 8a · 8e · 8a · 7a · 8u · 8a |
| Gambuh | 5 | 7u · 10u · 12i · 8u · 8o |
| Dhandhanggula | 10 | 10i · 10a · 8e · 7u · 9i · 7a · 6u · 8a · 12i · 7a |
| Durma | 7 | 12a · 7i · 6a · 7a · 8i · 5a · 7i |
| Pangkur | 7 | 8a · 11i · 8u · 7a · 12u · 8a · 8i |
| Megatruh | 5 | 12u · 8i · 8u · 8i · 8o |
| Pucung | 4 | 12u · 6a · 8i · 12a |
2.3 The Meters as Integer Sequences
Strip the vowels and a meter is an integer sequence — its syllable signature:
Maskumambang : (12, 6, 8, 8) Mijil : (10, 6, 10, 10, 6, 6) Sinom : (8, 8, 8, 8, 7, 8, 7, 8, 12) Kinanthi : (8, 8, 8, 8, 8, 8) Asmarandana : (8, 8, 8, 8, 7, 8, 8) Gambuh : (7, 10, 12, 8, 8) Dhandhanggula: (10, 10, 8, 7, 9, 7, 6, 8, 12, 7) Durma : (12, 7, 6, 7, 8, 5, 7) Pangkur : (8, 11, 8, 7, 12, 8, 8) Megatruh : (12, 8, 8, 8, 8) Pucung : (12, 6, 8, 12)
2.4 Combinatorial Properties
It is tempting — and many enthusiast write-ups do exactly this — to claim a huge key space by multiplying combinatorial possibilities of the script and meters. We will do the multiplication honestly, and then explain why most of the product is illusory.
(a) Meter selection. Choosing one of the eleven meters contributes log₂ 11 ≈ 3.459 bits. That is, less than a single ASCII character. Meter choice alone is cryptographically negligible.
(b) Symbol-space size of the script. Suppose we bound a written aksara cluster as: one of 20 base consonants, optionally one of ~7 vowel sandhangan (or the inherent vowel), optionally one of ~3 final-consonant sandhangan, optionally one medial. A crude upper bound on legal clusters is:
20 × (7+1) × (3+1) × (2+1) ≈ 20 × 8 × 4 × 3 = 1920
distinct clusters, of which a smaller subset (perhaps 400–700) actually occur with non-negligible frequency in real Javanese text. So the effective alphabet of written Javanese is on the order of a few hundred symbols — larger than Latin (~26–52), but this enlargement by itself buys only:
log₂ 700 ≈ 9.45 bits per symbol
of maximum per-symbol entropy, and natural-language redundancy collapses the realized entropy to roughly 1–1.5 bits per symbol (Shannon's estimate for English is ~1.0–1.3 bits/letter; Javanese is not magically different).
2.5 A Worked Entropy Discount
Let a key be a freshly composed Kinanthi stanza: 6 lines, guru wilangan all 8, so 48 syllables. Pattern 8u · 8i · 8a · 8i · 8a · 8i.
- Upper bound if syllables were uniform over 700 clusters: 48 × 9.45 ≈ 454 bits.
- Discount for natural-language redundancy (generous 2 bits/syllable): 48 × 2 = 96 bits.
- Discount for guru lagu: six fixed finals remove 6 × log₂5 ≈ 14 bits. Net: ≈ 82 bits.
- Discount for memorability: if the composer is reusing stock phrases, realistic entropy may fall to 40–60 bits.
Conclusion: a hand-composed macapat stanza, treated as a passphrase, plausibly carries 40–96 bits of entropy — comparable to a decent (not excellent) human passphrase, and well short of a 128-bit key. This is not a reason to abandon macapat; it is a reason to stretch it with a memory-hard KDF (§4.2) rather than to use it raw.
Javanese Philosophy of Language
3.1 Why a Cryptography Book Has a Philosophy Chapter
JCP's proponents make a strong claim: that cultural context — the web of meaning, allusion, and interpretation surrounding a Javanese text — constitutes cryptographic key material that machines cannot access. To evaluate that claim rather than merely assert or dismiss it, we must first describe the philosophy of language it rests on, accurately and sympathetically. We do that here. We then test it, unsympathetically, in Part IV. Sympathy first, then arithmetic.
3.2 Rasa: Meaning Below the Words
Central to Javanese aesthetics and kebatinan (inward, mystical practice) is rasa — a term spanning "feeling," "taste," "intuition," and "inner meaning." A text is held to have an outer sense (the literal words) and an inner sense (its rasa), and to read truly is to apprehend the latter. Macapat, sung rather than merely read, is a rasa-bearing form: the meter's emotional convention (Asmarandana = longing) frames how its words are felt.
For a cryptographer, the relevant question is operational: is rasa a function the sender and receiver compute identically, that an attacker cannot? If yes, it is a shared secret and could in principle key a cipher. If no — if rasa is interpretive, varying between competent readers — then it cannot be a key, because a key must be exactly reproducible by the legitimate parties and by no one else. We flag the question now and answer it in §11.2.
3.3 Konteks: The Contextual Determination of Meaning
Javanese discourse is famously context-sensitive. The language has elaborate speech levels (ngoko, madya, krama, krama inggil) selecting word forms by social relation. Much is communicated by sasmita (hint, allusion) and pasemon (veiled reference) rather than statement.
We treat this seriously in Chapter 10 — and show that it reduces, formally, to a low-entropy shared secret: useful as one factor, fatal as the whole scheme.
3.4 Semiotics: Syntactic vs Semantic Layers
We can frame the whole tension semiotically. Any sign system has:
- a syntactic layer — the formal manipulation of symbols by rules (this is what algorithms, including ciphers and the script itself, operate on);
- a semantic layer — the mapping of symbols to meanings;
- a pragmatic layer — meaning-in-use, dependent on speaker, context, intent.
JCP's bold proposal is to recruit the pragmatic layer — context, intent, cultural competence — as a security resource.
The thesis of this book, argued in full in Part IV:
The pragmatic layer can supply usability (mnemonic keys, plausible deniability, social key-distribution) and a modest, enumerable amount of entropy. It cannot supply confidentiality guarantees, because security guarantees are syntactic claims — statements about what an adversary cannot compute — and pragmatic meaning, by its nature, is neither uniformly distributed, secret from a determined ethnographer, nor exactly reproducible. Build on the syntactic rock; decorate with the pragmatic; never live in the decoration.
The JCP Protocol
Core Algorithm Specification
4.0 Two Constructions, Stated Honestly
We specify JCP in two layers, and we are explicit about which is which:
- JCP-Classical — a pedagogical construction that uses only the Javanese structures (script substitution + meter-driven polyalphabetic shifting). It is transparent, charming, and insecure: roughly the strength of a Vigenère cipher.
- JCP-Hardened — the construction we actually recommend if anyone wants to use JCP for real confidentiality. It keeps the Javanese layers as encoding and KDF personalization and delegates all confidentiality to a standard authenticated stream cipher (ChaCha20-Poly1305) keyed by a memory-hard KDF (Argon2id).
A reader who only remembers one sentence should remember this: JCP-Hardened is secure because of Argon2id and ChaCha20, not because of Java. JCP-Classical is insecure, and no amount of cultural depth fixes that.
4.1 Character Mapping: Latin → Aksara → Unicode
The encoding pipeline is a public, bijective transliteration. It is not part of the secret; per Kerckhoffs it is fully published.
- Romanization normalization. Input text is reduced to a canonical Javanese romanization (the Sriwedari/EYD-style scheme): lower-cased, with digraphs
dh, th, ny, ngrecognized as single phonemes. - Syllabification. The romanized stream is segmented into wanda (orthographic syllables).
- Aksara assembly. Each syllable maps to an aksara cluster: base consonant + sandhangan.
- Unicode emission and normalization. The cluster is emitted as a code point sequence in canonical order, then NFC-normalized.
The translocation is defined formally:
TRANSLIT : LatinText → AksaraCodepoints (public, total, invertible) TRANSLIT⁻¹: AksaraCodepoints → LatinText ∀ m : TRANSLIT⁻¹(TRANSLIT(m)) = normalize(m)
4.2 Tembang-Based Key Derivation Function (KDF)
The KDF turns a human-chosen macapat verse (plus optional context factors) into a uniform 256-bit key.
Inputs:
V— the secret verse: a macapat stanza chosen/composed by the userM— the meter name (one of 11), used as a domain labelσ— the verse's syllable signature and vowel signatureC— optional context stringS— a random 128-bit salt
Procedure (JCP-Hardened KDF):
function JCP_KDF(V, M, σ, C, S):
assert scans(V, σ) # meter check
pers = "JCP/v1|" + M + "|" + encode(σ) # personalization
pre = HKDF_Extract(salt = S,
ikm = NFC(V) || 0x00 || NFC(C))
seed = HKDF_Expand(pre, info = pers, L = 32)
key = Argon2id(password = seed,
salt = S || pers,
m = 256 MiB, t = 4, p = 2,
outlen = 32)
return key # 256-bit symmetric key
4.3 Encryption Round Structure
JCP-Classical (insecure, pedagogical). Let the secret verse have syllable signature g = (g₁, g₂, …, g_L). Index the aksara alphabet 0 … A-1 in the canonical hanacaraka order. To encrypt aksara stream p₀ p₁ p₂ …:
for i in 0,1,2,…:
shift_i = g[i mod L] # repeating metrical key
c_i = (p_i + shift_i) mod A # additive shift in the aksara ring
This is a polyalphabetic substitution cipher — a Vigenère cipher whose key is the integer sequence g.
JCP-Hardened (recommended).
function JCP_Encrypt(plaintext, key, M, σ):
A = NFC(TRANSLIT(plaintext))
N = random 96-bit nonce
AD = "JCP/v1|" + M + "|" + encode(σ)
ct, tag = ChaCha20Poly1305_Encrypt(
key = key, nonce = N,
plaintext = A, aad = AD)
return Frame{ version=1, M, S, N, ct, tag }
4.4 Decryption Process
function JCP_Decrypt(frame, V, C):
σ = signature_of(frame.M)
key = JCP_KDF(V, frame.M, σ, C, frame.S)
A = ChaCha20Poly1305_Decrypt(
key = key, nonce = frame.N,
ciphertext = frame.ct, tag = frame.tag,
aad = "JCP/v1|" + frame.M + "|" + encode(σ))
if A == ⊥: abort("authentication failed")
return TRANSLIT⁻¹(A)
4.5 Padding and Mode of Operation
JCP-Hardened operates as a stream AEAD (ChaCha20-Poly1305), needing no block padding. The unit of encryption is one frame per message. JCP therefore mandates one of: (a) random 96-bit nonces with a strict message-count limit, (b) an XChaCha20 variant with 192-bit nonces, or (c) a deterministic counter. We recommend XChaCha20-Poly1305 for JCP.
Key Generation and Management
5.1 Tembang Selection as Key Seed
The user-facing secret in JCP is a macapat verse, chosen in one of three ways, in decreasing order of security:
- Composed-fresh (recommended). The user composes an original stanza that scans correctly in a chosen meter.
- Composed-from-diceware. The user maps random words from a large Javanese wordlist into a scanning stanza.
- Canonical verse (discouraged). Using a known verse from a published serat. Entropy ≈ 15–17 bits.
5.2 Key Space Analysis
| Key method | Raw entropy H | After Argon2id |
|---|---|---|
| Canonical verse | 15–17 bits | broken in minutes |
| Hand-composed stanza | 40–96 bits | weak-to-moderate |
| Diceware-into-meter, 6 words | ~77 bits | strong vs. casual attackers |
| Diceware-into-meter, 10 words | ~129 bits | effectively unbrute-forceable |
The single most important equation in this book:
Security ≈ H_verse + log₂(KDF cost per guess) − log₂(attacker parallelism)
Notice that nothing in this equation is Javanese.
5.3 Cultural Context as Additional Key Material
We fold context C into the salt/IKM as defense in depth worth perhaps 10–25 bits against a non-targeted attacker. The design rule: the security argument must survive the full disclosure of C.
Implementation Examples
6.1 Full Walkthrough with Sample Plaintext
Plaintext (Latin): aja dumeh — "do not be arrogant."
Secret verse V (Kinanthi, 6×8, composed-from-diceware):
Line 1 (8u): wêlut sêga gunung samun Line 2 (8i): lawang wêngi tanpa tulis Line 3 (8a): grimis tiba ing pawana Line 4 (8i): sêpi sonya datan kèksi Line 5 (8a): watu item ngumpul ana Line 6 (8i): nglari dalan kang sêjati
Step A — meter check. scans(V, σ_Kinanthi) passes: counts all 8, finals match u i a i a i.
Step B — KDF. With random salt S, compute Argon2id → 256-bit key.
Step C — transliterate plaintext. aja dumeh → syllables a · ja · du · meh → aksara ꦲꦗꦢꦸꦩꦺꦃ (ha-ja, da+suku, ma+taling+wignyan).
Step D — AEAD. Random nonce N (192-bit, XChaCha20). Encrypt the aksara bytes.
Step E — frame. Emit Frame{v=1, M=Kinanthi, S, N, ct, tag}.
6.2 Code Examples
def transliterate(latin: str) -> bytes: rom = canonical_romanize(latin) wandas = syllabify(rom) cps = [] for w in wandas: base, medial, vowel, final = parse_syllable(w) cps += assemble_aksara(base, medial, vowel, final) return nfc(encode_codepoints(cps)) def jcp_kdf(verse: str, meter: str, context: str, salt: bytes) -> bytes: sig = signature_of(meter) assert scans(verse, sig) pers = b"JCP/v1|" + meter.encode() + b"|" + encode_sig(sig) ikm = nfc(verse.encode()) + b"\x00" + nfc(context.encode()) seed = hkdf(salt=salt, ikm=ikm, info=pers, length=32) return argon2id(password=seed, salt=salt + pers, mem=256*1024, iters=4, lanes=2, hashlen=32) def jcp_encrypt(plaintext, verse, meter, context): salt = random_bytes(16) key = jcp_kdf(verse, meter, context, salt) nonce = random_bytes(24) aad = b"JCP/v1|" + meter.encode() + b"|" + encode_sig(signature_of(meter)) ct, tag = xchacha20poly1305_encrypt(key, nonce, transliterate(plaintext), aad) return frame(version=1, meter=meter, salt=salt, nonce=nonce, ct=ct, tag=tag) def jcp_decrypt(fr, verse, context): key = jcp_kdf(verse, fr.meter, context, fr.salt) aad = b"JCP/v1|" + fr.meter.encode() + b"|" + encode_sig(signature_of(fr.meter)) pt = xchacha20poly1305_decrypt(key, fr.nonce, fr.ct, fr.tag, aad) if pt is AUTH_FAIL: raise ValueError("authentication failed") return untransliterate(pt)
And, for contrast, the entire JCP-Classical cipher:
def jcp_classical_encrypt(aksara_indices, guru_wilangan): A = ALPHABET_SIZE g = guru_wilangan return [(p + g[i % len(g)]) % A for i, p in enumerate(aksara_indices)]
6.3 Test Vectors
Vector C-1 (JCP-Classical, hand-verifiable). Use a 5-symbol toy alphabet for clarity: index ha=0, na=1, ca=2, ra=3, ka=4. Meter = Pucung-toy with g = (12, 6, 8, 12) mod 5 = (2, 1, 3, 2).
plaintext indices : ha na ca ra ka ha na ca ra ka = 0 1 2 3 4 0 1 2 3 4 shift g[i mod 4] : 2 1 3 2 2 1 3 2 2 1 cipher (p+g) mod 5 : 2 2 0 0 1 1 4 4 0 0 cipher symbols : ca ca ha ha na na ka ka ha ha
Vector H-1 (JCP-Hardened, parameter-complete):
meter : Kinanthi signature : counts (8,8,8,8,8,8), vowels (u,i,a,i,a,i) verse V : (the six Kinanthi lines above, exact UTF-8, NFC) context C : "" salt S : 0x00112233445566778899AABBCCDDEEFF KDF : HKDF-SHA256 → Argon2id(m=262144 KiB, t=4, p=2, outlen=32) nonce N : 0x000102030405060708090A0B0C0D0E0F1011121314151617 plaintext : "aja dumeh" aksara(pt) : ꦲꦗꦢꦸꦩꦺꦃ (NFC, canonical order) AAD : "JCP/v1|Kinanthi|8u8i8a8i8a8i"