diff --git a/C/Makefile b/C/Makefile index 2bc9cb60b..5d8ea64d2 100644 --- a/C/Makefile +++ b/C/Makefile @@ -1,4 +1,4 @@ -OBJS := bitstream.o dag.o deserialize.o eval.o frame.o jets.o jets-secp256k1.o rsort.o sha256.o type.o typeInference.o primitive/elements/env.o primitive/elements/exec.o primitive/elements/ops.o primitive/elements/jets.o primitive/elements/primitive.o primitive/elements/cmr.o +OBJS := bitstream.o dag.o deserialize.o eval.o frame.o jets.o jets-secp256k1.o rsort.o sha256.o type.o typeInference.o primitive/elements/env.o primitive/elements/exec.o primitive/elements/ops.o primitive/elements/jets.o primitive/elements/primitive.o primitive/elements/cmr.o primitive/elements/txEnv.o TEST_OBJS := test.o ctx8Pruned.o ctx8Unpruned.o hashBlock.o regression4.o schnorr0.o schnorr6.o typeSkipTest.o primitive/elements/checkSigHashAllTx1.o # From https://fastcompression.blogspot.com/2019/01/compiler-warnings.html diff --git a/C/deserialize.c b/C/deserialize.c index d65c0d5c5..182f23ba1 100644 --- a/C/deserialize.c +++ b/C/deserialize.c @@ -2,7 +2,6 @@ #include #include "limitations.h" -#include "primitive.h" #include "simplicity_alloc.h" #include "simplicity_assert.h" @@ -55,7 +54,7 @@ static simplicity_err getHash(sha256_midstate* result, bitstream* stream) { * i < 2^31 - 1 * NULL != stream */ -static simplicity_err decodeNode(dag_node* dag, uint_fast32_t i, bitstream* stream) { +static simplicity_err decodeNode(dag_node* dag, simplicity_callback_decodeJet decodeJet, uint_fast32_t i, bitstream* stream) { int32_t bit = read1Bit(stream); if (bit < 0) return (simplicity_err)bit; dag[i] = (dag_node){0}; @@ -63,7 +62,7 @@ static simplicity_err decodeNode(dag_node* dag, uint_fast32_t i, bitstream* stre bit = read1Bit(stream); if (bit < 0) return (simplicity_err)bit; if (bit) { - return simplicity_decodeJet(&dag[i], stream); + return decodeJet(&dag[i], stream); } else { /* Decode WORD. */ int32_t depth = simplicity_decodeUptoMaxInt(stream); @@ -153,9 +152,9 @@ static simplicity_err decodeNode(dag_node* dag, uint_fast32_t i, bitstream* stre * len < 2^31 * NULL != stream */ -static simplicity_err decodeDag(dag_node* dag, const uint_fast32_t len, combinator_counters* census, bitstream* stream) { +static simplicity_err decodeDag(dag_node* dag, simplicity_callback_decodeJet decodeJet, const uint_fast32_t len, combinator_counters* census, bitstream* stream) { for (uint_fast32_t i = 0; i < len; ++i) { - simplicity_err error = decodeNode(dag, i, stream); + simplicity_err error = decodeNode(dag, decodeJet, i, stream); if (!IS_OK(error)) return error; enumerator(census, dag[i].tag); @@ -186,7 +185,7 @@ static simplicity_err decodeDag(dag_node* dag, const uint_fast32_t len, combinat * of the function is positive and when NULL != census; * NULL == *dag when the return value is negative. */ -int_fast32_t simplicity_decodeMallocDag(dag_node** dag, combinator_counters* census, bitstream* stream) { +int_fast32_t simplicity_decodeMallocDag(dag_node** dag, simplicity_callback_decodeJet decodeJet, combinator_counters* census, bitstream* stream) { *dag = NULL; int32_t dagLen = simplicity_decodeUptoMaxInt(stream); if (dagLen <= 0) return dagLen; @@ -199,7 +198,7 @@ int_fast32_t simplicity_decodeMallocDag(dag_node** dag, combinator_counters* cen if (!*dag) return SIMPLICITY_ERR_MALLOC; if (census) *census = (combinator_counters){0}; - simplicity_err error = decodeDag(*dag, (uint_fast32_t)dagLen, census, stream); + simplicity_err error = decodeDag(*dag, decodeJet, (uint_fast32_t)dagLen, census, stream); if (IS_OK(error)) { error = HIDDEN == (*dag)[dagLen - 1].tag diff --git a/C/deserialize.h b/C/deserialize.h index d20561b01..dd5515d3c 100644 --- a/C/deserialize.h +++ b/C/deserialize.h @@ -6,6 +6,18 @@ #include "bitstream.h" #include "dag.h" +/* Decode an application specific jet from 'stream' into 'node'. + * All jets begin with a bit prefix of '1' which needs to have already been consumed from the 'stream'. + * Returns 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' if the stream's prefix doesn't match any valid code for a jet. + * Returns 'SIMPLICITY_ERR_BITSTRING_EOF' if not enough bits are available in the 'stream'. + * In the above error cases, 'dag' may be modified. + * Returns 'SIMPLICITY_NO_ERROR' if successful. + * + * Precondition: NULL != node + * NULL != stream + */ +typedef simplicity_err (*simplicity_callback_decodeJet)(dag_node* node, bitstream* stream); + /* Decode a length-prefixed Simplicity DAG from 'stream'. * Returns 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' the length prefix's value is too large. * Returns 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' if some node's child isn't a reference to one of the preceding nodes. @@ -28,6 +40,6 @@ * of the function is positive and when NULL != census; * NULL == *dag when the return value is negative. */ -int_fast32_t simplicity_decodeMallocDag(dag_node** dag, combinator_counters* census, bitstream* stream); +int_fast32_t simplicity_decodeMallocDag(dag_node** dag, simplicity_callback_decodeJet decodeJet, combinator_counters* census, bitstream* stream); #endif diff --git a/C/elements-sources.mk b/C/elements-sources.mk index 9737dc712..f0a2bcc24 100644 --- a/C/elements-sources.mk +++ b/C/elements-sources.mk @@ -29,6 +29,7 @@ ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/exec.c ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/jets.c ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/ops.c ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/primitive.c +ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/txEnv.c ELEMENTS_SIMPLICITY_LIB_HEADERS_INT = ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/bitstream.h @@ -42,7 +43,6 @@ ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/frame.h ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/jets.h ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/limitations.h ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/precomputed.h -ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive.h ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/rsort.h ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/sha256.h ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/sha256_x86.inc @@ -97,3 +97,4 @@ ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/primitiveEnum ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/primitiveEnumTy.inc ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/primitiveInitTy.inc ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/primitiveJetNode.inc +ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/txEnv.h diff --git a/C/primitive.h b/C/primitive.h deleted file mode 100644 index dc17fb0b9..000000000 --- a/C/primitive.h +++ /dev/null @@ -1,41 +0,0 @@ -/* This module defines the interface that each Simplicity application must implement. - */ -#ifndef SIMPLICITY_PRIMITIVE_H -#define SIMPLICITY_PRIMITIVE_H - -#include "bitstream.h" -#include "typeInference.h" - -/* Allocate a fresh set of unification variables bound to at least all the types necessary - * for all the jets that can be created by 'decodeJet', and also the type 'TWO^256', - * and also allocate space for 'extra_var_len' many unification variables. - * Return the number of non-trivial bindings created. - * - * However, if malloc fails, then return 0. - * - * Precondition: NULL != bound_var; - * NULL != word256_ix; - * NULL != extra_var_start; - * extra_var_len <= 6*DAG_LEN_MAX; - * - * Postcondition: Either '*bound_var == NULL' and the function returns 0 - * or 'unification_var (*bound_var)[*extra_var_start + extra_var_len]' is an array of unification variables - * such that for any 'jet : A |- B' there is some 'i < *extra_var_start' and 'j < *extra_var_start' such that - * '(*bound_var)[i]' is bound to 'A' and '(*bound_var)[j]' is bound to 'B' - * and, '*word256_ix < *extra_var_start' and '(*bound_var)[*word256_ix]' is bound the type 'TWO^256' - */ -size_t simplicity_mallocBoundVars(unification_var** bound_var, size_t* word256_ix, size_t* extra_var_start, size_t extra_var_len); - -/* Decode an Elements specific jet from 'stream' into 'node'. - * All jets begin with a bit prefix of '1' which needs to have already been consumed from the 'stream'. - * Returns 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' if the stream's prefix doesn't match any valid code for a jet. - * Returns 'SIMPLICITY_ERR_BITSTRING_EOF' if not enough bits are available in the 'stream'. - * In the above error cases, 'dag' may be modified. - * Returns 'SIMPLICITY_NO_ERROR' if successful. - * - * Precondition: NULL != node - * NULL != stream - */ -simplicity_err simplicity_decodeJet(dag_node* node, bitstream* stream); - -#endif diff --git a/C/primitive/elements/cmr.c b/C/primitive/elements/cmr.c index 133484fd3..b218e75cc 100644 --- a/C/primitive/elements/cmr.c +++ b/C/primitive/elements/cmr.c @@ -4,6 +4,7 @@ #include "../../limitations.h" #include "../../simplicity_alloc.h" #include "../../simplicity_assert.h" +#include "primitive.h" /* Deserialize a Simplicity 'program' and compute its CMR. * @@ -26,7 +27,7 @@ bool simplicity_elements_computeCmr( simplicity_err* error, unsigned char* cmr bitstream stream = initializeBitstream(program, program_len); dag_node* dag = NULL; - int_fast32_t dag_len = simplicity_decodeMallocDag(&dag, NULL, &stream); + int_fast32_t dag_len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, NULL, &stream); if (dag_len <= 0) { simplicity_assert(dag_len < 0); *error = (simplicity_err)dag_len; diff --git a/C/primitive/elements/env.c b/C/primitive/elements/env.c index a849dc45f..2b8587e39 100644 --- a/C/primitive/elements/env.c +++ b/C/primitive/elements/env.c @@ -3,7 +3,7 @@ #include #include #include -#include "primitive.h" +#include "txEnv.h" #include "ops.h" #include "../../rsort.h" #include "../../sha256.h" @@ -651,28 +651,3 @@ extern tapEnv* simplicity_elements_mallocTapEnv(const rawTapEnv* rawEnv) { extern void simplicity_elements_freeTapEnv(tapEnv* env) { simplicity_free(env); } - -/* Construct a txEnv structure from its components. - * This function will precompute any cached values. - * - * Precondition: NULL != tx - * NULL != taproot - * NULL != genesisHash - * ix < tx->numInputs - */ -txEnv simplicity_build_txEnv(const transaction* tx, const tapEnv* taproot, const sha256_midstate* genesisHash, uint_fast32_t ix) { - txEnv result = { .tx = tx - , .taproot = taproot - , .genesisHash = *genesisHash - , .ix = ix - }; - sha256_context ctx = sha256_init(result.sigAllHash.s); - sha256_hash(&ctx, genesisHash); - sha256_hash(&ctx, genesisHash); - sha256_hash(&ctx, &tx->txHash); - sha256_hash(&ctx, &taproot->tapEnvHash); - sha256_u32be(&ctx, ix); - sha256_finalize(&ctx); - - return result; -} diff --git a/C/primitive/elements/exec.c b/C/primitive/elements/exec.c index e38c9ca41..014e88200 100644 --- a/C/primitive/elements/exec.c +++ b/C/primitive/elements/exec.c @@ -3,6 +3,7 @@ #include #include #include "primitive.h" +#include "txEnv.h" #include "../../deserialize.h" #include "../../eval.h" #include "../../limitations.h" @@ -60,7 +61,7 @@ extern bool simplicity_elements_execSimplicity( simplicity_err* error, unsigned { bitstream stream = initializeBitstream(program, program_len); - dag_len = simplicity_decodeMallocDag(&dag, &census, &stream); + dag_len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, &census, &stream); if (dag_len <= 0) { simplicity_assert(dag_len < 0); *error = (simplicity_err)dag_len; @@ -79,7 +80,7 @@ extern bool simplicity_elements_execSimplicity( simplicity_err* error, unsigned if (IS_OK(*error)) { type* type_dag = NULL; - *error = simplicity_mallocTypeInference(&type_dag, dag, (uint_fast32_t)dag_len, &census); + *error = simplicity_mallocTypeInference(&type_dag, simplicity_elements_mallocBoundVars, dag, (uint_fast32_t)dag_len, &census); if (IS_OK(*error)) { simplicity_assert(NULL != type_dag); if (0 != dag[dag_len-1].sourceType || 0 != dag[dag_len-1].targetType) { diff --git a/C/primitive/elements/jets.c b/C/primitive/elements/jets.c index 8fb8bd143..b0cc3d256 100644 --- a/C/primitive/elements/jets.c +++ b/C/primitive/elements/jets.c @@ -1,7 +1,7 @@ #include "jets.h" #include "ops.h" -#include "primitive.h" +#include "txEnv.h" #include "../../taptweak.h" #include "../../simplicity_assert.h" diff --git a/C/primitive/elements/ops.h b/C/primitive/elements/ops.h index 87e9fb3a3..345d4eb27 100644 --- a/C/primitive/elements/ops.h +++ b/C/primitive/elements/ops.h @@ -4,7 +4,7 @@ #define SIMPLICITY_PRIMITIVE_ELEMENTS_OPS_H #include "../../sha256.h" -#include "primitive.h" +#include "txEnv.h" /* Add an 'confidential' value to be consumed by an ongoing SHA-256 evaluation. * If the 'confidential' value is blinded, then the 'evenPrefix' used if the y coordinate is even, diff --git a/C/primitive/elements/primitive.c b/C/primitive/elements/primitive.c index 28b6cf501..4d90422c7 100644 --- a/C/primitive/elements/primitive.c +++ b/C/primitive/elements/primitive.c @@ -1,10 +1,7 @@ -/* This module implements the 'primitive.h' interface for the Elements application of Simplicity. - */ #include "primitive.h" #include "jets.h" #include "../../limitations.h" -#include "../../primitive.h" #include "../../simplicity_alloc.h" #include "../../simplicity_assert.h" @@ -32,7 +29,7 @@ enum TypeNamesForJets { * '(*bound_var)[i]' is bound to 'A' and '(*bound_var)[j]' is bound to 'B' * and, '*word256_ix < *extra_var_start' and '(*bound_var)[*word256_ix]' is bound the type 'TWO^256' */ -size_t simplicity_mallocBoundVars(unification_var** bound_var, size_t* word256_ix, size_t* extra_var_start, size_t extra_var_len) { +size_t simplicity_elements_mallocBoundVars(unification_var** bound_var, size_t* word256_ix, size_t* extra_var_start, size_t extra_var_len) { static_assert(1 <= NumberOfTypeNames, "Missing TypeNamesForJets."); static_assert(NumberOfTypeNames <= NUMBER_OF_TYPENAMES_MAX, "Too many TypeNamesForJets."); static_assert(DAG_LEN_MAX <= (SIZE_MAX - NumberOfTypeNames) / 6, "NumberOfTypeNames + 6*DAG_LEN_MAX doesn't fit in size_t"); @@ -94,12 +91,12 @@ static dag_node jetNode(jetName name) { * Returns 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' if the stream's prefix doesn't match any valid code for a jet. * Returns 'SIMPLICITY_ERR_BITSTRING_EOF' if not enough bits are available in the 'stream'. * In the above error cases, 'dag' may be modified. - * Returns 'SIMPLICITY_NO_ERR' if successful. + * Returns 'SIMPLICITY_NO_ERROR' if successful. * * Precondition: NULL != node * NULL != stream */ -simplicity_err simplicity_decodeJet(dag_node* node, bitstream* stream) { +simplicity_err simplicity_elements_decodeJet(dag_node* node, bitstream* stream) { jetName name; simplicity_err error = decodePrimitive(&name, stream); if (!IS_OK(error)) return error; diff --git a/C/primitive/elements/primitive.h b/C/primitive/elements/primitive.h index b09510772..4ad133f14 100644 --- a/C/primitive/elements/primitive.h +++ b/C/primitive/elements/primitive.h @@ -1,276 +1,41 @@ -/* This module defines the environment ('txEnv') for Simplicity evaluation for Elements. - * It includes the transaction data and input index of the input whose Simplicity program is being executed. - * It also includes the commitment Merkle root of the program being executed. +/* Implements the required callbacks for the Elements Simplicity application. */ -#ifndef SIMPLICITY_PRIMITIVE_ELEMENTS_H -#define SIMPLICITY_PRIMITIVE_ELEMENTS_H +#ifndef SIMPLICITY_PRIMITIVE_ELEMENTS_PRIMITIVE_H +#define SIMPLICITY_PRIMITIVE_ELEMENTS_PRIMITIVE_H -#include -#include "../../sha256.h" +#include "../../bitstream.h" +#include "../../typeInference.h" -/* An Elements 'outpoint' consists of a transaction id and output index within that transaction. - * The transaction id can be a either a transaction within the chain, or the transaction id from another chain in case of a peg-in. - */ -typedef struct outpoint { - sha256_midstate txid; - uint_fast32_t ix; -} outpoint; - -/* In Elements, many fields can optionally be blinded and encoded as a point on the secp256k1 curve. - * This prefix determines the parity of the y-coordinate of that point point, or indicates the value is explicit. - * Sometimes values are entirely optional, in which case 'NONE' is a possibility. - */ -typedef enum confPrefix { - NONE = 0, - EXPLICIT = 1, - EVEN_Y = 2, - ODD_Y = 3 -} confPrefix; - -/* Returns true when the prefix indicates the associated value is a confidential value. */ -static inline bool is_confidential(confPrefix prefix) { - return EVEN_Y == prefix || ODD_Y == prefix; -} - -/* A confidential (256-bit) hash. - * When 'prefix' is either 'EVEN_Y' or 'ODD_Y' then 'data' contains the x-coordinate of the point on the secp256k1 curve - * representing the blinded value. - * When 'prefix' is 'EXPLICIT' then 'data' is the unblinded 256-bit hash. - * When 'prefix' is 'NONE' the value is "NULL" and the 'data' field is unused. - */ -typedef struct confidential { - sha256_midstate data; - confPrefix prefix; -} confidential; - -/* A confidential 64-bit value. - * When 'prefix' is either 'EVEN_Y' or 'ODD_Y' then 'confidential' contains the x-coordinate of the point on the secp256k1 curve - * representing the blinded value. - * When 'prefix' is 'EXPLICIT' then 'explicit' is the unblinded 256-bit hash. - * invariant: 'prefix' != 'NONE' - */ -typedef struct confAmount { - union { - sha256_midstate confidential; - uint_fast64_t explicit; - }; - confPrefix prefix; -} confAmount; - -/* In Elements, a null-data scriptPubKey consists of an OP_RETURN followed by data only pushes (i.e. only opcodes less than OP_16). - * This is an enumeration of all such data only push operation names. - * OP_IMMEDIATE represents OP_0 and all the one-byte prefixes of data pushes up to 75 bytes. - */ -typedef enum opcodeType { - OP_IMMEDIATE, - OP_PUSHDATA, - OP_PUSHDATA2, - OP_PUSHDATA4, - OP_1NEGATE, - OP_RESERVED, - OP_1, - OP_2, - OP_3, - OP_4, - OP_5, - OP_6, - OP_7, - OP_8, - OP_9, - OP_10, - OP_11, - OP_12, - OP_13, - OP_14, - OP_15, - OP_16 -} opcodeType; - -/* In Elements, a null-data scriptPubKey consists of an OP_RETURN followed by data only pushes (i.e. only opcodes less than OP_16). - * This is a structure represents a digest of all such operations. - * 'code' represents the operation name. - * If 'code' \in {OP_IMMEDIATE, OP_PUSHDATA, OP_PUSHDATA2, OP_PUSHDATA4} then 'dataHash' represents the SHA-256 hash of data pushed - * by the push operation. - */ -typedef struct opcode { - sha256_midstate dataHash; - opcodeType code; -} opcode; - -/* In Elements, a null-data scriptPubKey consists of an OP_RETURN followed by data only pushes (i.e. only opcodes less than OP_16). - * This is an structure for an array of digets of null-data scriptPubKeys. - * 'op' is an array of the (digests of) each data push. - * Note that 'len' is 0 for a null-data scriptPubKey consisting of only an OP_RETURN. - * - * Invariant: opcode op[len] (or op == NULL and len == 0) - */ -typedef struct parsedNullData { - const opcode* op; - uint_fast32_t len; -} parsedNullData; - -/* A structure representing data from one output from an Elements transaction. - * 'surjectionProofHash' is the SHA-256 hash of the output's surjection proof. - * 'rangeProofHash' is the SHA-256 hash of the output's range proof. - * 'scriptPubKey' is the SHA-256 hash of the outputs scriptPubKey. - * 'isNullData' is true if the output has a null-data scriptPubKey. - */ -typedef struct sigOutput { - confidential asset; - sha256_midstate surjectionProofHash; - sha256_midstate rangeProofHash; - confAmount amt; - confidential nonce; - sha256_midstate scriptPubKey; - uint_fast64_t assetFee; - parsedNullData pnd; - bool isNullData; - bool emptyScript; -} sigOutput; - -/* The data held by an Elements unspent transaction output database. - * This 'scriptPubKey' of the unspent transaction output, which in our application is digested as a SHA-256 hash. - * This also includes the asset and amount of the output, each of which may or may not be blinded. - */ -typedef struct utxo { - sha256_midstate scriptPubKey; - confidential asset; - confAmount amt; -} utxo; - -/* In Elements, a transaction input can optionally issue a new asset or reissue an existing asset. - * This enumerates those possibilities. - */ -typedef enum issuanceType { - NO_ISSUANCE = 0, - NEW_ISSUANCE, - REISSUANCE -} issuanceType; - -/* In Elements, a transaction input can optionally issue a new asset or reissue an existing asset. - * This structure contains data about such an issuance. - * 'assetRangeProofHash' is the SHA-256 hash of the asset amount's range proof. - * 'tokenRangeProofHash' is the SHA-256 hash of the token amount's range proof. +/* Allocate a fresh set of unification variables bound to at least all the types necessary + * for all the jets that can be created by 'decodeJet', and also the type 'TWO^256', + * and also allocate space for 'extra_var_len' many unification variables. + * Return the number of non-trivial bindings created. * - * Invariant: If 'type == NEW_ISSUANCE' then 'contractHash' and 'tokenAmt' are active; - * If 'type == REISSUANCE' then 'blindingNonce' is active; - */ -typedef struct assetIssuance { - union { - struct { - sha256_midstate contractHash; - confAmount tokenAmt; - }; - struct { - sha256_midstate blindingNonce; - }; - }; - sha256_midstate entropy; - sha256_midstate assetRangeProofHash; - sha256_midstate tokenRangeProofHash; - sha256_midstate assetId; /* Cached asset ID calculation. */ - sha256_midstate tokenId; /* Cached token ID calculation. */ - confAmount assetAmt; - issuanceType type; -} assetIssuance; - -/* A structure representing data from one input from an Elements transaction along with the utxo data of the output being redeemed. - * When 'hasAnnex' then 'annexHash' is a cache of the hash of the input's segwit annex. - * When 'isPegin' then the 'prevOutpoint' represents an outpoint of another chain - * and 'pegin' contains the hash of the parent chain's genesis block. - */ -typedef struct sigInput { - sha256_midstate annexHash; - sha256_midstate pegin; - sha256_midstate scriptSigHash; - outpoint prevOutpoint; - utxo txo; - uint_fast32_t sequence; - assetIssuance issuance; - bool hasAnnex; - bool isPegin; -} sigInput; - -/* A structure representing data from an Elements transaction (along with the utxo data of the outputs being redeemed). - * Includes a variety of cached hash values that are used in signature hash jets. - */ -typedef struct transaction { - const sigInput* input; - const sigOutput* output; - const sigOutput* const * feeOutputs; - sha256_midstate outputAssetAmountsHash; - sha256_midstate outputNoncesHash; - sha256_midstate outputScriptsHash; - sha256_midstate outputRangeProofsHash; - sha256_midstate outputSurjectionProofsHash; - sha256_midstate outputsHash; - sha256_midstate inputOutpointsHash; - sha256_midstate inputAssetAmountsHash; - sha256_midstate inputScriptsHash; - sha256_midstate inputUTXOsHash; - sha256_midstate inputSequencesHash; - sha256_midstate inputAnnexesHash; - sha256_midstate inputScriptSigsHash; - sha256_midstate inputsHash; - sha256_midstate issuanceAssetAmountsHash; - sha256_midstate issuanceTokenAmountsHash; - sha256_midstate issuanceRangeProofsHash; - sha256_midstate issuanceBlindingEntropyHash; - sha256_midstate issuancesHash; - sha256_midstate txHash; - sha256_midstate txid; - uint_fast32_t numInputs; - uint_fast32_t numOutputs; - uint_fast32_t numFees; - uint_fast32_t version; - uint_fast32_t lockTime; - /* lockDuration and lockDistance values are set even when the version is 0 or 1. - * This is similar to lockTime whose value is also set, even when the transaction is final. - */ - uint_fast16_t lockDistance; - uint_fast16_t lockDuration; /* Units of 512 seconds */ - bool isFinal; -} transaction; - -/* A structure representing taproot spending data from an Elements transaction. + * However, if malloc fails, then return 0. * - * Invariant: pathLen <= 128 - * sha256_midstate path[pathLen]; - */ -typedef struct tapEnv { - const sha256_midstate *path; - sha256_midstate tapLeafHash; - sha256_midstate tappathHash; - sha256_midstate tapEnvHash; - sha256_midstate internalKey; - sha256_midstate scriptCMR; - unsigned char pathLen; - unsigned char leafVersion; -} tapEnv; - -/* The 'txEnv' structure used by the Elements application of Simplicity. + * Precondition: NULL != bound_var; + * NULL != word256_ix; + * NULL != extra_var_start; + * extra_var_len <= 6*DAG_LEN_MAX; * - * It includes - * + the transaction data, which may be shared when Simplicity expressions are used for multiple inputs in the same transaction), - * + the input index under consideration, - * + the hash of the genesis block for the chain, - */ -typedef struct txEnv { - const transaction* tx; - const tapEnv* taproot; - sha256_midstate genesisHash; - sha256_midstate sigAllHash; - uint_fast32_t ix; -} txEnv; - -/* Construct a txEnv structure from its components. - * This function will precompute any cached values. + * Postcondition: Either '*bound_var == NULL' and the function returns 0 + * or 'unification_var (*bound_var)[*extra_var_start + extra_var_len]' is an array of unification variables + * such that for any 'jet : A |- B' there is some 'i < *extra_var_start' and 'j < *extra_var_start' such that + * '(*bound_var)[i]' is bound to 'A' and '(*bound_var)[j]' is bound to 'B' + * and, '*word256_ix < *extra_var_start' and '(*bound_var)[*word256_ix]' is bound the type 'TWO^256' + */ +size_t simplicity_elements_mallocBoundVars(unification_var** bound_var, size_t* word256_ix, size_t* extra_var_start, size_t extra_var_len); + +/* Decode an Elements specific jet from 'stream' into 'node'. + * All jets begin with a bit prefix of '1' which needs to have already been consumed from the 'stream'. + * Returns 'SIMPLICITY_ERR_DATA_OUT_OF_RANGE' if the stream's prefix doesn't match any valid code for a jet. + * Returns 'SIMPLICITY_ERR_BITSTRING_EOF' if not enough bits are available in the 'stream'. + * In the above error cases, 'dag' may be modified. + * Returns 'SIMPLICITY_NO_ERROR' if successful. * - * Precondition: NULL != tx - * NULL != taproot - * NULL != genesisHash - * ix < tx->numInputs + * Precondition: NULL != node + * NULL != stream */ -txEnv simplicity_build_txEnv(const transaction* tx, const tapEnv* taproot, const sha256_midstate* genesisHash, uint_fast32_t ix); +simplicity_err simplicity_elements_decodeJet(dag_node* node, bitstream* stream); #endif diff --git a/C/primitive/elements/txEnv.c b/C/primitive/elements/txEnv.c new file mode 100644 index 000000000..64c553699 --- /dev/null +++ b/C/primitive/elements/txEnv.c @@ -0,0 +1,26 @@ +#include "txEnv.h" + +/* Construct a txEnv structure from its components. + * This function will precompute any cached values. + * + * Precondition: NULL != tx + * NULL != taproot + * NULL != genesisHash + * ix < tx->numInputs + */ +txEnv simplicity_build_txEnv(const transaction* tx, const tapEnv* taproot, const sha256_midstate* genesisHash, uint_fast32_t ix) { + txEnv result = { .tx = tx + , .taproot = taproot + , .genesisHash = *genesisHash + , .ix = ix + }; + sha256_context ctx = sha256_init(result.sigAllHash.s); + sha256_hash(&ctx, genesisHash); + sha256_hash(&ctx, genesisHash); + sha256_hash(&ctx, &tx->txHash); + sha256_hash(&ctx, &taproot->tapEnvHash); + sha256_u32be(&ctx, ix); + sha256_finalize(&ctx); + + return result; +} diff --git a/C/primitive/elements/txEnv.h b/C/primitive/elements/txEnv.h new file mode 100644 index 000000000..fa2e9e918 --- /dev/null +++ b/C/primitive/elements/txEnv.h @@ -0,0 +1,276 @@ +/* This module defines the environment ('txEnv') for Simplicity evaluation for Elements. + * It includes the transaction data and input index of the input whose Simplicity program is being executed. + * It also includes the commitment Merkle root of the program being executed. + */ +#ifndef SIMPLICITY_PRIMITIVE_ELEMENTS_TXENV_H +#define SIMPLICITY_PRIMITIVE_ELEMENTS_TXENV_H + +#include +#include "../../sha256.h" + +/* An Elements 'outpoint' consists of a transaction id and output index within that transaction. + * The transaction id can be a either a transaction within the chain, or the transaction id from another chain in case of a peg-in. + */ +typedef struct outpoint { + sha256_midstate txid; + uint_fast32_t ix; +} outpoint; + +/* In Elements, many fields can optionally be blinded and encoded as a point on the secp256k1 curve. + * This prefix determines the parity of the y-coordinate of that point point, or indicates the value is explicit. + * Sometimes values are entirely optional, in which case 'NONE' is a possibility. + */ +typedef enum confPrefix { + NONE = 0, + EXPLICIT = 1, + EVEN_Y = 2, + ODD_Y = 3 +} confPrefix; + +/* Returns true when the prefix indicates the associated value is a confidential value. */ +static inline bool is_confidential(confPrefix prefix) { + return EVEN_Y == prefix || ODD_Y == prefix; +} + +/* A confidential (256-bit) hash. + * When 'prefix' is either 'EVEN_Y' or 'ODD_Y' then 'data' contains the x-coordinate of the point on the secp256k1 curve + * representing the blinded value. + * When 'prefix' is 'EXPLICIT' then 'data' is the unblinded 256-bit hash. + * When 'prefix' is 'NONE' the value is "NULL" and the 'data' field is unused. + */ +typedef struct confidential { + sha256_midstate data; + confPrefix prefix; +} confidential; + +/* A confidential 64-bit value. + * When 'prefix' is either 'EVEN_Y' or 'ODD_Y' then 'confidential' contains the x-coordinate of the point on the secp256k1 curve + * representing the blinded value. + * When 'prefix' is 'EXPLICIT' then 'explicit' is the unblinded 256-bit hash. + * invariant: 'prefix' != 'NONE' + */ +typedef struct confAmount { + union { + sha256_midstate confidential; + uint_fast64_t explicit; + }; + confPrefix prefix; +} confAmount; + +/* In Elements, a null-data scriptPubKey consists of an OP_RETURN followed by data only pushes (i.e. only opcodes less than OP_16). + * This is an enumeration of all such data only push operation names. + * OP_IMMEDIATE represents OP_0 and all the one-byte prefixes of data pushes up to 75 bytes. + */ +typedef enum opcodeType { + OP_IMMEDIATE, + OP_PUSHDATA, + OP_PUSHDATA2, + OP_PUSHDATA4, + OP_1NEGATE, + OP_RESERVED, + OP_1, + OP_2, + OP_3, + OP_4, + OP_5, + OP_6, + OP_7, + OP_8, + OP_9, + OP_10, + OP_11, + OP_12, + OP_13, + OP_14, + OP_15, + OP_16 +} opcodeType; + +/* In Elements, a null-data scriptPubKey consists of an OP_RETURN followed by data only pushes (i.e. only opcodes less than OP_16). + * This is a structure represents a digest of all such operations. + * 'code' represents the operation name. + * If 'code' \in {OP_IMMEDIATE, OP_PUSHDATA, OP_PUSHDATA2, OP_PUSHDATA4} then 'dataHash' represents the SHA-256 hash of data pushed + * by the push operation. + */ +typedef struct opcode { + sha256_midstate dataHash; + opcodeType code; +} opcode; + +/* In Elements, a null-data scriptPubKey consists of an OP_RETURN followed by data only pushes (i.e. only opcodes less than OP_16). + * This is an structure for an array of digets of null-data scriptPubKeys. + * 'op' is an array of the (digests of) each data push. + * Note that 'len' is 0 for a null-data scriptPubKey consisting of only an OP_RETURN. + * + * Invariant: opcode op[len] (or op == NULL and len == 0) + */ +typedef struct parsedNullData { + const opcode* op; + uint_fast32_t len; +} parsedNullData; + +/* A structure representing data from one output from an Elements transaction. + * 'surjectionProofHash' is the SHA-256 hash of the output's surjection proof. + * 'rangeProofHash' is the SHA-256 hash of the output's range proof. + * 'scriptPubKey' is the SHA-256 hash of the outputs scriptPubKey. + * 'isNullData' is true if the output has a null-data scriptPubKey. + */ +typedef struct sigOutput { + confidential asset; + sha256_midstate surjectionProofHash; + sha256_midstate rangeProofHash; + confAmount amt; + confidential nonce; + sha256_midstate scriptPubKey; + uint_fast64_t assetFee; + parsedNullData pnd; + bool isNullData; + bool emptyScript; +} sigOutput; + +/* The data held by an Elements unspent transaction output database. + * This 'scriptPubKey' of the unspent transaction output, which in our application is digested as a SHA-256 hash. + * This also includes the asset and amount of the output, each of which may or may not be blinded. + */ +typedef struct utxo { + sha256_midstate scriptPubKey; + confidential asset; + confAmount amt; +} utxo; + +/* In Elements, a transaction input can optionally issue a new asset or reissue an existing asset. + * This enumerates those possibilities. + */ +typedef enum issuanceType { + NO_ISSUANCE = 0, + NEW_ISSUANCE, + REISSUANCE +} issuanceType; + +/* In Elements, a transaction input can optionally issue a new asset or reissue an existing asset. + * This structure contains data about such an issuance. + * 'assetRangeProofHash' is the SHA-256 hash of the asset amount's range proof. + * 'tokenRangeProofHash' is the SHA-256 hash of the token amount's range proof. + * + * Invariant: If 'type == NEW_ISSUANCE' then 'contractHash' and 'tokenAmt' are active; + * If 'type == REISSUANCE' then 'blindingNonce' is active; + */ +typedef struct assetIssuance { + union { + struct { + sha256_midstate contractHash; + confAmount tokenAmt; + }; + struct { + sha256_midstate blindingNonce; + }; + }; + sha256_midstate entropy; + sha256_midstate assetRangeProofHash; + sha256_midstate tokenRangeProofHash; + sha256_midstate assetId; /* Cached asset ID calculation. */ + sha256_midstate tokenId; /* Cached token ID calculation. */ + confAmount assetAmt; + issuanceType type; +} assetIssuance; + +/* A structure representing data from one input from an Elements transaction along with the utxo data of the output being redeemed. + * When 'hasAnnex' then 'annexHash' is a cache of the hash of the input's segwit annex. + * When 'isPegin' then the 'prevOutpoint' represents an outpoint of another chain + * and 'pegin' contains the hash of the parent chain's genesis block. + */ +typedef struct sigInput { + sha256_midstate annexHash; + sha256_midstate pegin; + sha256_midstate scriptSigHash; + outpoint prevOutpoint; + utxo txo; + uint_fast32_t sequence; + assetIssuance issuance; + bool hasAnnex; + bool isPegin; +} sigInput; + +/* A structure representing data from an Elements transaction (along with the utxo data of the outputs being redeemed). + * Includes a variety of cached hash values that are used in signature hash jets. + */ +typedef struct transaction { + const sigInput* input; + const sigOutput* output; + const sigOutput* const * feeOutputs; + sha256_midstate outputAssetAmountsHash; + sha256_midstate outputNoncesHash; + sha256_midstate outputScriptsHash; + sha256_midstate outputRangeProofsHash; + sha256_midstate outputSurjectionProofsHash; + sha256_midstate outputsHash; + sha256_midstate inputOutpointsHash; + sha256_midstate inputAssetAmountsHash; + sha256_midstate inputScriptsHash; + sha256_midstate inputUTXOsHash; + sha256_midstate inputSequencesHash; + sha256_midstate inputAnnexesHash; + sha256_midstate inputScriptSigsHash; + sha256_midstate inputsHash; + sha256_midstate issuanceAssetAmountsHash; + sha256_midstate issuanceTokenAmountsHash; + sha256_midstate issuanceRangeProofsHash; + sha256_midstate issuanceBlindingEntropyHash; + sha256_midstate issuancesHash; + sha256_midstate txHash; + sha256_midstate txid; + uint_fast32_t numInputs; + uint_fast32_t numOutputs; + uint_fast32_t numFees; + uint_fast32_t version; + uint_fast32_t lockTime; + /* lockDuration and lockDistance values are set even when the version is 0 or 1. + * This is similar to lockTime whose value is also set, even when the transaction is final. + */ + uint_fast16_t lockDistance; + uint_fast16_t lockDuration; /* Units of 512 seconds */ + bool isFinal; +} transaction; + +/* A structure representing taproot spending data from an Elements transaction. + * + * Invariant: pathLen <= 128 + * sha256_midstate path[pathLen]; + */ +typedef struct tapEnv { + const sha256_midstate *path; + sha256_midstate tapLeafHash; + sha256_midstate tappathHash; + sha256_midstate tapEnvHash; + sha256_midstate internalKey; + sha256_midstate scriptCMR; + unsigned char pathLen; + unsigned char leafVersion; +} tapEnv; + +/* The 'txEnv' structure used by the Elements application of Simplicity. + * + * It includes + * + the transaction data, which may be shared when Simplicity expressions are used for multiple inputs in the same transaction), + * + the input index under consideration, + * + the hash of the genesis block for the chain, + */ +typedef struct txEnv { + const transaction* tx; + const tapEnv* taproot; + sha256_midstate genesisHash; + sha256_midstate sigAllHash; + uint_fast32_t ix; +} txEnv; + +/* Construct a txEnv structure from its components. + * This function will precompute any cached values. + * + * Precondition: NULL != tx + * NULL != taproot + * NULL != genesisHash + * ix < tx->numInputs + */ +txEnv simplicity_build_txEnv(const transaction* tx, const tapEnv* taproot, const sha256_midstate* genesisHash, uint_fast32_t ix); + +#endif diff --git a/C/test.c b/C/test.c index 11028fb64..65bf73591 100644 --- a/C/test.c +++ b/C/test.c @@ -21,6 +21,7 @@ #include "simplicity_alloc.h" #include "typeInference.h" #include "primitive/elements/checkSigHashAllTx1.h" +#include "primitive/elements/primitive.h" _Static_assert(CHAR_BIT == 8, "Buffers passed to fmemopen presume 8 bit chars"); @@ -78,7 +79,7 @@ static void test_hashBlock(void) { simplicity_err error; { bitstream stream = initializeBitstream(hashBlock, sizeof_hashBlock); - len = simplicity_decodeMallocDag(&dag, &census, &stream); + len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, &census, &stream); if (!dag) { simplicity_assert(len < 0); error = (simplicity_err)len; @@ -105,7 +106,7 @@ static void test_hashBlock(void) { type* type_dag; bitstream witness = initializeBitstream(hashBlock_witness, sizeof_hashBlock_witness); - if (!IS_OK(simplicity_mallocTypeInference(&type_dag, dag, (uint_fast32_t)len, &census)) || !type_dag || + if (!IS_OK(simplicity_mallocTypeInference(&type_dag, simplicity_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"); @@ -195,7 +196,7 @@ static void test_program(char* name, const unsigned char* program, size_t progra simplicity_err error; { bitstream stream = initializeBitstream(program, program_len); - len = simplicity_decodeMallocDag(&dag, &census, &stream); + len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, &census, &stream); if (!dag) { simplicity_assert(len < 0); error = (simplicity_err)len; @@ -231,7 +232,7 @@ static void test_program(char* name, const unsigned char* program, size_t progra } type* type_dag; bitstream witness_stream = initializeBitstream(witness, witness_len); - if (!IS_OK(simplicity_mallocTypeInference(&type_dag, dag, (uint_fast32_t)len, &census)) || !type_dag || + if (!IS_OK(simplicity_mallocTypeInference(&type_dag, simplicity_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"); @@ -319,7 +320,7 @@ static void test_occursCheck(void) { int_fast32_t len; { bitstream stream = initializeBitstream(buf, sizeof(buf)); - len = simplicity_decodeMallocDag(&dag, &census, &stream); + len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, &census, &stream); } if (!dag) { simplicity_assert(len < 0); @@ -327,7 +328,7 @@ static void test_occursCheck(void) { } else { type* type_dag; simplicity_assert(0 < len); - if (SIMPLICITY_ERR_TYPE_INFERENCE_OCCURS_CHECK == simplicity_mallocTypeInference(&type_dag, dag, (uint_fast32_t)len, &census) && + if (SIMPLICITY_ERR_TYPE_INFERENCE_OCCURS_CHECK == simplicity_mallocTypeInference(&type_dag, simplicity_elements_mallocBoundVars, dag, (uint_fast32_t)len, &census) && !type_dag) { successes++; } else { diff --git a/C/typeInference.c b/C/typeInference.c index 89f092326..e8359d5e9 100644 --- a/C/typeInference.c +++ b/C/typeInference.c @@ -3,7 +3,6 @@ #include #include "bounded.h" #include "limitations.h" -#include "primitive.h" #include "simplicity_alloc.h" #include "simplicity_assert.h" @@ -559,7 +558,7 @@ static simplicity_err freezeTypes(type* type_dag, dag_node* dag, unification_arr * or 'dag' is well-typed with '*type_dag' and without witness values * if the return value is not 'SIMPLICITY_NO_ERROR' then 'NULL == *type_dag' */ -simplicity_err simplicity_mallocTypeInference(type** type_dag, dag_node* dag, const uint_fast32_t len, const combinator_counters* census) { +simplicity_err simplicity_mallocTypeInference(type** type_dag, simplicity_callback_mallocBoundVars mallocBoundVars, dag_node* dag, const uint_fast32_t len, const combinator_counters* census) { *type_dag = NULL; static_assert(DAG_LEN_MAX <= SIZE_MAX / sizeof(unification_arrow), "arrow array too large."); static_assert(1 <= DAG_LEN_MAX, "DAG_LEN_MAX is zero."); @@ -569,7 +568,7 @@ simplicity_err simplicity_mallocTypeInference(type** type_dag, dag_node* dag, co unification_arrow* arrow = simplicity_malloc(len * sizeof(unification_arrow)); unification_var* bound_var = NULL; size_t word256_ix, extra_var_start; - const size_t orig_bindings_used = simplicity_mallocBoundVars(&bound_var, &word256_ix, &extra_var_start, max_extra_vars(census)); + const size_t orig_bindings_used = mallocBoundVars(&bound_var, &word256_ix, &extra_var_start, max_extra_vars(census)); size_t bindings_used = orig_bindings_used; static_assert(1 <= NUMBER_OF_TYPENAMES_MAX, "NUMBER_OF_TYPENAMES_MAX is zero."); diff --git a/C/typeInference.h b/C/typeInference.h index dd8ccf35f..3988d08b4 100644 --- a/C/typeInference.h +++ b/C/typeInference.h @@ -71,6 +71,26 @@ struct unification_var { bool isBound; }; +/* Allocate a fresh set of unification variables bound to at least all the types necessary + * for all the jets that can be created by 'simplicity_callbac_decodeJet', and also the type 'TWO^256', + * and also allocate space for 'extra_var_len' many unification variables. + * Return the number of non-trivial bindings created. + * + * However, if malloc fails, then return 0. + * + * Precondition: NULL != bound_var; + * NULL != word256_ix; + * NULL != extra_var_start; + * extra_var_len <= 6*DAG_LEN_MAX; + * + * Postcondition: Either '*bound_var == NULL' and the function returns 0 + * or 'unification_var (*bound_var)[*extra_var_start + extra_var_len]' is an array of unification variables + * such that for any 'jet : A |- B' there is some 'i < *extra_var_start' and 'j < *extra_var_start' such that + * '(*bound_var)[i]' is bound to 'A' and '(*bound_var)[j]' is bound to 'B' + * and, '*word256_ix < *extra_var_start' and '(*bound_var)[*word256_ix]' is bound the type 'TWO^256' + */ +typedef size_t (*simplicity_callback_mallocBoundVars)(unification_var** bound_var, size_t* word256_ix, size_t* extra_var_start, size_t extra_var_len); + /* If the Simplicity DAG, 'dag', has a principal type (including constraints due to sharing of subexpressions), * then allocate a well-formed type DAG containing all the types needed for all the subexpressions of 'dag', * with all free type variables instantiated at ONE, and set '*type_dag' to this allocation, @@ -91,6 +111,6 @@ struct unification_var { * or 'dag' is well-typed with '*type_dag' and without witness values * if the return value is not 'SIMPLICITY_NO_ERROR' then 'NULL == *type_dag' */ -simplicity_err simplicity_mallocTypeInference(type** type_dag, dag_node* dag, const uint_fast32_t len, const combinator_counters* census); +simplicity_err simplicity_mallocTypeInference(type** type_dag, simplicity_callback_mallocBoundVars mallocBoundVars, dag_node* dag, const uint_fast32_t len, const combinator_counters* census); #endif diff --git a/Haskell/Tests/Simplicity/Elements/FFI/Primitive.hs b/Haskell/Tests/Simplicity/Elements/FFI/Primitive.hs index 58f28c641..dbe79e824 100644 --- a/Haskell/Tests/Simplicity/Elements/FFI/Primitive.hs +++ b/Haskell/Tests/Simplicity/Elements/FFI/Primitive.hs @@ -20,12 +20,12 @@ decodeError (-2) = Left DataOutOfRange decodeError (-12) = Left BitstreamEof decodeError err = error $ "Simplicity.Elements.FFI.Primitive.decodeError: Unexpected error code " ++ show err -foreign import ccall unsafe "" simplicity_decodeJet :: Ptr DagNode -> Ptr Bitstream -> IO CInt +foreign import ccall unsafe "" simplicity_elements_decodeJet :: Ptr DagNode -> Ptr Bitstream -> IO CInt decodeJetNode :: Ptr Bitstream -> (Either ErrorCode (Ptr DagNode) -> IO a) -> IO a decodeJetNode pstream k = withDagNode $ \pnode -> do - error <- simplicity_decodeJet pnode pstream + error <- simplicity_elements_decodeJet pnode pstream k (decodeError error >> return pnode) decodeJetCMR :: [Bool] -> Either ErrorCode Hash256 diff --git a/Haskell/cbits/elements/env.c b/Haskell/cbits/elements/env.c index c6e72925c..9725e9e4f 100644 --- a/Haskell/cbits/elements/env.c +++ b/Haskell/cbits/elements/env.c @@ -1,6 +1,6 @@ #include "simplicity_alloc.h" #include "simplicity/elements/env.h" -#include "primitive/elements/primitive.h" +#include "primitive/elements/txEnv.h" const size_t c_sizeof_rawBuffer = sizeof(rawBuffer); const size_t c_sizeof_rawOutput = sizeof(rawOutput); diff --git a/Simplicity.cabal b/Simplicity.cabal index 7b6f4c37e..e6fcd305f 100644 --- a/Simplicity.cabal +++ b/Simplicity.cabal @@ -236,7 +236,7 @@ Test-Suite testsuite Simplicity.Serialization.Tests, Simplicity.TestCoreEval, Simplicity.Ty.Tests - C-sources: C/rsort.c, C/dag.c, C/primitive/elements/primitive.c, C/bitstream.c + C-sources: C/rsort.c, C/dag.c, C/primitive/elements/primitive.c, C/primitive/elements/txEnv.c, C/bitstream.c Haskell/cbits/bitstream.c, Haskell/cbits/dag.c build-depends: Simplicity, base >=4.9 && <4.20,