File Coverage

qxhash.c
Criterion Covered Total %
statement 70 82 85.3
branch 20 36 55.5
condition n/a
subroutine n/a
pod n/a
total 90 118 76.2


line stmt bran cond sub pod time code
1             /*
2             * libquickxor - QuickXorHash Library
3             *
4             * © 2019 by Tekki (Rolf Stöckli)
5             *
6             * The original C# algorithm was published by Microsoft under the following copyright:
7             *
8             * Copyright (c) 2016 Microsoft Corporation
9             *
10             * Permission is hereby granted, free of charge, to any person obtaining a copy
11             * of this software and associated documentation files (the "Software"), to deal
12             * in the Software without restriction, including without limitation the rights
13             * to use, copy, modify, merge, publish, distribute, sublicense, andor sell
14             * copies of the Software, and to permit persons to whom the Software is
15             * furnished to do so, subject to the following conditions:
16             *
17             * The above copyright notice and this permission notice shall be included in
18             * all copies or substantial portions of the Software.
19             *
20             */
21              
22             #include
23             #include
24             #include "qxhash.h"
25             #include "base64.h"
26              
27 4           QX* QX_new() {
28 4           QX* pqx = NULL;
29              
30 4           pqx = calloc(1, sizeof(QX));
31 4 50         if (pqx) {
32 4           pqx->kDataLength = QX_DATA_LENGTH;
33 4           pqx->kShift = QX_SHIFT;
34 4           pqx->kWidthInBits = QX_WIDTH_IN_BITS;
35 4           pqx->kWidthInBytes = QX_WIDTH_IN_BYTES;
36             }
37              
38 4           return pqx;
39             }
40              
41 18           void QX_add(QX* pqx, uint8_t* addData, size_t addSize) {
42             // the bitvector where we'll start xoring
43 18           size_t vectorArrayIndex = pqx->shiftSoFar / 64;
44              
45             // the position within the bit vector at which we begin xoring
46 18           int vectorOffset = pqx->shiftSoFar % 64;
47 18           size_t iterations = addSize > pqx->kWidthInBits ? pqx->kWidthInBits : addSize;
48              
49 1050 100         for (size_t i = 0; i < iterations; ++i) {
50 1032           size_t nextCell = vectorArrayIndex + 1;
51 1032           int bitsInVectorCell = 64;
52 1032 100         if (nextCell == pqx->kDataLength) {
53 192           nextCell = 0;
54 192 50         if (pqx->kWidthInBits % 64 > 0) {
55 192           bitsInVectorCell = pqx->kWidthInBits % 64;
56             }
57             }
58              
59 1032           uint8_t xoredByte = 0x0;
60 193040 100         for (size_t j = i; j < addSize; j += pqx->kWidthInBits) {
61 192008           xoredByte ^= addData[j];
62             }
63              
64 1032           pqx->data[vectorArrayIndex] ^= ((uint64_t)xoredByte) << vectorOffset;
65              
66 1032 100         if (vectorOffset > bitsInVectorCell - 8) {
67 132           pqx->data[nextCell] ^= ((uint64_t)xoredByte) >> (bitsInVectorCell - vectorOffset);
68             }
69              
70 1032           vectorOffset += pqx->kShift;
71 1032 100         if (vectorOffset >= bitsInVectorCell) {
72 210           vectorArrayIndex = nextCell;
73 210           vectorOffset -= bitsInVectorCell;
74             }
75             }
76              
77             // update the starting position in a circular shift pattern
78 18           pqx->shiftSoFar += pqx->kShift * (addSize % pqx->kWidthInBits);
79 18           pqx->shiftSoFar %= pqx->kWidthInBits;
80 18           pqx->lengthSoFar += addSize;
81 18           }
82              
83 12           char* QX_b64digest(QX* pqx) {
84 12           uint8_t* digest = NULL;
85             size_t hashSize;
86 12           char* hash = NULL;
87              
88 12           digest = QX_digest(pqx);
89 12           hashSize = 2 * pqx->kWidthInBytes;
90 12           hash = calloc(1, hashSize);
91              
92 12 50         if (digest && hash) {
    50          
93 12           B64_encode(digest, pqx->kWidthInBytes, hash, hashSize);
94             }
95              
96 12           free(digest);
97 12           digest = NULL;
98              
99 12           return hash;
100             }
101              
102 12           uint8_t* QX_digest(QX* pqx) {
103 12           uint8_t* digest = NULL;
104 12           uint8_t* digestLength = NULL;
105 12           size_t lengthSize = sizeof(pqx->lengthSoFar);
106              
107             // create a byte array big enough to hold all our data
108 12           digest = calloc(1, pqx->kWidthInBytes);
109              
110 12 50         if (digest) {
111             // block copy all our bitvectors to this byte array
112 12           memcpy(digest, pqx->data, pqx->kWidthInBytes);
113 12           digestLength = calloc(1, lengthSize);
114 12 50         if (digestLength) {
115             // xor the file length with the least significant bits
116 12           memcpy(digestLength, &pqx->lengthSoFar, lengthSize);
117              
118 108 100         for (size_t i = 0; i < lengthSize; ++i) {
119 96           digest[pqx->kWidthInBytes - lengthSize + i] ^= digestLength[i];
120             }
121              
122 12           free(digestLength);
123 12           digestLength = NULL;
124             }
125             }
126              
127 12           return digest;
128             }
129              
130 0           int QX_readFile(QX* pqx, char* filename) {
131 0           int status = 1;
132 0 0         if (pqx && strlen(filename)) {
    0          
133 0           FILE* pFile = NULL;
134 0           pFile = fopen(filename, "rb");
135 0 0         if (pFile) {
136             uint8_t buf[4096];
137             size_t len;
138              
139 0           QX_reset(pqx);
140 0 0         while ((len = fread(buf, 1, 4096, pFile)) > 0) {
141 0           QX_add(pqx, buf, len);
142             }
143 0           fclose(pFile);
144              
145 0           status = 0;
146             }
147             }
148 0           return status;
149             }
150              
151 4           void QX_free(QX*pqx) {
152 4 50         if (pqx) {
153 4           free(pqx);
154             }
155 4           }
156              
157 12           void QX_reset(QX* pqx) {
158 12 50         if (pqx) {
159 12           memset(pqx->data, 0, QX_DATA_LENGTH * sizeof(uint64_t));
160 12           pqx->lengthSoFar = 0;
161 12           pqx->shiftSoFar = 0;
162             }
163 12           }