├── .gitignore
├── LICENSE
├── README.md
├── doc
├── Expressions.md
├── Identifiers.md
├── Statements.md
└── Typess.md
└── src
├── BinaryOperation.cpp
├── BinaryOperation.h
├── Bits.h
├── BuildContext.cpp
├── BuildContext.h
├── Circuit.cpp
├── Circuit.h
├── CodeBloc.cpp
├── CodeBloc.h
├── Compiler.cpp
├── Compiler.h
├── CompositedGate.cpp
├── CompositedGate.h
├── Connection.cpp
├── Connection.h
├── Error.h
├── Expression.cpp
├── Expression.h
├── Expression_ArrayElement.cpp
├── Expression_ArrayElement.h
├── Expression_StructMember.cpp
├── Expression_StructMember.h
├── Expression_Variable.cpp
├── Expression_Variable.h
├── Function.cpp
├── Function.h
├── Gate.h
├── IGate.h
├── InterfaceInputsMap.h
├── LangageAttributes.cpp
├── LangageAttributes.h
├── LangageGrammar.cpp
├── LangageGrammar.h
├── Literal.cpp
├── Literal.h
├── Main.cpp
├── ParsingContext.cpp
├── ParsingContext.h
├── Program.cpp
├── Program.h
├── Scope.cpp
├── Scope.h
├── ScopeVariable.cpp
├── ScopeVariable.h
├── ShiftOperation.cpp
├── ShiftOperation.h
├── Statement.h
├── Statement_Break.cpp
├── Statement_Break.h
├── Statement_DeclareAndSetVar.cpp
├── Statement_DeclareAndSetVar.h
├── Statement_DeclareStruct.cpp
├── Statement_DeclareStruct.h
├── Statement_DeclareVar.cpp
├── Statement_DeclareVar.h
├── Statement_For.cpp
├── Statement_For.h
├── Statement_Function_Call.cpp
├── Statement_Function_Call.h
├── Statement_If.cpp
├── Statement_If.h
├── Statement_Increment.cpp
├── Statement_Increment.h
├── Statement_Return.cpp
├── Statement_Return.h
├── Statement_SetVar.cpp
├── Statement_SetVar.h
├── TapScriptGate.cpp
├── TapScriptGate.h
├── Test.cpp
├── Test.h
├── TestOperation.cpp
├── TestOperation.h
├── TokenId.h
├── Type.cpp
├── Type.h
├── TypeArray.cpp
├── TypeArray.h
├── TypeStruct.cpp
├── TypeStruct.h
├── UnaryOperation.cpp
├── UnaryOperation.h
├── VariableDefinition.h
├── bitcoin-bitvm-compiler.sln
├── bitcoin-bitvm-compiler.vcxproj
├── bitcoin-bitvm-compiler.vcxproj.filters
├── export.txt
├── sample
├── hello_word.bvc
├── test_add.bvc
├── test_and.bvc
├── test_array.bvc
├── test_array_2.bvc
├── test_array_3.bvc
├── test_complement.bvc
├── test_declare_and_set.bvc
├── test_decrement.bvc
├── test_equal_bool.bvc
├── test_equal_int8.bvc
├── test_for.bvc
├── test_greater.bvc
├── test_greater_or_equal.bvc
├── test_if.bvc
├── test_if_and_stuct.bvc
├── test_include.bvc
├── test_include.bvh
├── test_increment.bvc
├── test_int256.bvc
├── test_int32.bvc
├── test_int64.bvc
├── test_int8.bvc
├── test_literal.bvc
├── test_local_var.bvc
├── test_lower.bvc
├── test_lower_or_equal.bvc
├── test_negate.bvc
├── test_not.bvc
├── test_notequal_int8.bvc
├── test_or.bvc
├── test_parenthesis.bvc
├── test_precedencec.bvc
├── test_proc.bvc
├── test_shit_left.bvc
├── test_shit_right.bvc
├── test_struct.bvc
├── test_sub.bvc
└── test_xor.bvc
└── test.out
/.gitignore:
--------------------------------------------------------------------------------
1 | src/.vs
2 | /x64
3 | *.user
4 | *.tlog
5 | *.log
6 | *.obj
7 | *.exe
8 | *.pdb
9 | *.idb
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 |
9 | This version of the GNU Lesser General Public License incorporates
10 | the terms and conditions of version 3 of the GNU General Public
11 | License, supplemented by the additional permissions listed below.
12 |
13 | 0. Additional Definitions.
14 |
15 | As used herein, "this License" refers to version 3 of the GNU Lesser
16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
17 | General Public License.
18 |
19 | "The Library" refers to a covered work governed by this License,
20 | other than an Application or a Combined Work as defined below.
21 |
22 | An "Application" is any work that makes use of an interface provided
23 | by the Library, but which is not otherwise based on the Library.
24 | Defining a subclass of a class defined by the Library is deemed a mode
25 | of using an interface provided by the Library.
26 |
27 | A "Combined Work" is a work produced by combining or linking an
28 | Application with the Library. The particular version of the Library
29 | with which the Combined Work was made is also called the "Linked
30 | Version".
31 |
32 | The "Minimal Corresponding Source" for a Combined Work means the
33 | Corresponding Source for the Combined Work, excluding any source code
34 | for portions of the Combined Work that, considered in isolation, are
35 | based on the Application, and not on the Linked Version.
36 |
37 | The "Corresponding Application Code" for a Combined Work means the
38 | object code and/or source code for the Application, including any data
39 | and utility programs needed for reproducing the Combined Work from the
40 | Application, but excluding the System Libraries of the Combined Work.
41 |
42 | 1. Exception to Section 3 of the GNU GPL.
43 |
44 | You may convey a covered work under sections 3 and 4 of this License
45 | without being bound by section 3 of the GNU GPL.
46 |
47 | 2. Conveying Modified Versions.
48 |
49 | If you modify a copy of the Library, and, in your modifications, a
50 | facility refers to a function or data to be supplied by an Application
51 | that uses the facility (other than as an argument passed when the
52 | facility is invoked), then you may convey a copy of the modified
53 | version:
54 |
55 | a) under this License, provided that you make a good faith effort to
56 | ensure that, in the event an Application does not supply the
57 | function or data, the facility still operates, and performs
58 | whatever part of its purpose remains meaningful, or
59 |
60 | b) under the GNU GPL, with none of the additional permissions of
61 | this License applicable to that copy.
62 |
63 | 3. Object Code Incorporating Material from Library Header Files.
64 |
65 | The object code form of an Application may incorporate material from
66 | a header file that is part of the Library. You may convey such object
67 | code under terms of your choice, provided that, if the incorporated
68 | material is not limited to numerical parameters, data structure
69 | layouts and accessors, or small macros, inline functions and templates
70 | (ten or fewer lines in length), you do both of the following:
71 |
72 | a) Give prominent notice with each copy of the object code that the
73 | Library is used in it and that the Library and its use are
74 | covered by this License.
75 |
76 | b) Accompany the object code with a copy of the GNU GPL and this license
77 | document.
78 |
79 | 4. Combined Works.
80 |
81 | You may convey a Combined Work under terms of your choice that,
82 | taken together, effectively do not restrict modification of the
83 | portions of the Library contained in the Combined Work and reverse
84 | engineering for debugging such modifications, if you also do each of
85 | the following:
86 |
87 | a) Give prominent notice with each copy of the Combined Work that
88 | the Library is used in it and that the Library and its use are
89 | covered by this License.
90 |
91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
92 | document.
93 |
94 | c) For a Combined Work that displays copyright notices during
95 | execution, include the copyright notice for the Library among
96 | these notices, as well as a reference directing the user to the
97 | copies of the GNU GPL and this license document.
98 |
99 | d) Do one of the following:
100 |
101 | 0) Convey the Minimal Corresponding Source under the terms of this
102 | License, and the Corresponding Application Code in a form
103 | suitable for, and under terms that permit, the user to
104 | recombine or relink the Application with a modified version of
105 | the Linked Version to produce a modified Combined Work, in the
106 | manner specified by section 6 of the GNU GPL for conveying
107 | Corresponding Source.
108 |
109 | 1) Use a suitable shared library mechanism for linking with the
110 | Library. A suitable mechanism is one that (a) uses at run time
111 | a copy of the Library already present on the user's computer
112 | system, and (b) will operate properly with a modified version
113 | of the Library that is interface-compatible with the Linked
114 | Version.
115 |
116 | e) Provide Installation Information, but only if you would otherwise
117 | be required to provide such information under section 6 of the
118 | GNU GPL, and only to the extent that such information is
119 | necessary to install and execute a modified version of the
120 | Combined Work produced by recombining or relinking the
121 | Application with a modified version of the Linked Version. (If
122 | you use option 4d0, the Installation Information must accompany
123 | the Minimal Corresponding Source and Corresponding Application
124 | Code. If you use option 4d1, you must provide the Installation
125 | Information in the manner specified by section 6 of the GNU GPL
126 | for conveying Corresponding Source.)
127 |
128 | 5. Combined Libraries.
129 |
130 | You may place library facilities that are a work based on the
131 | Library side by side in a single library together with other library
132 | facilities that are not Applications and are not covered by this
133 | License, and convey such a combined library under terms of your
134 | choice, if you do both of the following:
135 |
136 | a) Accompany the combined library with a copy of the same work based
137 | on the Library, uncombined with any other library facilities,
138 | conveyed under the terms of this License.
139 |
140 | b) Give prominent notice with the combined library that part of it
141 | is a work based on the Library, and explaining where to find the
142 | accompanying uncombined form of the same work.
143 |
144 | 6. Revised Versions of the GNU Lesser General Public License.
145 |
146 | The Free Software Foundation may publish revised and/or new versions
147 | of the GNU Lesser General Public License from time to time. Such new
148 | versions will be similar in spirit to the present version, but may
149 | differ in detail to address new problems or concerns.
150 |
151 | Each version is given a distinguishing version number. If the
152 | Library as you received it specifies that a certain numbered version
153 | of the GNU Lesser General Public License "or any later version"
154 | applies to it, you have the option of following the terms and
155 | conditions either of that published version or of any later version
156 | published by the Free Software Foundation. If the Library as you
157 | received it does not specify a version number of the GNU Lesser
158 | General Public License, you may choose any version of the GNU Lesser
159 | General Public License ever published by the Free Software Foundation.
160 |
161 | If the Library as you received it specifies that a proxy can decide
162 | whether future versions of the GNU Lesser General Public License shall
163 | apply, that proxy's public statement of acceptance of any version is
164 | permanent authorization for you to choose that version for the
165 | Library.
166 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # bitcoin-bitvm-compiler
2 |
3 | Generate one or more logical circuits for BitVM Bitcoin from a C like source code
4 |
5 |
6 | ## Example :
7 |
8 | ```c
9 | // simple test program
10 | int8 main(int8 a, int8 b)
11 | {
12 | int8 local_a_and_b = a & b;
13 | return local_a_and_b;
14 | }
15 | ```
16 |
17 | Generate the circuit(s) with :
18 | ```
19 | bitvmcompiler.exe source.bvc export.txt
20 | ```
21 |
22 | Output :
23 | ```
24 | 16 16
25 | 16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
26 | 8 17 19 21 23 25 27 29 31
27 | 1 16 1 0 8 NAND
28 | 1 17 1 16 16 NAND
29 | 1 18 1 1 9 NAND
30 | 1 19 1 18 18 NAND
31 | 1 20 1 2 10 NAND
32 | 1 21 1 20 20 NAND
33 | 1 22 1 3 11 NAND
34 | 1 23 1 22 22 NAND
35 | 1 24 1 4 12 NAND
36 | 1 25 1 24 24 NAND
37 | 1 26 1 5 13 NAND
38 | 1 27 1 26 26 NAND
39 | 1 28 1 6 14 NAND
40 | 1 29 1 28 28 NAND
41 | 1 30 1 7 15 NAND
42 | 1 31 1 30 30 NAND
43 |
44 | ```
45 |
46 | ## Testing
47 |
48 | The circuit can be tested with -run
49 | ex:
50 | ```Batchfile
51 | bitvmcompiler.exe test_int8.bvc -run a=0x73,b=0x5F
52 | ```
53 | Output :
54 | ```
55 | Running with : a=0x73,b=0x5F
56 | Simulation result : 0x53
57 | ```
58 |
59 | Tested and build with Visual Studio 2022
60 |
61 | # Notes
62 |
63 | Bits are in low endian (x86 format)
64 |
65 | # Current todo list :
66 |
67 | - function call ... in progress...
68 | - #include support ... in progress...
69 | - set a limit to the number of gates
70 | - operators : \* / %
71 | - basic function stdlib (sha256, shnor, min, max,... )
72 | - write a better language documentation
73 | - linux : create a makefile
74 | - wasm support and browser demo site
75 | - check for unused inputs instead of a "no more gates" error
76 | - optimize the generated circuit (use less gates)
77 | - better syntax error messages
78 | - += operator
79 | - save the build circuit in a file, and load it for execution / generation
80 |
--------------------------------------------------------------------------------
/doc/Expressions.md:
--------------------------------------------------------------------------------
1 | # Expressions
2 |
3 | An expression is a sequence of operators and their operands
4 |
5 | Expressions can be composed of variables, literals, operators and parenthesis.
6 |
7 | ex :
8 | ```c
9 | local_var + 1
10 | var1 - var2 + var3
11 | (var1 > 1) & (var3 < 2)
12 | ```
13 |
14 | The following operators are curently supported
15 |
16 | |operator | description | operand type | result |
17 | |---------|----------------|--------------|--------------|
18 | |! |boolean not | int or bool | int or bool |
19 | |& |logical and | int or bool | int or bool |
20 | || |logical or | int or bool | int or bool |
21 | |^ |logical xor | int or bool | int or bool |
22 | |< |lower | int | bool |
23 | |<= |lower or equal | int | bool |
24 | |> |greater | int | bool |
25 | |>= |greater or equal| int | bool |
26 | |<< |bit shit left | int | int |
27 | |>> |bit shit right | int | int |
28 | |+ |addition | int | int |
29 | |- |substaction | int | int |
30 |
31 | operator precedence is the same as C/C++
32 |
33 |
--------------------------------------------------------------------------------
/doc/Identifiers.md:
--------------------------------------------------------------------------------
1 | # Identifiers
2 |
3 | variable names anc be any mix of letters, numbers and underscores, but must start with a letter or underscore.
4 | ex : ``my_var, _my_var, myVar, myVar1, my_var_1
5 |
6 | User defined types must start with an Uppercase char
7 | ex: ``Header STParam My_struct
8 |
9 | Variables names must start whit a lowercase char
10 | ex: ``header stParam my_Struct myParam
11 |
--------------------------------------------------------------------------------
/doc/Statements.md:
--------------------------------------------------------------------------------
1 | # Statements
2 |
3 | The current statements are supported:
4 |
5 | ## local variable declaration
6 |
7 | declare a new local var in the current scope
8 |
9 | example :
10 | ```c
11 | int8 local_var;
12 | ```
13 |
14 | ## Struct type declaration
15 |
16 | declare a new stucrture to be used as a user type
17 |
18 | example :
19 | ```c
20 | struct Header {
21 | int8 a;
22 | int8 b;
23 | };
24 | int8 main(Header st_ab)
25 | ```
26 |
27 |
28 | ## Assignment
29 |
30 | set a variable in the current scope
31 |
32 | example:
33 | ```c
34 | var = 1234;
35 | ```
36 |
37 | ## Increment / Decrement
38 |
39 | Only supported as a single statement
40 | not a operator like in C/C++
41 |
42 | example:
43 | ```c
44 | var++;
45 | var--;
46 | ```
47 |
48 |
49 | ## Local variable declaration and assignment
50 |
51 | declare and set a variable in the current scope
52 |
53 | example:
54 | ```c
55 | int8 local_var = 0;
56 | ```
57 |
58 | ## Return
59 |
60 | set the return value of the circuit
61 | every bloc **must** end with a return statment.
62 |
63 | example:
64 | ```c
65 | return 0;
66 | ```
67 |
68 | ## If
69 |
70 | execute a code bloc depending of an expression that must be boolean
71 | internally the compiler generate 2 sub circuits for each possible bloc
72 |
73 | example :
74 | ```c
75 | if (val==42) {
76 | return 1;
77 | }
78 | return 0;
79 | ```
80 |
81 | ## For
82 |
83 | Loops are restricted because a new circuit must be gneerated for each step
84 |
85 | - start and end values must be litteral int
86 | - step statement must be i++ or i--
87 | - loop variable must be declared in the init statement
88 | - loop variable must be integer
89 | - loop variable is const, it cannot be modified in the loop
90 |
91 | example :
92 | ```c
93 | int32 sum=0;
94 | for (int8 i=0;i<32;i++) {
95 | sum = sum+i;
96 | }
97 | return sum;
98 | ```
99 |
--------------------------------------------------------------------------------
/doc/Typess.md:
--------------------------------------------------------------------------------
1 | # Types
2 |
3 | The following native types are supported :
4 |
5 | | name | description |
6 | |-----------|--------------------------|
7 | | bool | boolean / bit |
8 | | int8 | signed 8 bits integer |
9 | | uint8 | unsigned 8 bits integer |
10 | | int32 | signed 32 bits integer |
11 | | uint32 | unsigned 32 bits integer |
12 | | int64 | signed 64 bits integer |
13 | | uint64 | unsigned 64 bits integer |
14 | | int256 | signed 256 bits integer |
15 | | uint256 | unsigned 256 bits integer|
16 |
17 | # Structures
18 |
19 | Structures are supported, the following syntax is used :
20 | ```
21 | struct Header {
22 | int8 a;
23 | int8 b;
24 | };
25 | Header my_header;
26 | my_header.a = 1;
27 | my_header.b = 0;
28 | ```
29 |
30 | # Arrays
31 |
32 | Fixed sized arrays are supported, the following syntax is used :
33 | ```
34 | type[]
35 | type can be any of the native types
36 | ```
37 |
38 | example :
39 | ```
40 | int8[10] my_array;
41 | int8 sum=0;
42 | for (int8 i=0; i<10;i++) {
43 | sum = sum + my_array[i];
44 | }
45 | ```
46 |
--------------------------------------------------------------------------------
/src/BinaryOperation.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Program.h"
3 | #include
4 | #include "Error.h"
5 | #include "Circuit.h"
6 | #include "LangageGrammar.h"
7 | #include "BuildContext.h"
8 |
9 |
10 | // constructor for BinaryOperation
11 | BinaryOperation::BinaryOperation(Operator op, Expression* left, Expression* right)
12 | : operation(op)
13 | , left_operand(left)
14 | , right_operand(right) {
15 | // TODO
16 | // build the expression for debug purposes
17 | }
18 |
19 | // visit all part used in the Expression
20 | void BinaryOperation::visit_epression(IVisitExpression& visitor) {
21 | left_operand->visit_epression(visitor);
22 | right_operand->visit_epression(visitor);
23 | }
24 |
25 | // reorg epxresion tree to ensure operator precedence
26 | // ex: "a + b * c" must be calculad as "a + (b * c)"
27 | // retrun the new root of the expression
28 | BinaryOperation* BinaryOperation::BinaryOperation::reorg_for_precedence(LangageAttributes& language) {
29 | // only if the 1st operand is a binary operation
30 | BinaryOperation* left_operand_2op = left_operand->cast_to_BinaryOperation();
31 | if (left_operand_2op == nullptr)
32 | return this; // do nothing and keep tree as it is
33 | // if the expression is in (), do nothing
34 | if (left_operand_2op->has_parentesis)
35 | return this;
36 | // if the precedence is ok
37 | // ex: a*b+c
38 | if (left_operand_2op->has_higher_precedence(*this, language))
39 | return this; // do nothing and keep tree as it is
40 | // if the precedence is not ok
41 | // ex: a*b+c
42 | // regorganize the tree :
43 | // this
44 | // left |
45 | // a + b * c
46 | // =>
47 | // result
48 | // | this
49 | // a + b * c
50 | auto a = left_operand_2op->left_operand;
51 | auto b = left_operand_2op->right_operand;
52 | auto c = this->right_operand;
53 | BinaryOperation* result = left_operand_2op;
54 | left_operand_2op->left_operand = a;
55 | this->left_operand = b;
56 | this->right_operand = c;
57 | left_operand_2op->right_operand = this;
58 | return result;
59 |
60 | }
61 | // true is the expression has a higher precedence than the othe expression
62 | bool BinaryOperation::has_higher_precedence(const BinaryOperation& other_expression, LangageAttributes& language) const {
63 | // compare precedence with the other expression
64 | int cmp = language.compare_operator_precedence((int)operation, (int)other_expression.operation);
65 | return cmp < 0;
66 | }
67 |
68 |
69 | // init
70 | void BinaryOperation::init(Scope& parent_scope) {
71 | // init operands
72 | left_operand->init(parent_scope);
73 | right_operand->init(parent_scope);
74 | // left and right operand must have the same type
75 | if (!left_operand->get_type().is_same_type(right_operand->get_type()))
76 | {
77 | // if left if a literal, try to cast right to the type of left
78 | if (left_operand->cast_to_literal() != nullptr)
79 | right_operand->cast_to_literal()->change_type(right_operand->get_type());
80 | else if (right_operand->cast_to_literal() != nullptr )
81 | right_operand->cast_to_literal()->change_type(left_operand->get_type());
82 | else
83 | throw Error("Type mismatch");
84 | }
85 | // type must ba a basic type
86 | const TypeBasic* type_basic = left_operand->get_type().cast_to_TypeBasic();
87 | if (type_basic == nullptr)
88 | throw Error("Type must be a basic type");
89 | // copy basic type
90 | result_type = *type_basic;
91 | }
92 |
93 | // build the circuit for the binairy expression
94 | std::vector BinaryOperation::build_circuit(BuildContext& ctx) {
95 |
96 | // build the L& R operands
97 | std::vector output_left = left_operand->build_circuit(ctx);
98 | std::vector output_right = right_operand->build_circuit(ctx);
99 |
100 | // create the gate for the operation
101 | BinaryGate* gate = nullptr;
102 | switch (operation)
103 | {
104 | case Operator::op_and:
105 | gate = new Gate_AND();
106 | break;
107 | case Operator::op_or:
108 | gate = new Gate_OR();
109 | break;
110 | case Operator::op_xor:
111 | gate = new Gate_XOR();
112 | break;
113 | case Operator::op_add:
114 | // a+b is not bit to bit independant
115 | return build_circuit_add(ctx, output_left, output_right);
116 | case Operator::op_sub:
117 | // a-b is not bit to bit independant
118 | return build_circuit_sub(ctx, output_left, output_right);
119 | default:
120 | assert(false);
121 | throw Error("Internal error : unexpected operator");
122 | }
123 |
124 | // for each bit connect gate input and output
125 | std::vector result;
126 | int size = get_type().size_in_bit();
127 | assert(output_left.size() == size);
128 | assert(output_right.size() == size);
129 | for (int i = 0; i < size; i++) {
130 | // IN
131 | std::array input_2_bit = { output_left[i], output_right[i] };
132 | // OUT = A OP B
133 | std::array bits_result = gate->add_to_circuit(ctx.circuit(), input_2_bit);
134 | //TODO
135 | //delete gate;
136 | result.insert(result.end(), bits_result.begin(), bits_result.end());
137 | }
138 | return result;
139 | }
140 | // build the circuit for the "a+b" expression
141 | std::vector BinaryOperation::build_circuit_add(BuildContext& ctx,
142 | std::vector& in_a,
143 | std::vector& in_b)
144 | {
145 | assert(in_a.size() == in_b.size());
146 | ctx.circuit().debug_info.description = "add";
147 |
148 | std::vector result;
149 | int size = (int)in_a.size();
150 | Gate_ADD gate_add; // add 2 birs, return carry + 1 bit
151 | Gate_ADDC gate_addc; // add 2 birs + carry, return carry + 1 bit
152 | // start with 1st bit addition
153 | std::array input_2_bit = { in_a[0], in_b[0] };
154 | std::array low_bits = gate_add.add_to_circuit(ctx.circuit(), input_2_bit);
155 | result.push_back(low_bits[0]);
156 | Connection* carry = low_bits[1];
157 | for (int i = 1; i < size; i++) {
158 | ctx.circuit().debug_info.description = "add bit " + std::to_string(i);
159 | // IN
160 | std::array input_3_bit = { in_a[i], in_b[i], carry };
161 | std::array bits_ = gate_addc.add_to_circuit(ctx.circuit(), input_3_bit);
162 | result.push_back(bits_[0]);
163 | carry = bits_[1];
164 | }
165 | // set debug info fo connexion
166 | for (int i = 0; i < size; i++) {
167 | result[i]->debug_description = "line " + std::to_string(ctx.current_statement ? ctx.current_statement->num_line:0) + " ADD bit " + std::to_string(i);
168 | }
169 |
170 | ctx.circuit().debug_info.description = "";
171 | assert(result.size() == size);
172 | return result;
173 | }
174 | // build the circuit for the "a-b" expression
175 | std::vector BinaryOperation::build_circuit_sub(BuildContext& ctx,
176 | std::vector& in_a,
177 | std::vector& in_b) {
178 | assert(in_a.size() == in_b.size());
179 | // implent wita a-b = a+(-b)
180 | // build the circuit for -b
181 | std::vector neg_b = UnaryOperation::build_circuit_negation(ctx, in_b);
182 | // build the circuit for a+(-b)
183 | std::vector a_minus_b = build_circuit_add(ctx, in_a, neg_b);
184 | return a_minus_b;
185 | }
186 |
--------------------------------------------------------------------------------
/src/BinaryOperation.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitrebitcoin/bitcoin-bitvm-compiler/03e3939492b925f1a9d28a05442a77817118b276/src/BinaryOperation.h
--------------------------------------------------------------------------------
/src/Bits.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | class Gate;
5 |
6 |
7 | // represents a bit in the circuit
8 | class Bit {
9 | private:
10 | bool value = false;
11 | public:
12 | // get the value of the bit : overrides the cast to bool operator
13 | operator bool() const {
14 | return value;
15 | }
16 | // set the value of the bit
17 | void set_value(bool b) {
18 | value = b;
19 | }
20 | };
21 | // arrays of bits
22 | using Bits = std::vector;
23 |
24 |
--------------------------------------------------------------------------------
/src/BuildContext.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "BuildContext.h"
3 | #include "Circuit.h"
4 |
5 | // constructor
6 | BuildContext::BuildContext(Caller caller) : create_caller(caller)
7 | {
8 | assert(caller == Caller::main_body);
9 | // alloc main circuit
10 | ctx_circuit = new Circuit();
11 | }
12 | // destructor
13 | BuildContext::~BuildContext() {
14 | build_all_next_statements = nullptr;
15 | }
16 |
17 |
18 | // copy constructor
19 | BuildContext::BuildContext(const BuildContext& source, Caller caller) : create_caller(caller)
20 | {
21 | nested_if = source.nested_if ;
22 | current_statement = source.current_statement;
23 |
24 | assert(caller != Caller::main_body);
25 | switch (caller)
26 | {
27 | case Caller::if_statement:
28 | // create a new sub circuit
29 | ctx_circuit = new Circuit();
30 | for_statement = source.for_statement;
31 | // action to build after the if statement
32 | build_all_next_statements = source.build_all_next_statements;
33 | build_on_break = source.build_on_break;
34 | nested_if++;
35 | break;
36 | case Caller::for_statement:
37 | // share the same circuit in a for statement
38 | ctx_circuit = source.ctx_circuit;
39 | // action to build after the for statement
40 | build_all_next_statements = source.build_all_next_statements;
41 | build_on_break = source.build_on_break;
42 |
43 | // copy all vaiables
44 | ctx_variables = source.variables();
45 | break;
46 | case Caller::build_next_lambda:
47 | // sub conterxt to preserve build_all_next_statements
48 | ctx_circuit = source.ctx_circuit;
49 | for_statement = source.for_statement;
50 | parent_ctx_variables = const_cast(&source.variables());
51 | break;
52 | default:
53 | assert(false);
54 | throw Error("internal error : unknown caller");
55 | }
56 | }
57 |
58 |
59 | // Init variables and If Gate for a "IF" statmeent
60 | void BuildContext::init_variables_if_gate(BuildContext& ctx_source, class Gate_IF* gate, bool bloc_side) {
61 | assert(create_caller == Caller::if_statement);
62 |
63 | // get all copy parameters from source
64 | BuildContext::InfoCopy infoCopy = ctx_source.get_info_copy();
65 |
66 | // init variables
67 | ctx_variables = infoCopy.variables_dest;
68 | // inits connexions to the gate
69 | for (Connection* connexion : infoCopy.connexions_dest) {
70 | gate->add_input(connexion, bloc_side);
71 | }
72 | // init circuit inputs
73 | circuit().set_circuit_inputs(infoCopy.nb_bits_in(), infoCopy.input_map);
74 | }
75 |
76 | // get all info needed to create a new copy of acontexte; for "if statement"
77 | BuildContext::InfoCopy BuildContext::get_info_copy(void) const {
78 |
79 | InfoCopy result;
80 | // get all variables to copy
81 | variables().visit_all_variables([&](const ScopeVariable& variable_source) {
82 |
83 | // copy var from source to dest
84 | ScopeVariable* copy_var = result.variables_dest.copy_var(variable_source);
85 | // copy connexions for source to the gate
86 | for (Connection* connexion_copy : copy_var->bits) {
87 | result.connexions_dest.push_back(connexion_copy);
88 | }
89 | });
90 |
91 | // basic impleation of InterfaceInputsMap
92 | class Void_InterfaceInputsMap : public InterfaceInputsMap {
93 | // InterfaceInputsMap Implementation
94 | // get a parameter info by name
95 | virtual InterfaceInputsMap::Info find_info_by_name(std::string name) const override {
96 | // used by commandline -run ony
97 | assert(false);
98 | throw Error("Internal error, not implemented");
99 | }
100 | };//InterfaceInputsMap
101 |
102 | // init circuit inputs
103 | result.input_map = new Void_InterfaceInputsMap();
104 |
105 | return result;
106 |
107 | }
108 |
109 |
110 | // visit all the circuits
111 | void BuildContext::visit_circuits(std::function fnVisit) {
112 | // main circuit
113 | fnVisit(circuit());
114 | // sub circuits
115 | circuit().visit_sub_circuits(fnVisit);
116 | }
117 |
118 | // get the variables in the contexte
119 | ScopeVariables& BuildContext::variables(void) const
120 | {
121 | // if we share varaibles with the parent context
122 | if (parent_ctx_variables != nullptr) {
123 | assert(create_caller == Caller::build_next_lambda );
124 | return *parent_ctx_variables;
125 | }
126 | return const_cast(this)->ctx_variables;
127 |
128 | }
129 |
130 |
--------------------------------------------------------------------------------
/src/BuildContext.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "VariableDefinition.h"
6 | #include "ScopeVariable.h"
7 |
8 |
9 | class Circuit;
10 | class ScopeVariables;
11 | class Connection;
12 | class Statement_For;
13 | class IVisitExpression;
14 | class InterfaceInputsMap;
15 | using InputsMap = InterfaceInputsMap*;
16 |
17 | // context for building the circuit
18 | class BuildContext {
19 | public:
20 | // description for debug purpose
21 | std::string debug_description;
22 | // current statement pour debug purpose
23 | class Statement* current_statement = nullptr;
24 |
25 | // creation or copy type
26 | enum class Caller { main_body, if_statement, for_statement, function_call, build_next_lambda};
27 | // action return, what to do to build all next statements
28 | enum class NextAction { Continue, Break, Return };
29 | // number of nested if
30 | int nested_if = 0;
31 |
32 | protected:
33 | Caller create_caller;
34 | Circuit* ctx_circuit = nullptr; // the circuit to build
35 | ScopeVariables ctx_variables; // current known variables in the current scope
36 | ScopeVariables* parent_ctx_variables= nullptr; // variables ftom the parent context
37 |
38 |
39 | public:
40 | Statement_For* for_statement = nullptr; // the current for statement if we are building a loop
41 |
42 | // action to do to build all next statementq
43 | std::function < NextAction(BuildContext&) > build_all_next_statements;
44 | // action to do in case a "break" is encountered
45 | std::function < NextAction(BuildContext&) > build_on_break;
46 |
47 | public:
48 | // constructor
49 | BuildContext(Caller caller);
50 | // copy constructor
51 | BuildContext(const BuildContext& source, Caller caller);
52 | // destructor
53 | ~BuildContext();
54 |
55 | // Init variables and If Gate for a "IF" statmeent
56 | void init_variables_if_gate(BuildContext& ctx_source, class Gate_IF* gate, bool bloc_side);
57 |
58 | // get the current circuit to build in the context
59 | Circuit& circuit(void) { return *ctx_circuit; }
60 | // get the variables in the contexte
61 | ScopeVariables& variables(void) const;
62 | // visit all the circuits
63 | void visit_circuits(std::function fnVisit);
64 | // are we in a for statement ?
65 | bool is_in_for_loop(void) const { return for_statement != nullptr; }
66 |
67 | protected:
68 | // get all info needed to create a new copy of acontexte; for "if statement"
69 | class InfoCopy {
70 | public:
71 | ScopeVariables variables_dest; // copy of all variables t
72 | std::vector connexions_dest; // connexion in the copied var
73 | InputsMap input_map = nullptr; // map for connexions_dest
74 | public:
75 | // number of bits in the new context
76 | int nb_bits_in(void) const { return (int)connexions_dest.size(); }
77 | };
78 | InfoCopy get_info_copy(void) const;
79 | };
80 |
81 |
--------------------------------------------------------------------------------
/src/Circuit.cpp:
--------------------------------------------------------------------------------
1 | // Gates.cpp
2 | // Implementation of the Circuit class.
3 |
4 |
5 | #include
6 | #include
7 | #include "Circuit.h"
8 | #include "Literal.h"
9 |
10 | // constructor
11 | Circuit::Circuit(void) {
12 | }
13 |
14 |
15 | // set the numbre of bits inputs of the circuit
16 | void Circuit::set_circuit_inputs(int bit_count, InputsMap map) {
17 | assert(!is_fully_constructed); // too late to set inputs
18 | for (int i = 0; i < bit_count; i++) {
19 | Connection* input_i = new Connection();
20 | inputs.push_back(input_i);
21 | }
22 | correspondance_inputs = map;
23 | }
24 |
25 | // set connections ouput
26 | void Circuit::set_output(std::vector new_outputs)
27 | {
28 | assert(!is_fully_constructed);
29 | assert(outputs.size() == 0);
30 | assert(new_outputs.size() > 0);
31 | assert(output_size_child == 0);
32 |
33 | for (Connection* connexion : new_outputs) {
34 | connexion->is_output = true;
35 | outputs.push_back(connexion);
36 | }
37 | }
38 | // if the circuit have sub circuits (If statement for exemple), set the output size only
39 | void Circuit::set_output_size_child(NbBit size) {
40 | assert(!is_fully_constructed);
41 | assert(outputs.size() == 0);
42 | assert(output_size_child == 0);
43 | assert(size > 0);
44 |
45 | output_size_child = size;
46 | }
47 |
48 |
49 |
50 | // add a gate and its connexions into the circuit
51 | void Circuit::add_gate(TapScriptGate* gate) {
52 | assert(!is_fully_constructed);
53 | // set debug info
54 | gate->debug_info = debug_info;
55 | // add the gate to the circuit
56 | gates.push_back(gate);
57 | // add ouputs to the circuits
58 | std::vector outs = gate->get_outputs();
59 | for (Connection* ouput_gate_i : outs) {
60 | // +1 connection
61 | connections.push_back(ouput_gate_i);
62 | }
63 | }
64 | // a get connection for a litteral values
65 | Connection* Circuit::get_literal_values(bool b) {
66 | // init at 1st call
67 | if (literals01[b] == nullptr) {
68 | literals01[b] = new Connection();
69 | literals01[b]->set_value(b);
70 | }
71 | return literals01[b];
72 | }
73 | // is the circuit usign litteral values ?
74 | bool Circuit::is_using_litteral_values(void) const {
75 | return literals01[0] != nullptr
76 | || literals01[1] != nullptr;
77 | }
78 |
79 | // get all gartes that have calculated inputes but have not been run yet
80 | std::vector Circuit::_get_computable_gate(void) const {
81 | std::vector computable_gates;
82 | for (TapScriptGate* gate : gates) {
83 | if ( gate->all_inputs_calculated()
84 | && !gate->is_computed) {
85 | computable_gates.push_back(gate);
86 | }
87 | }
88 | return computable_gates;
89 | }
90 |
91 | // init the value of a variable
92 | void CRunInputs::set_varaible_value(std::string name, std::string value) {
93 |
94 | assert(correspondance_inputs != nullptr);
95 | // look for the variable
96 | auto info_var = correspondance_inputs->find_info_by_name(name);
97 | if (!info_var.found)
98 | throw Error("Unknown variable name", name);
99 | // get the type of the variable
100 | Type *type = info_var.type;
101 | // muet be a basic type
102 | if (!type->is_basic())
103 | throw Error("Not a basic type", name);
104 | Type::Native native_type = type->cast_to_TypeBasic()->get_native_type();
105 |
106 | // convert the value to array of bit
107 | std::vector bits = Literal::get_bools_from_value_str(native_type, value);
108 | int nb_bit = type->size_in_bit();
109 | assert(nb_bit== bits.size());
110 |
111 | // set x bits of the value
112 | for (int i = 0; i < nb_bit; i++) {
113 | set_bit_value(info_var.offset_in_bit + i, bits[i]);
114 | }
115 |
116 | }
117 |
118 |
119 | // get inout of the circuit. to set values before running it
120 | CRunInputs Circuit::get_run_inputs(void) const {
121 | assert(is_fully_constructed);
122 | CRunInputs result;
123 | result.init((int)inputs.size(), correspondance_inputs);
124 | return std::move(result);
125 |
126 |
127 | }
128 |
129 | // size in bits of the output
130 | NbBit Circuit::nb_bits_output(void) const
131 | {
132 | // if the size comme from a sub circuit
133 | if (output_size_child != 0)
134 | {
135 | assert(outputs.size() == 0);
136 | return output_size_child;
137 | }
138 | return (NbBit)outputs.size();
139 | }
140 |
141 | // check if all outputs are computed
142 | bool Circuit::_all_outputs_calculated(void) const {
143 | if (outputs.size() == 0)
144 | return false;
145 |
146 | for (Connection* output : outputs) {
147 | if (!output->is_calculated())
148 | return false;
149 | }
150 | return true;
151 | }
152 |
153 |
154 | // run the circuit
155 | std::vector Circuit::run(const CRunInputs& in_values) const {
156 |
157 | assert(nb_bits_output() > 0);
158 | //assert(in_values.size() > 0); no in sub circuit. ex : "Return 0"
159 | assert(in_values.size() == inputs.size());
160 |
161 | // init bits values in input
162 | for (int i = 0; i < in_values.size(); i++)
163 | {
164 | inputs[i]->set_value(in_values[i]);
165 | }
166 |
167 | // run whle we have not a result
168 | int nb_step = 0;
169 | while (true)
170 | {
171 | // if all outputs are computed, we have a result
172 | if (_all_outputs_calculated()) {
173 | // build the result
174 | std::vector result(nb_bits_output());
175 | int i = 0;
176 | for (Connection* connection_i : outputs) {
177 | assert(connection_i->is_output);
178 | bool value_calculted = connection_i->get_value();
179 | result[i].set_value(value_calculted);
180 | i++;
181 | }
182 | return result;
183 | }
184 |
185 | // get gates that have calculated intpus
186 | std::vector gate_to_run = _get_computable_gate();
187 | // if no more gates to run, error
188 | if (gate_to_run.size() == 0)
189 | throw Error( "internal error : no more gates" );
190 |
191 | // special case If gate
192 | if (gate_to_run.size() == 1 && gate_to_run[0]->cast_to_IF() != nullptr) {
193 | // run the if gate : a sub progrma depending on the value of the condition
194 | Gate_IF* gate_if = gate_to_run[0]->cast_to_IF();
195 | return gate_if->compute_if();
196 | }
197 |
198 | // run all the gates, but if gate
199 | for (TapScriptGate* gate : gate_to_run) {
200 | if (!gate->cast_to_IF()) {
201 | gate->compute();
202 | assert(gate->is_computed);
203 | }
204 | }
205 |
206 | // continue calculation
207 | nb_step++;
208 |
209 | } // while (true)
210 |
211 | }
212 |
213 | // reset the circuit gates before a new run. resursive to all sub circuits
214 | void Circuit::reset(void) const {
215 | _reset_non_recursive();
216 | // reset sub circuits
217 | visit_sub_circuits([](Circuit& sub_circiut) {
218 | sub_circiut._reset_non_recursive();
219 | });
220 | }
221 |
222 | // reset the circuit gate before a new run. non recursive
223 | void Circuit::_reset_non_recursive(void) const
224 | {
225 | for (TapScriptGate* gate : gates) {
226 | gate->is_computed = false;
227 | }
228 | for (Connection* connection_i : connections) {
229 | connection_i->reset();
230 | }
231 | for (Connection* connection_i : inputs){
232 | connection_i->reset();
233 | }
234 |
235 |
236 | }
237 | // init gates and connections ID
238 | void Circuit::init_id_gates_and_connexions(int &connection_id)
239 | {
240 | // give an ID to all gates and all connections
241 | for (int i = 0; i < gates.size(); i++) {
242 | gates[i]->id = i;
243 | }
244 | // init literals
245 | if (literals01[0])
246 | literals01[0]->id = connection_id++;
247 | if (literals01[1])
248 | literals01[1]->id = connection_id++;
249 | // init inputs and connections
250 | for (Connection* input_i : inputs) {
251 | input_i->id = connection_id;
252 | connection_id++;
253 | }
254 | for (Connection* connection_i : connections) {
255 | if (connection_i->id != 0)
256 | continue;
257 | connection_i->id = connection_id;
258 | connection_id++;
259 | }
260 |
261 | is_fully_constructed = true;
262 | }
263 |
264 | // get stats on the circuit
265 | Circuit::Stats Circuit::get_stats(void) const {
266 | Circuit::Stats result;
267 | result.nb_gate =(int)gates.size();
268 | result.nb_connection =(int)connections.size();
269 | result.nb_input =(int)inputs.size();
270 | result.nb_output =(int)outputs.size();
271 | return result;
272 | }
273 |
274 | // export to a string
275 | std::string Circuit::export_to_string(void) const {
276 | //std::string result;
277 | std::ostringstream str_stream;
278 | export_to_stream(str_stream);
279 | return str_stream.str();
280 | }
281 | // export to a stream in the Bristol Fashion
282 | // inspired from https://github.com/mcbagz/LogicGates/blob/main/Example.ipynb
283 | // format : https://pypi.org/project/circuit/
284 | // see also https://homes.esat.kuleuven.be/~nsmart/MPC/
285 | void Circuit::export_to_stream(std::ostream& out) const {
286 | assert(is_fully_constructed);
287 |
288 | //# of gates + # of of wires
289 | out << std::to_string(gates.size()) << ' ' << std::to_string(connections.size());
290 | out << "\n";
291 | //# of inputs
292 | out << std::to_string(inputs.size());
293 | // inputs
294 | for (Connection* input_i : inputs) {
295 | out << " " << std::to_string(input_i->id);
296 | }
297 | out << "\n";
298 | //# of outputs
299 | out << std::to_string(outputs.size());
300 | // outputs
301 | for (Connection* output_i : outputs) {
302 | out << " " << std::to_string(output_i->id);
303 | }
304 |
305 | // 0 and 1 for litterals
306 | if (is_using_litteral_values())
307 | {
308 | // wire 0 is assigned the value 0 and wire 1 the value 1
309 | if (literals01[0]) {
310 | out << "\n" << "1 1 0 " << literals01[0]->id << " EQ";
311 | }
312 | if (literals01[1]) {
313 | out << "\n" << "1 1 1 " << literals01[1]->id << " EQ";
314 | }
315 | }
316 |
317 | // Gates
318 | for (TapScriptGate* gate_i : gates) {
319 | out << "\n";
320 | // # inputs
321 | auto outs = gate_i->get_outputs();
322 | out << std::to_string(outs.size());
323 | for (Connection* out_i : outs) {
324 | out << " " << std::to_string(out_i->id);
325 | }
326 | // # outputs
327 | out << " ";
328 | auto ins = gate_i->get_inputs();
329 | out << std::to_string(outs.size());
330 | for (Connection* in_i : ins) {
331 | out << " " << std::to_string(in_i->id);
332 | }
333 | // gate type
334 | out << " " << gate_i->get_export_type();
335 |
336 | }
337 |
338 | out << "\n";
339 | }
340 | // visit all sub circuits
341 | void Circuit::visit_sub_circuits(std::function visitor) const {
342 | for (TapScriptGate* gate_i : gates) {
343 | // special case If gate
344 | if (gate_i->cast_to_IF()) {
345 | // cast to IF gate
346 | Gate_IF* gate_if = gate_i->cast_to_IF();
347 | // visit sub circuits of the IF gate
348 | visitor(*gate_if->circuit_if_true);
349 | gate_if->circuit_if_true->visit_sub_circuits(visitor);
350 | visitor(*gate_if->circuit_if_false);
351 | gate_if->circuit_if_false->visit_sub_circuits(visitor);
352 |
353 | }
354 | }
355 |
356 | }
--------------------------------------------------------------------------------
/src/Circuit.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include "Bits.h"
5 | #include "Gate.h"
6 | #include "Error.h"
7 | #include "Function.h"
8 | #include "InterfaceInputsMap.h"
9 |
10 | class TapScriptGate;
11 | class Circuit;
12 | class CRunInputs;
13 |
14 |
15 | using InputsMap = InterfaceInputsMap*;
16 | using NbBit = int;
17 |
18 | // represents a virtual circuit
19 | class Circuit {
20 | public:
21 | // debug info
22 | CDebugInfo debug_info;
23 | private:
24 | // circuit id
25 | int id = 0;
26 | // inputs in the circuit
27 | std::vector inputs;
28 | // gates in the circuit
29 | std::vector gates;
30 | // ouputs of the circuit
31 | std::vector outputs;
32 | // if the circuit have sub circuits (If statement for exemple), set the output size only
33 | NbBit output_size_child = 0;
34 |
35 | // connections in the circuit
36 | std::vector connections;
37 | // litteral values : 0 an 1
38 | std::array literals01;
39 |
40 | // set to true when the circuit is connot be modified anymore
41 | bool is_fully_constructed = false;
42 |
43 | // map for input correspondance
44 | InputsMap correspondance_inputs = nullptr;
45 |
46 | public:
47 |
48 | // constructor
49 | Circuit(void);
50 |
51 | // set the number of bits inputs of the circuit
52 | void set_circuit_inputs(int bit_count, InputsMap input_map);
53 | // add a gate into the circuit
54 | void add_gate(TapScriptGate* gate);
55 | // set all connections ouput
56 | void set_output(std::vector new_outputs);
57 | // a get connection for a litteral values
58 | Connection* get_literal_values(bool b);
59 | // get the input gates in the circuit
60 | std::vector getInputs(void) { return inputs; }
61 | // is the circuit usign litteral values ?
62 | bool is_using_litteral_values(void) const;
63 |
64 | // if the circuit have sub circuits (If statement for exemple), set the output size only
65 | void set_output_size_child(NbBit size);
66 | // size in bits of the output
67 | NbBit nb_bits_output(void) const;
68 |
69 | // get inout of the circuit. to set values before running it
70 | CRunInputs get_run_inputs(void) const;
71 | // run the circuit
72 | std::vector run(const CRunInputs& inputs) const;
73 | // reset the circuit gate before a new run
74 | void reset(void) const;
75 | // set id fro the ciruit
76 | void set_id(int id) { this->id = id; }
77 | // init gates and connections ID
78 | void init_id_gates_and_connexions(int& connection_id);
79 |
80 | // export to a string
81 | std::string export_to_string(void) const;
82 | // export to a strem
83 | // inspired from https://github.com/mcbagz/LogicGates/blob/main/Example.ipynb
84 | // format : https://pypi.org/project/circuit/
85 | void export_to_stream(std::ostream& out) const;
86 | // get stats
87 | struct Stats {
88 | int nb_gate = 0;
89 | int nb_connection = 0;
90 | int nb_input = 0;
91 | int nb_output = 0;
92 | };
93 | Stats get_stats(void) const;
94 | // visit all sub circuits
95 | void visit_sub_circuits(std::function visitor) const;
96 |
97 | protected:
98 | // get all gates that have calculated inputes
99 | std::vector _get_computable_gate(void) const;
100 | // check if all outputs are computed
101 | bool _all_outputs_calculated(void) const;
102 | // reset the circuit gate before a new run. non recursive
103 | void _reset_non_recursive(void) const;
104 |
105 | };
106 |
107 | class CRunInputs : public std::vector
108 | {
109 | friend Circuit;
110 |
111 | protected:
112 | // map for inoput correspondance
113 | InputsMap correspondance_inputs = nullptr;
114 |
115 | private:
116 | // construstor, for Circuit ad gate_If only
117 | CRunInputs(void) {};
118 | // init inpute
119 | void init(int nb_bit, InputsMap _inputs) {
120 | // init the vector
121 | for (int i = 0; i < nb_bit; i++)
122 | this->push_back(Bit());
123 | correspondance_inputs = _inputs;
124 | }
125 |
126 | public:
127 | // init the value of a variable
128 | void set_varaible_value(std::string name, std::string value);
129 |
130 | // set a 1 bit value
131 | void set_bit_value(int numvar, bool b) {
132 | assert(numvar < (int)this->size());
133 | // set the value
134 | (*this)[numvar].set_value(b);
135 | }
136 | // set the value of a 8 bit var
137 | void set_int8_value(int numvar, std::vector bits) {
138 | assert(numvar * 8 < (int)this->size());
139 | assert(bits.size() == 8);
140 | // set 8 bits of the value
141 | for (int i = 0; i < 8; i++) {
142 | set_bit_value(numvar * 8 + i, bits[i]);
143 | }
144 | }
145 | // set the value of a 32 bit var
146 | void set_int32_value(int numvar, std::vector bits) {
147 | assert(numvar * 8 < (int)this->size());
148 | assert(bits.size() == 32);
149 | // set 8 bitsd of the value
150 | for (int i = 0; i < 32; i++) {
151 | set_bit_value(numvar * 32 + i, bits[i]);
152 | }
153 | }
154 | // set the value of a 64 bit var
155 | void set_int64_value(int numvar, std::vector bits) {
156 | assert(numvar * 8 < (int)this->size());
157 | assert(bits.size() == 64);
158 | // set 8 bitsd of the value
159 | for (int i = 0; i < 64; i++) {
160 | set_bit_value(numvar * 64 + i, bits[i]);
161 | }
162 | }
163 | // set the value of a 256 bit var
164 | void set_int256_value(int numvar, std::vector bits) {
165 | assert(numvar * 8 < (int)this->size());
166 | assert(bits.size() == 256);
167 | // set 8 bitsd of the value
168 | for (int i = 0; i < 256; i++) {
169 | set_bit_value(numvar * 256 + i, bits[i]);
170 | }
171 | }
172 | };
173 |
--------------------------------------------------------------------------------
/src/CodeBloc.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "CodeBloc.h"
3 | #include "Program.h"
4 | #include "Error.h"
5 | #include "Circuit.h"
6 |
7 |
8 | // get the return statement of the bloc
9 | Statement_Return* CodeBloc::get_return_statement(void) const {
10 | if (statements.size() == 0)
11 | return nullptr;
12 | // always last in bloc
13 | Statement* last_statement = statements.back();
14 | return last_statement->cast_to_Statement_Return();
15 | }
16 |
17 | // init a bloc
18 | void CodeBloc::init(Scope& scope) {
19 | init_ex(scope, InitOption::return_must_be_present);
20 | }
21 | // init a bloc, extentend version used in "for" statement
22 | void CodeBloc::init_ex(Scope& parent_scp, InitOption option) {
23 | // init parent function in the scope
24 | init_CodeBloc(parent_scp);
25 |
26 | // reoorganize the bloc in case of "If"
27 | //_reorganize_bloc_if_statement();
28 |
29 | // init statemtents
30 | for (Statement* statement_i : statements) {
31 | try {
32 | statement_i->init(*this);
33 | }
34 | catch (Error& e) {
35 | // add the line number
36 |
37 | e.line_number = statement_i->num_line;
38 | throw e;
39 | }
40 | }
41 |
42 | // check statements :
43 | if (statements.size() == 0)
44 | throw Error("Empty function");
45 |
46 | // if return (or break) is optionnal
47 | if (option == InitOption::return_not_required)
48 | return;
49 |
50 | Statement* last_statement = statements.back();
51 | // if last statement can be a break and iti is a break
52 | if (option == InitOption::return_or_break_must_be_present
53 | && last_statement->cast_to_Statement_Break() != nullptr)
54 | return; //OK
55 |
56 | // last statement must be a return or if
57 | if ( last_statement->cast_to_Statement_Return() == nullptr
58 | && last_statement->cast_to_Statement_If() == nullptr)
59 | throw Error("Last statement must be a return");
60 |
61 |
62 | }
63 |
64 | // reoorganize the bloc in case of "If"
65 | void CodeBloc::_reorganize_bloc_if_statement(void) {
66 |
67 | // build the statements before "return"
68 | for (int i = 0; i < statements.size() - 1; i++) {
69 | Statement* statement = statements[i];
70 | // if it is a if
71 | Statement_If* if_statement = statement->cast_to_Statement_If();
72 | if (if_statement != nullptr)
73 | {
74 | // get the bloc after the if : else statement
75 | CodeBloc* bloc_after_if = new CodeBloc();
76 | // add the bloc after the if
77 | for (int k = i + 1; k < statements.size(); k++)
78 | bloc_after_if->statements.push_back(statements[k]);
79 | // remove bloc after the if
80 | statements.erase(statements.begin() + i + 1, statements.end());
81 | // set the else bloc
82 | if_statement->setElseBloc(bloc_after_if);
83 | // no more statements
84 | return;
85 | }
86 |
87 | }
88 | }
89 | // visit all part used in the bloc
90 | void CodeBloc::visit_all_epressions(IVisitExpression& visitor)
91 | {
92 | for (Statement* statement_i : statements) {
93 | // visit expressions in the statement
94 | statement_i->visit_Expression([&](Expression& expression) {
95 | // visi expression
96 | expression.visit_epression(visitor);
97 | });
98 | }//for
99 | }
100 | // visit part used in the bloc, fram a given statement
101 | void CodeBloc::visit_all_epressions_from(IVisitExpression& visitor, int statement_index)
102 | {
103 | for (int i = statement_index; i < statements.size(); i++) {
104 | Statement* statement_i = statements[i];
105 | // visit expressions in the statement
106 | statement_i->visit_Expression([&](Expression& expression) {
107 | // visi expression
108 | expression.visit_epression(visitor);
109 | });
110 | }//for
111 |
112 | }
113 |
114 | // visit all expression used in all the statement
115 | void CodeBloc::visit_Expression(std::function visitor) const {
116 |
117 | for (Statement* statement_i : statements) {
118 | // visit expressions in the statement
119 | statement_i->visit_Expression(visitor);
120 | }//for
121 |
122 | }
123 |
124 | // build a circuit that represents the bloc
125 | BuildContext::NextAction CodeBloc::build_circuit(BuildContext& ctx) {
126 | // buidl form the first statement
127 | return _build_circuit_from(ctx,0);
128 | }
129 |
130 |
131 | // build a circuit that represents the bloc, from a statement index
132 | BuildContext::NextAction CodeBloc::_build_circuit_from(BuildContext& ctx, int first_statement_index) {
133 |
134 |
135 | // build the statements
136 | for (int i = first_statement_index; i < statements.size(); i++) {
137 | Statement* statement = statements[i];
138 | try {
139 |
140 | // action in case of if to bluild the circuit from a new position
141 | BuildContext ctx_internal(ctx, BuildContext::Caller::build_next_lambda);
142 | ctx_internal.debug_description = "statement " + std::to_string(i) + " / line " + std::to_string(statement->num_line);
143 | BuildContext* pctx_caller = &ctx;
144 | ctx_internal.build_all_next_statements = [this, pctx_caller, i](BuildContext& context_param) {
145 | auto action = _build_circuit_from(context_param, i + 1);
146 | if (action == BuildContext::NextAction::Return)
147 | return action;
148 | if (action == BuildContext::NextAction::Break)
149 | return pctx_caller->build_on_break(context_param);
150 | assert(pctx_caller->build_all_next_statements != nullptr);
151 | auto sub_action = pctx_caller->build_all_next_statements(context_param);
152 | return sub_action;
153 | };
154 | ctx_internal.build_on_break = ctx.build_on_break;
155 | ctx_internal.circuit().debug_info.source_line = statement->num_line;
156 | ctx_internal.circuit().debug_info.description = "statement";
157 |
158 | BuildContext::NextAction action =statement->build_circuit(ctx_internal);
159 |
160 | switch (action)
161 | {
162 | case BuildContext::NextAction::Continue: // proceed to next statement
163 | break;
164 | case BuildContext::NextAction::Break:
165 | //we should be in a from loop
166 | assert(ctx.is_in_for_loop());
167 | return BuildContext::NextAction::Break;
168 | case BuildContext::NextAction::Return:
169 | // nothing more to do
170 | return BuildContext::NextAction::Return;
171 | default:
172 | assert(false);
173 | break;
174 | }
175 |
176 | }
177 | catch (Error& e) {
178 | //add info to the error
179 | e.line_number = statement->num_line;
180 | throw e;
181 | }
182 | }
183 | return BuildContext::NextAction::Continue;
184 | }
185 |
--------------------------------------------------------------------------------
/src/CodeBloc.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "Scope.h"
5 | #include "Statement.h"
6 |
7 | class Function;
8 | class BuildContext;
9 | class Expression;
10 | class Expression_Variable;
11 | class IVisitExpression;
12 |
13 | class CodeBloc : public Scope {
14 | public:
15 | // code statements
16 | std::vector statements;
17 |
18 | public:
19 | // constructors
20 | CodeBloc(void) {} // code reorg for if statement
21 | CodeBloc(Statement* first_statement) { statements.push_back(first_statement); } // parsing
22 | // add a statement
23 | void add_statement(Statement* s) { statements.push_back(s); }
24 | // init a bloc
25 | void init( Scope& global_scope);
26 | // init a bloc, extentend version used in "for" statement
27 | enum class InitOption { return_must_be_present, return_or_break_must_be_present, return_not_required };
28 | void init_ex(Scope& global_scope, InitOption option);
29 | // build a circuit that represents the bloc
30 | BuildContext::NextAction build_circuit(BuildContext& ctx);
31 | // get the return statement of the bloc
32 | class Statement_Return* get_return_statement(void) const;
33 | // visit all part used in the bloc
34 | void visit_all_epressions(IVisitExpression& visitor);
35 | // visit part used in the bloc, fram a given statement
36 | void visit_all_epressions_from(IVisitExpression& visitor, int statement_index);
37 | // visit all expression used in all the statement
38 | void visit_Expression(std::function visitor) const;
39 |
40 | protected:
41 | // build a circuit that represents the bloc, from a statement index
42 | BuildContext::NextAction _build_circuit_from(BuildContext& ctx, int first_statement_index);
43 | // reoorganize the bloc in case of "If"
44 | void _reorganize_bloc_if_statement(void);
45 | };
--------------------------------------------------------------------------------
/src/Compiler.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitrebitcoin/bitcoin-bitvm-compiler/03e3939492b925f1a9d28a05442a77817118b276/src/Compiler.cpp
--------------------------------------------------------------------------------
/src/Compiler.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitrebitcoin/bitcoin-bitvm-compiler/03e3939492b925f1a9d28a05442a77817118b276/src/Compiler.h
--------------------------------------------------------------------------------
/src/CompositedGate.cpp:
--------------------------------------------------------------------------------
1 | // Gates.cpp
2 | // Implemnetaions of the composoiteds gates logic
3 | //@TODO: Optim, set a a TapRoopScrip
4 |
5 | #include "Gate.h"
6 | #include "Circuit.h"
7 |
8 |
9 | // add a NOT gate into the
10 |
11 | std::array Gate_NOT::add_to_circuit(Circuit& circuit, std::array& _inputs) {
12 | // implemented with a nand gate
13 | Gate_NAND* _nand = new Gate_NAND();
14 | std::array inputs2 = { _inputs[0], _inputs[0] };
15 | return _nand->add_to_circuit(circuit, inputs2);
16 | };
17 |
18 | // compute the output of the AND gate
19 | std::array Gate_AND::add_to_circuit(Circuit& circuit, std::array& _inputs) {
20 | // implemented with a nand + not
21 | Gate_NAND* _nand = new Gate_NAND();
22 | Gate_NAND* _nand_not = new Gate_NAND();
23 | std::array output_gate1 = _nand->add_to_circuit(circuit, _inputs);
24 | std::array output_gate2 = { output_gate1[0], output_gate1[0] };
25 | return _nand_not->add_to_circuit(circuit, output_gate2);
26 | };
27 |
28 | // compute the output of the OR gate
29 | std::array Gate_OR::add_to_circuit(Circuit& circuit, std::array& _inputs)
30 | {
31 | // implemented with r = not(a) nand not(b)
32 | Gate_NAND* _nand_a = new Gate_NAND();
33 | Gate_NAND* _nand_b = new Gate_NAND();
34 | Gate_NAND* _nand_r = new Gate_NAND();
35 | std::array inputs_a = { _inputs[0], _inputs[0] };
36 | std::array inputs_b = { _inputs[1], _inputs[1] };
37 | std::array not_a = _nand_a->add_to_circuit(circuit, inputs_a);
38 | std::array not_b = _nand_b->add_to_circuit(circuit, inputs_b);
39 | std::array not_ab = { not_a[0], not_b[0] };
40 | return _nand_r->add_to_circuit(circuit, not_ab);
41 |
42 | }
43 |
44 | // compute the output of the XOR gate
45 | std::array Gate_XOR::add_to_circuit(Circuit& circuit, std::array& _inputs)
46 | {
47 | // implemented with 4 nand gates
48 | Gate_NAND* _nand_1 = new Gate_NAND();
49 | Gate_NAND* _nand_2 = new Gate_NAND();
50 | Gate_NAND* _nand_3 = new Gate_NAND();
51 | Gate_NAND* _nand_4 = new Gate_NAND();
52 | // nand(a, b)
53 | std::array inputs_1 = { _inputs[0], _inputs[1] };
54 | std::array nand_ab = _nand_1->add_to_circuit(circuit, inputs_1);
55 | // nand(a, nand(a, b))
56 | std::array inputs_2 = { _inputs[0], nand_ab[0] };
57 | std::array nand_a_nand_ab = _nand_2->add_to_circuit(circuit, inputs_2);
58 | // nand(b, nand(a, b))
59 | std::array inputs_3 = { _inputs[1], nand_ab[0] };
60 | std::array nand_b_nand_ab = _nand_3->add_to_circuit(circuit, inputs_3);
61 | // result
62 | std::array inputs_4 = { nand_a_nand_ab[0], nand_b_nand_ab[0] };
63 | std::array xor_ab = _nand_4->add_to_circuit(circuit, inputs_4);
64 |
65 | return xor_ab;
66 |
67 | }
68 | // compute the output of the XNOR gate
69 | std::array Gate_XNOR::add_to_circuit(Circuit& circuit, std::array& _inputs)
70 | {
71 | // !(a xor b)
72 | std::array < Connection*, 1> xor_ab = Gate_XOR().add_to_circuit(circuit, _inputs);
73 | // !
74 | return Gate_NOT().add_to_circuit(circuit, xor_ab);
75 | }
76 | // (r,carry) = a + b
77 | // compute the output of the gate
78 | std::array Gate_ADD::add_to_circuit(Circuit& circuit, std::array& _inputs) {
79 |
80 | std::array _ab = { _inputs[0], _inputs[1] };
81 | std::array a_xor_b = Gate_XOR().add_to_circuit(circuit, _ab);
82 | std::array a_and_b = Gate_AND().add_to_circuit(circuit, _ab);
83 | // low = a xor b
84 | // carry = a and b
85 | return { a_xor_b[0], a_and_b[0] };
86 | }
87 |
88 | // full adder
89 | // (r,carry) = a + b + carry_in
90 | // compute the output of the gate
91 | std::array Gate_ADDC::add_to_circuit(Circuit& circuit, std::array& _inputs) {
92 | // easy implentation wirh 2 half adders and an or gate
93 | // source : https://www.geeksforgeeks.org/full-adder-in-digital-logic/
94 | std::array _ab = { _inputs[0], _inputs[1] };
95 | std::array add_ab = Gate_ADD().add_to_circuit(circuit, _ab);
96 | std::array _c_add_ab = { _inputs[2], add_ab[0] };
97 | std::array add_c_addab = Gate_ADD().add_to_circuit(circuit, _c_add_ab);
98 | // carry from the 2 addders
99 | std::array _2c = { add_ab[1], add_c_addab[1] };
100 | std::array c_out = Gate_OR().add_to_circuit(circuit, _2c);
101 |
102 | // low = a + b + c
103 | return { add_c_addab[0], c_out[0] };
104 | }
105 |
106 |
107 | // add the gate into the circuir
108 | std::array Gate_IF::add_to_circuit(Circuit& circuit, std::array& _input)
109 | {
110 | circuit.add_gate(this);
111 | set_inputs(_input);
112 | // no raal output
113 | std::array output_void = {};
114 | return output_void;
115 |
116 | }
117 |
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/src/CompositedGate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "IGate.h"
4 |
5 | // represent a gate implementd with other base gates. ex : a+b
6 | class CompositedGate : public IGate {
7 | public:
8 |
9 | };
10 | // template to build N/M composite gates
11 | template
12 | class T_CompositedGate : public T_NMGate< N, M, CompositedGate>
13 | {
14 | };
15 |
16 |
17 |
18 | class UnaryGate : public T_CompositedGate<1, 1> {};
19 | // r = !a
20 | class Gate_NOT : public UnaryGate
21 | {
22 | public:
23 | // compute the output of the NOT gate
24 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
25 | };
26 | class BinaryGate : public T_CompositedGate<2, 1> {};
27 | // r = a & b
28 | class Gate_AND : public BinaryGate
29 | {
30 | public:
31 | // compute the output of the AND gate
32 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
33 | };
34 | // r = a | b
35 | class Gate_OR : public BinaryGate
36 | {
37 | public:
38 | // compute the output of the OR gate
39 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
40 | };
41 | // r = a ^ b
42 | class Gate_XOR : public BinaryGate
43 | {
44 | public:
45 | // compute the output of the OR gate
46 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
47 | };
48 | // r = (a == b)
49 | class Gate_XNOR : public BinaryGate
50 | {
51 | public:
52 | // compute the output of the OR gate
53 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
54 | };
55 |
56 | // (r,carry) = a + b
57 | class Gate_ADD : public T_CompositedGate<2, 2>
58 | {
59 | public:
60 | // compute the output of the OR gate
61 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
62 | };
63 | // full adder
64 | // (r,carry) = a + b + c
65 | class Gate_ADDC : public T_CompositedGate<3, 2>
66 | {
67 | public:
68 | // compute the output of the gate
69 | virtual std::array add_to_circuit(Circuit& circuit, std::array& _inputs) override;
70 | };
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/src/Connection.cpp:
--------------------------------------------------------------------------------
1 | // implementation of class Connection
2 |
3 | #include "Connection.h"
4 | #include "Gate.h"
5 |
6 | bool Connection::is_calculated(void) const {
7 | return bit_value != nullptr;
8 | }
9 | // get the value of the bit
10 | bool Connection::get_value(void) const {
11 | assert(bit_value != nullptr);
12 | return *bit_value;
13 | }
14 | // set the value of the bit
15 | void Connection::set_value(bool b) {
16 | assert(bit_value == nullptr);
17 | bit_value = new Bit();
18 | bit_value->set_value(b);
19 | }
20 | // rest the value of the bit for a new run
21 | void Connection::reset(void) {
22 | delete bit_value;
23 | bit_value = nullptr;
24 | }
--------------------------------------------------------------------------------
/src/Connection.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "Bits.h"
7 | class TapScriptGate;
8 |
9 |
10 | // represents a connection in the circuit betwen 2 gates
11 | class Connection {
12 | public:
13 | // description for debug purpose
14 | std::string debug_description;
15 | // gates that set the bit value
16 | TapScriptGate* gate_out = nullptr;
17 | // gates that use the bit value a their input
18 | std::vector tab_gate_in;
19 | // set if this is an output of the circuit
20 | bool is_output = false;
21 | // id of the connection, for export
22 | int id = 0;
23 | private:
24 | // value in the connexion, during calculation only
25 | Bit* bit_value = nullptr;
26 |
27 | public:
28 | bool is_calculated(void) const;
29 | // get the value of the bit
30 | bool get_value(void) const;
31 | // set the value of the bit
32 | void set_value(bool b);
33 | // rest the value of the bit for a new run
34 | void reset(void);
35 |
36 | };
37 |
--------------------------------------------------------------------------------
/src/Error.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | // compiler error
6 | class Error {
7 | public:
8 | std::string file_name;
9 | std::string function_name;
10 | int line_number = 0;
11 | // main error message
12 | std::string message;
13 | public:
14 | // constructor
15 | Error(void) {}
16 | Error(const char* mess) : message(mess) {}
17 | Error(const char* mess, std::string more_info) : message(mess) { message += ' ' + more_info; }
18 | Error(std::string mess, std::string more_info) : message(mess) { message += ' ' + more_info; }
19 |
20 | // format the error message
21 | std::string toString(void) const {
22 | std::string res;
23 | if (function_name != "")
24 | res += function_name + "() :\n";
25 | if (file_name != "")
26 | res += file_name + "(" + std::to_string(line_number+1) + ") : " + message;
27 | else
28 | res += message;
29 | return res;
30 | }
31 | };
--------------------------------------------------------------------------------
/src/Expression.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Expression.h"
3 | #include "Literal.h"
4 |
5 | //change the type of all litteral to a give type in the expression
6 | // for the "int64 i = 0" case
7 | void Expression::change_all_litterals_type(const Type& new_type) {
8 |
9 | class Visitor : public IVisitExpression {
10 | protected:
11 | // Closure
12 | const Type& new_type;
13 | public:
14 | // constructor
15 | Visitor(const Type& t) : new_type(t) {}
16 | // -- IVisitExpression implemebtatoin
17 | // epxression part is a literal.ex : 123
18 | virtual void onLiteral(Literal& litteral) override {
19 | // check the type
20 | if (litteral.get_type().is_same_type(new_type))
21 | return; // nothing to do
22 | // change the litteral type
23 | litteral.change_type(new_type);
24 | }
25 | // expressison part is a varible. ex : a
26 | virtual void onVariable(Expression_Variable&) override {};
27 | // expressison part is a varible in a struct. ex : a.b
28 | virtual void onVariableInStruct(Expression_StructMember&) override {};
29 | // expressison part is a varible in a struct. ex : a.b
30 | virtual void onArrayElement(Expression_ArrayElement&) override {};
31 |
32 | };
33 | Visitor visitor(new_type);
34 | // visit all part used in the Expression
35 | visit_epression(visitor);
36 |
37 |
38 | }
--------------------------------------------------------------------------------
/src/Expression.h:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitrebitcoin/bitcoin-bitvm-compiler/03e3939492b925f1a9d28a05442a77817118b276/src/Expression.h
--------------------------------------------------------------------------------
/src/Expression_ArrayElement.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Expression_ArrayElement.h"
3 | #include "Error.h"
4 | #include "Scope.h"
5 | #include "TypeArray.h"
6 | #include "Literal.h"
7 | #include "Expression_Variable.h"
8 | #include "CompositedGate.h"
9 | #include "TestOperation.h"
10 |
11 | // constructor
12 | Expression_ArrayElement::Expression_ArrayElement(std::string name, Expression* index_)
13 | : array_name(name)
14 | , index(index_) {
15 | assert(index != nullptr);
16 | }
17 |
18 | // get element type
19 | const Type& Expression_ArrayElement::get_type(void) const {
20 | if (element_type == nullptr) {
21 | // error :type not yet set
22 | throw Error("Internal error, array type non resolded");
23 | }
24 | return *element_type;
25 | }
26 |
27 | // visit all part used in the Expression
28 | void Expression_ArrayElement::visit_epression(IVisitExpression& visitor)
29 | {
30 | visitor.onArrayElement(*this);
31 | }
32 |
33 | // init
34 | void Expression_ArrayElement::init(Scope& parent_scope) {
35 |
36 | // init index operand
37 | index->init(parent_scope);
38 |
39 | // get the array type from name
40 | const VariableDefinition* parent_definition = parent_scope.find_variable_by_name(array_name);
41 | if (parent_definition == nullptr) {
42 | // error : 'name' not found
43 | throw Error("identifier not found :", array_name);
44 | }
45 | // must be a an arrau
46 | assert(parent_definition->type != nullptr);
47 | assert(parent_definition->type->is_complete());
48 | const TypeArray* parent_type_array = parent_definition->type->cast_to_TypeArray();
49 | if (parent_type_array == nullptr) {
50 | // error : parent is not an array
51 | throw Error("not an array : ", array_name);
52 | }
53 | assert(parent_type_array->element_type != nullptr);
54 |
55 | // keep the type
56 | element_type = parent_type_array->element_type;
57 | }
58 |
59 | // get the array size = number of elements
60 | int Expression_ArrayElement::get_array_size(const ScopeVariable& var_array) const {
61 | // divide the number of bits in the arrya by the size of the element
62 | int element_size = element_type->size_in_bit();
63 | IndexType array_size = (IndexType)(var_array.bits.size() / element_size);
64 | return array_size;
65 |
66 | }
67 |
68 | // build the circuit for the expression for a int index value
69 | std::vector Expression_ArrayElement::build_circuit_for_int_index(BuildContext& ctx, const ScopeVariable& var_array, IndexType index_value) {
70 | assert(element_type != nullptr);
71 | int element_size = element_type->size_in_bit();
72 |
73 | // check index value
74 | IndexType array_size = get_array_size(var_array); // (int)var_array.bits.size() / element_size;
75 | if (index_value < 0 || index_value >= array_size)
76 | throw Error("Array index out of range : ", std::to_string(index_value));
77 |
78 | // get offest in bits in the array
79 | int offset_in_bit = element_size * index_value;
80 | auto begin_member = var_array.bits.begin() + offset_in_bit;
81 | // get the bits of the element
82 | std::vector < Connection*> bits_member(begin_member, begin_member + element_size);
83 | assert(bits_member.size() == element_type->size_in_bit());
84 | return bits_member;
85 | }
86 |
87 |
88 | // build the circuit for the expression
89 | std::vector Expression_ArrayElement::build_circuit(BuildContext& ctx) {
90 | // get the parent variable type by name
91 | ScopeVariable* var_array = ctx.variables().find_by_name(array_name);
92 | if (var_array == nullptr)
93 | throw Error("Unknonwn variable : ", array_name);
94 | // if variable not set
95 | if (!var_array->is_set())
96 | throw Error("Uninitialized variable : ", array_name);
97 |
98 | //1. literal value as index. ex : a[3]
99 | Literal* index_literal = index->cast_to_literal();
100 | if (index_literal != nullptr) {
101 | // set outputs to get the value of the part of variable in the struct
102 | return build_circuit_for_int_index(ctx, *var_array, index_literal->get_int_value());
103 | }
104 |
105 | //2. expression as index. ex : a[b+1]
106 |
107 |
108 | //2.1 : simmple var, ex : a[i]
109 | Expression_Variable* index_var = index->cast_to_Expression_Variable();
110 | if (index_var != nullptr)
111 | {
112 | // get the variable type by name
113 | ScopeVariable* var = ctx.variables().find_by_name(index_var->name);
114 | ScopeVariable::STValInt val_int = var->get_int_value();
115 | if (val_int.is_set) {
116 | return build_circuit_for_int_index(ctx, *var_array, val_int.value );
117 | }
118 | }
119 |
120 | //2.1 : complex expression, ex : a[i*j+1]
121 |
122 | //TODO
123 |
124 | // generate an expression like this :
125 | // (a[0] & (I==0))
126 | // | (a[1] & (I==1))
127 | // | (a[2] & (I==2))
128 | // ...
129 | // = a[i]
130 | // generte index circuit from its expression
131 | std::vector index_expression = index->build_circuit(ctx);
132 |
133 | std::vector result;
134 | // (a[i] xor (a[i] & (Index == 0)))
135 | IndexType array_size = get_array_size(*var_array);
136 | assert(array_size > 0);
137 | result = generate_expression_for_index( ctx, *var_array, index_expression, 0);
138 | for (IndexType index_to_test = 1; index_to_test < array_size; index_to_test++) {
139 | // (a[i] xor (a[i] & (Index==i))) ...
140 | std::vector next = generate_expression_for_index(ctx, *var_array, index_expression, index_to_test);
141 | // mix input : a = a | b
142 | result = generate_or(ctx, result, next);
143 | }
144 | // final result :
145 | return result;
146 | }
147 |
148 | // return (a | b) addeded to the circuit
149 | std::vector Expression_ArrayElement::generate_or(BuildContext& ctx, const std::vector& a, const std::vector& b) {
150 | assert(a.size() == b.size());
151 | std::vector result;
152 |
153 | Gate_OR gate_or;
154 |
155 | // for each bit connect gate input and output
156 | int size = (int)a.size();
157 | for (int i = 0; i < size; i++) {
158 | // IN
159 | std::array input_2_bit = { a[i], b[i] };
160 | // OUT = A OP B
161 | std::array bits_result = gate_or.add_to_circuit(ctx.circuit(), input_2_bit);
162 |
163 | //result.insert(result.end(), bits_result.begin(), bits_result.end());
164 | result.push_back(bits_result[0]);
165 |
166 | }
167 | return result;
168 |
169 | }
170 | // generate the expression a[index] & (expression==index)
171 | // the circuite will return a[index] if expression == index , 0 otherwise
172 | std::vector Expression_ArrayElement::generate_expression_for_index(BuildContext& ctx, const ScopeVariable& var_array, std::vector expression, IndexType index_value)
173 | {
174 | // gate for buildinf
175 | Gate_AND gate_and;
176 |
177 | // get a[index]
178 | std::vector a_at_index = build_circuit_for_int_index(ctx, var_array, index_value);
179 |
180 | // (expression==index] ?
181 | // get a type with the number of bits of the index
182 | TypeBasic type_exp = TypeBasic::get_TypeBasic_for_bitsize((int)expression.size());
183 | Literal index_as_literal(type_exp, std::to_string(index_value) );
184 | Scope* no_scope = nullptr;
185 | index_as_literal.init(*no_scope);
186 | std::vector index_as_connexions = index_as_literal.build_circuit(ctx);
187 | std::vector exp_eq_i = TestOperation::build_circuit_equal(ctx, expression, index_as_connexions);
188 |
189 | // a[index] & (expression==index)
190 | std::vector result;
191 | int size = (int)a_at_index.size();
192 | for (int i = 0; i < size; i++) {
193 | // IN : each bit of a[index] and same bit b = (expression==index)
194 | std::array input_2_bit = { a_at_index[i], exp_eq_i[0] };
195 |
196 | std::array bits_result = gate_and.add_to_circuit(ctx.circuit(), input_2_bit);
197 | result.push_back(bits_result[0]);
198 | }
199 |
200 | return result;
201 |
202 |
203 |
204 | }
205 |
206 |
--------------------------------------------------------------------------------
/src/Expression_ArrayElement.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "Expression.h"
5 | #include "BuildContext.h"
6 |
7 | // expression of the form "my_array[3]"
8 |
9 | using IndexType = int;
10 |
11 | class Expression_ArrayElement : public Expression {
12 | public:
13 | std::string array_name; // ex : "my_array"
14 | Expression* index = nullptr; // index in the array
15 |
16 | const Type* element_type = nullptr; // type the element
17 | int member_offest_in_bit = 0; // offset in bit of the member
18 |
19 | public:
20 | // constructor
21 | Expression_ArrayElement(std::string array_name, Expression* index);
22 |
23 | // get expression type
24 | virtual const Type& get_type(void) const override;
25 | // visit all part used in the Expression
26 | virtual void visit_epression(IVisitExpression& visitor) override;
27 | // init
28 | virtual void init(Scope& parent_scope) override;
29 |
30 | // build the circuit for the expression
31 | virtual std::vector build_circuit(BuildContext& ctx) override;
32 |
33 | protected:
34 | // get the array size = number of elements
35 | IndexType get_array_size(const ScopeVariable& var_array) const;
36 | // build the circuit for the expression for a int index value
37 | std::vector build_circuit_for_int_index(BuildContext& ctx, const ScopeVariable& var_array, IndexType index_value);
38 | // return (a & b) addeded to the circuit
39 | std::vector generate_or(BuildContext& ctx, const std::vector& a, const std::vector& b);
40 | // generate a circuite that will return a[index] if expression == index , 0 otherwise
41 | std::vector generate_expression_for_index(BuildContext& ctx, const ScopeVariable& var_array, std::vector expression, IndexType index_value);
42 | };
--------------------------------------------------------------------------------
/src/Expression_StructMember.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "Program.h"
3 | #include "Expression_StructMember.h"
4 | #include "Error.h"
5 | #include "Scope.h"
6 |
7 | // constructor
8 | Expression_StructMember::Expression_StructMember(std::string p, std::string m)
9 | : parent_name(p), member_name(m)
10 | {}
11 |
12 |
13 |
14 | // get expression type
15 | const Type& Expression_StructMember::get_type(void) const {
16 | if (member_type == nullptr) {
17 | // error :type not yet set
18 | throw Error("Internal error, member type non resolded", member_name);
19 | }
20 | return *member_type;
21 | }
22 | // init
23 | void Expression_StructMember::init(Scope& parent_scope) {
24 | // get the struct parent from name
25 | const VariableDefinition *parent_definition = parent_scope.find_variable_by_name(parent_name);
26 | if (parent_definition == nullptr) {
27 | // error : 'name' not found
28 | throw Error("identifier not found :", parent_name);
29 | }
30 | // must be a struct
31 | assert(parent_definition->type != nullptr);
32 | assert(parent_definition->type->is_complete());
33 | const TypeStruct* parent_type_struct = parent_definition->type->cast_to_TypeStruct();
34 | if (parent_type_struct == nullptr) {
35 | // error : parent is not a structure
36 | throw Error("not a structure : ", parent_name);
37 | }
38 |
39 | // get the member type by name
40 | TypeStruct::Member member = parent_type_struct->get_member_by_name(member_name);
41 | if (!member.is_valid) {
42 | // error : member not found
43 | throw Error("member not found : ", member_name);
44 | }
45 | // keep the type and the offset
46 | member_type = member.type;
47 | member_offest_in_bit = member.offest_in_bit;
48 | }
49 |
50 | // get all gates used by the parent struct variable
51 | std::vector Expression_StructMember::get_all_connexions_full_struct(BuildContext& ctx) const {
52 | // get the parent variable type by name
53 | ScopeVariable* var = ctx.variables().find_by_name(parent_name);
54 | if (var == nullptr)
55 | return {};
56 | // if variable not set
57 | if (!var->is_set())
58 | return {};
59 | // return all the bits of the variable
60 | return var->bits;
61 | }
62 |
63 |
64 | // build the circuit for the expression
65 | std::vector Expression_StructMember::build_circuit(BuildContext& ctx) {
66 | // get the parent variable type by name
67 | ScopeVariable* var = ctx.variables().find_by_name(parent_name);
68 | if (var == nullptr)
69 | throw Error("Unknonwn variable : ", parent_name);
70 | // if variable not set
71 | if (!var->is_set())
72 | throw Error("Uninitialized variable : ", parent_name);
73 |
74 | // set outputs to get the value of the part of variable in the struct
75 | assert(member_type != nullptr);
76 | int member_size = member_type->size_in_bit();
77 | auto begin_member = var->bits.begin() + member_offest_in_bit;
78 | std::vector < Connection*> bits_member(begin_member, begin_member + member_size);
79 | assert(bits_member.size() == member_type->size_in_bit());
80 | return bits_member;
81 |
82 | }
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/Expression_StructMember.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include "Expression.h"
5 | #include "BuildContext.h"
6 |
7 | // expression of the form "mystruct.member"
8 |
9 | class Expression_StructMember : public Expression {
10 | public:
11 | std::string parent_name; // ex : "mystruct"
12 | std::string member_name; // ex : "member"
13 |
14 | Type* member_type = nullptr; // type the var
15 | int member_offest_in_bit = 0; // offset in bit of the member in the struct
16 |
17 | public:
18 | // constructor
19 | Expression_StructMember(std::string parent_var, std::string member_name);
20 |
21 | // get expression type
22 | virtual const Type& get_type(void) const override;
23 | // visit all part used in the Expression
24 | virtual void visit_epression(IVisitExpression& visitor) override { visitor.onVariableInStruct(*this); }
25 | // init
26 | virtual void init(Scope& parent_scope) override;
27 | // get all gates used by the parent struct variable
28 | std::vector get_all_connexions_full_struct(BuildContext& ctx) const;
29 | // build the circuit for the expression
30 | virtual std::vector build_circuit(BuildContext& ctx) override;
31 | };
--------------------------------------------------------------------------------
/src/Expression_Variable.cpp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maitrebitcoin/bitcoin-bitvm-compiler/03e3939492b925f1a9d28a05442a77817118b276/src/Expression_Variable.cpp
--------------------------------------------------------------------------------
/src/Expression_Variable.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | class BuildContext;
4 |
5 |
6 | // a variable usage in an expression
7 | class Expression_Variable: public VariableDefinition, public Expression {
8 | public:
9 | // constructor
10 | Expression_Variable(std::string n) : VariableDefinition( (Type *)nullptr, n) {}
11 | // cast to Expression_Variable
12 | virtual Expression_Variable* cast_to_Expression_Variable(void) override { return this; }
13 | // get Operand type
14 | const Type& get_type(void) const { assert(type != nullptr); return *type; }
15 | // visit all part used in the Expression
16 | virtual void visit_epression(IVisitExpression& visitor) override { visitor.onVariable(*this); }
17 |
18 | // init, will grag the type from the symbol table
19 | virtual void init(Scope& parent_scope) override;
20 | // get all gates used by the variable
21 | std::vector get_all_connexions(BuildContext& ctx) const;
22 | // build the circuit for the expression
23 | virtual std::vector build_circuit(BuildContext& ctx) override;
24 | };
25 |
26 |
--------------------------------------------------------------------------------
/src/Function.cpp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #include