1
- using System ;
1
+ using System ;
2
2
using System . Linq ;
3
3
using System . Security . Cryptography ;
4
+ using System . Text ;
4
5
5
6
namespace ProbabilisticDataStructures
6
7
{
@@ -48,19 +49,32 @@ public static uint OptimalK(double fpRate)
48
49
49
50
/// <summary>
50
51
/// Returns the upper and lower base hash values from which the k hashes are
51
- /// derived.
52
+ /// derived. The result will be the same regardless of the endianness of the
53
+ /// architecture.
52
54
/// </summary>
53
55
/// <param name="data">The data bytes to hash.</param>
54
56
/// <param name="algorithm">The hashing algorithm to use.</param>
55
57
/// <returns>A HashKernel</returns>
56
58
public static HashKernelReturnValue HashKernel ( byte [ ] data , HashAlgorithm algorithm )
57
59
{
58
- var hash = new Hash ( algorithm ) ;
59
- hash . ComputeHash ( data ) ;
60
- var sum = hash . Sum ( ) ;
60
+ var sum = algorithm . ComputeHash ( data ) ;
61
+ return HashKernelFromHashBytes ( sum ) ;
62
+ }
63
+
64
+ /// <summary>
65
+ /// Returns the upper and lower base hash values from which the k hashes are
66
+ /// derived using the given hash bytes directly. The result will be the
67
+ /// same regardless of the endianness of the architecture. Used by a unit
68
+ /// test to confirm the calculation is compatible with the HashKernel from
69
+ /// https://github.com/tylertreat/BoomFilters running in Go.
70
+ /// </summary>
71
+ /// <param name="hashBytes">The hash bytes.</param>
72
+ /// <returns>A HashKernel</returns>
73
+ public static HashKernelReturnValue HashKernelFromHashBytes ( byte [ ] hashBytes )
74
+ {
61
75
return HashKernelReturnValue . Create (
62
- ToBigEndianUInt32 ( sum . Skip ( 4 ) . Take ( 4 ) . ToArray ( ) ) ,
63
- ToBigEndianUInt32 ( sum . Take ( 4 ) . ToArray ( ) )
76
+ HashBytesToUInt32 ( hashBytes , 0 ) ,
77
+ HashBytesToUInt32 ( hashBytes , 4 )
64
78
) ;
65
79
}
66
80
@@ -73,30 +87,73 @@ public static HashKernelReturnValue HashKernel(byte[] data, HashAlgorithm algori
73
87
/// <returns>A HashKernel</returns>
74
88
public static HashKernel128ReturnValue HashKernel128 ( byte [ ] data , HashAlgorithm algorithm )
75
89
{
76
- var hash = new Hash128 ( algorithm ) ;
77
- var sum = hash . ComputeHashAndSum ( data ) ;
90
+ var sum = algorithm . ComputeHash ( data ) ;
78
91
return HashKernel128ReturnValue . Create (
79
- ToBigEndianUInt64 ( sum , 8 ) ,
80
- ToBigEndianUInt64 ( sum , 0 )
92
+ HashBytesToUInt64 ( sum , 0 ) ,
93
+ HashBytesToUInt64 ( sum , 8 )
81
94
) ;
82
95
}
83
96
84
- public static uint ToBigEndianUInt32 ( byte [ ] bytes )
97
+ /// <summary>
98
+ /// Returns the uint represented by the given hash bytes, starting at
99
+ /// byte <paramref name="offset"/>. The result will be the same
100
+ /// regardless of the endianness of the architecture.
101
+ /// </summary>
102
+ /// <param name="hashBytes"></param>
103
+ /// <param name="offset"></param>
104
+ /// <returns></returns>
105
+ public static uint HashBytesToUInt32 ( byte [ ] hashBytes , int offset = 0 )
85
106
{
86
- if ( BitConverter . IsLittleEndian )
87
- Array . Reverse ( bytes ) ;
107
+ return
108
+ ( ( uint ) hashBytes [ offset ] ) |
109
+ ( ( uint ) hashBytes [ offset + 1 ] ) << 8 |
110
+ ( ( uint ) hashBytes [ offset + 2 ] ) << 16 |
111
+ ( ( uint ) hashBytes [ offset + 3 ] ) << 24 ;
112
+ }
88
113
89
- uint i = BitConverter . ToUInt32 ( bytes , 0 ) ;
90
- return i ;
114
+ /// <summary>
115
+ /// Returns the ulong represented by the given hash bytes, starting at
116
+ /// byte <paramref name="offset"/>. The result will be the same
117
+ /// regardless of the endianness of the architecture.
118
+ /// </summary>
119
+ /// <param name="hashBytes"></param>
120
+ /// <param name="offset"></param>
121
+ /// <returns></returns>
122
+ public static ulong HashBytesToUInt64 ( byte [ ] hashBytes , int offset = 0 )
123
+ {
124
+ return
125
+ ( ( ulong ) hashBytes [ offset ] ) |
126
+ ( ( ulong ) hashBytes [ offset + 1 ] ) << 8 |
127
+ ( ( ulong ) hashBytes [ offset + 2 ] ) << 16 |
128
+ ( ( ulong ) hashBytes [ offset + 3 ] ) << 24 |
129
+ ( ( ulong ) hashBytes [ offset + 4 ] ) << 32 |
130
+ ( ( ulong ) hashBytes [ offset + 5 ] ) << 40 |
131
+ ( ( ulong ) hashBytes [ offset + 6 ] ) << 48 |
132
+ ( ( ulong ) hashBytes [ offset + 7 ] ) << 56 ;
91
133
}
92
134
93
- public static ulong ToBigEndianUInt64 ( byte [ ] bytes , int offset )
135
+ /// <summary>
136
+ /// Compute the hash for the provided bytes.
137
+ /// </summary>
138
+ /// <param name="inputBytes">The bytes to hash.</param>
139
+ /// <returns>The hash string of the bytes.</returns>
140
+ public static string ComputeHashAsString ( byte [ ] inputBytes , HashAlgorithm hashAlgorithm )
94
141
{
95
- if ( BitConverter . IsLittleEndian )
96
- Array . Reverse ( bytes , offset , 8 ) ;
142
+ // Compute the hash of the input byte array.
143
+ byte [ ] data = hashAlgorithm . ComputeHash ( inputBytes ) ;
144
+
145
+ // Create a new StringBuilder to collect the bytes and create a string.
146
+ StringBuilder sb = new StringBuilder ( ) ;
147
+
148
+ // Loop through each byte of the hashed data and format each one as a
149
+ // hexadecimal string.
150
+ for ( int i = 0 ; i < data . Length ; i ++ )
151
+ {
152
+ sb . Append ( data [ i ] . ToString ( "X2" ) ) ;
153
+ }
97
154
98
- ulong i = BitConverter . ToUInt64 ( bytes , offset ) ;
99
- return i ;
155
+ // Return the hexadecimal string.
156
+ return sb . ToString ( ) ;
100
157
}
101
158
}
102
159
0 commit comments