Skip to content

Commit 6108c98

Browse files
Improve Word jet CMR computation
1 parent 1f7256a commit 6108c98

File tree

4 files changed

+329
-17
lines changed

4 files changed

+329
-17
lines changed

bitstring.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,21 @@ static inline bool getBit(const bitstring *s, size_t n) {
3232
return 1 & (s->arr[total_offset / CHAR_BIT] >> (CHAR_BIT - 1 - (total_offset % CHAR_BIT)));
3333
}
3434

35+
/* Return 8 bits from a bitstring staring from the nth bit.
36+
*
37+
* Precondition: NULL != s
38+
* n + 8 <= s->len;
39+
*/
40+
static inline uint_fast8_t getByte(const bitstring *s, size_t n) {
41+
simplicity_assert(8 <= s->len);
42+
simplicity_assert(n <= s->len - 8);
43+
size_t total_offset = s->offset + n;
44+
if (total_offset % CHAR_BIT <= CHAR_BIT - 8) {
45+
return (uint_fast8_t)(0xff & (s->arr[total_offset / CHAR_BIT] >> (CHAR_BIT - 8 - (total_offset % CHAR_BIT))));
46+
} else {
47+
/* CHAR_BIT < total_offset % CHAR_BIT + 8 */
48+
return (uint_fast8_t)(0xff & (((1U * s->arr[total_offset / CHAR_BIT]) << (total_offset % CHAR_BIT - (CHAR_BIT - 8)))
49+
| (s->arr[total_offset / CHAR_BIT + 1] >> (CHAR_BIT - (total_offset % CHAR_BIT - (CHAR_BIT - 8))))));
50+
}
51+
}
3552
#endif

dag.c

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,31 +97,39 @@ static sha256_midstate mkJetCMR(uint32_t *imr, uint_fast64_t weight) {
9797
* Precondition: 2^n == value->len
9898
*/
9999
sha256_midstate computeWordCMR(const bitstring* value, size_t n) {
100-
/* 'stack' is an array of 33 hashes consisting of 8 'uint32_t's each. */
101-
uint32_t stack[8*33] = {0};
100+
/* 'stack' is an array of 30 hashes consisting of 8 'uint32_t's each. */
101+
uint32_t stack[8*30] = {0};
102102
uint32_t *stack_ptr = stack;
103103
sha256_midstate imr = identityIV;
104104
simplicity_assert(n < 32);
105105
simplicity_assert((size_t)1 << n == value->len);
106106
/* Pass 1: Compute the CMR for the expression that writes 'value'.
107107
* This expression consists of deeply nested PAIRs of expressions that write one bit each.
108-
*
109-
* :TODO: This can be optimized by a constant factor by precomputing a table of CMRs of expressions
110-
* that, for example, write out every possible byte sequence.
111108
*/
112109
/* stack[0..7] (8 bytes) is kept as all zeros for later.
113110
* We start the stack_ptr at the second item.
114111
*/
115-
for(size_t i = 0; i < value->len; ++i) {
116-
/* stack_ptr == stack + 8*<count of the number of set bits in the value i> */
112+
if (n < 3) {
117113
stack_ptr += 8;
118-
memcpy(stack_ptr, &bit_cmr[getBit(value, i)], sizeof(uint32_t[8]));
119-
/* This inner for loop runs in ammortized constant time. */
120-
for (size_t j = i; j & 1; j = j >> 1) {
121-
sha256_midstate pair = cmrIV(PAIR);
122-
stack_ptr -= 8;
123-
sha256_compression(pair.s, stack_ptr);
124-
memcpy(stack_ptr, pair.s, sizeof(uint32_t[8]));
114+
size_t i;
115+
switch(n) {
116+
case 0: i = getBit(value, 0); break;
117+
case 1: i = 2 + ((1U * getBit(value, 0) << 1) | getBit(value, 1)); break;
118+
case 2: i = 6 + ((1U * getBit(value, 0) << 3) | (1U * getBit(value, 1) << 2) | (1U * getBit(value, 2) << 1) | getBit(value, 3)); break;
119+
}
120+
memcpy(stack_ptr, &word_cmr[i], sizeof(uint32_t[8]));
121+
} else {
122+
for (size_t i = 0; i < value->len >> 3; ++i) {
123+
/* stack_ptr == stack + 8*<count of the number of set bits in the value i> */
124+
stack_ptr += 8;
125+
memcpy(stack_ptr, &word_cmr[22 + getByte(value, 8*i)], sizeof(uint32_t[8]));
126+
/* This inner for loop runs in amortized constant time. */
127+
for (size_t j = i; j & 1; j = j >> 1) {
128+
sha256_midstate pair = cmrIV(PAIR);
129+
stack_ptr -= 8;
130+
sha256_compression(pair.s, stack_ptr);
131+
memcpy(stack_ptr, pair.s, sizeof(uint32_t[8]));
132+
}
125133
}
126134
}
127135
/* value->len is a power of 2.*/

0 commit comments

Comments
 (0)