{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0f2abd68-5065-49c2-aefa-65ca3c8be8f8",
   "metadata": {},
   "source": [
    "# Compiling homomorphic encryption circuits made easy"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f425b04-35ab-4a1c-8ed4-20ecdc7d2901",
   "metadata": {},
   "source": [
    "#### The only boilerplate consists of defining the plaintext space and the inputs of the program."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18d03a72-d22a-4f54-9a68-ab31507d1e34",
   "metadata": {},
   "outputs": [],
   "source": [
    "from galois import GF\n",
    "\n",
    "from circuit_compiler.compiler.nodes.leafs import Input\n",
    "\n",
    "gf = GF(11)\n",
    "\n",
    "a = Input(\"a\", gf)\n",
    "b = Input(\"b\", gf)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a7890f4-c770-4699-acba-ec2e6796a5bb",
   "metadata": {},
   "source": [
    "#### Programmers can use the primitives that they are used to."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0dd02769-50cc-4eb1-a9e0-896b944d9b28",
   "metadata": {},
   "outputs": [],
   "source": [
    "output = a < b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a26b9ca-2441-48e1-8aad-4b626755485e",
   "metadata": {},
   "source": [
    "#### A circuit can have an arbitrary number of outputs; here we only have one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d00fa605-4510-4393-bdb0-4dd54a21f5f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from circuit_compiler.compiler.circuit import Circuit\n",
    "\n",
    "circuit = Circuit(outputs=[output], gf=gf)\n",
    "circuit.display_graph()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc7c6e33-a7ad-4e2f-a742-40653160a0ca",
   "metadata": {},
   "source": [
    "#### Turning high-level circuits into arithmetic circuits is a fully automatic process that improves on the state of the art in multiple ways."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a441c9f5-de63-4253-bbb6-4b63511acc67",
   "metadata": {},
   "outputs": [],
   "source": [
    "arithmetic_circuit = circuit.arithmetize()\n",
    "arithmetic_circuit.display_graph()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33a64549-4081-4fb8-9631-1f007b368dfa",
   "metadata": {},
   "source": [
    "#### The compiler implements a form of semantic subexpression elimination that significantly optimizes large circuits."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1cd8bfaf-8113-444a-812c-b2a4fe124cec",
   "metadata": {},
   "outputs": [],
   "source": [
    "arithmetic_circuit.eliminate_subexpressions()\n",
    "arithmetic_circuit.display_graph()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a89d7c56-ef33-4ac6-b06a-0f88d45aff91",
   "metadata": {},
   "source": [
    "#### This much smaller circuit is still correct!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d50141a-b84a-4ac4-93e7-a7a1cf484688",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tabulate\n",
    "\n",
    "for val_a in range(11):\n",
    "    for val_b in range(11):\n",
    "        assert arithmetic_circuit.evaluate({\"a\": gf(val_a), \"b\": gf(val_b)}) == gf(val_a < val_b)\n",
    "\n",
    "data = [[arithmetic_circuit.evaluate({\"a\": gf(val_a), \"b\": gf(val_b)})[0] for val_a in range(11)] for val_b in range(11)]\n",
    "\n",
    "table = tabulate.tabulate(data, tablefmt='html')\n",
    "table"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
