News for hackers. Stuff that matters.
Re:Fast base64 encoding and decoding by _wmd on Wednesday January 17, 2018 @07:19PM (#16173445)
Today I learned!

    >>> import random,zlib,codecs
    >>> sample = random.getrandbits(1024).to_bytes(1024, 'big') * 1024
    >>> len(zlib.compress(codecs.encode(sample, 'base64')))
    22083
    >>> len(zlib.compress(codecs.encode(sample, 'hex')))
    4326
    >>>
edit: (25 minutes of digging around the Internet, and I find this):

    >>> sample = os.urandom(1024) * 1024

    >>> len(sample.encode('base64'))
    1416501
    >>> len(sample.encode('hex'))
    2097152
    >>> len(sample.encode('ascii85'))
    1310720

    >>> len(zlib.compress(sample.encode('base64')))
    82169
    >>> len(zlib.compress(sample.encode('hex')))
    12537
    >>> len(zlib.compress(sample.encode('ascii85')))
    8212
Had to use Python 2.x to make use of the 'hackercodecs' package that implements ascii85, but looks like it's the best of both worlds, assuming its character set suits whatever medium you are transferring over, and decoding it on the other end doesn't require some slow code.

final edit: I'm guessing it was an accidental trick of the repetitive input data lining up well. On real data hex still wins out (which should have been obvious in hindsight):

    >>> sample = ''.join(sorted(open('/usr/share/dict/words').readlines()))

    >>> len(zlib.compress(sample.encode('ascii85')))
    1320809
    >>> len(zlib.compress(sample.encode('base64')))
    1116678
    >>> len(zlib.compress(sample.encode('hex')))
    880651
Re:Fast base64 encoding and decoding by hackcasual on Thursday January 18, 2018 @02:02PM (#16180187)
Both hex and ascii85 will align at 1024 byte boundaries, base64 will align at 1024*3 bytes, so you'll end up with a symbol stream something like this:

symbol_1, symbol_2, symbol_3, ptr_to_1, ptr_to_2,...

ascii85 performs better than hex simply because it's dictionary is shorter.

If you compress something with a bit more structure, like "Hamlet", you'll get this:

    >>> import urllib.request,zlib,codecs,base64
    >>> hamlet = urllib.request.urlopen("http://www.gutenberg.org/cache/epub/2265/pg2265.txt").read()
    >>> len(codecs.encode(hamlet, 'base64'))
    248577
    >>> len(codecs.encode(hamlet, 'hex'))
    368018
    >>> len(base64.a85encode(hamlet))
    230012
    >>> len(zlib.compress(codecs.encode(hamlet, 'base64')))
    102788
    >>> len(zlib.compress(codecs.encode(hamlet, 'hex')))
    88827
    >>> len(zlib.compress(base64.a85encode(hamlet)))
    121364
Re:Fast base64 encoding and decoding by jwilk on Thursday January 18, 2018 @06:32AM (#16176319)
FWIW, Python (≥ 3.4) has an ascii85 implementation in the standard library:

    >>> import base64
    >>> base64.a85encode(b'spam')
    b'F)YQ)'
https://docs.python.org/3/library/base64.html#base64.a85enco...
Re:Fast base64 encoding and decoding by andreareina on Wednesday January 17, 2018 @07:41PM (#16173587)
Huh, my results are drastically different:

    $ dd if=/dev/urandom bs=512 count=2048 | base64 | gzip | wc
    ...
    4088   31928 1059085

    $ dd if=/dev/urandom bs=512 count=2048 | xxd -p | gzip | wc    ...
    5019   33798 1231268
1 megabyte of random data consistently results in ~1 megabyte of compressed base64 text, ~1.2 megabytes of compressed hex.
Re:Fast base64 encoding and decoding by Twirrim on Wednesday January 17, 2018 @09:19PM (#16174110)
Repeating the exercise using a photograph (https://imgur.com/B4tqkrZ):

    $ pv lock-your-screen.png | base64 | gzip | wc
     2.1MiB 0:00:00 [  13MiB/s] [================================>] 100%
       8641   48904 2264151


    $ pv lock-your-screen.png | xxd -p | gzip | wc
     2.1MiB 0:00:00 [4.41MiB/s] [================================>] 100%
      10109   49956 2573293

See the same against the jpg version (I've no idea why I have kept both a jpg and png of the same image around, especially given jpg is much better suited format):

    $ pv lock-your-screen.jpg | base64 | gzip | wc
     377KiB 0:00:00 [19.2MiB/s] [================================>] 100%
       1420    8373  392796


    $ pv lock-your-screen.jpg | xxd -p | gzip | wc
     377KiB 0:00:00 [9.36MiB/s] [================================>] 100%
       1487    8935  441077
In both cases base64 is both faster and compresses smaller.
Re:Fast base64 encoding and decoding by BeeOnRope on Thursday January 18, 2018 @12:08AM (#16174850)
This test isn't very informative because both .png and .jpg are already compressed formats, with "better than gzip" strength so gzip/deflate isn't going to be able to compress the underlying data.

You only see some compression because gzip is just backing out some of the redundancy added by the hex or base64 encoding, and the way the huffman coding works favors base64 slightly.

Try with uncompressed data and you'll get a different result.

Your speed comparison seems disingenuous: you are benchmarking "xxd", a generalized hex dump tool, against base64, a dedicated base-64 library. I wouldn't expect their speeds to have any interesting relationship with best possible speed of a tuned algorithm.

There is little doubt that base-16 encoding is going to be very fast, and trivially vectorizable (in a much simpler way than base-64).

Re:Fast base64 encoding and decoding by dnet on Thursday January 18, 2018 @04:01AM (#16175691)
> both .png and .jpg are already compressed formats, with "better than gzip" strength

FWIW, PNG and gzip both use the DEFLATE algorithm, so I wouldn't call PNG's compression "better than gzip".

Source: https://en.wikipedia.org/wiki/DEFLATE

> This has led to its widespread use, for example in gzip compressed files, PNG image files and the ZIP file format for which Katz originally designed it.

Re:Fast base64 encoding and decoding by BeeOnRope on Thursday January 18, 2018 @05:55PM (#16182396)
Like any domain-specific algorithms PNG uses deflate as a final step after using image-specific filters which take advantage of typical 2D features. So in general png will do much better than gzip on image data, but it will generally always do at least as well (perhaps I should have said that originally). In particular, the worse case .png compression (e.g., if you pass it random data, or text or something) is to use the "no op" filter followed by the usual deflate compression, which will end up right around plain gzip.

Now at least as good is enough for my point: by compressing a .png file with gzip you aren't going to see additional compression in general. When compressing a base-64 or hex encoding .png file, the additional compression you see is largely only a result of removing the redundancy of the encoding, not any compression of the underlying image.

Re:Fast base64 encoding and decoding by BeeOnRope on Thursday January 18, 2018 @08:04PM (#16183208)
Ooops, that should read "Like many domain-specific algorithms" not "Like any ..."
Re:Fast base64 encoding and decoding by _wmd on Wednesday January 17, 2018 @07:44PM (#16173609)
My data wasn't quite random! It repeats every 1kb, much smaller than zlib's window size (which is I think 16kb)
Re:Fast base64 encoding and decoding by nkurz on Wednesday January 17, 2018 @09:16PM (#16174095)
A good rule-of-thumb might be that if your results show that you able to consistently compress supposedly random data to less than the size required for just the random binary bits, you should either recheck your numbers, verify your random number generator, or quickly file for a patent!
Re:Fast base64 encoding and decoding by jmiserez on Thursday January 18, 2018 @04:24AM (#16175785)
You should add googling “Shannon” “entropy” and “information theory” to that list ;-)
Re:Fast base64 encoding and decoding by jmiserez on Thursday January 18, 2018 @04:09AM (#16175718)
Try with (much) more data, theoretically they should even out at some point.