mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
🐛Move checksum initializers to instance constructors.
This commit is contained in:
@@ -49,12 +49,12 @@ namespace DiscImageChef.Checksums
|
||||
/// </summary>
|
||||
public class SpamSumContext : IChecksum
|
||||
{
|
||||
const uint ROLLING_WINDOW = 7;
|
||||
const uint MIN_BLOCKSIZE = 3;
|
||||
const uint HASH_PRIME = 0x01000193;
|
||||
const uint HASH_INIT = 0x28021967;
|
||||
const uint NUM_BLOCKHASHES = 31;
|
||||
const uint SPAMSUM_LENGTH = 64;
|
||||
const uint ROLLING_WINDOW = 7;
|
||||
const uint MIN_BLOCKSIZE = 3;
|
||||
const uint HASH_PRIME = 0x01000193;
|
||||
const uint HASH_INIT = 0x28021967;
|
||||
const uint NUM_BLOCKHASHES = 31;
|
||||
const uint SPAMSUM_LENGTH = 64;
|
||||
const uint FUZZY_MAX_RESULT = 2 * SPAMSUM_LENGTH + 20;
|
||||
//"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
readonly byte[] b64 =
|
||||
@@ -67,30 +67,70 @@ namespace DiscImageChef.Checksums
|
||||
|
||||
FuzzyState self;
|
||||
|
||||
void roll_init()
|
||||
{
|
||||
self.Roll = new RollState {Window = new byte[ROLLING_WINDOW]};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the SpamSum structures
|
||||
/// </summary>
|
||||
public void Init()
|
||||
public SpamSumContext()
|
||||
{
|
||||
self = new FuzzyState {Bh = new BlockhashContext[NUM_BLOCKHASHES]};
|
||||
self =
|
||||
new FuzzyState {Bh = new BlockhashContext[NUM_BLOCKHASHES]};
|
||||
for(int i = 0; i < NUM_BLOCKHASHES; i++) self.Bh[i].Digest = new byte[SPAMSUM_LENGTH];
|
||||
|
||||
self.Bhstart = 0;
|
||||
self.Bhend = 1;
|
||||
self.Bh[0].H = HASH_INIT;
|
||||
self.Bh[0].Halfh = HASH_INIT;
|
||||
self.Bh[0].Digest[0] = 0;
|
||||
self.Bhstart = 0;
|
||||
self.Bhend = 1;
|
||||
self.Bh[0].H = HASH_INIT;
|
||||
self.Bh[0].Halfh = HASH_INIT;
|
||||
self.Bh[0].Digest[0] = 0;
|
||||
self.Bh[0].Halfdigest = 0;
|
||||
self.Bh[0].Dlen = 0;
|
||||
self.TotalSize = 0;
|
||||
self.Bh[0].Dlen = 0;
|
||||
self.TotalSize = 0;
|
||||
roll_init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the hash with data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len)
|
||||
{
|
||||
self.TotalSize += len;
|
||||
for(int i = 0; i < len; i++) fuzzy_engine_step(data[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the hash with data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data)
|
||||
{
|
||||
Update(data, (uint)data.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a byte array of the hash value.
|
||||
/// </summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
// SpamSum does not have a binary representation, or so it seems
|
||||
throw new NotImplementedException("SpamSum does not have a binary representation.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a base64 representation of the hash value.
|
||||
/// </summary>
|
||||
public string End()
|
||||
{
|
||||
FuzzyDigest(out byte[] result);
|
||||
|
||||
return CToString(result);
|
||||
}
|
||||
|
||||
void roll_init()
|
||||
{
|
||||
self.Roll = new RollState {Window = new byte[ROLLING_WINDOW]};
|
||||
}
|
||||
|
||||
/*
|
||||
* a rolling hash, based on the Adler checksum. By using a rolling hash
|
||||
* we can perform auto resynchronisation after inserts/deletes
|
||||
@@ -116,7 +156,7 @@ namespace DiscImageChef.Checksums
|
||||
* in theory should have no effect. This AND has been removed
|
||||
* for performance (jk) */
|
||||
self.Roll.H3 <<= 5;
|
||||
self.Roll.H3 ^= c;
|
||||
self.Roll.H3 ^= c;
|
||||
}
|
||||
|
||||
uint roll_sum()
|
||||
@@ -144,13 +184,13 @@ namespace DiscImageChef.Checksums
|
||||
if(self.Bhend == 0) // assert
|
||||
throw new Exception("Assertion failed");
|
||||
|
||||
obh = self.Bhend - 1;
|
||||
nbh = self.Bhend;
|
||||
self.Bh[nbh].H = self.Bh[obh].H;
|
||||
self.Bh[nbh].Halfh = self.Bh[obh].Halfh;
|
||||
self.Bh[nbh].Digest[0] = 0;
|
||||
obh = self.Bhend - 1;
|
||||
nbh = self.Bhend;
|
||||
self.Bh[nbh].H = self.Bh[obh].H;
|
||||
self.Bh[nbh].Halfh = self.Bh[obh].Halfh;
|
||||
self.Bh[nbh].Digest[0] = 0;
|
||||
self.Bh[nbh].Halfdigest = 0;
|
||||
self.Bh[nbh].Dlen = 0;
|
||||
self.Bh[nbh].Dlen = 0;
|
||||
++self.Bhend;
|
||||
}
|
||||
|
||||
@@ -165,6 +205,7 @@ namespace DiscImageChef.Checksums
|
||||
* blocksize. */ return;
|
||||
if(self.Bh[self.Bhstart + 1].Dlen < SPAMSUM_LENGTH / 2)
|
||||
/* Estimate adjustment would select this blocksize. */ return;
|
||||
|
||||
/* At this point we are clearly no longer interested in the
|
||||
* start_blocksize. Get rid of it. */
|
||||
++self.Bhstart;
|
||||
@@ -173,7 +214,7 @@ namespace DiscImageChef.Checksums
|
||||
void fuzzy_engine_step(byte c)
|
||||
{
|
||||
ulong h;
|
||||
uint i;
|
||||
uint i;
|
||||
/* At each character we update the rolling hash and the normal hashes.
|
||||
* When the rolling hash hits a reset value then we emit a normal hash
|
||||
* as a element of the signature and reset the normal hash. */
|
||||
@@ -182,7 +223,7 @@ namespace DiscImageChef.Checksums
|
||||
|
||||
for(i = self.Bhstart; i < self.Bhend; ++i)
|
||||
{
|
||||
self.Bh[i].H = sum_hash(c, self.Bh[i].H);
|
||||
self.Bh[i].H = sum_hash(c, self.Bh[i].H);
|
||||
self.Bh[i].Halfh = sum_hash(c, self.Bh[i].Halfh);
|
||||
}
|
||||
|
||||
@@ -193,12 +234,13 @@ namespace DiscImageChef.Checksums
|
||||
/* Once this condition is false for one bs, it is
|
||||
* automatically false for all further bs. I.e. if
|
||||
* h === -1 (mod 2*bs) then h === -1 (mod bs). */ break;
|
||||
|
||||
/* We have hit a reset point. We now emit hashes which are
|
||||
* based on all characters in the piece of the message between
|
||||
* the last reset point and this one */
|
||||
if(0 == self.Bh[i].Dlen) fuzzy_try_fork_blockhash();
|
||||
self.Bh[i].Digest[self.Bh[i].Dlen] = b64[self.Bh[i].H % 64];
|
||||
self.Bh[i].Halfdigest = b64[self.Bh[i].Halfh % 64];
|
||||
self.Bh[i].Digest[self.Bh[i].Dlen] = b64[self.Bh[i].H % 64];
|
||||
self.Bh[i].Halfdigest = b64[self.Bh[i].Halfh % 64];
|
||||
if(self.Bh[i].Dlen < SPAMSUM_LENGTH - 1)
|
||||
{
|
||||
/* We can have a problem with the tail overflowing. The
|
||||
@@ -208,45 +250,25 @@ namespace DiscImageChef.Checksums
|
||||
* last few pieces of the message into a single piece
|
||||
* */
|
||||
self.Bh[i].Digest[++self.Bh[i].Dlen] = 0;
|
||||
self.Bh[i].H = HASH_INIT;
|
||||
self.Bh[i].H = HASH_INIT;
|
||||
if(self.Bh[i].Dlen >= SPAMSUM_LENGTH / 2) continue;
|
||||
|
||||
self.Bh[i].Halfh = HASH_INIT;
|
||||
self.Bh[i].Halfh = HASH_INIT;
|
||||
self.Bh[i].Halfdigest = 0;
|
||||
}
|
||||
else fuzzy_try_reduce_blockhash();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the hash with data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
/// <param name="len">Length of buffer to hash.</param>
|
||||
public void Update(byte[] data, uint len)
|
||||
{
|
||||
self.TotalSize += len;
|
||||
for(int i = 0; i < len; i++) fuzzy_engine_step(data[i]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the hash with data.
|
||||
/// </summary>
|
||||
/// <param name="data">Data buffer.</param>
|
||||
public void Update(byte[] data)
|
||||
{
|
||||
Update(data, (uint)data.Length);
|
||||
}
|
||||
|
||||
// CLAUNIA: Flags seems to never be used in ssdeep, so I just removed it for code simplicity
|
||||
uint FuzzyDigest(out byte[] result)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
uint bi = self.Bhstart;
|
||||
uint h = roll_sum();
|
||||
int i, resultOff;
|
||||
int remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
|
||||
result = new byte[FUZZY_MAX_RESULT];
|
||||
uint bi = self.Bhstart;
|
||||
uint h = roll_sum();
|
||||
int i, resultOff;
|
||||
int remain = (int)(FUZZY_MAX_RESULT - 1); /* Exclude terminating '\0'. */
|
||||
result = new byte[FUZZY_MAX_RESULT];
|
||||
/* Verify that our elimination was not overeager. */
|
||||
if(!(bi == 0 || (ulong)SSDEEP_BS(bi) / 2 * SPAMSUM_LENGTH < self.TotalSize))
|
||||
throw new Exception("Assertion failed");
|
||||
@@ -259,6 +281,7 @@ namespace DiscImageChef.Checksums
|
||||
++bi;
|
||||
if(bi >= NUM_BLOCKHASHES) throw new OverflowException("The input exceeds data types.");
|
||||
}
|
||||
|
||||
/* Adapt blocksize guess to actual digest length. */
|
||||
while(bi >= self.Bhend) --bi;
|
||||
while(bi > self.Bhstart && self.Bh[bi].Dlen < SPAMSUM_LENGTH / 2) --bi;
|
||||
@@ -282,14 +305,15 @@ namespace DiscImageChef.Checksums
|
||||
|
||||
Array.Copy(self.Bh[bi].Digest, 0, result, resultOff, i);
|
||||
resultOff += i;
|
||||
remain -= i;
|
||||
remain -= i;
|
||||
if(h != 0)
|
||||
{
|
||||
if(remain <= 0) throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = b64[self.Bh[bi].H % 64];
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] || result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
@@ -300,8 +324,9 @@ namespace DiscImageChef.Checksums
|
||||
if(remain <= 0) throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = self.Bh[bi].Digest[i];
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] || result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
@@ -320,16 +345,17 @@ namespace DiscImageChef.Checksums
|
||||
|
||||
Array.Copy(self.Bh[bi].Digest, 0, result, resultOff, i);
|
||||
resultOff += i;
|
||||
remain -= i;
|
||||
remain -= i;
|
||||
|
||||
if(h != 0)
|
||||
{
|
||||
if(remain <= 0) throw new Exception("Assertion failed");
|
||||
|
||||
h = self.Bh[bi].Halfh;
|
||||
h = self.Bh[bi].Halfh;
|
||||
result[resultOff] = b64[h % 64];
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] || result[resultOff] != result[resultOff - 3])
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
@@ -343,8 +369,9 @@ namespace DiscImageChef.Checksums
|
||||
if(remain <= 0) throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff] = (byte)i;
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] || result[resultOff] != result[resultOff - 3])
|
||||
if(i < 3 || result[resultOff] != result[resultOff - 1] ||
|
||||
result[resultOff] != result[resultOff - 2] ||
|
||||
result[resultOff] != result[resultOff - 3])
|
||||
{
|
||||
++resultOff;
|
||||
--remain;
|
||||
@@ -355,7 +382,7 @@ namespace DiscImageChef.Checksums
|
||||
else if(h != 0)
|
||||
{
|
||||
if(self.Bh[bi].Dlen != 0) throw new Exception("Assertion failed");
|
||||
if(remain <= 0) throw new Exception("Assertion failed");
|
||||
if(remain <= 0) throw new Exception("Assertion failed");
|
||||
|
||||
result[resultOff++] = b64[self.Bh[bi].H % 64];
|
||||
/* No need to bother with FUZZY_FLAG_ELIMSEQ, because this
|
||||
@@ -367,25 +394,6 @@ namespace DiscImageChef.Checksums
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a byte array of the hash value.
|
||||
/// </summary>
|
||||
public byte[] Final()
|
||||
{
|
||||
// SpamSum does not have a binary representation, or so it seems
|
||||
throw new NotImplementedException("SpamSum does not have a binary representation.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a base64 representation of the hash value.
|
||||
/// </summary>
|
||||
public string End()
|
||||
{
|
||||
FuzzyDigest(out byte[] result);
|
||||
|
||||
return CToString(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash of a file
|
||||
/// </summary>
|
||||
@@ -417,7 +425,6 @@ namespace DiscImageChef.Checksums
|
||||
public static string Data(byte[] data, uint len, out byte[] hash)
|
||||
{
|
||||
SpamSumContext fuzzyContext = new SpamSumContext();
|
||||
fuzzyContext.Init();
|
||||
|
||||
fuzzyContext.Update(data, len);
|
||||
|
||||
@@ -469,8 +476,8 @@ namespace DiscImageChef.Checksums
|
||||
* output hash to stay compatible with ssdeep output. */
|
||||
struct BlockhashContext
|
||||
{
|
||||
public uint H;
|
||||
public uint Halfh;
|
||||
public uint H;
|
||||
public uint Halfh;
|
||||
public byte[] Digest;
|
||||
// SPAMSUM_LENGTH
|
||||
public byte Halfdigest;
|
||||
@@ -479,11 +486,11 @@ namespace DiscImageChef.Checksums
|
||||
|
||||
struct FuzzyState
|
||||
{
|
||||
public uint Bhstart;
|
||||
public uint Bhend;
|
||||
public uint Bhstart;
|
||||
public uint Bhend;
|
||||
public BlockhashContext[] Bh;
|
||||
//NUM_BLOCKHASHES
|
||||
public ulong TotalSize;
|
||||
public ulong TotalSize;
|
||||
public RollState Roll;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user