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