Skip to content

Commit f8a6764

Browse files
Implementation of exec.c for bitcoin
1 parent d190505 commit f8a6764

3 files changed

Lines changed: 178 additions & 1 deletion

File tree

C/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CORE_OBJS := bitstream.o dag.o deserialize.o eval.o frame.o jets.o jets-secp256k1.o rsort.o sha256.o type.o typeInference.o
2-
BITCOIN_OBJS := bitcoin/env.o bitcoin/ops.o bitcoin/bitcoinJets.o bitcoin/primitive.o bitcoin/txEnv.o
2+
BITCOIN_OBJS := bitcoin/env.o bitcoin/exec.o bitcoin/ops.o bitcoin/bitcoinJets.o bitcoin/primitive.o bitcoin/txEnv.o
33
ELEMENTS_OBJS := elements/env.o elements/exec.o elements/ops.o elements/elementsJets.o elements/primitive.o elements/cmr.o elements/txEnv.o
44
TEST_OBJS := test.o ctx8Pruned.o ctx8Unpruned.o hashBlock.o regression4.o schnorr0.o schnorr6.o typeSkipTest.o elements/checkSigHashAllTx1.o
55

C/bitcoin/exec.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include <simplicity/bitcoin/exec.h>
2+
3+
#include <stdalign.h>
4+
#include <string.h>
5+
#include "primitive.h"
6+
#include "txEnv.h"
7+
#include "../deserialize.h"
8+
#include "../eval.h"
9+
#include "../limitations.h"
10+
#include "../simplicity_alloc.h"
11+
#include "../simplicity_assert.h"
12+
#include "../typeInference.h"
13+
14+
/* Deserialize a Simplicity 'program' with its 'witness' data and execute it in the environment of the 'ix'th input of 'tx' with `taproot`.
15+
*
16+
* If at any time malloc fails then '*error' is set to 'SIMPLICITY_ERR_MALLOC' and 'false' is returned,
17+
* meaning we were unable to determine the result of the simplicity program.
18+
* Otherwise, 'true' is returned indicating that the result was successfully computed and returned in the '*error' value.
19+
*
20+
* If deserialization, analysis, or execution fails, then '*error' is set to some simplicity_err.
21+
* In particular, if the cost analysis exceeds the budget, or exceeds BUDGET_MAX, then '*error' is set to 'SIMPLICITY_ERR_EXEC_BUDGET'.
22+
* On the other hand, if the cost analysis is less than or equal to minCost, then '*error' is set to 'SIMPLICITY_ERR_OVERWEIGHT'.
23+
*
24+
* Note that minCost and budget parameters are in WU, while the cost analysis will be performed in milliWU.
25+
* Thus the minCost and budget specify a half open interval (minCost, budget] of acceptable cost values in milliWU.
26+
* Setting minCost to 0 effectively disables the minCost check as every Simplicity program has a non-zero cost analysis.
27+
*
28+
* If 'amr != NULL' and the annotated Merkle root of the decoded expression doesn't match 'amr' then '*error' is set to 'SIMPLICITY_ERR_AMR'.
29+
*
30+
* Otherwise '*error' is set to 'SIMPLICITY_NO_ERROR'.
31+
*
32+
* If 'ihr != NULL' and '*error' is set to 'SIMPLICITY_NO_ERROR', then the identity hash of the root of the decoded expression is written to 'ihr'.
33+
* Otherwise if 'ihr != NULL' and '*error' is not set to 'SIMPLCITY_NO_ERROR', then 'ihr' may or may not be written to.
34+
*
35+
* Precondition: NULL != error;
36+
* NULL != ihr implies unsigned char ihr[32]
37+
* NULL != tx;
38+
* NULL != taproot;
39+
* 0 <= minCost <= budget;
40+
* NULL != amr implies unsigned char amr[32]
41+
* unsigned char program[program_len]
42+
* unsigned char witness[witness_len]
43+
*/
44+
extern bool simplicity_bitcoin_execSimplicity( simplicity_err* error, unsigned char* ihr
45+
, const bitcoinTransaction* tx, uint_fast32_t ix, const bitcoinTapEnv* taproot
46+
, int64_t minCost, int64_t budget
47+
, const unsigned char* amr
48+
, const unsigned char* program, size_t program_len
49+
, const unsigned char* witness, size_t witness_len) {
50+
simplicity_assert(NULL != error);
51+
simplicity_assert(NULL != tx);
52+
simplicity_assert(NULL != taproot);
53+
simplicity_assert(0 <= minCost);
54+
simplicity_assert(minCost <= budget);
55+
simplicity_assert(NULL != program || 0 == program_len);
56+
simplicity_assert(NULL != witness || 0 == witness_len);
57+
58+
combinator_counters census;
59+
dag_node* dag = NULL;
60+
int_fast32_t dag_len;
61+
sha256_midstate amr_hash;
62+
63+
if (amr) sha256_toMidstate(amr_hash.s, amr);
64+
65+
{
66+
bitstream stream = initializeBitstream(program, program_len);
67+
dag_len = simplicity_decodeMallocDag(&dag, simplicity_bitcoin_decodeJet, &census, &stream);
68+
if (dag_len <= 0) {
69+
simplicity_assert(dag_len < 0);
70+
*error = (simplicity_err)dag_len;
71+
return IS_PERMANENT(*error);
72+
}
73+
simplicity_assert(NULL != dag);
74+
simplicity_assert((uint_fast32_t)dag_len <= DAG_LEN_MAX);
75+
*error = simplicity_closeBitstream(&stream);
76+
}
77+
78+
if (IS_OK(*error)) {
79+
if (0 != memcmp(taproot->scriptCMR.s, dag[dag_len-1].cmr.s, sizeof(uint32_t[8]))) {
80+
*error = SIMPLICITY_ERR_CMR;
81+
}
82+
}
83+
84+
if (IS_OK(*error)) {
85+
type* type_dag = NULL;
86+
*error = simplicity_mallocTypeInference(&type_dag, simplicity_bitcoin_mallocBoundVars, dag, (uint_fast32_t)dag_len, &census);
87+
if (IS_OK(*error)) {
88+
simplicity_assert(NULL != type_dag);
89+
if (0 != dag[dag_len-1].sourceType || 0 != dag[dag_len-1].targetType) {
90+
*error = SIMPLICITY_ERR_TYPE_INFERENCE_NOT_PROGRAM;
91+
}
92+
}
93+
if (IS_OK(*error)) {
94+
bitstream witness_stream = initializeBitstream(witness, witness_len);
95+
*error = simplicity_fillWitnessData(dag, type_dag, (uint_fast32_t)dag_len, &witness_stream);
96+
if (IS_OK(*error)) {
97+
*error = simplicity_closeBitstream(&witness_stream);
98+
if (SIMPLICITY_ERR_BITSTREAM_TRAILING_BYTES == *error) *error = SIMPLICITY_ERR_WITNESS_TRAILING_BYTES;
99+
if (SIMPLICITY_ERR_BITSTREAM_ILLEGAL_PADDING == *error) *error = SIMPLICITY_ERR_WITNESS_ILLEGAL_PADDING;
100+
}
101+
}
102+
if (IS_OK(*error)) {
103+
sha256_midstate ihr_buf;
104+
*error = simplicity_verifyNoDuplicateIdentityHashes(&ihr_buf, dag, type_dag, (uint_fast32_t)dag_len);
105+
if (IS_OK(*error) && ihr) sha256_fromMidstate(ihr, ihr_buf.s);
106+
}
107+
if (IS_OK(*error) && amr) {
108+
static_assert(DAG_LEN_MAX <= SIZE_MAX / sizeof(analyses), "analysis array too large.");
109+
static_assert(1 <= DAG_LEN_MAX, "DAG_LEN_MAX is zero.");
110+
static_assert(DAG_LEN_MAX - 1 <= UINT32_MAX, "analysis array index does nto fit in uint32_t.");
111+
analyses *analysis = simplicity_malloc((size_t)dag_len * sizeof(analyses));
112+
if (analysis) {
113+
simplicity_computeAnnotatedMerkleRoot(analysis, dag, type_dag, (uint_fast32_t)dag_len);
114+
if (0 != memcmp(amr_hash.s, analysis[dag_len-1].annotatedMerkleRoot.s, sizeof(uint32_t[8]))) {
115+
*error = SIMPLICITY_ERR_AMR;
116+
}
117+
} else {
118+
/* malloc failed which counts as a transient error. */
119+
*error = SIMPLICITY_ERR_MALLOC;
120+
}
121+
simplicity_free(analysis);
122+
}
123+
if (IS_OK(*error)) {
124+
txEnv env = simplicity_bitcoin_build_txEnv(tx, taproot, ix);
125+
static_assert(BUDGET_MAX <= UBOUNDED_MAX, "BUDGET_MAX doesn't fit in ubounded.");
126+
*error = evalTCOProgram( dag, type_dag, (size_t)dag_len
127+
, minCost <= BUDGET_MAX ? (ubounded)minCost : BUDGET_MAX
128+
, &(ubounded){budget <= BUDGET_MAX ? (ubounded)budget : BUDGET_MAX}
129+
, &env);
130+
}
131+
simplicity_free(type_dag);
132+
}
133+
134+
simplicity_free(dag);
135+
return IS_PERMANENT(*error);
136+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#ifndef SIMPLICITY_BITCOIN_EXEC_H
2+
#define SIMPLICITY_BITCOIN_EXEC_H
3+
4+
#include <stdbool.h>
5+
#include <stdint.h>
6+
#include <stdio.h>
7+
#include <simplicity/errorCodes.h>
8+
#include <simplicity/bitcoin/env.h>
9+
10+
/* Deserialize a Simplicity 'program' with its 'witness' data and execute it in the environment of the 'ix'th input of 'tx' with `taproot`.
11+
*
12+
* If at any time malloc fails then '*error' is set to 'SIMPLICITY_ERR_MALLOC' and 'false' is returned,
13+
* meaning we were unable to determine the result of the simplicity program.
14+
* Otherwise, 'true' is returned indicating that the result was successfully computed and returned in the '*error' value.
15+
*
16+
* If deserialization, analysis, or execution fails, then '*error' is set to some simplicity_err.
17+
*
18+
* If 'amr != NULL' and the annotated Merkle root of the decoded expression doesn't match 'amr' then '*error' is set to 'SIMPLICITY_ERR_AMR'.
19+
*
20+
* Otherwise '*error' is set to 'SIMPLICITY_NO_ERROR'.
21+
*
22+
* If 'ihr != NULL' and '*error' is set to 'SIMPLICITY_NO_ERROR', then the identity hash of the root of the decoded expression is written to 'ihr'.
23+
* Otherwise if 'ihr != NULL' and '*error' is not set to 'SIMPLCITY_NO_ERROR', then 'ihr' may or may not be written to.
24+
*
25+
* Precondition: NULL != error;
26+
* NULL != ihr implies unsigned char ihr[32]
27+
* NULL != tx;
28+
* NULL != taproot;
29+
* 0 <= budget;
30+
* 0 <= minCost <= budget;
31+
* NULL != amr implies unsigned char amr[32]
32+
* unsigned char program[program_len]
33+
* unsigned char witness[witness_len]
34+
*/
35+
extern bool simplicity_bitcoin_execSimplicity( simplicity_err* error, unsigned char* ihr
36+
, const bitcoinTransaction* tx, uint_fast32_t ix, const bitcoinTapEnv* taproot
37+
, int64_t minCost, int64_t budget
38+
, const unsigned char* amr
39+
, const unsigned char* program, size_t program_len
40+
, const unsigned char* witness, size_t witness_len);
41+
#endif

0 commit comments

Comments
 (0)