perlmeditation
eyepopslikeamosquito
<P>
<blockquote>
<P>
<I>Perl is famous for its ability to
create programs that are entirely illegible to everyone but
the developer who wrote them. The Perl community even has
obfuscation contests to see who can write the most
unintelligible Perl code.</I>
</P>
<P align="right">
<small>
-- Andrew Clinick, Microsoft Scripting Program Manager in
<a href="http://msdn2.microsoft.com/en-us/library/ms974552.aspx">Perl of Wisdom</a>
</small>
</P>
<P>
<I>it's almost depressing to think that someone might actually
believe this. Programmers, not languages, write obfuscated code; and
Perl certainly didn't invent the concept.
</I>
</P>
<P align="right">
<small>-- brian d foy response on comp.lang.perl.misc 16 February 1999</small>
</P>
<P>
<I>I may have become partially famous for my obscure one-liners here on
Usenet, but when I write production code for hire, it's compact but
readable and well-documented ... let us please stop passing around the myth that Perl
*is* write-only code, or *encourages* write-only code.</I>
</P>
<P align="right">
<small>-- Randal L. Schwartz response on comp.lang.perl.misc 1st March 1999</small>
</P>
</blockquote>
</P>
<P>
Let me begin this meditation on recreational obfuscation
by reaffirming [brian_d_foy]'s and [merlyn]'s responses
above:
Perl is indeed a fine language for writing compact yet readable and maintainable systems.
</P>
<P>
Though [id://173506], writing deliberately obfuscated code
as a recreational pastime forms a proud part of Perl's
history and culture -- a fun way to explore TMTOWTDI
and the rich expressiveness of the language.
</P>
<P>
Obfu participation, of course, is optional, and many Perl programmers
have no interest in it.
Indeed, the following Perl generalissimos have never fired an obfuscated
monastic projectile in anger:
[vroom], [merlyn],
[dws], [dragonchild],
[davorg], [Elian],
[brian_d_foy],
[TheDamian] and [TimToady]
(though, admittedly, Tim did flirt briefly with
C obfus in the mid 1980s).
In case you're interested, from the PM top 40, the most prolific obfuscator
is number 23, [davido], with 30 obfuscated
notches in his belt.
</P>
<P>
This, the third part of the seemingly never-ending
series on the lighter side of Perl culture, focuses on
artistic (or recreational) obfuscation. Naturally, I won't
waste time on obfuscation for job security or,
<I>horrors</I>, for perverse and futile attempts to close open source.
</P>
<readmore>
<P><B>History</B></P>
<P>
Obfuscated code began long before Perl did. In 1972,
for example, Messrs Woods and Lyon outraged the
conservative IBM/Cobol world by implementing
<a href="http://catb.org/~esr/intercal/">Intercal</a>
on an IBM 360.
Not to mention the
<a href="http://www.ioccc.org/">International Obfuscated C Code Contest</a>
of '84, contested over three years before Perl's glitzy
launch on 18 December 1987.
</P>
<P>
Perhaps the earliest example of obfuscated Perl code
were some
<a href="http://www.cpan.org/misc/japh.old">JAPHs</a>
concocted by [merlyn] in the early 1990s.
These early JAPHs, however, were only mildly obfuscated
compared to those generated by the fierce competition
of the TPJ-sponsored Obfuscated Perl Competitions,
started in 1996, and run by Jon Orwant.
</P>
<P>
Another significant promoter of obfu
is the Perl Monks web site, sporting a distinct
[Obfuscated Code] section, containing around 500 compositions.
Indeed, from over half a million nodes, the most
popular PM node of all time is an obfuscated one,
the famous [id://45213].
</P>
<P>
Finally, it should come as no surprise that the
country hosting
<a href="http://www.louvre.fr/">The Louvre</a>
is also home to many eminent Perl obfu artisans.
In particular, the Paris Perl Mongueurs (sic) have
a long tradition of artistic obfuscation, evident
from one of the finest obfu pages on the web,
<a href="http://paris.mongueurs.net/aplusplus.html">$A++</a>.
</P>
<P><B>Constraints</B></P>
<P>
<blockquote>
<P>
<I>The more constraints one imposes, the more one frees oneself of the chains that shackle the spirit... the arbitrariness of the constraint only serves to obtain precision of execution.</I>
</P>
<P align="right">
<small>-- Igor Stravinsky, 1882-1971</small>
</P>
</blockquote>
</P>
<P>
Constraints are the heart of obfu.
When viewed as an art form, obfu seems closest to
poetry (which is constrained by rhyme and meter)
and
<a href="http://www.nous.org.uk/oulipo.html">Oulipo</a>
(formal constraints in literature, a famous example
being
<a href="http://www.themodernword.com/scriptorium/perec.html">
Georges Perec's</a>
300 page novel "La Disparition",
written without using the letter 'e').
</P>
<P>
Perl obfu constraints might be classified as follows:
</P>
<P>
<ul>
<li>Hard for human reader to understand
<li>JAPH
<li>$A++
<li>Restricted character set
<li>Restricted Perl subset
<li>Ascii art
<li>Size
<li>Perform a specified function
<li>Multi-lingual
<li>Quine
<li>Palindromic
</ul>
</P>
<P>
Further to the above list, obfu specialists are
always on the lookout for an original and surprising
new constraint.
</P>
<P><B>Hard for Human Reader to Understand</B></P>
<P>
An obfu should be made as difficult as possible to
comprehend, not only by using cheap tricks --
such as <CODE>y}}}c</CODE> instead of
<CODE>length</CODE> -- but by employing
unnatural algorithms.
For some general tips on how to make code harder
to understand, see [id://323567].
A fine example of an unnatural algorithm is described
by MJD
<a href="http://perl.plover.com/obfuscated/">here</a>.
</P>
<P><B>JAPH</B></P>
<P>
An obfuscated JAPH is constrained to output the string "Just another Perl hacker," -- for more information on JAPHs, see [id://412464].
</P>
<P><B>$A++</B></P>
<P>
<blockquote>
<P>
<I>$A++ is a deformation of "A plus" which is itself the common way
to shorten "A plus tard". It is for the French what "see you" is to
"see you later" in English.
</I>
</P>
<P align="right">
<small>-- [stefp]</small>
</P>
<P>
<I>And for the Australians, what "see ya" is to "see ya later mate"
(or "see ya later cobber").</I>
</P>
<P align="right">
<small>-- [eyepopslikeamosquito]</small>
</P>
</blockquote>
</P>
<P>
Like the JAPH, the $A++ is just an arbitrary canonical program. An $A++ does not emit anything, it
simply increments the variable $A.
Traditionally, it's a parting word to end an email with,
so it should be short.
</P>
<P>
The first $A++ was composed by [BooK] on Friday Oct 15 1999:
<CODE>
$A = eval q.@{[.."0,"x$A.qq|0]}|
</CODE>
Not bad for a first attempt! A bit more interesting than the first JAPH. ;-)
</P>
<P>
From the [BooK] archives, here are the earliest $A++s:
<CODE>
1999/10/15 BooK $A = eval q.@{[.."0,"x$A.qq|0]}|
1999/11/04 BooK $A =~ s/$A/$A+1/e
1999/11/04 Moun inc( $a, $a, $tchoum ); sub inc { map { s/^(.*)$/$1+1/e; }
@_ }
2000/01/31 BooK
for(map{2**$_}(0..31)){if(($A&$_)==0){$A|=$_;last}else{$A&=~$_}}
2000/02/18 BooK $A+=@{[$A]}
2000/02/21 Moun $A =
((@S=("($A==$S[1])?($S[1]+1):(($S[1]++,eval($S[0]))[1])",0)),eval($S[0]))[1]
2000/03/13 BooK $A =~ s/(-)?(\d+(?:\.\d*)?)/$1.($2+($1?-1:1))/e
2000/03/13 BooK $A =~ s/(-)?(\d+(?:\.\d*)?)/"$1 1+"x$2.'1'/egoisme
2000/03/17 BooK $A+=0<<1|2<<3>>4
2000/03/24 BooK $A=~s/(-)?(\d+(?:\.\d*)?)/# les filles c'est des cloches
(Souchon)
"$1 1+"x$2.'1'/sexisme
2000/03/30 BooK $A=@{[($A)x$A,$A]}
2000/03/30 BooK $A=~s/($A)/$1+1/e
2000/03/31 BooK A:goto(A)if$A!=$A+++1
2000/04/05 BooK $A=$A{$A}?&{$A{$A}}($A):&{$A{$A}=sub{1+shift}}($A)
2000/04/05 grinder $a = do{ while(1&$a) {$a>>=1}continue {++$b}($a|1)<<$b };
2000/04/06 grinder $a = do{$_=!$_;$_<<=1
while($a&$_<<1<=$a);($a&$_|1)+($a&$_&&$a&~$_|1||$a&~$_)};
2000/04/11 stefp ${ '`' | '!' } -= $#$ + ${""} - ${''}
2000/04/11 stefp $ {'`'| '!'}-=-- +$#$+ $ { ""}- --$ { ''}
2000/04/12 BooK *A=\($A+1)
2000/04/12 grinder use Cobol;
PROCEDURE DIVISION
ADD 1 TO A GIVING B
MOVE B TO A
2000/04/12 grinder $A = do{$_=!$_;$_<<=1
while(${'@'|'!'&~'"'}>=${'@'|'!'&~'"'}&$_<<1);(${'@'|'!'&~'"'}&$_|1)+(${'@'
|'!'&~'"'
}&$_&&${'@'|'!'&~'"'}&~$_|1||${'@'|'!'&~'"'}&~$_)};
2000/04/13 stefp use AI;
incrémente la variable scalaire a de 1 unité # $a++
2000/04/13 stefp ${"A\0comme quoi perl n'ignore pas partout les \0"}++
</CODE>
</P>
<P>
On Apr 12 2000, [grinder] proposed
that these $A++s be collected and put on an
<a href="http://paris.mongueurs.net/aplusplus.html">$A++ web page</a>.
</P>
<P><B>Restricted Character Set</B></P>
<P>
In this $A++:
<CODE>
${~$/&~$;&$^}++
</CODE>
Nicholas Clark restrains himself to non-alphanumeric characters only.
The converse, a speciality of [mtve], is illustrated
by another $A++:
<CODE>
y ccccd x s vvchr oct oct ord uc ave x s vvucve le
s vvuc ave x s vvchr oct oct oct ord uc bve x eval
</CODE>
See also: [id://290607], [id://488853], [id://338686], [id://453519], [id://450993].
</P>
<P><B>Restricted Perl Subset</B></P>
<P>
Damian Conway's
<a href="http://damian.conway.org/Seminars//Extreme.html">Extreme Perl -- The Horror That Is SelfGOL</a>
is an, er, horrific example,
constraining itself to not importing any modules,
and not using a single if, unless, while, until,
for, foreach, goto, next, last, redo, map, or grep.
</P>
<P>
Constraints sometimes happen accidentally.
When writing a little Sierpinski triangle generator,
for example, I noticed it seemed
to be using an awful lot of s/// operations ... so I
naturally tried to make it use <I>only</I> this operator.
Then, I noticed a lot of 'g' and 'e' characters ...
so I tried to use as many of these as possible.
None of this was planned, it just sort of happened.
Here is the final result (it takes a command
line argument (1-9) indicating the triangle size).
<CODE>
#!/usr/bin/perl -l
s--@{[(gE^Ge)=~/[^g^e]/g]}[g^e]x((!!+~~g^e^g^e)<<pop).!gE-ge,
s-[^ge^ge]-s,,,,s,@{[(g^';').(e^'?')]},(G^'/').(E^'|')^Ge,ge,
print,s,(?<=/[^g^e])[^g^e][^g^e],$&^(G^'/').(E^'|')^gE,ge-ge
</CODE>
</P>
<P><B>Ascii Art</B></P>
<P>
The constraint here is that your code must fit into
a specified shape. Some obfus are further constrained
in that only certain characters may fill certain
parts of the shape.
</P>
<P>
If you employ this style of obfu, strive to extend
the theme defined by the shape to the source
code itself.
Note in [id://45213] for example, [Erudil]'s choice
of variable names: $camel, @dromedary, @camelhump, and
so on. To further illustrate, when tuning [id://397958],
I changed <CODE>O^N^E}(@X,1.6)</CODE> to
<CODE>S|A|T|U}(@R,$N)</CODE> to better align
the code to the Saturnian theme.
</P>
<P><B>Size</B></P>
<P>
There are often practical limits on the size of an obfu.
In the TPJ Obfuscated Perl Contests, for example,
the original 1024 character size limit was reduced
by the judges to 512 bytes for OPC 5 -- which was a
<I>nasty</I> spoiler for those entrants, such as [BooK]
(Perl/Postscript obfu) and [TheDamian] (SelfGOL),
who had prepared 1024-byte entries months in advance!
Other obfu types limited by size are JAPH, $A++ and
Ascii Art.
</P>
<P>
Overcoming size limits can be a chronic nuisance,
requiring considerable golfing skills in addition to obfuscation ones. And significant golfing often spoils
the artistic merit of the obfu.
</P>
<P><B>Perform a Specified Function</B></P>
<P>
A common constraint is to perform a specified function,
such as fly through a Mandelbrot, as in [id://329492],
or play a game, as in [id://169437].
Apart from playing games, spectacular visual effects
and mathematical algorithms are popular choices for obfus.
</P>
<P><B>Multi-Lingual</B></P>
<P>
Some early PM examples of these are
[id://55464] and [BooK]'s [id://133971] response
to [Ovid]'s [id://133308] provocation.
</P>
<P>
[BooK]'s prize-winning OPC 5 Perl/Postscript obfu
can be found
<a href="http://www.yapceurope.org/2001/proceedings/26/fractalcamel/bestever.html">here</a>.
</P>
<P>
Lyon's fiercely competitive Jerome Quelin tried to
"out-BooK" [BooK] in his YAPC::Europe 2003 talk
by showcasing an octo-lingual (perl, c, c++, befunge, brainf**k, python, ook, html/javascript) program that computed the Fibonacci series.
</P>
<P><B>Palindromic</B></P>
<P>
An $A++ penned by the [mtve]:
<CODE>
!$A+++!q!+++A$!
</CODE>
</P>
<P><B>Humour</B></P>
<P>
When composing an obfu, always be on the lookout for
opportunities to add humour -- as Abigail did in
the classic [id://22319].
</P>
<P><B>Exploring the Medieval Castle</B></P>
<P>
<blockquote>
<P>
<I>Programming in Perl5 is like exploring a large medieval castle, surrounded by a dark, mysterious forest, with something new and unexpected around each corner. There are dragons to be conquered, maidens to be rescued, and holy grails to be quested for. Lots of fun.</I>
</P>
<P align="right">
<small>-- Abigail in
<a href="http://dev.perl.org/perl6/list-summaries/2002/p6summary.2002-12-08.html">December 2002 Perl 6 Summary</a>
</small>
</P>
</blockquote>
</P>
<P>
Exploratory obfuscation is perhaps more fun in Perl than
most languages. Why? For starters, there ain't no
[id://417042]. And there are numerous
experimental, obsolete (e.g. D'oh not D::oh), half-baked
(e.g. typed declarations) and undocumented (e.g.
<a href="http://nntp.perl.org/group/perl.fwp/1367">Japhy explains where behaviour of --$| is documented</a>)
features begging to be exploited by the evil obfuscator.
Moreover, Perl offers more freedom and fewer limitations than most languages -- consider, for example, composing
a Python Ascii Art obfu, given its ludicrous
indentation rules.
</P>
<P>
Two sample exploratory $A++ obfus from [stefp] are:
<CODE>
%average::; print probably not my average $A++
</CODE>
and
<CODE>
sub _ : lvalue { $A }; ++_();
</CODE>
</P>
<P>
Perl 6 is expected to be less fun for the obfuscator.
Most people consider this to be a feature, but not Abigail, who further opined: <I>"Perl6 looks like a Louis-XVI castle and garden to me. Straight, symmetric, and bright. There are wigs to be powdered, minuets to be danced, all quite boring."</I>.
</P>
<P><B>Some Classic Obfus</B></P>
<P>
There are many obfus I've never seen. Please let us know of any classic obfus I've overlooked.
</P>
<P>
<ul>
<li>[id://4679]
<li>[id://11590]
<li>[id://22319]
<li>[id://45213]
<li>[id://77619]
<li>[id://118799]
<li>[id://176043]
<li>[id://289733]
<li>[id://290607]
<li>[id://329174]
<li>[id://329492]
<li>[id://385823]
<li>[id://397958]
<li>[id://470390]
<li><a href="http://libarynth.f0.am/cgi-bin/twiki/view/Libarynth/SelfGOL">The Horror That Is SelfGOL</a>
<li><a href="http://www.ioccc.org/1986/wall.c">Surprise C obfu</a>
<li><a href="http://www.yapceurope.org/2001/proceedings/26/fractalcamel/bestever.html">BooK's TPJ OPC 5 Perl/Postscript obfu</a>
<li><a href="http://perl.plover.com/obfuscated/">MJD's TPJ OPC 5 entry</a>
</ul>
</P>
<P><B>Some Keen Perl Monk Obfuscators</B></P>
<P>
Please let me know of any I have overlooked.
</P>
<P>
<ul>
<li> [Abigail]
<li> [ambrus]
<li> [benn]
<li> [blokhead]
<li> [BooK]
<li> [BronzeWing]
<li> [chargrill]
<li> [clintp]
<li> [cog]
<li> [davido]
<li> [domm]
<li> [Erudil]
<li> [gmax]
<li> [Grimy]
<li> [grinder]
<li> [japhy]
<li> [Jasper]
<li> [jbware]
<li> [joecamel]
<li> [Len]
<li> [liverpole]
<li> [mtve]
<li> [o0lit3]
<li> [stefp]
<li> [teamster_jr]
<li> [Toodles]
<li> [trizen]
</ul>
</P>
<P><B>References</B></P>
<P>
<ul>
<li>[id://323567]
<li>[id://342355]
<li>[id://346500]
<li>[id://20312]
<li>[id://169553]
<li>[id://140626]
<li>[id://157703]
<li>[id://33780]
<li><a href="http://jynx.perlmonk.org/content/obfuhints.shtml">jynx obfu tips</a>
<li><a href="http://paris.mongueurs.net/assombri/yapc-2000.html">BooK's YAPC::Europe 2000 talk</a>
<li><a href="http://domm.zsi.at/talks/obfu_yapc2002/">domm's YAPC::Europe 2002 talk</a>
<li><a href="http://search.cpan.org/dist/Language-Befunge/">Language::Befunge</a>
<li><a href="http://www.nous.org.uk/oulipo.html">Oulipo</a>
<li><a href="http://catb.org/~esr/intercal/">Intercal Resources Page</a>
<li><a href="http://www.muppetlabs.com/~breadbox/bf/">Brainf**k</a>
<li><a href="http://www.eleves.ens.fr:8080/home/madore/programs/unlambda/">Unlambda</a>
<li><a href="http://www.nyx.net/~gthompso/quine.htm">The Quine Page</a>
<li><a href="http://www.nyx.net/~gthompso/poly/polyglot.htm">The Polyglot List</a>
<li><a href="http://www.nyx.net/~gthompso/self_mult.htm">polyglot quines</a>
<li><a href="http://scienceblogs.com/goodmath/2007/04/true_pathology_a_multilingual.php">polygot quine in OCaml, Haskell and Scheme</a>
<li><a href="http://search.cpan.org/dist/Quine/">Japhy's Quine module</a>
<li><a href="http://ideology.com.au/polyglot/">Polyglot, a program in 8 languages</a>
<li><a href="http://mrtg.planetmirror.com/pub/slashdot/mirror/quadrilingual/">A program in 4 languages by Jerome Quelin</a>
<li>[id://234034]
<li>[id://204451]
<li>[id://41310]
<li><a href="http://www.foo.be/docs/tpj/issues/vol1_3/tpj0103-0010.html">TPJ OPC 0</a>
<li><a href="http://www.foo.be/docs/tpj/issues/vol2_3/tpj0203-0012.html">TPJ OPC 1</a>
<li><a href="http://www.foo.be/docs/tpj/issues/vol3_3/tpj0303-0015.html">TPJ OPC 3</a>
<li><a href="http://www.foo.be/docs/tpj/issues/vol4_3/tpj0403-0017.html">TPJ OPC 4</a>
<li><a href="http://www.foo.be/docs/tpj/issues/vol5_3/tpj0503-0014.html">TPJ OPC 5</a>
<li><a href="http://www.ntk.net/1998/10/16/">European domination at TPJ OPC 3</a>
<li><a href="http://cam.pm.org/projects_home.shtml">cam.pm Obfuscated Programming Contests</a>
<li><a href="http://en.wikipedia.org/wiki/Obfuscated_code">wikipedia Obfuscated_code</a>
<li><a href="http://en.wikipedia.org/wiki/Obfuscated_Perl_contest">wikipedia Obfuscated_Perl_contest</a>
<li><a href="http://c2.com/cgi/wiki?ObfuscatedPerl">c2.com ObfuscatedPerl entry</a>
<li><a href="http://www.oreilly.com/catalog/tpj3/toc.html">Games, Diversions & Perl Culture</a>
</ul>
</P>
<P>
<ul>
<li> [id://1110291]
<li> [id://1110292]
<li> [id://866594]
</ul>
</P>
<P><B>Obfuscation Generators</B></P>
<P>
Though I find these of academic interest, they
are of little interest to obfuscators because
they detract from artistic merit and originality.
Two examples of these are [id://161087] and
<a href="http://search.cpan.org/dist/Acme-EyeDrops/">Acme::EyeDrops</a>.
</P>
<P><B>Is Obfu related to Golf?</B></P>
<P>
As <a href="http://www.nntp.perl.org/group/perl.golf/1753">pointed out</a>
by champion golfer Eugene van der Pijll,
there is usually little overlap between obfu and
golf (the subject of the next installment of this series),
a different mindset being required by each.
</P>
<P>
Occasionally however, a golfer accidentally produces a highly obfuscated solution in the heat of battle.
In
<a href="http://perlgolf.sourceforge.net/TPR/0/5a/">TPR(0,5a) (won by Eugene)</a>,
for example, Michael Thelen commented: "How absolutely confusing! Replacing parens with whitespace makes this probably the most obfuscated program I've ever written"
on his way to producing this infix to RPN converter:
<CODE>
#!perl -lp
y/()^I /^I_/d+s@^I|(?<=\w)\D@($/="
$&$/")=~s#_(\C*?)^I|(\S)([
*/${":"x/\G[+-]/}]*)#$2
#;$+@eg;$_.=$/;y/
/ /s+chop
</CODE>
</P>
<P><B>Acknowledgements</B></P>
<P>
I would like to thank [BooK] and [stefp] for their help in preparing this article.
</P>
<P><B>Other Articles in This Series</B></P>
<P>
<ul>
<li> [id://410774]
<li> [id://412464]
<li> [id://437032]
<li> [id://451207]
<li> [id://540609]
</ul>
</P>
<P>
<small>
Updated June 2014: Added [id://470390] to list of "Some Classic Obfus". Thanks [ambrus] for [id://1090400|mentioning this].
</small>
</P>
</readmore>