#include "dag.h"
#include <stdbool.h>
#include "bounded.h"
#include "precomputed.h"
#include "rsort.h"
#include "sha256.h"
#include "simplicity_alloc.h"
#include "uword.h"
static sha256_midstate cmrIV(tag_t tag) {
switch (tag) {
case COMP: return cmr_compIV;
case ASSERTL:
case ASSERTR:
case CASE: return cmr_caseIV;
case PAIR: return cmr_pairIV;
case DISCONNECT: return cmr_disconnectIV;
case INJL: return cmr_injlIV;
case INJR: return cmr_injrIV;
case TAKE: return cmr_takeIV;
case DROP: return cmr_dropIV;
case IDEN: return cmr_idenIV;
case UNIT: return cmr_unitIV;
case WITNESS: return cmr_witnessIV;
case WORD:
case HIDDEN:
case JET:
break;
}
SIMPLICITY_UNREACHABLE;
}
static sha256_midstate imrIV(tag_t tag) {
return DISCONNECT == tag ? imr_disconnectIV
: WITNESS == tag ? imr_witnessIV
: cmrIV(tag);
}
static sha256_midstate amrIV(tag_t tag) {
switch (tag) {
case COMP: return amr_compIV;
case ASSERTL: return amr_assertlIV;
case ASSERTR: return amr_assertrIV;
case CASE: return amr_caseIV;
case PAIR: return amr_pairIV;
case DISCONNECT: return amr_disconnectIV;
case INJL: return amr_injlIV;
case INJR: return amr_injrIV;
case TAKE: return amr_takeIV;
case DROP: return amr_dropIV;
case IDEN: return amr_idenIV;
case UNIT: return amr_unitIV;
case WITNESS: return amr_witnessIV;
case HIDDEN:
case JET:
case WORD:
break;
}
SIMPLICITY_UNREACHABLE;
}
static sha256_midstate mkJetCMR(uint32_t *ih, uint_fast64_t weight) {
sha256_midstate result = jetIV;
uint32_t block[16] = {0};
block[6] = (uint32_t)(weight >> 32);
block[7] = (uint32_t)weight;
memcpy(&block[8], ih, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(result.s, block);
return result;
}
sha256_midstate rustsimplicity_0_6_computeWordCMR(const bitstring* value, size_t n) {
uint32_t stack[8*30] = {0};
uint32_t *stack_ptr = stack;
sha256_midstate ih = identityIV;
rustsimplicity_0_6_assert(n < 32);
rustsimplicity_0_6_assert((size_t)1 << n == value->len);
if (n < 3) {
stack_ptr += 8;
size_t i;
switch(n) {
case 0: i = getBit(value, 0); break;
case 1: i = 2 + ((1U * getBit(value, 0) << 1) | getBit(value, 1)); break;
case 2: i = 6 + ((1U * getBit(value, 0) << 3) | (1U * getBit(value, 1) << 2) | (1U * getBit(value, 2) << 1) | getBit(value, 3)); break;
}
memcpy(stack_ptr, &word_cmr[i], sizeof(uint32_t[8]));
} else {
for (size_t i = 0; i < value->len >> 3; ++i) {
stack_ptr += 8;
memcpy(stack_ptr, &word_cmr[22 + getByte(value, 8*i)], sizeof(uint32_t[8]));
for (size_t j = i; j & 1; j = j >> 1) {
sha256_midstate pair = cmrIV(PAIR);
stack_ptr -= 8;
rustsimplicity_0_6_sha256_compression(pair.s, stack_ptr);
memcpy(stack_ptr, pair.s, sizeof(uint32_t[8]));
}
}
}
rustsimplicity_0_6_assert(stack_ptr == stack + 8);
rustsimplicity_0_6_sha256_compression(ih.s, stack);
memcpy(&stack[0], word_type_root[0].s, sizeof(uint32_t[8]));
memcpy(&stack[8], word_type_root[n+1].s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(ih.s, stack);
return mkJetCMR(ih.s, ((uint_fast64_t)1 << n));
}
void rustsimplicity_0_6_computeCommitmentMerkleRoot(dag_node* dag, const uint_fast32_t i) {
uint32_t block[16] = {0};
size_t j = 8;
rustsimplicity_0_6_assert(HIDDEN != dag[i].tag);
rustsimplicity_0_6_assert(JET != dag[i].tag);
rustsimplicity_0_6_assert(WORD != dag[i].tag);
dag[i].cmr = cmrIV(dag[i].tag);
switch (dag[i].tag) {
case COMP:
case ASSERTL:
case ASSERTR:
case CASE:
case PAIR:
memcpy(block + j, dag[dag[i].child[1]].cmr.s, sizeof(uint32_t[8]));
j = 0;
case DISCONNECT:
case INJL:
case INJR:
case TAKE:
case DROP:
memcpy(block + j, dag[dag[i].child[0]].cmr.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(dag[i].cmr.s, block);
case IDEN:
case UNIT:
case WITNESS:
case HIDDEN:
case JET:
case WORD:
break;
}
}
static void computeIdentityHashRoots(sha256_midstate* ihr, const dag_node* dag, const type* type_dag, const uint_fast32_t len) {
for (size_t i = 0; i < len; ++i) {
uint32_t block[16] = {0};
size_t j = 8;
ihr[i] = HIDDEN == dag[i].tag ? dag[i].cmr
: JET == dag[i].tag ? dag[i].cmr
: WORD == dag[i].tag ? dag[i].cmr
: imrIV(dag[i].tag);
switch (dag[i].tag) {
case WITNESS:
rustsimplicity_0_6_sha256_bitstring(block, &dag[i].compactValue);
memcpy(block + 8, type_dag[WITNESS_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(ihr[i].s, block);
break;
case COMP:
case ASSERTL:
case ASSERTR:
case CASE:
case PAIR:
case DISCONNECT:
memcpy(block + j, ihr[dag[i].child[1]].s, sizeof(uint32_t[8]));
j = 0;
case INJL:
case INJR:
case TAKE:
case DROP:
memcpy(block + j, ihr[dag[i].child[0]].s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(ihr[i].s, block);
case IDEN:
case UNIT:
case HIDDEN:
case JET:
case WORD:
break;
}
}
for (size_t i = 0; i < len; ++i) {
uint32_t block[16] = {0};
if (HIDDEN == dag[i].tag) {
memcpy(block + 8, ihr[i].s, sizeof(uint32_t[8]));
ihr[i] = hiddenIV;
rustsimplicity_0_6_sha256_compression(ihr[i].s, block);
} else {
memcpy(block + 8, ihr[i].s, sizeof(uint32_t[8]));
ihr[i] = identityIV;
rustsimplicity_0_6_sha256_compression(ihr[i].s, block);
memcpy(block, type_dag[dag[i].sourceType].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[dag[i].targetType].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(ihr[i].s, block);
}
}
}
void rustsimplicity_0_6_computeAnnotatedMerkleRoot(analyses* analysis, const dag_node* dag, const type* type_dag, const uint_fast32_t len) {
for (uint_fast32_t i = 0; i < len; ++i) {
uint32_t block[16] = {0};
analysis[i].annotatedMerkleRoot = HIDDEN == dag[i].tag ? dag[i].cmr
: JET == dag[i].tag ? dag[i].cmr
: WORD == dag[i].tag ? dag[i].cmr
: amrIV(dag[i].tag);
switch (dag[i].tag) {
case ASSERTL:
case ASSERTR:
case CASE:
memcpy(block, type_dag[CASE_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8,
type_dag[CASE_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[CASE_C(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[CASE_D(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, analysis[dag[i].child[0]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, analysis[dag[i].child[1]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case DISCONNECT:
memcpy(block, type_dag[DISCONNECT_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[DISCONNECT_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[DISCONNECT_C(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[DISCONNECT_D(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, analysis[dag[i].child[0]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, analysis[dag[i].child[1]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case COMP:
memcpy(block + 8, type_dag[COMP_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[COMP_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[COMP_C(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, analysis[dag[i].child[0]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, analysis[dag[i].child[1]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case PAIR:
memcpy(block + 8, type_dag[PAIR_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[PAIR_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[PAIR_C(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, analysis[dag[i].child[0]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, analysis[dag[i].child[1]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case INJL:
case INJR:
memcpy(block, type_dag[INJ_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[INJ_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[INJ_C(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, analysis[dag[i].child[0]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case TAKE:
case DROP:
memcpy(block, type_dag[PROJ_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, type_dag[PROJ_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[PROJ_C(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
memcpy(block + 8, analysis[dag[i].child[0]].annotatedMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case IDEN:
memcpy(block + 8, type_dag[IDEN_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case UNIT:
memcpy(block + 8, type_dag[UNIT_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case WITNESS:
memcpy(block + 8, type_dag[WITNESS_A(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
memcpy(block, type_dag[WITNESS_B(dag, type_dag, i)].typeMerkleRoot.s, sizeof(uint32_t[8]));
rustsimplicity_0_6_sha256_bitstring(block + 8, &dag[i].compactValue);
rustsimplicity_0_6_sha256_compression(analysis[i].annotatedMerkleRoot.s, block);
break;
case HIDDEN:
case JET:
case WORD:
break;
}
}
}
simplicity_err rustsimplicity_0_6_verifyCanonicalOrder(dag_node* dag, const uint_fast32_t len) {
uint_fast32_t bottom = 0;
uint_fast32_t top = len-1;
if (!len) {
rustsimplicity_0_6_assert(false);
return SIMPLICITY_NO_ERROR;
}
dag[top].aux = len;
while (top < len) {
uint_fast32_t child = dag[top].child[0];
switch (dag[top].tag) {
case ASSERTL:
case ASSERTR:
case CASE:
case DISCONNECT:
case COMP:
case PAIR:
case INJL:
case INJR:
case TAKE:
case DROP:
if (bottom < child) {
dag[child].aux = top;
top = child;
continue;
}
if (bottom == child) bottom++;
case IDEN:
case UNIT:
case WITNESS:
case HIDDEN:
case JET:
case WORD:
break;
}
child = dag[top].child[1];
switch (dag[top].tag) {
case ASSERTL:
case ASSERTR:
case CASE:
case DISCONNECT:
case COMP:
case PAIR:
if (bottom < child) {
dag[child].aux = top;
top = child;
continue;
}
if (bottom == child) bottom++;
case INJL:
case INJR:
case TAKE:
case DROP:
case IDEN:
case UNIT:
case WITNESS:
case HIDDEN:
case JET:
case WORD:
break;
}
if (bottom < top) return SIMPLICITY_ERR_DATA_OUT_OF_ORDER;
if (bottom == top) bottom++;
top = dag[top].aux;
}
rustsimplicity_0_6_assert(bottom == top && top == len);
return SIMPLICITY_NO_ERROR;
}
simplicity_err rustsimplicity_0_6_fillWitnessData(dag_node* dag, type* type_dag, const uint_fast32_t len, bitstream *witness) {
static_assert(CELLS_MAX <= 0x80000000, "CELLS_MAX is too large.");
for (uint_fast32_t i = 0; i < len; ++i) {
if (WITNESS == dag[i].tag) {
if (CELLS_MAX < type_dag[WITNESS_B(dag, type_dag, i)].bitSize) return SIMPLICITY_ERR_EXEC_MEMORY;
if (witness->len <= 0) {
dag[i].compactValue = (bitstring){0};
if (type_dag[WITNESS_B(dag, type_dag, i)].bitSize) return SIMPLICITY_ERR_WITNESS_EOF;
} else {
dag[i].compactValue = (bitstring)
{ .arr = witness->arr
, .offset = witness->offset
, .len = 0
};
size_t cur = typeSkip(WITNESS_B(dag, type_dag, i), type_dag);
bool calling = true;
setTypeBack(cur, type_dag, 0);
while (cur) {
if (SUM == type_dag[cur].kind) {
rustsimplicity_0_6_assert(calling);
int32_t bit = read1Bit(witness);
if (bit < 0) return SIMPLICITY_ERR_WITNESS_EOF;
dag[i].compactValue.len++;
size_t next = typeSkip(type_dag[cur].typeArg[bit], type_dag);
if (next) {
setTypeBack(next, type_dag, type_dag[cur].back);
cur = next;
} else {
cur = type_dag[cur].back;
calling = false;
}
} else {
rustsimplicity_0_6_assert(PRODUCT == type_dag[cur].kind);
size_t next;
if (calling) {
next = typeSkip(type_dag[cur].typeArg[0], type_dag);
if (next) {
setTypeBack(next, type_dag, cur);
cur = next;
continue;
}
}
next = typeSkip(type_dag[cur].typeArg[1], type_dag);
if (next) {
setTypeBack(next, type_dag, type_dag[cur].back);
cur = next;
calling = true;
} else {
cur = type_dag[cur].back;
calling = false;
}
}
}
}
}
}
return SIMPLICITY_NO_ERROR;
}
simplicity_err rustsimplicity_0_6_verifyNoDuplicateIdentityHashes(sha256_midstate* ihr, const dag_node* dag, const type* type_dag, const uint_fast32_t dag_len) {
rustsimplicity_0_6_assert(0 < dag_len);
rustsimplicity_0_6_assert(dag_len <= DAG_LEN_MAX);
sha256_midstate* ih_buf = rustsimplicity_0_6_malloc((size_t)dag_len * sizeof(sha256_midstate));
if (!ih_buf) return SIMPLICITY_ERR_MALLOC;
computeIdentityHashRoots(ih_buf, dag, type_dag, dag_len);
if (ihr) *ihr = ih_buf[dag_len-1];
int result = rustsimplicity_0_6_hasDuplicates(ih_buf, dag_len);
rustsimplicity_0_6_free(ih_buf);
switch (result) {
case -1: return SIMPLICITY_ERR_MALLOC;
case 0: return SIMPLICITY_NO_ERROR;
default: return SIMPLICITY_ERR_UNSHARED_SUBEXPRESSION;
}
}