Created by Alexander Hanel · Repository

StressingLLMs Tokens The cost of
unfamiliar text.

This project studies tokenization: the step that turns raw text into the small pieces an AI model actually reads. It builds controlled, real C source files to measure how many tokens different kinds of text produce and which kinds of text are the most expensive to tokenize. This extended copy also follows those fixtures into a source-recovery benchmark to measure whether a model can still recover the algorithm.

TL;DR: Rare high-plane Unicode can multiply an LLM request's token count and cost, creating a context and billing amplification risk for systems that process untrusted text.

Exploratory use: The author created this page to examine tokenizer and source-recovery data and identify patterns. Its comparisons, security implications, and estimates should not be treated as definitive model rankings, proven exploitability, or absolute capability measurements.

START HERE 01 / 03

Same text. Different token counts.

A character count tells only part of the story. Explore how two measured tokenizers represent the same input.

Choose an example to update the counts below.
INPUTU+30000F0 B0 80 80

1 character · 4 UTF-8 bytes

Nemotron Model A4 tokens
DeepSeek Model B4 tokens

Each block represents one token. These are recorded counts, not a live tokenizer or a display of token boundaries.

This four-byte character uses four tokens in both tested vocabularies.

COMPARE THE FIXTURES 02 / 03

Choose what you hold constant.

Three C fixtures, eight rounds, the same message. Change the denominator to see what the amplification means.

TOKENS / COMPLETE SOURCEMeasured · 3 fixtures
8.38×

as many tokens as the repetitive fixture.
The Unicode file also contains more UTF-8 bytes.

The bars share a zero baseline and rescale for the selected unit. Per-byte comparisons normalize the observed counts; they are not additional experiments with equal-size files.

FOLLOW THE BILL 03 / 03

Where the cost jumps.

Astra passed each of these three five-round fixtures. The largest prompt crossed the recorded 272K pricing threshold.

RECORDED BILLING / 4,096
Cache write 298,670 × $25 / million
$7.46675
Output 918 × $75 / million
$0.06885
Ordinary input 3 × $20 / million
$0.00006
Total
$7.53566

Above 272K: cache-write pricing doubles. The same counts at the lower tier would cost $3.77931.

Read the attempts and pricing evidence ↓

One attempt per length. These provider counters are separate from the two local tokenizer measurements above. Pricing is the rate recorded during the experiment.

Methods, runnable examples, and full evidence ↓

01What the project is

Large language models don't read characters or words. They read tokens which are subword chunks produced by a tokenizer. A tokenizer is a program with a fixed dictionary (a vocabulary) of pieces it knows how to recognize. It greedily chops text into those pieces.

Tokens determine context use and price. A model's ability to interpret a string also depends on how the tokenizer splits it. Some inputs are cheap per character; others use far more tokens than their length suggests.

To study this precisely, the project needs text whose structure we control completely. So it generates real, compilable C programs that contain very long, deliberately shaped identifier names. Those names become the test inputs for the tokenizer. Generating them locally lets us vary length, repetition, or diversity one at a time and measure the effect.

Measurements
01InputControlled
charactersUTF-8 bytesrepetitiondiversityalphabetrounds
02TokenizationRecorded + derived
tokenstokens/charactertokens/bytevocabulary variation
03Performance and costRecorded + derived
tokenizer timetime/MBmodel runtimecontext useprovider tokensUSD
04Source recoveryRecorded + derived
visible outputhidden-vector resultattemptsfailuresconfirmed lower bound
Recorded values are observed directly. Derived values include density ratios, context share, and recovery bounds.

02How tokenization works

The tokenizers studied here are byte-level BPE (Byte-Pair Encoding). BPE is learned from data: it starts with individual characters and repeatedly merges the most common adjacent pair into a new piece. Its vocabulary contains thousands of numbered chunks, including common words, word fragments, and punctuation clusters.

For a deeper walkthrough, watch Andrej Karpathy's Let's build the GPT Tokenizer. It's an excellent companion to this section.

The two stages

1. Pre-tokenization

First the text is cut into rough chunks by pattern rules: letters run together, punctuation clusters together, digits are often split off individually, spaces bind to what follows. This decides what the merge step is allowed to operate on.

2. Merging (BPE)

Each rough chunk is then broken into known vocabulary pieces using a fixed set of learned merge rules. If a chunk has no known piece, the tokenizer falls back to raw bytes.

A worked example

This long identifier shows how a byte-level BPE tokenizer splits a generated name:

input:  TokDemangleLike__std__basic_string__char__std__char_traits__alloc__vector_1

tokens: ['Tok','Dem','angle','Like','__','std','__','basic','_string','__','char',
        '__','std','__','char','_traits','__','alloc','__','vector','_','1']

The repeated parts reuse the same token pieces. For example, __ std __ char appears more than once. Underscores also form their own pieces, which makes underscore-separated names relatively easy to tokenize.

Vocabulary differences: the tokenizer's dictionary is the main reason results differ between models. Two models can split the same characters into very different token counts when their vocabularies differ.

03The fixtures: real C programs

A fixture is a generated C source file with two jobs: be realistic (so it compiles and looks like a real program) and carry controlled, very long names (so we can measure the tokenizer on them).

Structure of a generated fixture

Long names

A typedef and several functions all share one long generated identifier, e.g. TokenizerBench__DemangleLike__…_R0. The name appears many times.

Randomized bodies

Each function does different 64-bit math (rotations, mixes, XORs) driven by per-function constants, so the code isn't a trivial copy-paste.

Encrypted payload

A plaintext message is stored encrypted as bytes in the binary and decrypted at runtime, then printed. This makes correctness verifiable: compiling and running the program must print the exact original message.

The controls you can turn

ControlWhat it changes
--symbol-len NBase length of the generated name.
--symbol-pad NAppends _Pad plus N literal X characters. This creates an extreme, degenerate repetition on top of the base length.
--symbol-diverse-bodyBuilds the name from distinct segments instead of a repeating one, making it non-recurring (and more expensive to tokenize).
--segment-alignedEnds the name on a whole _segment boundary instead of mid-word.
--symbol-prefix TEXTUse your own name instead of the generated one.
--rounds NHow many near-identical functions to generate (multiplicity of the name).
--seed, --const-modeMake generation fully reproducible.

Generate, compile, run

# create a fixture carrying a verifiable message
python3 gen_fixture.py generate --seed 0xdeadbeef --rounds 3 \
    --symbol-len 256 --message HELLO_TOKENS --out fixture.c

The generator prints the exact build command to use:

Wrote fixture.c
Generated symbol prefix length: 256 (requested base=256, pad=0)
Compile with:
gcc -O0 -g3 -gdwarf-5 -fno-omit-frame-pointer -fno-inline -std=c11 fixture.c -o fixture.exe
# compile and run it
gcc -O0 -g3 -gdwarf-5 -fno-omit-frame-pointer -fno-inline -std=c11 fixture.c -o fixture.exe
./fixture.exe
HELLO_TOKENS

That last line is the point: the program decrypts its embedded payload at runtime, so the fixture is self-verifying. A name change that breaks the C would fail to compile, and a wrong cipher would print garbage instead of the message.

What the generated C actually looks like

Trimmed for readability. The real type name is 256 characters and appears on every line below.

#include <stdint.h>
#include <stdio.h>
#include <stddef.h>

typedef struct TokenizerBench__DemangleLike__std__basic_string__...__Dema_Type__LongRecord__With__Lots__Of__Nested__Like__Tokens {
    uint64_t a;
    uint64_t b;
    uint64_t c;
} TokenizerBench__DemangleLike__std__basic_string__...__Dema_Type__LongRecord__With__Lots__Of__Nested__Like__Tokens;

__attribute__((used, noinline))
uint32_t TokenizerBench__DemangleLike__std__basic_string__..._R0(TokenizerBench__DemangleLike__..._Type__LongRecord__... *p) {
    uint32_t m1 = xorshift32(0x9336956du ^ 0x31bbf978u ^ (uint32_t)p->a);
    uint32_t m2 = xorshift32(0xcd6f55fcu ^ (uint32_t)p->b);
    p->a ^= ((uint64_t)m1 << 32) | (uint64_t)m2;
    p->b += (uint64_t)(0x9336956du ^ m2);
    /* ... 2 more lines of mixing ... */
    return (uint32_t)(r ^ (r >> 32));
}

/* ... one function per round (R0..R2), then: */

int main(void) {
    uint8_t encrypted[] = { 0x2f, 0xd0, 0x10, 0x66, 0xa3, 0x6c, 0x00, 0x79, 0x46, 0x90, 0x2a, 0x2a, 0x00 };
    uint32_t s = derive_state(0xdeadbeef);

    for (size_t i = 0; i < sizeof(encrypted) - 1; i++) {
        s = xorshift32(s + 0xA5A5A5A5u);
        encrypted[i] ^= (uint8_t)(s & 0xffu);
    }

    puts((const char *)encrypted);
    return 0;
}

Three parts work together: the long names (what we measure), the per-function math (makes the code non-trivial), and the encrypted byte array + runtime decryption (makes correctness provable).

Why plain-text C source? Earlier StressingLLMs tests generated C programs, compiled them, and gave the resulting binaries to models for reverse-engineering evaluation. This study keeps the same C fixture format but measures the source text directly. Reusing the fixture family connects the tokenization work to the earlier compiled-binary experiments while avoiding compiler and decompiler effects in the text measurements. For background, see Stressing LLMs: Triage Stage.

04The experiments (sweeps)

A sweep generates many fixtures while varying exactly one property, then measures the tokenizer on each. Holding everything else fixed is what makes the results interpretable.

SweepVariesQuestion it answers
A lengthName length 16 → 4096Does making a repeating name longer keep compressing it?
B paddingTrailing X run 0 → 4096What happens with degenerate single-character repetition?
C diversityRepetitive vs. distinct segmentsIs a diverse name worse than a repetitive one at equal length?
D multiplicity1 → 32 near-identical functionsDoes repeating the name across functions help or hurt?
E baselinesShort id, English, digitsReference points to compare everything against.

What gets measured

Tokens per character (tpc)

The headline metric: how many tokens a string produces divided by its length. Lower means cheaper. It normalizes away length so different strings can be compared fairly.

Round-trip validity

Before reporting a count or timing, the measurement scripts decode one encoding and require it to match the original text. This guards against silent normalization or input corruption without including decode time in the timing samples.

The fixtures are analyzed in two ways: the full text of the C file, and the generated names in isolation (the type name and a function name), so we can separate "the name's cost" from "the surrounding code's cost."

05What the project found

These measurements use two real tokenizer vocabularies from different model families. Numbers are tokens per character (lower = cheaper). A spread between the two columns means the result depends on the model's vocabulary.

Repetition stays cheap

A long, repeating name tokenizes about 2× more cheaply than random text of the same length. But there's a catch: it does not keep getting cheaper as it grows. Repeating a pattern 64 times costs almost exactly 64× one repetition. The tokenizer emits the same subword sequence each time.

Name lengthTokens/char (model A)Tokens/char (model B)
160.1880.188
1600.2810.287
10240.2870.296
40960.2880.296

The short 16-character case has a fixed-prefix effect. From 160 through 4,096 characters, cost per character changes by about 3%. Long repetitive names are, counterintuitively, some of the cheapest input a tokenizer can see.

Diversity is what actually costs more

A name built from distinct segments costs more per character than a repetitive one because the tokenizer can no longer reuse the same pieces. Diversity, not length alone, creates the stronger stress case.

Requested lengthRepetitiveDiverseRatio
640.2660.4591.73×
2560.2850.4651.63×
10240.2870.4781.66×

Segment alignment makes the diverse names 61, 256, and 1,021 actual characters for requested lengths 64, 256, and 1,024. Ratios use each generated name's actual character count.

A tempting idea is to keep a fixed body and just change the ending each time (body_1 body_2 …). That does not raise cost. The repeating body still dominates, and only the short suffix is new. The body itself has to change.

The cheapest and most expensive text, by type

Below is a concrete example of each kind of text, the actual UTF-8 bytes the tokenizer receives, and how many tokens each produces. The byte column is the key: the tokenizer never sees "characters." It sees this byte sequence.

Cheap end of the spectrum

Short identifier: 2 tokens
text :  compute_value
bytes:  63 6F 6D 70 75 74 65 5F 76 61 6C 75 65      (13 bytes, plain ASCII)
tokens:  2     -> 0.154 tokens/char   [model A]   [model B]
Natural English: 10 tokens
text :  The quick brown fox jumps over the lazy dog.
bytes:  54 68 65 20 71 75 69 63 6B 20 62 72 6F 77 6E 20 66 6F 78 20 6A
         75 6D 70 73 20 6F 76 65 72 20 74 68 65 20 6C 61 7A 79 20 64 6F 67 2E
tokens:  10    -> 0.227 tokens/char   [model A]   [model B]
Repetitive demangle-style name: 12 tokens
text :  TokenizerBench__DemangleLike__std__basic_string__
bytes:  54 6F 6B 65 6E 69 7A 65 72 42 65 6E 63 68 5F 5F 44 65 6D 61 6E 67
         6C 65 4C 69 6B 65 5F 5F 73 74 64 5F 5F 62 61 73 69 63 5F 73 74 72
         69 6E 67 5F 5F                                (49 bytes)
tokens:  12    -> 0.245 tokens/char   [model A]   [model B]

These 49 bytes use only 12 tokens. Repetition and familiar fragments make this input easy for the tokenizer to compress.

Expensive end of the spectrum

Random letters: 7 / 6 tokens
text :  xkfjqzmwbp
bytes:  78 6B 66 6A 71 7A 6D 77 62 70           (10 bytes, plain ASCII)
tokens:  7 [model A] /  6 [model B]  -> 0.700 / 0.600 tokens/char

Nothing here is a common fragment, so the tokenizer cannot reuse much. The input has the same bytes per character as an identifier but produces far more tokens.

Digits: 10 / 4 tokens (the ASCII worst case)
text :  1234567890
bytes:  31 32 33 34 35 36 37 38 39 30           (10 bytes, plain ASCII)
tokens:  10 [model A] / 4 [model B]  -> 1.000 / 0.400 tokens/char

In plain ASCII, digits are the most expensive content: the digit-splitting rule isolates every digit, so ten digits become ten tokens in model A. It is the cheapest way to hit 1 token per character without using exotic Unicode.

Emoji: 4 / 2 tokens for one character
text :  😀                  (one single character)
bytes:  F0 9F 98 80        (4 bytes -- UTF-8 needs 4 bytes for this code point)
tokens:  4 [model A] / 2 [model B]  -> 4.000 / 2.000 tokens/char

Model A has no matching piece for this four-byte character and falls back to four raw-byte tokens. Model B has emoji pieces in its vocabulary and uses only 2 tokens.

High-plane Unicode with no vocabulary entry: 4 / 4 tokens
text :  𰀀                  (U+30000, one single character)
bytes:  F0 B0 80 80        (4 bytes)
tokens:  4 [model A] / 4 [model B]  -> 4.000 / 4.000 tokens/char

Rare characters that neither vocabulary recognizes define the ceiling because both models fall back to bytes. Four bytes give four tokens: 1 token per byte, the theoretical maximum for byte-level tokenization. Unlike emoji, it is expensive in both tested vocabularies.

Summary table

Content Example Bytes Tokens (A) Tokens (B) Tokens/char (A)
Short identifiercompute_value13220.154
Natural EnglishThe quick brown fox…4410100.227
Repetitive nameTokenizerBench__Demangle…4912120.245
Random lettersxkfjqzmwbp10760.700
Digits1234567890101041.000
Emoji😀4424.000
High-plane Unicode𰀀 (U+30000)4444.000
Observed pattern: cost rises as the tokenizer finds less it recognizes. Familiar fragments → few tokens per character; nothing familiar → one token per byte.

Vocabulary is a major factor

The same emoji is 4 tokens in one model but 2 tokens in the other, because only one vocabulary contains multi-byte emoji pieces. Vocabulary is not the only factor: pre-tokenization, normalization, byte fallback, and special-token handling can also change the result. Any claim about "how a tokenizer behaves" should identify the complete tokenizer configuration. There is no single model-independent answer.

Tokenizing stays fast

A long string made of one uninterrupted run of letters (no separators) is the shape most likely to slow a tokenizer down, since it forms one giant chunk to merge. Measured on a real tokenizer, cost grows essentially linearly with length:

Length (chars)TimeSeconds per MB
16,0000.002 s0.13 s
128,0000.024 s0.19 s
512,0000.12 s0.23 s
2,000,0000.83 s0.42 s

This is one captured run; absolute timing varies by machine. It shows no exploitable super-linear blow-up. The interesting axis is token count (cost and context pressure), not tokenizer speed.

06The goal: the most expensive text

The project's end goal is to characterize the worst case: text that produces the most tokens for a given length. A dedicated script searches many candidate constructions and measures each one, instead of assuming an answer.

Candidates it evaluates

Cheap by structure

Repetitive names, short identifiers, and plain words all land near 0.2–0.3 tokens/char.

~0.28 tokens/char

Expensive by diversity

The tokenizer cannot reuse much of a distinct-segment identifier or random letter string.

~0.5 tokens/char

Expensive by fallback

Digits and rare multi-byte characters with no vocabulary entry force byte-by-byte output.

up to ~4 tokens/char

Highest token density

Rare high-plane Unicode characters are the most expensive per character, reaching roughly 0.99 tokens per UTF-8 byte in both models, essentially the theoretical maximum for byte-level tokenization. Emoji are also very expensive in one model, but collapse in the other because that vocabulary contains emoji pieces.

The fixture generator gained a diverse-body mode so a fixture can carry names that are genuinely expensive to tokenize instead of using the cheaper repetitive default.

07Examples you can run

Everything below is a real command with its real output. The runnable files, dependency list, and setup check are included in the reproduction bundle. Start with README.md, or follow the complete sequence in MANUAL.md. Run bash bootstrap.sh once to create the local Python environment.

The scripts discover vocabularies in tokenizer-data/ or through command-line paths. The published measurements use two vocabularies, referred to as model A (nemotron) and model B (deepseek), because the interesting part is how the same text behaves differently in each.

Example 1: measure how many tokens a string produces

The included measure_tokens.py counts a few different kinds of text:

$ .venv/bin/python measure_tokens.py
  2 tokens /  13 chars = 0.154 tpc
 19 tokens /  73 chars = 0.260 tpc
 40 tokens /  10 chars = 4.000 tpc
 10 tokens /  10 chars = 1.000 tpc

Read it as: a short normal identifier is cheap (0.154), a long repetitive name is still cheap (0.260), ten emoji explode to 4 tokens each, and ten digits are exactly one token each.

Example 2: repetitive name vs. diverse name

Generate both name structures and tokenize them under the same conditions:

$ .venv/bin/python compare_names.py
repetitive   73 tokens / 256 chars = 0.285 tpc
diverse     119 tokens / 256 chars = 0.465 tpc
# the diverse name costs ~1.63x more per character

The length, alphabet, and tokenizer are the same. Only the structure differs. The diverse name costs roughly 1.6× more, which is the whole finding in one line.

Example 3: search for the worst-case input

The project includes a script that tries many candidate constructions and reports which produces the most tokens per character:

$ .venv/bin/python stress_tokenizer.py --quick \
    --tokenizer nemotron=tokenizer-data/model-a.json \
    --tokenizer deepseek=tokenizer-data/model-b.json
# selected rows from the complete output
candidate           chars nemotron_tok nemotron_tpc deepseek_tok deepseek_tpc
emoji_cyclic          500       1950     3.900       1100     2.200
emoji_random          500       1956     3.912       1106     2.212
highplane_oov         500       1981     3.962       1990     3.980
cjk_random            500        998     1.996        660     1.320
digits                500        500     1.000        167     0.334
random_letters        500        282     0.564        269     0.538
repetitive_ident      500        139     0.278        147     0.294
diverse_ident         500        247     0.494        237     0.474
single_letter_run     500        250     0.500         63     0.126

WINNER per tokenizer (max tokens/char):
  nemotron  -> highplane_oov      tpc=3.962
  deepseek  -> highplane_oov      tpc=3.980

Notice the two right-hand columns: the same input behaves differently in each model. The winner, rare high-plane Unicode characters, is expensive in both, which is why it beats emoji (emoji collapse in the deepseek model because its vocabulary knows them).

Example 4: verify a fixture decrypts correctly

$ python3 gen_fixture.py generate --seed 0xdeadbeef --rounds 3 \
      --symbol-diverse-body --symbol-len 256 --message DIVERSE_OK --out div.c
Wrote div.c
Generated symbol prefix length: 256 (requested base=256, pad=0)
  note: diverse body enabled (non-recurring segments, seeded by 0xdeadbeef)
Compile with:
gcc -O0 -g3 -gdwarf-5 -fno-omit-frame-pointer -fno-inline -std=c11 div.c -o div.exe

$ gcc -O0 -g3 -gdwarf-5 -fno-omit-frame-pointer -fno-inline -std=c11 div.c -o div.exe
$ ./div.exe
DIVERSE_OK

The printed line equals the message that was encrypted into the file. The fixture proves itself.

Example 5: the highest-density tested fixture

Example 4 verified that a fixture works. This example builds the highest-density fixture found among the tested constructions and measures how expensive it is to tokenize the generated source. We use varied high-plane Unicode code points that byte-level tokenizers have no vocabulary entry for. The generator places them across the whole file.

Note on standards: these identifiers need C11 or later. The characters are raw multi-byte UTF-8, which older standards do not allow in identifiers. The practical situation depends on how strict the build is:
  • C89: rejected, even by default (stray '\360' in program).
  • C99: accepted by default by GCC, but rejected under strict conformance (-pedantic-errors).
  • C11 and later: accepted.
So the fixture is only portable to modern compilers, and every build command below uses -std=c11 for that reason. The generator emits these characters only when you explicitly ask for them.

Step 1: generate the Unicode fixture

$ python3 gen_fixture.py generate --seed 0xdeadbeef --rounds 8 \
      --symbol-len 512 --symbol-unicode-body --message HARDEST_FIXTURE_OK --out hardest.c
Wrote hardest.c
Generated symbol prefix length: 512 (requested base=512, pad=0)
  note: UNICODE body enabled (high-plane code points, ~4 tokens/char); requires -std=c11 or later to compile
Compile with:
gcc -O0 -g3 -gdwarf-5 -fno-omit-frame-pointer -fno-inline -std=c11 hardest.c -o hardest.exe

$ gcc -O0 -g3 -gdwarf-5 -fno-omit-frame-pointer -fno-inline -std=c11 hardest.c -o hardest.exe
$ ./hardest.exe
HARDEST_FIXTURE_OK

The file is 19,794 characters but 61,266 bytes because each identifier character is 4 UTF-8 bytes. It still compiles and prints its message correctly.

Anatomy of hardest.c

// ---------------------------------------------------------------
// header comment: seed, rounds, mode, and the suggested build command
// ---------------------------------------------------------------

#include <stdint.h>
#include <stdio.h>
#include <stddef.h>

// ---- 1) the type name: 512 high-plane code points (each 4 bytes) + ASCII suffix ----
typedef struct <512 x U+30000..U+303FF>_Type__LongRecord__With__Lots__Of__Nested__Like__Tokens {
    uint64_t a;
    uint64_t b;
    uint64_t c;
} <512 x U+30000..U+303FF>_Type__LongRecord__With__Lots__Of__Nested__Like__Tokens;

// ---- 2) a small shared helper ----
static uint32_t xorshift32(uint32_t x) {
    x ^= x << 13;
    x ^= x >> 17;
    x ^= x << 5;
    return x;
}

// ---- 3) eight near-identical functions, ONE PER ROUND ----
// each signature line is 1098 characters and contains the huge name TWICE
__attribute__((used, noinline))
uint32_t <512 x U+30000..U+303FF>_R0(<512 x U+30000..U+303FF>_Type__... *p) {
    uint32_t m1 = xorshift32(0x9336956du ^ 0x31bbf978u ^ (uint32_t)p->a);
    uint32_t m2 = xorshift32(0xcd6f55fcu ^ (uint32_t)p->b);
    p->a ^= ((uint64_t)m1 << 32) | (uint64_t)m2;
    p->b += (uint64_t)(0x9336956du ^ m2);
    p->b = (p->b << 10) | (p->b >> 54);
    p->c = (p->c + p->a) ^ (uint64_t)(0x31bbf978u ^ 0xcd6f55fcu);
    uint64_t r = p->a ^ p->b ^ p->c ^ (uint64_t)0x9336956du ^ ...;
    return (uint32_t)(r ^ (r >> 32));
}

// ... the same shape repeats for R1, R2, R3, R4, R5, R6, R7 ...

// ---- 4) a driver that calls all eight functions in sequence ----
uint32_t derive_state(uint32_t seed) {
    <512 x U+30000..U+303FF>_Type__... x = { seed, seed ^ 0x12345678ULL, seed + 0x9ULL };
    uint32_t s = seed;
    s ^= <512 x U+30000..U+303FF>_R0(&x);
    s ^= <512 x U+30000..U+303FF>_R1(&x);
    /* ... R2 .. R7 ... */
    s = xorshift32(s);
    return s;
}

// ---- 5) main(): decrypt the embedded message at runtime ----
int main(void) {
    uint8_t encrypted[] = { 0x2a, 0xa3, 0x34, /* ... */, 0x00 };
    uint32_t s = derive_state(0xdeadbeef);
    for (size_t i = 0; i < sizeof(encrypted) - 1; i++) {
        s = xorshift32(s + 0xA5A5A5A5u);
        encrypted[i] ^= (uint8_t)(s & 0xffu);
    }
    puts((const char *)encrypted);   // prints HARDEST_FIXTURE_OK
    return 0;
}

The identifier is abbreviated as <512 x U+30000..U+303FF> only for display. in the file it is 512 real code points, which makes it the highest-density tested case. See the "identifier in full" note below for why they are shown this way.

Step 2: tokenize the generated C file

$ .venv/bin/python tokenize_file.py hardest.c
19,794 chars -> 57,674 tokens
2.9137 tokens per character
0.941 tokens per byte

Compare that with the diverse-body fixture at the same inputs: 9,498 tokens (0.481 tpc). The Unicode fixture is roughly more expensive.

Step 3: where the difficulty comes from

$ .venv/bin/python where_do_the_tokens_go.py hardest.c
name: 567 chars / 2103 bytes -> 2045 tokens
name appears 11 times
tokens spent on the name: ~22,495
share of all tokens: 39.0%
One repeated name accounts for 39% of every token in the file. The name is 567 characters but 2,103 bytes, costing 2,045 tokens, or about 0.97 tokens per byte, essentially the ceiling for byte-level tokenization.

Step 4: the three name styles compared

The seed, rounds, and length are identical. Only the naming mode changes:

Name style Chars Bytes Tokens (A) Tokens/char (A) Tokens (B)
Repetitive (default)19,78619,7866,8790.3486,724
Diverse (--symbol-diverse-body)19,75919,7599,4980.4819,424
Unicode OOV (--symbol-unicode-body)19,79461,26657,6742.91457,701

All three rows were generated in the same directory with the same flags, only changing the mode, and measured with the same tokenizer. Char totals include the header comment, which embeds the output filename. Exact counts therefore shift slightly with the file name, while the token counts and ratios are stable.

Two effects stack: the characters are non-recurring and every one of them is 4 bytes with no vocabulary entry, so it falls back to raw bytes. That is why this mode is ~6× the diverse fixture and ~8× the repetitive one. Unlike some Unicode inputs such as emoji, it is expensive in both tokenizers.

Step 5: what the difficulty means in practice

Context window

45.1% of a 128k-token context window, from a 19,794-character, 61,266-byte source file.

Token-per-byte ceiling

0.941 tokens/byte across the whole file, near the theoretical maximum of 1, since non-vocab characters produce one token per byte.

vs. ordinary C

A typical small C file tokenizes at ~0.40 tokens/char. This one is ~7× that, for the same language.

How the hard name splits
first 8 tokens of the generated name:
['ð', '°', 'Ģ', '§', 'ð', '°', 'į', '©']

Those are the byte-level representations of the raw UTF-8 bytes. The tokenizer has no piece for these code points, so each byte becomes one token. That is exactly the fallback behaviour that creates this high-density case.

The generated identifier, up close

The identifier is shown as code points because most fonts render U+30000–U+303FF as blank or tofu boxes. The tokenizer likewise has no entry for these uncommon characters.

body: 512 characters, code points U+30000 .. U+303FF, each 4 UTF-8 bytes
U+30027 U+30369 U+303C1 U+30368 U+30305 U+303B8 U+302A6 U+30328 U+302EB U+30343
U+3030C U+30224 U+30235 U+30202 U+3016B U+30285 U+3031F U+30116 U+303E6 U+3034B
... (492 more, all in the same range) ...

+ ASCII suffix (55 chars):
_Type__LongRecord__With__Lots__Of__Nested__Like__Tokens

The 512 body characters contain 407 distinct code points, so there is almost no repetition for the tokenizer to exploit. (Counting the ASCII suffix too, the full 567-char name has 429 distinct characters.)

What the measurements show: unfamiliar input can cost more than longer, familiar text. A 19,794-character (61,266-byte) file of dense high-plane Unicode costs 57,674 tokens: more than a large real-world source file several times its size. Cost tracks familiarity, not length.

08Source-recovery benchmark

The tokenizer experiments establish the mechanism: at nearly the same source-character count, high-plane Unicode produces about as many tokens as diverse ASCII and 8.4× as many as repetitive ASCII. The source-recovery test asks whether a model can recover the program's decryption algorithm while processing that much irrelevant token pressure.

Source-only benchmark. The model receives the complete C source directly, without Ghidra or other analysis tools. An earlier Ghidra-mediated path truncated very long names to roughly 1,006 characters before the model saw them. Direct source delivery removes that measurement artifact.

Test design

Hold the algorithm fixed

Every tested fixture uses five generated rounds, seed 0xDEADBEEF, constant seed 0xC001D00D, and the same visible message.

Increase Unicode pressure

Only the high-plane Unicode symbol length changes: 1,024, 2,048, then 4,096 characters. The complete source is embedded inline in the initial request.

Grade general recovery

A pass requires one Python decoder, exact visible output, no plaintext literal, and a successful unseen seed/ciphertext vector using the same round functions.

GPT 6 Astra results

GPT 6 Astra was the only model that completed the new high-length inline series. OpenCode's free-model path began rejecting automated requests during the experiment. Those provider errors are excluded from model grading.

Graded attempts3 / 3 passVisible and hidden vectors
Confirmed lower bound4,096Unicode symbol characters
Largest request299,591Total provider-reported tokens
Runtime range23.0–24.5 sNo observed latency growth
Unicode
length
Outcome Source
chars
Source
bytes
Cache-write
tokens
Output
tokens
Total
tokens
Runtime Cost
1,024Pass22,80778,10378,2271,16279,39223.0 s$1.03597
2,048Pass41,239151,831151,7561,121152,88024.5 s$1.95303
4,096Pass78,103299,287298,670918299,59124.3 s$7.53566

These are OpenCode's provider counters, not Nemotron or DeepSeek tokenizer counts. OpenCode classified almost the whole inline source as cache write and only three tokens as ordinary input in each attempt. The categories are billing labels; total context is the meaningful comparison.

Context grew while runtime stayed flat

Provider-reported total tokens

1,024
79,392
2,048
152,880
4,096
272K price tier
299,591

From 1,024 to 4,096, total token traffic grew 3.77×. Runtime stayed near 24 seconds, output fell from 1,162 to 918 tokens, and every hidden test still passed. Across these three attempts, the added Unicode increased cost without a measured correctness or latency penalty.

Cost at 4,096 characters

More tokens increased cost once by increasing request size. They increased it a second time by crossing GPT 6 Astra's 272K-token long-context pricing boundary. OpenCode's recorded rates at the time were:

Context tierInput / 1MOutput / 1MCached read / 1MCached write / 1M
At or below 272K$10.00$50.00$1.00$12.50
Above 272K$20.00$75.00$2.00$25.00
4,096-character fixture:
298,670 cache-write tokens × $25 / 1M = $7.46675
    918 output tokens      × $75 / 1M = $0.06885
      3 input tokens       × $20 / 1M = $0.00006
                                          ──────────
                                      total $7.53566

At the lower tier, the same token counts would have cost about $3.77931. The increase comes from a billing threshold, not a cache failure or technical cache limit. Provider pricing can change; these values record the rates applied to the stored attempts.

Earlier Muse source-recovery observations

Muse Spark 1.3 completed an earlier attachment-based series. It passed at length 832, then submitted incorrect decryptors twice at 896 and twice at 1,024. Astra later passed the exact same 1,024-character generated source and continued through 4,096.

ModelDeliveryUnicode lengthAttemptsPassesObserved result
Muse Spark 1.3Attachment83211Pass
Muse Spark 1.3Attachment89620Incorrect decoder
Muse Spark 1.3Attachment1,02420Incorrect decoder
GPT 6 AstraInline1,024–4,09633All pass
These runs do not provide a controlled model ranking. Muse and Astra used different source-delivery paths, and each Astra length has only one attempt. The results may reflect different tolerance to this fixture, but they do not support a general model ranking.

The Unicode generator draws with replacement from 1,024 high-plane code points while avoiding adjacent duplicates. The 4,096-character symbol contained 997 unique characters. Past 1,024, added length mainly increases repetition and context volume; the alphabet stays fixed.

Infrastructure events excluded from model results

LengthClassificationWhat happened
2,048Harness errorThe first attempt hit the local operating system argument-size limit before inference. Large prompts were then piped through stdin.
4,096Provider errorThe first attempt was rejected by the workspace monthly spending limit. No model response was produced.
Source-recovery result: the original project showed that unfamiliar high-plane Unicode is extraordinarily expensive to tokenize. Source recovery showed that Astra could still ignore that noise and reconstruct the five-round decoder at nearly 300K reported tokens. In the tested range, context cost became the practical constraint before model correctness.

Security implications

The controlled measurements establish an input-amplification mechanism. At nearly the same source-character count, the Unicode fixture used about 6 times as many tokens as diverse ASCII and 8.4 times as many as repetitive ASCII. Increasing the high-plane Unicode body also pushed the provider request across a more expensive context-pricing tier. Character-count limits alone would not reveal either effect.

Abuse hypothesis, not a demonstrated exploit. A system that automatically sends untrusted source code to an LLM could be made to spend more money or consume more context by accepting extremely long identifiers filled with uncommon four-byte code points. This is particularly relevant to automated code review, malware triage, and other security products whose inputs may be controlled by the subject being analyzed. Enough amplification could exhaust a request budget, cross a billing threshold, reduce how much surrounding evidence fits in context, or trigger truncation before analysis begins.

The experiment did not demonstrate an outage, missed vulnerability, or dependable model failure. Tokenization time remained close to linear, and Astra completed all three tested fixtures. The supported concern is therefore context and billing amplification, with possible downstream analysis loss if a product handles oversized input poorly.

Defensive validation should measure UTF-8 bytes and tokens with the deployed model's tokenizer, not characters alone. Products can flag extreme token density or identifier length, enforce per-request context and spending limits, and replace repeated hostile identifiers with stable placeholders in the model-facing copy while preserving an exact mapping to the original source. Rejection or truncation should be explicit and structure-aware. Unicode normalization alone is insufficient because valid high-plane code points may remain unchanged.

These archived provider results are included for inspection in the reproduction bundle, but its offline verifier does not rerun them: full analysis · campaign index · 1,024 report · 2,048 report · 4,096 report

09Glossary

Token

A subword chunk read by a model. It may be shorter than a word or span several characters.

Tokenizer

The program that converts text into tokens using a fixed vocabulary and merge rules.

Vocabulary

The dictionary of known pieces. Different models have different vocabularies.

High-plane Unicode

An informal term used here for Unicode code points above the Basic Multilingual Plane, starting at U+10000. The fixtures use U+30000 through U+303FF; each code point occupies four bytes in UTF-8 and is uncommon in tokenizer vocabularies.

BPE (Byte-Pair Encoding)

A method that learns frequent character pairs and merges them into larger pieces.

Pre-tokenization

The rule-based first cut of text into rough chunks before merging.

Byte fallback

When a character is not in the vocabulary, it is emitted as one token per raw byte. Byte fallback is the expensive case.

Cache-write tokens

Prompt tokens billed while a provider creates a reusable prompt-cache entry. They are separate from ordinary input, output, and cache-read tokens. In these one-shot attempts, nearly all inline source text was classified as cache write. This increased cost but did not indicate an error or technical cache limit.

Tokens per character (tpc)

Token count divided by length. The primary cost metric here.

Fixture

A generated, compilable C program carrying a controlled identifier and a verifiable encrypted message.

Sweep

A series of fixtures varying one property, measured together.

Repetition ratio

How much cheaper a repeated pattern is than its non-repeated equivalent.