用于识别具有散列的字符串匹配并且没有误报的算法

时间:2015-01-18 02:08:11

标签: c++ string algorithm hash

我需要找到一个给定的字符串是否匹配列表中的字符串而没有列表中的字符串;基本上我需要散列字符串并仅匹配哈希列表。问题是确保没有误报,因此只能找到完全匹配,并且找不到任何其他字符集。这对于实际的字符串列表来说当然很容易,即使简单的二进制搜索也可以工作,但我想要一种在没有实际字符存在的情况下工作的算法(即预先计算)。布隆过滤器不保证某些任意字符集可能不匹配。

更新:这类似于仅存储密码哈希,然后对输入的密码进行哈希处理,然后将其与哈希列表进行比较,以查看密码是否是其中之一(不可否认通常不使用密码)。这个要求的原因是不必发送实际文本,只需要发送哈希值。

更新2:如果没有完美的哈希函数,有没有其他方法可以做到这一点?我有成千上万的条目,找到一个完美的哈希很难。也许类似于布隆过滤器,但有更好的保证?

4 个答案:

答案 0 :(得分:1)

良好的加密散列函数(具有足够的位)将使得错误匹配的概率极小;足够小,暴力攻击基本上是不可能的。大多数安全系统都认为这种机制是充分的。

如果您希望绝对保证不会出现误报,那么您实际上需要包含足够的数据来验证输入;它不能比目标字符串短(但它不必更大)。实际上,您需要加密目标字符串。由于加密密钥和加密字符串都是可见的,为了避免有人简单地解密加密字符串,您需要使用asymmetric cipher。这些计算成本很高,但这对您的环境来说可能不是问题。

答案 1 :(得分:0)

任何完美的哈希都可以。用字符串比较跟进,以确认它不是误报。

答案 2 :(得分:0)

这是一个“几乎完美”的散列算法:

MPQ Hash

它用于星际争霸保存文件。该算法非常有效,并且具有非常低的碰撞可能性(平均约为1:18889465931478580854784)。

以下是此算法的工作原理。

  

1.计算三个哈希值(偏移哈希值和两个哈希值)并将它们存储在变量中。

     

2.移动到偏移哈希的条目

     

3.该条目是否未使用?如果是这样,请停止搜索并返回“找不到文件”。

     

4.两个检查哈希值是否与我们要查找的文件的哈希值相匹配?如果是,请停止搜索并返回当前条目。

     

5.移动到列表中的下一个条目,如果我们在最后一个条目中,则回到开头。

     

6.我们刚刚移动的条目与偏移哈希相同(我们是否查看了整个哈希表?)?如果是这样,请停止搜索并返回“找不到文件”。

     

7.回到第3步。

这是散列和散列表函数:

unsigned long HashString(char *lpszFileName, unsigned long dwHashType)
{
    //lpszFileName is the string to be hashed.
    //dwHashType will change the hash value according to hash mode.
    //You can see how it's used in the beginning of GetHashTablePos().
    unsigned char *key = (unsigned char *)lpszFileName;
    unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
    int ch;

    while(*key != 0)
    {
        ch = toupper(*key++);   //Convert every character to upper case.
        //dwHashType will change the hash value in different hashing modes.
        //(Whether to calculate the position or to verify.)
        seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
    }
    return seed1;
}

int GetHashTablePos(char *lpszString, MPQHASHTABLE *lpTable, int nTableSize)
{
    const int HASH_OFFSET = 0, HASH_A = 1, HASH_B = 2;
    //nHash controls where the hash value of the string should be stored in the hash table.
    //nHashA and nHashB are used for verifying the match
    int nHash = HashString(lpszString, HASH_OFFSET), 
        nHashA = HashString(lpszString, HASH_A), 
        nHashB = HashString(lpszString, HASH_B), 
        nHashStart = nHash % nTableSize, nHashPos = nHashStart;

    while (lpTable[nHashPos].bExists)
    {
        if (lpTable[nHashPos].nHashA == nHashA && lpTable[nHashPos].nHashB == nHashB)
            return nHashPos;   //If found, return the entry index
        else
            nHashPos = (nHashPos + 1) % nTableSize;   //Not found, move to next position

        if (nHashPos == nHashStart)
            break;  //Reach the beginning of table, stop searching.
    }

    return -1; //Error value
}

答案 3 :(得分:0)

您可以考虑整理一个bloom filter。这基本上是一组散列算法和散列表,当作为一组时,可以给出非常高的正确匹配概率。它不是100%,但你可以随心所欲地接近它。