这是计算fletcher64校验和的正确方法吗?

时间:2012-03-01 17:47:27

标签: c checksum reliability

fletcher16源代码在wikipedia上这样给出。

uint16_t Fletcher16( uint8_t* data, int count )
{
   uint16_t sum1 = 0;
   uint16_t sum2 = 0;
   int index;

   for( index = 0; index < count; ++index )
   {
      sum1 = (sum1 + data[index]) % 255;
      sum2 = (sum2 + sum1) % 255;
   }

   return (sum2 << 8) | sum1;
}

从该示例中,我实现了64位版本,如下所示。

unsigned long Fletcher64( unsigned int* data, int count )
{
   unsigned long sum1 = 0;
   unsigned long sum2 = 0;
   int index;

   for( index = 0; index < count; ++index )
   {
      sum1 = (sum1 + data[index]) % UINT_MAX; // UINT_MAX = 2^32
      sum2 = (sum2 + sum1) % UINT_MAX;
   }

   return (sum2 << 32) | sum1;
}

我的方法是正确的,还是我做错了什么?

3 个答案:

答案 0 :(得分:2)

大多数哈希算法采用内存块的参数和哈希的字节数(有时是位数)。您已将字节数更改为字数 - 这是一个相当重要的更改。

此外,由于您更改了计算大小,因此计算sum2的方式已更改。只要您没有尝试复制原始算法的每值值,这很好,但如果这是一个兼容的优化,那么这可能是错误的。

答案 1 :(得分:0)

这是错的。您将丢失0-3个字节的尾随数据,因为您只是在汇总数据中的DWORD,但可能仍有一些字节,具体取决于数据大小。我建议这些implementations

javax.servlet.ServletException: javax.servlet.ServletException: java.lang.NoClassDefFoundError: org/apache/commons/lang/UnhandledException
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:515)
    org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:419)

将尾随字节考虑在内。 fletcher64_A是最终实现,flechter64_B执行Mecki所描述的模数。您可以看到两个实现都生成相同的值(它们没有。请参阅编辑)。

编辑#1: 正如Thomas Tempelmann评论的那样,这不太正确。将尝试在某个时刻修复算法。 您可以检查fletcher算法中的求和何时溢出here。这或多或少与维基百科条目所说的相符。

编辑#2:编辑#2: 我在这里使用模板化的naiive和优化算法进行了测试。使用“g ++ -std = c ++ 11 -O2 -Wall -pedantic test.cpp&amp;&amp; ./a.out”编译并运行它。需要注意的是32位版本正在运行,但不是16位和64位版本。如果您发现错误并发表评论,我将不胜感激。 @Thomas Tempelmann:优化版本在我的电脑上快了大约6倍!

#include <iostream>
#include <inttypes.h>

uint64_t fletcher64_A(const uint8_t * data, uint64_t count)
{
    // calculate how many full double words the input has
    uint64_t dwords = count / 4;
    // now calculate the flechter-64 checksum from double words
    uint64_t sum1 = 0;
    uint64_t sum2 = 0;
    const uint32_t * data32 = reinterpret_cast<const uint32_t*>(data);
    for (uint64_t index = 0; index < dwords; ++index) 
    {
        sum1 = (sum1 + data32[index]) % UINT32_MAX;
        sum2 = (sum2 + sum1) % UINT32_MAX;
    }
    // calculate how many extra bytes, that do not fit into a double word, the input has
    uint64_t remainingBytes = count - dwords * 4;
    if (remainingBytes > 0)
    {
        // copy the excess bytes to our dummy variable. you could use memcpy here...
        uint32_t dummy = 0;
        for (uint64_t index = 0; index < remainingBytes; ++index)
        {
            reinterpret_cast<uint8_t*>(&dummy)[index] = data[dwords * 4 + index];
        }
        // now add the dummy on top
        sum1 = (sum1 + dummy) % UINT32_MAX;
        sum2 = (sum2 + sum1) % UINT32_MAX;
    }
    // build final checksum
    return (sum2 << 32) | sum1;
}

uint64_t fletcher64_B(const uint8_t * data, uint64_t count)
{
    // calculate how many full double words the input has
    uint64_t dwords = count / 4;
    // now calculate the flechter-64 checksum from double words
    uint32_t sum1 = 0;
    uint32_t sum2 = 0;
    const uint32_t * data32 = reinterpret_cast<const uint32_t*>(data);
    for (uint64_t index = 0; index < dwords; ++index) 
    {
        sum1 += data32[index];
        sum2 += sum1;
    }
    // calculate how many extra bytes, that do not fit into a double word, the input has
    uint64_t remainingBytes = count - dwords * 4;
    if (remainingBytes > 0)
    {
        // copy the excess bytes to our dummy variable. you could use memcpy here...
        uint32_t dummy = 0;
        for (uint64_t index = 0; index < remainingBytes; ++index)
        {
            reinterpret_cast<uint8_t*>(&dummy)[index] = data[dwords * 4 + index];
        }
        // now add the dummy on top
        sum1 += dummy;
        sum2 += sum1;
    }
    // build final checksum
    return ((uint64_t)sum2 << 32) | sum1;
}

int main() {
    const std::string data = "abcdefghijklmnopqrstuvwxyz0123456789helloworld!";
    uint64_t ca = fletcher64_A(reinterpret_cast<const uint8_t*>(data.data()), data.size());
    uint64_t cb = fletcher64_B(reinterpret_cast<const uint8_t*>(data.data()), data.size());
    std::cout << "String size: " << data.size() << ", checksum a: 0x" << std::hex << ca << ", checksum b: 0x" << cb << std::endl;
    return 0;
}

答案 2 :(得分:-1)

是的,它似乎是正确的,但请务必进行测试。