挫败LZMA2压缩


11

目标

创建一个或多个程序以共同破坏和修复文件,以防止LZMA2有效工作。打扰和修复例程必须是相互的,因此您可以准确地恢复原始文件。

目标

压缩方式

  • Ubuntu /相关: xz -kz5 <infile>
  • 视窗: 7z.exe a -txz -mx5 <outfile> <infile>
  • 其他:使用压缩级别5的LZMA2压缩器将莎士比亚作品压缩为1570550字节±100字节。

得分;总和(一切以字节为单位,ls -ldir它):

  • 程序的大小(可逆地“破坏” /修复文件所需的总和)
  • 大小之间的差异(绝对值):
    • 莎士比亚的原始作品集和经过修改(未压缩)的副本。
    • 原始照片和修改(未压缩)的副本。
  • 大小差异或0,两者之间的较大者:
    • 莎士比亚原始作品集减去修改后的LZMA2压缩副本。
    • 原始照片减去修改后的LZMA2压缩副本。

得分不高,懒惰但符合标准的Python 2.x示例:

import sys
x = 7919 if sys.argv[1] == 'b' else -7919
i = bytearray(open(sys.argv[2], 'rb').read())
for n in range(len(i)):
    i[n] = (i[n] + x*n) % 256
o = open(sys.argv[2]+'~', 'wb').write(i)

跑步...

$ python break.py b pg100.txt 
$ python break.py f pg100.txt~ 
$ diff -s pg100.txt pg100.txt~~
Files pg100.txt and pg100.txt~~ are identical
$ python break.py b Glühwendel_brennt_durch.jpg 
$ python break.py f Glühwendel_brennt_durch.jpg~
$ diff -s Glühwendel_brennt_durch.jpg Glühwendel_brennt_durch.jpg~~
Files Glühwendel_brennt_durch.jpg and Glühwendel_brennt_durch.jpg~~ are identical
$ xz -kz5 pg100.txt~
$ xz -kz5 Glühwendel_brennt_durch.jpg~
$ ls -ln
-rw-rw-r-- 1 2092 2092     194 May 23 17:37 break.py
-rw-rw-r-- 1 2092 2092 1659874 May 23 16:20 Glühwendel_brennt_durch.jpg
-rw-rw-r-- 1 2092 2092 1659874 May 23 17:39 Glühwendel_brennt_durch.jpg~
-rw-rw-r-- 1 2092 2092 1659874 May 23 17:39 Glühwendel_brennt_durch.jpg~~
-rw-rw-r-- 1 2092 2092 1646556 May 23 17:39 Glühwendel_brennt_durch.jpg~.xz
-rw-rw-r-- 1 2092 2092 5589891 May 23 17:24 pg100.txt
-rw-rw-r-- 1 2092 2092 5589891 May 23 17:39 pg100.txt~
-rw-rw-r-- 1 2092 2092 5589891 May 23 17:39 pg100.txt~~
-rw-rw-r-- 1 2092 2092 3014136 May 23 17:39 pg100.txt~.xz

得分了

  • = 194 + 绝对(5589891 − 5589891)+ 最大值(5589891 − 3014136,0)+ 绝对(1659874 − 1659874)+ 最大(1659874 − 1646556,0)
  • = 194 + 0 + 2575755 + 0 + 13318
  • 2,589,267字节。 不好,但是对文件不执行任何操作,则得到4,635,153字节的分数。

澄清度

这是高尔夫,因此您正在尝试自己的得分降至最低。我不确定这些评论是否指出了我的得分上的合理漏洞,或者是因为我将其弄得太复杂了。无论如何,您都想要最小的

  • 源代码
  • 未压缩的修改文件和原始文件之间的差异(例如,如果您通过在末尾附加一个兆兆0来对其进行修改,则您的分数只会增加一兆字节)
  • 压缩后的修改文件与原始文件之间的差异(例如,文件变得越不可压缩,则得分越高)。一个完全不可压缩的文件,其增长很小或根本没有增长,将获得0分。

2
棘手的答案:步骤1-算出您有多少可用磁盘空间,然后将其除以文件大小,得到N。步骤2-将文件附加到自身N次并附加数字N。步骤3-意识到有没有压缩文件的空间,但最终导致文件大小的绝对差异达到几个terrabytes(或更多)...。[要反转,请从文件末尾读取N并将文件缩小到大小的1 / N。 ]
MT0

@ MT0:嗯,我认为解决的办法是差异应该不会是绝对的。如果修改后的文件较大,则应减去分数。
克劳迪(Cluaudiu)2014年

@ MT0如果您修改文件使其大小达到1 TB,那么您的分数将为1 TB ...在尝试打高尔夫球时非常糟糕。
尼克T

@ MT0我在帖子中添加了说明,对您有帮助吗?
尼克T

2
一个小问题。如果t特别不可压缩,则压缩程序可能会生成更大的文件。在这种情况下,您应该得到奖励,而不是受到惩罚,不是吗?
克劳迪(Claudiu)2014年

Answers:


8

Python,得分= 120

import sys,hashlib
i=0
for c in sys.stdin.read():sys.stdout.write(chr(ord(c)^ord(hashlib.md5(str(i)).digest()[0])));i+=1

计数器模式下使用md5进行一次填充。将文件与之异或。这具有以下优点:原始文件和已破坏文件的大小相同,并且破坏程序和修复程序是相同的程序。

压缩后的破坏文件比原始文件大。


我调整了进球,所以如果压缩的文件较大比原来的同行,你不惩罚他们只是得分为0。不知道区别是哪一种方式为您的文件,但你可能要更新的比分
尼克ŧ

@NickT:已更新。
基思·兰德尔

8

C,51 = 51 + 0 + 0 + 0 + 0

main(c){for(;c=~getchar();putchar(~c^rand()>>23));}

高尔夫技巧下,该程序为标准输入中的每个字节循环,并执行rand()的异或运算。我在OpenBSD 5.5的libc中用rand()测试了它。

用法:

./scramble <orig >scrambled
./scramble <scrambled >orig.copy

为了测试我的程序,我编写了一个shell脚本test.sh(57行)来编译我的程序并计算分数。

$ sh test.sh
[1/4] Compiling scramble...
/tmp//ccbcB43x.o(.text+0x6): In function `main':
: warning: rand() isn't random; consider using arc4random()
[2/4] Scrambling files...
[3/4] Compressing scrambled files...
[4/4] Checking descrambler...
SCORE: 51=51+0+0+0+0
You may wish to rm -rf tmp.9Tjw89dgCs
$ ls -l tmp.9Tjw89dgCs/
total 43032
-rw-r--r--  1 kernigh  kernigh  1659874 May 28 17:23 filament.jpg.cp
-rw-r--r--  1 kernigh  kernigh  1659874 May 28 17:23 filament.jpg.sc
-rw-r--r--  1 kernigh  kernigh  1660016 May 28 17:23 filament.jpg.sc.xz
-rw-r--r--  1 kernigh  kernigh  5589891 May 28 17:23 pg100.txt.cp
-rw-r--r--  1 kernigh  kernigh  5589891 May 28 17:23 pg100.txt.sc
-rw-r--r--  1 kernigh  kernigh  5590232 May 28 17:23 pg100.txt.sc.xz
-rwxr-xr-x  1 kernigh  kernigh     8564 May 28 17:23 scramble

关于rand()和右移的注意事项

任何压缩算法都不能压缩随机数据。如果我使用流密码对其进行加密,我可以将pg100.txtfilament.jpg伪装成随机数据。

我的第一个想法是使用pad来对密文进行异或运算以生成密文,然后将密文pad都存储在加扰的文件中。这将增加文件的大小,并增加我的分数。显而易见的选择是对每个文件使用相同的填充,并且仅将密文存储在加扰的文件中。如果我只调用rand(),它将使用默认种子1,并且每次都使用相同的填充

OpenBSD 5.5在stdlib.hrand.c中定义rand():

/* from stdlib.h */
#define RAND_MAX    0x7fffffff

/* from rand.c */
static u_int next = 1;

int
rand_r(u_int *seed)
{
    *seed = *seed * 1103515245 + 12345;
    return (*seed % ((u_int)RAND_MAX + 1));
}

int
rand(void)
{
    return (rand_r(&next));
}

这是线性同余生成器。最大的缺陷是低位的周期短。第一位的周期为2:如果您使用掷硬币rand()&1,则硬币的正面,反面,正面,反面等等。第n位的周期为2 n。有31位,因此整个序列的周期为2 31

LZMA2可以在短时间内找到模式并将其压缩。最短的代码~c^rand()占用低8位,并且不会阻止压缩。正确的转变有~c^rand()>>9帮助,但还不够。我用~c^rand()>>23

  • ~c 分数:4227957 = 40 + 0 + 0 + 4019391 + 208526
  • ~c^rand() 分数:2474616 = 47 + 0 + 0 + 2463735 + 10834
  • ~c^rand()>>9 分数:350717 = 50 + 0 + 0 + 350667 + 0
  • ~c^rand()>>23 分数:51 = 51 + 0 + 0 + 0 + 0

5

BrainFuck:129(129 + 0 + 0 + 0 + 0)*

random.bf(添加了换行符以提高可读性)

,+[->>>>++[<++++++++[<[<++>-]>>[>>]+>>+[-[->>+<<<[<[<<]<
+>]>[>[>>]]]<[>>[-]]>[>[-<<]>[<+<]]+<<]<[>+<-]>>-]<[-<<+
>>]<<.,+[->]>>>]]

要创建,unrandom.bf您需要更改第二行中的最后一个+。

大部分代码基于Daniel B Cristofani 基于Rule30的随机数生成器,该生成器适用于将数字添加到每个输入,并在没有更多输入时终止。

*我已经测试了到目前为止已处理的字节212992(在12小时后处理),并且两个文件都变成了213064压缩文件。我想肯定可以在一周末完成,但是我不想等待发布。如果错误,我会更新分数,但请保留规则,因为Rule30会发动!

琐事:规则30是史蒂芬·沃尔夫拉姆(Stephen Wolfram)于1983年发现的,根据Wikipedia的说法,该规则用于在Mathematica中产生随机整数。

编译并运行:

它使用指数时间和空间(每个处理的字符迭代多于32个单元),因此它需要BrainFuck运行时,该运行时至少需要178,876,517个单元来编码Shakespear文件,不将非ascii视为unicode,具有超过8位的单元并使用-1为eof(介于255和-1之间)。我通常使用其他人的口译员,但是这次我需要成为一个插件并推广自己的:

jitbf --eof -1 -b 16 -c 200000000 random.bf < pg100.txt > pg100.txt.ran
jitbf --eof -1 -b 16 -c 200000000 random.bf < Glühwendel_brennt_durch.jpg > Glühwendel_brennt_durch.jpg.ran

jitfb将BrainFuck编译为优化的C,并滥用perl Inline :: C来运行它。它与我的Extended BrainFuck编译器捆绑在一起。使用参数中的单元格大小和宽度,它将分配大约400MB。


3

CJam,22个字节

G,~q{5$H$+255%_@^o}/];

这使用了具有递归关系s n =(s n-5 + s n-16)%255(我错误选择,但仍然有效)的滞后斐波那契生成器和一个琐碎的种子来生成伪随机字节流,然后将其与输入进行异或。

我已使用2014年5月1日发布的CJam 0.6测试了我的代码。

这个怎么运作

G,~                    e# Dump 0, 1, ... and 15 on the stack.
   q                   e# Read from STDIN.
    {             }/   e# For each character in the input.
     5$H$              e# Copy the sixth and 19th element from the stack.
         +255%         e# Push their sum modulo 255.
              _@       e# Duplicate and rotate the character on top.
                ^o     e# XOR and print.
                    ]; e# Clear the stack.

得分了

$ LANG=en_US
$ alias cjam='java -jar /usr/local/share/cjam/cjam-0.6.jar'
$ cjam thwart.cjam < pg100.txt > pg100.txt~
$ cjam thwart.cjam < pg100.txt~ > pg100.txt~~
$ diff -s pg100.txt pg100.txt~~
Files pg100.txt and pg100.txt~~ are identical
$ cjam thwart.cjam < Gluehwendel_brennt_durch.jpg > Gluehwendel_brennt_durch.jpg~
$ cjam thwart.cjam < Gluehwendel_brennt_durch.jpg~ > Gluehwendel_brennt_durch.jpg~~
$ diff -s Gluehwendel_brennt_durch.jpg Gluehwendel_brennt_durch.jpg~~
Files Gluehwendel_brennt_durch.jpg and Gluehwendel_brennt_durch.jpg~~ are identical
$ xz -kz5 pg100.txt~ Gluehwendel_brennt_durch.jpg~
$ wc -c thwart.cjam pg100.txt* Gluehwendel_brennt_durch.jpg*
      22 thwart.cjam
 5589889 pg100.txt
 5589889 pg100.txt~
 5589889 pg100.txt~~
 5590232 pg100.txt~.xz
 1659874 Gluehwendel_brennt_durch.jpg
 1659874 Gluehwendel_brennt_durch.jpg~
 1659874 Gluehwendel_brennt_durch.jpg~~
 1660016 Gluehwendel_brennt_durch.jpg~.xz
28999559 total

3

PHP,117 + 0 + 0 + 0 + 0 = 117

因为您是否真的会将处理数据的任务委托给其他任何语言都无法识别?

<?=substr(gmp_export(gmp_invert(2*gmp_import($s=stream_get_contents(STDIN))+1,$m=2*gmp_pow(256,strlen($s)))/2+$m),1);

虽然所有其他解决方案都基于“安全”构造(例如“随机数生成器”或“军用级密码术”),但该解决方案只是将字符串解释为表示模数为2⋅256^长度的奇数,并计算其模逆

演示:

$ php thwart.php < 100.txt.utf-8 > 100.txt.utf-8~
$ php thwart.php < 100.txt.utf-8~ > 100.txt.utf-8~~
$ diff -s 100.txt.utf-8 100.txt.utf-8~~
Files 100.txt.utf-8 and 100.txt.utf-8~~ are identical
$ php thwart.php < Glühwendel_brennt_durch.jpg > Glühwendel_brennt_durch.jpg~
$ php thwart.php < Glühwendel_brennt_durch.jpg~ > Glühwendel_brennt_durch.jpg~~
$ diff -s Glühwendel_brennt_durch.jpg Glühwendel_brennt_durch.jpg~~
Files Glühwendel_brennt_durch.jpg and Glühwendel_brennt_durch.jpg~~ are identical
$ xz -kz5 100.txt.utf-8~ Glühwendel_brennt_durch.jpg~
$ wc -c *
 5589889 100.txt.utf-8
 5589889 100.txt.utf-8~
 5590232 100.txt.utf-8~.xz
 5589889 100.txt.utf-8~~
 1659874 Glühwendel_brennt_durch.jpg
 1659874 Glühwendel_brennt_durch.jpg~
 1660016 Glühwendel_brennt_durch.jpg~.xz
 1659874 Glühwendel_brennt_durch.jpg~~
     117 thwart.php
28999654 total

2

Shell脚本,203

id|gpg --batch --passphrase-fd 0 --personal-compress-preferences Uncompressed $1 $2

运行它:

% sh break.sh -c pg100.txt                       
% sh break.sh -d pg100.txt.gpg > pg100.txt-original
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected
% diff -s pg100.txt pg100.txt-original
Files pg100.txt and pg100.txt-original are identical
% sh break.sh -c Glühwendel_brennt_durch.jpg
% sh break.sh -d Glühwendel_brennt_durch.jpg.gpg > Glühwendel_brennt_durch.jpg-original
gpg: CAST5 encrypted data
gpg: encrypted with 1 passphrase
gpg: WARNING: message was not integrity protected
% diff -s Glühwendel_brennt_durch.jpg Glühwendel_brennt_durch.jpg-original
Files Glühwendel_brennt_durch.jpg and Glühwendel_brennt_durch.jpg-original are identical
% xz -kz5 Glühwendel_brennt_durch.jpg.gpg 
% xz -kz5 pg100.txt.gpg 
% ls -ln
total 28340
-rw-r--r-- 1 1000 1000      84 May 24 04:33 break.sh
-rw-r--r-- 1 1000 1000 1659874 Jan 19 17:22 Glühwendel_brennt_durch.jpg
-rw-r--r-- 1 1000 1000 1659943 May 24 04:46 Glühwendel_brennt_durch.jpg.gpg
-rw-r--r-- 1 1000 1000 1660084 May 24 04:46 Glühwendel_brennt_durch.jpg.gpg.xz
-rw-r--r-- 1 1000 1000 1659874 May 24 04:46 Glühwendel_brennt_durch.jpg-original
-rw-r--r-- 1 1000 1000 5589891 May 24 03:55 pg100.txt
-rw-r--r-- 1 1000 1000 5589941 May 24 04:43 pg100.txt.gpg
-rw-r--r-- 1 1000 1000 5590284 May 24 04:43 pg100.txt.gpg.xz
-rw-r--r-- 1 1000 1000 5589891 May 24 04:43 pg100.txt-original

不是很便携,但是可以以几个字节为代价。需要PGP(也可以使用OpenSSL实现)。编码文件和原始文件之间的〜50字节差异可能可以保存。

得分:

84 + abs(1659874-1659943)+ max(1659874-1660084,0)+ abs(5589891-5589941)+ max(5589891-5590284,0)= 203


1

Python,得分= 183 + 7 + 6 + 0 + 0 = 196

评分会因使文件完全不可压缩而受到惩罚,因为这样压缩后的文件会比压缩开销大。因此,我的程序使它们比完全不可压缩的略少:

import sys
from random import randint as J,seed
x=sys.stdin.read()
seed(ord(x[1]))
n=int(2362*J(1,2)**2.359)
sys.stdout.write(x[:n]+''.join(chr(ord(c)^J(0,255))for c in x[n:]))

结果:

Laxori@Laxori-PC /cygdrive/f/Programming/lzkill
$ cat photo.jpg | python break.py > photo.jpg~; cat photo.jpg~ | python break.py > photo.jpg~~; diff photo.jpg photo.jpg~~; xz -kz5 photo.jpg~

Laxori@Laxori-PC /cygdrive/f/Programming/lzkill
$ cat pg100.txt | python break.py > pg100.txt~; cat pg100.txt~ | python break.py > pg100.txt~~; diff pg100.txt pg100.txt~~; xz -kz5 pg100.txt~

Laxori@Laxori-PC /cygdrive/f/Programming/lzkill
$ ls -l
total 28337
----------+ 1 Laxori mkpasswd     183 2014-05-24 13:43 break.py
----------+ 1 Laxori mkpasswd 5589891 2014-05-23 19:19 pg100.txt
-rw-r--r--+ 1 Laxori mkpasswd 5589891 2014-05-24 13:45 pg100.txt~
-rw-r--r--+ 1 Laxori mkpasswd 5589884 2014-05-24 13:45 pg100.txt~.xz
-rw-r--r--+ 1 Laxori mkpasswd 5589891 2014-05-24 13:45 pg100.txt~~
----------+ 1 Laxori mkpasswd 1659874 2014-05-23 19:19 photo.jpg
-rw-r--r--+ 1 Laxori mkpasswd 1659874 2014-05-24 13:44 photo.jpg~
-rw-r--r--+ 1 Laxori mkpasswd 1659880 2014-05-24 13:44 photo.jpg~.xz
-rw-r--r--+ 1 Laxori mkpasswd 1659874 2014-05-24 13:44 photo.jpg~~

Laxori@Laxori-PC /cygdrive/f/Programming/lzkill
$ python
Python 2.5.2 (r252:60911, Dec  2 2008, 09:26:14)
[GCC 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 183 + abs(5589891-5589884) + abs(1659874-1659880)
196

使用当前规则,压缩文件更大不会受到任何影响。规则有变化吗?如果是这样的话,这种改变对这个程序是不公平的。
kernigh 2014年

@kernigh:是的,他们在我发布后改变了。确实,它们从一开始就应该是现在的样子。
克劳迪(Cluaudiu)2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.