用于识别具有哈希且无误报的字符串匹配项的算法

algorithm to identify string matches with hashing and no false positives

本文关键字:字符 字符串 串匹配 算法 识别 哈希且 用于      更新时间:2023-10-16

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

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

更新2:没有完美的哈希函数,有没有另一种方法可以做到这一点?我有数十万个条目,很难找到一个完美的哈希值。也许像布隆过滤器这样的东西,但有更好的保证?

一个好的加密哈希函数(具有足够的位)将使错误匹配的概率非常小;足够小,以至于暴力攻击基本上是不可能的。大多数安全系统认为这种机制是充分的。

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

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

这是一个"近乎完美"的哈希算法:

MPQ 哈希

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

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

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

2.移至偏移哈希的条目

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

两个检查哈希 4.Do 与我们正在寻找的文件的检查哈希匹配?如果是这样,请停止搜索并返回当前条目。

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

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

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
}

您可以考虑将布隆过滤器放在一起。 这基本上是一组哈希算法和哈希表,当它们作为一个组时,可以给出非常高的正确匹配概率。 它不是 100%,但您可以随心所欲地接近它。