I won't make these full pages until I've written an implementation. Or someone else does.
This is an attempt to make a form of Brainf*** with encrypted source, similar to a very simple Malbolge. I failed to make it significantly harder to write programs in, but at least the programs are shorter.
To encrypt a Brainf*** program:
- Convert each of the commands to a 3-bit number in binary (with each of (><+-.,) equalling 000, 001, 010, etc. respectively).
- Concatenate the commands into a bit-string.
- Split the bit-string into groups of seven, and interpret these as ASCII characters.
However, the encrypted form of the source must entirely consist of printable characters (codes 32-126 inclusive). So (+++++++) becomes "$I" followed by Special Character #18 (Device Control 2); thus, it is invalid. Since 3-bit commands become 7-bit characters, that means that each group of 7 commands becomes 3 characters. This means that a program can be written 7 commands at a time, but it also means that each group of commands must contain exactly 7 things. Hence, there are two restrictions imposed by the encryption:
- Some combinations of commands are invalid, e.g. (+++++++), which must be written as (++++-++) for reasons that will become clear later. Note that this actually increments the current cell 5 times, which brings us to the next restriction:
- Each group of commands must contain exactly 7 things, e.g. (++++.), which must be written (++++-+.).
Programming in Cryptf***
Suppose I wish to write an encrypted command which increments the current cell as many times as possible:
+ + + + + + + 0100100 1001001 0010010 $ I DC2
This does not entirely consist of printable characters, so we must change it somehow. In fact, there is a simple way for fixing a command sequence: since the first two bits of a character are 64 and 32, and a character is printable if it is >=32 and <=126, we can make a character printable by making one of the first two bits 1. Hence:
+ + + + - + + 0100100 1001001 1010010 $ I R
This increments the current cell 4-1+2=5 times, which is the maximum possible with a single triple of encrypted characters.
Here are some "useful" triples:
Increment current cell 5 times: +++++ = ++++-++ = $IR Set current cell to 0: [-] = [-]+--+ = giZ (among others) Output current cell: . = .+++--- = DI[ (among others) Decrement current cell 7 times: ------- = 6m[
In fact, for each Brainf*** command, there exists a large number of different triples that are equivalent, mostly beginning with a variation of (+-+-+-), so it sadly is trivial to encrypt a program, though decryption is not.
The Hello World program
There may be a shorter version than this, but here is an encrypted version of the shortest Brainf*** Hello World program.
I wonder how one would go about finding a minimal Hello World program?
Informal specification of mugh brains
This is a definition of mugh brains. It makes use of zombie and civilian actors, which aren't really actors (just syntactic salt).
There are four variable types:
- Zombies, who hold variables and act on them.
- Civilians, who create variables.
- Flesh, which holds one int32 value.
- Brains, which are int32 stacks.
- Case-insensitive (uses all-lowercase)
- Commands separated by newlines (spacing is important!)
- Zombies are "require host to be dead"-type (not that that makes a difference)
List of commands
|civilian (name)||Creates a civilian. The name must be unique.|
|zombie (name)||Creates a zombie, and selects them as the current zombie. The name must be unique.|
|kill (name)||If the name belongs to a civilian, destroys them, and creates flesh and brains of the same name as them (e.g. killing Einstein creates Einstein's flesh and Einstein's brains). If the name belongs to a zombie, destroys them, and drops any flesh or brains they may be holding.|
|infect (name)||Turns a civilian into a zombie, and creates their brains, which they automatically pick up. Doesn't work if there are no zombies.|
|(zombie)||Selects a zombie as current.|
|get (name)'s (flesh/brains)||Makes the current zombie pick up the given flesh or brains, if they exist. Doesn't work if the zombie is already holding something.|
|drop||Makes the current zombie put down their held flesh or brains.|
|(moan)||Pushes a value in octal onto the current zombie's flesh or brains. To encode values, see below. Doesn't work if the zombie isn't holding something.|
|(moan) (moan)||Uses a processing moan with the given argument. Again, see below for more information. Doesn't work if the zombie isn't holding something.|
|destroy [(name)'s ](flesh/brains)||Destroys flesh or brains. If no name is given, targets the current zombie's currently held flesh or brains. If the name belongs to a zombie or civilian who is still alive, they are killed first and then have their flesh or brains destroyed.|
|tear (flesh/brains)||Pops from the current zombie's currently held flesh or brains, discarding the value. Doesn't work if the zombie isn't holding something.|
|bite (flesh/brains)||Pops from the current zombie's currently held flesh or brains, outputting the value as an integer. Doesn't work if the zombie isn't holding something.|
|eat (flesh/brains)||Same as bite, but if it was brains, all the values are popped and outputted. Destroys the flesh or brains afterwards.|
I tried my best, here and below, to recreate the style of famous zombie moans, and the original example program.
To make it easier for the programmer to make it look good, there are several possible moans for each possible digit.
|Octal digit||One possible string||Another possible string|
For example, 619 could be "gaahoarb", "gaahoarurr", "gaahgrurr", "aahgoarb", "aahgoarurr", etc.
Here, "Top" refers to the top value (if targetting brains) or just the value (if targetting flesh). "a" is the argument.
|blaah (a)||Pushes Top subtract a|
|blagh (a)||Pushes a subtract Top|
|braah (a)||Duplicates Top (has no effect on flesh; ignores argument)|
|bragh (a)||Reverses order of values (has no effect on flesh; ignores argument)|
|brargh (a)||Swaps topmost two items (has no effect on flesh; ignores argument)|
|daah (a)||Pushes Top add a|
|deaah (a)||Reads a character and pushes its integer value (ignores argument)|
|feaah (a)||Pushes 1 if a > top; pushes 0 if a < top|
|grahn (a)||Pushes Top multiply a|
|moahn (a)||Pushes Top divide a|
|moan (a)||Pushes Top mod a|
|mroahn (a)||Pushes a divide Top|
|mroan (a)||Pushes a mod Top|
|nugh (a)||Pushes Not(a) (bitwise Not)|
|nuhh (a)||Pushes Not(Top) (bitwise Not)|
Hello World program:
zombie napoleon civilian batman kill batman get batman's brains gurr hraah garghargh goarargh goahurr aahgragh goahagh hrugh groar aahgragh goarargh aahgrargh garghoar gaahugh eat brains