Skip to content

Commit 5054ab8

Browse files
owengregsonclaude
andcommitted
docs: update CLAUDE.md for unified naming system
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e60d750 commit 5054ab8

File tree

1 file changed

+16
-4
lines changed

1 file changed

+16
-4
lines changed

CLAUDE.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ JS VM obfuscator — compiles JavaScript functions into custom bytecode executed
66

77
- **Build**: `npm run build` (tsup, ESM-only)
88
- **Typecheck**: `npm run typecheck` (tsc --noEmit)
9-
- **Test**: `npm run test` (vitest, 1882 tests)
9+
- **Test**: `npm run test` (vitest, 1913 tests)
1010
- **Test watch**: `npm run test:watch`
1111
- **Node**: >= 18, **Module**: ESM (`"type": "module"`)
1212

@@ -43,10 +43,20 @@ src/
4343
expressions.ts Expression compilation (calls, members, operators, etc.)
4444
classes.ts Class compilation (methods, properties, inheritance)
4545
46+
naming/
47+
token.ts NameToken class — opaque handle with fail-fast .name/.toString()
48+
scope.ts NameScope class — child scope with own PRNG, claims tokens
49+
registry.ts NameRegistry class — central coordinator, resolveAll(), alphabet
50+
reserved.ts JS reserved words + excluded names sets
51+
claims.ts Canonical key definitions for RuntimeNames + TempNames scopes
52+
setup.ts Bridge: NameRegistry → RuntimeNames/TempNames (backward compat)
53+
compat-types.ts RuntimeNames and TempNames type interfaces
54+
index.ts Barrel exports
55+
4656
encoding/
47-
names.ts RuntimeNames interface + per-build randomized name generation (LCG PRNG)
57+
names.ts (Legacy) RuntimeNames interface + name generation — being replaced by naming/
4858
fingerprint.ts Build-time fingerprint computation
49-
decoder.ts Build-time custom FNV-1a+LCG cipher + custom alphabet encoding + alphabet generation
59+
decoder.ts Build-time custom FNV-1a+LCG cipher + custom alphabet encoding
5060
rolling-cipher.ts Build-time rolling cipher encryption + implicit key derivation
5161
5262
ruamvm/
@@ -104,6 +114,7 @@ test/
104114
security/ Anti-reversing, string encoding, rolling cipher, VM shielding, new feature tests
105115
integration/ Real-world patterns (Chrome extension, RuamTester)
106116
ruamvm/ AST emitter and transform tests
117+
naming/ Unified naming system tests (NameRegistry, AST integration, setup bridge)
107118
108119
docs/
109120
v1-transformations.md Archived v1 pipeline documentation
@@ -119,7 +130,8 @@ docs/
119130
- **Per-file opcode shuffle**: Seeded Fisher-Yates (LCG) produces different instruction encodings per build. Seed + shuffle constants live in `constants.ts`.
120131
- **Always-binary format**: All bytecode units are serialized to compact binary (`Uint8Array`) and encoded with a per-build shuffled 64-char alphabet (`A-Za-z0-9_$`). Same bit-packing as base64 (3 bytes → 4 chars) but no padding and a randomized alphabet per build. Output looks like random identifier strings. Alphabet generated via Fisher-Yates shuffle seeded from build seed. JSON serialization path has been eliminated. Runtime decoder builds a reverse lookup table from the embedded alphabet string.
121132
- **Constant pool string encoding**: All string constants are XOR-encoded with an LCG key stream. Binary format uses `BINARY_TAG_ENCODED_STRING` (tag 11) with uint16 char codes. Decoded at load time by the `strDec` runtime function. When rolling cipher is on, the encoding key is derived implicitly from bytecode metadata (no plaintext seed). Strings remain encoded even after outer encryption is reversed.
122-
- **Per-build identifier randomization**: All internal VM identifiers (`_vm`, `_BT`, `stack`, etc.) are replaced with random 2-6 char names generated via LCG PRNG (same seed as opcode shuffle). Adaptive retry increases minimum length after collisions. Managed by `RuntimeNames` interface in `encoding/names.ts`.
133+
- **Unified naming system** (`naming/`): A central `NameRegistry` + `NameScope` + `NameToken` architecture manages all per-build randomized identifiers. The registry creates scoped name pools, resolves all names collision-free via `resolveAll()`, and produces the encoding alphabet. The `setupRegistry()` function bridges the registry to the existing `RuntimeNames`/`TempNames` interfaces for backward compatibility. AST nodes accept `Name` (NameToken | string) for all identifier positions. Handler locals use `ctx.local("descriptiveName")` pattern (currently pass-through, will be registry-backed). Post-processing `obfuscateLocals` still renames handler-local variables.
134+
- **Per-build identifier randomization**: All internal VM identifiers are replaced with random 2-5 char names via the NameRegistry's LCG PRNG (same seed as opcode shuffle). Three length tiers: short (2-3), medium (3-4), long (4-5). Adaptive retry increases length after collisions. The encoding alphabet (64-char, Fisher-Yates shuffled) is also generated by the registry.
123135
- **Watermark**: Steganographic — the WATERMARK_MAGIC constant (FNV-1a of "ruam" = `0x2812af9a`) is XOR-folded into the FNV offset basis used for key anchor computation. No visible variable, string, or pattern in output. Verified by comparing key anchor results: using standard FNV basis instead of watermarked basis breaks all rolling cipher decryption.
124136
- **Prototypal scope chain**: Scope chain uses `Object.create(parent)` / `Object.getPrototypeOf(scope)` instead of a `{sPar, sVars}` linked list. Variables are own properties on scope objects. `in` operator traverses the prototype chain for reads; `Object.prototype.hasOwnProperty.call` walk for stores. TDZ uses a per-build sentinel object at IIFE scope (identity comparison via `===`). Program scope is `Object.create(null)` with `defineProperty` bindings.
125137
- **Array-based stack**: Stack uses native `Array.push()`/`Array.pop()`/`S[S.length-1]` instead of a dedicated stack pointer variable (`S[++P]`/`S[P--]`/`S[P]`). The stack pointer (`stp`) is generated but unused (preserved for LCG sequence stability). Exception handlers save `S.length` as `_sp` and restore via `S.length=_h._sp`. Stack encoding Proxy intercepts `push()` set traps on numeric indices.

0 commit comments

Comments
 (0)