diff --git a/build_msvc/libelementssimplicity/libelementssimplicity.vcxproj b/build_msvc/libelementssimplicity/libelementssimplicity.vcxproj
index f975f8316dd..068b9316ada 100644
--- a/build_msvc/libelementssimplicity/libelementssimplicity.vcxproj
+++ b/build_msvc/libelementssimplicity/libelementssimplicity.vcxproj
@@ -9,7 +9,6 @@
-
@@ -20,11 +19,13 @@
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 81b72882e40..d01d4a1a874 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -2601,8 +2601,8 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent
m_spent_output_spk_single_hashes = GetSpentScriptPubKeysSHA256(m_spent_outputs);
m_output_spk_single_hashes = GetOutputScriptPubKeysSHA256(txTo);
- std::vector simplicityRawAnnex(txTo.witness.vtxinwit.size());
- std::vector simplicityRawInput(txTo.vin.size());
+ std::vector simplicityRawAnnex(txTo.witness.vtxinwit.size());
+ std::vector simplicityRawInput(txTo.vin.size());
for (size_t i = 0; i < txTo.vin.size(); ++i) {
simplicityRawInput[i].prevTxid = txTo.vin[i].prevout.hash.begin();
simplicityRawInput[i].prevIx = txTo.vin[i].prevout.n;
@@ -2639,7 +2639,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent
}
}
- std::vector simplicityRawOutput(txTo.vout.size());
+ std::vector simplicityRawOutput(txTo.vout.size());
for (size_t i = 0; i < txTo.vout.size(); ++i) {
simplicityRawOutput[i].asset = txTo.vout[i].nAsset.vchCommitment.empty() ? NULL : txTo.vout[i].nAsset.vchCommitment.data();
simplicityRawOutput[i].value = txTo.vout[i].nValue.vchCommitment.empty() ? NULL : txTo.vout[i].nValue.vchCommitment.data();
@@ -2659,7 +2659,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent
}
}
- rawTransaction simplicityRawTx;
+ rawElementsTransaction simplicityRawTx;
uint256 rawHash = txTo.GetHash();
simplicityRawTx.txid = rawHash.begin();
simplicityRawTx.input = simplicityRawInput.data();
@@ -3114,14 +3114,14 @@ uint32_t GenericTransactionSignatureChecker::GetnIn() const
}
template
-bool GenericTransactionSignatureChecker::CheckSimplicity(const valtype& program, const valtype& witness, const rawTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const
+bool GenericTransactionSignatureChecker::CheckSimplicity(const valtype& program, const valtype& witness, const rawElementsTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const
{
simplicity_err error;
- tapEnv* simplicityTapEnv = simplicity_elements_mallocTapEnv(&simplicityRawTap);
+ elementsTapEnv* simplicityTapEnv = simplicity_elements_mallocTapEnv(&simplicityRawTap);
assert(txdata->m_simplicity_tx_data);
assert(simplicityTapEnv);
- if (!simplicity_elements_execSimplicity(&error, 0, txdata->m_simplicity_tx_data.get(), nIn, simplicityTapEnv, txdata->m_hash_genesis_block.data(), budget, 0, program.data(), program.size(), witness.data(), witness.size())) {
+ if (!simplicity_elements_execSimplicity(&error, 0, txdata->m_simplicity_tx_data.get(), nIn, simplicityTapEnv, txdata->m_hash_genesis_block.data(), 0, budget, 0, program.data(), program.size(), witness.data(), witness.size())) {
assert(!"simplicity_elements_execSimplicity internal error");
}
simplicity_elements_freeTapEnv(simplicityTapEnv);
@@ -3154,6 +3154,7 @@ bool GenericTransactionSignatureChecker::CheckSimplicity(const valtype& progr
case SIMPLICITY_ERR_ANTIDOS: return set_error(serror, SCRIPT_ERR_SIMPLICITY_ANTIDOS);
case SIMPLICITY_ERR_HIDDEN_ROOT: return set_error(serror, SCRIPT_ERR_SIMPLICITY_HIDDEN_ROOT);
case SIMPLICITY_ERR_AMR: return set_error(serror, SCRIPT_ERR_SIMPLICITY_AMR);
+ case SIMPLICITY_ERR_OVERWEIGHT: return set_error(serror, SCRIPT_ERR_SIMPLICITY_OVERWEIGHT);
default: return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
}
}
@@ -3312,7 +3313,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
const valtype& simplicity_program = SpanPopBack(stack);
const valtype& simplicity_witness = SpanPopBack(stack);
const int64_t budget = ::GetSerializeSize(witness.stack, PROTOCOL_VERSION) + VALIDATION_WEIGHT_OFFSET;
- rawTapEnv simplicityRawTap;
+ rawElementsTapEnv simplicityRawTap;
simplicityRawTap.controlBlock = control.data();
simplicityRawTap.pathLen = (control.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
simplicityRawTap.scriptCMR = script_bytes.data();
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index e54e15678e6..6ec8339d9c4 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -171,12 +171,12 @@ bool CheckSignatureEncoding(const std::vector &vchSig, unsigned i
struct SimplicityTransactionDeleter
{
- void operator()(transaction* ptr)
+ void operator()(elementsTransaction* ptr)
{
simplicity_elements_freeTransaction(ptr);
}
};
-using SimplicityTransactionUniquePtr = std::unique_ptr;
+using SimplicityTransactionUniquePtr = std::unique_ptr;
struct PrecomputedTransactionData
{
@@ -345,7 +345,7 @@ class BaseSignatureChecker
return std::numeric_limits::max();
}
- virtual bool CheckSimplicity(const std::vector& witness, const std::vector& program, const rawTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const
+ virtual bool CheckSimplicity(const std::vector& witness, const std::vector& program, const rawElementsTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const
{
return false;
}
@@ -393,7 +393,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
const PrecomputedTransactionData* GetPrecomputedTransactionData() const override;
uint32_t GetnIn() const override;
- bool CheckSimplicity(const std::vector& program, const std::vector& witness, const rawTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const override;
+ bool CheckSimplicity(const std::vector& program, const std::vector& witness, const rawElementsTapEnv& simplicityRawTap, int64_t budget, ScriptError* serror) const override;
};
using TransactionSignatureChecker = GenericTransactionSignatureChecker;
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index a50888dd8f9..b79c9e7b347 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -180,6 +180,8 @@ std::string ScriptErrorString(const ScriptError serror)
return SIMPLICITY_ERR_MSG(SIMPLICITY_ERR_HIDDEN_ROOT);
case SCRIPT_ERR_SIMPLICITY_AMR:
return SIMPLICITY_ERR_MSG(SIMPLICITY_ERR_AMR);
+ case SCRIPT_ERR_SIMPLICITY_OVERWEIGHT:
+ return SIMPLICITY_ERR_MSG(SIMPLICITY_ERR_OVERWEIGHT);
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;
diff --git a/src/script/script_error.h b/src/script/script_error.h
index 8fac6496d08..0285255e1e7 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -122,6 +122,7 @@ typedef enum ScriptError_t
SCRIPT_ERR_SIMPLICITY_ANTIDOS,
SCRIPT_ERR_SIMPLICITY_HIDDEN_ROOT,
SCRIPT_ERR_SIMPLICITY_AMR,
+ SCRIPT_ERR_SIMPLICITY_OVERWEIGHT,
/* Must go last */
SCRIPT_ERR_ERROR_COUNT
diff --git a/src/simplicity/Makefile b/src/simplicity/Makefile
index 06506b819c5..a0cb534209a 100644
--- a/src/simplicity/Makefile
+++ b/src/simplicity/Makefile
@@ -1,5 +1,5 @@
-OBJS := bitstream.o cmr.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/elementsJets.o primitive/elements/primitive.o
-TEST_OBJS := test.o ctx8Pruned.o ctx8Unpruned.o hashBlock.o regression4.o schnorr0.o schnorr6.o typeSkipTest.o primitive/elements/checkSigHashAllTx1.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 elements/env.o elements/exec.o elements/ops.o elements/elementsJets.o elements/primitive.o elements/cmr.o elements/txEnv.o
+TEST_OBJS := test.o ctx8Pruned.o ctx8Unpruned.o hashBlock.o regression4.o schnorr0.o schnorr6.o typeSkipTest.o elements/checkSigHashAllTx1.o
# From https://fastcompression.blogspot.com/2019/01/compiler-warnings.html
CWARN := -Werror -Wall -Wextra -Wcast-qual -Wcast-align -Wstrict-aliasing -Wpointer-arith -Winit-self -Wshadow -Wswitch-enum -Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls -Wfloat-equal -Wundef -Wconversion
@@ -14,7 +14,7 @@ CFLAGS := $(CFLAGS) -I include
jets-secp256k1.o: jets-secp256k1.c
$(CC) -c $(CFLAGS) $(CWARN) -Wno-conversion $(CPPFLAGS) -o $@ $<
-primitive/elements/elementsJets.o: primitive/elements/elementsJets.c
+elements/elementsJets.o: elements/elementsJets.c
$(CC) -c $(CFLAGS) $(CWARN) -Wno-switch-enum -Wswitch $(CPPFLAGS) -o $@ $<
sha256.o: sha256.c
diff --git a/src/simplicity/deserialize.c b/src/simplicity/deserialize.c
index d65c0d5c5cf..182f23ba16e 100644
--- a/src/simplicity/deserialize.c
+++ b/src/simplicity/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/src/simplicity/deserialize.h b/src/simplicity/deserialize.h
index d20561b011c..dd5515d3c8d 100644
--- a/src/simplicity/deserialize.h
+++ b/src/simplicity/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/src/simplicity/elements-sources.mk b/src/simplicity/elements-sources.mk
index 189a04983af..1c0dc4b9a9b 100644
--- a/src/simplicity/elements-sources.mk
+++ b/src/simplicity/elements-sources.mk
@@ -5,14 +5,13 @@
ELEMENTS_SIMPLICITY_INCLUDE_DIR_INT = %reldir%/include
ELEMENTS_SIMPLICITY_DIST_HEADERS_INT =
-ELEMENTS_SIMPLICITY_DIST_HEADERS_INT += %reldir%/include/simplicity/cmr.h
ELEMENTS_SIMPLICITY_DIST_HEADERS_INT += %reldir%/include/simplicity/errorCodes.h
+ELEMENTS_SIMPLICITY_DIST_HEADERS_INT += %reldir%/include/simplicity/elements/cmr.h
ELEMENTS_SIMPLICITY_DIST_HEADERS_INT += %reldir%/include/simplicity/elements/env.h
ELEMENTS_SIMPLICITY_DIST_HEADERS_INT += %reldir%/include/simplicity/elements/exec.h
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT =
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/bitstream.c
-ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/cmr.c
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/dag.c
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/deserialize.c
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/eval.c
@@ -24,11 +23,13 @@ ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/sha256.c
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/type.c
ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/typeInference.c
-ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/env.c
-ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/exec.c
-ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/primitive/elements/elementsJets.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%/elements/cmr.c
+ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/elements/env.c
+ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/elements/exec.c
+ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/elements/elementsJets.c
+ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/elements/ops.c
+ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/elements/primitive.c
+ELEMENTS_SIMPLICITY_LIB_SOURCES_INT += %reldir%/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
@@ -89,11 +89,12 @@ ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/secp256k1/secp256k1.h
ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/secp256k1/secp256k1_impl.h
ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/secp256k1/util.h
-ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/decodeElementsJets.inc
-ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/elementsJets.h
-ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/ops.h
-ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/primitive.h
-ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/primitive/elements/primitiveEnumJet.inc
-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%/elements/decodeElementsJets.inc
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/elementsJets.h
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/ops.h
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/primitive.h
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/primitiveEnumJet.inc
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/primitiveEnumTy.inc
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/primitiveInitTy.inc
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/primitiveJetNode.inc
+ELEMENTS_SIMPLICITY_LIB_HEADERS_INT += %reldir%/elements/txEnv.h
diff --git a/src/simplicity/primitive/elements/checkSigHashAllTx1.c b/src/simplicity/elements/checkSigHashAllTx1.c
similarity index 100%
rename from src/simplicity/primitive/elements/checkSigHashAllTx1.c
rename to src/simplicity/elements/checkSigHashAllTx1.c
diff --git a/src/simplicity/primitive/elements/checkSigHashAllTx1.h b/src/simplicity/elements/checkSigHashAllTx1.h
similarity index 90%
rename from src/simplicity/primitive/elements/checkSigHashAllTx1.h
rename to src/simplicity/elements/checkSigHashAllTx1.h
index b2bb7c5d9d0..c7a4582e095 100644
--- a/src/simplicity/primitive/elements/checkSigHashAllTx1.h
+++ b/src/simplicity/elements/checkSigHashAllTx1.h
@@ -1,9 +1,9 @@
-#ifndef SIMPLICITY_PRIMITIVE_ELEMENTS_CHECKSIGHASHALLTX1_H
-#define SIMPLICITY_PRIMITIVE_ELEMENTS_CHECKSIGHASHALLTX1_H
+#ifndef SIMPLICITY_ELEMENTS_CHECKSIGHASHALLTX1_H
+#define SIMPLICITY_ELEMENTS_CHECKSIGHASHALLTX1_H
#include
#include
-#include "../../bounded.h"
+#include "../bounded.h"
/* A length-prefixed encoding of the following Simplicity program:
* Simplicity.Programs.CheckSig.Lib.checkSigVerify' Simplicity.Elements.Programs.SigHash.Lib.sigAllHash
diff --git a/src/simplicity/cmr.c b/src/simplicity/elements/cmr.c
similarity index 73%
rename from src/simplicity/cmr.c
rename to src/simplicity/elements/cmr.c
index b4a94fc7de6..dd73be4ed93 100644
--- a/src/simplicity/cmr.c
+++ b/src/simplicity/elements/cmr.c
@@ -1,9 +1,10 @@
-#include
+#include
-#include "deserialize.h"
-#include "limitations.h"
-#include "simplicity_alloc.h"
-#include "simplicity_assert.h"
+#include "../deserialize.h"
+#include "../limitations.h"
+#include "../simplicity_alloc.h"
+#include "../simplicity_assert.h"
+#include "primitive.h"
/* Deserialize a Simplicity 'program' and compute its CMR.
*
@@ -18,15 +19,15 @@
* unsigned char cmr[32]
* unsigned char program[program_len]
*/
-bool simplicity_computeCmr( simplicity_err* error, unsigned char* cmr
- , const unsigned char* program, size_t program_len) {
+bool simplicity_elements_computeCmr( simplicity_err* error, unsigned char* cmr
+ , const unsigned char* program, size_t program_len) {
simplicity_assert(NULL != error);
simplicity_assert(NULL != cmr);
simplicity_assert(NULL != program || 0 == program_len);
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/src/simplicity/primitive/elements/decodeElementsJets.inc b/src/simplicity/elements/decodeElementsJets.inc
similarity index 100%
rename from src/simplicity/primitive/elements/decodeElementsJets.inc
rename to src/simplicity/elements/decodeElementsJets.inc
diff --git a/src/simplicity/primitive/elements/elementsJets.c b/src/simplicity/elements/elementsJets.c
similarity index 99%
rename from src/simplicity/primitive/elements/elementsJets.c
rename to src/simplicity/elements/elementsJets.c
index e958f2fffec..dfdf5be6342 100644
--- a/src/simplicity/primitive/elements/elementsJets.c
+++ b/src/simplicity/elements/elementsJets.c
@@ -1,9 +1,9 @@
#include "elementsJets.h"
#include "ops.h"
-#include "primitive.h"
-#include "../../taptweak.h"
-#include "../../simplicity_assert.h"
+#include "txEnv.h"
+#include "../taptweak.h"
+#include "../simplicity_assert.h"
/* Read a 256-bit hash value from the 'src' frame, advancing the cursor 256 cells.
*
@@ -145,19 +145,19 @@ static void issuanceTokenAmt(frameItem* dst, const assetIssuance* issuance) {
}
}
-static uint_fast32_t lockHeight(const transaction* tx) {
+static uint_fast32_t lockHeight(const elementsTransaction* tx) {
return !tx->isFinal && tx->lockTime < 500000000U ? tx->lockTime : 0;
}
-static uint_fast32_t lockTime(const transaction* tx) {
+static uint_fast32_t lockTime(const elementsTransaction* tx) {
return !tx->isFinal && 500000000U <= tx->lockTime ? tx->lockTime : 0;
}
-static uint_fast16_t lockDistance(const transaction* tx) {
+static uint_fast16_t lockDistance(const elementsTransaction* tx) {
return 2 <= tx->version ? tx->lockDistance : 0;
}
-static uint_fast16_t lockDuration(const transaction* tx) {
+static uint_fast16_t lockDuration(const elementsTransaction* tx) {
return 2 <= tx->version ? tx->lockDuration : 0;
}
diff --git a/src/simplicity/primitive/elements/elementsJets.h b/src/simplicity/elements/elementsJets.h
similarity index 98%
rename from src/simplicity/primitive/elements/elementsJets.h
rename to src/simplicity/elements/elementsJets.h
index 2043fc023bb..d6412195c6c 100644
--- a/src/simplicity/primitive/elements/elementsJets.h
+++ b/src/simplicity/elements/elementsJets.h
@@ -1,9 +1,9 @@
/* This module defines primitives and jets that are specific to the Elements application for Simplicity.
*/
-#ifndef SIMPLICITY_PRIMITIVE_ELEMENTS_JETS_H
-#define SIMPLICITY_PRIMITIVE_ELEMENTS_JETS_H
+#ifndef SIMPLICITY_ELEMENTS_ELEMENTSJETS_H
+#define SIMPLICITY_ELEMENTS_ELEMENTSJETS_H
-#include "../../jets.h"
+#include "../jets.h"
/* Jets for the Elements application of Simplicity. */
bool simplicity_version(frameItem* dst, frameItem src, const txEnv* env);
diff --git a/src/simplicity/primitive/elements/env.c b/src/simplicity/elements/env.c
similarity index 88%
rename from src/simplicity/primitive/elements/env.c
rename to src/simplicity/elements/env.c
index a849dc45fd4..af39d5223d9 100644
--- a/src/simplicity/primitive/elements/env.c
+++ b/src/simplicity/elements/env.c
@@ -3,12 +3,12 @@
#include
#include
#include
-#include "primitive.h"
+#include "txEnv.h"
#include "ops.h"
-#include "../../rsort.h"
-#include "../../sha256.h"
-#include "../../simplicity_assert.h"
-#include "../../simplicity_alloc.h"
+#include "../rsort.h"
+#include "../sha256.h"
+#include "../simplicity_assert.h"
+#include "../simplicity_alloc.h"
#define PADDING(alignType, allocated) ((alignof(alignType) - (allocated) % alignof(alignType)) % alignof(alignType))
@@ -17,13 +17,13 @@
* Precondition: NULL != result;
* NULL != scriptPubKey;
*/
-static void hashBuffer(sha256_midstate* result, const rawBuffer* buffer) {
+static void hashBuffer(sha256_midstate* result, const rawElementsBuffer* buffer) {
sha256_context ctx = sha256_init(result->s);
sha256_uchars(&ctx, buffer->buf, buffer->len);
sha256_finalize(&ctx);
}
-/* Initialize a 'confidential' asset or 'confidential' nonce from an unsigned char array from a 'rawTransaction'.
+/* Initialize a 'confidential' asset or 'confidential' nonce from an unsigned char array from a 'rawElementsTransaction'.
*
* Precondition: NULL != conf;
* unsigned char rawConf[33] or rawConf == NULL;
@@ -40,7 +40,7 @@ static void copyRawConfidential(confidential* conf, const unsigned char* rawConf
}
}
-/* Initialize a 'confAmount' from an unsigned char array from a 'rawTransaction'.
+/* Initialize a 'confAmount' from an unsigned char array from a 'rawElementsTransaction'.
*
* Precondition: NULL != amt;
* unsigned char rawAmt[rawAmt[0] == 0x01 ? 9 : 33] or rawAmt == NULL
@@ -60,12 +60,12 @@ static void copyRawAmt(confAmount* amt, const unsigned char* rawAmt) {
}
}
-/* Initialize a 'sigInput' from a 'rawInput', copying or hashing the data as needed.
+/* Initialize a 'sigInput' from a 'rawElementsInput', copying or hashing the data as needed.
*
* Precondition: NULL != result;
* NULL != input;
*/
-static void copyInput(sigInput* result, const rawInput* input) {
+static void copyInput(sigInput* result, const rawElementsInput* input) {
*result = (sigInput){ .prevOutpoint = { .ix = input->prevIx }
, .sequence = input->sequence
, .isPegin = !!input->pegin
@@ -79,8 +79,8 @@ static void copyInput(sigInput* result, const rawInput* input) {
copyRawConfidential(&result->txo.asset, input->txo.asset);
copyRawAmt(&result->txo.amt, input->txo.value);
hashBuffer(&result->scriptSigHash, &input->scriptSig);
- hashBuffer(&result->issuance.assetRangeProofHash, &(rawBuffer){0});
- hashBuffer(&result->issuance.tokenRangeProofHash, &(rawBuffer){0});
+ hashBuffer(&result->issuance.assetRangeProofHash, &(rawElementsBuffer){0});
+ hashBuffer(&result->issuance.tokenRangeProofHash, &(rawElementsBuffer){0});
if (input->issuance.amount || input->issuance.inflationKeys) {
sha256_toMidstate(result->issuance.blindingNonce.s, input->issuance.blindingNonce);
copyRawAmt(&result->issuance.assetAmt, input->issuance.amount);
@@ -104,13 +104,13 @@ static void copyInput(sigInput* result, const rawInput* input) {
}
/* As specified in https://github.com/ElementsProject/elements/blob/de942511a67c3a3fcbdf002a8ee7e9ba49679b78/src/primitives/transaction.h#L304-L307. */
-static bool isFee(const rawOutput* output) {
+static bool isFee(const rawElementsOutput* output) {
return 0 == output->scriptPubKey.len && /* Empty scriptPubKey */
NULL != output->asset && 0x01 == output->asset[0] && /* Explicit asset */
NULL != output->value && 0x01 == output->value[0]; /* Explicit amount */
}
-static uint_fast32_t countFeeOutputs(const rawTransaction* rawTx) {
+static uint_fast32_t countFeeOutputs(const rawElementsTransaction* rawTx) {
uint_fast32_t result = 0;
for (uint_fast32_t i = 0; i < rawTx->numOutputs; ++i) {
result += isFee(&rawTx->output[i]);
@@ -126,7 +126,7 @@ static uint_fast32_t countFeeOutputs(const rawTransaction* rawTx) {
*
* Precondition: NULL != scriptPubKey
*/
-static uint_fast32_t countNullDataCodes(const rawBuffer* scriptPubKey) {
+static uint_fast32_t countNullDataCodes(const rawElementsBuffer* scriptPubKey) {
if (0 == scriptPubKey->len || 0x6a != scriptPubKey->buf[0] ) return 0;
uint_fast32_t result = 0;
@@ -161,7 +161,7 @@ static uint_fast32_t countNullDataCodes(const rawBuffer* scriptPubKey) {
*
* Precondition: NULL != rawTx
*/
-static uint_fast64_t countTotalNullDataCodes(const rawTransaction* rawTx) {
+static uint_fast64_t countTotalNullDataCodes(const rawElementsTransaction* rawTx) {
uint_fast64_t result = 0;
for (uint_fast32_t i = 0; i < rawTx->numOutputs; ++i) {
result += countNullDataCodes(&rawTx->output[i].scriptPubKey);
@@ -186,7 +186,7 @@ static uint_fast64_t countTotalNullDataCodes(const rawTransaction* rawTx) {
* NULL != scriptPubKey;
* countNullDataCodes(scriptPubKey) <= *allocationLen
*/
-static void parseNullData(parsedNullData* result, opcode** allocation, size_t* allocationLen, const rawBuffer* scriptPubKey) {
+static void parseNullData(parsedNullData* result, opcode** allocation, size_t* allocationLen, const rawElementsBuffer* scriptPubKey) {
*result = (parsedNullData){ .op = *allocation };
if (0 == scriptPubKey->len || 0x6a != scriptPubKey->buf[0] ) { result->op = NULL; return; }
@@ -233,7 +233,7 @@ static void parseNullData(parsedNullData* result, opcode** allocation, size_t* a
*allocationLen -= result->len;
}
-/* Initialize a 'sigOutput' from a 'rawOutput', copying or hashing the data as needed.
+/* Initialize a 'sigOutput' from a 'rawElementsOutput', copying or hashing the data as needed.
*
* '*allocation' is incremented by 'countNullDataCodes(&output->scriptPubKey)'
* '*allocationLen' is decremented by 'countNullDataCodes(&output->scriptPubKey)'.
@@ -245,7 +245,7 @@ static void parseNullData(parsedNullData* result, opcode** allocation, size_t* a
* NULL != output;
* countNullDataCodes(&output->scriptPubKey) <= *allocationLen
*/
-static void copyOutput(sigOutput* result, opcode** allocation, size_t* allocationLen, const rawOutput* output) {
+static void copyOutput(sigOutput* result, opcode** allocation, size_t* allocationLen, const rawElementsOutput* output) {
hashBuffer(&result->scriptPubKey, &output->scriptPubKey);
result->emptyScript = 0 == output->scriptPubKey.len;
copyRawConfidential(&result->asset, output->asset);
@@ -253,8 +253,8 @@ static void copyOutput(sigOutput* result, opcode** allocation, size_t* allocatio
copyRawConfidential(&result->nonce, output->nonce);
parseNullData(&result->pnd, allocation, allocationLen, &output->scriptPubKey);
result->isNullData = NULL != result->pnd.op;
- hashBuffer(&result->surjectionProofHash, is_confidential(result->asset.prefix) ? &output->surjectionProof : &(rawBuffer){0});
- hashBuffer(&result->rangeProofHash, is_confidential(result->amt.prefix) ? &output->rangeProof : &(rawBuffer){0});
+ hashBuffer(&result->surjectionProofHash, is_confidential(result->asset.prefix) ? &output->surjectionProof : &(rawElementsBuffer){0});
+ hashBuffer(&result->rangeProofHash, is_confidential(result->amt.prefix) ? &output->rangeProof : &(rawElementsBuffer){0});
result->assetFee = 0;
}
@@ -306,15 +306,15 @@ static uint_fast32_t sumFees(sigOutput** feeOutputs, uint_fast32_t numFees) {
return result + 1;
}
-/* Allocate and initialize a 'transaction' from a 'rawTransaction', copying or hashing the data as needed.
+/* Allocate and initialize a 'elementsTransaction' from a 'rawElementsTransaction', copying or hashing the data as needed.
* Returns NULL if malloc fails (or if malloc cannot be called because we require an allocation larger than SIZE_MAX).
*
* Precondition: NULL != rawTx
*/
-extern transaction* simplicity_elements_mallocTransaction(const rawTransaction* rawTx) {
+extern elementsTransaction* simplicity_elements_mallocTransaction(const rawElementsTransaction* rawTx) {
if (!rawTx) return NULL;
- size_t allocationSize = sizeof(transaction);
+ size_t allocationSize = sizeof(elementsTransaction);
const size_t pad1 = PADDING(sigInput, allocationSize);
if (SIZE_MAX - allocationSize < pad1) return NULL;
@@ -360,8 +360,8 @@ extern transaction* simplicity_elements_mallocTransaction(const rawTransaction*
/* Casting through void* to avoid warning about pointer alignment.
* Our padding is done carefully to ensure alignment.
*/
- transaction* const tx = (transaction*)(void*)allocation;
- allocation += sizeof(transaction) + pad1;
+ elementsTransaction* const tx = (elementsTransaction*)(void*)allocation;
+ allocation += sizeof(elementsTransaction) + pad1;
sigInput* const input = (sigInput*)(void*)allocation;
allocation += rawTx->numInputs * sizeof(sigInput) + pad2;
@@ -379,15 +379,15 @@ extern transaction* simplicity_elements_mallocTransaction(const rawTransaction*
but C forgoes the complicated specification of C++. Therefore we must make an explicit cast of feeOutputs in C.
See for details.
*/
- *tx = (transaction){ .input = input
- , .output = output
- , .feeOutputs = (sigOutput const * const *)feeOutputs
- , .numInputs = rawTx->numInputs
- , .numOutputs = rawTx->numOutputs
- , .version = rawTx->version
- , .lockTime = rawTx->lockTime
- , .isFinal = true
- };
+ *tx = (elementsTransaction){ .input = input
+ , .output = output
+ , .feeOutputs = (sigOutput const * const *)feeOutputs
+ , .numInputs = rawTx->numInputs
+ , .numOutputs = rawTx->numOutputs
+ , .version = rawTx->version
+ , .lockTime = rawTx->lockTime
+ , .isFinal = true
+ };
sha256_toMidstate(tx->txid.s, rawTx->txid);
{
@@ -569,22 +569,22 @@ extern transaction* simplicity_elements_mallocTransaction(const rawTransaction*
return tx;
}
-/* Free a pointer to 'transaction'.
+/* Free a pointer to 'elementsTransaction'.
*/
-extern void simplicity_elements_freeTransaction(transaction* tx) {
+extern void simplicity_elements_freeTransaction(elementsTransaction* tx) {
simplicity_free(tx);
}
-/* Allocate and initialize a 'tapEnv' from a 'rawTapEnv', copying or hashing the data as needed.
+/* Allocate and initialize a 'elementsTapEnv' from a 'rawElementsTapEnv', copying or hashing the data as needed.
* Returns NULL if malloc fails (or if malloc cannot be called because we require an allocation larger than SIZE_MAX).
*
* Precondition: *rawEnv is well-formed (i.e. rawEnv->pathLen <= 128.)
*/
-extern tapEnv* simplicity_elements_mallocTapEnv(const rawTapEnv* rawEnv) {
+extern elementsTapEnv* simplicity_elements_mallocTapEnv(const rawElementsTapEnv* rawEnv) {
if (!rawEnv) return NULL;
if (128 < rawEnv->pathLen) return NULL;
- size_t allocationSize = sizeof(tapEnv);
+ size_t allocationSize = sizeof(elementsTapEnv);
const size_t numMidstate = rawEnv->pathLen;
const size_t pad1 = PADDING(sha256_midstate, allocationSize);
@@ -604,25 +604,25 @@ extern tapEnv* simplicity_elements_mallocTapEnv(const rawTapEnv* rawEnv) {
/* Casting through void* to avoid warning about pointer alignment.
* Our padding is done carefully to ensure alignment.
*/
- tapEnv* const env = (tapEnv*)(void*)allocation;
+ elementsTapEnv* const env = (elementsTapEnv*)(void*)allocation;
sha256_midstate* path = NULL;
sha256_midstate internalKey;
sha256_toMidstate(internalKey.s, &rawEnv->controlBlock[1]);
if (numMidstate) {
- allocation += sizeof(tapEnv) + pad1;
+ allocation += sizeof(elementsTapEnv) + pad1;
if (rawEnv->pathLen) {
path = (sha256_midstate*)(void*)allocation;
}
}
- *env = (tapEnv){ .leafVersion = rawEnv->controlBlock[0] & 0xfe
- , .internalKey = internalKey
- , .path = path
- , .pathLen = rawEnv->pathLen
- };
+ *env = (elementsTapEnv){ .leafVersion = rawEnv->controlBlock[0] & 0xfe
+ , .internalKey = internalKey
+ , .path = path
+ , .pathLen = rawEnv->pathLen
+ };
sha256_toMidstate(env->scriptCMR.s, rawEnv->scriptCMR);
{
@@ -646,33 +646,8 @@ extern tapEnv* simplicity_elements_mallocTapEnv(const rawTapEnv* rawEnv) {
return env;
}
-/* Free a pointer to 'tapEnv'.
+/* Free a pointer to 'elementsTapEnv'.
*/
-extern void simplicity_elements_freeTapEnv(tapEnv* env) {
+extern void simplicity_elements_freeTapEnv(elementsTapEnv* 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/src/simplicity/primitive/elements/exec.c b/src/simplicity/elements/exec.c
similarity index 74%
rename from src/simplicity/primitive/elements/exec.c
rename to src/simplicity/elements/exec.c
index e38c9ca41a5..4dfcf421056 100644
--- a/src/simplicity/primitive/elements/exec.c
+++ b/src/simplicity/elements/exec.c
@@ -3,12 +3,13 @@
#include
#include
#include "primitive.h"
-#include "../../deserialize.h"
-#include "../../eval.h"
-#include "../../limitations.h"
-#include "../../simplicity_alloc.h"
-#include "../../simplicity_assert.h"
-#include "../../typeInference.h"
+#include "txEnv.h"
+#include "../deserialize.h"
+#include "../eval.h"
+#include "../limitations.h"
+#include "../simplicity_alloc.h"
+#include "../simplicity_assert.h"
+#include "../typeInference.h"
/* Deserialize a Simplicity 'program' with its 'witness' data and execute it in the environment of the 'ix'th input of 'tx' with `taproot`.
*
@@ -17,6 +18,12 @@
* Otherwise, 'true' is returned indicating that the result was successfully computed and returned in the '*error' value.
*
* If deserialization, analysis, or execution fails, then '*error' is set to some simplicity_err.
+ * In particular, if the cost analysis exceeds the budget, or exceeds BUDGET_MAX, then '*error' is set to 'SIMPLICITY_ERR_EXEC_BUDGET'.
+ * On the other hand, if the cost analysis is less than or equal to minCost, then '*error' is set to 'SIMPLICITY_ERR_OVERWEIGHT'.
+ *
+ * Note that minCost and budget parameters are in WU, while the cost analysis will be performed in milliWU.
+ * Thus the minCost and budget specify a half open interval (minCost, budget] of acceptable cost values in milliWU.
+ * Setting minCost to 0 effectively disables the minCost check as every Simplicity program has a non-zero cost analysis.
*
* If 'amr != NULL' and the annotated Merkle root of the decoded expression doesn't match 'amr' then '*error' is set to 'SIMPLICITY_ERR_AMR'.
*
@@ -30,15 +37,15 @@
* NULL != tx;
* NULL != taproot;
* unsigned char genesisBlockHash[32]
- * 0 <= budget;
+ * 0 <= minCost <= budget;
* NULL != amr implies unsigned char amr[32]
* unsigned char program[program_len]
* unsigned char witness[witness_len]
*/
extern bool simplicity_elements_execSimplicity( simplicity_err* error, unsigned char* ihr
- , const transaction* tx, uint_fast32_t ix, const tapEnv* taproot
+ , const elementsTransaction* tx, uint_fast32_t ix, const elementsTapEnv* taproot
, const unsigned char* genesisBlockHash
- , int64_t budget
+ , int64_t minCost, int64_t budget
, const unsigned char* amr
, const unsigned char* program, size_t program_len
, const unsigned char* witness, size_t witness_len) {
@@ -46,7 +53,8 @@ extern bool simplicity_elements_execSimplicity( simplicity_err* error, unsigned
simplicity_assert(NULL != tx);
simplicity_assert(NULL != taproot);
simplicity_assert(NULL != genesisBlockHash);
- simplicity_assert(0 <= budget);
+ simplicity_assert(0 <= minCost);
+ simplicity_assert(minCost <= budget);
simplicity_assert(NULL != program || 0 == program_len);
simplicity_assert(NULL != witness || 0 == witness_len);
@@ -60,7 +68,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 +87,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) {
@@ -117,9 +125,12 @@ extern bool simplicity_elements_execSimplicity( simplicity_err* error, unsigned
simplicity_free(analysis);
}
if (IS_OK(*error)) {
- txEnv env = simplicity_build_txEnv(tx, taproot, &genesis_hash, ix);
+ txEnv env = simplicity_elements_build_txEnv(tx, taproot, &genesis_hash, ix);
static_assert(BUDGET_MAX <= UBOUNDED_MAX, "BUDGET_MAX doesn't fit in ubounded.");
- *error = evalTCOProgram(dag, type_dag, (size_t)dag_len, &(ubounded){budget <= BUDGET_MAX ? (ubounded)budget : BUDGET_MAX}, &env);
+ *error = evalTCOProgram( dag, type_dag, (size_t)dag_len
+ , minCost <= BUDGET_MAX ? (ubounded)minCost : BUDGET_MAX
+ , &(ubounded){budget <= BUDGET_MAX ? (ubounded)budget : BUDGET_MAX}
+ , &env);
}
simplicity_free(type_dag);
}
diff --git a/src/simplicity/primitive/elements/ops.c b/src/simplicity/elements/ops.c
similarity index 100%
rename from src/simplicity/primitive/elements/ops.c
rename to src/simplicity/elements/ops.c
diff --git a/src/simplicity/primitive/elements/ops.h b/src/simplicity/elements/ops.h
similarity index 95%
rename from src/simplicity/primitive/elements/ops.h
rename to src/simplicity/elements/ops.h
index 87e9fb3a32e..d704d64e0a7 100644
--- a/src/simplicity/primitive/elements/ops.h
+++ b/src/simplicity/elements/ops.h
@@ -1,10 +1,10 @@
/* This module defines operations used in the construction the environment ('txEnv') and some jets.
*/
-#ifndef SIMPLICITY_PRIMITIVE_ELEMENTS_OPS_H
-#define SIMPLICITY_PRIMITIVE_ELEMENTS_OPS_H
+#ifndef SIMPLICITY_ELEMENTS_OPS_H
+#define SIMPLICITY_ELEMENTS_OPS_H
-#include "../../sha256.h"
-#include "primitive.h"
+#include "../sha256.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/src/simplicity/primitive/elements/primitive.c b/src/simplicity/elements/primitive.c
similarity index 89%
rename from src/simplicity/primitive/elements/primitive.c
rename to src/simplicity/elements/primitive.c
index da08b920940..72e41e5b6c6 100644
--- a/src/simplicity/primitive/elements/primitive.c
+++ b/src/simplicity/elements/primitive.c
@@ -1,12 +1,9 @@
-/* This module implements the 'primitive.h' interface for the Elements application of Simplicity.
- */
#include "primitive.h"
#include "elementsJets.h"
-#include "../../limitations.h"
-#include "../../primitive.h"
-#include "../../simplicity_alloc.h"
-#include "../../simplicity_assert.h"
+#include "../limitations.h"
+#include "../simplicity_alloc.h"
+#include "../simplicity_assert.h"
/* An enumeration of all the types we need to construct to specify the input and output types of all jets created by 'decodeJet'. */
enum TypeNamesForJets {
@@ -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");
@@ -71,7 +68,7 @@ static simplicity_err decodePrimitive(jetName* result, bitstream* stream) {
if (bit < 0) return (simplicity_err)bit;
if (!bit) {
/* Core jets */
-#include "../../decodeCoreJets.inc"
+#include "../decodeCoreJets.inc"
return SIMPLICITY_ERR_DATA_OUT_OF_RANGE;
} else {
/* Elements jets */
@@ -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/src/simplicity/primitive.h b/src/simplicity/elements/primitive.h
similarity index 78%
rename from src/simplicity/primitive.h
rename to src/simplicity/elements/primitive.h
index dc17fb0b948..16b426783e9 100644
--- a/src/simplicity/primitive.h
+++ b/src/simplicity/elements/primitive.h
@@ -1,10 +1,10 @@
-/* This module defines the interface that each Simplicity application must implement.
+/* Implements the required callbacks for the Elements Simplicity application.
*/
-#ifndef SIMPLICITY_PRIMITIVE_H
-#define SIMPLICITY_PRIMITIVE_H
+#ifndef SIMPLICITY_ELEMENTS_PRIMITIVE_H
+#define SIMPLICITY_ELEMENTS_PRIMITIVE_H
-#include "bitstream.h"
-#include "typeInference.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',
@@ -24,7 +24,7 @@
* '(*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);
/* 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'.
@@ -36,6 +36,6 @@ size_t simplicity_mallocBoundVars(unification_var** bound_var, size_t* word256_i
* Precondition: NULL != node
* NULL != stream
*/
-simplicity_err simplicity_decodeJet(dag_node* node, bitstream* stream);
+simplicity_err simplicity_elements_decodeJet(dag_node* node, bitstream* stream);
#endif
diff --git a/src/simplicity/primitive/elements/primitiveEnumJet.inc b/src/simplicity/elements/primitiveEnumJet.inc
similarity index 100%
rename from src/simplicity/primitive/elements/primitiveEnumJet.inc
rename to src/simplicity/elements/primitiveEnumJet.inc
diff --git a/src/simplicity/primitive/elements/primitiveEnumTy.inc b/src/simplicity/elements/primitiveEnumTy.inc
similarity index 100%
rename from src/simplicity/primitive/elements/primitiveEnumTy.inc
rename to src/simplicity/elements/primitiveEnumTy.inc
diff --git a/src/simplicity/primitive/elements/primitiveInitTy.inc b/src/simplicity/elements/primitiveInitTy.inc
similarity index 100%
rename from src/simplicity/primitive/elements/primitiveInitTy.inc
rename to src/simplicity/elements/primitiveInitTy.inc
diff --git a/src/simplicity/primitive/elements/primitiveJetNode.inc b/src/simplicity/elements/primitiveJetNode.inc
similarity index 100%
rename from src/simplicity/primitive/elements/primitiveJetNode.inc
rename to src/simplicity/elements/primitiveJetNode.inc
diff --git a/src/simplicity/elements/txEnv.c b/src/simplicity/elements/txEnv.c
new file mode 100644
index 00000000000..a7b9f8ef12c
--- /dev/null
+++ b/src/simplicity/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_elements_build_txEnv(const elementsTransaction* tx, const elementsTapEnv* 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/src/simplicity/primitive/elements/primitive.h b/src/simplicity/elements/txEnv.h
similarity index 95%
rename from src/simplicity/primitive/elements/primitive.h
rename to src/simplicity/elements/txEnv.h
index b095107722f..f4493530de0 100644
--- a/src/simplicity/primitive/elements/primitive.h
+++ b/src/simplicity/elements/txEnv.h
@@ -2,11 +2,11 @@
* 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_H
-#define SIMPLICITY_PRIMITIVE_ELEMENTS_H
+#ifndef SIMPLICITY_ELEMENTS_TXENV_H
+#define SIMPLICITY_ELEMENTS_TXENV_H
#include
-#include "../../sha256.h"
+#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.
@@ -194,7 +194,7 @@ typedef struct 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 {
+typedef struct elementsTransaction {
const sigInput* input;
const sigOutput* output;
const sigOutput* const * feeOutputs;
@@ -230,14 +230,14 @@ typedef struct transaction {
uint_fast16_t lockDistance;
uint_fast16_t lockDuration; /* Units of 512 seconds */
bool isFinal;
-} transaction;
+} elementsTransaction;
/* A structure representing taproot spending data from an Elements transaction.
*
* Invariant: pathLen <= 128
* sha256_midstate path[pathLen];
*/
-typedef struct tapEnv {
+typedef struct elementsTapEnv {
const sha256_midstate *path;
sha256_midstate tapLeafHash;
sha256_midstate tappathHash;
@@ -246,7 +246,7 @@ typedef struct tapEnv {
sha256_midstate scriptCMR;
unsigned char pathLen;
unsigned char leafVersion;
-} tapEnv;
+} elementsTapEnv;
/* The 'txEnv' structure used by the Elements application of Simplicity.
*
@@ -256,8 +256,8 @@ typedef struct tapEnv {
* + the hash of the genesis block for the chain,
*/
typedef struct txEnv {
- const transaction* tx;
- const tapEnv* taproot;
+ const elementsTransaction* tx;
+ const elementsTapEnv* taproot;
sha256_midstate genesisHash;
sha256_midstate sigAllHash;
uint_fast32_t ix;
@@ -271,6 +271,6 @@ typedef struct txEnv {
* NULL != genesisHash
* ix < tx->numInputs
*/
-txEnv simplicity_build_txEnv(const transaction* tx, const tapEnv* taproot, const sha256_midstate* genesisHash, uint_fast32_t ix);
+txEnv simplicity_elements_build_txEnv(const elementsTransaction* tx, const elementsTapEnv* taproot, const sha256_midstate* genesisHash, uint_fast32_t ix);
#endif
diff --git a/src/simplicity/eval.c b/src/simplicity/eval.c
index b1117e8b0d5..6c9e9dc05e8 100644
--- a/src/simplicity/eval.c
+++ b/src/simplicity/eval.c
@@ -571,6 +571,7 @@ typedef struct boundsAnalysis {
* When maxCells < UBOUNDED_MAX, if the bounds on the number of cells needed for evaluation of 'dag' on an idealized Bit Machine exceeds maxCells,
* then return SIMPLICITY_ERR_EXEC_MEMORY.
* When maxCost < UBOUNDED_MAX, if the bounds on the dag's CPU cost exceeds 'maxCost', then return SIMPLICITY_ERR_EXEC_BUDGET.
+ * If the bounds on the dag's CPU cost is less than or equal to 'minCost', then return SIMPLICITY_ERR_OVERWEIGHT.
* Otherwise returns SIMPLICITY_NO_ERR.
*
* Precondition: NULL != cellsBound
@@ -583,11 +584,9 @@ typedef struct boundsAnalysis {
* and if maxCells < UBOUNDED_MAX then '*cellsBound' bounds the number of cells needed for evaluation of 'dag' on an idealized Bit Machine
* and if maxCells < UBOUNDED_MAX then '*UWORDBound' bounds the number of UWORDs needed for the frames during evaluation of 'dag'
* and if maxCells < UBOUNDED_MAX then '*frameBound' bounds the number of stack frames needed during execution of 'dag'.
- *
- * :TODO: The cost calculations below are estimated and need to be replaced by experimental data.
*/
simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBound, ubounded *frameBound, ubounded *costBound
- , ubounded maxCells, ubounded maxCost, const dag_node* dag, const type* type_dag, const size_t len) {
+ , ubounded maxCells, ubounded minCost, ubounded maxCost, const dag_node* dag, const type* type_dag, const size_t len) {
static_assert(DAG_LEN_MAX <= SIZE_MAX / sizeof(boundsAnalysis), "bound array too large.");
static_assert(1 <= DAG_LEN_MAX, "DAG_LEN_MAX is zero.");
static_assert(DAG_LEN_MAX - 1 <= UINT32_MAX, "bound array index does not fit in uint32_t.");
@@ -741,6 +740,7 @@ simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBo
*/
return (maxCells < *cellsBound) ? SIMPLICITY_ERR_EXEC_MEMORY
: (maxCost < *costBound) ? SIMPLICITY_ERR_EXEC_BUDGET
+ : (*costBound <= minCost) ? SIMPLICITY_ERR_OVERWEIGHT
: SIMPLICITY_NO_ERROR;
}
@@ -748,11 +748,16 @@ simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBo
* If bitSize(A) > 0, initialize the active read frame's data with 'input[ROUND_UWORD(bitSize(A))]'.
*
* If malloc fails, returns 'SIMPLICITY_ERR_MALLOC'.
- * When a budget is given, if static analysis results determines the bound on cpu requirements exceed the allowed budget, returns 'SIMPLICITY_ERR_EXEC_BUDGET'
- * If static analysis results determines the bound on memory allocation requirements exceed the allowed limits, returns 'SIMPLICITY_ERR_EXEC_MEMORY'
+ * When a budget is given, if static analysis results determines the bound on cpu requirements exceed the allowed budget, returns 'SIMPLICITY_ERR_EXEC_BUDGET'.
+ * If static analysis results determines the bound on cpu requirements is less than or equal to the minCost, returns 'SIMPLICITY_ERR_OVERWEIGHT'.
+ * If static analysis results determines the bound on memory allocation requirements exceed the allowed limits, returns 'SIMPLICITY_ERR_EXEC_MEMORY'.
* If during execution some jet execution fails, returns 'SIMPLICITY_ERR_EXEC_JET'.
* If during execution some 'assertr' or 'assertl' combinator fails, returns 'SIMPLICITY_ERR_EXEC_ASESRT'.
*
+ * Note that minCost and budget parameters are in WU, while the cost analysis will be performed in milliWU.
+ * Thus the minCost and budget specify a half open interval (minCost, budget] of acceptable cost values in milliWU.
+ * Setting minCost to 0 effectively disables the minCost check as every Simplicity program has a non-zero cost analysis.
+ *
* If none of the above conditions fail and bitSize(B) > 0, then a copy the final active write frame's data is written to 'output[roundWord(bitSize(B))]'.
*
* If 'anti_dos_checks' includes the 'CHECK_EXEC' flag, and not every non-HIDDEN dag node is executed, returns 'SIMPLICITY_ERR_ANTIDOS'
@@ -764,19 +769,25 @@ simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBo
* bitSize(A) == 0 or UWORD input[ROUND_UWORD(bitSize(A))];
* bitSize(B) == 0 or UWORD output[ROUND_UWORD(bitSize(B))];
* if NULL != budget then *budget <= BUDGET_MAX
+ * if NULL != budget then minCost <= *budget
+ * minCost <= BUDGET_MAX
* if 'dag[len]' represents a Simplicity expression with primitives then 'NULL != env';
*/
simplicity_err simplicity_evalTCOExpression( flags_type anti_dos_checks, UWORD* output, const UWORD* input
- , const dag_node* dag, type* type_dag, size_t len, const ubounded* budget, const txEnv* env
- ) {
+ , const dag_node* dag, type* type_dag, size_t len, ubounded minCost, const ubounded* budget, const txEnv* env
+ ) {
simplicity_assert(1 <= len);
simplicity_assert(len <= DAG_LEN_MAX);
- if (budget) { simplicity_assert(*budget <= BUDGET_MAX); }
+ if (budget) {
+ simplicity_assert(*budget <= BUDGET_MAX);
+ simplicity_assert(minCost <= *budget);
+ }
+ simplicity_assert(minCost <= BUDGET_MAX);
static_assert(1 <= UBOUNDED_MAX, "UBOUNDED_MAX is zero.");
static_assert(BUDGET_MAX <= (UBOUNDED_MAX - 1) / 1000, "BUDGET_MAX is too large.");
static_assert(CELLS_MAX < UBOUNDED_MAX, "CELLS_MAX is too large.");
ubounded cellsBound, UWORDBound, frameBound, costBound;
- simplicity_err result = simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, CELLS_MAX, budget ? *budget*1000 : UBOUNDED_MAX, dag, type_dag, len);
+ simplicity_err result = simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, CELLS_MAX, minCost*1000, budget ? *budget*1000 : UBOUNDED_MAX, dag, type_dag, len);
if (!IS_OK(result)) return result;
/* frameBound is at most 2*len. */
diff --git a/src/simplicity/eval.h b/src/simplicity/eval.h
index ba6a6759057..cef5cb73b20 100644
--- a/src/simplicity/eval.h
+++ b/src/simplicity/eval.h
@@ -18,6 +18,7 @@ typedef unsigned char flags_type;
* When maxCells < UBOUNDED_MAX, if the bounds on the number of cells needed for evaluation of 'dag' on an idealized Bit Machine exceeds maxCells,
* then return SIMPLICITY_ERR_EXEC_MEMORY.
* When maxCost < UBOUNDED_MAX, if the bounds on the dag's CPU cost exceeds 'maxCost', then return SIMPLICITY_ERR_EXEC_BUDGET.
+ * If the bounds on the dag's CPU cost is less than or equal to 'minCost', then return SIMPLICITY_ERR_OVERWEIGHT.
* Otherwise returns SIMPLICITY_NO_ERR.
*
* Precondition: NULL != cellsBound
@@ -32,17 +33,22 @@ typedef unsigned char flags_type;
* and if maxCells < UBOUNDED_MAX then '*frameBound' bounds the number of stack frames needed during execution of 'dag'.
*/
simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBound, ubounded *frameBound, ubounded *costBound
- , ubounded maxCells, ubounded maxCost, const dag_node* dag, const type* type_dag, const size_t len);
+ , ubounded maxCells, ubounded minCost, ubounded maxCost, const dag_node* dag, const type* type_dag, const size_t len);
/* Run the Bit Machine on the well-typed Simplicity expression 'dag[len]' of type A |- B.
* If bitSize(A) > 0, initialize the active read frame's data with 'input[ROUND_UWORD(bitSize(A))]'.
*
* If malloc fails, returns 'SIMPLICITY_ERR_MALLOC'.
- * When a budget is given, if static analysis results determines the bound on cpu requirements exceed the allowed budget, returns 'SIMPLICITY_ERR_EXEC_BUDGET'
- * If static analysis results determines the bound on memory allocation requirements exceed the allowed limits, returns 'SIMPLICITY_ERR_EXEC_MEMORY'
+ * When a budget is given, if static analysis results determines the bound on cpu requirements exceed the allowed budget, returns 'SIMPLICITY_ERR_EXEC_BUDGET'.
+ * If static analysis results determines the bound on cpu requirements is less than or equal to the minCost, returns 'SIMPLICITY_ERR_OVERWEIGHT'.
+ * If static analysis results determines the bound on memory allocation requirements exceed the allowed limits, returns 'SIMPLICITY_ERR_EXEC_MEMORY'.
* If during execution some jet execution fails, returns 'SIMPLICITY_ERR_EXEC_JET'.
* If during execution some 'assertr' or 'assertl' combinator fails, returns 'SIMPLICITY_ERR_EXEC_ASESRT'.
*
+ * Note that minCost and budget parameters are in WU, while the cost analysis will be performed in milliWU.
+ * Thus the minCost and budget specify a half open interval (minCost, budget] of acceptable cost values in milliWU.
+ * Setting minCost to 0 effectively disables the minCost check as every Simplicity program has a non-zero cost analysis.
+ *
* If none of the above conditions fail and bitSize(B) > 0, then a copy the final active write frame's data is written to 'output[roundWord(bitSize(B))]'.
*
* If 'anti_dos_checks' includes the 'CHECK_EXEC' flag, and not every non-HIDDEN dag node is executed, returns 'SIMPLICITY_ERR_ANTIDOS'
@@ -54,19 +60,27 @@ simplicity_err simplicity_analyseBounds( ubounded *cellsBound, ubounded *UWORDBo
* bitSize(A) == 0 or UWORD input[ROUND_UWORD(bitSize(A))];
* bitSize(B) == 0 or UWORD output[ROUND_UWORD(bitSize(B))];
* if NULL != budget then *budget <= BUDGET_MAX
+ * if NULL != budget then minCost <= *budget
+ * minCost <= BUDGET_MAX
* if 'dag[len]' represents a Simplicity expression with primitives then 'NULL != env';
*/
simplicity_err simplicity_evalTCOExpression( flags_type anti_dos_checks, UWORD* output, const UWORD* input
- , const dag_node* dag, type* type_dag, size_t len, const ubounded* budget, const txEnv* env
- );
+ , const dag_node* dag, type* type_dag, size_t len, ubounded minCost, const ubounded* budget, const txEnv* env
+ );
/* Run the Bit Machine on the well-typed Simplicity program 'dag[len]'.
*
* If malloc fails, returns 'SIMPLICITY_ERR_MALLOC'.
- * When a budget is given, if static analysis results determines the bound on cpu requirements exceed the allowed budget, returns 'SIMPLICITY_ERR_EXEC_BUDGET'
- * If static analysis results determines the bound on memory allocation requirements exceed the allowed limits, returns 'SIMPLICITY_ERR_EXEC_MEMORY'
+ * When a budget is given, if static analysis results determines the bound on cpu requirements exceed the allowed budget, returns 'SIMPLICITY_ERR_EXEC_BUDGET'.
+ * If static analysis results determines the bound on cpu requirements is less than or equal to the minCost, returns 'SIMPLICITY_ERR_OVERWEIGHT'.
+ * If static analysis results determines the bound on memory allocation requirements exceed the allowed limits, returns 'SIMPLICITY_ERR_EXEC_MEMORY'.
* If during execution some jet execution fails, returns 'SIMPLICITY_ERR_EXEC_JET'.
* If during execution some 'assertr' or 'assertl' combinator fails, returns 'SIMPLICITY_ERR_EXEC_ASESRT'.
+ *
+ * Note that minCost and budget parameters are in WU, while the cost analysis will be performed in milliWU.
+ * Thus the minCost and budget specify a half open interval (minCost, budget] of acceptable cost values in milliWU.
+ * Setting minCost to 0 effectively disables the minCost check as every Simplicity program has a non-zero cost analysis.
+ *
* If not every non-HIDDEN dag node is executed, returns 'SIMPLICITY_ERR_ANTIDOS'
* If not every case node has both branches executed, returns 'SIMPLICITY_ERR_ANTIDOS'
*
@@ -74,9 +88,11 @@ simplicity_err simplicity_evalTCOExpression( flags_type anti_dos_checks, UWORD*
*
* Precondition: dag_node dag[len] and 'dag' is well-typed with 'type_dag' for an expression of type ONE |- ONE;
* if NULL != budget then *budget <= BUDGET_MAX
+ * if NULL != budget then minCost <= *budget
+ * minCost <= BUDGET_MAX
* if 'dag[len]' represents a Simplicity expression with primitives then 'NULL != env';
*/
-static inline simplicity_err evalTCOProgram(const dag_node* dag, type* type_dag, size_t len, const ubounded* budget, const txEnv* env) {
- return simplicity_evalTCOExpression(CHECK_ALL, NULL, NULL, dag, type_dag, len, budget, env);
+static inline simplicity_err evalTCOProgram(const dag_node* dag, type* type_dag, size_t len, ubounded minCost, const ubounded* budget, const txEnv* env) {
+ return simplicity_evalTCOExpression(CHECK_ALL, NULL, NULL, dag, type_dag, len, minCost, budget, env);
}
#endif
diff --git a/src/simplicity/include/simplicity/cmr.h b/src/simplicity/include/simplicity/elements/cmr.h
similarity index 74%
rename from src/simplicity/include/simplicity/cmr.h
rename to src/simplicity/include/simplicity/elements/cmr.h
index 4bde71a28e6..af3a0077940 100644
--- a/src/simplicity/include/simplicity/cmr.h
+++ b/src/simplicity/include/simplicity/elements/cmr.h
@@ -1,5 +1,5 @@
-#ifndef SIMPLICITY_CMR_H
-#define SIMPLICITY_CMR_H
+#ifndef SIMPLICITY_ELEMENTS_CMR_H
+#define SIMPLICITY_ELEMENTS_CMR_H
#include
#include
@@ -18,6 +18,6 @@
* unsigned char cmr[32]
* unsigned char program[program_len]
*/
-extern bool simplicity_computeCmr( simplicity_err* error, unsigned char* cmr
- , const unsigned char* program, size_t program_len);
+extern bool simplicity_elements_computeCmr( simplicity_err* error, unsigned char* cmr
+ , const unsigned char* program, size_t program_len);
#endif
diff --git a/src/simplicity/include/simplicity/elements/env.h b/src/simplicity/include/simplicity/elements/env.h
index e5c683f9f2c..ef55f31bc31 100644
--- a/src/simplicity/include/simplicity/elements/env.h
+++ b/src/simplicity/include/simplicity/elements/env.h
@@ -4,9 +4,9 @@
#include
#include
-/* This section builds the 'rawTransaction' structure which is the transaction data needed to build an Elements 'txEnv' environment
+/* This section builds the 'rawElementsTransaction' structure which is the transaction data needed to build an Elements 'txEnv' environment
* for evaluating Simplicity expressions within.
- * The 'rawTransaction' is copied into an opaque 'transaction' structure that can be reused within evaluating Simplicity on multiple
+ * The 'rawElementsTransaction' is copied into an opaque 'elementsTransaction' structure that can be reused within evaluating Simplicity on multiple
* inputs within the same transaction.
*/
@@ -14,10 +14,10 @@
*
* Invariant: if 0 < len then unsigned char buf[len]
*/
-typedef struct rawBuffer {
+typedef struct rawElementsBuffer {
const unsigned char* buf;
uint32_t len;
-} rawBuffer;
+} rawElementsBuffer;
/* A structure representing data for one output from an Elements transaction.
*
@@ -25,14 +25,14 @@ typedef struct rawBuffer {
* unsigned char value[value[0] == 1 ? 9 : 33] or value == NULL;
* unsigned char nonce[33] or nonce == NULL;
*/
-typedef struct rawOutput {
+typedef struct rawElementsOutput {
const unsigned char* asset;
const unsigned char* value;
const unsigned char* nonce;
- rawBuffer scriptPubKey;
- rawBuffer surjectionProof;
- rawBuffer rangeProof;
-} rawOutput;
+ rawElementsBuffer scriptPubKey;
+ rawElementsBuffer surjectionProof;
+ rawElementsBuffer rangeProof;
+} rawElementsOutput;
/* A structure representing data for one input from an Elements transaction, including its taproot annex,
* plus the TXO data of the output being redeemed.
@@ -46,8 +46,8 @@ typedef struct rawOutput {
* unsigned char txo.asset[33] or txo.asset == NULL;
* unsigned char txo.value[txo.value[0] == 1 ? 9 : 33] or txo.value == NULL;
*/
-typedef struct rawInput {
- const rawBuffer* annex;
+typedef struct rawElementsInput {
+ const rawElementsBuffer* annex;
const unsigned char* prevTxid;
const unsigned char* pegin;
struct {
@@ -55,48 +55,48 @@ typedef struct rawInput {
const unsigned char* assetEntropy;
const unsigned char* amount;
const unsigned char* inflationKeys;
- rawBuffer amountRangePrf;
- rawBuffer inflationKeysRangePrf;
+ rawElementsBuffer amountRangePrf;
+ rawElementsBuffer inflationKeysRangePrf;
} issuance;
struct {
const unsigned char* asset;
const unsigned char* value;
- rawBuffer scriptPubKey;
+ rawElementsBuffer scriptPubKey;
} txo;
- rawBuffer scriptSig;
+ rawElementsBuffer scriptSig;
uint32_t prevIx;
uint32_t sequence;
-} rawInput;
+} rawElementsInput;
/* A structure representing data for an Elements transaction, including the TXO data of each output being redeemed.
*
* Invariant: unsigned char txid[32];
- * rawInput input[numInputs];
- * rawOutput output[numOutputs];
+ * rawElementsInput input[numInputs];
+ * rawElementsOutput output[numOutputs];
*/
-typedef struct rawTransaction {
+typedef struct rawElementsTransaction {
const unsigned char* txid; /* While in theory we could recompute the txid ourselves, it is easier and safer for it to be provided. */
- const rawInput* input;
- const rawOutput* output;
+ const rawElementsInput* input;
+ const rawElementsOutput* output;
uint32_t numInputs;
uint32_t numOutputs;
uint32_t version;
uint32_t lockTime;
-} rawTransaction;
+} rawElementsTransaction;
-/* A forward declaration for the structure containing a copy (and digest) of the rawTransaction data */
-typedef struct transaction transaction;
+/* A forward declaration for the structure containing a copy (and digest) of the rawElementsTransaction data */
+typedef struct elementsTransaction elementsTransaction;
-/* Allocate and initialize a 'transaction' from a 'rawTransaction', copying or hashing the data as needed.
+/* Allocate and initialize a 'elementsTransaction' from a 'rawElementsTransaction', copying or hashing the data as needed.
* Returns NULL if malloc fails (or if malloc cannot be called because we require an allocation larger than SIZE_MAX).
*
* Precondition: NULL != rawTx
*/
-extern transaction* simplicity_elements_mallocTransaction(const rawTransaction* rawTx);
+extern elementsTransaction* simplicity_elements_mallocTransaction(const rawElementsTransaction* rawTx);
-/* Free a pointer to 'transaction'.
+/* Free a pointer to 'elementsTransaction'.
*/
-extern void simplicity_elements_freeTransaction(transaction* tx);
+extern void simplicity_elements_freeTransaction(elementsTransaction* tx);
/* A structure representing taproot spending data for an Elements transaction.
*
@@ -104,23 +104,23 @@ extern void simplicity_elements_freeTransaction(transaction* tx);
* unsigned char controlBlock[33+pathLen*32];
* unsigned char scriptCMR[32];
*/
-typedef struct rawTapEnv {
+typedef struct rawElementsTapEnv {
const unsigned char* controlBlock;
const unsigned char* scriptCMR;
unsigned char pathLen;
-} rawTapEnv;
+} rawElementsTapEnv;
-/* A forward declaration for the structure containing a copy (and digest) of the rawTapEnv data */
-typedef struct tapEnv tapEnv;
+/* A forward declaration for the structure containing a copy (and digest) of the rawElementsTapEnv data */
+typedef struct elementsTapEnv elementsTapEnv;
-/* Allocate and initialize a 'tapEnv' from a 'rawTapEnv', copying or hashing the data as needed.
+/* Allocate and initialize a 'elementsTapEnv' from a 'rawElementsTapEnv', copying or hashing the data as needed.
* Returns NULL if malloc fails (or if malloc cannot be called because we require an allocation larger than SIZE_MAX).
*
* Precondition: *rawEnv is well-formed (i.e. rawEnv->pathLen <= 128.)
*/
-extern tapEnv* simplicity_elements_mallocTapEnv(const rawTapEnv* rawEnv);
+extern elementsTapEnv* simplicity_elements_mallocTapEnv(const rawElementsTapEnv* rawEnv);
-/* Free a pointer to 'tapEnv'.
+/* Free a pointer to 'elementsTapEnv'.
*/
-extern void simplicity_elements_freeTapEnv(tapEnv* env);
+extern void simplicity_elements_freeTapEnv(elementsTapEnv* env);
#endif
diff --git a/src/simplicity/include/simplicity/elements/exec.h b/src/simplicity/include/simplicity/elements/exec.h
index 758df913a16..18f70709e1f 100644
--- a/src/simplicity/include/simplicity/elements/exec.h
+++ b/src/simplicity/include/simplicity/elements/exec.h
@@ -14,6 +14,12 @@
* Otherwise, 'true' is returned indicating that the result was successfully computed and returned in the '*error' value.
*
* If deserialization, analysis, or execution fails, then '*error' is set to some simplicity_err.
+ * In particular, if the cost analysis exceeds the budget, or exceeds BUDGET_MAX, then '*error' is set to 'SIMPLICITY_ERR_EXEC_BUDGET'.
+ * On the other hand, if the cost analysis is less than or equal to minCost, then '*error' is set to 'SIMPLICITY_ERR_OVERWEIGHT'.
+ *
+ * Note that minCost and budget parameters are in WU, while the cost analysis will be performed in milliWU.
+ * Thus the minCost and budget specify a half open interval (minCost, budget] of acceptable cost values in milliWU.
+ * Setting minCost to 0 effectively disables the minCost check as every Simplicity program has a non-zero cost analysis.
*
* If 'amr != NULL' and the annotated Merkle root of the decoded expression doesn't match 'amr' then '*error' is set to 'SIMPLICITY_ERR_AMR'.
*
@@ -27,15 +33,15 @@
* NULL != tx;
* NULL != taproot;
* unsigned char genesisBlockHash[32]
- * 0 <= budget;
+ * 0 <= minCost <= budget;
* NULL != amr implies unsigned char amr[32]
* unsigned char program[program_len]
* unsigned char witness[witness_len]
*/
extern bool simplicity_elements_execSimplicity( simplicity_err* error, unsigned char* ihr
- , const transaction* tx, uint_fast32_t ix, const tapEnv* taproot
+ , const elementsTransaction* tx, uint_fast32_t ix, const elementsTapEnv* taproot
, const unsigned char* genesisBlockHash
- , int64_t budget
+ , int64_t minCost, int64_t budget
, const unsigned char* amr
, const unsigned char* program, size_t program_len
, const unsigned char* witness, size_t witness_len);
diff --git a/src/simplicity/include/simplicity/errorCodes.h b/src/simplicity/include/simplicity/errorCodes.h
index 00ffee51c07..cea6e7dbc77 100644
--- a/src/simplicity/include/simplicity/errorCodes.h
+++ b/src/simplicity/include/simplicity/errorCodes.h
@@ -36,6 +36,7 @@ typedef enum {
SIMPLICITY_ERR_ANTIDOS = -42,
SIMPLICITY_ERR_HIDDEN_ROOT = -44,
SIMPLICITY_ERR_AMR = -46,
+ SIMPLICITY_ERR_OVERWEIGHT = -48,
} simplicity_err;
/* Check if failure is permanent (or success which is always permanent). */
@@ -102,6 +103,8 @@ static inline const char * SIMPLICITY_ERR_MSG(simplicity_err err) {
return "Program's root is HIDDEN";
case SIMPLICITY_ERR_AMR:
return "Program's AMR does not match";
+ case SIMPLICITY_ERR_OVERWEIGHT:
+ return "Program's budget is too large";
default:
return "Unknown error code";
}
diff --git a/src/simplicity/test.c b/src/simplicity/test.c
index 445b5726786..4ec33387d56 100644
--- a/src/simplicity/test.c
+++ b/src/simplicity/test.c
@@ -5,7 +5,7 @@
#include
#include
#include
-#include
+#include
#include "ctx8Pruned.h"
#include "ctx8Unpruned.h"
#include "dag.h"
@@ -20,7 +20,8 @@
#include "typeSkipTest.h"
#include "simplicity_alloc.h"
#include "typeInference.h"
-#include "primitive/elements/checkSigHashAllTx1.h"
+#include "elements/checkSigHashAllTx1.h"
+#include "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");
@@ -152,7 +153,7 @@ static void test_hashBlock(void) {
}
{
ubounded cellsBound, UWORDBound, frameBound, costBound;
- if (IS_OK(simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len))
+ if (IS_OK(simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len))
&& hashBlock_cost == costBound) {
successes++;
} else {
@@ -160,7 +161,7 @@ static void test_hashBlock(void) {
printf("Expected %d for cost, but got %d instead.\n", hashBlock_cost, costBound);
}
}
- simplicity_err err = simplicity_evalTCOExpression(CHECK_NONE, output, input, dag, type_dag, (uint_fast32_t)len, NULL, NULL);
+ simplicity_err err = simplicity_evalTCOExpression(CHECK_NONE, output, input, dag, type_dag, (uint_fast32_t)len, 0, NULL, NULL);
if (IS_OK(err)) {
/* The expected result is the value 'SHA256("abc")'. */
const uint32_t expectedHash[8] = { 0xba7816bful, 0x8f01cfeaul, 0x414140deul, 0x5dae2223ul
@@ -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");
@@ -264,7 +265,8 @@ static void test_program(char* name, const unsigned char* program, size_t progra
}
if (expectedCost) {
ubounded cellsBound, UWORDBound, frameBound, costBound;
- if (IS_OK(simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len))
+ if (IS_OK(simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len))
+ && 0 < costBound
&& *expectedCost == costBound) {
successes++;
} else {
@@ -272,7 +274,8 @@ static void test_program(char* name, const unsigned char* program, size_t progra
printf("Expected %u for cost, but got %u instead.\n", *expectedCost, costBound);
}
/* Analysis should pass when computed bounds are used. */
- if (IS_OK(simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, cellsBound, costBound, dag, type_dag, (uint_fast32_t)len))) {
+ if (IS_OK(simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, cellsBound, costBound-1, costBound, dag, type_dag, (uint_fast32_t)len))
+ && *expectedCost == costBound) {
successes++;
} else {
failures++;
@@ -280,7 +283,7 @@ static void test_program(char* name, const unsigned char* program, size_t progra
}
/* if cellsBound is non-zero, analysis should fail when smaller cellsBound is used. */
if (0 < cellsBound) {
- if (SIMPLICITY_ERR_EXEC_MEMORY == simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, cellsBound-1, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len)) {
+ if (SIMPLICITY_ERR_EXEC_MEMORY == simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, cellsBound-1, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len)) {
successes++;
} else {
failures++;
@@ -289,15 +292,24 @@ static void test_program(char* name, const unsigned char* program, size_t progra
}
/* Analysis should fail when smaller costBound is used. */
if (0 < *expectedCost &&
- SIMPLICITY_ERR_EXEC_BUDGET == simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, *expectedCost-1, dag, type_dag, (uint_fast32_t)len)
+ SIMPLICITY_ERR_EXEC_BUDGET == simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, *expectedCost-1, dag, type_dag, (uint_fast32_t)len)
) {
successes++;
} else {
failures++;
printf("Analysis with too small cost bounds failed.\n");
}
+ /* Analysis should fail when overweight. */
+ if (0 < *expectedCost &&
+ SIMPLICITY_ERR_OVERWEIGHT == simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, *expectedCost, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len)
+ ) {
+ successes++;
+ } else {
+ failures++;
+ printf("Analysis with too large minCost failed.\n");
+ }
}
- simplicity_err actualResult = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, NULL, NULL);
+ simplicity_err actualResult = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, 0, NULL, NULL);
if (expectedResult == actualResult) {
successes++;
} else {
@@ -319,7 +331,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 +339,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 {
@@ -345,18 +357,18 @@ static void test_elements(void) {
sha256_fromMidstate(amr, elementsCheckSigHashAllTx1_amr);
unsigned char genesisHash[32] = "\x0f\x91\x88\xf1\x3c\xb7\xb2\xc7\x1f\x2a\x33\x5e\x3a\x4f\xc3\x28\xbf\x5b\xeb\x43\x60\x12\xaf\xca\x59\x0b\x1a\x11\x46\x6e\x22\x06";
- rawTapEnv rawTaproot = (rawTapEnv)
+ rawElementsTapEnv rawTaproot = (rawElementsTapEnv)
{ .controlBlock = (unsigned char [33]){"\xbe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3b\x78\xce\x56\x3f\x89\xa0\xed\x94\x14\xf5\xaa\x28\xad\x0d\x96\xd6\x79\x5f\x9c\x63"}
, .pathLen = 0
, .scriptCMR = cmr
};
- tapEnv* taproot = simplicity_elements_mallocTapEnv(&rawTaproot);
+ elementsTapEnv* taproot = simplicity_elements_mallocTapEnv(&rawTaproot);
printf("Test elements\n");
{
- rawTransaction testTx1 = (rawTransaction)
+ rawElementsTransaction testTx1 = (rawElementsTransaction)
{ .txid = (unsigned char[32]){"\xdb\x9a\x3d\xe0\xb6\xb8\xcc\x74\x1e\x4d\x6c\x8f\x19\xce\x75\xec\x0d\xfd\x01\x02\xdb\x9c\xb5\xcd\x27\xa4\x1a\x66\x91\x66\x3a\x07"}
- , .input = (rawInput[])
+ , .input = (rawElementsInput[])
{ { .annex = NULL
, .prevTxid = (unsigned char[32]){"\xeb\x04\xb6\x8e\x9a\x26\xd1\x16\x04\x6c\x76\xe8\xff\x47\x33\x2f\xb7\x1d\xda\x90\xff\x4b\xef\x53\x70\xf2\x52\x26\xd3\xbc\x09\xfc"}
, .prevIx = 0
@@ -367,7 +379,7 @@ static void test_elements(void) {
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xe4\x00"}
, .scriptPubKey = {0}
} } }
- , .output = (rawOutput[])
+ , .output = (rawElementsOutput[])
{ { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xd7\x1c"}
, .nonce = NULL
@@ -385,13 +397,13 @@ static void test_elements(void) {
, .version = 0x00000002
, .lockTime = 0x00000000
};
- transaction* tx1 = simplicity_elements_mallocTransaction(&testTx1);
+ elementsTransaction* tx1 = simplicity_elements_mallocTransaction(&testTx1);
if (tx1) {
successes++;
simplicity_err execResult;
{
unsigned char cmrResult[32];
- if (simplicity_computeCmr(&execResult, cmrResult, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1) && IS_OK(execResult)) {
+ if (simplicity_elements_computeCmr(&execResult, cmrResult, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1) && IS_OK(execResult)) {
if (0 == memcmp(cmrResult, cmr, sizeof(unsigned char[8]))) {
successes++;
} else {
@@ -400,12 +412,12 @@ static void test_elements(void) {
}
} else {
failures++;
- printf("simplicity_computeCmr of elementsCheckSigHashAllTx1 unexpectedly produced %d.\n", execResult);
+ printf("simplicity_elements_computeCmr of elementsCheckSigHashAllTx1 unexpectedly produced %d.\n", execResult);
}
}
{
unsigned char ihrResult[32];
- if (simplicity_elements_execSimplicity(&execResult, ihrResult, tx1, 0, taproot, genesisHash, (elementsCheckSigHashAllTx1_cost + 999)/1000, amr, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && IS_OK(execResult)) {
+ if (simplicity_elements_execSimplicity(&execResult, ihrResult, tx1, 0, taproot, genesisHash, 0, (elementsCheckSigHashAllTx1_cost + 999)/1000, amr, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && IS_OK(execResult)) {
sha256_midstate ihr;
sha256_toMidstate(ihr.s, ihrResult);
if (0 == memcmp(ihr.s, elementsCheckSigHashAllTx1_ihr, sizeof(uint32_t[8]))) {
@@ -421,7 +433,7 @@ static void test_elements(void) {
if (elementsCheckSigHashAllTx1_cost){
/* test the same transaction without adequate budget. */
simplicity_assert(elementsCheckSigHashAllTx1_cost);
- if (simplicity_elements_execSimplicity(&execResult, ihrResult, tx1, 0, taproot, genesisHash, (elementsCheckSigHashAllTx1_cost - 1)/1000, amr, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_BUDGET == execResult) {
+ if (simplicity_elements_execSimplicity(&execResult, ihrResult, tx1, 0, taproot, genesisHash, 0, (elementsCheckSigHashAllTx1_cost - 1)/1000, amr, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_BUDGET == execResult) {
successes++;
} else {
failures++;
@@ -434,7 +446,7 @@ static void test_elements(void) {
unsigned char brokenSig[sizeof_elementsCheckSigHashAllTx1_witness];
memcpy(brokenSig, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness);
brokenSig[sizeof_elementsCheckSigHashAllTx1_witness - 1] ^= 0x80;
- if (simplicity_elements_execSimplicity(&execResult, NULL, tx1, 0, taproot, genesisHash, BUDGET_MAX, NULL, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, brokenSig, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_JET == execResult) {
+ if (simplicity_elements_execSimplicity(&execResult, NULL, tx1, 0, taproot, genesisHash, 0, BUDGET_MAX, NULL, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, brokenSig, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_JET == execResult) {
successes++;
} else {
failures++;
@@ -449,9 +461,9 @@ static void test_elements(void) {
}
/* test a modified transaction with the same signature. */
{
- rawTransaction testTx2 = (rawTransaction)
+ rawElementsTransaction testTx2 = (rawElementsTransaction)
{ .txid = (unsigned char[32]){"\xdb\x9a\x3d\xe0\xb6\xb8\xcc\x74\x1e\x4d\x6c\x8f\x19\xce\x75\xec\x0d\xfd\x01\x02\xdb\x9c\xb5\xcd\x27\xa4\x1a\x66\x91\x66\x3a\x07"}
- , .input = (rawInput[])
+ , .input = (rawElementsInput[])
{ { .prevTxid = (unsigned char[32]){"\xeb\x04\xb6\x8e\x9a\x26\xd1\x16\x04\x6c\x76\xe8\xff\x47\x33\x2f\xb7\x1d\xda\x90\xff\x4b\xef\x53\x70\xf2\x52\x26\xd3\xbc\x09\xfc"}
, .prevIx = 0
, .sequence = 0xffffffff /* Here is the modification. */
@@ -460,7 +472,7 @@ static void test_elements(void) {
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xe4\x00"}
, .scriptPubKey = {0}
} } }
- , .output = (rawOutput[])
+ , .output = (rawElementsOutput[])
{ { .asset = (unsigned char[33]){"\x01\x23\x0f\x4f\x5d\x4b\x7c\x6f\xa8\x45\x80\x6e\xe4\xf6\x77\x13\x45\x9e\x1b\x69\xe8\xe6\x0f\xce\xe2\xe4\x94\x0c\x7a\x0d\x5d\xe1\xb2"}
, .value = (unsigned char[9]){"\x01\x00\x00\x00\x02\x54\x0b\xd7\x1c"}
, .nonce = NULL
@@ -478,12 +490,12 @@ static void test_elements(void) {
, .version = 0x00000002
, .lockTime = 0x00000000
};
- transaction* tx2 = simplicity_elements_mallocTransaction(&testTx2);
+ elementsTransaction* tx2 = simplicity_elements_mallocTransaction(&testTx2);
if (tx2) {
successes++;
simplicity_err execResult;
{
- if (simplicity_elements_execSimplicity(&execResult, NULL, tx2, 0, taproot, genesisHash, BUDGET_MAX, NULL, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_JET == execResult) {
+ if (simplicity_elements_execSimplicity(&execResult, NULL, tx2, 0, taproot, genesisHash, 0, BUDGET_MAX, NULL, elementsCheckSigHashAllTx1, sizeof_elementsCheckSigHashAllTx1, elementsCheckSigHashAllTx1_witness, sizeof_elementsCheckSigHashAllTx1_witness) && SIMPLICITY_ERR_EXEC_JET == execResult) {
successes++;
} else {
failures++;
@@ -625,6 +637,83 @@ static void iden8mebi_test(void) {
}
}
}
+static void exactBudget_test(void) {
+ /* Core Simplicity program with a cost that is exactly 410000 milliWU */
+ const unsigned char program[] = {
+ 0xe0, 0x09, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x81, 0x02,
+ 0x05, 0xb4, 0x6d, 0xa0, 0x80
+ };
+ const ubounded expectedCost = 410; /* in WU */
+
+ printf("Test exactBudget\n");
+
+ dag_node* dag;
+ type* type_dag;
+ combinator_counters census;
+ int_fast32_t len;
+ simplicity_err error, expected;
+ sha256_midstate ihr;
+ {
+ bitstream stream = initializeBitstream(program, sizeof(program));
+ len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, &census, &stream);
+ simplicity_assert(dag);
+ simplicity_assert(0 < len);
+ error = simplicity_closeBitstream(&stream);
+ simplicity_assert(IS_OK(error));
+ }
+ error = simplicity_mallocTypeInference(&type_dag, simplicity_elements_mallocBoundVars, dag, (uint_fast32_t)len, &census);
+ simplicity_assert(IS_OK(error));
+ simplicity_assert(type_dag);
+ simplicity_assert(!dag[len-1].sourceType);
+ simplicity_assert(!dag[len-1].targetType);
+ {
+ bitstream stream = initializeBitstream(NULL, 0);
+ error = simplicity_fillWitnessData(dag, type_dag, (uint_fast32_t)len, &stream);
+ simplicity_assert(IS_OK(error));
+ }
+ error = simplicity_verifyNoDuplicateIdentityHashes(&ihr, dag, type_dag, (uint_fast32_t)len);
+ simplicity_assert(IS_OK(error));
+ {
+ ubounded cellsBound, UWORDBound, frameBound, costBound;
+ error = simplicity_analyseBounds(&cellsBound, &UWORDBound, &frameBound, &costBound, UBOUNDED_MAX, 0, UBOUNDED_MAX, dag, type_dag, (uint_fast32_t)len);
+ simplicity_assert(IS_OK(error));
+ simplicity_assert(1000*expectedCost == costBound);
+ }
+ error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost, &expectedCost, NULL);
+ expected = SIMPLICITY_ERR_OVERWEIGHT;
+ if (expected == error) {
+ successes++;
+ } else {
+ failures++;
+ printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
+ }
+ error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost-1, &(ubounded){expectedCost-1}, NULL);
+ expected = SIMPLICITY_ERR_EXEC_BUDGET;
+ if (expected == error) {
+ successes++;
+ } else {
+ failures++;
+ printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
+ }
+ error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost, &(ubounded){expectedCost+1}, NULL);
+ expected = SIMPLICITY_ERR_OVERWEIGHT;
+ if (expected == error) {
+ successes++;
+ } else {
+ failures++;
+ printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
+ }
+ error = evalTCOProgram(dag, type_dag, (uint_fast32_t)len, expectedCost-1, &expectedCost, NULL);
+ expected = SIMPLICITY_NO_ERROR;
+ if (expected == error) {
+ successes++;
+ } else {
+ failures++;
+ printf("Expected %d from evaluation, but got %d instead.\n", expected, error);
+ }
+ simplicity_free(type_dag);
+ simplicity_free(dag);
+}
int main(int argc, char **argv) {
while (true) {
@@ -676,6 +765,7 @@ int main(int argc, char **argv) {
test_program("schnorr6", schnorr6, sizeof_schnorr6, schnorr6_witness, sizeof_schnorr6_witness, SIMPLICITY_ERR_EXEC_JET, schnorr6_cmr, schnorr6_ihr, schnorr6_amr, &schnorr0_cost);
test_program("typeSkipTest", typeSkipTest, sizeof_typeSkipTest, typeSkipTest_witness, sizeof_typeSkipTest_witness, SIMPLICITY_NO_ERROR, NULL, NULL, NULL, NULL);
test_elements();
+ exactBudget_test();
regression_tests();
iden8mebi_test();
diff --git a/src/simplicity/typeInference.c b/src/simplicity/typeInference.c
index 89f09232626..e8359d5e934 100644
--- a/src/simplicity/typeInference.c
+++ b/src/simplicity/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/src/simplicity/typeInference.h b/src/simplicity/typeInference.h
index dd8ccf35fde..3988d08b461 100644
--- a/src/simplicity/typeInference.h
+++ b/src/simplicity/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/src/test/fuzz/simplicity.cpp b/src/test/fuzz/simplicity.cpp
index 25722a5f3ce..363ee93ac52 100644
--- a/src/test/fuzz/simplicity.cpp
+++ b/src/test/fuzz/simplicity.cpp
@@ -5,7 +5,7 @@
#include
#include
extern "C" {
-#include
+#include
#include
#include
}
@@ -31,9 +31,9 @@ static std::vector TAPROOT_ANNEX(99, 0x50);
// Defined in simplicity_compute_amr.c
extern "C" {
-bool simplicity_computeAmr( simplicity_err* error, unsigned char* amr
- , const unsigned char* program, size_t program_len
- , const unsigned char* witness, size_t witness_len);
+bool simplicity_elements_computeAmr( simplicity_err* error, unsigned char* amr
+ , const unsigned char* program, size_t program_len
+ , const unsigned char* witness, size_t witness_len);
}
void initialize_simplicity()
@@ -149,8 +149,8 @@ FUZZ_TARGET_INIT(simplicity, initialize_simplicity)
simplicity_err error;
unsigned char cmr[32];
unsigned char amr[32];
- assert(simplicity_computeAmr(&error, amr, prog_data, prog_data_len, wit_data, wit_data_len));
- assert(simplicity_computeCmr(&error, cmr, prog_data, prog_data_len));
+ assert(simplicity_elements_computeAmr(&error, amr, prog_data, prog_data_len, wit_data, wit_data_len));
+ assert(simplicity_elements_computeCmr(&error, cmr, prog_data, prog_data_len));
// The remainder is just copy/pasted from the original fuzztest
@@ -196,7 +196,7 @@ FUZZ_TARGET_INIT(simplicity, initialize_simplicity)
}
// 5. Set up Simplicity environment and tx environment
- rawTapEnv simplicityRawTap;
+ rawElementsTapEnv simplicityRawTap;
simplicityRawTap.controlBlock = TAPROOT_CONTROL.data();
simplicityRawTap.pathLen = (TAPROOT_CONTROL.size() - TAPROOT_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE;
simplicityRawTap.scriptCMR = cmr;
@@ -210,15 +210,15 @@ FUZZ_TARGET_INIT(simplicity, initialize_simplicity)
unsigned char imr_out[32];
unsigned char *imr = mtx.vin[0].prevout.hash.data()[2] & 2 ? imr_out : NULL;
- const transaction* tx = txdata.m_simplicity_tx_data.get();
- tapEnv* taproot = simplicity_elements_mallocTapEnv(&simplicityRawTap);
- simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
+ const elementsTransaction* tx = txdata.m_simplicity_tx_data.get();
+ elementsTapEnv* taproot = simplicity_elements_mallocTapEnv(&simplicityRawTap);
+ simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), 0, budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
// 5. Secondary test -- try flipping a bunch of bits and check that this doesn't mess things up
for (size_t j = 0; j < 8 * prog_bytes.size(); j++) {
if (j > 32 && j % 23 != 0) continue; // skip most bits so this test doesn't overwhelm the fuzz time
prog_bytes.data()[j / 8] ^= (1 << (j % 8));
- simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
+ simplicity_elements_execSimplicity(&error, imr, tx, nIn, taproot, GENESIS_HASH.data(), 0, budget, amr, prog_bytes.data(), prog_bytes.size(), wit_bytes.data(), wit_bytes.size());
}
// 6. Cleanup
diff --git a/src/test/fuzz/simplicity_compute_amr.c b/src/test/fuzz/simplicity_compute_amr.c
index dfa0450e174..3e8d9f93818 100644
--- a/src/test/fuzz/simplicity_compute_amr.c
+++ b/src/test/fuzz/simplicity_compute_amr.c
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include
+#include
#include
#include // simplicity_decodeMallocDag
#include // DAG_LEN_MAX
@@ -10,11 +10,12 @@
#include // simplicity_mallocTypeInference
#include
#include
+#include
// Copy of computeCmr used for AMR
-bool simplicity_computeAmr( simplicity_err* error, unsigned char* amr
- , const unsigned char* program, size_t program_len
- , const unsigned char* witness, size_t witness_len) {
+bool simplicity_elements_computeAmr( simplicity_err* error, unsigned char* amr
+ , const unsigned char* program, size_t program_len
+ , const unsigned char* witness, size_t witness_len) {
simplicity_assert(NULL != error);
simplicity_assert(NULL != amr);
simplicity_assert(NULL != program || 0 == program_len);
@@ -23,7 +24,7 @@ bool simplicity_computeAmr( simplicity_err* error, unsigned char* amr
bitstream stream = initializeBitstream(program, program_len);
dag_node* dag = NULL;
combinator_counters census;
- int_fast32_t dag_len = simplicity_decodeMallocDag(&dag, &census, &stream);
+ int_fast32_t dag_len = simplicity_decodeMallocDag(&dag, simplicity_elements_decodeJet, &census, &stream);
if (dag_len <= 0) {
simplicity_assert(dag_len < 0);
*error = (simplicity_err)dag_len;
@@ -34,7 +35,7 @@ bool simplicity_computeAmr( simplicity_err* error, unsigned char* amr
type* type_dag = NULL;
if (IS_OK(*error)) {
- *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);
}
bitstream witness_stream;
if (IS_OK(*error)) {
diff --git a/src/test/fuzz/simplicity_tx.cpp b/src/test/fuzz/simplicity_tx.cpp
index a5bf99552ba..f5b8b4aa849 100644
--- a/src/test/fuzz/simplicity_tx.cpp
+++ b/src/test/fuzz/simplicity_tx.cpp
@@ -7,7 +7,7 @@
#include