Commit d65da2db authored by Rusty Russell's avatar Rusty Russell

Much nicer example: genetic algo to approximate jpeg

(And cute image!)
parent 3fb9ac93
CFLAGS=-g -Wall -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -I../../..
CFLAGS=-g -O3 -Wall -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -I../../..
all: find_md5 md5_worker dns_lookup
find_md5: md5_server.c ../../../libccan.a
$(CC) $(CFLAGS) -o $@ $^
md5_worker: md5_worker.c ../../../libccan.a
$(CC) $(CFLAGS) -o $@ $^
all: dns_lookup
dns_lookup: dns_lookup.c ../../../libccan.a
$(CC) $(CFLAGS) -o $@ $^
$(CC) $(CFLAGS) -o $@ $^
arabella: arabella.c ../../../libccan.a
$(CC) $(CFLAGS) -o $@ $^ -ljpeg -lm
This diff is collapsed.
/* Tries to find data with a given MD5 (up to N bits). */
#include "ccan/antithread/antithread.h"
#include "ccan/string/string.h"
#include "ccan/talloc/talloc.h"
#include "md5_finder.h"
#include <err.h>
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
static void usage(void)
{
errx(1, "Usage: md5calc <hexstring> <numcpus>");
}
static void parse_hexstring(const char *string, struct md5_search *md5s)
{
unsigned int i;
if (strstarts(string, "0x") || strstarts(string, "0X"))
string += 2;
for (i = 0; i < MD5_HASH_WORDS; i++) {
unsigned int n[4], j;
int ret;
ret = sscanf(string, "%02x%02x%02x%02x",
&n[0], &n[1], &n[2], &n[3]);
string += 8;
if (ret == EOF)
break;
for (j = 0; j < ret; j++) {
md5s->mask[MD5_HASH_WORDS-i-1] |= (0xFF << (8*j));
md5s->md5[MD5_HASH_WORDS-i-1] |= (n[j] << (8*j));
}
if (ret != 4)
break;
}
}
static void init_pattern(u8 *pattern, unsigned int num_bytes, u64 total)
{
unsigned int i;
for (i = 0; i < num_bytes; i++) {
pattern[i] = 'A' + (total % 26);
total /= 26;
}
}
#define PATTERN_BYTES 32
int main(int argc, char *argv[])
{
struct at_pool *atp;
struct md5_search md5s;
unsigned int i, maxfd, numathreads = argc == 3 ? atoi(argv[2]) : 0;
u64 total = 0;
fd_set fds;
char *cmdline[] = { "./md5_worker", NULL };
struct athread *at[numathreads];
if (numathreads == 0)
usage();
memset(&md5s, 0, sizeof(md5s));
parse_hexstring(argv[1], &md5s);
md5s.num_tries = 1024*1024;
md5s.num_bytes = PATTERN_BYTES;
/* *2 to allow for allocation inefficiency. */
atp = at_pool((sizeof(md5s) + PATTERN_BYTES) * (numathreads + 1) * 2);
if (!atp)
err(1, "Can't create pool");
/* Free pool on exit. */
// talloc_steal(talloc_autofree_context(), atp);
FD_ZERO(&fds);
maxfd = 0;
for (i = 0; i < numathreads; i++) {
at[i] = at_spawn(atp, NULL, cmdline);
if (!at[i])
err(1, "Can't spawn child");
FD_SET(at_fd(at[i]), &fds);
if (at_fd(at[i]) > maxfd)
maxfd = at_fd(at[i]);
}
for (;;) {
struct md5_search *m, *res;
fd_set in = fds;
/* Shouldn't fail! */
m = talloc(at_pool_ctx(atp), struct md5_search);
*m = md5s;
md5s.num_tries++;
m->pattern = talloc_array(m, u8, m->num_bytes);
init_pattern(m->pattern, m->num_bytes, total);
select(maxfd+1, &in, NULL, NULL, NULL);
for (i = 0; i < numathreads; i++)
if (FD_ISSET(at_fd(at[i]), &in))
break;
if (i == numathreads)
errx(1, "Select returned, but noone ready?");
res = at_read(at[i]);
if (res == NULL) {
warn("Thread died?");
FD_CLR(at_fd(at[i]), &fds);
continue;
}
if (res != INITIAL_POINTER) {
if (res->success) {
printf("Success! '%.*s'\n",
res->num_bytes, (char *)res->pattern);
exit(0);
}
m->num_tries++;
talloc_free(res);
}
at_tell(at[i], m);
total += m->num_tries;
}
}
/* Worker thread: tries to find data with given MD5. */
#include "ccan/antithread/antithread.h"
#include "md5_finder.h"
#include <netinet/in.h>
#include <err.h>
#include <string.h>
/*
* Cryptographic API.
*
* MD5 Message Digest Algorithm (RFC1321).
*
* Derived from cryptoapi implementation, originally based on the
* public domain implementation written by Colin Plumb in 1993.
*
* Copyright (c) Cryptoapi developers.
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#define MD5_DIGEST_SIZE 16
#define MD5_HMAC_BLOCK_SIZE 64
#define MD5_BLOCK_WORDS 16
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
#define MD5STEP(f, w, x, y, z, in, s) \
(w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
struct md5_ctx {
u32 hash[MD5_HASH_WORDS];
u32 block[MD5_BLOCK_WORDS];
u64 byte_count;
};
static void md5_transform(u32 *hash, u32 const *in)
{
u32 a, b, c, d;
a = hash[0];
b = hash[1];
c = hash[2];
d = hash[3];
MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
hash[0] += a;
hash[1] += b;
hash[2] += c;
hash[3] += d;
}
/* XXX: this stuff can be optimized */
static inline void le32_to_cpu_array(u32 *buf, unsigned int words)
{
while (words--) {
*buf = ntohl(*buf);
buf++;
}
}
static inline void cpu_to_le32_array(u32 *buf, unsigned int words)
{
while (words--) {
*buf = htonl(*buf);
buf++;
}
}
static inline void md5_transform_helper(struct md5_ctx *ctx)
{
le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32));
md5_transform(ctx->hash, ctx->block);
}
static void md5_init(struct md5_ctx *mctx)
{
mctx->hash[0] = 0x67452301;
mctx->hash[1] = 0xefcdab89;
mctx->hash[2] = 0x98badcfe;
mctx->hash[3] = 0x10325476;
mctx->byte_count = 0;
}
static void md5_update(struct md5_ctx *mctx, const u8 *data, unsigned int len)
{
const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
mctx->byte_count += len;
if (avail > len) {
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
data, len);
return;
}
memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
data, avail);
md5_transform_helper(mctx);
data += avail;
len -= avail;
while (len >= sizeof(mctx->block)) {
memcpy(mctx->block, data, sizeof(mctx->block));
md5_transform_helper(mctx);
data += sizeof(mctx->block);
len -= sizeof(mctx->block);
}
memcpy(mctx->block, data, len);
}
static void md5_final(struct md5_ctx *mctx)
{
const unsigned int offset = mctx->byte_count & 0x3f;
char *p = (char *)mctx->block + offset;
int padding = 56 - (offset + 1);
*p++ = 0x80;
if (padding < 0) {
memset(p, 0x00, padding + sizeof (u64));
md5_transform_helper(mctx);
p = (char *)mctx->block;
padding = 56;
}
memset(p, 0, padding);
mctx->block[14] = mctx->byte_count << 3;
mctx->block[15] = mctx->byte_count >> 29;
le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
sizeof(u64)) / sizeof(u32));
md5_transform(mctx->hash, mctx->block);
cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
}
static bool bits_match(const u32 a[MD5_HASH_WORDS],
const u32 b[MD5_HASH_WORDS],
const u32 mask[MD5_HASH_WORDS])
{
unsigned int i;
for (i = 0; i < MD5_HASH_WORDS; i++) {
if ((a[i] & mask[i]) != (b[i] & mask[i]))
return false;
}
#if 0
printf("mask = %08x%08x%08x%08x\n"
"a = %08x%08x%08x%08x\n"
"b = %08x%08x%08x%08x\n",
mask[0], mask[1], mask[2], mask[3],
a[0], a[1], a[2], a[3],
b[0], b[1], b[2], b[3]);
#endif
return true;
}
static void inc_pattern(u8 *pattern, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++) {
pattern[i]++;
if (pattern[i] <= 'Z')
break;
pattern[i] = 'A';
}
}
int main(int argc, char *argv[])
{
struct at_pool *atp = at_get_pool(&argc, argv, NULL);
struct md5_search *md5s;
if (!atp)
err(1, "Not a worker thread?");
/* Tell parent we're ready. */
at_tell_parent(atp, INITIAL_POINTER);
while ((md5s = at_read_parent(atp)) != NULL) {
unsigned int i;
md5s->success = false;
for (i = 0; i < md5s->num_tries; i++) {
struct md5_ctx ctx;
md5_init(&ctx);
md5_update(&ctx, md5s->pattern, md5s->num_bytes);
md5_final(&ctx);
if (bits_match(ctx.hash, md5s->md5, md5s->mask)) {
md5s->success = true;
break;
}
inc_pattern(md5s->pattern, md5s->num_bytes);
}
at_tell_parent(atp, md5s);
}
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment