#include "rsort.h"
#include <string.h>
#include "simplicity_assert.h"
#include "simplicity_alloc.h"
static_assert(UCHAR_MAX < SIZE_MAX, "UCHAR_MAX >= SIZE_MAX");
#define CHAR_COUNT ((size_t)1 << CHAR_BIT)
static unsigned char readIndex(const sha256_midstate* a, unsigned int i) {
return ((const unsigned char*)(a->s))[i];
}
static bool freq(uint32_t* result, const sha256_midstate * const * a, uint_fast32_t len, unsigned int j) {
memset(result, 0, CHAR_COUNT * sizeof(uint32_t));
if (0 == len) return true;
for (size_t i = 0; i < len - 1; ++i) {
result[readIndex(a[i],j)]++;
}
return len == ++result[readIndex(a[len-1],j)];
}
static void cumulative(uint32_t* restrict bucketEdge, const uint32_t* restrict sizes) {
uint32_t accumulator = bucketEdge[0] + sizes[0];
for (unsigned int i = 1; i < CHAR_COUNT; ++i) {
bucketEdge[i] = accumulator;
accumulator += sizes[i];
}
}
static void swap(const sha256_midstate** a, const sha256_midstate** b) {
const sha256_midstate* tmp = *a;
*a = *b;
*b = tmp;
}
static void sort_buckets(const sha256_midstate** a, uint32_t* restrict bucketSize, const uint32_t* restrict bucketEdge, unsigned int ix) {
for (unsigned int i = 0; i < CHAR_COUNT; ++i) {
size_t start = bucketEdge[i];
while (bucketSize[i]) {
size_t bucket = readIndex(a[start], ix);
rustsimplicity_0_6_assert(bucketSize[bucket]);
bucketSize[bucket]--;
swap(a + start, a + bucketEdge[bucket] + bucketSize[bucket]);
}
}
}
static void rsort_ex(const sha256_midstate** a, uint_fast32_t len, const sha256_midstate** hasDuplicates, uint32_t* stack) {
unsigned int depth = 0;
size_t bucketCount[sizeof((*a)->s) + 1];
size_t totalBucketCount = 1;
static_assert(sizeof((*a)->s) <= UINT_MAX, "UINT_MAX too small to hold depth.");
stack[0]=0;
bucketCount[depth] = 1;
while(totalBucketCount) {
while(0 == bucketCount[depth]) {
rustsimplicity_0_6_assert(depth);
depth--;
}
bucketCount[depth]--; totalBucketCount--;
if (2 <= len - stack[totalBucketCount]) {
uint32_t bucketSize[CHAR_COUNT];
uint32_t* bucketEdge = stack + totalBucketCount;
uint32_t begin = bucketEdge[0];
while (depth < sizeof((*a)->s) && freq(bucketSize, a + begin, len - begin, depth)) {
depth++;
bucketCount[depth] = 0;
};
if (depth < sizeof((*a)->s)) {
cumulative(bucketEdge, bucketSize);
rustsimplicity_0_6_assert(len == bucketEdge[UCHAR_MAX] + bucketSize[UCHAR_MAX]);
sort_buckets(a, bucketSize, bucketEdge, depth);
depth++; bucketCount[depth] = CHAR_COUNT; totalBucketCount += CHAR_COUNT;
continue;
}
if (hasDuplicates) {
*hasDuplicates = a[begin];
return;
}
}
len = stack[totalBucketCount];
}
rustsimplicity_0_6_assert(0 == len);
if (hasDuplicates) *hasDuplicates = NULL;
}
bool rustsimplicity_0_6_rsort(const sha256_midstate** a, uint_fast32_t len) {
uint32_t *stack = rustsimplicity_0_6_malloc(((CHAR_COUNT - 1)*(sizeof((*a)->s)) + 1) * sizeof(uint32_t));
if (!stack) return false;
rsort_ex(a, len, NULL, stack);
rustsimplicity_0_6_free(stack);
return true;
}
int rustsimplicity_0_6_hasDuplicates(const sha256_midstate* a, uint_fast32_t len) {
if (len < 2) return 0;
static_assert(sizeof(a->s) * CHAR_BIT == 256, "sha256_midstate.s has unnamed padding.");
static_assert(DAG_LEN_MAX <= UINT32_MAX, "DAG_LEN_MAX does not fit in uint32_t.");
static_assert(DAG_LEN_MAX <= SIZE_MAX / sizeof(const sha256_midstate*), "perm array too large.");
rustsimplicity_0_6_assert((size_t)len <= SIZE_MAX / sizeof(const sha256_midstate*));
const sha256_midstate **perm = rustsimplicity_0_6_malloc(len * sizeof(const sha256_midstate*));
uint32_t *stack = rustsimplicity_0_6_malloc(((CHAR_COUNT - 1)*(sizeof((*perm)->s)) + 1) * sizeof(uint32_t));
int result = perm && stack ? 0 : -1;
if (0 <= result) {
for (uint_fast32_t i = 0; i < len; ++i) {
perm[i] = a + i;
}
const sha256_midstate *duplicate;
rsort_ex(perm, len, &duplicate, stack);
result = NULL != duplicate;
}
rustsimplicity_0_6_free(perm);
rustsimplicity_0_6_free(stack);
return result;
}