# VBForums CodeBank > CodeBank - Visual Basic 6 and earlier >  [VB6/VBA] SipHash cryptographically secure keyed hash function

## wqweto

These *mdSiphash.bas* and *mdHalfSiphash.bas* modules implement SipHash and HalfSipHash high-speed secure pseudorandom function for short messages in pure VB6.

Output size and number of iterations for update and finalize can be set with calls to *CryptoSiphashInit* and *CryptoHalfSiphashInit* respectively while procedures containing SipHash24 in the name are using 2 rounds on updates and 4 rounds on finalize with 8-byte output, while SipHash13 named procedures use 1 round on updates and 3 rounds on finalize with 8-byte output again (can be 16 bytes). For HalfSipHash the output is 4 bytes long by default (can be 8 bytes).

The speed of compiled VB6 code is not very great when using Variants for LongLongs for SipHash but HalfSipHash is specifically designed for 32-bit operations and this results in better performance in VB6:

*SipHash-2-4 - 3.2MB/s, SipHash-1-3 - 6.4MB/s, HalfSipHash-2-4 - 110MB/s, HalfSipHash-1-3 - 240MB/s*
In TwinBASIC the same SipHash imlementation outperforms HalfSipHash in both x86 and x64 configurations, here are x64 compiled results:

*SipHash-2-4 - 156MB/s, SipHash-1-3 - 215MB/s, HalfSipHash-2-4 - 102MB/s, HalfSipHash-1-3 - 147MB/s*


```
'--- mdSiphash.bas
Option Explicit
DefObj A-Z

#Const HasPtrSafe = (VBA7 <> 0)
#Const HasOperators = (TWINBASIC <> 0)

#If HasPtrSafe Then
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function VariantChangeType Lib "oleaut32" (Dest As Variant, Src As Variant, ByVal wFlags As Integer, ByVal vt As VbVarType) As Long
Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long, lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) As Long
#Else
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function VariantChangeType Lib "oleaut32" (Dest As Variant, Src As Variant, ByVal wFlags As Integer, ByVal vt As VbVarType) As Long
Private Declare Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) As Long
#End If

Private Const LNG_BLOCKSZ       As Long = 8
Private Const LNG_KEYSZ         As Long = 16

Public Type CryptoSiphashContext
#If HasPtrSafe Then
    V0                  As LongLong
    V1                  As LongLong
    V2                  As LongLong
    V3                  As LongLong
#Else
    V0                  As Variant
    V1                  As Variant
    V2                  As Variant
    V3                  As Variant
#End If
    Partial(0 To LNG_BLOCKSZ - 1) As Byte
    NPartial            As Long
    NInput              As Currency
    UpdateIters         As Long
    FinalizeIters       As Long
    OutSize             As Long
End Type

#If HasPtrSafe Then
#If Not HasOperators Then
    Private LNG_POW2(0 To 63)       As LongLong
    Private LNG_SIGN_BIT            As LongLong ' 2 ^ 63
#End If
    Private LNG_ZERO                As LongLong
    Private LNG_IV(0 To 3)          As LongLong
#Else
    Private LNG_POW2(0 To 63)       As Variant
    Private LNG_SIGN_BIT            As Variant
    Private LNG_ZERO                As Variant
    Private LNG_IV(0 To 3)          As Variant
#End If

#If Not HasOperators Then
#If HasPtrSafe Then
Private Function RotL64(ByVal lX As LongLong, ByVal lN As Long) As LongLong
#Else
Private Function RotL64(lX As Variant, ByVal lN As Long) As Variant
#End If
    '--- RotL64 = LShift(X, n) Or RShift(X, 64 - n)
    Debug.Assert lN <> 0
    RotL64 = ((lX And (LNG_POW2(63 - lN) - 1)) * LNG_POW2(lN) Or -((lX And LNG_POW2(63 - lN)) <> 0) * LNG_SIGN_BIT) Or _
        ((lX And (LNG_SIGN_BIT Xor -1)) \ LNG_POW2(64 - lN) Or -(lX < 0) * LNG_POW2(lN - 1))
End Function

#If HasPtrSafe Then
Private Function UAdd64(ByVal lX As LongLong, ByVal lY As LongLong) As LongLong
#Else
Private Function UAdd64(lX As Variant, lY As Variant) As Variant
#End If
    If (lX Xor lY) >= 0 Then
        UAdd64 = ((lX Xor LNG_SIGN_BIT) + lY) Xor LNG_SIGN_BIT
    Else
        UAdd64 = lX + lY
    End If
End Function

Private Sub pvCompress(uCtx As CryptoSiphashContext, ByVal lRounds As Long)
    With uCtx
        Do While lRounds > 0
            .V0 = UAdd64(.V0, .V1)
            .V2 = UAdd64(.V2, .V3)
            .V1 = RotL64(.V1, 13)
            .V3 = RotL64(.V3, 16)
            .V1 = .V1 Xor .V0
            .V3 = .V3 Xor .V2
            .V0 = RotL64(.V0, 32)
            
            .V2 = UAdd64(.V2, .V1)
            .V0 = UAdd64(.V0, .V3)
            .V1 = RotL64(.V1, 17)
            .V3 = RotL64(.V3, 21)
            .V1 = .V1 Xor .V2
            .V3 = .V3 Xor .V0
            .V2 = RotL64(.V2, 32)
            lRounds = lRounds - 1
        Loop
    End With
End Sub
#Else
[ IntegerOverflowChecks (False) ]
Private Sub pvCompress(uCtx As CryptoSiphashContext, ByVal lRounds As Long)
    With uCtx
        Do While lRounds > 0
            .V0 += .V1
            .V2 += .V3
            .V1 = (.V1 << 13) Or (.V1 >> 51)
            .V3 = (.V3 << 16) Or (.V3 >> 48)
            .V1 = .V1 Xor .V0
            .V3 = .V3 Xor .V2
            .V0 = (.V0 << 32) Or (.V0 >> 32)
            .V2 += .V1
            .V0 += .V3
            .V1 = (.V1 << 17) Or (.V1 >> 47)
            .V3 = (.V3 << 21) Or (.V3 >> 43)
            .V1 = .V1 Xor .V2
            .V3 = .V3 Xor .V0
            .V2 = (.V2 << 32) Or (.V2 >> 32)
            lRounds -= 1
        Loop
    End With
End Sub
#End If

#If Not HasPtrSafe Then
Private Function CLngLng(vValue As Variant) As Variant
    Const VT_I8 As Long = &H14
    Call VariantChangeType(CLngLng, vValue, 0, VT_I8)
End Function
#End If

Public Sub CryptoSiphashInit(uCtx As CryptoSiphashContext, baKey() As Byte, _
            Optional ByVal UpdateIters As Long = 2, _
            Optional ByVal FinalizeIters As Long = 4, _
            Optional ByVal OutSize As Long = 8)
#If HasPtrSafe Then
    Static K(0 To 1)    As LongLong
#Else
    Static K(0 To 1)    As Variant
#End If
    Dim lIdx            As Long
    
    If LNG_IV(0) = 0 Then
        LNG_IV(0) = CLngLng("&H736f6d6570736575")
        LNG_IV(1) = CLngLng("&H646f72616e646f6d")
        LNG_IV(2) = CLngLng("&H6c7967656e657261")
        LNG_IV(3) = CLngLng("&H7465646279746573")
        LNG_ZERO = CLngLng(0)
        #If Not HasOperators Then
            LNG_POW2(0) = CLngLng(1)
            For lIdx = 1 To 63
                LNG_POW2(lIdx) = CVar(LNG_POW2(lIdx - 1)) * 2
            Next
            LNG_SIGN_BIT = LNG_POW2(63)
        #End If
    End If
    If UBound(baKey) + 1 < LNG_KEYSZ Then
        K(0) = LNG_ZERO: K(1) = LNG_ZERO
        #If HasPtrSafe Then
            If UBound(baKey) >= 0 Then
                Call CopyMemory(K(0), baKey(0), UBound(baKey) + 1)
            End If
        #Else
            lIdx = UBound(baKey) + 1
            If lIdx > 0 Then
                Call CopyMemory(ByVal VarPtr(K(0)) + 8, baKey(0), IIf(lIdx > 8, 8, lIdx))
            End If
            lIdx = UBound(baKey) - 7
            If lIdx > 0 Then
                Call CopyMemory(ByVal VarPtr(K(1)) + 8, baKey(8), lIdx)
            End If
        #End If
    Else
        #If HasPtrSafe Then
            Call CopyMemory(K(0), baKey(0), LNG_KEYSZ)
        #Else
            K(0) = LNG_ZERO: K(1) = LNG_ZERO
            Call CopyMemory(ByVal VarPtr(K(0)) + 8, baKey(0), 8)
            Call CopyMemory(ByVal VarPtr(K(1)) + 8, baKey(8), 8)
        #End If
    End If
    With uCtx
        If OutSize > 8 Then
            lIdx = &HEE
        Else
            lIdx = 0
        End If
        .V0 = LNG_IV(0) Xor K(0)
        .V1 = LNG_IV(1) Xor K(1) Xor lIdx
        .V2 = LNG_IV(2) Xor K(0)
        .V3 = LNG_IV(3) Xor K(1)
        .NPartial = 0
        .NInput = 0
        .UpdateIters = UpdateIters
        .FinalizeIters = FinalizeIters
        .OutSize = OutSize
    End With
End Sub

Public Sub CryptoSiphashUpdate(uCtx As CryptoSiphashContext, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1)
#If HasPtrSafe Then
    Static B            As LongLong
#Else
    Static B            As Variant
#End If
    Dim lIdx            As Long

    With uCtx
        If Size < 0 Then
            Size = UBound(baInput) + 1 - Pos
        End If
        .NInput = .NInput + Size
        If .NPartial > 0 And Size > 0 Then
            lIdx = LNG_BLOCKSZ - .NPartial
            If lIdx > Size Then
                lIdx = Size
            End If
            Call CopyMemory(.Partial(.NPartial), baInput(Pos), lIdx)
            .NPartial = .NPartial + lIdx
            Pos = Pos + lIdx
            Size = Size - lIdx
        End If
        Do While Size > 0 Or .NPartial = LNG_BLOCKSZ
            If .NPartial <> 0 Then
                #If HasPtrSafe Then
                    Call CopyMemory(B, .Partial(0), LNG_BLOCKSZ)
                #Else
                    B = LNG_ZERO
                    Call CopyMemory(ByVal VarPtr(B) + 8, .Partial(0), LNG_BLOCKSZ)
                #End If
                .NPartial = 0
            ElseIf Size >= LNG_BLOCKSZ Then
                #If HasPtrSafe Then
                    Call CopyMemory(B, baInput(Pos), LNG_BLOCKSZ)
                #Else
                    B = LNG_ZERO
                    Call CopyMemory(ByVal VarPtr(B) + 8, baInput(Pos), LNG_BLOCKSZ)
                #End If
                Pos = Pos + LNG_BLOCKSZ
                Size = Size - LNG_BLOCKSZ
            Else
                Call CopyMemory(.Partial(0), baInput(Pos), Size)
                .NPartial = Size
                Exit Do
            End If
            .V3 = .V3 Xor B
            pvCompress uCtx, .UpdateIters
            .V0 = .V0 Xor B
        Loop
    End With
End Sub

Public Sub CryptoSiphashFinalize(uCtx As CryptoSiphashContext, baOutput() As Byte)
#If HasPtrSafe Then
    Static B            As LongLong
#Else
    Static B            As Variant
#End If
    Dim lIdx            As Long
    
    With uCtx
        ReDim baOutput(0 To .OutSize - 1) As Byte
        #If HasOperators Then
            B = CLngLng(.NInput) << 56
        #Else
            B = RotL64(CLngLng(.NInput) And &HFF, 56)
        #End If
        #If HasPtrSafe Then
            Call CopyMemory(B, .Partial(0), .NPartial)
        #Else
            Call CopyMemory(ByVal VarPtr(B) + 8, .Partial(0), .NPartial)
        #End If
        .V3 = .V3 Xor B
        pvCompress uCtx, .UpdateIters
        .V0 = .V0 Xor B
        If .OutSize > 8 Then
            lIdx = &HEE
        Else
            lIdx = &HFF
        End If
        .V2 = .V2 Xor lIdx
        pvCompress uCtx, .FinalizeIters
        B = .V0 Xor .V1 Xor .V2 Xor .V3
        If .OutSize < 8 Then
            lIdx = .OutSize
        Else
            lIdx = 8
        End If
        #If HasPtrSafe Then
            Call CopyMemory(baOutput(0), B, lIdx)
        #Else
            Call CopyMemory(baOutput(0), ByVal VarPtr(B) + 8, lIdx)
        #End If
        If .OutSize > 8 Then
            .V1 = .V1 Xor &HDD
            pvCompress uCtx, .FinalizeIters
            B = .V0 Xor .V1 Xor .V2 Xor .V3
            If .OutSize < 16 Then
                lIdx = .OutSize - 8
            Else
                lIdx = 8
            End If
            #If HasPtrSafe Then
                Call CopyMemory(baOutput(8), B, lIdx)
            #Else
                Call CopyMemory(baOutput(8), ByVal VarPtr(B) + 8, lIdx)
            #End If
        End If
    End With
End Sub

Public Function CryptoSiphash24ByteArray(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Byte()
    Dim uCtx            As CryptoSiphashContext
    
    CryptoSiphashInit uCtx, baKey, UpdateIters:=2, FinalizeIters:=4
    CryptoSiphashUpdate uCtx, baInput, Pos, Size
    CryptoSiphashFinalize uCtx, CryptoSiphash24ByteArray
End Function

Private Function ToUtf8Array(sText As String) As Byte()
    Const CP_UTF8       As Long = 65001
    Dim baRetVal()      As Byte
    Dim lSize           As Long
    
    lSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(sText), Len(sText), ByVal 0, 0, 0, 0)
    If lSize > 0 Then
        ReDim baRetVal(0 To lSize - 1) As Byte
        Call WideCharToMultiByte(CP_UTF8, 0, StrPtr(sText), Len(sText), baRetVal(0), lSize, 0, 0)
    Else
        baRetVal = vbNullString
    End If
    ToUtf8Array = baRetVal
End Function

Private Function ToHex(baData() As Byte) As String
    Dim lIdx            As Long
    Dim sByte           As String
    
    ToHex = String$(UBound(baData) * 2 + 2, 48)
    For lIdx = 0 To UBound(baData)
        sByte = LCase$(Hex$(baData(lIdx)))
        If Len(sByte) = 1 Then
            Mid$(ToHex, lIdx * 2 + 2, 1) = sByte
        Else
            Mid$(ToHex, lIdx * 2 + 1, 2) = sByte
        End If
    Next
End Function

Public Function CryptoSiphash24Text(sKey As String, sText As String) As String
    CryptoSiphash24Text = ToHex(CryptoSiphash24ByteArray(ToUtf8Array(sKey), ToUtf8Array(sText)))
End Function

Public Function CryptoSiphash13ByteArray(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Byte()
    Dim uCtx            As CryptoSiphashContext
    
    CryptoSiphashInit uCtx, baKey, UpdateIters:=1, FinalizeIters:=3
    CryptoSiphashUpdate uCtx, baInput, Pos, Size
    CryptoSiphashFinalize uCtx, CryptoSiphash13ByteArray
End Function

Public Function CryptoSiphash13Text(sKey As String, sText As String) As String
    CryptoSiphash13Text = ToHex(CryptoSiphash13ByteArray(ToUtf8Array(sKey), ToUtf8Array(sText)))
End Function
```

cheers,
</wqw>

----------


## wqweto

(continued)



```
'--- mdHalfSiphash.bas
Option Explicit
DefObj A-Z

#Const HasPtrSafe = (VBA7 <> 0)
#Const HasOperators = (TWINBASIC <> 0)

#If HasPtrSafe Then
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As LongPtr, ByVal cchWideChar As Long, lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) As Long
Private Declare PtrSafe Function CallWindowProc Lib "user32" Alias "CallWindowProcW" (ByVal lpPrevWndFunc As LongPtr, ByVal hWnd As LongPtr, ByVal Msg As Long, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
#Else
Private Enum LongPtr
    [_]
End Enum
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcW" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
#End If

Private Const LNG_BLOCKSZ       As Long = 4
Private Const LNG_KEYSZ         As Long = 8
Private Const LNG_POW2_4        As Long = 2 ^ 4
Private Const LNG_POW2_5        As Long = 2 ^ 5
Private Const LNG_POW2_6        As Long = 2 ^ 6
Private Const LNG_POW2_7        As Long = 2 ^ 7
Private Const LNG_POW2_8        As Long = 2 ^ 8
Private Const LNG_POW2_12       As Long = 2 ^ 12
Private Const LNG_POW2_13       As Long = 2 ^ 13
Private Const LNG_POW2_15       As Long = 2 ^ 15
Private Const LNG_POW2_16       As Long = 2 ^ 16
Private Const LNG_POW2_18       As Long = 2 ^ 18
Private Const LNG_POW2_19       As Long = 2 ^ 19
Private Const LNG_POW2_23       As Long = 2 ^ 23
Private Const LNG_POW2_24       As Long = 2 ^ 24
Private Const LNG_POW2_25       As Long = 2 ^ 25
Private Const LNG_POW2_26       As Long = 2 ^ 26
Private Const LNG_POW2_27       As Long = 2 ^ 27
Private Const LNG_POW2_31       As Long = &H80000000
    
Private Type ArrayLong128
    Item(0 To 127)      As Long
End Type

Public Type CryptoHalfSiphashContext
    V0                  As Long
    V1                  As Long
    V2                  As Long
    V3                  As Long
    Partial(0 To LNG_BLOCKSZ - 1) As Byte
    NPartial            As Long
    NInput              As Currency
    UpdateIters         As Long
    FinalizeIters       As Long
    OutSize             As Long
End Type

#If Not HasOperators Then
Private Sub pvCompress(uCtx As CryptoHalfSiphashContext, ByVal lRounds As Long)
    With uCtx
        Do While lRounds > 0
'            .V0 = UAdd32(.V0, .V1)
'            .V1 = RotL32(.V1, 5) Xor .V0
'            .V2 = UAdd32(.V2, .V3)
'            .V3 = RotL32(.V3, 8) Xor .V2
'            .V0 = RotL32(.V0, 16)
            If (.V0 Xor .V1) >= 0 Then
                .V0 = ((.V0 Xor &H80000000) + .V1) Xor &H80000000
            Else
                .V0 = .V0 + .V1
            End If
            .V1 = ((.V1 And (LNG_POW2_26 - 1)) * LNG_POW2_5 Or -((.V1 And LNG_POW2_26) <> 0) * LNG_POW2_31) Or _
                ((.V1 And (LNG_POW2_31 Xor -1)) \ LNG_POW2_27 Or -(.V1 < 0) * LNG_POW2_4) Xor .V0
            If (.V2 Xor .V3) >= 0 Then
                .V2 = ((.V2 Xor &H80000000) + .V3) Xor &H80000000
            Else
                .V2 = .V2 + .V3
            End If
            .V3 = ((.V3 And (LNG_POW2_23 - 1)) * LNG_POW2_8 Or -((.V3 And LNG_POW2_23) <> 0) * LNG_POW2_31) Or _
                ((.V3 And (LNG_POW2_31 Xor -1)) \ LNG_POW2_24 Or -(.V3 < 0) * LNG_POW2_7) Xor .V2
            .V0 = ((.V0 And (LNG_POW2_15 - 1)) * LNG_POW2_16 Or -((.V0 And LNG_POW2_15) <> 0) * LNG_POW2_31) Or _
                ((.V0 And (LNG_POW2_31 Xor -1)) \ LNG_POW2_16 Or -(.V0 < 0) * LNG_POW2_15)
            

'            .V2 = UAdd32(.V2, .V1)
'            .V1 = RotL32(.V1, 13) Xor .V2
'            .V0 = UAdd32(.V0, .V3)
'            .V3 = RotL32(.V3, 7) Xor .V0
'            .V2 = RotL32(.V2, 16)
            If (.V2 Xor .V1) >= 0 Then
                .V2 = ((.V2 Xor &H80000000) + .V1) Xor &H80000000
            Else
                .V2 = .V2 + .V1
            End If
            .V1 = ((.V1 And (LNG_POW2_18 - 1)) * LNG_POW2_13 Or -((.V1 And LNG_POW2_18) <> 0) * LNG_POW2_31) Or _
                ((.V1 And (LNG_POW2_31 Xor -1)) \ LNG_POW2_19 Or -(.V1 < 0) * LNG_POW2_12) Xor .V2
            If (.V0 Xor .V3) >= 0 Then
                .V0 = ((.V0 Xor &H80000000) + .V3) Xor &H80000000
            Else
                .V0 = .V0 + .V3
            End If
            .V3 = ((.V3 And (LNG_POW2_24 - 1)) * LNG_POW2_7 Or -((.V3 And LNG_POW2_24) <> 0) * LNG_POW2_31) Or _
                ((.V3 And (LNG_POW2_31 Xor -1)) \ LNG_POW2_25 Or -(.V3 < 0) * LNG_POW2_6) Xor .V0
            .V2 = ((.V2 And (LNG_POW2_15 - 1)) * LNG_POW2_16 Or -((.V2 And LNG_POW2_15) <> 0) * LNG_POW2_31) Or _
                ((.V2 And (LNG_POW2_31 Xor -1)) \ LNG_POW2_16 Or -(.V2 < 0) * LNG_POW2_15)

            lRounds = lRounds - 1
        Loop
    End With
End Sub
#Else
[ IntegerOverflowChecks (False) ]
Private Sub pvCompress(uCtx As CryptoHalfSiphashContext, ByVal lRounds As Long)
    With uCtx
        Do While lRounds > 0
            .V0 += .V1
            .V1 = ((.V1 << 5) Or (.V1 >> 27)) Xor .V0
            .V2 += .V3
            .V3 = ((.V3 << 8) Or (.V3 >> 24)) Xor .V2
            .V0 = (.V0 << 16) Or (.V0 >> 16)
            
            .V2 += .V1
            .V1 = ((.V1 << 13) Or (.V1 >> 19)) Xor .V2
            .V0 += .V3
            .V3 = ((.V3 << 7) Or (.V3 >> 25)) Xor .V0
            .V2 = (.V2 << 16) Or (.V2 >> 16)
            
            lRounds -= 1
        Loop
    End With
End Sub
#End If

Private Function pvCompressArray(uCtx As CryptoHalfSiphashContext, ByVal lSize As Long, uBlock As ArrayLong128, NotUsed As Long) As Long
    Dim lIdx            As Long
    
    With uCtx
        For lIdx = 0 To lSize - 1
            .V3 = .V3 Xor uBlock.Item(lIdx)
            pvCompress uCtx, .UpdateIters
            .V0 = .V0 Xor uBlock.Item(lIdx)
        Next
    End With
End Function

Public Sub CryptoHalfSiphashInit(uCtx As CryptoHalfSiphashContext, baKey() As Byte, _
            Optional ByVal UpdateIters As Long = 2, _
            Optional ByVal FinalizeIters As Long = 4, _
            Optional ByVal OutSize As Long = 4)
    Static K(0 To 1)    As Long
    Dim lIdx            As Long
    
    If UBound(baKey) + 1 < LNG_KEYSZ Then
        K(0) = 0: K(1) = 0
        If UBound(baKey) >= 0 Then
            Call CopyMemory(K(0), baKey(0), UBound(baKey) + 1)
        End If
    Else
        Call CopyMemory(K(0), baKey(0), LNG_KEYSZ)
    End If
    With uCtx
        If OutSize > 4 Then
            lIdx = &HEE
        Else
            lIdx = 0
        End If
        .V0 = K(0)
        .V1 = K(1) Xor lIdx
        .V2 = &H6C796765 Xor K(0)
        .V3 = &H74656462 Xor K(1)
        .NPartial = 0
        .NInput = 0
        .UpdateIters = UpdateIters
        .FinalizeIters = FinalizeIters
        .OutSize = OutSize
    End With
End Sub

Public Sub CryptoHalfSiphashUpdate(uCtx As CryptoHalfSiphashContext, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1)
    Dim B               As Long
    Dim lIdx            As Long
    Dim lBlocks         As Long

    With uCtx
        If Size < 0 Then
            Size = UBound(baInput) + 1 - Pos
        End If
        .NInput = .NInput + Size
        If .NPartial > 0 And Size > 0 Then
            lIdx = LNG_BLOCKSZ - .NPartial
            If lIdx > Size Then
                lIdx = Size
            End If
            Call CopyMemory(.Partial(.NPartial), baInput(Pos), lIdx)
            .NPartial = .NPartial + lIdx
            Pos = Pos + lIdx
            Size = Size - lIdx
        End If
        Do While Size > 0 Or .NPartial = LNG_BLOCKSZ
            If .NPartial <> 0 Then
                Call CopyMemory(B, .Partial(0), LNG_BLOCKSZ)
                .NPartial = 0
                .V3 = .V3 Xor B
                pvCompress uCtx, .UpdateIters
                .V0 = .V0 Xor B
            ElseIf Size >= 128 * LNG_BLOCKSZ Then
                lBlocks = Size \ (128 * LNG_BLOCKSZ)
                For lIdx = 0 To lBlocks - 1
                    Call CallWindowProc(AddressOf pvCompressArray, VarPtr(uCtx), 128, VarPtr(baInput(Pos)), VarPtr(0))
                    Pos = Pos + 128 * LNG_BLOCKSZ
                    Size = Size - 128 * LNG_BLOCKSZ
                Next
            ElseIf Size >= LNG_BLOCKSZ Then
                lIdx = Size \ LNG_BLOCKSZ
                Call CallWindowProc(AddressOf pvCompressArray, VarPtr(uCtx), lIdx, VarPtr(baInput(Pos)), VarPtr(0))
                Pos = Pos + lIdx * LNG_BLOCKSZ
                Size = Size - lIdx * LNG_BLOCKSZ
            Else
                Call CopyMemory(.Partial(0), baInput(Pos), Size)
                .NPartial = Size
                Exit Do
            End If
        Loop
    End With
End Sub

Public Sub CryptoHalfSiphashFinalize(uCtx As CryptoHalfSiphashContext, baOutput() As Byte)
    Dim B               As Long
    Dim lIdx            As Long
    
    With uCtx
        ReDim baOutput(0 To .OutSize - 1) As Byte
        #If HasOperators Then
            B = CLng(.NInput) << 24
        #Else
            B = .NInput And &HFF
'            B = RotL32(B, 24)
            B = ((B And (LNG_POW2_7 - 1)) * LNG_POW2_24 Or -((B And LNG_POW2_7) <> 0) * LNG_POW2_31) Or _
                ((B And (LNG_POW2_31 Xor -1)) \ LNG_POW2_8 Or -(B < 0) * LNG_POW2_23)
        #End If
        Call CopyMemory(B, .Partial(0), .NPartial)
        .V3 = .V3 Xor B
        pvCompress uCtx, .UpdateIters
        .V0 = .V0 Xor B
        If .OutSize > 4 Then
            lIdx = &HEE
        Else
            lIdx = &HFF
        End If
        .V2 = .V2 Xor lIdx
        pvCompress uCtx, .FinalizeIters
        B = .V1 Xor .V3
        If .OutSize < 4 Then
            lIdx = .OutSize
        Else
            lIdx = 4
        End If
        Call CopyMemory(baOutput(0), B, lIdx)
        If .OutSize > 4 Then
            .V1 = .V1 Xor &HDD
            pvCompress uCtx, .FinalizeIters
            B = .V1 Xor .V3
            If .OutSize < 8 Then
                lIdx = .OutSize - 4
            Else
                lIdx = 4
            End If
            Call CopyMemory(baOutput(4), B, lIdx)
        End If
    End With
End Sub

Private Function ToUtf8Array(sText As String) As Byte()
    Const CP_UTF8       As Long = 65001
    Dim baRetVal()      As Byte
    Dim lSize           As Long
    
    lSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(sText), Len(sText), ByVal 0, 0, 0, 0)
    If lSize > 0 Then
        ReDim baRetVal(0 To lSize - 1) As Byte
        Call WideCharToMultiByte(CP_UTF8, 0, StrPtr(sText), Len(sText), baRetVal(0), lSize, 0, 0)
    Else
        baRetVal = vbNullString
    End If
    ToUtf8Array = baRetVal
End Function

Private Function ToHex(baData() As Byte) As String
    Dim lIdx            As Long
    Dim sByte           As String
    
    ToHex = String$(UBound(baData) * 2 + 2, 48)
    For lIdx = 0 To UBound(baData)
        sByte = LCase$(Hex$(baData(lIdx)))
        If Len(sByte) = 1 Then
            Mid$(ToHex, lIdx * 2 + 2, 1) = sByte
        Else
            Mid$(ToHex, lIdx * 2 + 1, 2) = sByte
        End If
    Next
End Function

Public Function CryptoHalfSiphash24ByteArray(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Byte()
    Dim uCtx            As CryptoHalfSiphashContext
    
    CryptoHalfSiphashInit uCtx, baKey, UpdateIters:=2, FinalizeIters:=4
    CryptoHalfSiphashUpdate uCtx, baInput, Pos, Size
    CryptoHalfSiphashFinalize uCtx, CryptoHalfSiphash24ByteArray
End Function

Public Function CryptoHalfSiphash24Long(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Long
    Dim baOuput()       As Byte
    
    baOuput = CryptoHalfSiphash24ByteArray(baKey, baInput, Pos, Size)
    Call CopyMemory(CryptoHalfSiphash24Long, baOuput(0), 4)
End Function

Public Function CryptoHalfSiphash24Text(sKey As String, sText As String) As String
    CryptoHalfSiphash24Text = ToHex(CryptoHalfSiphash24ByteArray(ToUtf8Array(sKey), ToUtf8Array(sText)))
End Function

Public Function CryptoHalfSiphash13ByteArray(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Byte()
    Dim uCtx            As CryptoHalfSiphashContext
    
    CryptoHalfSiphashInit uCtx, baKey, UpdateIters:=1, FinalizeIters:=3
    CryptoHalfSiphashUpdate uCtx, baInput, Pos, Size
    CryptoHalfSiphashFinalize uCtx, CryptoHalfSiphash13ByteArray
End Function

Public Function CryptoHalfSiphash13Long(baKey() As Byte, baInput() As Byte, Optional ByVal Pos As Long, Optional ByVal Size As Long = -1) As Long
    Dim baOuput()       As Byte
    
    baOuput = CryptoHalfSiphash13ByteArray(baKey, baInput, Pos, Size)
    Call CopyMemory(CryptoHalfSiphash13Long, baOuput(0), 4)
End Function

Public Function CryptoHalfSiphash13Text(sKey As String, sText As String) As String
    CryptoHalfSiphash13Text = ToHex(CryptoHalfSiphash13ByteArray(ToUtf8Array(sKey), ToUtf8Array(sText)))
End Function
```

cheers,
</wqw>

----------

