#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <getopt.h>
#include <simplicity/elements/exec.h>
#include <simplicity/elements/cmr.h>
#include "ctx8Pruned.h"
#include "ctx8Unpruned.h"
#include "dag.h"
#include "deserialize.h"
#include "eval.h"
#include "hashBlock.h"
#include "rsort.h"
#include "sha256.h"
#include "schnorr0.h"
#include "schnorr6.h"
#include "regression4.h"
#include "typeSkipTest.h"
#include "simplicity_alloc.h"
#include "typeInference.h"
#include "elements/checkSigHashAllTx1.h"
#include "elements/primitive.h"
_Static_assert(CHAR_BIT == 8, "Buffers passed to fmemopen presume 8 bit chars");
static const double secondsPerWU = 1 / 1000. / 1000.;
static int successes = 0;
static int failures = 0;
#ifdef TIMING_FLAG
static int timing_flag = 1;
#else
static int timing_flag = 0;
#endif
static void fprint_cmr(FILE* stream, const uint32_t* cmr) {
fprintf(stream, "0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
cmr[0], cmr[1], cmr[2], cmr[3], cmr[4], cmr[5], cmr[6], cmr[7]
);
}
static void test_decodeUptoMaxInt(void) {
printf("Test decodeUptoMaxInt\n");
const unsigned char buf[] =
{ 0x4b, 0x86, 0x39, 0xe8, 0xdf, 0xc0, 0x38, 0x0f, 0x7f, 0xff, 0xff, 0x00
, 0x00, 0x00, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x3c, 0x3b, 0xff, 0xff, 0xff
, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00
};
const int32_t expected[] =
{ 1, 2, 3, 4, 5, 7, 8, 15, 16, 17
, 0xffff, 0x10000, 0x40000000, 0x7fffffff, SIMPLICITY_ERR_DATA_OUT_OF_RANGE
};
bitstream stream = initializeBitstream(buf, sizeof(buf));
for (size_t i = 0; i < sizeof(expected)/sizeof(expected[0]); ++i) {
int32_t result = rustsimplicity_0_6_decodeUptoMaxInt(&stream);
if (expected[i] == result) {
successes++;
} else {
failures++;
printf("Unexpected result during parsing. Expected %d and received %d\n", expected[i], result);
}
}
}
static void test_hashBlock(void) {
printf("Test hashBlock\n");
dag_node* dag;
combinator_counters census;
int_fast32_t len;
simplicity_err error;
{
bitstream stream = initializeBitstream(hashBlock, sizeof_hashBlock);
len = rustsimplicity_0_6_decodeMallocDag(&dag, rustsimplicity_0_6_elements_decodeJet, &census, &stream);
if (!dag) {
rustsimplicity_0_6_assert(len < 0);
error = (simplicity_err)len;
failures++;
printf("Error parsing dag: %d\n", error);
} else {
rustsimplicity_0_6_assert(0 < len);
error = rustsimplicity_0_6_closeBitstream(&stream);
if (!IS_OK(error)) {
failures++;
printf("Error closing dag stream for hashblock\n");
}
}
}
if (dag && IS_OK(error)) {
successes++;
if (0 == memcmp(hashBlock_cmr, dag[len-1].cmr.s, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected CMR of hashblock\n");
}
type* type_dag;
bitstream witness = initializeBitstream(hashBlock_witness, sizeof_hashBlock_witness);
if (!IS_OK(rustsimplicity_0_6_mallocTypeInference(&type_dag, rustsimplicity_0_6_elements_mallocBoundVars, dag, (uint_fast32_t)len, &census)) || !type_dag ||
type_dag[dag[len-1].sourceType].bitSize != 768 || type_dag[dag[len-1].targetType].bitSize != 256) {
failures++;
printf("Unexpected failure of type inference for hashblock\n");
} else if (!IS_OK(rustsimplicity_0_6_fillWitnessData(dag, type_dag, (uint_fast32_t)len, &witness))) {
failures++;
printf("Unexpected failure of fillWitnessData for hashblock\n");
} else if (!IS_OK(rustsimplicity_0_6_closeBitstream(&witness))) {
failures++;
printf("Unexpected failure of witness stream for hashblock\n");
} else {
{
analyses analysis[len];
rustsimplicity_0_6_computeAnnotatedMerkleRoot(analysis, dag, type_dag, (uint_fast32_t)len);
if (0 == memcmp(hashBlock_amr, analysis[len-1].annotatedMerkleRoot.s, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected AMR of hashblock\n");
}
}
{
sha256_midstate ihr;
if (IS_OK(rustsimplicity_0_6_verifyNoDuplicateIdentityHashes(&ihr, dag, type_dag, (uint_fast32_t)len)) &&
0 == memcmp(hashBlock_ihr, ihr.s, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected IHR of hashblock\n");
}
}
ubounded inputBitSize = type_dag[dag[len-1].sourceType].bitSize;
ubounded outputBitSize = type_dag[dag[len-1].targetType].bitSize;
UWORD input[ROUND_UWORD(inputBitSize)];
UWORD output[ROUND_UWORD(outputBitSize)];
{ frameItem frame = initWriteFrame(inputBitSize, &input[ROUND_UWORD(inputBitSize)]);
rustsimplicity_0_6_assert(256+512 == inputBitSize);
write32s(&frame, (uint32_t[8])
{ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 }
, 8);
write32s(&frame, (uint32_t[16]){ [0] = 0x61626380, [15] = 0x18 }, 16);
}
{
ubounded cellsBound, UWORDBound, frameBound, costBound;
if (IS_OK(rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len))
&& hashBlock_cost == costBound) {
successes++;
} else {
failures++;
printf("Expected %d for cost, but got %d instead.\n", hashBlock_cost, costBound);
}
}
simplicity_err err = rustsimplicity_0_6_evalTCOExpression(CHECK_NONE, output, input, dag, type_dag, (uint_fast32_t)len, 0, NULL, NULL);
if (IS_OK(err)) {
const uint32_t expectedHash[8] = { 0xba7816bful, 0x8f01cfeaul, 0x414140deul, 0x5dae2223ul
, 0xb00361a3ul, 0x96177a9cul, 0xb410ff61ul, 0xf20015adul };
frameItem frame = initReadFrame(outputBitSize, &output[0]);
uint32_t result[8];
rustsimplicity_0_6_assert(256 == outputBitSize);
read32s(result, 8, &frame);
if (0 == memcmp(expectedHash, result, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected output of hashblock computation.\n");
}
} else {
failures++;
printf("Unexpected failure of hashblock evaluation: %d\n", err);
}
}
rustsimplicity_0_6_free(type_dag);
}
rustsimplicity_0_6_free(dag);
}
static void test_program(char* name, const unsigned char* program, size_t program_len, const unsigned char* witness, size_t witness_len,
simplicity_err expectedResult, const uint32_t* expectedCMR,
const uint32_t* expectedIHR, const uint32_t* expectedAMR, const ubounded *expectedCost) {
printf("Test %s\n", name);
dag_node* dag;
combinator_counters census;
int_fast32_t len;
simplicity_err error;
{
bitstream stream = initializeBitstream(program, program_len);
len = rustsimplicity_0_6_decodeMallocDag(&dag, rustsimplicity_0_6_elements_decodeJet, &census, &stream);
if (!dag) {
rustsimplicity_0_6_assert(len < 0);
error = (simplicity_err)len;
failures++;
printf("Error parsing dag: %d\n", error);
} else {
rustsimplicity_0_6_assert(0 < len);
error = rustsimplicity_0_6_closeBitstream(&stream);
if (!IS_OK(error)) {
if (expectedResult == error) {
successes++;
} else {
failures++;
printf("Error closing dag stream: %d\n", error);
}
}
}
}
if (dag && IS_OK(error)) {
successes++;
if (expectedCMR) {
if (0 == memcmp(expectedCMR, dag[len-1].cmr.s, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected CMR. Expected\n{");
fprint_cmr(stdout, expectedCMR);
printf("}, but received\n{");
fprint_cmr(stdout, dag[len-1].cmr.s);
printf("}\n");
}
}
type* type_dag;
bitstream witness_stream = initializeBitstream(witness, witness_len);
if (!IS_OK(rustsimplicity_0_6_mallocTypeInference(&type_dag, rustsimplicity_0_6_elements_mallocBoundVars, dag, (uint_fast32_t)len, &census)) || !type_dag ||
dag[len-1].sourceType != 0 || dag[len-1].targetType != 0) {
failures++;
printf("Unexpected failure of type inference.\n");
} else if (!IS_OK(rustsimplicity_0_6_fillWitnessData(dag, type_dag, (uint_fast32_t)len, &witness_stream))) {
failures++;
printf("Unexpected failure of fillWitnessData.\n");
} else if (!IS_OK(rustsimplicity_0_6_closeBitstream(&witness_stream))) {
failures++;
printf("Unexpected failure closing witness_stream\n");
} else {
if (expectedAMR) {
analyses analysis[len];
rustsimplicity_0_6_computeAnnotatedMerkleRoot(analysis, dag, type_dag, (uint_fast32_t)len);
if (0 == memcmp(expectedAMR, analysis[len-1].annotatedMerkleRoot.s, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected AMR.\n");
}
}
{
sha256_midstate ihr;
if (IS_OK(rustsimplicity_0_6_verifyNoDuplicateIdentityHashes(&ihr, dag, type_dag, (uint_fast32_t)len)) &&
(!expectedIHR || 0 == memcmp(expectedIHR, ihr.s, sizeof(uint32_t[8])))) {
successes++;
} else {
failures++;
printf("Unexpected IHR.\n");
}
}
if (expectedCost) {
ubounded cellsBound, UWORDBound, frameBound, costBound;
if (IS_OK(rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len))
&& 0 < costBound
&& *expectedCost == costBound) {
successes++;
} else {
failures++;
printf("Expected %u for cost, but got %u instead.\n", *expectedCost, costBound);
}
if (IS_OK(rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, cellsBound, costBound-1, costBound, dag, type_dag, (uint_fast32_t)len))
&& *expectedCost == costBound) {
successes++;
} else {
failures++;
printf("Analysis with computed bounds failed.\n");
}
if (0 < cellsBound) {
if (SIMPLICITY_ERR_EXEC_MEMORY == rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, cellsBound-1, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len)) {
successes++;
} else {
failures++;
printf("Analysis with too small cells bounds failed. \n");
}
}
if (0 < *expectedCost &&
SIMPLICITY_ERR_EXEC_BUDGET == rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, *expectedCost-1, dag, type_dag, (uint_fast32_t)len)
) {
successes++;
} else {
failures++;
printf("Analysis with too small cost bounds failed.\n");
}
if (0 < *expectedCost &&
SIMPLICITY_ERR_OVERWEIGHT == rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, *expectedCost, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len)
) {
successes++;
} else {
failures++;
printf("Analysis with too large minCost failed.\n");
}
}
simplicity_err actualResult = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, 0, NULL, NULL);
if (expectedResult == actualResult) {
successes++;
} else {
failures++;
printf("Expected %d from evaluation, but got %d instead.\n", expectedResult, actualResult);
}
}
rustsimplicity_0_6_free(type_dag);
}
rustsimplicity_0_6_free(dag);
}
static void test_occursCheck(void) {
printf("Test occursCheck\n");
const unsigned char buf[] = { 0xc1, 0x07, 0x20, 0x30 };
dag_node* dag;
combinator_counters census;
int_fast32_t len;
{
bitstream stream = initializeBitstream(buf, sizeof(buf));
len = rustsimplicity_0_6_decodeMallocDag(&dag, rustsimplicity_0_6_elements_decodeJet, &census, &stream);
}
if (!dag) {
rustsimplicity_0_6_assert(len < 0);
printf("Error parsing dag: %" PRIdFAST32 "\n", len);
} else {
type* type_dag;
rustsimplicity_0_6_assert(0 < len);
if (SIMPLICITY_ERR_TYPE_INFERENCE_OCCURS_CHECK == rustsimplicity_0_6_mallocTypeInference(&type_dag, rustsimplicity_0_6_elements_mallocBoundVars, dag, (uint_fast32_t)len, &census) &&
!type_dag) {
successes++;
} else {
printf("Unexpected occurs check success\n");
failures++;
}
rustsimplicity_0_6_free(type_dag);
}
rustsimplicity_0_6_free(dag);
}
static void test_elements(void) {
unsigned char cmr[32], amr[32];
sha256_fromMidstate(cmr, elementsCheckSigHashAllTx1_cmr);
sha256_fromMidstate(amr, elementsCheckSigHashAllTx1_amr);
unsigned char genesisHash[32] = "\x0f\x91\x88\xf1\x3c\xb7\xb2\xc7\x1f\x2a\x33\x5e\x3a\x4f\xc3\x28\xbf\x5b\xeb\x43\x60\x12\xaf\xca\x59\x0b\x1a\x11\x46\x6e\x22\x06";
rawElementsTapEnv rawTaproot = (rawElementsTapEnv)
{ .controlBlock = (unsigned char [33]){"\xbe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3b\x78\xce\x56\x3f\x89\xa0\xed\x94\x14\xf5\xaa\x28\xad\x0d\x96\xd6\x79\x5f\x9c\x63"}
, .pathLen = 0
, .scriptCMR = cmr
};
elementsTapEnv* taproot = rustsimplicity_0_6_elements_mallocTapEnv(&rawTaproot);
printf("Test elements\n");
{
rawElementsTransaction testTx1 = (rawElementsTransaction)
{ .txid = (unsigned char[32]){"\xdb\x9a\x3d\xe0\xb6\xb8\xcc\x74\x1e\x4d\x6c\x8f\x19\xce\x75\xec\x0d\xfd\x01\x02\xdb\x9c\xb5\xcd\x27\xa4\x1a\x66\x91\x66\x3a\x07"}
, .input = (rawElementsInput[])
{ { .annex = NULL
, .prevTxid = (unsigned char[32]){"\xeb\x04\xb6\x8e\x9a\x26\xd1\x16\x04\x6c\x76\xe8\xff\x47\x33\x2f\xb7\x1d\xda\x90\xff\x4b\xef\x53\x70\xf2\x52\x26\xd3\xbc\x09\xfc"}
, .prevIx = 0
, .sequence = 0xfffffffe
, .issuance = {0}
, .scriptSig = {0}
, .txo = { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xe4\x00"}
, .scriptPubKey = {0}
} } }
, .output = (rawElementsOutput[])
{ { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xd7\x1c"}
, .nonce = NULL
, .scriptPubKey = { .buf = (unsigned char [26]){"\x19\x76\xa9\x14\x48\x63\x3e\x2c\x0e\xe9\x49\x5d\xd3\xf9\xc4\x37\x32\xc4\x7f\x47\x02\xa3\x62\xc8\x88\xac"}
, .len = 26
}
}
, { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x00\x00\x00\x0c\xe4"}
, .nonce = NULL
, .scriptPubKey = {0}
} }
, .numInputs = 1
, .numOutputs = 2
, .version = 0x00000002
, .lockTime = 0x00000000
};
elementsTransaction* tx1 = rustsimplicity_0_6_elements_mallocTransaction(&testTx1);
if (tx1) {
successes++;
simplicity_err execResult;
{
unsigned char cmrResult[32];
if (rustsimplicity_0_6_elements_computeCmr(&execResult, cmrResult, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1) && IS_OK(execResult)) {
if (0 == memcmp(cmrResult, cmr, sizeof(unsigned char[8]))) {
successes++;
} else {
failures++;
printf("Unexpected CMR of elementsCheckSigHashAllTx1\n");
}
} else {
failures++;
printf("rustsimplicity_0_6_elements_computeCmr of elementsCheckSigHashAllTx1 unexpectedly produced %d.\n", execResult);
}
}
{
unsigned char ihrResult[32];
if (rustsimplicity_0_6_elements_execSimplicity(&execResult, ihrResult, tx1, 0, taproot, genesisHash, 0, (elementsCheckSigHashAllTx1_cost + 999)/1000, amr, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && IS_OK(execResult)) {
sha256_midstate ihr;
sha256_toMidstate(ihr.s, ihrResult);
if (0 == memcmp(ihr.s, elementsCheckSigHashAllTx1_ihr, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Unexpected IHR of elementsCheckSigHashAllTx1\n");
}
} else {
failures++;
printf("execSimplicity of elementsCheckSigHashAllTx1 on tx1 unexpectedly produced %d.\n", execResult);
}
if (elementsCheckSigHashAllTx1_cost){
rustsimplicity_0_6_assert(elementsCheckSigHashAllTx1_cost);
if (rustsimplicity_0_6_elements_execSimplicity(&execResult, ihrResult, tx1, 0, taproot, genesisHash, 0, (elementsCheckSigHashAllTx1_cost - 1)/1000, amr, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_BUDGET == execResult) {
successes++;
} else {
failures++;
printf("execSimplicity of elementsCheckSigHashAllTx1 on tx1 unexpectedly produced %d.\n", execResult);
}
}
}
{
unsigned char brokenSig[sizeof_elementsCheckSigHashAllTx1_witness];
memcpy(brokenSig, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness);
brokenSig[sizeof_elementsCheckSigHashAllTx1_witness - 1] ^= 0x80;
if (rustsimplicity_0_6_elements_execSimplicity(&execResult, NULL, tx1, 0, taproot, genesisHash, 0, BUDGET_MAX, NULL, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, brokenSig, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_JET == execResult) {
successes++;
} else {
failures++;
printf("execSimplicity of brokenSig on tx1 unexpectedly produced %d.\n", execResult);
}
}
} else {
printf("mallocTransaction(&rawTx1) failed\n");
failures++;
}
rustsimplicity_0_6_elements_freeTransaction(tx1);
}
{
rawElementsTransaction testTx2 = (rawElementsTransaction)
{ .txid = (unsigned char[32]){"\xdb\x9a\x3d\xe0\xb6\xb8\xcc\x74\x1e\x4d\x6c\x8f\x19\xce\x75\xec\x0d\xfd\x01\x02\xdb\x9c\xb5\xcd\x27\xa4\x1a\x66\x91\x66\x3a\x07"}
, .input = (rawElementsInput[])
{ { .prevTxid = (unsigned char[32]){"\xeb\x04\xb6\x8e\x9a\x26\xd1\x16\x04\x6c\x76\xe8\xff\x47\x33\x2f\xb7\x1d\xda\x90\xff\x4b\xef\x53\x70\xf2\x52\x26\xd3\xbc\x09\xfc"}
, .prevIx = 0
, .sequence = 0xffffffff
, .issuance = {0}
, .txo = { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xe4\x00"}
, .scriptPubKey = {0}
} } }
, .output = (rawElementsOutput[])
{ { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xd7\x1c"}
, .nonce = NULL
, .scriptPubKey = { .buf = (unsigned char [26]){"\x19\x76\xa9\x14\x48\x63\x3e\x2c\x0e\xe9\x49\x5d\xd3\xf9\xc4\x37\x32\xc4\x7f\x47\x02\xa3\x62\xc8\x88\xac"}
, .len = 26
}
}
, { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x00\x00\x00\x0c\xe4"}
, .nonce = NULL
, .scriptPubKey = {0}
} }
, .numInputs = 1
, .numOutputs = 2
, .version = 0x00000002
, .lockTime = 0x00000000
};
elementsTransaction* tx2 = rustsimplicity_0_6_elements_mallocTransaction(&testTx2);
if (tx2) {
successes++;
simplicity_err execResult;
{
if (rustsimplicity_0_6_elements_execSimplicity(&execResult, NULL, tx2, 0, taproot, genesisHash, 0, BUDGET_MAX, NULL, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_JET == execResult) {
successes++;
} else {
failures++;
printf("execSimplicity of elementsCheckSigHashAllTx1 on tx2 unexpectedly produced %d.\n", execResult);
}
}
} else {
printf("mallocTransaction(&testTx2) failed\n");
failures++;
}
rustsimplicity_0_6_elements_freeTransaction(tx2);
}
rustsimplicity_0_6_elements_freeTapEnv(taproot);
}
static sha256_midstate hashint(uint_fast32_t n) {
sha256_midstate result;
sha256_context ctx = sha256_init(result.s);
sha256_u32le(&ctx, n);
sha256_finalize(&ctx);
return result;
}
static sha256_midstate rsort_no_duplicates(uint_fast32_t i) {
return hashint(i);
}
static sha256_midstate rsort_all_duplicates(uint_fast32_t i) {
(void)i;
return hashint(0);
}
static sha256_midstate rsort_one_duplicate(uint_fast32_t i) {
return hashint(i ? i : 1);
}
static sha256_midstate rsort_diagonal(uint_fast32_t i) {
sha256_midstate result = {0};
unsigned char *alias = (unsigned char *)(result.s);
for (uint_fast32_t j = 0; j < sizeof(result.s); ++j) {
alias[j] = j == i ? 0 : 0xff;
}
return result;
}
static void test_hasDuplicates(const char* name, int expected, sha256_midstate (*f)(uint_fast32_t), uint_fast32_t n) {
sha256_midstate hashes[n];
printf("Test %s\n", name);
for(uint_fast32_t i = 0; i < n; ++i) {
hashes[i] = f(i);
}
int actual = rustsimplicity_0_6_hasDuplicates(hashes, n);
if (expected == actual) {
successes++;
} else if (actual < 0) {
failures++;
printf("Unexpected failure of hasDuplicates\n");
} else if (0 == expected) {
failures++;
printf("Expected no duplicate but found some.\n");
} else {
failures++;
printf("Expected duplicates but found none.\n");
}
}
static void regression_tests(void) {
{
size_t sizeof_regression3 = ((size_t)1 << 20) + 4;
unsigned char *regression3 = rustsimplicity_0_6_calloc(sizeof_regression3, 1);
clock_t start, end;
double diff, bound;
const uint32_t cmr[] = {
0x872d12eeu, 0x631ae2e7u, 0xffb8b06au, 0xc54ef77fu, 0x693adbffu, 0xb229e760u, 0x111b8fd9u, 0x13d88b7au
};
rustsimplicity_0_6_assert(regression3);
regression3[0] = 0xb7; regression3[1] = 0x08;
regression3[sizeof_regression3 - 2] = 0x48; regression3[sizeof_regression3 - 1] = 0x20;
start = clock();
test_program("regression3", regression3, sizeof_regression3, NULL, 0, SIMPLICITY_ERR_EXEC_MEMORY, cmr, NULL, NULL, NULL);
end = clock();
diff = (double)(end - start) / CLOCKS_PER_SEC;
bound = (double)(sizeof_regression3) * secondsPerWU;
printf("cpu_time_used by regression3: %f s. (Should be less than %f s.)\n", diff, bound);
if (timing_flag) {
if (diff <= bound) {
successes++;
} else {
failures++;
printf("regression3 took too long.\n");
}
}
rustsimplicity_0_6_free(regression3);
}
{
clock_t start, end;
double diff, bound;
start = clock();
test_program("regression4", regression4, sizeof_regression4, NULL, 0, SIMPLICITY_NO_ERROR, NULL, NULL, NULL, NULL);
end = clock();
diff = (double)(end - start) / CLOCKS_PER_SEC;
bound = (double)(sizeof_regression4) * secondsPerWU;
printf("cpu_time_used by regression4: %f s. (Should be less than %f s.)\n", diff, bound);
if (timing_flag) {
if (diff <= bound) {
successes++;
} else {
failures++;
printf("regression4 took too long.\n");
}
}
}
}
static void iden8mebi_test(void) {
const unsigned char iden8mebi[23] = {0xe1, 0x08};
const ubounded expectedCost = 1677721500;
clock_t start, end;
double diff, bound;
start = clock();
test_program("iden8mebi", iden8mebi, sizeof(iden8mebi), NULL, 0, SIMPLICITY_NO_ERROR, NULL, NULL, NULL, &expectedCost);
end = clock();
diff = (double)(end - start) / CLOCKS_PER_SEC;
bound = (double)expectedCost / 1000. * secondsPerWU;
printf("cpu_time_used by iden8mebi: %f s. (Should be less than %f s.)\n", diff, bound);
if (timing_flag) {
if (diff <= bound) {
successes++;
} else {
failures++;
printf("iden8mebi took too long.\n");
}
}
}
static void exactBudget_test(void) {
const unsigned char program[] = {
0xe0, 0x09, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, 0x02,
0x05, 0xb4, 0x6d, 0xa0, 0x80
};
const ubounded expectedCost = 410;
printf("Test exactBudget\n");
dag_node* dag;
type* type_dag;
combinator_counters census;
int_fast32_t len;
simplicity_err error, expected;
sha256_midstate ihr;
{
bitstream stream = initializeBitstream(program, sizeof(program));
len = rustsimplicity_0_6_decodeMallocDag(&dag, rustsimplicity_0_6_elements_decodeJet, &census, &stream);
rustsimplicity_0_6_assert(dag);
rustsimplicity_0_6_assert(0 < len);
error = rustsimplicity_0_6_closeBitstream(&stream);
rustsimplicity_0_6_assert(IS_OK(error));
}
error = rustsimplicity_0_6_mallocTypeInference(&type_dag, rustsimplicity_0_6_elements_mallocBoundVars, dag, (uint_fast32_t)len, &census);
rustsimplicity_0_6_assert(IS_OK(error));
rustsimplicity_0_6_assert(type_dag);
rustsimplicity_0_6_assert(!dag[len-1].sourceType);
rustsimplicity_0_6_assert(!dag[len-1].targetType);
{
bitstream stream = initializeBitstream(NULL, 0);
error = rustsimplicity_0_6_fillWitnessData(dag, type_dag, (uint_fast32_t)len, &stream);
rustsimplicity_0_6_assert(IS_OK(error));
}
error = rustsimplicity_0_6_verifyNoDuplicateIdentityHashes(&ihr, dag, type_dag, (uint_fast32_t)len);
rustsimplicity_0_6_assert(IS_OK(error));
{
ubounded cellsBound, UWORDBound, frameBound, costBound;
error = rustsimplicity_0_6_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len);
rustsimplicity_0_6_assert(IS_OK(error));
rustsimplicity_0_6_assert(1000*expectedCost == costBound);
}
error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost, &expectedCost, NULL);
expected = SIMPLICITY_ERR_OVERWEIGHT;
if (expected == error) {
successes++;
} else {
failures++;
printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
}
error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost-1, &(ubounded){expectedCost-1}, NULL);
expected = SIMPLICITY_ERR_EXEC_BUDGET;
if (expected == error) {
successes++;
} else {
failures++;
printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
}
error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost, &(ubounded){expectedCost+1}, NULL);
expected = SIMPLICITY_ERR_OVERWEIGHT;
if (expected == error) {
successes++;
} else {
failures++;
printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
}
error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost-1, &expectedCost, NULL);
expected = SIMPLICITY_NO_ERROR;
if (expected == error) {
successes++;
} else {
failures++;
printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
}
rustsimplicity_0_6_free(type_dag);
rustsimplicity_0_6_free(dag);
}
int main(int argc, char **argv) {
while (true) {
static struct option long_options[] = {
{"timing", no_argument, &timing_flag, 1},
{"no-timing", no_argument, &timing_flag, 0},
{0, 0, 0, 0}
};
int opt_result = getopt_long(argc, argv, "", long_options, NULL);
if (-1 == opt_result) break;
if (0 == opt_result) continue;
exit(EXIT_FAILURE);
}
if (rustsimplicity_0_6_sha256_compression_is_optimized()) {
printf("Sha optimization enabled.\n");
if (timing_flag) {
printf("Timings are checked.\n");
} else {
printf("Timings not checked.\n");
}
} else {
printf("Sha optimization disabled.\n");
if (timing_flag) {
printf("Timings cannot be checked.\n");
} else {
printf("Timings not checked.\n");
}
timing_flag = 0;
}
test_decodeUptoMaxInt();
test_hashBlock();
test_occursCheck();
test_hasDuplicates("hasDuplicates no duplicates testcase", 0, rsort_no_duplicates, 10000);
test_hasDuplicates("hasDuplicates all duplicates testcase", 1, rsort_all_duplicates, 10000);
test_hasDuplicates("hasDuplicates one duplicate testcase", 1, rsort_one_duplicate, 10000);
test_hasDuplicates("hasDuplicates diagonal testcase", 0, rsort_diagonal, 33);
test_program("ctx8Pruned", ctx8Pruned, sizeof_ctx8Pruned, ctx8Pruned_witness, sizeof_ctx8Pruned_witness, SIMPLICITY_NO_ERROR, ctx8Pruned_cmr, ctx8Pruned_ihr, ctx8Pruned_amr, &ctx8Pruned_cost);
test_program("ctx8Unpruned", ctx8Unpruned, sizeof_ctx8Unpruned, ctx8Unpruned_witness, sizeof_ctx8Unpruned_witness, SIMPLICITY_ERR_ANTIDOS, ctx8Unpruned_cmr, ctx8Unpruned_ihr, ctx8Unpruned_amr, &ctx8Unpruned_cost);
if (0 == memcmp(ctx8Pruned_cmr, ctx8Unpruned_cmr, sizeof(uint32_t[8]))) {
successes++;
} else {
failures++;
printf("Pruned and Unpruned CMRs are not the same.\n");
}
test_program("schnorr0", schnorr0, sizeof_schnorr0, schnorr0_witness, sizeof_schnorr0_witness, SIMPLICITY_NO_ERROR, schnorr0_cmr, schnorr0_ihr, schnorr0_amr, &schnorr0_cost);
test_program("schnorr6", schnorr6, sizeof_schnorr6, schnorr6_witness, sizeof_schnorr6_witness, SIMPLICITY_ERR_EXEC_JET, schnorr6_cmr, schnorr6_ihr, schnorr6_amr, &schnorr0_cost);
test_program("typeSkipTest", typeSkipTest, sizeof_typeSkipTest, typeSkipTest_witness, sizeof_typeSkipTest_witness, SIMPLICITY_NO_ERROR, NULL, NULL, NULL, NULL);
test_elements();
exactBudget_test();
regression_tests();
iden8mebi_test();
printf("Successes: %d\n", successes);
printf("Failures: %d\n", failures);
return (0 == failures) ? EXIT_SUCCESS : EXIT_FAILURE;
}