Каков наилучший способ хеширования этой сложной структуры в VB6? - PullRequest
0 голосов
/ 21 сентября 2009

У меня определены следующие структуры (имена анонимны, но типы данных верны):

Public Type ExampleDataItem
    Limit As Integer    ' could be any value 0-999
    Status As Integer   ' could be any value 0-2
    ValidUntil As Date  ' always a valid date
End Type

Public Type ExampleData
    Name As String      ' could be 5-20 chars long
    ValidOn As Date     ' could be valid date or 1899-12-30 representing "null"
    Salt As Integer     ' random value 42-32767
    Items(0 To 13) As ExampleDataItem
End Type

Я хотел бы сгенерировать 32-битный хэш-код для экземпляра ExampleData. Важно минимизировать коллизии хешей, производительность и порядок данных не важны.

Пока у меня есть (в псевдокоде):

  1. Сериализация всех членов в один байтовый массив.
  2. Перебрать массив байтов, считывая 4 байта за раз в Long значение.
  3. XOR все значения Long вместе.

Я не могу опубликовать свой код, потому что он сильно зависит от служебных классов для выполнения сериализации, но если кто-то захочет увидеть его независимо от этого, я опубликую его.

Будет ли это нормально, или кто-нибудь может предложить лучший способ сделать это?

EDIT:

Этот код используется для реализации части системы лицензирования программного обеспечения. Цель хэша - подтвердить, совпадают ли данные, введенные конечным пользователем, с данными, введенными специалистом технической поддержки. Следовательно, хеш должен:

  1. Будь очень коротким. Вот почему я подумал, что 32 бита будут наиболее подходящими, потому что они могут быть представлены как 10-значное десятичное число на экране. Это легко, быстро и однозначно прочитать по телефону и набрать.
  2. Получается из всех полей в структуре данных, без каких-либо дополнительных искусственных ключей или других хитростей.

Хеш не требуется для поиска, тестирования уникальности или для хранения ExampleData экземпляров в любом виде коллекции, но только для одной цели, описанной выше.

Ответы [ 4 ]

3 голосов
/ 22 сентября 2009

Можете ли вы использовать CRC32? У Стива МакМахона есть реализация . Добавьте к этому немного кодировки base32 , и вы получите достаточно короткое, чтобы читать по телефону.

0 голосов
/ 21 сентября 2009

РЕДАКТИРОВАТЬ: вопрос был отредактирован, чтобы уточнить, что цель состоит в обнаружении ошибок печати, а не минимизации коллизий между совершенно разными значениями. В этом случае ответ Дана Ф. является лучшим, ИМХО, а не мое предложение ниже (хотя это замечательно).


Вы можете использовать Microsoft CryptoAPI вместо использования собственного алгоритма хеширования.

  • Например, , эта статья Microsoft об использовании CryptoAPI из VB6 должна помочь вам начать работу.
  • Или это от Edanmo на mvps.org для хеширования строки в VB6.

РЕДАКТИРОВАТЬ: следующий комментарий. Если вы настаиваете на 32-битном значении, будет трудно минимизировать коллизии хешей. Моя книга по алгоритму предлагает использовать метод Хорнера в качестве достойного алгоритма хеширования общего назначения. У меня сейчас нет времени, чтобы узнать больше информации и внедрить в VB6. CopyMemory , вероятно, было бы полезно:)

0 голосов
/ 22 сентября 2009

Учитывая, что производительность не является целью, если размер файла не важен, и вы хотите уникальное значение для каждого элемента. Просто добавьте поле ID. Это тип данных является строкой. Затем используйте эту функцию для генерации GUID. Это будет уникальный идентификатор. Используйте его как ключ для диктонары или коллекции.

Public Type GUID
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(7) As Byte
End Type

Public Type GUID2              '15 BYTES TOTAL
    Data1(14) As Byte
End Type

Public Declare Function CoCreateGuid Lib "OLE32.DLL" (pGuid As GUID) As Long

Public Function GetGUID() As String
    Dim VBRIG_PROC_ID_STRING As String
    VBRIG_PROC_ID_STRING = "GetGUID()"

    Dim lResult As Long
    Dim lguid As GUID
    Dim MyguidString As String
    Dim MyGuidString1 As String
    Dim MyGuidString2 As String
    Dim MyGuidString3 As String
    Dim DataLen As Integer
    Dim StringLen As Integer
    Dim i As Integer
    On Error GoTo error_olemsg
    lResult = CoCreateGuid(lguid)
    If lResult = 0 Then
        MyGuidString1 = Hex$(lguid.Data1)
        StringLen = Len(MyGuidString1)
        DataLen = Len(lguid.Data1)
        MyGuidString1 = LeadingZeros(2 * DataLen, StringLen) & MyGuidString1
        'First 4 bytes (8 hex digits)
        MyGuidString2 = Hex$(lguid.Data2)
        StringLen = Len(MyGuidString2)
        DataLen = Len(lguid.Data2)
        MyGuidString2 = LeadingZeros(2 * DataLen, StringLen) & Trim$(MyGuidString2)
        'Next 2 bytes (4 hex digits)
        MyGuidString3 = Hex$(lguid.Data3)
        StringLen = Len(MyGuidString3)
        DataLen = Len(lguid.Data3)
        MyGuidString3 = LeadingZeros(2 * DataLen, StringLen) & Trim$(MyGuidString3)
        'Next 2 bytes (4 hex digits)
        GetGUID = MyGuidString1 & MyGuidString2 & MyGuidString3
        For i = 0 To 7
            MyguidString = MyguidString & Format$(Hex$(lguid.Data4(i)), "00")
        Next i
        'MyGuidString contains last 8 bytes of Guid (16 hex digits)
        GetGUID = GetGUID & MyguidString
    Else
        GetGUID = "00000000" ' return zeros if function unsuccessful
    End If
    Exit Function
error_olemsg:
    GetGUID = "00000000"
    Exit Function
End Function

Public Function LeadingZeros(ExpectedLen As Integer, ActualLen As Integer) As String
    LeadingZeros = String$(ExpectedLen - ActualLen, "0")
End Function
0 голосов
/ 21 сентября 2009

Возможно, вы слишком обдумали это, или я не понимаю проблему. По сути, вы можете просто хэш (CStr (Salt) + Name + CStr (ValidOn) + Anyotherstrings).

Нет особой необходимости проходить процесс сериализации в байтовый массив и значения XORing. Infact XOR значения вместе таким образом, скорее всего, создаст хэш-коллизии, где вы не намерены их.

Редактировать: Кажется, теперь я понимаю. Вы создаете свое собственное хеш-значение, объединяя данные в XOR? Это, к сожалению, вполне может привести к столкновениям. Я знаю, что VB6 не содержит никаких алгоритмов хэширования, поэтому вам лучше всего импортировать и использовать что-то вроде реализации SHA256 Фила Фресле .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...