-5

I am looking for some way to "digest" a string, but always return the same 32 (or 64) byte long value (as a hex string or plain characters). Something like the following code does:

std::string digest(const std::string& input)
{
    std::string result = "";
    // do something with the input string, update result accordingly
    return result;
}

and a little bit more details: I want exactly the opposite of what a classical digest function does which is that for each different string it returns a different but always the same (1 to 1) value. I want a function which for each string returns every time the same value (n to 1).

Obviously, "easy" solutions as return the same constant result every time are not considered a solution :) The code should actually digest the input string and build up the result as a result of the operation.

And an example:

 digest ("fox") == digest ("whale")

should be true.

Or mathematically speaking:

for ∀ a and b if a != b => digest (a) == digest(b). That is why i called this anti-digest.

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • Have you tried the SHA family or MD5 crypto algorithm? – Thomas Matthews Sep 15 '14 at 19:16
  • No, they are real digest functions. If you feed them with different strings they return a different value. I want something that always returns the same for different strings. – Ferenc Deak Sep 15 '14 at 19:25
  • 4
    *I want something that always returns the same for different strings*, [XKCD 221 - Random Number](http://www.xkcd.com/221/) should cover it then. – Elliott Frisch Sep 15 '14 at 19:26
  • I still don't understand the amount of downvotes :( ... this is a real life scenario used for unit tests... – Ferenc Deak Sep 16 '14 at 08:41
  • Your function *must be* a constant. How can it be anything else? Just because it's "real life" doesn't mean it is exempt from the laws of physics or mathematics. – President James K. Polk Sep 16 '14 at 22:30

2 Answers2

3

A long mathematical demonstration

Your requirement is:

a!=b  =>   digest(a)==digest(b)

Let's take another message any other message c, and suppose it's different from a and b:

a!=c  =>  digest(a)==digest(c)  
b!=c  =>  digest(b)==digest(c) 

From this you see that the digest will be constant for any c unless it is equal to a or b.

Now take another message x whatever it may be:

c!=x  => digest(c)==digest(x)

By contraposing this implication, this is equivalent to :

digest(x)!=digest(c) => c==x

So suppose there would be an x with a digest different from the constant digest(c). The we have:

digest(x)!=digest(c) and digest(x)!=digest(a)
=>  x==c  and x==a 
=>  c==a  
=>  digest(c)!=digest(a)

But this contradict out original hypothesis about a, c, digest(a) and digest(c), so there can't be such an x. So you can conclude that your digest MUST BE a strictly constant function.

Now suppose your function would not be constant:

digest(x)!=digest(a) =>  x==a  

but if digest is a function, it will always return the same result for the same input, meaning that x==a => digest(x) ==digest(a). This demonstrates that there is no other solution than a constant function.

In short and in C++

A function will return the same result for the same parameter, unless there are side effet (static variable or whatever). Your requirement of having same result for different values, but different result for same values is simply not feasible in a function with only one parameter.

Christophe
  • 68,716
  • 7
  • 72
  • 138
-1

It seems, I was somehow unclear on what I want to achieve ...

Anyway, I came up with the following:

static const size_t DIGEST_SIZE = 32;
std::string antiDigest(const std::string& a)
{
    if(a.empty()) { throw "cannot digest empty string"; }
    char r[DIGEST_SIZE ] = {0};
    int block_size = std::min(DIGEST_SIZE, a.length());
    int block_count = 1 + DIGEST_SIZE / a.length();
    for(int i=0; i<block_size; i++)
    {
        int hlp = 0, bc = 0;

        while(bc < block_count)
        {
            int idx = i + bc * block_size;
            if(idx >= a.length()) break;
            hlp += a[idx];
            bc ++;
        }
        hlp = (int)(hlp << 3) + hlp;
        unsigned int hlp2 = 0;
        while(hlp)
        {
            int t = hlp - ((hlp/10) * 10);
            hlp2 += t;
            hlp /= 10;
        }
        bc = 0;
        while(bc < block_count)
        {
            int idx = i + bc * block_size;
            if(idx >= DIGEST_SIZE) break;
            r[idx] = ( (hlp2 / 10) + (hlp2-(hlp2/10)*10)) ;    
            bc++;
        }
    }

    std::stringstream result; 
    for(int i=0; i<DIGEST_SIZE; i++)
    {
        result << int_to_hex(r[i]) ;
    }
    return result.str();
}

On ideone: http://ideone.com/t4dibL

Obviously, this can be obfuscated even more with replacing the mathematical operations with bitwise operations, but for a proof of concept this does it.

Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167