1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
//! # CipherCore
//!
//! If you have any questions, or, more generally, would like to discuss CipherCore, please [join the Slack community](https://join.slack.com/t/slack-r5s9809/shared_invite/zt-1901t4ec3-W4pk~nsTl2dY8Is5HFWT4w).
//!
//! # Table of contents
//! - [CipherCore](#ciphercore)
//! - [Table of contents](#table-of-contents)
//! - [Overview](#overview)
//!    - [What is CipherCore?](#what-is-ciphercore)
//!    - [What is Secure Computation?](#what-is-secure-computation)
//!    - [CipherCore and Intermediate Representation](#ciphercore-and-intermediate-representation)
//!    - [Bird's eye view of SMPC](#birds-eye-view-of-smpc)
//!       - [Secret sharing](#secret-sharing)
//!    - [High-level structure of CipherCore](#high-level-structure-of-ciphercore)
//!       - [What is CipherCore useful for](#what-is-ciphercore-useful-for)
//! - [System requirements, installation and licensing](#system-requirements-installation-and-licensing)
//! - [Quick start](#quick-start)
//!    - [Creating computation graph](#creating-computation-graph)
//!    - [Working with the graph using CLI tools](#working-with-the-graph-using-cli-tools)
//! - [Examples](#examples)
//!    - [Matrix multiplication](#matrix-multiplication)
//!    - [Millionaires' problem](#millionaires-problem)
//!    - [Minimum of an array](#minimum-of-an-array)
//!    - [Sort](#sort)
//! - [Graph creation and management](#graph-creation-and-management)
//!    - [Overview of CipherCore operations](#overview-of-ciphercore-operations)
//!       - [Data types](#data-types)
//!       - [Basic operations](#basic-operations)
//!       - [Custom operations](#custom-operations)
//! - [CLI Tools](#cli-tools)
//!    - [Compiler](#compiler)
//!    - [Evaluator](#evaluator)
//!       - [Secret-shared input](#secret-shared-input)
//!       - [Input format](#input-format)
//!    - [Visualization](#visualization)
//!    - [Inspection](#inspection)
//!
//! # Overview
//!
//! ## What is CipherCore?
//!
//! CipherCore is a general purpose library for processing encrypted data.
//! It’s a state-of-the-art platform for building customized applications that can run directly over encrypted data without decrypting it first.
//! CipherCore can be used to run tasks on multiple distributed datasets owned by multiple organizations within the same enterprise or even different enterprises without disclosing the data to other parties.
//! The library is based on a technology called secure computation.
//!
//! ## What is Secure Computation?
//!
//! Secure Multi-Party Computation (SMPC) is a cutting-edge subfield of cryptography that provides various types of protocols allowing the execution of certain programs over encrypted data ([read more](https://en.wikipedia.org/wiki/Secure_multi-party_computation)).
//! SMPC protocols take as input a restricted form of computation called [circuit representation](https://en.wikipedia.org/wiki/Boolean_circuit).
//! Translating high-level programs into circuit representation is a complicated, error-prone and time-consuming process.
//! CipherCore compiler drastically simplifies the process by automatically translating and compiling high-level programs directly into the SMPC protocols, thus, allowing any software developer to use secure computation without requiring any knowledge of cryptography.
//!
//! ## CipherCore and Intermediate Representation
//!
//! CipherCore’s ease of use is due to introducing a new intermediate representation layer of _computation graphs_ between the application layer and the protocol layer.
//! Applications are mapped to a computation graph first and then to an SMPC protocol.
//! This architecture allows for rapid integration of various SMPC protocols as new cryptographic backends.
//! If you are familiar with ML frameworks such as [PyTorch](https://pytorch.org/), [TensorFlow](https://www.tensorflow.org/) or [JAX](https://github.com/google/jax) (or [MLIR](https://mlir.llvm.org/) on a lower level), then you likely know what computation graphs are.
//!
//! ![CipherCore architecture](https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/ciphercore_architecture.png)
//!
//! ## Bird's eye view of SMPC
//!
//! At a high level, Secure Multi-Party Computation protocols (SMPC) allow, given a program with several inputs belonging to several parties, execute it in a way such that:
//! * The output gets revealed only to a desired set of the parties;
//! * No party learns anything about inputs belonging to other parties other than what can be inferred from the revealed outputs.
//!
//! The literature on SMPC is vast and we refer the reader to a [comprehensive overview](https://github.com/rdragos/awesome-mpc) of the existing protocols. Typically, there is a three-way trade-off between:
//! * Efficiency
//! * Number of parties
//! * Threat model
//!
//! CipherCore is designed in a way that allows most existing SMPC protocols to be readily plugged as a backend.
//! Currently, we support [the ABY3 SMPC protocol](https://eprint.iacr.org/2018/403.pdf), which works for three parties and is one of the most efficient available protocols.
//!
//! ### Secret sharing
//!
//! Often, typically as a part of a larger computation, we need to run SMPC protocol on *secret* inputs that no single party is supposed to know. This can be achieved using a technique called *secret sharing*.
//!
//! The ABY3 protocol uses *replicated secret sharing*.
//! Specifically, a secret value `v` is presented in the form of a triple `(v_0, v_1, v_2)` such that `v = v_0 + v_1 + v_2` and each party has only two components of this triple, namely:
//! * Party 0 holds `(v_0, v_1)`,
//! * Party 1 holds `(v_1, v_2)`,
//! * Party 2 holds `(v_2, v_0)`.
//!
//! Each pair individually is fully random and carries no information about `v`, but, if brought together, the triple allows to recover the secret value.
//!
//! Public values are not secret shared, i.e., each party has a copy of a public value locally. Also, if we want to keep the result of the computation, then it can be maintained in the above secret shared form.
//!
//! ## High-level structure of CipherCore
//!
//! There are four natural stages when working with CipherCore:
//! 1. Formulate a computation one wishes to run securely as a computation graph using graph building API;
//! 2. **Compile** the graph into a new, typically larger, computation graph that corresponds to an SMPC protocol that performs the same computation but, at the same time, preserves the privacy of inputs and outputs. This step can be done using the CipherCore **compiler** that is part of the repository. Currently, we only support the ABY3 SMPC protocol for three non-colluding parties, but this will likely change in the future.
//! 3. Check that the resulting secure protocol works correctly. This can be done by running it on sample inputs using a **local evaluator**. This repository contains a reference implementation of an evaluator, which is simple, but not efficient. We also provide access to a Docker image that contains a binary of a **fast evaluator**, which is typically several orders of magnitude more efficient. The performance of the fast evaluator is a strong predictor (modulo network interactions) of actual end-to-end secure protocol execution done by three distributed parties;
//! 4. Execute the secure protocol end-to-end by three actual distributed parties that interact over the network. This can be done using the CipherCore **runtime**. We provide the trial access to the runtime on request. (see [here](#system-requirements-installation-and-licensing) for details)
//!
//! ### What is CipherCore useful for
//!
//! For an overview of instructions supported by CipherCore, see [here](#overview-of-ciphercore-operations).
//!
//! At a high level, CipherCore operations are designed to support most of the popular machine learning (ML training and inference) and analytics (e.g., [private set intersection](https://en.wikipedia.org/wiki/Private_set_intersection) and, more generally, joins) workloads.
//!
//! Going further, we plan to release **SecureAI**, which transforms popular ONNX graphs obtained from ML models into CipherCore graphs, which are in turn amenable to the SMPC compilation.
//!
//! # System requirements, installation and licensing
//!
//! CipherCore consists of three major parts:
//! * API for building and working with computation graphs;
//! * CLI tools that include the compiler and the evaluator;
//! * The Runtime that executes compiled computation graphs of secure protocols between several distributed parties.
//!
//! This crate can be used both as dependencies within your Rust projects and as a way to install the CLI tools.
//! For the former, add `ciphercore-base` to the dependencies of your Rust project, for the latter, run `cargo install ciphercore-base`.
//! We support most Linux and macOS systems (as well as Windows via WSL) with an Intel CPU.
//! For the crates to build, we require a system-wide install of [OpenSSL](https://www.openssl.org/) discoverable by the Rust [`openssl` crate](https://docs.rs/openssl/latest/openssl/) (the latter typically means the availability of [pkg-config](https://en.wikipedia.org/wiki/Pkg-config)).
//!
//! In addition, you can check out the Python package for the computation graph building API and the Docker image with pre-installed Python package and CLI tools including the *fast evaluator*, whose source code is *not* available in this repository.
//! More information about these parts of CipherCore can be found in [the CipherCore GitHub repo](https://github.com/ciphermodelabs/ciphercore).
//!
//! Everything provided in this repository is licensed under the [Apache 2.0 license](https://github.com/ciphermodelabs/ciphercore/blob/main/LICENSE.txt).
//!
//! If you download and run fast evaluator, you agree with the [CipherMode EULA](https://github.com/ciphermodelabs/EULA/blob/main/CipherMode%20Labs%20Inc.%20EULA%20(Version%2005-03-22).pdf).
//!
//! To request the trial access to the CipherCore Runtime, [e-mail us](mailto:ciphercore@ciphermode.tech).
//!
//! # Quick start
//!
//! Let us consider the following secure computation problem that involves three parties, which we denote by 0, 1, and 2.
//! Party 0 and party 1 each have a 5x5 square matrix with integer entries.
//! The parties would like to multiply these matrices and reveal the result to party 2 in a way that parties 0 and 1 learn nothing about each other's inputs, and party 2 learns nothing about the inputs other than their product.
//! Let us show how this problem can be solved using CipherCore.
//!
//! We need to start with creating a computation graph for the above problem.
//!
//! ## Creating computation graph
//!
//! We assume that you already have Rust and Cargo installed: please refer to the [Rust website](https://www.rust-lang.org/learn/get-started) for the installation instructions.
//!
//! First, let's create a new Rust project as follows: `cargo new private_matrix_multiplication`. Next, go to the project's directory: `cd private_matrix_multiplication`. Then, you need to add the crates `ciphercore-base` and `serde_json` as dependencies (we need the latter for serialization). In order to do this, please make the `Cargo.toml` file look like this:
//! ```toml
//! [package]
//! name = "private_matrix_multiplication"
//! version = "0.1.0"
//! edition = "2021"
//!
//! [dependencies]
//! ciphercore-base = "0.1.0"
//! serde_json = "1.0.81"
//! ```
//!
//! Now, replace the contents of `src/main.rs` with the following:
//!
//! ```no_run
//! use ciphercore_base::graphs::create_context;
//! use ciphercore_base::data_types::{array_type, INT64};
//! use ciphercore_base::errors::Result;
//!
//! fn main() {
//!     || -> Result<()> {
//!         // Create a context that hosts our computation graph.
//!         let context = create_context()?;
//!         // Create our graph within the context.
//!         let graph = context.create_graph()?;
//!         // Create two input nodes that correspond to 5x5
//!         // matrix with signed 64-bit integer entries.
//!         let a = graph.input(array_type(vec![5, 5], INT64))?;
//!         let b = graph.input(array_type(vec![5, 5], INT64))?;
//!         // Create a node that computes the product of `a`
//!         // and `b`.
//!         let c = a.matmul(b)?;
//!         // Declare `c` to be the final result
//!         // of computation.
//!         graph.set_output_node(c)?;
//!         // Freeze the graph thus declaring it to be final.
//!         graph.finalize()?;
//!         // Set `graph` as the main graph of the context.
//!         context.set_main_graph(graph)?;
//!         // Finalize the context.
//!         context.finalize()?;
//!         // Print the serialized context to stdout.
//!         println!("{}", serde_json::to_string(&context)?);
//!         Ok(())
//!     }().unwrap();
//! }
//! ```
//!
//! Next, let's build our project by running `cargo build --release`.
//! Finally, let us generate the graph and serialize it to the file `a.json` as follows: `./target/release/private_matrix_multiplication > a.json`.
//!
//! ## Working with the graph using CLI tools
//!
//! To work with the computation graph, we need to install CLI tools provided with CipherCore by running `cargo install ciphercore-base`.
//! This assumes you have Rust and Cargo installed: please refer to the [Rust website](https://www.rust-lang.org/learn/get-started) for the installation instructions.
//!
//! We can visualize the computation graph we just created as follows (this assumes that [GraphViz](https://graphviz.org/) is installed):
//! ```bash
//! ciphercore_visualize_context a.json | dot -Tsvg -o a.svg
//! ```
//!
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/tutorial_graph_plain.svg" alt="Plain Graph" width="30%"/>
//! </p>
//!
//! So far, nothing outstanding has happened. The graph simply has two input nodes that correspond to the input matrices, and the output node that corresponds to their produce.
//! Each node of the graph has a _type_ associated with it, which is depicted on the image.
//! These types are inferred automatically during the graph construction.
//!
//! Now let us compile the computation graph and turn it into a secure protocol. For this we run:
//! ```bash
//! ciphercore_compile a.json simple 0,1 2 > b.json
//! ```
//!
//! Here, the parameters `0,1 2` means that the inputs belong to the parties 0 and 1, respectively, and the output needs to be revealed only to the party 2.
//!
//! If we visualize the resulting computation graph of the secure protocol, we get the following:
//!
//! ```bash
//! ciphercore_visualize_context b.json | dot -Tsvg -o b.svg
//! ```
//!
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/tutorial_graph_mpc.svg" alt="MPC Graph" width="40%"/>
//! </p>
//!
//! As one can see, the compiled graph is much more complicated: in particular, it contains nodes that call a [cryptographic pseudo-random generator](https://en.wikipedia.org/wiki/Pseudorandom_generator), [cryptographic pseudo-random function](https://en.wikipedia.org/wiki/Pseudorandom_function_family) as well as nodes that correspond to network interactions between the parties.
//!
//! We can gather the statistics of the compiled graph as follows: `ciphercore_inspect b.json` and get the following:
//! ```bash
//! -------Stats--------
//! Inputs:
//!     1. Name:unnamed
//!     Type:i64[5, 5]
//!     2. Name:unnamed
//!     Type:i64[5, 5]
//! Output:
//!     Name:unnamed
//!     Type:i64[5, 5]
//! Network rounds: 4
//! Network traffic: 2.00KB
//! Total number of integer arithmetic operations:   2.84K Ops
//!     Total number of 1-bit arithmetic operations:   384 Ops
//!     Total number of 8-bit arithmetic operations:   0 Ops
//!     Total number of 16-bit arithmetic operations:  0 Ops
//!     Total number of 32-bit arithmetic operations:  0 Ops
//!     Total number of 64-bit arithmetic operations:  2.45K Ops
//! Total operations: 55
//! Operations:
//!     NOP           13
//!     Add           13
//!     Subtract      9
//!     PRF           9
//!     Matmul        6
//!     Random        3
//!     Input         2
//! ```
//! Let us note that the compiled graph has exactly the same matrix multiplication functionality as the original graph, but it gives a blueprint of the secure protocol.
//! That is, if three non-colluding parties faithfully execute the compiled graph using the CipherCore runtime, there will be no information leakage as desired.
//!
//! Note that the runtime is *not* included in this repository, but its trial version available upon request: [e-mail us](mailto:ciphercore@ciphermode.tech).
//!
//! Now let us execute the compiled graph locally, for the evaluation purposes.
//! Let us paste the following two 5x5 matrices that comprise input data to the file `inputs.json`:
//! ```json
//! [
//!     {"kind": "array",
//!      "type": "i64",
//!      "value": [[1, 2, 3, 4, 5],
//!                [6, 7, 8, 9, 10],
//!                [11, 12, 13, 14, 15],
//!                [16, 17, 18, 19, 20],
//!                [21, 22, 23, 24, 25]]},
//!     {"kind": "array",
//!      "type": "i64",
//!      "value": [[21, 22, 23, 24, 25],
//!                [26, 27, 28, 29, 30],
//!                [31, 32, 33, 34, 35],
//!                [36, 37, 38, 39, 40],
//!                [41, 42, 43, 44, 45]]}
//! ]
//! ```
//!
//! If we now run the compiled graph on these inputs as follows:
//! ```bash
//! ciphercore_evaluate b.json inputs.json
//! ```
//! we get the correct result:
//! ```json
//! {"kind": "array",
//!  "type": "i64",
//!  "value": [[515, 530, 545, 560, 575],
//!            [1290, 1330, 1370, 1410, 1450],
//!            [2065, 2130, 2195, 2260, 2325],
//!            [2840, 2930, 3020, 3110, 3200],
//!            [3615, 3730, 3845, 3960, 4075]]}
//! ```
//!
//! Instead of the reference evaluator, one can use the binary of a **fast evaluator** that we provide as a part of the CipherCore Docker image. See [this manual](https://github.com/ciphermodelabs/ciphercore/blob/main/reference/main.md#docker-image) for more details.
//! For the above toy example, the difference in the performance is negligible, but for more "serious" examples, it can be dramatic.
//!
//! This tutorial just scratches the surface what one can accomplish using CipherCore. For more, see the remainder of this document (e.g., [Examples](#examples)) as well as [CipherCore documentation](https://docs.rs/ciphercore-base/latest/ciphercore_base/).
//!
//! # Examples
//!
//! The repository contains several examples of how non-trivial algorithms can be created and executed within CipherCore.
//! These examples are structured in a similar way as the [Quick start](#quick-start) example and include:
//! * a documented Rust code creating a computation graph for a specific task (see the [applications](https://docs.rs/ciphercore-base/0.1.0/ciphercore_base/applications/index.html) module).
//! To understand the logic and core concepts of this code, please consult [Graph creation and management](#graph-creation-and-management).
//! This construction logic is covered by unit tests.
//! * a documented Rust code of a binary (check it out [here](https://github.com/ciphermodelabs/ciphercore/tree/main/ciphercore-base/src/bin)) that creates a context with the aforementioned graph and returns its serialization into JSON.
//! This serialization can be later used for converting the graph to its secure computation counterpart, visualization and inspection as was shown in [Quick start](#quick-start).
//! * two scripts `build_graph.sh` and `run.sh` in [`example_scripts`](https://github.com/ciphermodelabs/ciphercore/tree/main/ciphercore-base/example_scripts)
//!    * `build_graph.sh` creates a computation graph of a secure protocol for a specific task and saves its JSON-serializes it in `mpc_graph.json`.
//!    * `run.sh` takes the graph serialization and runs it on inputs provided in `inputs.json` as in [Quick start](#quick-start).
//!
//! The following examples are provided:
//! * matrix multiplication,
//! * Millionaires' problem,
//! * minimum of an array,
//! * sort using [Radix Sort MPC protocol](https://eprint.iacr.org/2019/695.pdf),
//!
//! ## Matrix multiplication
//!
//! Given two matrices in the form of 2-dimensional arrays, their product is computed.
//! The serialization binary generates the following simple graph, as matrix multiplication is a built-in operation of CipherCore.
//!
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/matmul.svg" alt="Multiplication Graph" width="30%"/>
//! </p>
//!
//! ## Millionaires' problem
//!
//! Two millionaires want to find out who is richer without revealing their wealth.
//! This is [a classic SMPC problem](https://en.wikipedia.org/wiki/Yao%27s_Millionaires%27_problem).
//! The serialization binary generates the following simple graph, as the greater-than operation is a built-in custom operation of CipherCore.
//!
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/millionaires.svg" alt="Millionaires' Problem Graph" width="30%"/>
//! </p>
//!
//! ## Minimum of an array
//!
//! Given an array of unsigned integers, their minimum is computed.
//! The serialization binary generates the following graph corresponding to the tournament method.
//! Note that each `Min` operation is performed elementwise on arrays of 32-bit elements.
//!
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/minimum.svg" alt="Minimum Graph" width="30%"/>
//! </p>
//!
//! ## Sort
//!
//! Given an array of integers, this example sorts them in an ascending order.
//! The serialization binary generates the following graph corresponding to [the Radix Sort MPC protocol](https://eprint.iacr.org/2019/695.pdf).
//!
//! # Graph creation and management
//!
//! The main object of CipherCore is a computation [*graph*](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html).
//! You can think of a graph as an algorithm description where every instruction corresponds to a [*node*](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Node.html).
//! Nodes correspond to operations that can change data, form new data (e.g. [constant nodes](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.constant)) or provide input data (i.e, [input nodes](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.input)).
//!
//! All the computation graphs should exist in a [*context*](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Context.html), which is a special object containing auxiliary information about graphs and nodes. A context can be created by the following function:
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! This context is empty.
//! Let's add a new graph to it:
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! This fresh graph doesn't contain any nodes.
//! Thus, the corresponding algorithm does nothing.
//! Let's implement a simple algorithm, or graph, that adds two 32-bit signed integers.
//!
//! First, define input types of the graph.
//! There are only two input integers of the same type, which is defined below.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! Here, we create a type containing only one integer (i.e., a [*scalar*](https://docs.rs/ciphercore-base/latest/ciphercore_base/data_types/enum.Type.html#variant.Scalar)) of scalar type [INT32](https://docs.rs/ciphercore-base/latest/ciphercore_base/data_types/constant.INT32.html).
//! Similarly, one can create arrays, vectors, tuples and named tuples; see the documentation on [data types](https://docs.rs/ciphercore-base/latest/ciphercore_base/data_types/index.html) for more details.
//!
//! Now, we can add two input nodes to the graph corresponding to two input integers.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! let i1 = g.input(t.clone()).unwrap();
//! let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! Our toy algorithm contains only one instruction, namely "add two input integers".
//! This instruction corresponds to an addition node that can be attached to the graph as follows.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! Note that you can describe various operations via nodes, e.g. arithmetic operations, permutation of arrays, extraction of subarrays, composition of values into vectors or tuples, iteration etc.
//! See [Graph](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html) for more details.
//!
//! Any algorithm should have an output.
//! In the graph language, it means that any graph should have an output node.
//! Let's promote the above addition node to the output node of the graph.
//! Note that the output node can be set only once.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! Now the addition algorithm is fully described as a graph.
//! Now, we should tell CipherCore that the graph is ready by finalizing it.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! After this command the graph can't be changed.
//!
//! CipherCore can evaluate only finalized graphs in a finalized context.
//! To finalize a context, one should set its main graph using the below command.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! ```
//!
//! Similarly to graphs, a context is finalized by the [`finalize`](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Context.html#method.finalize) function; contexts can't be changed after finalization.
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! c.finalize().unwrap();
//! ```
//!
//! The above text gives a glimpse of how computation graphs in CipherCore can be created.
//! For a comprehensive description of the respective API, see [the documentation of CipherCore](https://docs.rs/ciphercore-base/latest/ciphercore_base/index.html).
//!
//! Contexts and graphs can be serialized and deserialized using [serde](https://serde.rs/). Here is how you can serialize a context `c` into JSON:
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # use serde::{Deserialize, Serialize};
//! # let c = create_context().unwrap();
//! # let g = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let i1 = g.input(t.clone()).unwrap();
//! # let i2 = g.input(t).unwrap();
//! # let a = g.add(i1, i2).unwrap(); // you can also write i1.add(i2).unwrap()
//! # g.set_output_node(a).unwrap(); // you can also write a.set_as_output().unwrap()
//! # g.finalize().unwrap();
//! # c.set_main_graph(g).unwrap(); //you can also write g.set_as_main().unwrap()
//! # c.finalize().unwrap();
//! println!("{}", serde_json::to_string(&c).unwrap());
//! ```
//!
//! The resulting graph has the following structure
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/manual_graph.svg" alt="Manual Graph" width="30%"/>
//! </p>
//!
//! ## Overview of CipherCore operations
//!
//! Computation graphs consist of nodes that represent operations.
//! CipherCore operations can be attached to the graph calling a [Graph method](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html).
//! For example,  
//!
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let graph = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let arg1 = graph.input(t.clone()).unwrap();
//! # let arg2 = graph.input(t).unwrap();
//! graph.add(arg1, arg2).unwrap();
//! ```
//!
//! Some operations can be called as a [Node method](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Node.html).
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{INT32, scalar_type};
//! # let c = create_context().unwrap();
//! # let graph = c.create_graph().unwrap();
//! # let t = scalar_type(INT32);
//! # let arg1 = graph.input(t.clone()).unwrap();
//! # let arg2 = graph.input(t).unwrap();
//! arg1.add(arg2).unwrap();
//! ```
//!
//! ### Data types
//!
//! See [documentation](https://docs.rs/ciphercore-base/latest/ciphercore_base/data_types/index.html).
//!
//! Each node in a CipherCore graph has its associated type. Types can be:
//! * **Scalars** A scalar can be a bit or a (signed or unsigned) 8-, 16-, 32- or 64-bit integer.
//! * **(Multi-dimensional) arrays** An array is given by its *shape* and a *scalar entry type*.
//! * **Tuples** A tuple is a fixed-sized sequence of values of potentially different types.
//! * **Named tuples** A named tuple is the same as a tuple except that sequence elements can be addressed by its *names*.
//! * **Vectors** A vector is a sequence of entries of the same type. Unlike arrays, the elements of vectors don't have to be scalars.
//!
//! ### Basic operations
//!
//! CipherCore provides a variety of built-in basic operations that include
//! * [input](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.input),
//! * arithmetic operations (that can operate on the whole arrays at once):
//!    * [addition](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.add),
//!    * [subtraction](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.subtract),
//!    * [multiplication](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.multiply),
//!    * [mixed multiplication of integers and bits](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.mixed_multiply),
//!    * [dot product](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.dot),
//!    * [matrix multiplication](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.matmul),
//!    * [summation of array entries](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.sum),
//!    * [truncation](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.truncate),
//! * [constants](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.constant),
//! * conversion between the binary and arithmetic representations of integers ([a2b](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.a2b), [b2a](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.b2a)),
//! * conversion between vectors and arrays ([array_to_vector](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.array_to_vector) or [vector_to_array](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.vector_to_array)),
//! * composing values into [vectors](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.create_vector), [tuples](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.create_tuple) or [named tuples](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.create_named_tuple),
//! * extracting sub-arrays ([get](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.get), [get_slice](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.get_slice)), vector elements ([vector_get](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.vector_get)) or tuple elements ([tuple_get](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.tuple_get), [named_tuple_get](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.named_tuple_get)),
//! * [permutation](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.permute_axes) of arrays,
//! * [sort](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.sort) of arrays by the key,
//! * [repetition of values](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.repeat),
//! * [reshaping](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.reshape) values to other compatible types,
//! * [joining arrays](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.stack),
//! * [zipping vectors](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.zip),
//! * [calling](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.call) another graph with inputs contained in given nodes,
//! * [iteration](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.iterate).
//!
//! ### Custom operations
//!
//! In addition, CipherCore provides [a custom operation](https://docs.rs/ciphercore-base/latest/ciphercore_base/custom_ops/struct.CustomOperation.html) interface that calls a pre-defined computation graph created for a specific task.
//! Users can create their own custom operations from basic functions by implementing a struct satisfying the [CustomOperationBody](https://docs.rs/ciphercore-base/latest/ciphercore_base/custom_ops/trait.CustomOperationBody.html) trait.
//! The computation graph associated with a custom operation is defined within the [instantiate](https://docs.rs/ciphercore-base/latest/ciphercore_base/custom_ops/trait.CustomOperationBody.html#tymethod.instantiate) method.
//! Note that different computation graphs can be created depending on input types and the number of inputs.
//! Thus, a custom operation is a tool to create [a polymorphic function](https://en.wikipedia.org/wiki/Polymorphism_(computer_science)).
//!
//! To attach a custom operation to the computation graph, use the [custom_op](https://docs.rs/ciphercore-base/latest/ciphercore_base/graphs/struct.Graph.html#method.custom_op) method as follows.
//! ```no_run
//! # use ciphercore_base::graphs::create_context;
//! # use ciphercore_base::data_types::{BIT, array_type};
//! # use ciphercore_base::ops::min_max::Min;
//! # use ciphercore_base::custom_ops::CustomOperation;
//! # let c = create_context().unwrap();
//! # let graph = c.create_graph().unwrap();
//! # let t = array_type(vec![32], BIT);
//! # let arg1 = graph.input(t.clone()).unwrap();
//! # let arg2 = graph.input(t).unwrap();
//! graph.custom_op(CustomOperation::new(Min {signed_comparison: true}), vec![arg1,arg2]).unwrap();
//! ```
//!
//! The following custom operations are already implemented within CipherCore:
//! * [bitwise NOT](https://docs.rs/ciphercore-base/latest/ciphercore_base/custom_ops/struct.Not.html),
//! * [bitwise OR](https://docs.rs/ciphercore-base/latest/ciphercore_base/custom_ops/struct.Or.html),
//! * [the binary adder](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/adder/struct.BinaryAdd.html),
//! * [clipping](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/clip/struct.Clip2K.html),
//! * comparison functions:
//!    * [equal](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/comparisons/struct.Equal.html),
//!    * [not-equal](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/comparisons/struct.NotEqual.html),
//!    * [greater-than](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/comparisons/struct.GreaterThan.html),
//!    * [greater-than-equal-to](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/comparisons/struct.GreaterThanEqualTo.html),
//!    * [less-than](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/comparisons/struct.LessThan.html),
//!    * [less-than-equal-to](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/comparisons/struct.LessThanEqualTo.html),
//!    * [maximum](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/min_max/struct.Max.html),
//!    * [minimum](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/min_max/struct.Min.html),
//! * [multiplexer](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/multiplexer/struct.Mux.html),
//! * [multiplicative inverse](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/newton_inversion/struct.NewtonInversion.html),
//! * [inverse square root](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/inverse_sqrt/struct.InverseSqrt.html),
//! * [sorting by integer key](https://docs.rs/ciphercore-base/latest/ciphercore_base/ops/integer_key_sort/struct.SortByIntegerKey.html).
//!
//! # CLI Tools
//!
//! ## Compiler
//!
//! To compile a computation graph to a computation graph of a secure protocol between three parties one can use the CipherCore compiler `ciphercore_compile`.
//!
//! Under the hood, the compilation passes through the following stages:
//! 1. All custom operations of the input graph are instantiated, i.e., they are replaced by the `Call` operations of the graphs that describe the logic of these operations.
//! 2. All `Call` and `Iterate` operations are inlined, i.e., they are replaced by equivalent sets of basic operations without calling other computation graphs.
//! 3. The resulting graph is optimized by removing unnecessary and repetitive operations.
//! 4. Operations of the fully instantiated and inlined graph are converted to their SMPC counterparts.
//! At this stage, `Input` nodes are replaced by operations that perform [secret sharing](#secret-sharing) of input values according to the compiler arguments.
//! The output node of the graph is followed by operations performing revealing to authorized parties.
//! 5. Step 1-3 are repeated on the resulting SMPC graph.
//!
//! The resulting graph is typically larger than the original graph as was shown [above](#working-with-the-graph-using-cli-tools).
//! It includes specific cryptographic and networking operations that help protect and communicate [secret shared values](#secret-sharing).
//!
//! To learn about the invocation of compilation binary and its command-line arguments description, you can run:   
//! ```bash
//! ciphercore_compile --help
//! ```
//!
//! It is invoked as follows:
//! ```bash
//! ciphercore_compile <CONTEXT_PATH> <INLINE_MODE> <INPUT_PARTIES> <OUTPUT_PARTIES>
//! ```
//!
//! where:
//! * `<CONTEXT_PATH>`: The path to a context, where the main graph is to be evaluated privately;
//! * `<INLINE_MODE>`: Before we compile a graph, we instantiate all custom operations, inline all `Call` and `Iterate` operations, and finally optimize the resulting graph. CipherCore offers three different mode for inlining: `simple`, `depth-optimized-default`, and `depth-optimized-extreme`. These modes provide different trade-offs between the compute and the number of networking rounds needed to execute the secure protocol: `simple` mode aims to optimize compute ignoring the networking, `depth-optimized-extreme` minimizes networking latency, while `depth-optimized-default` is somewhere in between.
//! * `<INPUT_PARTIES>`: You should provide a comma delimited list of entities which provide each input. If you specify a number x=0,1,2 it means the party x is providing that input. If you specify `public` it means the input value is public. If you specify `secret-shared` it means that input is secret-shared between all parties. For example, `<INPUT_PARTIES> = 2,public,0,secret-shared` means party 2 provides first input, next input is a public value, the third input is provided by party 0, and the last input is secret-shared among all parties. Check [Secret sharing](#secret-sharing) for technical details.
//! * `<OUTPUT_PARTIES>`: You should provide a comma delimited list of entities that receives the output. Please note that duplicate entries are not allowed in the list. Possible values for `<OUTPUT_PARTIES>` are as follows:
//!    1. `secret-shared`: No party receives the output, it stays in the secret-shared form.
//!    2. `public`: All parties receive the output.
//!    3. A comma delimited list of distinct party numbers: listed parties and only them receive the output.
//!
//! For instance:
//! ```bash
//! ciphercore_compile a.json simple 0,1 2 > b.json
//! ```
//!
//! compiles the graph `a.json` using simple inlining (optimizes for compute rather than network rounds) assuming the first input is provided by party 0, the second input is provided by party 1, and the output is going to be revealed to party 2.
//!
//! ## Evaluator
//!
//! One can run a computation graph (compiled or not) on a given data locally via a reference evaluator, using a binary `ciphercore_evaluate`.
//! In order to use the fast evaluator, please use the binary `ciphercore_evaluate_fast` from within the CipherCore [Docker image](https://github.com/ciphermodelabs/ciphercore/blob/main/reference/main.md#docker-image), which is fully-compatible with `ciphercore_evaluate`.
//! This is a good way to test the functionality as well as -- if we use the fast evaluator -- get a decent idea about the end-to-end performance of the actual protocol when executed within the CipherCore runtime (modulo networking interactions).
//! Either evaluator takes two mandatory parameters: path to a serialized context which main graph we'd like to evaluate and a file with inputs given in the JSON format.
//!
//! ### Secret-shared input
//!
//! If an input to a compiled graph is given in a [secret-shared format](#secret-sharing), you can optionally provide a vanilla plaintext input, and it will be secret-shared automatically.
//!
//! ### Input format
//!
//! Inputs and outputs are given in a human-readable JSON format. For example:
//!
//! ```json
//! [
//!     {"kind": "scalar", "type": "i32", "value": 123456},
//!     {"kind": "array", "type": "bit", "value": [[0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]]},
//!     {"kind": "tuple", "value": [{"kind": "scalar", "type": "i32", "value": 123456}, {"kind": "tuple", "value": []}]},
//!     {"kind": "vector", "value": [{"kind": "scalar", "type": "i32", "value": 123456}, {"kind": "scalar", "type": "i32", "value": 654321}]}
//! ]
//! ```
//!
//! You can learn more by checking out the [provided examples](#examples).
//!
//! ## Visualization
//!
//! The visualization tool, namely `ciphercore_visualize_context`, generates a set of instructions for GraphViz to draw all the graphs and their associated nodes from the given `Context` input.
//! To use it, you need to [install](https://graphviz.org/download/) Graphviz.
//!
//! For instance, if we create the following context:
//!
//! ```no_run
//! use ciphercore_base::data_types::{array_type, UINT64};
//! use ciphercore_base::errors::Result;
//! use ciphercore_base::graphs::create_context;
//!
//! fn main() {
//!     || -> Result<()> {
//!         let c = create_context()?;
//!         let mul = {
//!             let g = c.create_graph()?;
//!             let i0 = g.input(array_type(vec![2, 2], UINT64))?;
//!             i0.set_name("MultIp0")?;
//!             let i1 = g.input(array_type(vec![2, 2, 2], UINT64))?;
//!             i1.set_name("MultIp1")?;
//!             let op_mul = g.multiply(i0, i1)?;
//!             op_mul.set_name("Product")?;
//!             g.set_output_node(op_mul)?;
//!             g.finalize()?;
//!             g
//!         };
//!         let sum_g = c.create_graph()?;
//!         let i0 = sum_g.input(array_type(vec![2], UINT64))?;
//!         i0.set_name("Input a")?;
//!         let i1 = sum_g.input(array_type(vec![2, 2], UINT64))?;
//!         i1.set_name("Input b")?;
//!         let i2 = sum_g.input(array_type(vec![2, 2, 2], UINT64))?;
//!         i2.set_name("Input c")?;
//!         let prod = sum_g.call(mul, vec![i1, i2])?;
//!         let op = sum_g.add(i0, prod)?;
//!         op.set_name("Output")?;
//!         sum_g.set_output_node(op)?;
//!         sum_g.finalize()?;
//!         c.set_main_graph(sum_g)?;
//!         c.finalize()?;
//!         println!("{}", serde_json::to_string(&c)?);
//!         Ok(())
//!     }()
//!     .unwrap();
//! }
//! ```
//!
//! save the output to file `context.json`, and visualize it as follows:
//!
//! ```bash
//! ciphercore_visualize_context context.json | dot -Tsvg -o vis.svg
//! ```
//!
//! we get:
//!
//! <p align = "center">
//!     <img src="https://raw.githubusercontent.com/ciphermodelabs/ciphercore/main/reference/images/arr_mul.svg" alt="Array Multiplication Graph" width="60%"/>
//! </p>
//!
//! ## Inspection
//!
//! Using graph inspection, you can get insightful statistics about a computation graph.
//! These statistics include names and types of all of the input nodes, name and type of the output node, number of network rounds required to evaluate the graph, number of arithmetic operations required to evaluate the graph, and number of times each type of node occurring in the graph.
//!
//! To learn about the invocation of graph inspection binary and its command-line arguments description, you can run:   
//!
//! ```bash
//! ciphercore_inspect --help
//! ```
//!
//! You can inspect both compiled and uncompiled graphs. For example, for a compiled graph stored in `b.json` you can simply run inspect by:
//!
//! ```bash
//! ciphercore_inspect b.json
//! ```
//!
//! and get a result like:
//!
//! ```bash
//! Calculating stats...
//! -------Stats--------
//! Inputs:
//!     1. Name:unnamed
//!     Type:i64[5, 5]
//!     2. Name:unnamed
//!     Type:i64[5, 5]
//! Output:
//!     Name:unnamed
//!     Type:i64[5, 5]
//! Network rounds: 4
//! Network traffic: 2.00KB
//! Total number of integer arithmetic operations:   2.84K Ops
//!     Total number of 1-bit arithmetic operations:   384 Ops
//!     Total number of 8-bit arithmetic operations:   0 Ops
//!     Total number of 16-bit arithmetic operations:  0 Ops
//!     Total number of 32-bit arithmetic operations:  0 Ops
//!     Total number of 64-bit arithmetic operations:  2.45K Ops
//! Total operations: 55
//! Operations:
//!     NOP           13
//!     Add           13
//!     PRF           9
//!     Subtract      9
//!     Matmul        6
//!     Random        3
//!     Input         2
//! ```
//!
//! For uncompiled graphs, you have the option to first prepare the graph for inspection.
//! In preparation phase, we instantiate all custom operations, inline all `Call` and `Iterate` operations, and finally optimize the resulting graph.
//! CipherCore offers three different mode for inlining: `simple`, `depth-optimized-default`, and `depth-optimized-extreme`.
//! You can chose which inlining mode should be used for preparing the input graph.
//! If you do not chose any inlining mode, the `simple` mode will be used as a default.
//! For example, for an uncompiled graph stored in `a.json` you can run inspect by:
//!
//! ```bash
//! ciphercore_inspect a.json prepare depth-optimized-default
//! ```
//!
//! and get a result as follows:
//!
//! ```bash
//! Instantiating...
//! Inlining...
//! Optimizing...
//! Calculating stats...
//! -------Stats--------
//! Inputs:
//!     1. Name:unnamed
//!     Type:i64[5, 5]
//!     2. Name:unnamed
//!     Type:i64[5, 5]
//! Output:
//!     Name:unnamed
//!     Type:i64[5, 5]
//! Network rounds: 0
//! Network traffic: 0B
//! Total number of integer arithmetic operations:   125 Ops
//!     Total number of 1-bit arithmetic operations:   0 Ops
//!     Total number of 8-bit arithmetic operations:   0 Ops
//!     Total number of 16-bit arithmetic operations:  0 Ops
//!     Total number of 32-bit arithmetic operations:  0 Ops
//!     Total number of 64-bit arithmetic operations:  125 Ops
//! Total operations: 3
//! Operations:
//!     Input         2
//!     Matmul        1
//! ```
#![allow(clippy::needless_doctest_main)]

#[macro_use]
pub mod errors;
pub mod applications;
#[doc(hidden)]
pub mod broadcast;
#[doc(hidden)]
pub mod bytes;
mod constants;
pub mod custom_ops;
pub mod data_types;
pub mod data_values;
#[doc(hidden)]
pub mod evaluators;
pub mod graphs;
#[doc(hidden)]
pub mod inline;
#[doc(hidden)]
pub mod join_utils;
#[doc(hidden)]
pub mod mpc;
pub mod ops;
#[doc(hidden)]
pub mod optimizer;
#[doc(hidden)]
pub mod random;
#[doc(hidden)]
pub mod slices;
#[doc(hidden)]
pub mod type_inference;
pub mod typed_value;
#[doc(hidden)]
pub mod typed_value_operations;
#[doc(hidden)]
pub mod typed_value_secret_shared;
#[doc(hidden)]
mod typed_value_serialization;
#[doc(hidden)]
pub mod version;

#[cfg(test)]
#[macro_use]
extern crate maplit;