Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling

My 1st post (japh)

by blazar (Canon)
on Nov 25, 2004 at 15:01 UTC ( #410408=obfuscated: print w/replies, xml ) Need Help??

Hi all,

this is my very first post here. I'd like to talk about my latest japh. My previous attempts had concentrated on either code or data obfuscation by means of tons of stuff like q* constructs with strange delimiters, eval(), and so on.

For this particular one instead I had a precise algorithm in mind. Eventually it turned out to be more of a golfing exercise than an obfuscation one. All in all there's no obfuscation at all and not much data obfuscation either, in the sense that it is clear to see *where* it is stored. Still IMHO it's not so easy to understand *what* the algorithm does and *why* it works. Here it is:

{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB=' .'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_, 256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}#JAPH,
Note that it's not a japh in the strictest sense, i.e. it doesn't simply print() "Just another Perl hacker,\n". Also, the effect it achieves is manifest under xterms and at *DOS prompt, whereas Linux console, even with $|==1 is too fast for it. A variant in which I slow it down by making it do a "few" unnecessary operations is
{$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr (($a||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB=' .'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g)x2,$_, 256),-9999..249,7);s/[^\w,]/ /g;$\=/^J/?$/:"\r";print,redo}
Despite what some people think about this kind of exercises, it turned out to be very instructive.

For example the first versions of this japh were so verbose that I didn't hope it would have been possible to shrink it to fit in .sig's standards. A big improvement was obtained when I realized that I didn't need to work with strings of "\0" and "\01" as I had initially assumed, but that any two chars would do instead. This is obvious if you think about the possible outcome of an expression of the kind a*b*c where * is a binary operation "of the kind of XOR" and a,b, and c can take two values only. But it was not so obvious until I stopped to think about it...

Replies are listed 'Best First'.
Re: My 1st post (japh)
by jdalbec (Deacon) on Nov 25, 2004 at 23:40 UTC
    Most of the second and third lines are devoted to initializing $a (and $| as a side effect):
    ||=join'',map--$|x$_,(unpack'w',unpack'u','G^<R<Y]*YB=' .'KYU;*EVH[.FHF2W+#"\Z*5TI/ER<Z`S(G.DZZ9OX0Z')=~/./g
    The two unpacks generate an array consisting of the number 14417713111218131332253147132969324349431334211136532212511512172112293224231453242. The decimal digits of this number are then extracted via =~/./g and used to run-length decode a bit string 1000011110... via map--$|x$_. Since the number of decimal digits is odd, the last value of $| is 1.

    After we remove the initialization code and the trailing #JAPH, comment we have:

    {$_=pack'B8'x25,unpack'A8'x32,$a^=sub{pop^pop}->(map substr (($a)x2,$_,256),7,249);s/[^\w,]/ /g;$ \=/^J/?$/:"\r";print,redo}
    The expression substr(($a)x2,$_,256) produces a copy of the bitstring rotated left by $_ characters (assuming 0<=$_<256). The map sets $_ to 7 and 249 producing the bitstring rotated left by 7 characters and rotated right by 7 characters respectively. These bitstrings are passed to sub{pop^pop} which XORs them together. They are then further XORed with the original bitstring.

    The unpack separates the bitstring into groups of 8 bits, and the pack converts the first 25 groups into characters. The substitution converts everything but letters and commas into spaces. The next statement sets the output line ending to a CR unless the first letter of $_ is a J in which case it sets it to the input line ending. The final redo starts over at the beginning of the block.

    The rotate-and-XOR operation used in this program has period 128, so every 128 iterations the JAPH string is printed. The initial bitstring becomes the JAPH string after 67 iterations. I note with interest that the bytes after the end of the JAPH string are not all binary zeros.
      You're right about everything. Incidentally this was not meant as a challenge or anything like that. However your exposition is as terse and clean as one could have been.

      The bytes "beyond JAPH" are not zeroes for I tried to take advantage of the remaining 56 degrees of freedom. (The lenght of the string must be a power of two for the periodicity effect to take place.)

      The wrong assumption I had initially done was that due to the belonging of 'a'..'z' and 'A'..'Z' to a restricted part of the set of all 256 charachters (especially "in terms of individual bits"), somewhere along the orbit of the transformation, and for a fortunate choice of the remaining bits I would have got a particularly "simple" string, for a sensible definition of "simple", i.e. something that I could code with ease in a sufficiently small space.

      So the further unpack()s where not expected at all in the beginning. Also, I had thought of an extensive search over all 2^56 remaining 7-bytes strings, 63 odd rotate values and 127 iterations of the transformation. On a second thought, considerations inherent to the limited duration of the universe , human life compared to it, and computing power available, convinced me to try a random search instead (wrt the 7-bytes strings).

      I got the string I'm actually employing after running my brute force search program for a while. It is nice in that (i) it yields a short enough coded string, (ii) it doesn't need escaping of chars (in some cases the string contains both "'"s and '"'s), (iii) it needs a resonably high number of iterations to reach the JAPH string.

      It may be worth mentioning that I've been running the search program in the background for a few weeks on a cluster of machines I have access to and it hasn't found a single coded string shorter than the current one, let alone a "better" one. In this connection it may also be worth mentioning that notwithstanding the fact that it had been launched with nice 18, that it caught correctly signals and that it carefully avoided having more than one instance running on each machine, it caught the attention of a few idio^Wother users who complained about it, so that I had to stop it definitely.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: obfuscated [id://410408]
Approved by Happy-the-monk
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others avoiding work at the Monastery: (5)
As of 2022-11-30 17:51 GMT
Find Nodes?
    Voting Booth?