From 1a4006cc260754919ba865ca3c8d2f5f4de32df8 Mon Sep 17 00:00:00 2001 From: Russell O'Connor Date: Tue, 29 Apr 2025 14:02:29 -0400 Subject: [PATCH] Make primitive.h functions indirect The original plan here was to build different Simplicity primitives (e.g. Elements and Bitcoin), which are selected at link time. However, we would like to link multiple sets of primitives into Haskell for testing purposes. This means we will need different names for the Bitcoin and Elements to bind them. To support this we turn the primitive.h functions into callbacks for the various specific primitive implementations. Various functions are rearranged to support the removal of primitive.h and make the pairing of .c file implementing .h header files more consistent. It should now be the case that each .c files implement exactly the declairations of one .h file. --- C/Makefile | 2 +- C/deserialize.c | 13 +- C/deserialize.h | 14 +- C/elements-sources.mk | 3 +- C/primitive.h | 41 --- C/primitive/elements/cmr.c | 3 +- C/primitive/elements/env.c | 27 +- C/primitive/elements/exec.c | 5 +- C/primitive/elements/jets.c | 2 +- C/primitive/elements/ops.h | 2 +- C/primitive/elements/primitive.c | 9 +- C/primitive/elements/primitive.h | 297 ++---------------- C/primitive/elements/txEnv.c | 26 ++ C/primitive/elements/txEnv.h | 276 ++++++++++++++++ C/test.c | 13 +- C/typeInference.c | 5 +- C/typeInference.h | 22 +- .../Simplicity/Elements/FFI/Primitive.hs | 4 +- Haskell/cbits/elements/env.c | 2 +- Simplicity.cabal | 2 +- 20 files changed, 400 insertions(+), 368 deletions(-) delete mode 100644 C/primitive.h create mode 100644 C/primitive/elements/txEnv.c create mode 100644 C/primitive/elements/txEnv.h 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,