osu-crypto / libPSI

A repository for private set intersection.
Other
168 stars 47 forks source link

The collision handling code in KkrtPsiSender seems not working. #57

Closed cmZoO closed 1 year ago

cmZoO commented 1 year ago

The cuckoo hash of KKRT needs to produce 3 hash locations for each input, these locations may collide. So, the function hashItems of KkrtPsiSender contains some codes for dealing the collisions. The dealing logic is as follows. If the itemIdx input got a collision, then the position perm[itemIdx] of the array myMaskBuff will fill with junk data.

// if we got a collision, then fill the final mask locations with junk data
prngs[0].get(masks.data() + (perm[itemIdx0] * mNumHashFunctions + 1) * masks.stride(), c01 * masks.stride());
prngs[1].get(masks.data() + (perm[itemIdx1] * mNumHashFunctions + 1) * masks.stride(), c11 * masks.stride());
prngs[2].get(masks.data() + (perm[itemIdx2] * mNumHashFunctions + 1) * masks.stride(), c21 * masks.stride());
prngs[3].get(masks.data() + (perm[itemIdx3] * mNumHashFunctions + 1) * masks.stride(), c31 * masks.stride());
prngs[4].get(masks.data() + (perm[itemIdx4] * mNumHashFunctions + 1) * masks.stride(), c41 * masks.stride());
prngs[5].get(masks.data() + (perm[itemIdx5] * mNumHashFunctions + 1) * masks.stride(), c51 * masks.stride());
prngs[6].get(masks.data() + (perm[itemIdx6] * mNumHashFunctions + 1) * masks.stride(), c61 * masks.stride());
prngs[7].get(masks.data() + (perm[itemIdx7] * mNumHashFunctions + 1) * masks.stride(), c71 * masks.stride());

However, ignoring the syntax mistake that the hashItems has not used the correct c02~c72, these codes for dealing with collisions seem still not working.

The reason is that during the encoding part, the encoding codes as follow will try to encode the inputIdx = mPermute[i] input into location i of array myMaskBuff.

// lets check a random item to see if it can be encoded. If so,
// we will write this item's encodings in the myMaskBuff at position i.
auto inputIdx = mPermute[i];

// for each hash function, try to encode the item.
for (u64 h = 0; h < mParams.mNumHashes; ++h)
{
    auto& bIdx = binIdxs(inputIdx, h);

    // if the bin index is less than r, then we have received
    // the correction and can encode it
    if (bIdx < r)
    {
        // write the encoding into myMaskBuff at position  i, h
        auto encoding = myMaskBuff.data() + (i * mParams.mNumHashes + h) * myMaskBuff.stride();
        mOtSender->encode(bIdx, &inputs[inputIdx], encoding, myMaskBuff.stride());

        // make this location as already been encoded
        bIdx = -1;
    }
}

This permutation logic of encoding is different from the permutation logic used to fill junk data in hashItems, one is using perm[itemIdx](itemIdx is index of input) and the other is using mPermute[i](i is the current location of myMaskBuff), and will result in the junk data being rewritten while the actual location of the collision will not be filled.

Here is a toy example

We also run a test using command line ./frontend.exe -kkrt -n 1000000, and following is our observation.

Overall, because the collision handling code in hashItems places the junk data in the wrong position, and the encoding part ignores the collisions, the myMaskBuff that send to the receiver contains zero values, which might leak the information of collisions.

ladnir commented 1 year ago

fixed. Thanks for finding this...

It now computes the inverse permutation https://github.com/osu-crypto/libPSI/blob/master/libPSI/PSI/Kkrt/KkrtPsiSender.cpp#L105

and used that in the hashing code.