From ae72b58ea66c6b5ddd10b90ad3296901bcf812d5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 26 Feb 2024 11:40:05 +0000 Subject: [PATCH] deploy: 48dd6a16487bbc66356f60d6a17c0cca8192b419 --- 404.html | 4 ++-- ZKContainers.html | 6 +++--- assets/js/{03cb0a55.effbdeae.js => 03cb0a55.12036a44.js} | 2 +- assets/js/{076f2345.aced6b81.js => 076f2345.e539f211.js} | 2 +- assets/js/{0dca48ed.bfa3c731.js => 0dca48ed.55ac5a02.js} | 2 +- assets/js/{0ec3cab9.2180a8ed.js => 0ec3cab9.e355dffd.js} | 2 +- assets/js/{2b850a9b.40ab3057.js => 2b850a9b.a413b9a9.js} | 2 +- assets/js/{3db59c3c.422f8b46.js => 3db59c3c.ed96355d.js} | 2 +- assets/js/{46bc3aca.cc5c1b6f.js => 46bc3aca.7b300224.js} | 2 +- assets/js/{584ea0b6.c8828735.js => 584ea0b6.d52ce6af.js} | 2 +- assets/js/{62ce5d13.2a27b3b1.js => 62ce5d13.dd7fe865.js} | 2 +- assets/js/{90656eea.d15777d5.js => 90656eea.6292a4ae.js} | 2 +- assets/js/{93a51358.5e6e7172.js => 93a51358.2c386f0b.js} | 2 +- assets/js/{a09c2993.b358e04d.js => a09c2993.1d68ad2b.js} | 2 +- assets/js/{acd9d3d0.ed9bd5c9.js => acd9d3d0.782ff31b.js} | 2 +- assets/js/{ec013bfd.0bc0bf0d.js => ec013bfd.cb089409.js} | 2 +- assets/js/{fdbbc319.0dcb1a13.js => fdbbc319.b8d6ecfd.js} | 2 +- ...{runtime~main.59ac1dd1.js => runtime~main.0d664441.js} | 2 +- contributor-guide.html | 6 +++--- grants.html | 6 +++--- icicle/colab-instructions.html | 6 +++--- icicle/golang-bindings.html | 6 +++--- icicle/integrations.html | 6 +++--- icicle/introduction.html | 6 +++--- icicle/overview.html | 8 ++++---- icicle/primitives/msm.html | 6 +++--- icicle/primitives/ntt.html | 6 +++--- icicle/primitives/overview.html | 6 +++--- icicle/primitives/poseidon.html | 6 +++--- icicle/rust-bindings.html | 6 +++--- icicle/supporting-additional-curves.html | 6 +++--- index.html | 6 +++--- search.html | 4 ++-- 33 files changed, 66 insertions(+), 66 deletions(-) rename assets/js/{03cb0a55.effbdeae.js => 03cb0a55.12036a44.js} (99%) rename assets/js/{076f2345.aced6b81.js => 076f2345.e539f211.js} (97%) rename assets/js/{0dca48ed.bfa3c731.js => 0dca48ed.55ac5a02.js} (98%) rename assets/js/{0ec3cab9.2180a8ed.js => 0ec3cab9.e355dffd.js} (99%) rename assets/js/{2b850a9b.40ab3057.js => 2b850a9b.a413b9a9.js} (99%) rename assets/js/{3db59c3c.422f8b46.js => 3db59c3c.ed96355d.js} (98%) rename assets/js/{46bc3aca.cc5c1b6f.js => 46bc3aca.7b300224.js} (98%) rename assets/js/{584ea0b6.c8828735.js => 584ea0b6.d52ce6af.js} (97%) rename assets/js/{62ce5d13.2a27b3b1.js => 62ce5d13.dd7fe865.js} (98%) rename assets/js/{90656eea.d15777d5.js => 90656eea.6292a4ae.js} (98%) rename assets/js/{93a51358.5e6e7172.js => 93a51358.2c386f0b.js} (98%) rename assets/js/{a09c2993.b358e04d.js => a09c2993.1d68ad2b.js} (98%) rename assets/js/{acd9d3d0.ed9bd5c9.js => acd9d3d0.782ff31b.js} (99%) rename assets/js/{ec013bfd.0bc0bf0d.js => ec013bfd.cb089409.js} (98%) rename assets/js/{fdbbc319.0dcb1a13.js => fdbbc319.b8d6ecfd.js} (97%) rename assets/js/{runtime~main.59ac1dd1.js => runtime~main.0d664441.js} (77%) diff --git a/404.html b/404.html index 0e7f253..6804085 100644 --- a/404.html +++ b/404.html @@ -7,13 +7,13 @@ Page Not Found | Ingonyama Developer Documentation - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/ZKContainers.html b/ZKContainers.html index 3fc60fa..af3aa35 100644 --- a/ZKContainers.html +++ b/ZKContainers.html @@ -7,14 +7,14 @@ ZKContainer | Ingonyama Developer Documentation - +
Skip to main content

ZKContainer

We found that developing ZK provers with ICICLE gives developers the ability to scale ZK provers across many machines and many GPUs. To make this possible we developed the ZKContainer.

What is a ZKContainer?โ€‹

A ZKContainer is an standardized, optimized and secure docker container that we configured with ICICLE applications in mind. A developer using our ZKContainer can deploy an ICICLE application on a single machine or on a thousand GPU machines in a data center with minimal concerns regarding compatibility.

ZKContainer has been used by Ingonyama clients to achieve scalability across large data centers. -We suggest you read our article regarding ZKContainer to understand the benefits of using them.

ZKContainer inside a ZK data center

- +We suggest you read our article regarding ZKContainer to understand the benefits of using them.

ZKContainer inside a ZK data center

+ \ No newline at end of file diff --git a/assets/js/03cb0a55.effbdeae.js b/assets/js/03cb0a55.12036a44.js similarity index 99% rename from assets/js/03cb0a55.effbdeae.js rename to assets/js/03cb0a55.12036a44.js index 357a98c..ba674c8 100644 --- a/assets/js/03cb0a55.effbdeae.js +++ b/assets/js/03cb0a55.12036a44.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[929],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),p=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=a,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||o;return n?i.createElement(h,r(r({ref:t},u),{},{components:n})):i.createElement(h,r({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,r[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var i=n(7462),a=(n(7294),n(3905));n(8209);const o={},r="Poseidon",l={unversionedId:"icicle/primitives/poseidon",id:"icicle/primitives/poseidon",title:"Poseidon",description:"Poseidon is a popular hash in the ZK ecosystem primarily because its optimized to work over large prime fields, a common setting for ZK proofs, thereby minimizing the number of multiplicative operations required.",source:"@site/docs/icicle/primitives/poseidon.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/poseidon",permalink:"/icicle/primitives/poseidon",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/poseidon.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"MSM - Multi scalar multiplication",permalink:"/icicle/primitives/msm"},next:{title:"NTT - Number Theoretic Transform",permalink:"/icicle/primitives/ntt"}},s={},p=[{value:"Initialization",id:"initialization",level:3},{value:"Applying full and partial rounds",id:"applying-full-and-partial-rounds",level:3},{value:"Full rounds",id:"full-rounds",level:4},{value:"Partial Rounds",id:"partial-rounds",level:4},{value:"Using Poseidon",id:"using-poseidon",level:2},{value:"Supported API",id:"supported-api",level:3},{value:"Supported curves",id:"supported-curves",level:3},{value:"Constants",id:"constants",level:3},{value:"Rust API",id:"rust-api",level:3},{value:"The Tree Builder",id:"the-tree-builder",level:2},{value:"Benchmarks",id:"benchmarks",level:3}],u={toc:p},d="wrapper";function c(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,i.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"poseidon"},"Poseidon"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://eprint.iacr.org/2019/458.pdf"},"Poseidon")," is a popular hash in the ZK ecosystem primarily because its optimized to work over large prime fields, a common setting for ZK proofs, thereby minimizing the number of multiplicative operations required."),(0,a.kt)("p",null,"Poseidon has also been specifically designed to be efficient when implemented within ZK circuits, Poseidon uses far less constraints compared to other hash functions like Keccak or SHA-256 in the context of ZK circuits."),(0,a.kt)("p",null,"Poseidon has been used in many popular ZK protocols such as Filecoin and ",(0,a.kt)("a",{parentName:"p",href:"https://drive.google.com/file/d/1bZZvKMQHaZGA4L9eZhupQLyGINkkFG_b/view?usp=drive_open"},"Plonk"),"."),(0,a.kt)("p",null,"Our implementation of Poseidon is implemented in accordance with the optimized ",(0,a.kt)("a",{parentName:"p",href:"https://spec.filecoin.io/algorithms/crypto/poseidon/"},"Filecoin version"),"."),(0,a.kt)("p",null,"Let understand how Poseidon works."),(0,a.kt)("h3",{id:"initialization"},"Initialization"),(0,a.kt)("p",null,"Poseidon starts with the initialization of its internal state, which is composed of the input elements and some pregenerated constants. An initial round constant is added to each element of the internal state. Adding The round constants ensure the state is properly mixed from the outset."),(0,a.kt)("p",null,"This is done to prevent collisions and to prevent certain cryptographic attacks by ensuring that the internal state is sufficiently mixed and unpredictable."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Alt text",src:n(3729).Z,width:"872",height:"294"})),(0,a.kt)("h3",{id:"applying-full-and-partial-rounds"},"Applying full and partial rounds"),(0,a.kt)("p",null,'To generate a secure hash output, the algorithm goes through a series of "full rounds" and "partial rounds" as well as transformations between these sets of rounds.'),(0,a.kt)("p",null,"First full rounds => apply SBox and Round constants => partial rounds => Last full rounds => Apply SBox"),(0,a.kt)("h4",{id:"full-rounds"},"Full rounds"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Alt text",src:n(6757).Z,width:"864",height:"552"})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Uniform Application of S-Box:")," In full rounds, the S-box (a non-linear transformation) is applied uniformly to every element of the hash function's internal state. This ensures a high degree of mixing and diffusion, contributing to the hash function's security. The functions S-box involves raising each element of the state to a certain power denoted by ",(0,a.kt)("inlineCode",{parentName:"p"},"\u03b1")," a member of the finite field defined by the prime ",(0,a.kt)("inlineCode",{parentName:"p"},"p"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"\u03b1")," can be different depending on the the implementation and user configuration."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Linear Transformation:")," After applying the S-box, a linear transformation is performed on the state. This involves multiplying the state by a MDS (Maximum Distance Separable) Matrix. which further diffuses the transformations applied by the S-box across the entire state."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Addition of Round Constants:")," Each element of the state is then modified by adding a unique round constant. These constants are different for each round and are precomputed as part of the hash function's initialization. The addition of round constants ensures that even minor changes to the input produce significant differences in the output."),(0,a.kt)("h4",{id:"partial-rounds"},"Partial Rounds"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Selective Application of S-Box:")," Partial rounds apply the S-box transformation to only one element of the internal state per round, rather than to all elements. This selective application significantly reduces the computational complexity of the hash function without compromising its security. The choice of which element to apply the S-box to can follow a specific pattern or be fixed, depending on the design of the hash function."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Linear Transformation and Round Constants:")," A linear transformation is performed and round constants are added. The linear transformation in partial rounds can be designed to be less computationally intensive (this is done by using a sparse matrix) than in full rounds, further optimizing the function's efficiency."),(0,a.kt)("p",null,"The user of Poseidon can often choose how many partial or full rounds he wishes to apply; more full rounds will increase security but degrade performance. The choice and balance is highly dependent on the use case."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Alt text",src:n(9836).Z,width:"866",height:"560"})),(0,a.kt)("h2",{id:"using-poseidon"},"Using Poseidon"),(0,a.kt)("p",null,"ICICLE Poseidon is implemented for GPU and parallelization is performed for each element of the state rather than for each state.\nWhat that means is we calculate multiple hash-sums over multiple pre-images in parallel, rather than going block by block over the input vector."),(0,a.kt)("p",null,"So for Poseidon of arity 2 and input of size 1024 * 2, we would expect 1024 elements of output. Which means each block would be of size 2 and that would result in 1024 Poseidon hashes being performed."),(0,a.kt)("h3",{id:"supported-api"},"Supported API"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust/icicle-core/src/poseidon"},(0,a.kt)("inlineCode",{parentName:"a"},"Rust")),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/appUtils/poseidon"},(0,a.kt)("inlineCode",{parentName:"a"},"C++"))),(0,a.kt)("h3",{id:"supported-curves"},"Supported curves"),(0,a.kt)("p",null,"Poseidon supports the following curves:"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"bls12-377"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"bls12-381"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"bn-254"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"bw6-761")),(0,a.kt)("h3",{id:"constants"},"Constants"),(0,a.kt)("p",null,"Poseidon is extremely customizable and using different constants will produce different hashes, security levels and performance results."),(0,a.kt)("p",null,"We support pre-calculated and optimized constants for each of the ",(0,a.kt)("a",{parentName:"p",href:"#supported-curves"},"supported curves"),".The constants can be found ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/appUtils/poseidon/constants"},"here")," and are labeled clearly per curve ",(0,a.kt)("inlineCode",{parentName:"p"},"_poseidon.h"),"."),(0,a.kt)("p",null,"If you wish to generate your own constants you can use our python script which can be found ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/b6dded89cdef18348a5d4e2748b71ce4211c63ad/icicle/appUtils/poseidon/constants/generate_parameters.py#L1"},"here"),"."),(0,a.kt)("p",null,"Prerequisites:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Install python 3"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"pip install poseidon-hash")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"pip install galois==0.3.7")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"pip install numpy"))),(0,a.kt)("p",null,"You will then need to modify the following values before running the script."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-python"},"# Modify these\narity = 11 # we support arity 2, 4, 8 and 11.\np = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 # bls12-381\n# p = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 # bls12-377\n# p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 # bn254\n# p = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 # bw6-761\nprime_bit_len = 255\nfield_bytes = 32\n\n...\n\n# primitive_element = None\nprimitive_element = 7 # bls12-381\n# primitive_element = 22 # bls12-377\n# primitive_element = 5 # bn254\n# primitive_element = 15 # bw6-761\n")),(0,a.kt)("p",null,"We only support ",(0,a.kt)("inlineCode",{parentName:"p"},"alpha = 5")," so if you want to use another alpha for SBox please reach out on discord or open a github issue."),(0,a.kt)("h3",{id:"rust-api"},"Rust API"),(0,a.kt)("p",null,"This is the most basic way to use the Poseidon API."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},"let test_size = 1 << 10;\nlet arity = 2u32;\nlet ctx = get_default_device_context();\nlet constants = load_optimized_poseidon_constants::(arity, &ctx).unwrap();\nlet config = PoseidonConfig::default();\n\nlet inputs = vec![F::one(); test_size * arity as usize];\nlet outputs = vec![F::zero(); test_size];\nlet mut input_slice = HostOrDeviceSlice::on_host(inputs);\nlet mut output_slice = HostOrDeviceSlice::on_host(outputs);\n\nposeidon_hash_many::(\n &mut input_slice,\n &mut output_slice,\n test_size as u32,\n arity as u32,\n &constants,\n &config,\n)\n.unwrap();\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"PoseidonConfig::default()")," can be modified, by default the inputs and outputs are set to be on ",(0,a.kt)("inlineCode",{parentName:"p"},"Host")," for example."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"impl<'a> Default for PoseidonConfig<'a> {\n fn default() -> Self {\n let ctx = get_default_device_context();\n Self {\n ctx,\n are_inputs_on_device: false,\n are_outputs_on_device: false,\n input_is_a_state: false,\n aligned: false,\n loop_state: false,\n is_async: false,\n }\n }\n}\n")),(0,a.kt)("p",null,"In the example above ",(0,a.kt)("inlineCode",{parentName:"p"},"load_optimized_poseidon_constants::(arity, &ctx).unwrap();")," is used which will load the correct constants based on arity and curve. Its possible to ",(0,a.kt)("a",{parentName:"p",href:"#constants"},"generate")," your own constants and load them."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},'let ctx = get_default_device_context();\n let cargo_manifest_dir = env!("CARGO_MANIFEST_DIR");\n let constants_file = PathBuf::from(cargo_manifest_dir)\n .join("tests")\n .join(format!("{}_constants.bin", field_prefix));\n let mut constants_buf = vec![];\n File::open(constants_file)\n .unwrap()\n .read_to_end(&mut constants_buf)\n .unwrap();\n\n let mut custom_constants = vec![];\n for chunk in constants_buf.chunks(field_bytes) {\n custom_constants.push(F::from_bytes_le(chunk));\n }\n\n let custom_constants = create_optimized_poseidon_constants::(\n arity as u32,\n &ctx,\n full_rounds_half,\n partial_rounds,\n &mut custom_constants,\n )\n .unwrap();\n')),(0,a.kt)("p",null,"For more examples using different configurations refer here."),(0,a.kt)("h2",{id:"the-tree-builder"},"The Tree Builder"),(0,a.kt)("p",null,"The tree builder allows you to build Merkle trees using Poseidon. "),(0,a.kt)("p",null,"You can define both the tree's ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," and its ",(0,a.kt)("inlineCode",{parentName:"p"},"arity"),". The tree ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," determines the number of layers in the tree, including the root and the leaf layer. The ",(0,a.kt)("inlineCode",{parentName:"p"},"arity")," determines how many children each internal node can have."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},'let height = 20;\nlet arity = 2;\nlet leaves = vec![F::one(); 1 << (height - 1)];\nlet mut digests = vec![F::zero(); merkle_tree_digests_len(height, arity)];\n\nlet mut leaves_slice = HostOrDeviceSlice::on_host(leaves);\n\nlet ctx = get_default_device_context();\nlet constants = load_optimized_poseidon_constants::(arity, &ctx).unwrap()\n\nlet mut config = TreeBuilderConfig::default();\nconfig.keep_rows = 1;\nbuild_poseidon_merkle_tree::(&mut leaves_slice, &mut digests, height, arity, &constants, &config).unwrap();\n\nprintln!("Root: {:?}", digests[0..1][0]);\n')),(0,a.kt)("p",null,"Similar to Poseidon, you can also configure the Tree Builder ",(0,a.kt)("inlineCode",{parentName:"p"},"TreeBuilderConfig::default()")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"keep_rows"),": The number of rows which will be written to output, 0 will write all rows."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"are_inputs_on_device"),": Have the inputs been loaded to device memory ?"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"is_async"),": Should the TreeBuilder run asynchronously? ",(0,a.kt)("inlineCode",{parentName:"li"},"False")," will block the current CPU thread. ",(0,a.kt)("inlineCode",{parentName:"li"},"True")," will require you call ",(0,a.kt)("inlineCode",{parentName:"li"},"cudaStreamSynchronize")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"cudaDeviceSynchronize")," to retrieve the result.")),(0,a.kt)("h3",{id:"benchmarks"},"Benchmarks"),(0,a.kt)("p",null,"We ran the Poseidon tree builder on: "),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"CPU"),": 12th Gen Intel(R) Core(TM) i9-12900K/"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"GPU"),": RTX 3090 Ti"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Tree height"),": 30 (2^29 elements)"),(0,a.kt)("p",null,"The benchmarks include copying data from and to the device."),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Rows to keep parameter"),(0,a.kt)("th",{parentName:"tr",align:null},"Run time, Icicle"),(0,a.kt)("th",{parentName:"tr",align:null},"Supranational PC2"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"10"),(0,a.kt)("td",{parentName:"tr",align:null},"8.3 seconds"),(0,a.kt)("td",{parentName:"tr",align:null},"13.6 seconds")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"20"),(0,a.kt)("td",{parentName:"tr",align:null},"8.2 seconds"),(0,a.kt)("td",{parentName:"tr",align:null},"13.6 seconds")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"29"),(0,a.kt)("td",{parentName:"tr",align:null},"12.2 seconds"),(0,a.kt)("td",{parentName:"tr",align:null},"13.6 seconds")))))}c.isMDXComponent=!0},6757:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/image-1-5902a94e1680e802186934fdf8ff205e.png"},9836:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/image-2-943ff9b12b39ca32378f75f981ebfb7b.png"},3729:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/image-bff569244d897bcfcd16d979cb29fb9c.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[929],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),p=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return i.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=a,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||o;return n?i.createElement(h,r(r({ref:t},u),{},{components:n})):i.createElement(h,r({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,r=new Array(o);r[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,r[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var i=n(7462),a=(n(7294),n(3905));n(8209);const o={},r="Poseidon",l={unversionedId:"icicle/primitives/poseidon",id:"icicle/primitives/poseidon",title:"Poseidon",description:"Poseidon is a popular hash in the ZK ecosystem primarily because its optimized to work over large prime fields, a common setting for ZK proofs, thereby minimizing the number of multiplicative operations required.",source:"@site/docs/icicle/primitives/poseidon.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/poseidon",permalink:"/icicle/primitives/poseidon",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/poseidon.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"MSM - Multi scalar multiplication",permalink:"/icicle/primitives/msm"},next:{title:"NTT - Number Theoretic Transform",permalink:"/icicle/primitives/ntt"}},s={},p=[{value:"Initialization",id:"initialization",level:3},{value:"Applying full and partial rounds",id:"applying-full-and-partial-rounds",level:3},{value:"Full rounds",id:"full-rounds",level:4},{value:"Partial Rounds",id:"partial-rounds",level:4},{value:"Using Poseidon",id:"using-poseidon",level:2},{value:"Supported API",id:"supported-api",level:3},{value:"Supported curves",id:"supported-curves",level:3},{value:"Constants",id:"constants",level:3},{value:"Rust API",id:"rust-api",level:3},{value:"The Tree Builder",id:"the-tree-builder",level:2},{value:"Benchmarks",id:"benchmarks",level:3}],u={toc:p},d="wrapper";function c(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,i.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"poseidon"},"Poseidon"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://eprint.iacr.org/2019/458.pdf"},"Poseidon")," is a popular hash in the ZK ecosystem primarily because its optimized to work over large prime fields, a common setting for ZK proofs, thereby minimizing the number of multiplicative operations required."),(0,a.kt)("p",null,"Poseidon has also been specifically designed to be efficient when implemented within ZK circuits, Poseidon uses far less constraints compared to other hash functions like Keccak or SHA-256 in the context of ZK circuits."),(0,a.kt)("p",null,"Poseidon has been used in many popular ZK protocols such as Filecoin and ",(0,a.kt)("a",{parentName:"p",href:"https://drive.google.com/file/d/1bZZvKMQHaZGA4L9eZhupQLyGINkkFG_b/view?usp=drive_open"},"Plonk"),"."),(0,a.kt)("p",null,"Our implementation of Poseidon is implemented in accordance with the optimized ",(0,a.kt)("a",{parentName:"p",href:"https://spec.filecoin.io/algorithms/crypto/poseidon/"},"Filecoin version"),"."),(0,a.kt)("p",null,"Let understand how Poseidon works."),(0,a.kt)("h3",{id:"initialization"},"Initialization"),(0,a.kt)("p",null,"Poseidon starts with the initialization of its internal state, which is composed of the input elements and some pregenerated constants. An initial round constant is added to each element of the internal state. Adding The round constants ensure the state is properly mixed from the outset."),(0,a.kt)("p",null,"This is done to prevent collisions and to prevent certain cryptographic attacks by ensuring that the internal state is sufficiently mixed and unpredictable."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Alt text",src:n(3729).Z,width:"872",height:"294"})),(0,a.kt)("h3",{id:"applying-full-and-partial-rounds"},"Applying full and partial rounds"),(0,a.kt)("p",null,'To generate a secure hash output, the algorithm goes through a series of "full rounds" and "partial rounds" as well as transformations between these sets of rounds.'),(0,a.kt)("p",null,"First full rounds => apply SBox and Round constants => partial rounds => Last full rounds => Apply SBox"),(0,a.kt)("h4",{id:"full-rounds"},"Full rounds"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Alt text",src:n(6757).Z,width:"864",height:"552"})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Uniform Application of S-Box:")," In full rounds, the S-box (a non-linear transformation) is applied uniformly to every element of the hash function's internal state. This ensures a high degree of mixing and diffusion, contributing to the hash function's security. The functions S-box involves raising each element of the state to a certain power denoted by ",(0,a.kt)("inlineCode",{parentName:"p"},"\u03b1")," a member of the finite field defined by the prime ",(0,a.kt)("inlineCode",{parentName:"p"},"p"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"\u03b1")," can be different depending on the the implementation and user configuration."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Linear Transformation:")," After applying the S-box, a linear transformation is performed on the state. This involves multiplying the state by a MDS (Maximum Distance Separable) Matrix. which further diffuses the transformations applied by the S-box across the entire state."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Addition of Round Constants:")," Each element of the state is then modified by adding a unique round constant. These constants are different for each round and are precomputed as part of the hash function's initialization. The addition of round constants ensures that even minor changes to the input produce significant differences in the output."),(0,a.kt)("h4",{id:"partial-rounds"},"Partial Rounds"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Selective Application of S-Box:")," Partial rounds apply the S-box transformation to only one element of the internal state per round, rather than to all elements. This selective application significantly reduces the computational complexity of the hash function without compromising its security. The choice of which element to apply the S-box to can follow a specific pattern or be fixed, depending on the design of the hash function."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Linear Transformation and Round Constants:")," A linear transformation is performed and round constants are added. The linear transformation in partial rounds can be designed to be less computationally intensive (this is done by using a sparse matrix) than in full rounds, further optimizing the function's efficiency."),(0,a.kt)("p",null,"The user of Poseidon can often choose how many partial or full rounds he wishes to apply; more full rounds will increase security but degrade performance. The choice and balance is highly dependent on the use case."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Alt text",src:n(9836).Z,width:"866",height:"560"})),(0,a.kt)("h2",{id:"using-poseidon"},"Using Poseidon"),(0,a.kt)("p",null,"ICICLE Poseidon is implemented for GPU and parallelization is performed for each element of the state rather than for each state.\nWhat that means is we calculate multiple hash-sums over multiple pre-images in parallel, rather than going block by block over the input vector."),(0,a.kt)("p",null,"So for Poseidon of arity 2 and input of size 1024 * 2, we would expect 1024 elements of output. Which means each block would be of size 2 and that would result in 1024 Poseidon hashes being performed."),(0,a.kt)("h3",{id:"supported-api"},"Supported API"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust/icicle-core/src/poseidon"},(0,a.kt)("inlineCode",{parentName:"a"},"Rust")),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/appUtils/poseidon"},(0,a.kt)("inlineCode",{parentName:"a"},"C++"))),(0,a.kt)("h3",{id:"supported-curves"},"Supported curves"),(0,a.kt)("p",null,"Poseidon supports the following curves:"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"bls12-377"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"bls12-381"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"bn-254"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"bw6-761")),(0,a.kt)("h3",{id:"constants"},"Constants"),(0,a.kt)("p",null,"Poseidon is extremely customizable and using different constants will produce different hashes, security levels and performance results."),(0,a.kt)("p",null,"We support pre-calculated and optimized constants for each of the ",(0,a.kt)("a",{parentName:"p",href:"#supported-curves"},"supported curves"),".The constants can be found ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/appUtils/poseidon/constants"},"here")," and are labeled clearly per curve ",(0,a.kt)("inlineCode",{parentName:"p"},"_poseidon.h"),"."),(0,a.kt)("p",null,"If you wish to generate your own constants you can use our python script which can be found ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/b6dded89cdef18348a5d4e2748b71ce4211c63ad/icicle/appUtils/poseidon/constants/generate_parameters.py#L1"},"here"),"."),(0,a.kt)("p",null,"Prerequisites:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Install python 3"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"pip install poseidon-hash")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"pip install galois==0.3.7")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"pip install numpy"))),(0,a.kt)("p",null,"You will then need to modify the following values before running the script."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-python"},"# Modify these\narity = 11 # we support arity 2, 4, 8 and 11.\np = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 # bls12-381\n# p = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 # bls12-377\n# p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 # bn254\n# p = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 # bw6-761\nprime_bit_len = 255\nfield_bytes = 32\n\n...\n\n# primitive_element = None\nprimitive_element = 7 # bls12-381\n# primitive_element = 22 # bls12-377\n# primitive_element = 5 # bn254\n# primitive_element = 15 # bw6-761\n")),(0,a.kt)("p",null,"We only support ",(0,a.kt)("inlineCode",{parentName:"p"},"alpha = 5")," so if you want to use another alpha for SBox please reach out on discord or open a github issue."),(0,a.kt)("h3",{id:"rust-api"},"Rust API"),(0,a.kt)("p",null,"This is the most basic way to use the Poseidon API."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},"let test_size = 1 << 10;\nlet arity = 2u32;\nlet ctx = get_default_device_context();\nlet constants = load_optimized_poseidon_constants::(arity, &ctx).unwrap();\nlet config = PoseidonConfig::default();\n\nlet inputs = vec![F::one(); test_size * arity as usize];\nlet outputs = vec![F::zero(); test_size];\nlet mut input_slice = HostOrDeviceSlice::on_host(inputs);\nlet mut output_slice = HostOrDeviceSlice::on_host(outputs);\n\nposeidon_hash_many::(\n &mut input_slice,\n &mut output_slice,\n test_size as u32,\n arity as u32,\n &constants,\n &config,\n)\n.unwrap();\n")),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},"PoseidonConfig::default()")," can be modified, by default the inputs and outputs are set to be on ",(0,a.kt)("inlineCode",{parentName:"p"},"Host")," for example."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"impl<'a> Default for PoseidonConfig<'a> {\n fn default() -> Self {\n let ctx = get_default_device_context();\n Self {\n ctx,\n are_inputs_on_device: false,\n are_outputs_on_device: false,\n input_is_a_state: false,\n aligned: false,\n loop_state: false,\n is_async: false,\n }\n }\n}\n")),(0,a.kt)("p",null,"In the example above ",(0,a.kt)("inlineCode",{parentName:"p"},"load_optimized_poseidon_constants::(arity, &ctx).unwrap();")," is used which will load the correct constants based on arity and curve. Its possible to ",(0,a.kt)("a",{parentName:"p",href:"#constants"},"generate")," your own constants and load them."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},'let ctx = get_default_device_context();\n let cargo_manifest_dir = env!("CARGO_MANIFEST_DIR");\n let constants_file = PathBuf::from(cargo_manifest_dir)\n .join("tests")\n .join(format!("{}_constants.bin", field_prefix));\n let mut constants_buf = vec![];\n File::open(constants_file)\n .unwrap()\n .read_to_end(&mut constants_buf)\n .unwrap();\n\n let mut custom_constants = vec![];\n for chunk in constants_buf.chunks(field_bytes) {\n custom_constants.push(F::from_bytes_le(chunk));\n }\n\n let custom_constants = create_optimized_poseidon_constants::(\n arity as u32,\n &ctx,\n full_rounds_half,\n partial_rounds,\n &mut custom_constants,\n )\n .unwrap();\n')),(0,a.kt)("p",null,"For more examples using different configurations refer here."),(0,a.kt)("h2",{id:"the-tree-builder"},"The Tree Builder"),(0,a.kt)("p",null,"The tree builder allows you to build Merkle trees using Poseidon. "),(0,a.kt)("p",null,"You can define both the tree's ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," and its ",(0,a.kt)("inlineCode",{parentName:"p"},"arity"),". The tree ",(0,a.kt)("inlineCode",{parentName:"p"},"height")," determines the number of layers in the tree, including the root and the leaf layer. The ",(0,a.kt)("inlineCode",{parentName:"p"},"arity")," determines how many children each internal node can have."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-rust"},'let height = 20;\nlet arity = 2;\nlet leaves = vec![F::one(); 1 << (height - 1)];\nlet mut digests = vec![F::zero(); merkle_tree_digests_len(height, arity)];\n\nlet mut leaves_slice = HostOrDeviceSlice::on_host(leaves);\n\nlet ctx = get_default_device_context();\nlet constants = load_optimized_poseidon_constants::(arity, &ctx).unwrap()\n\nlet mut config = TreeBuilderConfig::default();\nconfig.keep_rows = 1;\nbuild_poseidon_merkle_tree::(&mut leaves_slice, &mut digests, height, arity, &constants, &config).unwrap();\n\nprintln!("Root: {:?}", digests[0..1][0]);\n')),(0,a.kt)("p",null,"Similar to Poseidon, you can also configure the Tree Builder ",(0,a.kt)("inlineCode",{parentName:"p"},"TreeBuilderConfig::default()")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"keep_rows"),": The number of rows which will be written to output, 0 will write all rows."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"are_inputs_on_device"),": Have the inputs been loaded to device memory ?"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"is_async"),": Should the TreeBuilder run asynchronously? ",(0,a.kt)("inlineCode",{parentName:"li"},"False")," will block the current CPU thread. ",(0,a.kt)("inlineCode",{parentName:"li"},"True")," will require you call ",(0,a.kt)("inlineCode",{parentName:"li"},"cudaStreamSynchronize")," or ",(0,a.kt)("inlineCode",{parentName:"li"},"cudaDeviceSynchronize")," to retrieve the result.")),(0,a.kt)("h3",{id:"benchmarks"},"Benchmarks"),(0,a.kt)("p",null,"We ran the Poseidon tree builder on: "),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"CPU"),": 12th Gen Intel(R) Core(TM) i9-12900K/"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"GPU"),": RTX 3090 Ti"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Tree height"),": 30 (2^29 elements)"),(0,a.kt)("p",null,"The benchmarks include copying data from and to the device."),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Rows to keep parameter"),(0,a.kt)("th",{parentName:"tr",align:null},"Run time, Icicle"),(0,a.kt)("th",{parentName:"tr",align:null},"Supranational PC2"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"10"),(0,a.kt)("td",{parentName:"tr",align:null},"8.3 seconds"),(0,a.kt)("td",{parentName:"tr",align:null},"13.6 seconds")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"20"),(0,a.kt)("td",{parentName:"tr",align:null},"8.2 seconds"),(0,a.kt)("td",{parentName:"tr",align:null},"13.6 seconds")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"29"),(0,a.kt)("td",{parentName:"tr",align:null},"12.2 seconds"),(0,a.kt)("td",{parentName:"tr",align:null},"13.6 seconds")))))}c.isMDXComponent=!0},6757:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/image-1-5902a94e1680e802186934fdf8ff205e.png"},9836:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/image-2-943ff9b12b39ca32378f75f981ebfb7b.png"},3729:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/image-bff569244d897bcfcd16d979cb29fb9c.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file diff --git a/assets/js/076f2345.aced6b81.js b/assets/js/076f2345.e539f211.js similarity index 97% rename from assets/js/076f2345.aced6b81.js rename to assets/js/076f2345.e539f211.js index 3e4782a..0ee8c0e 100644 --- a/assets/js/076f2345.aced6b81.js +++ b/assets/js/076f2345.e539f211.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[131],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,f=d["".concat(c,".").concat(m)]||d[m]||u[m]||o;return n?r.createElement(f,i(i({ref:t},p),{},{components:n})):r.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var r=n(7462),a=(n(7294),n(3905));n(8209);const o={},i="ZKContainer",s={unversionedId:"ZKContainers",id:"ZKContainers",title:"ZKContainer",description:"We found that developing ZK provers with ICICLE gives developers the ability to scale ZK provers across many machines and many GPUs. To make this possible we developed the ZKContainer.",source:"@site/docs/ZKContainers.md",sourceDirName:".",slug:"/ZKContainers",permalink:"/ZKContainers",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/ZKContainers.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Run ICICLE on Google Colab",permalink:"/icicle/colab-instructions"},next:{title:"Ingonyama Grant programs",permalink:"/grants"}},c={},l=[{value:"What is a ZKContainer?",id:"what-is-a-zkcontainer",level:2}],p={toc:l},d="wrapper";function u(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,r.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"zkcontainer"},"ZKContainer"),(0,a.kt)("p",null,"We found that developing ZK provers with ICICLE gives developers the ability to scale ZK provers across many machines and many GPUs. To make this possible we developed the ZKContainer."),(0,a.kt)("h2",{id:"what-is-a-zkcontainer"},"What is a ZKContainer?"),(0,a.kt)("p",null,"A ZKContainer is an standardized, optimized and secure docker container that we configured with ICICLE applications in mind. A developer using our ZKContainer can deploy an ICICLE application on a single machine or on a thousand GPU machines in a data center with minimal concerns regarding compatibility."),(0,a.kt)("p",null,"ZKContainer has been used by Ingonyama clients to achieve scalability across large data centers.\nWe suggest you read our ",(0,a.kt)("a",{parentName:"p",href:"https://medium.com/@ingonyama/product-announcement-zk-containers-0e2a1f2d0a2b"},"article")," regarding ZKContainer to understand the benefits of using them."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"ZKContainer inside a ZK data center",src:n(4943).Z,width:"1400",height:"875"})))}u.isMDXComponent=!0},4943:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/architecture-zkcontainer-2bf99eb4700d652c0e85f8938a75f1ea.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[131],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var c=r.createContext({}),l=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),d=l(n),m=a,f=d["".concat(c,".").concat(m)]||d[m]||u[m]||o;return n?r.createElement(f,i(i({ref:t},p),{},{components:n})):r.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var r=n(7462),a=(n(7294),n(3905));n(8209);const o={},i="ZKContainer",s={unversionedId:"ZKContainers",id:"ZKContainers",title:"ZKContainer",description:"We found that developing ZK provers with ICICLE gives developers the ability to scale ZK provers across many machines and many GPUs. To make this possible we developed the ZKContainer.",source:"@site/docs/ZKContainers.md",sourceDirName:".",slug:"/ZKContainers",permalink:"/ZKContainers",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/ZKContainers.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Run ICICLE on Google Colab",permalink:"/icicle/colab-instructions"},next:{title:"Ingonyama Grant programs",permalink:"/grants"}},c={},l=[{value:"What is a ZKContainer?",id:"what-is-a-zkcontainer",level:2}],p={toc:l},d="wrapper";function u(e){let{components:t,...o}=e;return(0,a.kt)(d,(0,r.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"zkcontainer"},"ZKContainer"),(0,a.kt)("p",null,"We found that developing ZK provers with ICICLE gives developers the ability to scale ZK provers across many machines and many GPUs. To make this possible we developed the ZKContainer."),(0,a.kt)("h2",{id:"what-is-a-zkcontainer"},"What is a ZKContainer?"),(0,a.kt)("p",null,"A ZKContainer is an standardized, optimized and secure docker container that we configured with ICICLE applications in mind. A developer using our ZKContainer can deploy an ICICLE application on a single machine or on a thousand GPU machines in a data center with minimal concerns regarding compatibility."),(0,a.kt)("p",null,"ZKContainer has been used by Ingonyama clients to achieve scalability across large data centers.\nWe suggest you read our ",(0,a.kt)("a",{parentName:"p",href:"https://medium.com/@ingonyama/product-announcement-zk-containers-0e2a1f2d0a2b"},"article")," regarding ZKContainer to understand the benefits of using them."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"ZKContainer inside a ZK data center",src:n(4943).Z,width:"1400",height:"875"})))}u.isMDXComponent=!0},4943:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/architecture-zkcontainer-2bf99eb4700d652c0e85f8938a75f1ea.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file diff --git a/assets/js/0dca48ed.bfa3c731.js b/assets/js/0dca48ed.55ac5a02.js similarity index 98% rename from assets/js/0dca48ed.bfa3c731.js rename to assets/js/0dca48ed.55ac5a02.js index d59ef54..1bdd08f 100644 --- a/assets/js/0dca48ed.bfa3c731.js +++ b/assets/js/0dca48ed.55ac5a02.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[67],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),g=a,h=u["".concat(s,".").concat(g)]||u[g]||d[g]||i;return n?r.createElement(h,o(o({ref:t},p),{},{components:n})):r.createElement(h,o({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));n(8209);const i={},o="ICICLE integrated provers",l={unversionedId:"icicle/integrations",id:"icicle/integrations",title:"ICICLE integrated provers",description:"ICICLE has been used by companies like Celer Network, Gnark and others to accelerate their ZK proving pipeline.",source:"@site/docs/icicle/integrations.md",sourceDirName:"icicle",slug:"/icicle/integrations",permalink:"/icicle/integrations",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/integrations.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Getting started with ICICLE",permalink:"/icicle/introduction"},next:{title:"Golang bindings",permalink:"/icicle/golang-bindings"}},s={},c=[{value:"A primer to building your own integrations",id:"a-primer-to-building-your-own-integrations",level:2},{value:"Using ICICLE integrated provers",id:"using-icicle-integrated-provers",level:2},{value:"Gnark",id:"gnark",level:3},{value:"Halo2",id:"halo2",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...i}=e;return(0,a.kt)(u,(0,r.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"icicle-integrated-provers"},"ICICLE integrated provers"),(0,a.kt)("p",null,"ICICLE has been used by companies like ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/celer-network"},"Celer Network"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark")," and others to accelerate their ZK proving pipeline."),(0,a.kt)("p",null,"Many of these integrations have been a collaboration between Ingonyama and the integrating company. We have learned a lot about designing GPU based ZK provers."),(0,a.kt)("p",null,"If you're interested in understanding these integrations better or learning how you can use ICICLE to accelerate your existing ZK proving pipeline this is the place for you."),(0,a.kt)("h2",{id:"a-primer-to-building-your-own-integrations"},"A primer to building your own integrations"),(0,a.kt)("p",null,"Lets illustrate an ICICLE integration, so you can understand the core API and design overview of ICICLE."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"ICICLE architecture",src:n(2547).Z,width:"906",height:"878"})),(0,a.kt)("p",null,"Engineers usually use a cryptography library to implement their ZK protocols. These libraries implement efficient primitives which are used as building blocks for the protocol; ICICLE is such a library. The difference is that ICICLE is designed from the start to run on GPUs; the Rust and Golang APIs abstract away all low level CUDA details. Our goal was to allow developers with no GPU experience to quickly get started with ICICLE."),(0,a.kt)("p",null,"A developer may use ICICLE with two main approaches in mind."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Drop in replacement approach."),(0,a.kt)("li",{parentName:"ol"},"Full GPU replacement approach.")),(0,a.kt)("p",null,"The first approach for GPU-accelerating your Prover with ICICLE is quick to implement, but it has limitations, such as reduced memory optimization and limited protocol tuning for GPUs. It's a solid starting point, but those committed to fully leveraging GPU acceleration should consider a more comprehensive approach."),(0,a.kt)("p",null,"A full GPU replacement means performing the entire ZK proof on the GPU. This approach will reduce latency to a minimum and requires you to change the way you implement the protocol to be more GPU friendly. This approach will take full advantage of GPU acceleration. Redesigning your prover this way may take more engineering effort but we promise you that its worth it!"),(0,a.kt)("h2",{id:"using-icicle-integrated-provers"},"Using ICICLE integrated provers"),(0,a.kt)("p",null,"Here we cover how a developer can run existing circuits on ICICLE integrated provers."),(0,a.kt)("h3",{id:"gnark"},"Gnark"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark")," officially supports GPU proving with ICICLE. Currently only Groth16 on curve ",(0,a.kt)("inlineCode",{parentName:"p"},"BN254")," is supported. This means that if you are currently using Gnark to write your circuits you can enjoy GPU acceleration without making many changes."),(0,a.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"Currently ICICLE has been merged to Gnark ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"master branch"),", however the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark/releases/tag/v0.9.1"},"latest release")," is from October 2023."))),(0,a.kt)("p",null,"Make sure your golang circuit project has ",(0,a.kt)("inlineCode",{parentName:"p"},"gnark")," as a dependency and that you are using the master branch for now."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"go get github.com/consensys/gnark@master\n")),(0,a.kt)("p",null,"You should see two indirect dependencies added."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n github.com/ingonyama-zk/icicle v0.1.0 // indirect\n github.com/ingonyama-zk/iciclegnark v0.1.1 // indirect\n...\n")),(0,a.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"As you may notice we are using ICICLE v0.1 here since golang bindings are only support in ICICLE v0.1 for the time being."))),(0,a.kt)("p",null,"To switch over to ICICLE proving, make sure to change the backend you are using, below is an example of how this should be done."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"// toggle on\nproofIci, err := groth16.Prove(ccs, pk, secretWitness, backend.WithIcicleAcceleration())\n\n// toggle off\nproof, err := groth16.Prove(ccs, pk, secretWitness)\n")),(0,a.kt)("p",null,"Now that you have enabled ",(0,a.kt)("inlineCode",{parentName:"p"},"WithIcicleAcceleration")," backend simple change the way your run your circuits to:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"go run -tags=icicle main.go\n")),(0,a.kt)("p",null,"Your logs should look something like this if everything went as expected."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"13:12:05 INF compiling circuit\n13:12:05 INF parsed circuit inputs nbPublic=1 nbSecret=1\n13:12:05 INF building constraint builder nbConstraints=3\n13:12:05 DBG precomputing proving key in GPU acceleration=icicle backend=groth16 curve=bn254 nbConstraints=3\n13:12:05 DBG constraint system solver done nbConstraints=3 took=0.070259\n13:12:05 DBG prover done acceleration=icicle backend=groth16 curve=bn254 nbConstraints=3 took=80.356684\n13:12:05 DBG verifier done backend=groth16 curve=bn254 took=1.843888\n")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"acceleration=icicle")," indicates that the prover is running in acceleration mode with ICICLE."),(0,a.kt)("p",null,"You can reference the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark?tab=readme-ov-file#gpu-support"},"Gnark docs")," for further information."),(0,a.kt)("h3",{id:"halo2"},"Halo2"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/zkonduit/halo2"},"Halo2")," fork integrated with ICICLE for GPU acceleration. This means that you can run your existing Halo2 circuits with GPU acceleration just by activating a feature flag."),(0,a.kt)("p",null,"To enable GPU acceleration just enable ",(0,a.kt)("inlineCode",{parentName:"p"},"icicle_gpu")," ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/zkonduit/halo2/blob/3d7b5e61b3052680ccb279e05bdcc21dd8a8fedf/halo2_proofs/Cargo.toml#L102"},"feature flag"),"."),(0,a.kt)("p",null,"This feature flag will seamlessly toggle on GPU acceleration for you."))}d.isMDXComponent=!0},2547:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/architecture-high-level-3c1ae0f257c7921b77378aa3daaab41c.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[67],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(n),g=a,h=u["".concat(s,".").concat(g)]||u[g]||d[g]||i;return n?r.createElement(h,o(o({ref:t},p),{},{components:n})):r.createElement(h,o({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=g;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));n(8209);const i={},o="ICICLE integrated provers",l={unversionedId:"icicle/integrations",id:"icicle/integrations",title:"ICICLE integrated provers",description:"ICICLE has been used by companies like Celer Network, Gnark and others to accelerate their ZK proving pipeline.",source:"@site/docs/icicle/integrations.md",sourceDirName:"icicle",slug:"/icicle/integrations",permalink:"/icicle/integrations",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/integrations.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Getting started with ICICLE",permalink:"/icicle/introduction"},next:{title:"Golang bindings",permalink:"/icicle/golang-bindings"}},s={},c=[{value:"A primer to building your own integrations",id:"a-primer-to-building-your-own-integrations",level:2},{value:"Using ICICLE integrated provers",id:"using-icicle-integrated-provers",level:2},{value:"Gnark",id:"gnark",level:3},{value:"Halo2",id:"halo2",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...i}=e;return(0,a.kt)(u,(0,r.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"icicle-integrated-provers"},"ICICLE integrated provers"),(0,a.kt)("p",null,"ICICLE has been used by companies like ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/celer-network"},"Celer Network"),", ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark")," and others to accelerate their ZK proving pipeline."),(0,a.kt)("p",null,"Many of these integrations have been a collaboration between Ingonyama and the integrating company. We have learned a lot about designing GPU based ZK provers."),(0,a.kt)("p",null,"If you're interested in understanding these integrations better or learning how you can use ICICLE to accelerate your existing ZK proving pipeline this is the place for you."),(0,a.kt)("h2",{id:"a-primer-to-building-your-own-integrations"},"A primer to building your own integrations"),(0,a.kt)("p",null,"Lets illustrate an ICICLE integration, so you can understand the core API and design overview of ICICLE."),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"ICICLE architecture",src:n(2547).Z,width:"906",height:"878"})),(0,a.kt)("p",null,"Engineers usually use a cryptography library to implement their ZK protocols. These libraries implement efficient primitives which are used as building blocks for the protocol; ICICLE is such a library. The difference is that ICICLE is designed from the start to run on GPUs; the Rust and Golang APIs abstract away all low level CUDA details. Our goal was to allow developers with no GPU experience to quickly get started with ICICLE."),(0,a.kt)("p",null,"A developer may use ICICLE with two main approaches in mind."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Drop in replacement approach."),(0,a.kt)("li",{parentName:"ol"},"Full GPU replacement approach.")),(0,a.kt)("p",null,"The first approach for GPU-accelerating your Prover with ICICLE is quick to implement, but it has limitations, such as reduced memory optimization and limited protocol tuning for GPUs. It's a solid starting point, but those committed to fully leveraging GPU acceleration should consider a more comprehensive approach."),(0,a.kt)("p",null,"A full GPU replacement means performing the entire ZK proof on the GPU. This approach will reduce latency to a minimum and requires you to change the way you implement the protocol to be more GPU friendly. This approach will take full advantage of GPU acceleration. Redesigning your prover this way may take more engineering effort but we promise you that its worth it!"),(0,a.kt)("h2",{id:"using-icicle-integrated-provers"},"Using ICICLE integrated provers"),(0,a.kt)("p",null,"Here we cover how a developer can run existing circuits on ICICLE integrated provers."),(0,a.kt)("h3",{id:"gnark"},"Gnark"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark")," officially supports GPU proving with ICICLE. Currently only Groth16 on curve ",(0,a.kt)("inlineCode",{parentName:"p"},"BN254")," is supported. This means that if you are currently using Gnark to write your circuits you can enjoy GPU acceleration without making many changes."),(0,a.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"Currently ICICLE has been merged to Gnark ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"master branch"),", however the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark/releases/tag/v0.9.1"},"latest release")," is from October 2023."))),(0,a.kt)("p",null,"Make sure your golang circuit project has ",(0,a.kt)("inlineCode",{parentName:"p"},"gnark")," as a dependency and that you are using the master branch for now."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"go get github.com/consensys/gnark@master\n")),(0,a.kt)("p",null,"You should see two indirect dependencies added."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n github.com/ingonyama-zk/icicle v0.1.0 // indirect\n github.com/ingonyama-zk/iciclegnark v0.1.1 // indirect\n...\n")),(0,a.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"As you may notice we are using ICICLE v0.1 here since golang bindings are only support in ICICLE v0.1 for the time being."))),(0,a.kt)("p",null,"To switch over to ICICLE proving, make sure to change the backend you are using, below is an example of how this should be done."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"// toggle on\nproofIci, err := groth16.Prove(ccs, pk, secretWitness, backend.WithIcicleAcceleration())\n\n// toggle off\nproof, err := groth16.Prove(ccs, pk, secretWitness)\n")),(0,a.kt)("p",null,"Now that you have enabled ",(0,a.kt)("inlineCode",{parentName:"p"},"WithIcicleAcceleration")," backend simple change the way your run your circuits to:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"go run -tags=icicle main.go\n")),(0,a.kt)("p",null,"Your logs should look something like this if everything went as expected."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"13:12:05 INF compiling circuit\n13:12:05 INF parsed circuit inputs nbPublic=1 nbSecret=1\n13:12:05 INF building constraint builder nbConstraints=3\n13:12:05 DBG precomputing proving key in GPU acceleration=icicle backend=groth16 curve=bn254 nbConstraints=3\n13:12:05 DBG constraint system solver done nbConstraints=3 took=0.070259\n13:12:05 DBG prover done acceleration=icicle backend=groth16 curve=bn254 nbConstraints=3 took=80.356684\n13:12:05 DBG verifier done backend=groth16 curve=bn254 took=1.843888\n")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"acceleration=icicle")," indicates that the prover is running in acceleration mode with ICICLE."),(0,a.kt)("p",null,"You can reference the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark?tab=readme-ov-file#gpu-support"},"Gnark docs")," for further information."),(0,a.kt)("h3",{id:"halo2"},"Halo2"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/zkonduit/halo2"},"Halo2")," fork integrated with ICICLE for GPU acceleration. This means that you can run your existing Halo2 circuits with GPU acceleration just by activating a feature flag."),(0,a.kt)("p",null,"To enable GPU acceleration just enable ",(0,a.kt)("inlineCode",{parentName:"p"},"icicle_gpu")," ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/zkonduit/halo2/blob/3d7b5e61b3052680ccb279e05bdcc21dd8a8fedf/halo2_proofs/Cargo.toml#L102"},"feature flag"),"."),(0,a.kt)("p",null,"This feature flag will seamlessly toggle on GPU acceleration for you."))}d.isMDXComponent=!0},2547:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/architecture-high-level-3c1ae0f257c7921b77378aa3daaab41c.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file diff --git a/assets/js/0ec3cab9.2180a8ed.js b/assets/js/0ec3cab9.e355dffd.js similarity index 99% rename from assets/js/0ec3cab9.2180a8ed.js rename to assets/js/0ec3cab9.e355dffd.js index c6dab9d..a733b6b 100644 --- a/assets/js/0ec3cab9.2180a8ed.js +++ b/assets/js/0ec3cab9.e355dffd.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[862],{3905:(a,e,t)=>{t.d(e,{Zo:()=>N,kt:()=>h});var s=t(7294);function n(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function m(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(a);e&&(s=s.filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),t.push.apply(t,s)}return t}function p(a){for(var e=1;e=0||(n[t]=a[t]);return n}(a,e);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(a);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(a,t)&&(n[t]=a[t])}return n}var i=s.createContext({}),l=function(a){var e=s.useContext(i),t=e;return a&&(t="function"==typeof a?a(e):p(p({},e),a)),t},N=function(a){var e=l(a.components);return s.createElement(i.Provider,{value:e},a.children)},o="mdxType",k={inlineCode:"code",wrapper:function(a){var e=a.children;return s.createElement(s.Fragment,{},e)}},c=s.forwardRef((function(a,e){var t=a.components,n=a.mdxType,m=a.originalType,i=a.parentName,N=r(a,["components","mdxType","originalType","parentName"]),o=l(t),c=n,h=o["".concat(i,".").concat(c)]||o[c]||k[c]||m;return t?s.createElement(h,p(p({ref:e},N),{},{components:t})):s.createElement(h,p({ref:e},N))}));function h(a,e){var t=arguments,n=e&&e.mdxType;if("string"==typeof a||n){var m=t.length,p=new Array(m);p[0]=c;var r={};for(var i in e)hasOwnProperty.call(e,i)&&(r[i]=e[i]);r.originalType=a,r[o]="string"==typeof a?a:n,p[1]=r;for(var l=2;l{t.r(e),t.d(e,{assets:()=>i,contentTitle:()=>p,default:()=>k,frontMatter:()=>m,metadata:()=>r,toc:()=>l});var s=t(7462),n=(t(7294),t(3905));t(8209);const m={},p="NTT - Number Theoretic Transform",r={unversionedId:"icicle/primitives/ntt",id:"icicle/primitives/ntt",title:"NTT - Number Theoretic Transform",description:"The Number Theoretic Transform (NTT) is a variant of the Fourier Transform used over finite fields or rings, particularly those of integers modulo a prime number. NTT operates in a discrete domain and is used primarily in applications requiring modular arithmetic, such as cryptography and polynomial multiplication.",source:"@site/docs/icicle/primitives/ntt.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/ntt",permalink:"/icicle/primitives/ntt",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/ntt.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Poseidon",permalink:"/icicle/primitives/poseidon"},next:{title:"Supporting Additional Curves",permalink:"/icicle/supporting-additional-curves"}},i={},l=[{value:"Supported curves",id:"supported-curves",level:3},{value:"Examples",id:"examples",level:3},{value:"NTT API overview",id:"ntt-api-overview",level:2},{value:"NTT Config",id:"ntt-config",level:3},{value:"Fields",id:"fields",level:4},{value:"Usage",id:"usage",level:4},{value:"Ordering",id:"ordering",level:3},{value:"Modes",id:"modes",level:3},{value:"Supported algorithms",id:"supported-algorithms",level:2},{value:"Radix 2",id:"radix-2",level:3},{value:"Mixed Radix",id:"mixed-radix",level:3},{value:"Which algorithm should I choose ?",id:"which-algorithm-should-i-choose-",level:3}],N={toc:l},o="wrapper";function k(a){let{components:e,...t}=a;return(0,n.kt)(o,(0,s.Z)({},N,t,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"ntt---number-theoretic-transform"},"NTT - Number Theoretic Transform"),(0,n.kt)("p",null,"The Number Theoretic Transform (NTT) is a variant of the Fourier Transform used over finite fields or rings, particularly those of integers modulo a prime number. NTT operates in a discrete domain and is used primarily in applications requiring modular arithmetic, such as cryptography and polynomial multiplication."),(0,n.kt)("p",null,"NTT is defined similarly to the Discrete Fourier Transform (DFT), but instead of using complex roots of unity, it uses roots of unity within a finite field. The definition hinges on the properties of the finite field, specifically the existence of a primitive root of unity of order ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," (where ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is typically a power of 2), and the modulo operation is performed with respect to a specific prime number that supports these roots."),(0,n.kt)("p",null,"Formally, given a sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, a_1, ..., a_{N-1}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6389em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"..."),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", the NTT of this sequence is another sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_0, A_1, ..., A_{N-1}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8917em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"..."),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", computed as follows:"),(0,n.kt)("div",{className:"math math-display"},(0,n.kt)("span",{parentName:"div",className:"katex-display"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("munderover",{parentName:"mrow"},(0,n.kt)("mo",{parentName:"munderover"},"\u2211"),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"n"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mn",{parentName:"mrow"},"0")),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1"))),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mi",{parentName:"msub"},"n")),(0,n.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"\u03c9"),(0,n.kt)("mrow",{parentName:"msup"},(0,n.kt)("mi",{parentName:"mrow"},"n"),(0,n.kt)("mi",{parentName:"mrow"},"k"))),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"1em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_k = \\sum_{n=0}^{N-1} a_n \\cdot \\omega^{nk} \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"3.0954em",verticalAlign:"-1.2671em"}}),(0,n.kt)("span",{parentName:"span",className:"mop op-limits"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-1.8829em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"n"),(0,n.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span"},(0,n.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,n.kt)("span",{parentName:"span",style:{top:"-4.3em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.2671em"}},(0,n.kt)("span",{parentName:"span"}))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.1514em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"n")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8991em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8991em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"nk"))))))))),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"1em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))),(0,n.kt)("p",null,"where:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is the size of the input sequence and is a power of 2,"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," is a prime number such that ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"+"),(0,n.kt)("mn",{parentName:"mrow"},"1")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p = kN + 1")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"1")))))," for some integer ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"))))),", ensuring that ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," supports the existence of ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"))))),"th roots of unity,"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"\u03c9")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\omega")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9")))))," is a primitive ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"))))),"th root of unity modulo ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p"))))),", meaning ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"\u03c9"),(0,n.kt)("mi",{parentName:"msup"},"N")),(0,n.kt)("mo",{parentName:"mrow"},"\u2261"),(0,n.kt)("mn",{parentName:"mrow"},"1"),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"0.6667em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\omega^N \\equiv 1 \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8413em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8413em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.063em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N")))))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"\u2261"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"1"),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.6667em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," and no smaller positive power of ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"\u03c9")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\omega")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9")))))," is congruent to 1 modulo ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p"))))),","),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k")))))," ranges from 0 to ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N-1")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"1"))))),", and it indexes the output sequence.")),(0,n.kt)("p",null,"The NTT is particularly useful because it enables efficient polynomial multiplication under modulo arithmetic, crucial for algorithms in cryptographic protocols, and other areas requiring fast modular arithmetic operations. "),(0,n.kt)("p",null,"There exists also INTT which is the inverse operation of NTT. INTT can take as input an output sequence of integers from an NTT and reconstruct the original sequence."),(0,n.kt)("h1",{id:"using-ntt"},"Using NTT"),(0,n.kt)("h3",{id:"supported-curves"},"Supported curves"),(0,n.kt)("p",null,"NTT supports the following curves:"),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"bls12-377"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"bls12-381"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"bn-254"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"bw6-761")),(0,n.kt)("h3",{id:"examples"},"Examples"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/d84ffd2679a4cb8f8d1ac2ad2897bc0b95f4eeeb/examples/rust/ntt/src/main.rs#L1"},"Rust API examples"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/d84ffd2679a4cb8f8d1ac2ad2897bc0b95f4eeeb/examples/c%2B%2B/ntt/example.cu#L1"},"C++ API examples")))),(0,n.kt)("h2",{id:"ntt-api-overview"},"NTT API overview"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn ntt(\n input: &HostOrDeviceSlice,\n dir: NTTDir,\n cfg: &NTTConfig,\n output: &mut HostOrDeviceSlice,\n) -> IcicleResult<()>\n")),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"ntt:ntt")," expects:"),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"input")," - buffer to read the inputs of the NTT from. ",(0,n.kt)("br",null),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"dir")," - whether to compute forward or inverse NTT. ",(0,n.kt)("br",null),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"cfg")," - config used to specify extra arguments of the NTT. ",(0,n.kt)("br",null),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"output")," - buffer to write the NTT outputs into. Must be of the same size as input."),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"input")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"output")," buffers can be on device or on host. Being on host means that they will be transferred to device during runtime."),(0,n.kt)("h3",{id:"ntt-config"},"NTT Config"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"pub struct NTTConfig<'a, S> {\n pub ctx: DeviceContext<'a>,\n pub coset_gen: S,\n pub batch_size: i32,\n pub ordering: Ordering,\n are_inputs_on_device: bool, \n are_outputs_on_device: bool,\n pub is_async: bool,\n pub ntt_algorithm: NttAlgorithm,\n}\n")),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"NTTConfig")," struct is a configuration object used to specify parameters for an NTT instance."),(0,n.kt)("h4",{id:"fields"},"Fields"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"ctx: DeviceContext<'a>")),": Specifies the device context, including the device ID and the stream ID.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"coset_gen: S")),": Defines the coset generator used for coset (i)NTTs. By default, this is set to ",(0,n.kt)("inlineCode",{parentName:"p"},"S::one()"),", indicating that no coset is being used.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"batch_size: i32")),": Determines the number of NTTs to compute in a single batch. The default value is 1, meaning that operations are performed on individual inputs without batching. Batch processing can significantly improve performance by leveraging parallelism in GPU computations.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"ordering: Ordering")),": Controls the ordering of inputs and outputs for the NTT operation. This field can be used to specify decimation strategies (in time or in frequency) and the type of butterfly algorithm (Cooley-Tukey or Gentleman-Sande). The ordering is crucial for compatibility with various algorithmic approaches and can impact the efficiency of the NTT.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"are_inputs_on_device: bool")),": Indicates whether the input data has been preloaded on the device memory. If ",(0,n.kt)("inlineCode",{parentName:"p"},"false")," inputs will be copied from host to device.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"are_outputs_on_device: bool")),": Indicates whether the output data is preloaded in device memory. If ",(0,n.kt)("inlineCode",{parentName:"p"},"false")," outputs will be copied from host to device. If the inputs and outputs are the same pointer NTT will be computed in place.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"is_async: bool")),": Specifies whether the NTT operation should be performed asynchronously. When set to ",(0,n.kt)("inlineCode",{parentName:"p"},"true"),", the NTT function will not block the CPU, allowing other operations to proceed concurrently. Asynchronous execution requires careful synchronization to ensure data integrity and correctness.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"ntt_algorithm: NttAlgorithm")),": Can be one of ",(0,n.kt)("inlineCode",{parentName:"p"},"Auto"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"Radix2"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"MixedRadix"),".\n",(0,n.kt)("inlineCode",{parentName:"p"},"Auto")," will select ",(0,n.kt)("inlineCode",{parentName:"p"},"Radix 2")," or ",(0,n.kt)("inlineCode",{parentName:"p"},"Mixed Radix")," algorithm based on heuristics.\n",(0,n.kt)("inlineCode",{parentName:"p"},"Radix2")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"MixedRadix")," will force the use of an algorithm regardless of the input size or other considerations. You should use one of these options when you know for sure that you want to "))),(0,n.kt)("h4",{id:"usage"},"Usage"),(0,n.kt)("p",null,"Example initialization with default settings:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"let default_config = NTTConfig::default();\n")),(0,n.kt)("p",null,"Customizing the configuration:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"let custom_config = NTTConfig {\n ctx: custom_device_context,\n coset_gen: my_coset_generator,\n batch_size: 10,\n ordering: Ordering::kRN,\n are_inputs_on_device: true,\n are_outputs_on_device: true,\n is_async: false,\n ntt_algorithm: NttAlgorithm::MixedRadix,\n};\n")),(0,n.kt)("h3",{id:"ordering"},"Ordering"),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"Ordering")," enum defines how inputs and outputs are arranged for the NTT operation, offering flexibility in handling data according to different algorithmic needs or compatibility requirements. It primarily affects the sequencing of data points for the transform, which can influence both performance and the compatibility with certain algorithmic approaches. The available ordering options are:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kNN")," (Natural-Natural):")," Both inputs and outputs are in their natural order. This is the simplest form of ordering, where data is processed in the sequence it is given, without any rearrangement.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kNR")," (Natural-Reversed):")," Inputs are in natural order, while outputs are in bit-reversed order. This ordering is typically used in algorithms that benefit from having the output in a bit-reversed pattern.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kRN")," (Reversed-Natural):")," Inputs are in bit-reversed order, and outputs are in natural order. This is often used with the Cooley-Tukey FFT algorithm.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kRR")," (Reversed-Reversed):")," Both inputs and outputs are in bit-reversed order.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kNM")," (Natural-Mixed):")," Inputs are provided in their natural order, while outputs are arranged in a digit-reversed (mixed) order. This ordering is good for mixed radix NTT operations, where the mixed or digit-reversed ordering of outputs is a generalization of the bit-reversal pattern seen in simpler, radix-2 cases.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kMN")," (Mixed-Natural):")," Inputs are in a digit-reversed (mixed) order, while outputs are restored to their natural order. This ordering would primarily be used for mixed radix NTT"))),(0,n.kt)("p",null,"Choosing an algorithm is heavily dependent on your use case. For example Cooley-Tukey will often use ",(0,n.kt)("inlineCode",{parentName:"p"},"kRN")," and Gentleman-Sande often uses ",(0,n.kt)("inlineCode",{parentName:"p"},"kNR"),"."),(0,n.kt)("h3",{id:"modes"},"Modes"),(0,n.kt)("p",null,"NTT also supports two different modes ",(0,n.kt)("inlineCode",{parentName:"p"},"Batch NTT")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"Single NTT")),(0,n.kt)("p",null,"Batch NTT allows you to run many NTTs with a single API call, Single MSM will launch a single MSM computation."),(0,n.kt)("p",null,"You may toggle between single and batch NTT by simply configure ",(0,n.kt)("inlineCode",{parentName:"p"},"batch_size")," to be larger then 1 in your ",(0,n.kt)("inlineCode",{parentName:"p"},"NTTConfig"),"."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"let mut cfg = ntt::get_default_ntt_config::();\ncfg.batch_size = 10 // your ntt using this config will run in batch mode.\n")),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"batch_size=1")," would keep our NTT in single NTT mode."),(0,n.kt)("p",null,"Deciding weather to use ",(0,n.kt)("inlineCode",{parentName:"p"},"batch NTT")," vs ",(0,n.kt)("inlineCode",{parentName:"p"},"single NTT")," is highly dependent on your application and use case."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Single NTT Mode")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Choose this mode when your application requires processing individual NTT operations in isolation.")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Batch NTT Mode")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Batch NTT mode can significantly reduce read/write as well as computation overhead by executing multiple NTT operations in parallel.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Batch mode may also offer better utilization of computational resources (memory and compute)."))),(0,n.kt)("h2",{id:"supported-algorithms"},"Supported algorithms"),(0,n.kt)("p",null,"Our NTT implementation supports two algorithms ",(0,n.kt)("inlineCode",{parentName:"p"},"radix-2")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"mixed-radix"),"."),(0,n.kt)("h3",{id:"radix-2"},"Radix 2"),(0,n.kt)("p",null,'At its core, the Radix-2 NTT algorithm divides the problem into smaller sub-problems, leveraging the properties of "divide and conquer" to reduce the overall computational complexity. The algorithm operates on sequences whose lengths are powers of two.'),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Input Preparation:"),"\nThe input is a sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mo",{parentName:"mrow"},"\u2026"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1"))),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mtext",{parentName:"mrow"},"\xa0where\xa0"),(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, a_1, \\ldots, a_{N-1}, \\text{ where } N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9028em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"minner"},"\u2026"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord text"},(0,n.kt)("span",{parentName:"span",className:"mord"},"\xa0where\xa0")),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is a power of two.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Recursive Decomposition:"),"\nThe algorithm recursively divides the input sequence into smaller sequences. At each step, it separates the sequence into even-indexed and odd-indexed elements, forming two subsequences that are then processed independently.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Butterfly Operations:"),'\nThe core computational element of the Radix-2 NTT is the "butterfly" operation, which combines pairs of elements from the sequences obtained in the decomposition step. '),(0,n.kt)("p",{parentName:"li"},'Each butterfly operation involves multiplication by a "twiddle factor," which is a root of unity in the finite field, and addition or subtraction of the results, all performed modulo the prime modulus.'),(0,n.kt)("div",{parentName:"li",className:"math math-display"},(0,n.kt)("span",{parentName:"div",className:"katex-display"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"+"),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"B"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"W"),(0,n.kt)("mi",{parentName:"msup"},"k")),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"1em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_k = (A_k + B_k \\cdot W^k) \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,n.kt)("span",{parentName:"span",className:"mopen"},"("),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05017em"}},"B"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0502em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"1.1491em",verticalAlign:"-0.25em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"W"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8991em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))))))),(0,n.kt)("span",{parentName:"span",className:"mclose"},")"),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"1em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mi",{parentName:"msub"},"k"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," - The output of the butterfly operation for the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"))))),"-th element"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mi",{parentName:"msub"},"k"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," - an element from the even-indexed subset"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"B"),(0,n.kt)("mi",{parentName:"msub"},"k"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"B_k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05017em"}},"B"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0502em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," - an element from the odd-indexed subset"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," - prime modulus"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k")))))," - The index of the current operation within the butterfly or the transform stage"))),(0,n.kt)("p",null," The twiddle factors are precomputed to save runtime and improve performance."),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Bit-Reversal Permutation:"),"\nA final step involves rearranging the output sequence into the correct order. Due to the halving process in the decomposition steps, the elements of the transformed sequence are initially in a bit-reversed order. A bit-reversal permutation is applied to obtain the final sequence in natural order.")),(0,n.kt)("h3",{id:"mixed-radix"},"Mixed Radix"),(0,n.kt)("p",null,'The Mixed Radix NTT algorithm extends the concepts of the Radix-2 algorithm by allowing the decomposition of the input sequence based on various factors of its length. Specifically ICICLEs implementation splits the input into blocks of sizes 16,32,64 compared to radix2 which is always splitting such that we end with NTT of size 2. This approach offers enhanced flexibility and efficiency, especially for input sizes that are composite numbers, by leveraging the "divide and conquer" strategy across multiple radixes.'),(0,n.kt)("p",null,"The NTT blocks in Mixed Radix are implemented more efficiently based on winograd NTT but also optimized memory and register usage is better compared to Radix-2."),(0,n.kt)("p",null,"Mixed Radix can reduce the number of stages required to compute for large inputs."),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Input Preparation:"),"\nThe input to the Mixed Radix NTT is a sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mo",{parentName:"mrow"},"\u2026"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, a_1, \\ldots, a_{N-1}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6389em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"minner"},"\u2026"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", where ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is not strictly required to be a power of two. Instead, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," can be any composite number, ideally factorized into primes or powers of primes.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Factorization and Decomposition:"),"\nUnlike the Radix-2 algorithm, which strictly divides the computational problem into halves, the Mixed Radix NTT algorithm implements a flexible decomposition approach which isn't limited to prime factorization. "),(0,n.kt)("p",{parentName:"li"},"For example, an NTT of size 256 can be decomposed into two stages of ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mn",{parentName:"mrow"},"16"),(0,n.kt)("mo",{parentName:"mrow"},"\xd7"),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mtext",{parentName:"msub"},"NTT"),(0,n.kt)("mn",{parentName:"msub"},"16"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"16 \\times \\text{NTT}_{16}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7278em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"16"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\xd7"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord text"},(0,n.kt)("span",{parentName:"span",className:"mord"},"NTT")),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"16"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", leveraging a composite factorization strategy rather than decomposing into eight stages of ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mtext",{parentName:"msub"},"NTT"),(0,n.kt)("mn",{parentName:"msub"},"2"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{NTT}_{2}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord text"},(0,n.kt)("span",{parentName:"span",className:"mord"},"NTT")),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"2"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))))))),". This exemplifies the use of composite factors (in this case, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mn",{parentName:"mrow"},"256"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mn",{parentName:"mrow"},"16"),(0,n.kt)("mo",{parentName:"mrow"},"\xd7"),(0,n.kt)("mn",{parentName:"mrow"},"16")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"256 = 16 \\times 16")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"256"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7278em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"16"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\xd7"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"16"))))),") to apply smaller NTT transforms, optimizing computational efficiency by adapting the decomposition strategy to the specific structure of ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"))))),".")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Butterfly Operations with Multiple Radixes:"),"\nThe Mixed Radix algorithm utilizes butterfly operations for various radix sizes. Each sub-transform involves specific butterfly operations characterized by multiplication with twiddle factors appropriate for the radix in question."),(0,n.kt)("p",{parentName:"li"},"The generalized butterfly operation for a radix-",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"r")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"r")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," element can be expressed as:"),(0,n.kt)("div",{parentName:"li",className:"math math-display"},(0,n.kt)("span",{parentName:"div",className:"katex-display"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"r"))),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("munderover",{parentName:"mrow"},(0,n.kt)("mo",{parentName:"munderover"},"\u2211"),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mn",{parentName:"mrow"},"0")),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"r"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1"))),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"k"))),(0,n.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"W"),(0,n.kt)("mrow",{parentName:"msup"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mi",{parentName:"mrow"},"k"))),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"1em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_{k,r} = \\sum_{j=0}^{r-1} (A_{j,k} \\cdot W^{jk}) \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02778em"}},"r"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"3.2149em",verticalAlign:"-1.4138em"}}),(0,n.kt)("span",{parentName:"span",className:"mop op-limits"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-1.8723em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span"},(0,n.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,n.kt)("span",{parentName:"span",style:{top:"-4.3em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02778em"}},"r"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.4138em"}},(0,n.kt)("span",{parentName:"span"}))))),(0,n.kt)("span",{parentName:"span",className:"mopen"},"("),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"1.1491em",verticalAlign:"-0.25em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"W"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8991em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"jk"))))))))),(0,n.kt)("span",{parentName:"span",className:"mclose"},")"),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"1em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))),(0,n.kt)("p",{parentName:"li"},"where ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"r")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_{k,r}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02778em"}},"r"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," is the output of the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"r"),(0,n.kt)("mi",{parentName:"mrow"},"a"),(0,n.kt)("mi",{parentName:"mrow"},"d"),(0,n.kt)("mi",{parentName:"mrow"},"i"),(0,n.kt)("mi",{parentName:"mrow"},"x"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"r")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"radix-r")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"d"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"i"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"x"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," butterfly operation for the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"t"),(0,n.kt)("mi",{parentName:"mrow"},"h")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k-th")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"t"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," set of inputs, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"k")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_{j,k}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," represents the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"t"),(0,n.kt)("mi",{parentName:"mrow"},"h")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"j-th")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.854em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"t"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," input element for the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"t"),(0,n.kt)("mi",{parentName:"mrow"},"h")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k-th")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"t"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," operation, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"W")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"W")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"W")))))," is the twiddle factor, and ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," is the prime modulus.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Recombination and Reordering:"),"\nAfter applying the appropriate butterfly operations across all decomposition levels, the Mixed Radix algorithm recombines the results into a single output sequence. Due to the varied sizes of the sub-transforms, a more complex reordering process may be required compared to Radix-2. This involves digit-reversal permutations to ensure that the final output sequence is correctly ordered."))),(0,n.kt)("h3",{id:"which-algorithm-should-i-choose-"},"Which algorithm should I choose ?"),(0,n.kt)("p",null,"Radix 2 is faster for small NTTs. A small NTT would be around logN = 16 and batch size 1. Its also more suited for inputs which are power of 2 (e.g., 256, 512, 1024). Radix 2 won't necessarily perform better for smaller ",(0,n.kt)("inlineCode",{parentName:"p"},"logn")," with larger batches."),(0,n.kt)("p",null,"Mixed radix on the other hand better for larger NTTs with larger input sizes which are not necessarily power of 2."),(0,n.kt)("p",null,"Performance really depends on logn size, batch size, ordering, inverse, coset, coeff-field and which GPU you are using."),(0,n.kt)("p",null,"For this reason we implemented our ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/774250926c00ffe84548bc7dd97aea5227afed7e/icicle/appUtils/ntt/ntt.cu#L474"},"heuristic auto-selection")," which should choose the most efficient algorithm in most cases. "),(0,n.kt)("p",null,"We still recommend you benchmark for your specific use case if you think a different configuration would yield better results."))}k.isMDXComponent=!0},8209:(a,e,t)=>{t(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[862],{3905:(a,e,t)=>{t.d(e,{Zo:()=>N,kt:()=>h});var s=t(7294);function n(a,e,t){return e in a?Object.defineProperty(a,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):a[e]=t,a}function m(a,e){var t=Object.keys(a);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(a);e&&(s=s.filter((function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),t.push.apply(t,s)}return t}function p(a){for(var e=1;e=0||(n[t]=a[t]);return n}(a,e);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(a);for(s=0;s=0||Object.prototype.propertyIsEnumerable.call(a,t)&&(n[t]=a[t])}return n}var i=s.createContext({}),l=function(a){var e=s.useContext(i),t=e;return a&&(t="function"==typeof a?a(e):p(p({},e),a)),t},N=function(a){var e=l(a.components);return s.createElement(i.Provider,{value:e},a.children)},o="mdxType",k={inlineCode:"code",wrapper:function(a){var e=a.children;return s.createElement(s.Fragment,{},e)}},c=s.forwardRef((function(a,e){var t=a.components,n=a.mdxType,m=a.originalType,i=a.parentName,N=r(a,["components","mdxType","originalType","parentName"]),o=l(t),c=n,h=o["".concat(i,".").concat(c)]||o[c]||k[c]||m;return t?s.createElement(h,p(p({ref:e},N),{},{components:t})):s.createElement(h,p({ref:e},N))}));function h(a,e){var t=arguments,n=e&&e.mdxType;if("string"==typeof a||n){var m=t.length,p=new Array(m);p[0]=c;var r={};for(var i in e)hasOwnProperty.call(e,i)&&(r[i]=e[i]);r.originalType=a,r[o]="string"==typeof a?a:n,p[1]=r;for(var l=2;l{t.r(e),t.d(e,{assets:()=>i,contentTitle:()=>p,default:()=>k,frontMatter:()=>m,metadata:()=>r,toc:()=>l});var s=t(7462),n=(t(7294),t(3905));t(8209);const m={},p="NTT - Number Theoretic Transform",r={unversionedId:"icicle/primitives/ntt",id:"icicle/primitives/ntt",title:"NTT - Number Theoretic Transform",description:"The Number Theoretic Transform (NTT) is a variant of the Fourier Transform used over finite fields or rings, particularly those of integers modulo a prime number. NTT operates in a discrete domain and is used primarily in applications requiring modular arithmetic, such as cryptography and polynomial multiplication.",source:"@site/docs/icicle/primitives/ntt.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/ntt",permalink:"/icicle/primitives/ntt",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/ntt.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Poseidon",permalink:"/icicle/primitives/poseidon"},next:{title:"Supporting Additional Curves",permalink:"/icicle/supporting-additional-curves"}},i={},l=[{value:"Supported curves",id:"supported-curves",level:3},{value:"Examples",id:"examples",level:3},{value:"NTT API overview",id:"ntt-api-overview",level:2},{value:"NTT Config",id:"ntt-config",level:3},{value:"Fields",id:"fields",level:4},{value:"Usage",id:"usage",level:4},{value:"Ordering",id:"ordering",level:3},{value:"Modes",id:"modes",level:3},{value:"Supported algorithms",id:"supported-algorithms",level:2},{value:"Radix 2",id:"radix-2",level:3},{value:"Mixed Radix",id:"mixed-radix",level:3},{value:"Which algorithm should I choose ?",id:"which-algorithm-should-i-choose-",level:3}],N={toc:l},o="wrapper";function k(a){let{components:e,...t}=a;return(0,n.kt)(o,(0,s.Z)({},N,t,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"ntt---number-theoretic-transform"},"NTT - Number Theoretic Transform"),(0,n.kt)("p",null,"The Number Theoretic Transform (NTT) is a variant of the Fourier Transform used over finite fields or rings, particularly those of integers modulo a prime number. NTT operates in a discrete domain and is used primarily in applications requiring modular arithmetic, such as cryptography and polynomial multiplication."),(0,n.kt)("p",null,"NTT is defined similarly to the Discrete Fourier Transform (DFT), but instead of using complex roots of unity, it uses roots of unity within a finite field. The definition hinges on the properties of the finite field, specifically the existence of a primitive root of unity of order ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," (where ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is typically a power of 2), and the modulo operation is performed with respect to a specific prime number that supports these roots."),(0,n.kt)("p",null,"Formally, given a sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, a_1, ..., a_{N-1}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6389em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"..."),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", the NTT of this sequence is another sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"."),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_0, A_1, ..., A_{N-1}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8917em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"..."),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", computed as follows:"),(0,n.kt)("div",{className:"math math-display"},(0,n.kt)("span",{parentName:"div",className:"katex-display"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("munderover",{parentName:"mrow"},(0,n.kt)("mo",{parentName:"munderover"},"\u2211"),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"n"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mn",{parentName:"mrow"},"0")),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1"))),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mi",{parentName:"msub"},"n")),(0,n.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"\u03c9"),(0,n.kt)("mrow",{parentName:"msup"},(0,n.kt)("mi",{parentName:"mrow"},"n"),(0,n.kt)("mi",{parentName:"mrow"},"k"))),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"1em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_k = \\sum_{n=0}^{N-1} a_n \\cdot \\omega^{nk} \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"3.0954em",verticalAlign:"-1.2671em"}}),(0,n.kt)("span",{parentName:"span",className:"mop op-limits"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-1.8829em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"n"),(0,n.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span"},(0,n.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,n.kt)("span",{parentName:"span",style:{top:"-4.3em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.2671em"}},(0,n.kt)("span",{parentName:"span"}))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.1514em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"n")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8991em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8991em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"nk"))))))))),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"1em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))),(0,n.kt)("p",null,"where:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is the size of the input sequence and is a power of 2,"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," is a prime number such that ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"+"),(0,n.kt)("mn",{parentName:"mrow"},"1")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p = kN + 1")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"1")))))," for some integer ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"))))),", ensuring that ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," supports the existence of ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"))))),"th roots of unity,"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"\u03c9")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\omega")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9")))))," is a primitive ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"))))),"th root of unity modulo ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p"))))),", meaning ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"\u03c9"),(0,n.kt)("mi",{parentName:"msup"},"N")),(0,n.kt)("mo",{parentName:"mrow"},"\u2261"),(0,n.kt)("mn",{parentName:"mrow"},"1"),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"0.6667em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\omega^N \\equiv 1 \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8413em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8413em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.063em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N")))))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"\u2261"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"1"),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.6667em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," and no smaller positive power of ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"\u03c9")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\omega")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03588em"}},"\u03c9")))))," is congruent to 1 modulo ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p"))))),","),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k")))))," ranges from 0 to ",(0,n.kt)("span",{parentName:"li",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N-1")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7667em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"1"))))),", and it indexes the output sequence.")),(0,n.kt)("p",null,"The NTT is particularly useful because it enables efficient polynomial multiplication under modulo arithmetic, crucial for algorithms in cryptographic protocols, and other areas requiring fast modular arithmetic operations. "),(0,n.kt)("p",null,"There exists also INTT which is the inverse operation of NTT. INTT can take as input an output sequence of integers from an NTT and reconstruct the original sequence."),(0,n.kt)("h1",{id:"using-ntt"},"Using NTT"),(0,n.kt)("h3",{id:"supported-curves"},"Supported curves"),(0,n.kt)("p",null,"NTT supports the following curves:"),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"bls12-377"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"bls12-381"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"bn-254"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"bw6-761")),(0,n.kt)("h3",{id:"examples"},"Examples"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/d84ffd2679a4cb8f8d1ac2ad2897bc0b95f4eeeb/examples/rust/ntt/src/main.rs#L1"},"Rust API examples"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/d84ffd2679a4cb8f8d1ac2ad2897bc0b95f4eeeb/examples/c%2B%2B/ntt/example.cu#L1"},"C++ API examples")))),(0,n.kt)("h2",{id:"ntt-api-overview"},"NTT API overview"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"pub fn ntt(\n input: &HostOrDeviceSlice,\n dir: NTTDir,\n cfg: &NTTConfig,\n output: &mut HostOrDeviceSlice,\n) -> IcicleResult<()>\n")),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"ntt:ntt")," expects:"),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"input")," - buffer to read the inputs of the NTT from. ",(0,n.kt)("br",null),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"dir")," - whether to compute forward or inverse NTT. ",(0,n.kt)("br",null),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"cfg")," - config used to specify extra arguments of the NTT. ",(0,n.kt)("br",null),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"output")," - buffer to write the NTT outputs into. Must be of the same size as input."),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"input")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"output")," buffers can be on device or on host. Being on host means that they will be transferred to device during runtime."),(0,n.kt)("h3",{id:"ntt-config"},"NTT Config"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"pub struct NTTConfig<'a, S> {\n pub ctx: DeviceContext<'a>,\n pub coset_gen: S,\n pub batch_size: i32,\n pub ordering: Ordering,\n are_inputs_on_device: bool, \n are_outputs_on_device: bool,\n pub is_async: bool,\n pub ntt_algorithm: NttAlgorithm,\n}\n")),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"NTTConfig")," struct is a configuration object used to specify parameters for an NTT instance."),(0,n.kt)("h4",{id:"fields"},"Fields"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"ctx: DeviceContext<'a>")),": Specifies the device context, including the device ID and the stream ID.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"coset_gen: S")),": Defines the coset generator used for coset (i)NTTs. By default, this is set to ",(0,n.kt)("inlineCode",{parentName:"p"},"S::one()"),", indicating that no coset is being used.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"batch_size: i32")),": Determines the number of NTTs to compute in a single batch. The default value is 1, meaning that operations are performed on individual inputs without batching. Batch processing can significantly improve performance by leveraging parallelism in GPU computations.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"ordering: Ordering")),": Controls the ordering of inputs and outputs for the NTT operation. This field can be used to specify decimation strategies (in time or in frequency) and the type of butterfly algorithm (Cooley-Tukey or Gentleman-Sande). The ordering is crucial for compatibility with various algorithmic approaches and can impact the efficiency of the NTT.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"are_inputs_on_device: bool")),": Indicates whether the input data has been preloaded on the device memory. If ",(0,n.kt)("inlineCode",{parentName:"p"},"false")," inputs will be copied from host to device.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"are_outputs_on_device: bool")),": Indicates whether the output data is preloaded in device memory. If ",(0,n.kt)("inlineCode",{parentName:"p"},"false")," outputs will be copied from host to device. If the inputs and outputs are the same pointer NTT will be computed in place.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"is_async: bool")),": Specifies whether the NTT operation should be performed asynchronously. When set to ",(0,n.kt)("inlineCode",{parentName:"p"},"true"),", the NTT function will not block the CPU, allowing other operations to proceed concurrently. Asynchronous execution requires careful synchronization to ensure data integrity and correctness.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"ntt_algorithm: NttAlgorithm")),": Can be one of ",(0,n.kt)("inlineCode",{parentName:"p"},"Auto"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"Radix2"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"MixedRadix"),".\n",(0,n.kt)("inlineCode",{parentName:"p"},"Auto")," will select ",(0,n.kt)("inlineCode",{parentName:"p"},"Radix 2")," or ",(0,n.kt)("inlineCode",{parentName:"p"},"Mixed Radix")," algorithm based on heuristics.\n",(0,n.kt)("inlineCode",{parentName:"p"},"Radix2")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"MixedRadix")," will force the use of an algorithm regardless of the input size or other considerations. You should use one of these options when you know for sure that you want to "))),(0,n.kt)("h4",{id:"usage"},"Usage"),(0,n.kt)("p",null,"Example initialization with default settings:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"let default_config = NTTConfig::default();\n")),(0,n.kt)("p",null,"Customizing the configuration:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"let custom_config = NTTConfig {\n ctx: custom_device_context,\n coset_gen: my_coset_generator,\n batch_size: 10,\n ordering: Ordering::kRN,\n are_inputs_on_device: true,\n are_outputs_on_device: true,\n is_async: false,\n ntt_algorithm: NttAlgorithm::MixedRadix,\n};\n")),(0,n.kt)("h3",{id:"ordering"},"Ordering"),(0,n.kt)("p",null,"The ",(0,n.kt)("inlineCode",{parentName:"p"},"Ordering")," enum defines how inputs and outputs are arranged for the NTT operation, offering flexibility in handling data according to different algorithmic needs or compatibility requirements. It primarily affects the sequencing of data points for the transform, which can influence both performance and the compatibility with certain algorithmic approaches. The available ordering options are:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kNN")," (Natural-Natural):")," Both inputs and outputs are in their natural order. This is the simplest form of ordering, where data is processed in the sequence it is given, without any rearrangement.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kNR")," (Natural-Reversed):")," Inputs are in natural order, while outputs are in bit-reversed order. This ordering is typically used in algorithms that benefit from having the output in a bit-reversed pattern.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kRN")," (Reversed-Natural):")," Inputs are in bit-reversed order, and outputs are in natural order. This is often used with the Cooley-Tukey FFT algorithm.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kRR")," (Reversed-Reversed):")," Both inputs and outputs are in bit-reversed order.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kNM")," (Natural-Mixed):")," Inputs are provided in their natural order, while outputs are arranged in a digit-reversed (mixed) order. This ordering is good for mixed radix NTT operations, where the mixed or digit-reversed ordering of outputs is a generalization of the bit-reversal pattern seen in simpler, radix-2 cases.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},(0,n.kt)("inlineCode",{parentName:"strong"},"kMN")," (Mixed-Natural):")," Inputs are in a digit-reversed (mixed) order, while outputs are restored to their natural order. This ordering would primarily be used for mixed radix NTT"))),(0,n.kt)("p",null,"Choosing an algorithm is heavily dependent on your use case. For example Cooley-Tukey will often use ",(0,n.kt)("inlineCode",{parentName:"p"},"kRN")," and Gentleman-Sande often uses ",(0,n.kt)("inlineCode",{parentName:"p"},"kNR"),"."),(0,n.kt)("h3",{id:"modes"},"Modes"),(0,n.kt)("p",null,"NTT also supports two different modes ",(0,n.kt)("inlineCode",{parentName:"p"},"Batch NTT")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"Single NTT")),(0,n.kt)("p",null,"Batch NTT allows you to run many NTTs with a single API call, Single MSM will launch a single MSM computation."),(0,n.kt)("p",null,"You may toggle between single and batch NTT by simply configure ",(0,n.kt)("inlineCode",{parentName:"p"},"batch_size")," to be larger then 1 in your ",(0,n.kt)("inlineCode",{parentName:"p"},"NTTConfig"),"."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-rust"},"let mut cfg = ntt::get_default_ntt_config::();\ncfg.batch_size = 10 // your ntt using this config will run in batch mode.\n")),(0,n.kt)("p",null,(0,n.kt)("inlineCode",{parentName:"p"},"batch_size=1")," would keep our NTT in single NTT mode."),(0,n.kt)("p",null,"Deciding weather to use ",(0,n.kt)("inlineCode",{parentName:"p"},"batch NTT")," vs ",(0,n.kt)("inlineCode",{parentName:"p"},"single NTT")," is highly dependent on your application and use case."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Single NTT Mode")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Choose this mode when your application requires processing individual NTT operations in isolation.")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Batch NTT Mode")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Batch NTT mode can significantly reduce read/write as well as computation overhead by executing multiple NTT operations in parallel.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Batch mode may also offer better utilization of computational resources (memory and compute)."))),(0,n.kt)("h2",{id:"supported-algorithms"},"Supported algorithms"),(0,n.kt)("p",null,"Our NTT implementation supports two algorithms ",(0,n.kt)("inlineCode",{parentName:"p"},"radix-2")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"mixed-radix"),"."),(0,n.kt)("h3",{id:"radix-2"},"Radix 2"),(0,n.kt)("p",null,'At its core, the Radix-2 NTT algorithm divides the problem into smaller sub-problems, leveraging the properties of "divide and conquer" to reduce the overall computational complexity. The algorithm operates on sequences whose lengths are powers of two.'),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Input Preparation:"),"\nThe input is a sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mo",{parentName:"mrow"},"\u2026"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1"))),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mtext",{parentName:"mrow"},"\xa0where\xa0"),(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, a_1, \\ldots, a_{N-1}, \\text{ where } N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9028em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"minner"},"\u2026"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord text"},(0,n.kt)("span",{parentName:"span",className:"mord"},"\xa0where\xa0")),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is a power of two.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Recursive Decomposition:"),"\nThe algorithm recursively divides the input sequence into smaller sequences. At each step, it separates the sequence into even-indexed and odd-indexed elements, forming two subsequences that are then processed independently.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Butterfly Operations:"),'\nThe core computational element of the Radix-2 NTT is the "butterfly" operation, which combines pairs of elements from the sequences obtained in the decomposition step. '),(0,n.kt)("p",{parentName:"li"},'Each butterfly operation involves multiplication by a "twiddle factor," which is a root of unity in the finite field, and addition or subtraction of the results, all performed modulo the prime modulus.'),(0,n.kt)("div",{parentName:"li",className:"math math-display"},(0,n.kt)("span",{parentName:"div",className:"katex-display"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"+"),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"B"),(0,n.kt)("mi",{parentName:"msub"},"k")),(0,n.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"W"),(0,n.kt)("mi",{parentName:"msup"},"k")),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"1em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_k = (A_k + B_k \\cdot W^k) \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,n.kt)("span",{parentName:"span",className:"mopen"},"("),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"+"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05017em"}},"B"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0502em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"1.1491em",verticalAlign:"-0.25em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"W"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8991em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))))))),(0,n.kt)("span",{parentName:"span",className:"mclose"},")"),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"1em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mi",{parentName:"msub"},"k"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," - The output of the butterfly operation for the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"))))),"-th element"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mi",{parentName:"msub"},"k"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," - an element from the even-indexed subset"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"B"),(0,n.kt)("mi",{parentName:"msub"},"k"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"B_k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05017em"}},"B"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0502em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," - an element from the odd-indexed subset"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," - prime modulus"),(0,n.kt)("p",{parentName:"li"},(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k")))))," - The index of the current operation within the butterfly or the transform stage"))),(0,n.kt)("p",null," The twiddle factors are precomputed to save runtime and improve performance."),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("strong",{parentName:"li"},"Bit-Reversal Permutation:"),"\nA final step involves rearranging the output sequence into the correct order. Due to the halving process in the decomposition steps, the elements of the transformed sequence are initially in a bit-reversed order. A bit-reversal permutation is applied to obtain the final sequence in natural order.")),(0,n.kt)("h3",{id:"mixed-radix"},"Mixed Radix"),(0,n.kt)("p",null,'The Mixed Radix NTT algorithm extends the concepts of the Radix-2 algorithm by allowing the decomposition of the input sequence based on various factors of its length. Specifically ICICLEs implementation splits the input into blocks of sizes 16,32,64 compared to radix2 which is always splitting such that we end with NTT of size 2. This approach offers enhanced flexibility and efficiency, especially for input sizes that are composite numbers, by leveraging the "divide and conquer" strategy across multiple radixes.'),(0,n.kt)("p",null,"The NTT blocks in Mixed Radix are implemented more efficiently based on winograd NTT but also optimized memory and register usage is better compared to Radix-2."),(0,n.kt)("p",null,"Mixed Radix can reduce the number of stages required to compute for large inputs."),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Input Preparation:"),"\nThe input to the Mixed Radix NTT is a sequence of integers ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"0")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mn",{parentName:"msub"},"1")),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mo",{parentName:"mrow"},"\u2026"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"a"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"N"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, a_1, \\ldots, a_{N-1}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6389em",verticalAlign:"-0.2083em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1")))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"minner"},"\u2026"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mpunct"},","),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3283em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.10903em"}},"N"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2083em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", where ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," is not strictly required to be a power of two. Instead, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N")))))," can be any composite number, ideally factorized into primes or powers of primes.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Factorization and Decomposition:"),"\nUnlike the Radix-2 algorithm, which strictly divides the computational problem into halves, the Mixed Radix NTT algorithm implements a flexible decomposition approach which isn't limited to prime factorization. "),(0,n.kt)("p",{parentName:"li"},"For example, an NTT of size 256 can be decomposed into two stages of ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mn",{parentName:"mrow"},"16"),(0,n.kt)("mo",{parentName:"mrow"},"\xd7"),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mtext",{parentName:"msub"},"NTT"),(0,n.kt)("mn",{parentName:"msub"},"16"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"16 \\times \\text{NTT}_{16}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7278em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"16"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\xd7"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord text"},(0,n.kt)("span",{parentName:"span",className:"mord"},"NTT")),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"16"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))))))),", leveraging a composite factorization strategy rather than decomposing into eight stages of ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mtext",{parentName:"msub"},"NTT"),(0,n.kt)("mn",{parentName:"msub"},"2"))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"\\text{NTT}_{2}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8333em",verticalAlign:"-0.15em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord text"},(0,n.kt)("span",{parentName:"span",className:"mord"},"NTT")),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"2"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,n.kt)("span",{parentName:"span"})))))))))),". This exemplifies the use of composite factors (in this case, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mn",{parentName:"mrow"},"256"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mn",{parentName:"mrow"},"16"),(0,n.kt)("mo",{parentName:"mrow"},"\xd7"),(0,n.kt)("mn",{parentName:"mrow"},"16")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"256 = 16 \\times 16")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"256"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7278em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"16"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\xd7"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6444em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},"16"))))),") to apply smaller NTT transforms, optimizing computational efficiency by adapting the decomposition strategy to the specific structure of ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"N")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"N")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"N"))))),".")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Butterfly Operations with Multiple Radixes:"),"\nThe Mixed Radix algorithm utilizes butterfly operations for various radix sizes. Each sub-transform involves specific butterfly operations characterized by multiplication with twiddle factors appropriate for the radix in question."),(0,n.kt)("p",{parentName:"li"},"The generalized butterfly operation for a radix-",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"r")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"r")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," element can be expressed as:"),(0,n.kt)("div",{parentName:"li",className:"math math-display"},(0,n.kt)("span",{parentName:"div",className:"katex-display"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML",display:"block"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"r"))),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("munderover",{parentName:"mrow"},(0,n.kt)("mo",{parentName:"munderover"},"\u2211"),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow"},"="),(0,n.kt)("mn",{parentName:"mrow"},"0")),(0,n.kt)("mrow",{parentName:"munderover"},(0,n.kt)("mi",{parentName:"mrow"},"r"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mn",{parentName:"mrow"},"1"))),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"k"))),(0,n.kt)("mo",{parentName:"mrow"},"\u22c5"),(0,n.kt)("msup",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msup"},"W"),(0,n.kt)("mrow",{parentName:"msup"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mi",{parentName:"mrow"},"k"))),(0,n.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,n.kt)("mspace",{parentName:"mrow"}),(0,n.kt)("mspace",{parentName:"mrow",width:"1em"}),(0,n.kt)("mrow",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"m"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"o"),(0,n.kt)("mi",{parentName:"mrow",mathvariant:"normal"},"d")),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mtext",{parentName:"mrow"},"\u2009"),(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_{k,r} = \\sum_{j=0}^{r-1} (A_{j,k} \\cdot W^{jk}) \\mod p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02778em"}},"r"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,n.kt)("span",{parentName:"span",className:"mrel"},"="),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"3.2149em",verticalAlign:"-1.4138em"}}),(0,n.kt)("span",{parentName:"span",className:"mop op-limits"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.8011em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-1.8723em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mrel mtight"},"="),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,n.kt)("span",{parentName:"span",style:{top:"-3.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span"},(0,n.kt)("span",{parentName:"span",className:"mop op-symbol large-op"},"\u2211"))),(0,n.kt)("span",{parentName:"span",style:{top:"-4.3em",marginLeft:"0em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"3.05em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02778em"}},"r"),(0,n.kt)("span",{parentName:"span",className:"mbin mtight"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mord mtight"},"1"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"1.4138em"}},(0,n.kt)("span",{parentName:"span"}))))),(0,n.kt)("span",{parentName:"span",className:"mopen"},"("),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"})))))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u22c5"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"1.1491em",verticalAlign:"-0.25em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"W"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.8991em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-3.113em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"jk"))))))))),(0,n.kt)("span",{parentName:"span",className:"mclose"},")"),(0,n.kt)("span",{parentName:"span",className:"mspace allowbreak"}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"1em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.8889em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathrm"},"mod"))),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))),(0,n.kt)("p",{parentName:"li"},"where ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"X"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"r")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"X_{k,r}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.07847em"}},"X"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"-0.0785em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.02778em"}},"r"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," is the output of the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"r"),(0,n.kt)("mi",{parentName:"mrow"},"a"),(0,n.kt)("mi",{parentName:"mrow"},"d"),(0,n.kt)("mi",{parentName:"mrow"},"i"),(0,n.kt)("mi",{parentName:"mrow"},"x"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"r")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"radix-r")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"d"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"i"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"x"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.4306em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.02778em"}},"r")))))," butterfly operation for the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"t"),(0,n.kt)("mi",{parentName:"mrow"},"h")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k-th")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"t"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," set of inputs, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("msub",{parentName:"mrow"},(0,n.kt)("mi",{parentName:"msub"},"A"),(0,n.kt)("mrow",{parentName:"msub"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,n.kt)("mi",{parentName:"mrow"},"k")))),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"A_{j,k}")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,n.kt)("span",{parentName:"span",className:"mord"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"A"),(0,n.kt)("span",{parentName:"span",className:"msupsub"},(0,n.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3361em"}},(0,n.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,n.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,n.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mtight"},(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mpunct mtight"},","),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.03148em"}},"k"))))),(0,n.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,n.kt)("span",{parentName:"span",className:"vlist-r"},(0,n.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,n.kt)("span",{parentName:"span"}))))))))))," represents the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"j"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"t"),(0,n.kt)("mi",{parentName:"mrow"},"h")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"j-th")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.854em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.05724em"}},"j"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"t"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," input element for the ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"k"),(0,n.kt)("mo",{parentName:"mrow"},"\u2212"),(0,n.kt)("mi",{parentName:"mrow"},"t"),(0,n.kt)("mi",{parentName:"mrow"},"h")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"k-th")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.7778em",verticalAlign:"-0.0833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.03148em"}},"k"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}}),(0,n.kt)("span",{parentName:"span",className:"mbin"},"\u2212"),(0,n.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2222em"}})),(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"t"),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"h")))))," operation, ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"W")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"W")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.13889em"}},"W")))))," is the twiddle factor, and ",(0,n.kt)("span",{parentName:"p",className:"math math-inline"},(0,n.kt)("span",{parentName:"span",className:"katex"},(0,n.kt)("span",{parentName:"span",className:"katex-mathml"},(0,n.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,n.kt)("semantics",{parentName:"math"},(0,n.kt)("mrow",{parentName:"semantics"},(0,n.kt)("mi",{parentName:"mrow"},"p")),(0,n.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"p")))),(0,n.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,n.kt)("span",{parentName:"span",className:"base"},(0,n.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,n.kt)("span",{parentName:"span",className:"mord mathnormal"},"p")))))," is the prime modulus.")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Recombination and Reordering:"),"\nAfter applying the appropriate butterfly operations across all decomposition levels, the Mixed Radix algorithm recombines the results into a single output sequence. Due to the varied sizes of the sub-transforms, a more complex reordering process may be required compared to Radix-2. This involves digit-reversal permutations to ensure that the final output sequence is correctly ordered."))),(0,n.kt)("h3",{id:"which-algorithm-should-i-choose-"},"Which algorithm should I choose ?"),(0,n.kt)("p",null,"Radix 2 is faster for small NTTs. A small NTT would be around logN = 16 and batch size 1. Its also more suited for inputs which are power of 2 (e.g., 256, 512, 1024). Radix 2 won't necessarily perform better for smaller ",(0,n.kt)("inlineCode",{parentName:"p"},"logn")," with larger batches."),(0,n.kt)("p",null,"Mixed radix on the other hand better for larger NTTs with larger input sizes which are not necessarily power of 2."),(0,n.kt)("p",null,"Performance really depends on logn size, batch size, ordering, inverse, coset, coeff-field and which GPU you are using."),(0,n.kt)("p",null,"For this reason we implemented our ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/774250926c00ffe84548bc7dd97aea5227afed7e/icicle/appUtils/ntt/ntt.cu#L474"},"heuristic auto-selection")," which should choose the most efficient algorithm in most cases. "),(0,n.kt)("p",null,"We still recommend you benchmark for your specific use case if you think a different configuration would yield better results."))}k.isMDXComponent=!0},8209:(a,e,t)=>{t(7294)}}]); \ No newline at end of file diff --git a/assets/js/2b850a9b.40ab3057.js b/assets/js/2b850a9b.a413b9a9.js similarity index 99% rename from assets/js/2b850a9b.40ab3057.js rename to assets/js/2b850a9b.a413b9a9.js index 6d169cf..c8c15d7 100644 --- a/assets/js/2b850a9b.40ab3057.js +++ b/assets/js/2b850a9b.a413b9a9.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[614],{3905:(e,t,i)=>{i.d(t,{Zo:()=>u,kt:()=>h});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function r(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function l(e){for(var t=1;t=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),i=t;return e&&(i="function"==typeof e?e(t):l(l({},t),e)),i},u=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=c(i),m=a,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||r;return i?n.createElement(h,l(l({ref:t},u),{},{components:i})):n.createElement(h,l({ref:t},u))}));function h(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=i.length,l=new Array(r);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,l[1]=o;for(var c=2;c{i.r(t),i.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var n=i(7462),a=(i(7294),i(3905));i(8209);const r={},l="Getting started with ICICLE",o={unversionedId:"icicle/introduction",id:"icicle/introduction",title:"Getting started with ICICLE",description:"This guide is oriented towards developers who want to start writing code with the ICICLE libraries. If you just want to run your existing ZK circuits on GPU refer to this guide please.",source:"@site/docs/icicle/introduction.md",sourceDirName:"icicle",slug:"/icicle/introduction",permalink:"/icicle/introduction",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/introduction.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"What is ICICLE?",permalink:"/icicle/overview"},next:{title:"ICICLE integrated provers",permalink:"/icicle/integrations"}},s={},c=[{value:"ICICLE repository overview",id:"icicle-repository-overview",level:2},{value:"ICICLE Core",id:"icicle-core",level:3},{value:"ICICLE Rust and Golang bindings",id:"icicle-rust-and-golang-bindings",level:3},{value:"Running ICICLE",id:"running-icicle",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Optional Prerequisites",id:"optional-prerequisites",level:4},{value:"Setting up ICICLE and running tests",id:"setting-up-icicle-and-running-tests",level:3},{value:"Setting up our environment",id:"setting-up-our-environment",level:4},{value:"ICICLE Core",id:"icicle-core-1",level:4},{value:"ICICLE Rust",id:"icicle-rust",level:4},{value:"ICICLE Golang",id:"icicle-golang",level:4},{value:"Running ICICLE examples",id:"running-icicle-examples",level:3},{value:"Writing new bindings for ICICLE",id:"writing-new-bindings-for-icicle",level:2},{value:"ICICLE Adapters",id:"icicle-adapters",level:3}],u={toc:c},p="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"getting-started-with-icicle"},"Getting started with ICICLE"),(0,a.kt)("p",null,"This guide is oriented towards developers who want to start writing code with the ICICLE libraries. If you just want to run your existing ZK circuits on GPU refer to ",(0,a.kt)("a",{parentName:"p",href:"/icicle/integrations#using-icicle-integrations"},"this guide")," please."),(0,a.kt)("h2",{id:"icicle-repository-overview"},"ICICLE repository overview"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"ICICLE API overview",src:i(5870).Z,width:"1932",height:"996"})),(0,a.kt)("p",null,"The diagram above displays the general architecture of ICICLE and the API layers that exist. The CUDA API, which we also call ICICLE Core, is the lowest level and is comprised of CUDA kernels which implement all primitives such as MSM as well as C++ wrappers which expose these methods for different curves."),(0,a.kt)("p",null,"ICICLE Core compiles into a static library. This library can be used with our official Golang and Rust wrappers or you can implement a wrapper for it in any language."),(0,a.kt)("p",null,"Based on this dependency architecture, the ICICLE repository has three main sections, each of which is independent from the other."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"ICICLE core"),(0,a.kt)("li",{parentName:"ul"},"ICICLE Rust bindings"),(0,a.kt)("li",{parentName:"ul"},"ICICLE Golang bindings")),(0,a.kt)("h3",{id:"icicle-core"},"ICICLE Core"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle"},"ICICLE core")," contains all the low level CUDA code implementing primitives such as ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/primitives"},"points")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/appUtils/msm"},"MSM"),". There also exists higher level C++ wrappers to expose the low level CUDA primitives (",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/c1a32a9879a7612916e05aa3098f76144de4109e/icicle/appUtils/msm/msm.cu#L1"},"example"),")."),(0,a.kt)("p",null,"ICICLE Core would typically be compiled into a static library and used in a third party language such as Rust or Golang."),(0,a.kt)("h3",{id:"icicle-rust-and-golang-bindings"},"ICICLE Rust and Golang bindings"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust"},"ICICLE Rust bindings")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/tree/main/goicicle"},"ICICLE Golang bindings"))),(0,a.kt)("p",null,"These bindings allow you to easily use ICICLE in a Rust or Golang project. Setting up Golang bindings requires a bit of extra steps compared to the Rust bindings which utilize the ",(0,a.kt)("inlineCode",{parentName:"p"},"cargo build")," tool."),(0,a.kt)("h2",{id:"running-icicle"},"Running ICICLE"),(0,a.kt)("p",null,"This guide assumes that you have a Linux or Windows machine with a Nvidia GPU installed. If you don't have access to a Nvidia GPU you can access one for free on ",(0,a.kt)("a",{parentName:"p",href:"https://colab.google/"},"Google Colab"),"."),(0,a.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"NVCC (version 12.0 or newer)"),(0,a.kt)("li",{parentName:"ul"},"cmake 3.18 and above"),(0,a.kt)("li",{parentName:"ul"},"GCC - version 9 or newer is recommended."),(0,a.kt)("li",{parentName:"ul"},"Any Nvidia GPU"),(0,a.kt)("li",{parentName:"ul"},"Linux or Windows operating system.")),(0,a.kt)("h4",{id:"optional-prerequisites"},"Optional Prerequisites"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Docker, latest version."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html"},"NVIDIA Container Toolkit"))),(0,a.kt)("p",null,"If you don't wish to install these prerequisites you can follow this tutorial using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/Dockerfile"},"ZK-Container")," (docker container). To learn more about using ZK-Containers ",(0,a.kt)("a",{parentName:"p",href:"/ZKContainers"},"read this"),"."),(0,a.kt)("h3",{id:"setting-up-icicle-and-running-tests"},"Setting up ICICLE and running tests"),(0,a.kt)("p",null,"The objective of this guide is to make sure you can run the ICICLE Core, Rust and Golang tests. Achieving this will ensure you know how to setup ICICLE and run a ICICLE program. For simplicity, we will be using the ICICLE docker container as our environment, however, you may install the prerequisites on your machine and follow the same commands in your terminal."),(0,a.kt)("h4",{id:"setting-up-our-environment"},"Setting up our environment"),(0,a.kt)("p",null,"Lets begin by cloning the ICICLE repository:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"git clone https://github.com/ingonyama-zk/icicle\n")),(0,a.kt)("p",null,"We will proceed to build the docker image ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/Dockerfile"},"found here"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker build -t icicle-demo .\ndocker run -it --runtime=nvidia --gpus all --name icicle_container icicle-demo\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"-it")," runs the container in interactive mode with a terminal."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"--gpus all")," Allocate all available GPUs to the container. You can also specify which GPUs to use if you don't want to allocate all."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"--runtime=nvidia")," Use the NVIDIA runtime, necessary for GPU support.")),(0,a.kt)("p",null,"To read more about these settings reference this ",(0,a.kt)("a",{parentName:"p",href:"https://developer.nvidia.com/nvidia-container-runtime"},"article"),"."),(0,a.kt)("p",null,"If you accidentally close your terminal and want to reconnect just call:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker exec -it icicle_container bash\n")),(0,a.kt)("p",null,"Lets make sure that we have the correct CUDA version before proceeding"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"nvcc --version\n")),(0,a.kt)("p",null,"You should see something like this"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"nvcc: NVIDIA (R) Cuda compiler driver\nCopyright (c) 2005-2023 NVIDIA Corporation\nBuilt on Tue_Aug_15_22:02:13_PDT_2023\nCuda compilation tools, release 12.2, V12.2.140\nBuild cuda_12.2.r12.2/compiler.33191640_0\n")),(0,a.kt)("p",null,"Make sure the release version is at least 12.0."),(0,a.kt)("h4",{id:"icicle-core-1"},"ICICLE Core"),(0,a.kt)("p",null,"ICICLE Core is found under ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle"},(0,a.kt)("inlineCode",{parentName:"a"},"/icicle")),". To build and run the tests first:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd icicle\n")),(0,a.kt)("p",null,"We are going to compile ICICLE for a specific curve"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"mkdir -p build\ncmake -S . -B build -DCURVE=bn254 -DBUILD_TESTS=ON\ncmake --build build\n")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"-DBUILD_TESTS=ON")," compiles the tests, without this flag ",(0,a.kt)("inlineCode",{parentName:"p"},"ctest")," won't work.\n",(0,a.kt)("inlineCode",{parentName:"p"},"-DCURVE=bn254")," tells the compiler which curve to build. You can find a list of supported curves ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/curves"},"here"),"."),(0,a.kt)("p",null,"The output in ",(0,a.kt)("inlineCode",{parentName:"p"},"build")," folder should include the static libraries for the compiled curve."),(0,a.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"Make sure to only use ",(0,a.kt)("inlineCode",{parentName:"p"},"-DBUILD_TESTS=ON")," for running tests as the archive output will only be available when ",(0,a.kt)("inlineCode",{parentName:"p"},"-DBUILD_TESTS=ON")," is not supplied."))),(0,a.kt)("p",null,"To run the test"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd build\nctest\n")),(0,a.kt)("h4",{id:"icicle-rust"},"ICICLE Rust"),(0,a.kt)("p",null,"The rust bindings work by first compiling the CUDA static libraries as seen ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/wrappers/rust/icicle-curves/icicle-bn254/build.rs"},"here"),". The compilation of CUDA and the Rust library is all handled by the rust build toolchain."),(0,a.kt)("p",null,"Similar to ICICLE Core here we also have to compile per curve."),(0,a.kt)("p",null,"Lets compile curve ",(0,a.kt)("inlineCode",{parentName:"p"},"bn254")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd wrappers/rust/icicle-curves/icicle-bn254\n")),(0,a.kt)("p",null,"Now lets build our library"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cargo build --release\n")),(0,a.kt)("p",null,"This may take a couple of minutes since we are compiling both the CUDA and Rust code."),(0,a.kt)("p",null,"To run the tests"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cargo test -- --test-threads=1\n")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"--test-threads=1")," is needed because currently some tests might interfere with one another inside the GPU."),(0,a.kt)("p",null,"We also include some benchmarks"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cargo bench\n")),(0,a.kt)("h4",{id:"icicle-golang"},"ICICLE Golang"),(0,a.kt)("p",null,"Golang is WIP in v1, coming soon. Please checkout a previous ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases/tag/v0.1.0"},"release v0.1.0")," for golang bindings."),(0,a.kt)("h3",{id:"running-icicle-examples"},"Running ICICLE examples"),(0,a.kt)("p",null,"ICICLE examples can be found ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle-examples"},"here")," these examples cover some simple use cases using C++, rust and golang."),(0,a.kt)("p",null,"In each example directory, ZK-container files are located in a subdirectory ",(0,a.kt)("inlineCode",{parentName:"p"},".devcontainer"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"msm/\n\u251c\u2500\u2500 .devcontainer\n \u251c\u2500\u2500 devcontainer.json\n \u2514\u2500\u2500 Dockerfile\n")),(0,a.kt)("p",null,"Lets run one of our C++ examples, in this case the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle-examples/blob/main/c%2B%2B/msm/example.cu"},"MSM example"),"."),(0,a.kt)("p",null,"Clone the repository"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"git clone https://github.com/ingonyama-zk/icicle-examples.git\ncd icicle-examples\n")),(0,a.kt)("p",null,"Enter the test directory"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd c++/msm\n")),(0,a.kt)("p",null,"Now lets build our docker file and run the test inside it. Make sure you have installed the ",(0,a.kt)("a",{parentName:"p",href:"#optional-prerequisites"},"optional prerequisites"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker build -t icicle-example-msm -f .devcontainer/Dockerfile .\n")),(0,a.kt)("p",null,"Lets start and enter the container"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker run -it --rm --gpus all -v .:/icicle-example icicle-example-msm\n")),(0,a.kt)("p",null,"to run the example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"rm -rf build\nmkdir -p build\ncmake -S . -B build\ncmake --build build\n./build/example\n")),(0,a.kt)("p",null,"You can now experiment with our other examples, perhaps try to run a rust or golang example next."),(0,a.kt)("h2",{id:"writing-new-bindings-for-icicle"},"Writing new bindings for ICICLE"),(0,a.kt)("p",null,"Since ICICLE Core is written in CUDA / C++ its really simple to generate static libraries. These static libraries can be installed on any system and called by higher level languages such as Golang."),(0,a.kt)("p",null,"static libraries can be loaded into memory once and used by multiple programs, reducing memory usage and potentially improving performance. They also allow you to separate functionality into distinct modules so your static library may need to compile only specific features that you want to use."),(0,a.kt)("p",null,"Lets review the Golang bindings since its a pretty verbose example (compared to rust which hides it pretty well) of using static libraries. Golang has a library named ",(0,a.kt)("inlineCode",{parentName:"p"},"CGO")," which can be used to link static libraries. Here's a basic example on how you can use cgo to link these libraries:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},'/*\n#cgo LDFLAGS: -L/path/to/shared/libs -lbn254 -lbls12_381 -lbls12_377 -lbw6_671\n#include "icicle.h" // make sure you use the correct header file(s)\n*/\nimport "C"\n\nfunc main() {\n // Now you can call the C functions from the ICICLE libraries.\n // Note that C function calls are prefixed with \'C.\' in Go code.\n\n out := (*C.BN254_projective_t)(unsafe.Pointer(p))\n in := (*C.BN254_affine_t)(unsafe.Pointer(affine))\n\n C.projective_from_affine_bn254(out, in)\n}\n')),(0,a.kt)("p",null,"The comments on the first line tell ",(0,a.kt)("inlineCode",{parentName:"p"},"CGO")," which libraries to import as well as which header files to include. You can then call methods which are part of the static library and defined in the header file, ",(0,a.kt)("inlineCode",{parentName:"p"},"C.projective_from_affine_bn254")," is an example."),(0,a.kt)("p",null,"If you wish to create your own bindings for a language of your choice we suggest you start by investigating how you can call static libraries."),(0,a.kt)("h3",{id:"icicle-adapters"},"ICICLE Adapters"),(0,a.kt)("p",null,"One of the core ideas behind ICICLE is that developers can gradually accelerate their provers. Many protocols are written using other cryptographic libraries and completely replacing them may be complex and time consuming."),(0,a.kt)("p",null,"Therefore we offer adapters for various popular libraries, these adapters allow us to convert points and scalars between different formats defined by various libraries. Here is a list:"),(0,a.kt)("p",null,"Golang adapters:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/iciclegnark"},"Gnark crypto adapter"))))}d.isMDXComponent=!0},5870:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/apilevels-1ab85a883df418516e16eb87aa7b0385.png"},8209:(e,t,i)=>{i(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[614],{3905:(e,t,i)=>{i.d(t,{Zo:()=>u,kt:()=>h});var n=i(7294);function a(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function r(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function l(e){for(var t=1;t=0||(a[i]=e[i]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(a[i]=e[i])}return a}var s=n.createContext({}),c=function(e){var t=n.useContext(s),i=t;return e&&(i="function"==typeof e?e(t):l(l({},t),e)),i},u=function(e){var t=c(e.components);return n.createElement(s.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var i=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=c(i),m=a,h=p["".concat(s,".").concat(m)]||p[m]||d[m]||r;return i?n.createElement(h,l(l({ref:t},u),{},{components:i})):n.createElement(h,l({ref:t},u))}));function h(e,t){var i=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=i.length,l=new Array(r);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:a,l[1]=o;for(var c=2;c{i.r(t),i.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>c});var n=i(7462),a=(i(7294),i(3905));i(8209);const r={},l="Getting started with ICICLE",o={unversionedId:"icicle/introduction",id:"icicle/introduction",title:"Getting started with ICICLE",description:"This guide is oriented towards developers who want to start writing code with the ICICLE libraries. If you just want to run your existing ZK circuits on GPU refer to this guide please.",source:"@site/docs/icicle/introduction.md",sourceDirName:"icicle",slug:"/icicle/introduction",permalink:"/icicle/introduction",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/introduction.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"What is ICICLE?",permalink:"/icicle/overview"},next:{title:"ICICLE integrated provers",permalink:"/icicle/integrations"}},s={},c=[{value:"ICICLE repository overview",id:"icicle-repository-overview",level:2},{value:"ICICLE Core",id:"icicle-core",level:3},{value:"ICICLE Rust and Golang bindings",id:"icicle-rust-and-golang-bindings",level:3},{value:"Running ICICLE",id:"running-icicle",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Optional Prerequisites",id:"optional-prerequisites",level:4},{value:"Setting up ICICLE and running tests",id:"setting-up-icicle-and-running-tests",level:3},{value:"Setting up our environment",id:"setting-up-our-environment",level:4},{value:"ICICLE Core",id:"icicle-core-1",level:4},{value:"ICICLE Rust",id:"icicle-rust",level:4},{value:"ICICLE Golang",id:"icicle-golang",level:4},{value:"Running ICICLE examples",id:"running-icicle-examples",level:3},{value:"Writing new bindings for ICICLE",id:"writing-new-bindings-for-icicle",level:2},{value:"ICICLE Adapters",id:"icicle-adapters",level:3}],u={toc:c},p="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(p,(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"getting-started-with-icicle"},"Getting started with ICICLE"),(0,a.kt)("p",null,"This guide is oriented towards developers who want to start writing code with the ICICLE libraries. If you just want to run your existing ZK circuits on GPU refer to ",(0,a.kt)("a",{parentName:"p",href:"/icicle/integrations#using-icicle-integrations"},"this guide")," please."),(0,a.kt)("h2",{id:"icicle-repository-overview"},"ICICLE repository overview"),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"ICICLE API overview",src:i(5870).Z,width:"1932",height:"996"})),(0,a.kt)("p",null,"The diagram above displays the general architecture of ICICLE and the API layers that exist. The CUDA API, which we also call ICICLE Core, is the lowest level and is comprised of CUDA kernels which implement all primitives such as MSM as well as C++ wrappers which expose these methods for different curves."),(0,a.kt)("p",null,"ICICLE Core compiles into a static library. This library can be used with our official Golang and Rust wrappers or you can implement a wrapper for it in any language."),(0,a.kt)("p",null,"Based on this dependency architecture, the ICICLE repository has three main sections, each of which is independent from the other."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"ICICLE core"),(0,a.kt)("li",{parentName:"ul"},"ICICLE Rust bindings"),(0,a.kt)("li",{parentName:"ul"},"ICICLE Golang bindings")),(0,a.kt)("h3",{id:"icicle-core"},"ICICLE Core"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle"},"ICICLE core")," contains all the low level CUDA code implementing primitives such as ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/primitives"},"points")," and ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/appUtils/msm"},"MSM"),". There also exists higher level C++ wrappers to expose the low level CUDA primitives (",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/c1a32a9879a7612916e05aa3098f76144de4109e/icicle/appUtils/msm/msm.cu#L1"},"example"),")."),(0,a.kt)("p",null,"ICICLE Core would typically be compiled into a static library and used in a third party language such as Rust or Golang."),(0,a.kt)("h3",{id:"icicle-rust-and-golang-bindings"},"ICICLE Rust and Golang bindings"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust"},"ICICLE Rust bindings")),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/tree/main/goicicle"},"ICICLE Golang bindings"))),(0,a.kt)("p",null,"These bindings allow you to easily use ICICLE in a Rust or Golang project. Setting up Golang bindings requires a bit of extra steps compared to the Rust bindings which utilize the ",(0,a.kt)("inlineCode",{parentName:"p"},"cargo build")," tool."),(0,a.kt)("h2",{id:"running-icicle"},"Running ICICLE"),(0,a.kt)("p",null,"This guide assumes that you have a Linux or Windows machine with a Nvidia GPU installed. If you don't have access to a Nvidia GPU you can access one for free on ",(0,a.kt)("a",{parentName:"p",href:"https://colab.google/"},"Google Colab"),"."),(0,a.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"NVCC (version 12.0 or newer)"),(0,a.kt)("li",{parentName:"ul"},"cmake 3.18 and above"),(0,a.kt)("li",{parentName:"ul"},"GCC - version 9 or newer is recommended."),(0,a.kt)("li",{parentName:"ul"},"Any Nvidia GPU"),(0,a.kt)("li",{parentName:"ul"},"Linux or Windows operating system.")),(0,a.kt)("h4",{id:"optional-prerequisites"},"Optional Prerequisites"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Docker, latest version."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html"},"NVIDIA Container Toolkit"))),(0,a.kt)("p",null,"If you don't wish to install these prerequisites you can follow this tutorial using a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/Dockerfile"},"ZK-Container")," (docker container). To learn more about using ZK-Containers ",(0,a.kt)("a",{parentName:"p",href:"/ZKContainers"},"read this"),"."),(0,a.kt)("h3",{id:"setting-up-icicle-and-running-tests"},"Setting up ICICLE and running tests"),(0,a.kt)("p",null,"The objective of this guide is to make sure you can run the ICICLE Core, Rust and Golang tests. Achieving this will ensure you know how to setup ICICLE and run a ICICLE program. For simplicity, we will be using the ICICLE docker container as our environment, however, you may install the prerequisites on your machine and follow the same commands in your terminal."),(0,a.kt)("h4",{id:"setting-up-our-environment"},"Setting up our environment"),(0,a.kt)("p",null,"Lets begin by cloning the ICICLE repository:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"git clone https://github.com/ingonyama-zk/icicle\n")),(0,a.kt)("p",null,"We will proceed to build the docker image ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/Dockerfile"},"found here"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker build -t icicle-demo .\ndocker run -it --runtime=nvidia --gpus all --name icicle_container icicle-demo\n")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"-it")," runs the container in interactive mode with a terminal."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"--gpus all")," Allocate all available GPUs to the container. You can also specify which GPUs to use if you don't want to allocate all."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"--runtime=nvidia")," Use the NVIDIA runtime, necessary for GPU support.")),(0,a.kt)("p",null,"To read more about these settings reference this ",(0,a.kt)("a",{parentName:"p",href:"https://developer.nvidia.com/nvidia-container-runtime"},"article"),"."),(0,a.kt)("p",null,"If you accidentally close your terminal and want to reconnect just call:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker exec -it icicle_container bash\n")),(0,a.kt)("p",null,"Lets make sure that we have the correct CUDA version before proceeding"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"nvcc --version\n")),(0,a.kt)("p",null,"You should see something like this"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"nvcc: NVIDIA (R) Cuda compiler driver\nCopyright (c) 2005-2023 NVIDIA Corporation\nBuilt on Tue_Aug_15_22:02:13_PDT_2023\nCuda compilation tools, release 12.2, V12.2.140\nBuild cuda_12.2.r12.2/compiler.33191640_0\n")),(0,a.kt)("p",null,"Make sure the release version is at least 12.0."),(0,a.kt)("h4",{id:"icicle-core-1"},"ICICLE Core"),(0,a.kt)("p",null,"ICICLE Core is found under ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle"},(0,a.kt)("inlineCode",{parentName:"a"},"/icicle")),". To build and run the tests first:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd icicle\n")),(0,a.kt)("p",null,"We are going to compile ICICLE for a specific curve"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"mkdir -p build\ncmake -S . -B build -DCURVE=bn254 -DBUILD_TESTS=ON\ncmake --build build\n")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"-DBUILD_TESTS=ON")," compiles the tests, without this flag ",(0,a.kt)("inlineCode",{parentName:"p"},"ctest")," won't work.\n",(0,a.kt)("inlineCode",{parentName:"p"},"-DCURVE=bn254")," tells the compiler which curve to build. You can find a list of supported curves ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/curves"},"here"),"."),(0,a.kt)("p",null,"The output in ",(0,a.kt)("inlineCode",{parentName:"p"},"build")," folder should include the static libraries for the compiled curve."),(0,a.kt)("div",{className:"admonition admonition-info alert alert--info"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"}))),"info")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"Make sure to only use ",(0,a.kt)("inlineCode",{parentName:"p"},"-DBUILD_TESTS=ON")," for running tests as the archive output will only be available when ",(0,a.kt)("inlineCode",{parentName:"p"},"-DBUILD_TESTS=ON")," is not supplied."))),(0,a.kt)("p",null,"To run the test"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd build\nctest\n")),(0,a.kt)("h4",{id:"icicle-rust"},"ICICLE Rust"),(0,a.kt)("p",null,"The rust bindings work by first compiling the CUDA static libraries as seen ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/wrappers/rust/icicle-curves/icicle-bn254/build.rs"},"here"),". The compilation of CUDA and the Rust library is all handled by the rust build toolchain."),(0,a.kt)("p",null,"Similar to ICICLE Core here we also have to compile per curve."),(0,a.kt)("p",null,"Lets compile curve ",(0,a.kt)("inlineCode",{parentName:"p"},"bn254")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd wrappers/rust/icicle-curves/icicle-bn254\n")),(0,a.kt)("p",null,"Now lets build our library"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cargo build --release\n")),(0,a.kt)("p",null,"This may take a couple of minutes since we are compiling both the CUDA and Rust code."),(0,a.kt)("p",null,"To run the tests"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cargo test -- --test-threads=1\n")),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"--test-threads=1")," is needed because currently some tests might interfere with one another inside the GPU."),(0,a.kt)("p",null,"We also include some benchmarks"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cargo bench\n")),(0,a.kt)("h4",{id:"icicle-golang"},"ICICLE Golang"),(0,a.kt)("p",null,"Golang is WIP in v1, coming soon. Please checkout a previous ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases/tag/v0.1.0"},"release v0.1.0")," for golang bindings."),(0,a.kt)("h3",{id:"running-icicle-examples"},"Running ICICLE examples"),(0,a.kt)("p",null,"ICICLE examples can be found ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle-examples"},"here")," these examples cover some simple use cases using C++, rust and golang."),(0,a.kt)("p",null,"In each example directory, ZK-container files are located in a subdirectory ",(0,a.kt)("inlineCode",{parentName:"p"},".devcontainer"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"msm/\n\u251c\u2500\u2500 .devcontainer\n \u251c\u2500\u2500 devcontainer.json\n \u2514\u2500\u2500 Dockerfile\n")),(0,a.kt)("p",null,"Lets run one of our C++ examples, in this case the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle-examples/blob/main/c%2B%2B/msm/example.cu"},"MSM example"),"."),(0,a.kt)("p",null,"Clone the repository"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"git clone https://github.com/ingonyama-zk/icicle-examples.git\ncd icicle-examples\n")),(0,a.kt)("p",null,"Enter the test directory"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"cd c++/msm\n")),(0,a.kt)("p",null,"Now lets build our docker file and run the test inside it. Make sure you have installed the ",(0,a.kt)("a",{parentName:"p",href:"#optional-prerequisites"},"optional prerequisites"),"."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker build -t icicle-example-msm -f .devcontainer/Dockerfile .\n")),(0,a.kt)("p",null,"Lets start and enter the container"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"docker run -it --rm --gpus all -v .:/icicle-example icicle-example-msm\n")),(0,a.kt)("p",null,"to run the example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"rm -rf build\nmkdir -p build\ncmake -S . -B build\ncmake --build build\n./build/example\n")),(0,a.kt)("p",null,"You can now experiment with our other examples, perhaps try to run a rust or golang example next."),(0,a.kt)("h2",{id:"writing-new-bindings-for-icicle"},"Writing new bindings for ICICLE"),(0,a.kt)("p",null,"Since ICICLE Core is written in CUDA / C++ its really simple to generate static libraries. These static libraries can be installed on any system and called by higher level languages such as Golang."),(0,a.kt)("p",null,"static libraries can be loaded into memory once and used by multiple programs, reducing memory usage and potentially improving performance. They also allow you to separate functionality into distinct modules so your static library may need to compile only specific features that you want to use."),(0,a.kt)("p",null,"Lets review the Golang bindings since its a pretty verbose example (compared to rust which hides it pretty well) of using static libraries. Golang has a library named ",(0,a.kt)("inlineCode",{parentName:"p"},"CGO")," which can be used to link static libraries. Here's a basic example on how you can use cgo to link these libraries:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-go"},'/*\n#cgo LDFLAGS: -L/path/to/shared/libs -lbn254 -lbls12_381 -lbls12_377 -lbw6_671\n#include "icicle.h" // make sure you use the correct header file(s)\n*/\nimport "C"\n\nfunc main() {\n // Now you can call the C functions from the ICICLE libraries.\n // Note that C function calls are prefixed with \'C.\' in Go code.\n\n out := (*C.BN254_projective_t)(unsafe.Pointer(p))\n in := (*C.BN254_affine_t)(unsafe.Pointer(affine))\n\n C.projective_from_affine_bn254(out, in)\n}\n')),(0,a.kt)("p",null,"The comments on the first line tell ",(0,a.kt)("inlineCode",{parentName:"p"},"CGO")," which libraries to import as well as which header files to include. You can then call methods which are part of the static library and defined in the header file, ",(0,a.kt)("inlineCode",{parentName:"p"},"C.projective_from_affine_bn254")," is an example."),(0,a.kt)("p",null,"If you wish to create your own bindings for a language of your choice we suggest you start by investigating how you can call static libraries."),(0,a.kt)("h3",{id:"icicle-adapters"},"ICICLE Adapters"),(0,a.kt)("p",null,"One of the core ideas behind ICICLE is that developers can gradually accelerate their provers. Many protocols are written using other cryptographic libraries and completely replacing them may be complex and time consuming."),(0,a.kt)("p",null,"Therefore we offer adapters for various popular libraries, these adapters allow us to convert points and scalars between different formats defined by various libraries. Here is a list:"),(0,a.kt)("p",null,"Golang adapters:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/iciclegnark"},"Gnark crypto adapter"))))}d.isMDXComponent=!0},5870:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/apilevels-1ab85a883df418516e16eb87aa7b0385.png"},8209:(e,t,i)=>{i(7294)}}]); \ No newline at end of file diff --git a/assets/js/3db59c3c.422f8b46.js b/assets/js/3db59c3c.ed96355d.js similarity index 98% rename from assets/js/3db59c3c.422f8b46.js rename to assets/js/3db59c3c.ed96355d.js index ba8b3b2..f0fe332 100644 --- a/assets/js/3db59c3c.422f8b46.js +++ b/assets/js/3db59c3c.ed96355d.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[472],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),m=i,f=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(f,o(o({ref:t},u),{},{components:n})):r.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:i,o[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));n(8209);const a={},o="Supporting Additional Curves",c={unversionedId:"icicle/supporting-additional-curves",id:"icicle/supporting-additional-curves",title:"Supporting Additional Curves",description:"Supporting additional curves is still a work in progress and is bound to change in the future. Currently, the process is very manual but plan to automate the majority of it in future releases.",source:"@site/docs/icicle/supporting-additional-curves.md",sourceDirName:"icicle",slug:"/icicle/supporting-additional-curves",permalink:"/icicle/supporting-additional-curves",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/supporting-additional-curves.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"NTT - Number Theoretic Transform",permalink:"/icicle/primitives/ntt"},next:{title:"Run ICICLE on Google Colab",permalink:"/icicle/colab-instructions"}},l={},s=[{value:"ICICLE Core",id:"icicle-core",level:2},{value:"Bindings",id:"bindings",level:2},{value:"Rust",id:"rust",level:3},{value:"Golang",id:"golang",level:3}],u={toc:s},p="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"supporting-additional-curves"},"Supporting Additional Curves"),(0,i.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,i.kt)("div",{parentName:"div",className:"admonition-heading"},(0,i.kt)("h5",{parentName:"div"},(0,i.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,i.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,i.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,i.kt)("div",{parentName:"div",className:"admonition-content"},(0,i.kt)("p",{parentName:"div"},"Supporting additional curves is still a work in progress and is bound to change in the future. Currently, the process is very manual but plan to automate the majority of it in future releases."))),(0,i.kt)("p",null,"We understand the need for ZK developers to use different curves, some common some more exotic. For this reason we designed ICICLE to allow developers to add any curve they desire."),(0,i.kt)("h2",{id:"icicle-core"},"ICICLE Core"),(0,i.kt)("p",null,"ICICLE core is very generic by design so all algorithms and primitives are designed to work based of configuration files ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/icicle/curves/curve_config.cuh"},"selected during compile")," time. This is why we compile ICICLE Core per curve."),(0,i.kt)("p",null,"To add support a new curve you must create a new file under ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/curves"},(0,i.kt)("inlineCode",{parentName:"a"},"icicle/curves")),". The file should be named ",(0,i.kt)("inlineCode",{parentName:"p"},"_params.cuh"),"."),(0,i.kt)("p",null,"We also require some changes to ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/icicle/curves/curve_config.cuh#L16-L29"},(0,i.kt)("inlineCode",{parentName:"a"},"curve_config.cuh")),", we need to add a new curve id."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"...\n\n#define BN254 1\n#define BLS12_381 2\n#define BLS12_377 3\n#define BW6_761 4\n#define 5\n\n...\n")),(0,i.kt)("p",null,"Make sure to modify the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/4beda3a900eda961f39af3a496f8184c52bf3b41/icicle/curves/curve_config.cuh#L16-L29"},"rest of the file")," accordingly."),(0,i.kt)("p",null,"Finally we must modify the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/icicle/CMakeLists.txt#L64"},(0,i.kt)("inlineCode",{parentName:"a"},"make")," file")," to make sure we can compile our new curve."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"set(SUPPORTED_CURVES bn254;bls12_381;bls12_377;bw6_761;)\n")),(0,i.kt)("h2",{id:"bindings"},"Bindings"),(0,i.kt)("p",null,"In order to support a new curves in the binding libraries you first must support it in ICICLE core."),(0,i.kt)("h3",{id:"rust"},"Rust"),(0,i.kt)("p",null,"Create a new folder named ",(0,i.kt)("inlineCode",{parentName:"p"},"icicle-")," under the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust/icicle-curves"},"rust wrappers folder"),". Your new directory should look like this."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"\u2514\u2500\u2500 rust\n \u251c\u2500\u2500 icicle-curves\n \u251c\u2500\u2500 icicle-\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 Cargo.toml\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 build.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 src/\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 curve.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 lib.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 msm/\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 mod.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 ntt/\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 mod.rs\n")),(0,i.kt)("p",null,"Lets look at ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/wrappers/rust/icicle-curves/icicle-bn254/src/ntt/mod.rs"},(0,i.kt)("inlineCode",{parentName:"a"},"ntt/mod.rs"))," for example."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'...\n\nextern "C" {\n #[link_name = "bn254NTTCuda"]\n fn ntt_cuda<\'a>(\n input: *const ScalarField,\n size: usize,\n is_inverse: bool,\n config: &NTTConfig<\'a, ScalarField>,\n output: *mut ScalarField,\n ) -> CudaError;\n\n #[link_name = "bn254DefaultNTTConfig"]\n fn default_ntt_config() -> NTTConfig<\'static, ScalarField>;\n\n #[link_name = "bn254InitializeDomain"]\n fn initialize_ntt_domain(primitive_root: ScalarField, ctx: &DeviceContext) -> CudaError;\n}\n\n...\n')),(0,i.kt)("p",null,"Here you would need to replace ",(0,i.kt)("inlineCode",{parentName:"p"},"bn254NTTCuda")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"NTTCuda"),". Most of these changes are pretty straight forward. One thing you should pay attention to is limb sizes as these change for different curves. For example ",(0,i.kt)("inlineCode",{parentName:"p"},"BN254")," ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/4beda3a900eda961f39af3a496f8184c52bf3b41/wrappers/rust/icicle-curves/icicle-bn254/src/curve.rs#L15"},"has limb size of 8")," but for your curve this may be different."),(0,i.kt)("h3",{id:"golang"},"Golang"),(0,i.kt)("p",null,"Golang is WIP in v1, coming soon. Please checkout a previous ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases/tag/v0.1.0"},"release v0.1.0")," for golang bindings."))}d.isMDXComponent=!0},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[472],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var l=r.createContext({}),s=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,l=e.parentName,u=c(e,["components","mdxType","originalType","parentName"]),p=s(n),m=i,f=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return n?r.createElement(f,o(o({ref:t},u),{},{components:n})):r.createElement(f,o({ref:t},u))}));function f(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[p]="string"==typeof e?e:i,o[1]=c;for(var s=2;s{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>o,default:()=>d,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var r=n(7462),i=(n(7294),n(3905));n(8209);const a={},o="Supporting Additional Curves",c={unversionedId:"icicle/supporting-additional-curves",id:"icicle/supporting-additional-curves",title:"Supporting Additional Curves",description:"Supporting additional curves is still a work in progress and is bound to change in the future. Currently, the process is very manual but plan to automate the majority of it in future releases.",source:"@site/docs/icicle/supporting-additional-curves.md",sourceDirName:"icicle",slug:"/icicle/supporting-additional-curves",permalink:"/icicle/supporting-additional-curves",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/supporting-additional-curves.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"NTT - Number Theoretic Transform",permalink:"/icicle/primitives/ntt"},next:{title:"Run ICICLE on Google Colab",permalink:"/icicle/colab-instructions"}},l={},s=[{value:"ICICLE Core",id:"icicle-core",level:2},{value:"Bindings",id:"bindings",level:2},{value:"Rust",id:"rust",level:3},{value:"Golang",id:"golang",level:3}],u={toc:s},p="wrapper";function d(e){let{components:t,...n}=e;return(0,i.kt)(p,(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"supporting-additional-curves"},"Supporting Additional Curves"),(0,i.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,i.kt)("div",{parentName:"div",className:"admonition-heading"},(0,i.kt)("h5",{parentName:"div"},(0,i.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,i.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,i.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,i.kt)("div",{parentName:"div",className:"admonition-content"},(0,i.kt)("p",{parentName:"div"},"Supporting additional curves is still a work in progress and is bound to change in the future. Currently, the process is very manual but plan to automate the majority of it in future releases."))),(0,i.kt)("p",null,"We understand the need for ZK developers to use different curves, some common some more exotic. For this reason we designed ICICLE to allow developers to add any curve they desire."),(0,i.kt)("h2",{id:"icicle-core"},"ICICLE Core"),(0,i.kt)("p",null,"ICICLE core is very generic by design so all algorithms and primitives are designed to work based of configuration files ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/icicle/curves/curve_config.cuh"},"selected during compile")," time. This is why we compile ICICLE Core per curve."),(0,i.kt)("p",null,"To add support a new curve you must create a new file under ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/icicle/curves"},(0,i.kt)("inlineCode",{parentName:"a"},"icicle/curves")),". The file should be named ",(0,i.kt)("inlineCode",{parentName:"p"},"_params.cuh"),"."),(0,i.kt)("p",null,"We also require some changes to ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/icicle/curves/curve_config.cuh#L16-L29"},(0,i.kt)("inlineCode",{parentName:"a"},"curve_config.cuh")),", we need to add a new curve id."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"...\n\n#define BN254 1\n#define BLS12_381 2\n#define BLS12_377 3\n#define BW6_761 4\n#define 5\n\n...\n")),(0,i.kt)("p",null,"Make sure to modify the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/4beda3a900eda961f39af3a496f8184c52bf3b41/icicle/curves/curve_config.cuh#L16-L29"},"rest of the file")," accordingly."),(0,i.kt)("p",null,"Finally we must modify the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/icicle/CMakeLists.txt#L64"},(0,i.kt)("inlineCode",{parentName:"a"},"make")," file")," to make sure we can compile our new curve."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"set(SUPPORTED_CURVES bn254;bls12_381;bls12_377;bw6_761;)\n")),(0,i.kt)("h2",{id:"bindings"},"Bindings"),(0,i.kt)("p",null,"In order to support a new curves in the binding libraries you first must support it in ICICLE core."),(0,i.kt)("h3",{id:"rust"},"Rust"),(0,i.kt)("p",null,"Create a new folder named ",(0,i.kt)("inlineCode",{parentName:"p"},"icicle-")," under the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust/icicle-curves"},"rust wrappers folder"),". Your new directory should look like this."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"\u2514\u2500\u2500 rust\n \u251c\u2500\u2500 icicle-curves\n \u251c\u2500\u2500 icicle-\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 Cargo.toml\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 build.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 src/\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 curve.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 lib.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u251c\u2500\u2500 msm/\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 mod.rs\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 ntt/\n \u2502\xa0\xa0 \u2502\xa0\xa0 \u2514\u2500\u2500 mod.rs\n")),(0,i.kt)("p",null,"Lets look at ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/wrappers/rust/icicle-curves/icicle-bn254/src/ntt/mod.rs"},(0,i.kt)("inlineCode",{parentName:"a"},"ntt/mod.rs"))," for example."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'...\n\nextern "C" {\n #[link_name = "bn254NTTCuda"]\n fn ntt_cuda<\'a>(\n input: *const ScalarField,\n size: usize,\n is_inverse: bool,\n config: &NTTConfig<\'a, ScalarField>,\n output: *mut ScalarField,\n ) -> CudaError;\n\n #[link_name = "bn254DefaultNTTConfig"]\n fn default_ntt_config() -> NTTConfig<\'static, ScalarField>;\n\n #[link_name = "bn254InitializeDomain"]\n fn initialize_ntt_domain(primitive_root: ScalarField, ctx: &DeviceContext) -> CudaError;\n}\n\n...\n')),(0,i.kt)("p",null,"Here you would need to replace ",(0,i.kt)("inlineCode",{parentName:"p"},"bn254NTTCuda")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"NTTCuda"),". Most of these changes are pretty straight forward. One thing you should pay attention to is limb sizes as these change for different curves. For example ",(0,i.kt)("inlineCode",{parentName:"p"},"BN254")," ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/4beda3a900eda961f39af3a496f8184c52bf3b41/wrappers/rust/icicle-curves/icicle-bn254/src/curve.rs#L15"},"has limb size of 8")," but for your curve this may be different."),(0,i.kt)("h3",{id:"golang"},"Golang"),(0,i.kt)("p",null,"Golang is WIP in v1, coming soon. Please checkout a previous ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases/tag/v0.1.0"},"release v0.1.0")," for golang bindings."))}d.isMDXComponent=!0},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file diff --git a/assets/js/46bc3aca.cc5c1b6f.js b/assets/js/46bc3aca.7b300224.js similarity index 98% rename from assets/js/46bc3aca.cc5c1b6f.js rename to assets/js/46bc3aca.7b300224.js index 1f2453a..f9629a8 100644 --- a/assets/js/46bc3aca.cc5c1b6f.js +++ b/assets/js/46bc3aca.7b300224.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[287],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>f});var r=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function a(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=r.createContext({}),s=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},p=function(e){var n=s(e.components);return r.createElement(l.Provider,{value:n},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(t),d=i,f=u["".concat(l,".").concat(d)]||u[d]||g[d]||o;return t?r.createElement(f,a(a({ref:n},p),{},{components:t})):r.createElement(f,a({ref:n},p))}));function f(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=d;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c[u]="string"==typeof e?e:i,a[1]=c;for(var s=2;s{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>g,frontMatter:()=>o,metadata:()=>c,toc:()=>s});var r=t(7462),i=(t(7294),t(3905));t(8209);const o={},a="Golang bindings",c={unversionedId:"icicle/golang-bindings",id:"icicle/golang-bindings",title:"Golang bindings",description:"Golang is WIP in v1, coming soon. Please checkout a previous release v0.1.0 for golang bindings.",source:"@site/docs/icicle/golang-bindings.md",sourceDirName:"icicle",slug:"/icicle/golang-bindings",permalink:"/icicle/golang-bindings",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/golang-bindings.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"ICICLE integrated provers",permalink:"/icicle/integrations"},next:{title:"Rust bindings",permalink:"/icicle/rust-bindings"}},l={},s=[],p={toc:s},u="wrapper";function g(e){let{components:n,...t}=e;return(0,i.kt)(u,(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"golang-bindings"},"Golang bindings"),(0,i.kt)("p",null,"Golang is WIP in v1, coming soon. Please checkout a previous ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases/tag/v0.1.0"},"release v0.1.0")," for golang bindings."))}g.isMDXComponent=!0},8209:(e,n,t)=>{t(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[287],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>f});var r=t(7294);function i(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function a(e){for(var n=1;n=0||(i[t]=e[t]);return i}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(i[t]=e[t])}return i}var l=r.createContext({}),s=function(e){var n=r.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):a(a({},n),e)),t},p=function(e){var n=s(e.components);return r.createElement(l.Provider,{value:n},e.children)},u="mdxType",g={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},d=r.forwardRef((function(e,n){var t=e.components,i=e.mdxType,o=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(t),d=i,f=u["".concat(l,".").concat(d)]||u[d]||g[d]||o;return t?r.createElement(f,a(a({ref:n},p),{},{components:t})):r.createElement(f,a({ref:n},p))}));function f(e,n){var t=arguments,i=n&&n.mdxType;if("string"==typeof e||i){var o=t.length,a=new Array(o);a[0]=d;var c={};for(var l in n)hasOwnProperty.call(n,l)&&(c[l]=n[l]);c.originalType=e,c[u]="string"==typeof e?e:i,a[1]=c;for(var s=2;s{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>a,default:()=>g,frontMatter:()=>o,metadata:()=>c,toc:()=>s});var r=t(7462),i=(t(7294),t(3905));t(8209);const o={},a="Golang bindings",c={unversionedId:"icicle/golang-bindings",id:"icicle/golang-bindings",title:"Golang bindings",description:"Golang is WIP in v1, coming soon. Please checkout a previous release v0.1.0 for golang bindings.",source:"@site/docs/icicle/golang-bindings.md",sourceDirName:"icicle",slug:"/icicle/golang-bindings",permalink:"/icicle/golang-bindings",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/golang-bindings.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"ICICLE integrated provers",permalink:"/icicle/integrations"},next:{title:"Rust bindings",permalink:"/icicle/rust-bindings"}},l={},s=[],p={toc:s},u="wrapper";function g(e){let{components:n,...t}=e;return(0,i.kt)(u,(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,i.kt)("h1",{id:"golang-bindings"},"Golang bindings"),(0,i.kt)("p",null,"Golang is WIP in v1, coming soon. Please checkout a previous ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases/tag/v0.1.0"},"release v0.1.0")," for golang bindings."))}g.isMDXComponent=!0},8209:(e,n,t)=>{t(7294)}}]); \ No newline at end of file diff --git a/assets/js/584ea0b6.c8828735.js b/assets/js/584ea0b6.d52ce6af.js similarity index 97% rename from assets/js/584ea0b6.c8828735.js rename to assets/js/584ea0b6.d52ce6af.js index 920ebef..c33fa3e 100644 --- a/assets/js/584ea0b6.c8828735.js +++ b/assets/js/584ea0b6.d52ce6af.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[83],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),g=a,d=u["".concat(c,".").concat(g)]||u[g]||m[g]||o;return r?n.createElement(d,i(i({ref:t},p),{},{components:r})):n.createElement(d,i({ref:t},p))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=g;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var n=r(7462),a=(r(7294),r(3905));r(8209);const o={},i="Ingonyama Grant programs",s={unversionedId:"grants",id:"grants",title:"Ingonyama Grant programs",description:"Ingonyama understands the importance of supporting and fostering a vibrant community of researchers and builders to advance ZK. To encourage progress, we are not only developing in the open but also sharing resources with researchers and builders through various programs.",source:"@site/docs/grants.md",sourceDirName:".",slug:"/grants",permalink:"/grants",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/grants.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"ZKContainer",permalink:"/ZKContainers"},next:{title:"Contributor's Guide",permalink:"/contributor-guide"}},c={},l=[{value:"ICICLE ZK-GPU Ecosystem Grant",id:"icicle-zk-gpu-ecosystem-grant",level:2},{value:"Bounties & Grants",id:"bounties--grants",level:3},{value:"Contact",id:"contact",level:2}],p={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"ingonyama-grant-programs"},"Ingonyama Grant programs"),(0,a.kt)("p",null,"Ingonyama understands the importance of supporting and fostering a vibrant community of researchers and builders to advance ZK. To encourage progress, we are not only developing in the open but also sharing resources with researchers and builders through various programs."),(0,a.kt)("h2",{id:"icicle-zk-gpu-ecosystem-grant"},"ICICLE ZK-GPU Ecosystem Grant"),(0,a.kt)("p",null,"Ingonyama invites researchers and practitioners to collaborate in advancing ZK acceleration. We are allocating $100,000 for grants to support this initiative."),(0,a.kt)("h3",{id:"bounties--grants"},"Bounties & Grants"),(0,a.kt)("p",null,"Eligibility for grants includes:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Students"),": Utilize ICICLE in your research."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Performance Improvement"),": Enhance the performance of accelerated primitives in ICICLE."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Protocol Porting"),": Migrate existing ZK protocols to ICICLE."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"New Primitives"),": Contribute new primitives to ICICLE."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Benchmarking"),": Compare ZK benchmarks against ICICLE.")),(0,a.kt)("h2",{id:"contact"},"Contact"),(0,a.kt)("p",null,"For questions or submissions: ",(0,a.kt)("a",{parentName:"p",href:"mailto:grants@ingonyama.com"},"grants@ingonyama.com")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Read the full article ",(0,a.kt)("a",{parentName:"strong",href:"https://www.ingonyama.com/blog/icicle-for-researchers-grants-challenges"},"here"))))}m.isMDXComponent=!0},8209:(e,t,r)=>{r(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[83],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>d});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var c=n.createContext({}),l=function(e){var t=n.useContext(c),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=l(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=l(r),g=a,d=u["".concat(c,".").concat(g)]||u[g]||m[g]||o;return r?n.createElement(d,i(i({ref:t},p),{},{components:r})):n.createElement(d,i({ref:t},p))}));function d(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=g;var s={};for(var c in t)hasOwnProperty.call(t,c)&&(s[c]=t[c]);s.originalType=e,s[u]="string"==typeof e?e:a,i[1]=s;for(var l=2;l{r.r(t),r.d(t,{assets:()=>c,contentTitle:()=>i,default:()=>m,frontMatter:()=>o,metadata:()=>s,toc:()=>l});var n=r(7462),a=(r(7294),r(3905));r(8209);const o={},i="Ingonyama Grant programs",s={unversionedId:"grants",id:"grants",title:"Ingonyama Grant programs",description:"Ingonyama understands the importance of supporting and fostering a vibrant community of researchers and builders to advance ZK. To encourage progress, we are not only developing in the open but also sharing resources with researchers and builders through various programs.",source:"@site/docs/grants.md",sourceDirName:".",slug:"/grants",permalink:"/grants",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/grants.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"ZKContainer",permalink:"/ZKContainers"},next:{title:"Contributor's Guide",permalink:"/contributor-guide"}},c={},l=[{value:"ICICLE ZK-GPU Ecosystem Grant",id:"icicle-zk-gpu-ecosystem-grant",level:2},{value:"Bounties & Grants",id:"bounties--grants",level:3},{value:"Contact",id:"contact",level:2}],p={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,n.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"ingonyama-grant-programs"},"Ingonyama Grant programs"),(0,a.kt)("p",null,"Ingonyama understands the importance of supporting and fostering a vibrant community of researchers and builders to advance ZK. To encourage progress, we are not only developing in the open but also sharing resources with researchers and builders through various programs."),(0,a.kt)("h2",{id:"icicle-zk-gpu-ecosystem-grant"},"ICICLE ZK-GPU Ecosystem Grant"),(0,a.kt)("p",null,"Ingonyama invites researchers and practitioners to collaborate in advancing ZK acceleration. We are allocating $100,000 for grants to support this initiative."),(0,a.kt)("h3",{id:"bounties--grants"},"Bounties & Grants"),(0,a.kt)("p",null,"Eligibility for grants includes:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Students"),": Utilize ICICLE in your research."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Performance Improvement"),": Enhance the performance of accelerated primitives in ICICLE."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Protocol Porting"),": Migrate existing ZK protocols to ICICLE."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"New Primitives"),": Contribute new primitives to ICICLE."),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("strong",{parentName:"li"},"Benchmarking"),": Compare ZK benchmarks against ICICLE.")),(0,a.kt)("h2",{id:"contact"},"Contact"),(0,a.kt)("p",null,"For questions or submissions: ",(0,a.kt)("a",{parentName:"p",href:"mailto:grants@ingonyama.com"},"grants@ingonyama.com")),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Read the full article ",(0,a.kt)("a",{parentName:"strong",href:"https://www.ingonyama.com/blog/icicle-for-researchers-grants-challenges"},"here"))))}m.isMDXComponent=!0},8209:(e,t,r)=>{r(7294)}}]); \ No newline at end of file diff --git a/assets/js/62ce5d13.2a27b3b1.js b/assets/js/62ce5d13.dd7fe865.js similarity index 98% rename from assets/js/62ce5d13.2a27b3b1.js rename to assets/js/62ce5d13.dd7fe865.js index ad2949f..8583b60 100644 --- a/assets/js/62ce5d13.2a27b3b1.js +++ b/assets/js/62ce5d13.dd7fe865.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[774],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(n),d=a,g=p["".concat(l,".").concat(d)]||p[d]||m[d]||o;return n?r.createElement(g,s(s({ref:t},u),{},{components:n})):r.createElement(g,s({ref:t},u))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:a,s[1]=i;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));n(8209);const o={},s="Run ICICLE on Google Colab",i={unversionedId:"icicle/colab-instructions",id:"icicle/colab-instructions",title:"Run ICICLE on Google Colab",description:"Google Colab let's you use a GPU free of charge, it's an Nvidia T4 GPU with 16 GB of memory, capable of running latest CUDA (tested on Cuda 12.2)",source:"@site/docs/icicle/colab-instructions.md",sourceDirName:"icicle",slug:"/icicle/colab-instructions",permalink:"/icicle/colab-instructions",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/colab-instructions.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Supporting Additional Curves",permalink:"/icicle/supporting-additional-curves"},next:{title:"ZKContainer",permalink:"/ZKContainers"}},l={},c=[{value:"Prepare Colab environment",id:"prepare-colab-environment",level:2},{value:"Cloning ICICLE and running test",id:"cloning-icicle-and-running-test",level:2}],u={toc:c},p="wrapper";function m(e){let{components:t,...o}=e;return(0,a.kt)(p,(0,r.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"run-icicle-on-google-colab"},"Run ICICLE on Google Colab"),(0,a.kt)("p",null,"Google Colab let's you use a GPU free of charge, it's an Nvidia T4 GPU with 16 GB of memory, capable of running latest CUDA (tested on Cuda 12.2)\nAs Colab is able to interact with shell commands, a user can also install a framework and load git repositories into Colab space."),(0,a.kt)("h2",{id:"prepare-colab-environment"},"Prepare Colab environment"),(0,a.kt)("p",null,"First thing to do in a notebook is to set the runtime type to a T4 GPU."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},'in the upper corner click on the dropdown menu and select "change runtime type"')),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Change runtime",src:n(4429).Z,width:"423",height:"388"})),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},'In the window select "T4 GPU" and press Save')),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"T4 GPU",src:n(8259).Z,width:"582",height:"424"})),(0,a.kt)("p",null,"Installing Rust is rather simple, just execute the following command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!apt install rustc cargo\n")),(0,a.kt)("p",null,"To test the installation of Rust:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!rustc --version\n!cargo --version\n")),(0,a.kt)("p",null,"A successful installation will result in a rustc and cargo version print, a faulty installation will look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"/bin/bash: line 1: rustc: command not found\n/bin/bash: line 1: cargo: command not found\n")),(0,a.kt)("p",null,"Now we will check the environment:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!nvcc --version\n!gcc --version\n!cmake --version\n!nvidia-smi\n")),(0,a.kt)("p",null,"A correct environment should print the result with no bash errors for ",(0,a.kt)("inlineCode",{parentName:"p"},"nvidia-smi")," command and result in a ",(0,a.kt)("strong",{parentName:"p"},"Teslt T4 GPU")," type:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"nvcc: NVIDIA (R) Cuda compiler driver\nCopyright (c) 2005-2023 NVIDIA Corporation\nBuilt on Tue_Aug_15_22:02:13_PDT_2023\nCuda compilation tools, release 12.2, V12.2.140\nBuild cuda_12.2.r12.2/compiler.33191640_0\ngcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0\nCopyright (C) 2021 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ncmake version 3.27.9\n\nCMake suite maintained and supported by Kitware (kitware.com/cmake).\nWed Jan 17 13:10:18 2024\n+---------------------------------------------------------------------------------------+\n| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n|-----------------------------------------+----------------------+----------------------+\n| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n| | | MIG M. |\n|=========================================+======================+======================|\n| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n| N/A 39C P8 9W / 70W | 0MiB / 15360MiB | 0% Default |\n| | | N/A |\n+-----------------------------------------+----------------------+----------------------+\n\n+---------------------------------------------------------------------------------------+\n| Processes: |\n| GPU GI CI PID Type Process name GPU Memory |\n| ID ID Usage |\n|=======================================================================================|\n| No running processes found |\n+---------------------------------------------------------------------------------------+\n")),(0,a.kt)("h2",{id:"cloning-icicle-and-running-test"},"Cloning ICICLE and running test"),(0,a.kt)("p",null,"Now we are ready to clone ICICE repository,"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!git clone https://github.com/ingonyama-zk/icicle.git\n")),(0,a.kt)("p",null,"We now can browse the repository and run tests to check the runtime environment:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!ls -la\n%cd icicle\n")),(0,a.kt)("p",null,"Let's run a test!\nNavigate to icicle/wrappers/rust/icicle-curves/icicle-bn254 and run cargo test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"%cd wrappers/rust/icicle-curves/icicle-bn254/\n!cargo test --release\n")),(0,a.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"Compiling the first time may take a while"))),(0,a.kt)("p",null,"Test run should end like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"running 15 tests\ntest curve::tests::test_ark_point_convert ... ok\ntest curve::tests::test_ark_scalar_convert ... ok\ntest curve::tests::test_affine_projective_convert ... ok\ntest curve::tests::test_point_equality ... ok\ntest curve::tests::test_field_convert_montgomery ... ok\ntest curve::tests::test_scalar_equality ... ok\ntest curve::tests::test_points_convert_montgomery ... ok\ntest msm::tests::test_msm ... ok\ntest msm::tests::test_msm_skewed_distributions ... ok\ntest ntt::tests::test_ntt ... ok\ntest ntt::tests::test_ntt_arbitrary_coset ... ok\ntest msm::tests::test_msm_batch has been running for over 60 seconds\ntest msm::tests::test_msm_batch ... ok\ntest ntt::tests::test_ntt_coset_from_subgroup ... ok\ntest ntt::tests::test_ntt_device_async ... ok\ntest ntt::tests::test_ntt_batch ... ok\n\ntest result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 99.39s\n")),(0,a.kt)("p",null,"Viola, ICICLE in Colab!"))}m.isMDXComponent=!0},4429:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/colab_change_runtime-eda3091877f78ec971a41338d6b33c2c.png"},8259:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/t4_gpu-798c30098fd3b77784113e9a13659489.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[774],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),c=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=c(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),p=c(n),d=a,g=p["".concat(l,".").concat(d)]||p[d]||m[d]||o;return n?r.createElement(g,s(s({ref:t},u),{},{components:n})):r.createElement(g,s({ref:t},u))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,s=new Array(o);s[0]=d;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[p]="string"==typeof e?e:a,s[1]=i;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(7462),a=(n(7294),n(3905));n(8209);const o={},s="Run ICICLE on Google Colab",i={unversionedId:"icicle/colab-instructions",id:"icicle/colab-instructions",title:"Run ICICLE on Google Colab",description:"Google Colab let's you use a GPU free of charge, it's an Nvidia T4 GPU with 16 GB of memory, capable of running latest CUDA (tested on Cuda 12.2)",source:"@site/docs/icicle/colab-instructions.md",sourceDirName:"icicle",slug:"/icicle/colab-instructions",permalink:"/icicle/colab-instructions",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/colab-instructions.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Supporting Additional Curves",permalink:"/icicle/supporting-additional-curves"},next:{title:"ZKContainer",permalink:"/ZKContainers"}},l={},c=[{value:"Prepare Colab environment",id:"prepare-colab-environment",level:2},{value:"Cloning ICICLE and running test",id:"cloning-icicle-and-running-test",level:2}],u={toc:c},p="wrapper";function m(e){let{components:t,...o}=e;return(0,a.kt)(p,(0,r.Z)({},u,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"run-icicle-on-google-colab"},"Run ICICLE on Google Colab"),(0,a.kt)("p",null,"Google Colab let's you use a GPU free of charge, it's an Nvidia T4 GPU with 16 GB of memory, capable of running latest CUDA (tested on Cuda 12.2)\nAs Colab is able to interact with shell commands, a user can also install a framework and load git repositories into Colab space."),(0,a.kt)("h2",{id:"prepare-colab-environment"},"Prepare Colab environment"),(0,a.kt)("p",null,"First thing to do in a notebook is to set the runtime type to a T4 GPU."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},'in the upper corner click on the dropdown menu and select "change runtime type"')),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"Change runtime",src:n(4429).Z,width:"423",height:"388"})),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},'In the window select "T4 GPU" and press Save')),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"T4 GPU",src:n(8259).Z,width:"582",height:"424"})),(0,a.kt)("p",null,"Installing Rust is rather simple, just execute the following command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!apt install rustc cargo\n")),(0,a.kt)("p",null,"To test the installation of Rust:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!rustc --version\n!cargo --version\n")),(0,a.kt)("p",null,"A successful installation will result in a rustc and cargo version print, a faulty installation will look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"/bin/bash: line 1: rustc: command not found\n/bin/bash: line 1: cargo: command not found\n")),(0,a.kt)("p",null,"Now we will check the environment:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!nvcc --version\n!gcc --version\n!cmake --version\n!nvidia-smi\n")),(0,a.kt)("p",null,"A correct environment should print the result with no bash errors for ",(0,a.kt)("inlineCode",{parentName:"p"},"nvidia-smi")," command and result in a ",(0,a.kt)("strong",{parentName:"p"},"Teslt T4 GPU")," type:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"nvcc: NVIDIA (R) Cuda compiler driver\nCopyright (c) 2005-2023 NVIDIA Corporation\nBuilt on Tue_Aug_15_22:02:13_PDT_2023\nCuda compilation tools, release 12.2, V12.2.140\nBuild cuda_12.2.r12.2/compiler.33191640_0\ngcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0\nCopyright (C) 2021 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions. There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ncmake version 3.27.9\n\nCMake suite maintained and supported by Kitware (kitware.com/cmake).\nWed Jan 17 13:10:18 2024\n+---------------------------------------------------------------------------------------+\n| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n|-----------------------------------------+----------------------+----------------------+\n| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n| | | MIG M. |\n|=========================================+======================+======================|\n| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n| N/A 39C P8 9W / 70W | 0MiB / 15360MiB | 0% Default |\n| | | N/A |\n+-----------------------------------------+----------------------+----------------------+\n\n+---------------------------------------------------------------------------------------+\n| Processes: |\n| GPU GI CI PID Type Process name GPU Memory |\n| ID ID Usage |\n|=======================================================================================|\n| No running processes found |\n+---------------------------------------------------------------------------------------+\n")),(0,a.kt)("h2",{id:"cloning-icicle-and-running-test"},"Cloning ICICLE and running test"),(0,a.kt)("p",null,"Now we are ready to clone ICICE repository,"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!git clone https://github.com/ingonyama-zk/icicle.git\n")),(0,a.kt)("p",null,"We now can browse the repository and run tests to check the runtime environment:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"!ls -la\n%cd icicle\n")),(0,a.kt)("p",null,"Let's run a test!\nNavigate to icicle/wrappers/rust/icicle-curves/icicle-bn254 and run cargo test:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"%cd wrappers/rust/icicle-curves/icicle-bn254/\n!cargo test --release\n")),(0,a.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,a.kt)("div",{parentName:"div",className:"admonition-heading"},(0,a.kt)("h5",{parentName:"div"},(0,a.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,a.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,a.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,a.kt)("div",{parentName:"div",className:"admonition-content"},(0,a.kt)("p",{parentName:"div"},"Compiling the first time may take a while"))),(0,a.kt)("p",null,"Test run should end like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-sh"},"running 15 tests\ntest curve::tests::test_ark_point_convert ... ok\ntest curve::tests::test_ark_scalar_convert ... ok\ntest curve::tests::test_affine_projective_convert ... ok\ntest curve::tests::test_point_equality ... ok\ntest curve::tests::test_field_convert_montgomery ... ok\ntest curve::tests::test_scalar_equality ... ok\ntest curve::tests::test_points_convert_montgomery ... ok\ntest msm::tests::test_msm ... ok\ntest msm::tests::test_msm_skewed_distributions ... ok\ntest ntt::tests::test_ntt ... ok\ntest ntt::tests::test_ntt_arbitrary_coset ... ok\ntest msm::tests::test_msm_batch has been running for over 60 seconds\ntest msm::tests::test_msm_batch ... ok\ntest ntt::tests::test_ntt_coset_from_subgroup ... ok\ntest ntt::tests::test_ntt_device_async ... ok\ntest ntt::tests::test_ntt_batch ... ok\n\ntest result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 99.39s\n")),(0,a.kt)("p",null,"Viola, ICICLE in Colab!"))}m.isMDXComponent=!0},4429:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/colab_change_runtime-eda3091877f78ec971a41338d6b33c2c.png"},8259:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/t4_gpu-798c30098fd3b77784113e9a13659489.png"},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file diff --git a/assets/js/90656eea.d15777d5.js b/assets/js/90656eea.6292a4ae.js similarity index 98% rename from assets/js/90656eea.d15777d5.js rename to assets/js/90656eea.6292a4ae.js index 0e83ef3..c255bee 100644 --- a/assets/js/90656eea.d15777d5.js +++ b/assets/js/90656eea.6292a4ae.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[827],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>v});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(r),d=n,v=u["".concat(s,".").concat(d)]||u[d]||m[d]||o;return r?i.createElement(v,a(a({ref:t},p),{},{components:r})):i.createElement(v,a({ref:t},p))}));function v(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:n,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));r(8209);const o={},a="ICICLE Primitives",c={unversionedId:"icicle/primitives/overview",id:"icicle/primitives/overview",title:"ICICLE Primitives",description:"This section of the documentation is dedicated to the ICICLE primitives, we will cover the usage and internal details of our primitives such as hashing algorithms, MSM and NTT.",source:"@site/docs/icicle/primitives/overview.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/overview",permalink:"/icicle/primitives/overview",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/overview.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Rust bindings",permalink:"/icicle/rust-bindings"},next:{title:"MSM - Multi scalar multiplication",permalink:"/icicle/primitives/msm"}},s={},l=[{value:"Supported primitives",id:"supported-primitives",level:2}],p={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,n.kt)(u,(0,i.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"icicle-primitives"},"ICICLE Primitives"),(0,n.kt)("p",null,"This section of the documentation is dedicated to the ICICLE primitives, we will cover the usage and internal details of our primitives such as hashing algorithms, MSM and NTT."),(0,n.kt)("h2",{id:"supported-primitives"},"Supported primitives"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"./msm"},"MSM")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/icicle/primitives/poseidon"},"Poseidon Hash"))))}m.isMDXComponent=!0},8209:(e,t,r)=>{r(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[827],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>v});var i=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function a(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=i.createContext({}),l=function(e){var t=i.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):a(a({},t),e)),r},p=function(e){var t=l(e.components);return i.createElement(s.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},d=i.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=l(r),d=n,v=u["".concat(s,".").concat(d)]||u[d]||m[d]||o;return r?i.createElement(v,a(a({ref:t},p),{},{components:r})):i.createElement(v,a({ref:t},p))}));function v(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,a=new Array(o);a[0]=d;var c={};for(var s in t)hasOwnProperty.call(t,s)&&(c[s]=t[s]);c.originalType=e,c[u]="string"==typeof e?e:n,a[1]=c;for(var l=2;l{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>m,frontMatter:()=>o,metadata:()=>c,toc:()=>l});var i=r(7462),n=(r(7294),r(3905));r(8209);const o={},a="ICICLE Primitives",c={unversionedId:"icicle/primitives/overview",id:"icicle/primitives/overview",title:"ICICLE Primitives",description:"This section of the documentation is dedicated to the ICICLE primitives, we will cover the usage and internal details of our primitives such as hashing algorithms, MSM and NTT.",source:"@site/docs/icicle/primitives/overview.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/overview",permalink:"/icicle/primitives/overview",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/overview.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Rust bindings",permalink:"/icicle/rust-bindings"},next:{title:"MSM - Multi scalar multiplication",permalink:"/icicle/primitives/msm"}},s={},l=[{value:"Supported primitives",id:"supported-primitives",level:2}],p={toc:l},u="wrapper";function m(e){let{components:t,...r}=e;return(0,n.kt)(u,(0,i.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"icicle-primitives"},"ICICLE Primitives"),(0,n.kt)("p",null,"This section of the documentation is dedicated to the ICICLE primitives, we will cover the usage and internal details of our primitives such as hashing algorithms, MSM and NTT."),(0,n.kt)("h2",{id:"supported-primitives"},"Supported primitives"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"./msm"},"MSM")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/icicle/primitives/poseidon"},"Poseidon Hash"))))}m.isMDXComponent=!0},8209:(e,t,r)=>{r(7294)}}]); \ No newline at end of file diff --git a/assets/js/93a51358.5e6e7172.js b/assets/js/93a51358.2c386f0b.js similarity index 98% rename from assets/js/93a51358.5e6e7172.js rename to assets/js/93a51358.2c386f0b.js index df4e4d4..b0e2235 100644 --- a/assets/js/93a51358.5e6e7172.js +++ b/assets/js/93a51358.2c386f0b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[984],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>g});var i=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function c(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=i.createContext({}),s=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},u=function(e){var n=s(e.components);return i.createElement(l.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},m=i.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,l=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=s(t),m=r,g=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return t?i.createElement(g,c(c({ref:n},u),{},{components:t})):i.createElement(g,c({ref:n},u))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,c=new Array(a);c[0]=m;var o={};for(var l in n)hasOwnProperty.call(n,l)&&(o[l]=n[l]);o.originalType=e,o[p]="string"==typeof e?e:r,c[1]=o;for(var s=2;s{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>o,toc:()=>s});var i=t(7462),r=(t(7294),t(3905));t(8209);const a={},c="Rust bindings",o={unversionedId:"icicle/rust-bindings",id:"icicle/rust-bindings",title:"Rust bindings",description:"Rust bindings allow you to use ICICLE as a rust library.",source:"@site/docs/icicle/rust-bindings.md",sourceDirName:"icicle",slug:"/icicle/rust-bindings",permalink:"/icicle/rust-bindings",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/rust-bindings.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Golang bindings",permalink:"/icicle/golang-bindings"},next:{title:"ICICLE Primitives",permalink:"/icicle/primitives/overview"}},l={},s=[{value:"Using ICICLE Rust bindings in your project",id:"using-icicle-rust-bindings-in-your-project",level:2}],u={toc:s},p="wrapper";function d(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,i.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"rust-bindings"},"Rust bindings"),(0,r.kt)("p",null,"Rust bindings allow you to use ICICLE as a rust library."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-core")," defines all interfaces, macros and common methods."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-cuda-runtime")," defines DeviceContext which can be used to manage a specific GPU as well as wrapping common CUDA methods."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-curves")," implements all interfaces and macros from icicle-core for each curve. For example icicle-bn254 implements curve bn254. Each curve has its own build script which will build the CUDA libraries for that curve as part of the rust-toolchain build."),(0,r.kt)("h2",{id:"using-icicle-rust-bindings-in-your-project"},"Using ICICLE Rust bindings in your project"),(0,r.kt)("p",null,"Simply add the following to your ",(0,r.kt)("inlineCode",{parentName:"p"},"Cargo.toml"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'# GPU Icicle integration\nicicle-cuda-runtime = { git = "https://github.com/ingonyama-zk/icicle.git", tag = "v1.0.0" }\nicicle-core = { git = "https://github.com/ingonyama-zk/icicle.git", tag = "v1.0.0" }\nicicle-bn254 = { git = "https://github.com/ingonyama-zk/icicle.git", tag = "v1.0.0" }\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-bn254")," being the curve you wish to use and ",(0,r.kt)("inlineCode",{parentName:"p"},"icicle-core")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"icicle-cuda-runtime")," contain ICICLE utilities and CUDA wrappers."),(0,r.kt)("p",null,"If you wish to point to a specific ICICLE branch add ",(0,r.kt)("inlineCode",{parentName:"p"},'branch = ""')," or ",(0,r.kt)("inlineCode",{parentName:"p"},'tag = ""')," to the ICICLE dependency. For a specific commit add ",(0,r.kt)("inlineCode",{parentName:"p"},'rev = ""'),"."),(0,r.kt)("p",null,"When you build your project ICICLE will be built as part of the build command."),(0,r.kt)("h1",{id:"how-do-the-rust-bindings-work"},"How do the rust bindings work?"),(0,r.kt)("p",null,"The rust bindings are just rust wrappers for ICICLE Core static libraries which can be compiled. We integrate the compilation of the static libraries into rusts toolchain to make usage seamless and easy. This is achieved by ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/wrappers/rust/icicle-curves/icicle-bn254/build.rs"},"extending rusts build command"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'use cmake::Config;\nuse std::env::var;\n\nfn main() {\n println!("cargo:rerun-if-env-changed=CXXFLAGS");\n println!("cargo:rerun-if-changed=../../../../icicle");\n\n let cargo_dir = var("CARGO_MANIFEST_DIR").unwrap();\n let profile = var("PROFILE").unwrap();\n\n let out_dir = Config::new("../../../../icicle")\n .define("BUILD_TESTS", "OFF") //TODO: feature\n .define("CURVE", "bn254")\n .define("CMAKE_BUILD_TYPE", "Release")\n .build_target("icicle")\n .build();\n\n println!("cargo:rustc-link-search={}/build", out_dir.display());\n\n println!("cargo:rustc-link-lib=ingo_bn254");\n println!("cargo:rustc-link-lib=stdc++");\n // println!("cargo:rustc-link-search=native=/usr/local/cuda/lib64");\n println!("cargo:rustc-link-lib=cudart");\n}\n')))}d.isMDXComponent=!0},8209:(e,n,t)=>{t(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[984],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>g});var i=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function a(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);n&&(i=i.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,i)}return t}function c(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var l=i.createContext({}),s=function(e){var n=i.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):c(c({},n),e)),t},u=function(e){var n=s(e.components);return i.createElement(l.Provider,{value:n},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var n=e.children;return i.createElement(i.Fragment,{},n)}},m=i.forwardRef((function(e,n){var t=e.components,r=e.mdxType,a=e.originalType,l=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=s(t),m=r,g=p["".concat(l,".").concat(m)]||p[m]||d[m]||a;return t?i.createElement(g,c(c({ref:n},u),{},{components:t})):i.createElement(g,c({ref:n},u))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var a=t.length,c=new Array(a);c[0]=m;var o={};for(var l in n)hasOwnProperty.call(n,l)&&(o[l]=n[l]);o.originalType=e,o[p]="string"==typeof e?e:r,c[1]=o;for(var s=2;s{t.r(n),t.d(n,{assets:()=>l,contentTitle:()=>c,default:()=>d,frontMatter:()=>a,metadata:()=>o,toc:()=>s});var i=t(7462),r=(t(7294),t(3905));t(8209);const a={},c="Rust bindings",o={unversionedId:"icicle/rust-bindings",id:"icicle/rust-bindings",title:"Rust bindings",description:"Rust bindings allow you to use ICICLE as a rust library.",source:"@site/docs/icicle/rust-bindings.md",sourceDirName:"icicle",slug:"/icicle/rust-bindings",permalink:"/icicle/rust-bindings",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/rust-bindings.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Golang bindings",permalink:"/icicle/golang-bindings"},next:{title:"ICICLE Primitives",permalink:"/icicle/primitives/overview"}},l={},s=[{value:"Using ICICLE Rust bindings in your project",id:"using-icicle-rust-bindings-in-your-project",level:2}],u={toc:s},p="wrapper";function d(e){let{components:n,...t}=e;return(0,r.kt)(p,(0,i.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"rust-bindings"},"Rust bindings"),(0,r.kt)("p",null,"Rust bindings allow you to use ICICLE as a rust library."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-core")," defines all interfaces, macros and common methods."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-cuda-runtime")," defines DeviceContext which can be used to manage a specific GPU as well as wrapping common CUDA methods."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-curves")," implements all interfaces and macros from icicle-core for each curve. For example icicle-bn254 implements curve bn254. Each curve has its own build script which will build the CUDA libraries for that curve as part of the rust-toolchain build."),(0,r.kt)("h2",{id:"using-icicle-rust-bindings-in-your-project"},"Using ICICLE Rust bindings in your project"),(0,r.kt)("p",null,"Simply add the following to your ",(0,r.kt)("inlineCode",{parentName:"p"},"Cargo.toml"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},'# GPU Icicle integration\nicicle-cuda-runtime = { git = "https://github.com/ingonyama-zk/icicle.git", tag = "v1.0.0" }\nicicle-core = { git = "https://github.com/ingonyama-zk/icicle.git", tag = "v1.0.0" }\nicicle-bn254 = { git = "https://github.com/ingonyama-zk/icicle.git", tag = "v1.0.0" }\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"icicle-bn254")," being the curve you wish to use and ",(0,r.kt)("inlineCode",{parentName:"p"},"icicle-core")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"icicle-cuda-runtime")," contain ICICLE utilities and CUDA wrappers."),(0,r.kt)("p",null,"If you wish to point to a specific ICICLE branch add ",(0,r.kt)("inlineCode",{parentName:"p"},'branch = ""')," or ",(0,r.kt)("inlineCode",{parentName:"p"},'tag = ""')," to the ICICLE dependency. For a specific commit add ",(0,r.kt)("inlineCode",{parentName:"p"},'rev = ""'),"."),(0,r.kt)("p",null,"When you build your project ICICLE will be built as part of the build command."),(0,r.kt)("h1",{id:"how-do-the-rust-bindings-work"},"How do the rust bindings work?"),(0,r.kt)("p",null,"The rust bindings are just rust wrappers for ICICLE Core static libraries which can be compiled. We integrate the compilation of the static libraries into rusts toolchain to make usage seamless and easy. This is achieved by ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/main/wrappers/rust/icicle-curves/icicle-bn254/build.rs"},"extending rusts build command"),"."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-rust"},'use cmake::Config;\nuse std::env::var;\n\nfn main() {\n println!("cargo:rerun-if-env-changed=CXXFLAGS");\n println!("cargo:rerun-if-changed=../../../../icicle");\n\n let cargo_dir = var("CARGO_MANIFEST_DIR").unwrap();\n let profile = var("PROFILE").unwrap();\n\n let out_dir = Config::new("../../../../icicle")\n .define("BUILD_TESTS", "OFF") //TODO: feature\n .define("CURVE", "bn254")\n .define("CMAKE_BUILD_TYPE", "Release")\n .build_target("icicle")\n .build();\n\n println!("cargo:rustc-link-search={}/build", out_dir.display());\n\n println!("cargo:rustc-link-lib=ingo_bn254");\n println!("cargo:rustc-link-lib=stdc++");\n // println!("cargo:rustc-link-search=native=/usr/local/cuda/lib64");\n println!("cargo:rustc-link-lib=cudart");\n}\n')))}d.isMDXComponent=!0},8209:(e,n,t)=>{t(7294)}}]); \ No newline at end of file diff --git a/assets/js/a09c2993.b358e04d.js b/assets/js/a09c2993.1d68ad2b.js similarity index 98% rename from assets/js/a09c2993.b358e04d.js rename to assets/js/a09c2993.1d68ad2b.js index 4f653c9..11920ca 100644 --- a/assets/js/a09c2993.b358e04d.js +++ b/assets/js/a09c2993.1d68ad2b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[128],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var o=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=o.createContext({}),s=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var r=e.components,a=e.mdxType,n=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),m=a,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||n;return r?o.createElement(f,i(i({ref:t},p),{},{components:r})):o.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var n=r.length,i=new Array(n);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>n,metadata:()=>c,toc:()=>s});var o=r(7462),a=(r(7294),r(3905));r(8209);const n={slug:"/",displayed_sidebar:"GettingStartedSidebar",title:""},i="Welcome to Ingonyama's Developer Documentation",c={unversionedId:"introduction",id:"introduction",title:"",description:"Ingonyama is a next-generation semiconductor company, focusing on Zero-Knowledge Proof hardware acceleration. We build accelerators for advanced cryptography, unlocking real-time applications. Our focus is on democratizing access to compute intensive cryptography and making it accessible for developers to build on top of.",source:"@site/docs/introduction.md",sourceDirName:".",slug:"/",permalink:"/",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/introduction.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{slug:"/",displayed_sidebar:"GettingStartedSidebar",title:""},sidebar:"GettingStartedSidebar",next:{title:"What is ICICLE?",permalink:"/icicle/overview"}},l={},s=[{value:"Our current take on hardware acceleration",id:"our-current-take-on-hardware-acceleration",level:2},{value:"ICICLE",id:"icicle",level:2},{value:"Get in Touch",id:"get-in-touch",level:2}],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,o.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"welcome-to-ingonyamas-developer-documentation"},"Welcome to Ingonyama's Developer Documentation"),(0,a.kt)("p",null,"Ingonyama is a next-generation semiconductor company, focusing on Zero-Knowledge Proof hardware acceleration. We build accelerators for advanced cryptography, unlocking real-time applications. Our focus is on democratizing access to compute intensive cryptography and making it accessible for developers to build on top of."),(0,a.kt)("p",null,"Currently our flagship products are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"ICICLE"),":\n",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," is a fully featured GPU accelerated cryptography library for building ZK provers. ICICLE allows you to accelerate your ZK existing protocols in a matter of hours or implement your protocol from scratch on GPU.")),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"our-current-take-on-hardware-acceleration"},"Our current take on hardware acceleration"),(0,a.kt)("p",null,"We believe GPUs are as important for ZK as for AI."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"GPUs are a perfect match for ZK compute - around 97% of ZK protocol runtime is parallel by nature."),(0,a.kt)("li",{parentName:"ul"},"GPUs are simple for developers to use and scale compared to other hardware platforms."),(0,a.kt)("li",{parentName:"ul"},"GPUs are extremely competitive in terms of power / performance and price (3x cheaper)."),(0,a.kt)("li",{parentName:"ul"},"GPUs are popular and readily available.")),(0,a.kt)("p",null,"For a more in-depth understanding on this topic we suggest you read ",(0,a.kt)("a",{parentName:"p",href:"https://www.ingonyama.com/blog/revisiting-paradigm-hardware-acceleration-for-zero-knowledge-proofs"},"our article on the subject"),"."),(0,a.kt)("p",null,"Despite our current focus on GPUs we are still hard at work developing a ZPU (ZK Processing Unit), with the goal of offering a programmable hardware platform for ZK. To read more about ZPUs we suggest you read this ",(0,a.kt)("a",{parentName:"p",href:"https://medium.com/@ingonyama/zpu-the-zero-knowledge-processing-unit-f886a48e00e0"},"article"),"."),(0,a.kt)("h2",{id:"icicle"},"ICICLE"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," is a cryptography library for ZK using GPUs.\nICICLE implements blazing fast cryptographic primitives such as EC operations, MSM, NTT, Poseidon hash and more on GPU."),(0,a.kt)("p",null,"ICICLE is designed to be easy to use, developers don't have to touch a single line of CUDA code. Our Rust and Golang bindings allow your team to transition from CPU to GPU with minimal changes."),(0,a.kt)("p",null,"Learn more about ICICLE and GPUs ",(0,a.kt)("a",{parentName:"p",href:"/icicle/overview"},"here"),"."),(0,a.kt)("h2",{id:"get-in-touch"},"Get in Touch"),(0,a.kt)("p",null,"If you have any questions, ideas, or are thinking of building something in this space join the discussion on ",(0,a.kt)("a",{parentName:"p",href:"https://discord.gg/6vYrE7waPj"},"Discord"),". You can explore our code on ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk"},"github")," or read some of ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/papers"},"our research papers"),"."),(0,a.kt)("p",null,"Follow us on ",(0,a.kt)("a",{parentName:"p",href:"https://x.com/Ingo_zk"},"Twitter")," and ",(0,a.kt)("a",{parentName:"p",href:"https://www.youtube.com/@ingo_ZK"},"YouTube")," and sign up for our ",(0,a.kt)("a",{parentName:"p",href:"https://wkf.ms/3LKCbdj"},"mailing list")," to get our latest announcements."))}d.isMDXComponent=!0},8209:(e,t,r)=>{r(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[128],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>f});var o=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,o)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=o.createContext({}),s=function(e){var t=o.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return o.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var r=e.components,a=e.mdxType,n=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),m=a,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||n;return r?o.createElement(f,i(i({ref:t},p),{},{components:r})):o.createElement(f,i({ref:t},p))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var n=r.length,i=new Array(n);i[0]=m;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:a,i[1]=c;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>n,metadata:()=>c,toc:()=>s});var o=r(7462),a=(r(7294),r(3905));r(8209);const n={slug:"/",displayed_sidebar:"GettingStartedSidebar",title:""},i="Welcome to Ingonyama's Developer Documentation",c={unversionedId:"introduction",id:"introduction",title:"",description:"Ingonyama is a next-generation semiconductor company, focusing on Zero-Knowledge Proof hardware acceleration. We build accelerators for advanced cryptography, unlocking real-time applications. Our focus is on democratizing access to compute intensive cryptography and making it accessible for developers to build on top of.",source:"@site/docs/introduction.md",sourceDirName:".",slug:"/",permalink:"/",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/introduction.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{slug:"/",displayed_sidebar:"GettingStartedSidebar",title:""},sidebar:"GettingStartedSidebar",next:{title:"What is ICICLE?",permalink:"/icicle/overview"}},l={},s=[{value:"Our current take on hardware acceleration",id:"our-current-take-on-hardware-acceleration",level:2},{value:"ICICLE",id:"icicle",level:2},{value:"Get in Touch",id:"get-in-touch",level:2}],p={toc:s},u="wrapper";function d(e){let{components:t,...r}=e;return(0,a.kt)(u,(0,o.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"welcome-to-ingonyamas-developer-documentation"},"Welcome to Ingonyama's Developer Documentation"),(0,a.kt)("p",null,"Ingonyama is a next-generation semiconductor company, focusing on Zero-Knowledge Proof hardware acceleration. We build accelerators for advanced cryptography, unlocking real-time applications. Our focus is on democratizing access to compute intensive cryptography and making it accessible for developers to build on top of."),(0,a.kt)("p",null,"Currently our flagship products are:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("strong",{parentName:"li"},"ICICLE"),":\n",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," is a fully featured GPU accelerated cryptography library for building ZK provers. ICICLE allows you to accelerate your ZK existing protocols in a matter of hours or implement your protocol from scratch on GPU.")),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"our-current-take-on-hardware-acceleration"},"Our current take on hardware acceleration"),(0,a.kt)("p",null,"We believe GPUs are as important for ZK as for AI."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"GPUs are a perfect match for ZK compute - around 97% of ZK protocol runtime is parallel by nature."),(0,a.kt)("li",{parentName:"ul"},"GPUs are simple for developers to use and scale compared to other hardware platforms."),(0,a.kt)("li",{parentName:"ul"},"GPUs are extremely competitive in terms of power / performance and price (3x cheaper)."),(0,a.kt)("li",{parentName:"ul"},"GPUs are popular and readily available.")),(0,a.kt)("p",null,"For a more in-depth understanding on this topic we suggest you read ",(0,a.kt)("a",{parentName:"p",href:"https://www.ingonyama.com/blog/revisiting-paradigm-hardware-acceleration-for-zero-knowledge-proofs"},"our article on the subject"),"."),(0,a.kt)("p",null,"Despite our current focus on GPUs we are still hard at work developing a ZPU (ZK Processing Unit), with the goal of offering a programmable hardware platform for ZK. To read more about ZPUs we suggest you read this ",(0,a.kt)("a",{parentName:"p",href:"https://medium.com/@ingonyama/zpu-the-zero-knowledge-processing-unit-f886a48e00e0"},"article"),"."),(0,a.kt)("h2",{id:"icicle"},"ICICLE"),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," is a cryptography library for ZK using GPUs.\nICICLE implements blazing fast cryptographic primitives such as EC operations, MSM, NTT, Poseidon hash and more on GPU."),(0,a.kt)("p",null,"ICICLE is designed to be easy to use, developers don't have to touch a single line of CUDA code. Our Rust and Golang bindings allow your team to transition from CPU to GPU with minimal changes."),(0,a.kt)("p",null,"Learn more about ICICLE and GPUs ",(0,a.kt)("a",{parentName:"p",href:"/icicle/overview"},"here"),"."),(0,a.kt)("h2",{id:"get-in-touch"},"Get in Touch"),(0,a.kt)("p",null,"If you have any questions, ideas, or are thinking of building something in this space join the discussion on ",(0,a.kt)("a",{parentName:"p",href:"https://discord.gg/6vYrE7waPj"},"Discord"),". You can explore our code on ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk"},"github")," or read some of ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/papers"},"our research papers"),"."),(0,a.kt)("p",null,"Follow us on ",(0,a.kt)("a",{parentName:"p",href:"https://x.com/Ingo_zk"},"Twitter")," and ",(0,a.kt)("a",{parentName:"p",href:"https://www.youtube.com/@ingo_ZK"},"YouTube")," and sign up for our ",(0,a.kt)("a",{parentName:"p",href:"https://wkf.ms/3LKCbdj"},"mailing list")," to get our latest announcements."))}d.isMDXComponent=!0},8209:(e,t,r)=>{r(7294)}}]); \ No newline at end of file diff --git a/assets/js/acd9d3d0.ed9bd5c9.js b/assets/js/acd9d3d0.782ff31b.js similarity index 99% rename from assets/js/acd9d3d0.ed9bd5c9.js rename to assets/js/acd9d3d0.782ff31b.js index 84a80b9..a5fc41d 100644 --- a/assets/js/acd9d3d0.ed9bd5c9.js +++ b/assets/js/acd9d3d0.782ff31b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[244],{3905:(e,a,t)=>{t.d(a,{Zo:()=>o,kt:()=>k});var n=t(7294);function s(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function m(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function r(e){for(var a=1;a=0||(s[t]=e[t]);return s}(e,a);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var l=n.createContext({}),p=function(e){var a=n.useContext(l),t=a;return e&&(t="function"==typeof e?e(a):r(r({},a),e)),t},o=function(e){var a=p(e.components);return n.createElement(l.Provider,{value:a},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},h=n.forwardRef((function(e,a){var t=e.components,s=e.mdxType,m=e.originalType,l=e.parentName,o=i(e,["components","mdxType","originalType","parentName"]),c=p(t),h=s,k=c["".concat(l,".").concat(h)]||c[h]||u[h]||m;return t?n.createElement(k,r(r({ref:a},o),{},{components:t})):n.createElement(k,r({ref:a},o))}));function k(e,a){var t=arguments,s=a&&a.mdxType;if("string"==typeof e||s){var m=t.length,r=new Array(m);r[0]=h;var i={};for(var l in a)hasOwnProperty.call(a,l)&&(i[l]=a[l]);i.originalType=e,i[c]="string"==typeof e?e:s,r[1]=i;for(var p=2;p{t.r(a),t.d(a,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>m,metadata:()=>i,toc:()=>p});var n=t(7462),s=(t(7294),t(3905));t(8209);const m={},r="MSM - Multi scalar multiplication",i={unversionedId:"icicle/primitives/msm",id:"icicle/primitives/msm",title:"MSM - Multi scalar multiplication",description:"MSM stands for Multi scalar multiplication, its defined as:",source:"@site/docs/icicle/primitives/msm.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/msm",permalink:"/icicle/primitives/msm",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/msm.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"ICICLE Primitives",permalink:"/icicle/primitives/overview"},next:{title:"Poseidon",permalink:"/icicle/primitives/poseidon"}},l={},p=[{value:"Supported curves",id:"supported-curves",level:2},{value:"Supported algorithms",id:"supported-algorithms",level:2},{value:"Bucket accumulation",id:"bucket-accumulation",level:3},{value:"When should I use Bucket accumulation?",id:"when-should-i-use-bucket-accumulation",level:4},{value:"Large triangle accumulation",id:"large-triangle-accumulation",level:3},{value:"When should I use Large triangle accumulation?",id:"when-should-i-use-large-triangle-accumulation",level:4},{value:"How do I toggle between the supported algorithms?",id:"how-do-i-toggle-between-the-supported-algorithms",level:3},{value:"MSM Modes",id:"msm-modes",level:2},{value:"Which mode should I use?",id:"which-mode-should-i-use",level:3},{value:"How do I toggle between MSM modes?",id:"how-do-i-toggle-between-msm-modes",level:3},{value:"Support for G2 group",id:"support-for-g2-group",level:2}],o={toc:p},c="wrapper";function u(e){let{components:a,...t}=e;return(0,s.kt)(c,(0,n.Z)({},o,t,{components:a,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"msm---multi-scalar-multiplication"},"MSM - Multi scalar multiplication"),(0,s.kt)("p",null,"MSM stands for Multi scalar multiplication, its defined as:"),(0,s.kt)("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("mi",null,"M"),(0,s.kt)("mi",null,"S"),(0,s.kt)("mi",null,"M"),(0,s.kt)("mo",{stretchy:"false"},"("),(0,s.kt)("mi",null,"a"),(0,s.kt)("mo",null,","),(0,s.kt)("mi",null,"G"),(0,s.kt)("mo",{stretchy:"false"},")"),(0,s.kt)("mo",null,"="),(0,s.kt)("munderover",null,(0,s.kt)("mo",{"data-mjx-texclass":"OP",movablelimits:"false"},"\u2211"),(0,s.kt)("mrow",{"data-mjx-texclass":"ORD"},(0,s.kt)("mi",null,"j"),(0,s.kt)("mo",null,"="),(0,s.kt)("mn",null,"0")),(0,s.kt)("mrow",{"data-mjx-texclass":"ORD"},(0,s.kt)("mi",null,"n"),(0,s.kt)("mo",null,"\u2212"),(0,s.kt)("mn",null,"1"))),(0,s.kt)("msub",null,(0,s.kt)("mi",null,"a"),(0,s.kt)("mi",null,"j")),(0,s.kt)("msub",null,(0,s.kt)("mi",null,"G"),(0,s.kt)("mi",null,"j"))),(0,s.kt)("p",null,"Where"),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"msub"},"G"),(0,s.kt)("mi",{parentName:"msub"},"j")),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow"},"G")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"G_j \\in G")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3117em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G")))))," - points from an Elliptic Curve group."),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"msub"},"a"),(0,s.kt)("mn",{parentName:"msub"},"0")),(0,s.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,s.kt)("mo",{parentName:"mrow"},"\u2026"),(0,s.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"msub"},"a"),(0,s.kt)("mi",{parentName:"msub"},"n"))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, \\ldots, a_n")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mpunct"},","),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},"\u2026"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mpunct"},","),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.1514em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"n")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,s.kt)("span",{parentName:"span"}))))))))))," - Scalars"),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"M"),(0,s.kt)("mi",{parentName:"mrow"},"S"),(0,s.kt)("mi",{parentName:"mrow"},"M"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"a"),(0,s.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,s.kt)("mi",{parentName:"mrow"},"G"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow"},"G")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"MSM(a, G) \\in G")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"MSM"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,s.kt)("span",{parentName:"span",className:"mpunct"},","),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G")))))," - a single EC (elliptic curve point) point"),(0,s.kt)("p",null,"In words, MSM is the sum of scalar and EC point multiplications. We can see from this definition that the core operations occurring are Modular Multiplication and Elliptic curve point addition. Each multiplication can be computed independently and then the products are summed, making MSM inherently parallelizable."),(0,s.kt)("p",null,"Accelerating MSM is crucial to a ZK protocol's performance due to the ",(0,s.kt)("a",{parentName:"p",href:"https://hackmd.io/@0xMonia/SkQ6-oRz3#Hardware-acceleration-in-action"},"large percent of run time")," they take when generating proofs."),(0,s.kt)("p",null,"You can learn more about how MSMs work from this ",(0,s.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=Bl5mQA7UL2I"},"video")," and from our resource list on ",(0,s.kt)("a",{parentName:"p",href:"https://www.ingonyama.com/ingopedia/msm"},"Ingopedia"),"."),(0,s.kt)("h1",{id:"using-msm"},"Using MSM"),(0,s.kt)("h2",{id:"supported-curves"},"Supported curves"),(0,s.kt)("p",null,"MSM supports the following curves:"),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"bls12-377"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"bls12-381"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"bn-254"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"bw6-761")),(0,s.kt)("h2",{id:"supported-algorithms"},"Supported algorithms"),(0,s.kt)("p",null,"Our MSM implementation supports two algorithms ",(0,s.kt)("inlineCode",{parentName:"p"},"Bucket accumulation")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"Large triangle accumulation"),"."),(0,s.kt)("h3",{id:"bucket-accumulation"},"Bucket accumulation"),(0,s.kt)("p",null,'The Bucket Accumulation algorithm is a method of dividing the overall MSM task into smaller, more manageable sub-tasks. It involves partitioning scalars and their corresponding points into different "buckets" based on the scalar values.'),(0,s.kt)("p",null,"Bucket Accumulation can be more parallel-friendly because it involves dividing the computation into smaller, independent tasks, distributing scalar-point pairs into buckets and summing points within each bucket. This division makes it well suited for parallel processing on GPUs."),(0,s.kt)("h4",{id:"when-should-i-use-bucket-accumulation"},"When should I use Bucket accumulation?"),(0,s.kt)("p",null,"In scenarios involving large MSM computations with many scalar-point pairs, the ability to parallelize operations makes Bucket Accumulation more efficient. The larger the MSM task, the more significant the potential gains from parallelization."),(0,s.kt)("h3",{id:"large-triangle-accumulation"},"Large triangle accumulation"),(0,s.kt)("p",null,"Large Triangle Accumulation is a method for optimizing MSM which focuses on reducing the number of point doublings in the computation. This algorithm is based on the observation that the number of point doublings can be minimized by structuring the computation in a specific manner."),(0,s.kt)("h4",{id:"when-should-i-use-large-triangle-accumulation"},"When should I use Large triangle accumulation?"),(0,s.kt)("p",null,"The Large Triangle Accumulation algorithm is more sequential in nature, as it builds upon each step sequentially (accumulating sums and then performing doubling). This structure can make it less suitable for parallelization but potentially more efficient for a ",(0,s.kt)("b",null,"large batch of smaller MSM computations"),"."),(0,s.kt)("h3",{id:"how-do-i-toggle-between-the-supported-algorithms"},"How do I toggle between the supported algorithms?"),(0,s.kt)("p",null,"When creating your MSM Config you may state which algorithm you wish to use. ",(0,s.kt)("inlineCode",{parentName:"p"},"is_big_triangle=true")," will activate Large triangle accumulation and ",(0,s.kt)("inlineCode",{parentName:"p"},"is_big_triangle=false")," will activate Bucket accumulation."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"...\n\nlet mut cfg_bls12377 = msm::get_default_msm_config::();\n\n// is_big_triangle will determine which algorithm to use \ncfg_bls12377.is_big_triangle = true;\n\nmsm::msm(&scalars, &points, &cfg, &mut msm_results).unwrap();\n...\n")),(0,s.kt)("p",null,"You may reference the rust code ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/77a7613aa21961030e4e12bf1c9a78a2dadb2518/wrappers/rust/icicle-core/src/msm/mod.rs#L54"},"here"),"."),(0,s.kt)("h2",{id:"msm-modes"},"MSM Modes"),(0,s.kt)("p",null,"ICICLE MSM also supports two different modes ",(0,s.kt)("inlineCode",{parentName:"p"},"Batch MSM")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"Single MSM")),(0,s.kt)("p",null,"Batch MSM allows you to run many MSMs with a single API call, Single MSM will launch a single MSM computation."),(0,s.kt)("h3",{id:"which-mode-should-i-use"},"Which mode should I use?"),(0,s.kt)("p",null,"This decision is highly dependent on your use case and design. However, if your design allows for it, using batch mode can significantly improve efficiency. Batch processing allows you to perform multiple MSMs leveraging the parallel processing capabilities of GPUs."),(0,s.kt)("p",null,"Single MSM mode should be used when batching isn't possible or when you have to run a single MSM."),(0,s.kt)("h3",{id:"how-do-i-toggle-between-msm-modes"},"How do I toggle between MSM modes?"),(0,s.kt)("p",null,"Toggling between MSM modes occurs automatically based on the number of results you are expecting from the ",(0,s.kt)("inlineCode",{parentName:"p"},"msm::msm")," function. If you are expecting an array of ",(0,s.kt)("inlineCode",{parentName:"p"},"msm_results"),", ICICLE will automatically split ",(0,s.kt)("inlineCode",{parentName:"p"},"scalars")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"points")," into equal parts and run them as multiple MSMs in parallel."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"...\n\nlet mut msm_result: HostOrDeviceSlice<'_, G1Projective> = HostOrDeviceSlice::cuda_malloc(1).unwrap();\nmsm::msm(&scalars, &points, &cfg, &mut msm_result).unwrap();\n\n...\n")),(0,s.kt)("p",null,"In the example above we allocate a single expected result which the MSM method will interpret as ",(0,s.kt)("inlineCode",{parentName:"p"},"batch_size=1")," and run a single MSM."),(0,s.kt)("p",null,"In the next example, we are expecting 10 results which sets ",(0,s.kt)("inlineCode",{parentName:"p"},"batch_size=10")," and runs 10 MSMs in batch mode."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"...\n\nlet mut msm_results: HostOrDeviceSlice<'_, G1Projective> = HostOrDeviceSlice::cuda_malloc(10).unwrap();\nmsm::msm(&scalars, &points, &cfg, &mut msm_results).unwrap();\n\n...\n")),(0,s.kt)("p",null,"Here is a ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/77a7613aa21961030e4e12bf1c9a78a2dadb2518/wrappers/rust/icicle-core/src/msm/mod.rs#L108"},"reference")," to the code which automatically sets the batch size. For more MSM examples have a look ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/77a7613aa21961030e4e12bf1c9a78a2dadb2518/examples/rust/msm/src/main.rs#L1"},"here"),"."),(0,s.kt)("h2",{id:"support-for-g2-group"},"Support for G2 group"),(0,s.kt)("p",null,"MSM also supports G2 group. "),(0,s.kt)("p",null,"Using MSM in G2 requires a G2 config, and of course your Points should also be G2 Points."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"... \n\nlet scalars = HostOrDeviceSlice::Host(upper_scalars[..size].to_vec());\nlet g2_points = HostOrDeviceSlice::Host(g2_upper_points[..size].to_vec());\nlet mut g2_msm_results: HostOrDeviceSlice<'_, G2Projective> = HostOrDeviceSlice::cuda_malloc(1).unwrap();\nlet mut g2_cfg = msm::get_default_msm_config::();\n\nmsm::msm(&scalars, &g2_points, &g2_cfg, &mut g2_msm_results).unwrap();\n\n...\n")),(0,s.kt)("p",null,"Here you can ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/5a96f9937d0a7176d88c766bd3ef2062b0c26c37/examples/rust/msm/src/main.rs#L114"},"find an example")," of MSM on G2 Points."))}u.isMDXComponent=!0},8209:(e,a,t)=>{t(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[244],{3905:(e,a,t)=>{t.d(a,{Zo:()=>o,kt:()=>k});var n=t(7294);function s(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function m(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function r(e){for(var a=1;a=0||(s[t]=e[t]);return s}(e,a);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var l=n.createContext({}),p=function(e){var a=n.useContext(l),t=a;return e&&(t="function"==typeof e?e(a):r(r({},a),e)),t},o=function(e){var a=p(e.components);return n.createElement(l.Provider,{value:a},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},h=n.forwardRef((function(e,a){var t=e.components,s=e.mdxType,m=e.originalType,l=e.parentName,o=i(e,["components","mdxType","originalType","parentName"]),c=p(t),h=s,k=c["".concat(l,".").concat(h)]||c[h]||u[h]||m;return t?n.createElement(k,r(r({ref:a},o),{},{components:t})):n.createElement(k,r({ref:a},o))}));function k(e,a){var t=arguments,s=a&&a.mdxType;if("string"==typeof e||s){var m=t.length,r=new Array(m);r[0]=h;var i={};for(var l in a)hasOwnProperty.call(a,l)&&(i[l]=a[l]);i.originalType=e,i[c]="string"==typeof e?e:s,r[1]=i;for(var p=2;p{t.r(a),t.d(a,{assets:()=>l,contentTitle:()=>r,default:()=>u,frontMatter:()=>m,metadata:()=>i,toc:()=>p});var n=t(7462),s=(t(7294),t(3905));t(8209);const m={},r="MSM - Multi scalar multiplication",i={unversionedId:"icicle/primitives/msm",id:"icicle/primitives/msm",title:"MSM - Multi scalar multiplication",description:"MSM stands for Multi scalar multiplication, its defined as:",source:"@site/docs/icicle/primitives/msm.md",sourceDirName:"icicle/primitives",slug:"/icicle/primitives/msm",permalink:"/icicle/primitives/msm",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/primitives/msm.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"ICICLE Primitives",permalink:"/icicle/primitives/overview"},next:{title:"Poseidon",permalink:"/icicle/primitives/poseidon"}},l={},p=[{value:"Supported curves",id:"supported-curves",level:2},{value:"Supported algorithms",id:"supported-algorithms",level:2},{value:"Bucket accumulation",id:"bucket-accumulation",level:3},{value:"When should I use Bucket accumulation?",id:"when-should-i-use-bucket-accumulation",level:4},{value:"Large triangle accumulation",id:"large-triangle-accumulation",level:3},{value:"When should I use Large triangle accumulation?",id:"when-should-i-use-large-triangle-accumulation",level:4},{value:"How do I toggle between the supported algorithms?",id:"how-do-i-toggle-between-the-supported-algorithms",level:3},{value:"MSM Modes",id:"msm-modes",level:2},{value:"Which mode should I use?",id:"which-mode-should-i-use",level:3},{value:"How do I toggle between MSM modes?",id:"how-do-i-toggle-between-msm-modes",level:3},{value:"Support for G2 group",id:"support-for-g2-group",level:2}],o={toc:p},c="wrapper";function u(e){let{components:a,...t}=e;return(0,s.kt)(c,(0,n.Z)({},o,t,{components:a,mdxType:"MDXLayout"}),(0,s.kt)("h1",{id:"msm---multi-scalar-multiplication"},"MSM - Multi scalar multiplication"),(0,s.kt)("p",null,"MSM stands for Multi scalar multiplication, its defined as:"),(0,s.kt)("math",{xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("mi",null,"M"),(0,s.kt)("mi",null,"S"),(0,s.kt)("mi",null,"M"),(0,s.kt)("mo",{stretchy:"false"},"("),(0,s.kt)("mi",null,"a"),(0,s.kt)("mo",null,","),(0,s.kt)("mi",null,"G"),(0,s.kt)("mo",{stretchy:"false"},")"),(0,s.kt)("mo",null,"="),(0,s.kt)("munderover",null,(0,s.kt)("mo",{"data-mjx-texclass":"OP",movablelimits:"false"},"\u2211"),(0,s.kt)("mrow",{"data-mjx-texclass":"ORD"},(0,s.kt)("mi",null,"j"),(0,s.kt)("mo",null,"="),(0,s.kt)("mn",null,"0")),(0,s.kt)("mrow",{"data-mjx-texclass":"ORD"},(0,s.kt)("mi",null,"n"),(0,s.kt)("mo",null,"\u2212"),(0,s.kt)("mn",null,"1"))),(0,s.kt)("msub",null,(0,s.kt)("mi",null,"a"),(0,s.kt)("mi",null,"j")),(0,s.kt)("msub",null,(0,s.kt)("mi",null,"G"),(0,s.kt)("mi",null,"j"))),(0,s.kt)("p",null,"Where"),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"msub"},"G"),(0,s.kt)("mi",{parentName:"msub"},"j")),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow"},"G")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"G_j \\in G")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.9694em",verticalAlign:"-0.2861em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3117em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight",style:{marginRight:"0.05724em"}},"j")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.2861em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G")))))," - points from an Elliptic Curve group."),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"msub"},"a"),(0,s.kt)("mn",{parentName:"msub"},"0")),(0,s.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,s.kt)("mo",{parentName:"mrow"},"\u2026"),(0,s.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,s.kt)("msub",{parentName:"mrow"},(0,s.kt)("mi",{parentName:"msub"},"a"),(0,s.kt)("mi",{parentName:"msub"},"n"))),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"a_0, \\ldots, a_n")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.625em",verticalAlign:"-0.1944em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.3011em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mtight"},"0")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,s.kt)("span",{parentName:"span"})))))),(0,s.kt)("span",{parentName:"span",className:"mpunct"},","),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"minner"},"\u2026"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mpunct"},","),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,s.kt)("span",{parentName:"span",className:"msupsub"},(0,s.kt)("span",{parentName:"span",className:"vlist-t vlist-t2"},(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.1514em"}},(0,s.kt)("span",{parentName:"span",style:{top:"-2.55em",marginLeft:"0em",marginRight:"0.05em"}},(0,s.kt)("span",{parentName:"span",className:"pstrut",style:{height:"2.7em"}}),(0,s.kt)("span",{parentName:"span",className:"sizing reset-size6 size3 mtight"},(0,s.kt)("span",{parentName:"span",className:"mord mathnormal mtight"},"n")))),(0,s.kt)("span",{parentName:"span",className:"vlist-s"},"\u200b")),(0,s.kt)("span",{parentName:"span",className:"vlist-r"},(0,s.kt)("span",{parentName:"span",className:"vlist",style:{height:"0.15em"}},(0,s.kt)("span",{parentName:"span"}))))))))))," - Scalars"),(0,s.kt)("p",null,(0,s.kt)("span",{parentName:"p",className:"math math-inline"},(0,s.kt)("span",{parentName:"span",className:"katex"},(0,s.kt)("span",{parentName:"span",className:"katex-mathml"},(0,s.kt)("math",{parentName:"span",xmlns:"http://www.w3.org/1998/Math/MathML"},(0,s.kt)("semantics",{parentName:"math"},(0,s.kt)("mrow",{parentName:"semantics"},(0,s.kt)("mi",{parentName:"mrow"},"M"),(0,s.kt)("mi",{parentName:"mrow"},"S"),(0,s.kt)("mi",{parentName:"mrow"},"M"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},"("),(0,s.kt)("mi",{parentName:"mrow"},"a"),(0,s.kt)("mo",{parentName:"mrow",separator:"true"},","),(0,s.kt)("mi",{parentName:"mrow"},"G"),(0,s.kt)("mo",{parentName:"mrow",stretchy:"false"},")"),(0,s.kt)("mo",{parentName:"mrow"},"\u2208"),(0,s.kt)("mi",{parentName:"mrow"},"G")),(0,s.kt)("annotation",{parentName:"semantics",encoding:"application/x-tex"},"MSM(a, G) \\in G")))),(0,s.kt)("span",{parentName:"span",className:"katex-html","aria-hidden":"true"},(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"1em",verticalAlign:"-0.25em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal",style:{marginRight:"0.10903em"}},"MSM"),(0,s.kt)("span",{parentName:"span",className:"mopen"},"("),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"a"),(0,s.kt)("span",{parentName:"span",className:"mpunct"},","),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.1667em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G"),(0,s.kt)("span",{parentName:"span",className:"mclose"},")"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}}),(0,s.kt)("span",{parentName:"span",className:"mrel"},"\u2208"),(0,s.kt)("span",{parentName:"span",className:"mspace",style:{marginRight:"0.2778em"}})),(0,s.kt)("span",{parentName:"span",className:"base"},(0,s.kt)("span",{parentName:"span",className:"strut",style:{height:"0.6833em"}}),(0,s.kt)("span",{parentName:"span",className:"mord mathnormal"},"G")))))," - a single EC (elliptic curve point) point"),(0,s.kt)("p",null,"In words, MSM is the sum of scalar and EC point multiplications. We can see from this definition that the core operations occurring are Modular Multiplication and Elliptic curve point addition. Each multiplication can be computed independently and then the products are summed, making MSM inherently parallelizable."),(0,s.kt)("p",null,"Accelerating MSM is crucial to a ZK protocol's performance due to the ",(0,s.kt)("a",{parentName:"p",href:"https://hackmd.io/@0xMonia/SkQ6-oRz3#Hardware-acceleration-in-action"},"large percent of run time")," they take when generating proofs."),(0,s.kt)("p",null,"You can learn more about how MSMs work from this ",(0,s.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=Bl5mQA7UL2I"},"video")," and from our resource list on ",(0,s.kt)("a",{parentName:"p",href:"https://www.ingonyama.com/ingopedia/msm"},"Ingopedia"),"."),(0,s.kt)("h1",{id:"using-msm"},"Using MSM"),(0,s.kt)("h2",{id:"supported-curves"},"Supported curves"),(0,s.kt)("p",null,"MSM supports the following curves:"),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"bls12-377"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"bls12-381"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"bn-254"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"bw6-761")),(0,s.kt)("h2",{id:"supported-algorithms"},"Supported algorithms"),(0,s.kt)("p",null,"Our MSM implementation supports two algorithms ",(0,s.kt)("inlineCode",{parentName:"p"},"Bucket accumulation")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"Large triangle accumulation"),"."),(0,s.kt)("h3",{id:"bucket-accumulation"},"Bucket accumulation"),(0,s.kt)("p",null,'The Bucket Accumulation algorithm is a method of dividing the overall MSM task into smaller, more manageable sub-tasks. It involves partitioning scalars and their corresponding points into different "buckets" based on the scalar values.'),(0,s.kt)("p",null,"Bucket Accumulation can be more parallel-friendly because it involves dividing the computation into smaller, independent tasks, distributing scalar-point pairs into buckets and summing points within each bucket. This division makes it well suited for parallel processing on GPUs."),(0,s.kt)("h4",{id:"when-should-i-use-bucket-accumulation"},"When should I use Bucket accumulation?"),(0,s.kt)("p",null,"In scenarios involving large MSM computations with many scalar-point pairs, the ability to parallelize operations makes Bucket Accumulation more efficient. The larger the MSM task, the more significant the potential gains from parallelization."),(0,s.kt)("h3",{id:"large-triangle-accumulation"},"Large triangle accumulation"),(0,s.kt)("p",null,"Large Triangle Accumulation is a method for optimizing MSM which focuses on reducing the number of point doublings in the computation. This algorithm is based on the observation that the number of point doublings can be minimized by structuring the computation in a specific manner."),(0,s.kt)("h4",{id:"when-should-i-use-large-triangle-accumulation"},"When should I use Large triangle accumulation?"),(0,s.kt)("p",null,"The Large Triangle Accumulation algorithm is more sequential in nature, as it builds upon each step sequentially (accumulating sums and then performing doubling). This structure can make it less suitable for parallelization but potentially more efficient for a ",(0,s.kt)("b",null,"large batch of smaller MSM computations"),"."),(0,s.kt)("h3",{id:"how-do-i-toggle-between-the-supported-algorithms"},"How do I toggle between the supported algorithms?"),(0,s.kt)("p",null,"When creating your MSM Config you may state which algorithm you wish to use. ",(0,s.kt)("inlineCode",{parentName:"p"},"is_big_triangle=true")," will activate Large triangle accumulation and ",(0,s.kt)("inlineCode",{parentName:"p"},"is_big_triangle=false")," will activate Bucket accumulation."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"...\n\nlet mut cfg_bls12377 = msm::get_default_msm_config::();\n\n// is_big_triangle will determine which algorithm to use \ncfg_bls12377.is_big_triangle = true;\n\nmsm::msm(&scalars, &points, &cfg, &mut msm_results).unwrap();\n...\n")),(0,s.kt)("p",null,"You may reference the rust code ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/77a7613aa21961030e4e12bf1c9a78a2dadb2518/wrappers/rust/icicle-core/src/msm/mod.rs#L54"},"here"),"."),(0,s.kt)("h2",{id:"msm-modes"},"MSM Modes"),(0,s.kt)("p",null,"ICICLE MSM also supports two different modes ",(0,s.kt)("inlineCode",{parentName:"p"},"Batch MSM")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"Single MSM")),(0,s.kt)("p",null,"Batch MSM allows you to run many MSMs with a single API call, Single MSM will launch a single MSM computation."),(0,s.kt)("h3",{id:"which-mode-should-i-use"},"Which mode should I use?"),(0,s.kt)("p",null,"This decision is highly dependent on your use case and design. However, if your design allows for it, using batch mode can significantly improve efficiency. Batch processing allows you to perform multiple MSMs leveraging the parallel processing capabilities of GPUs."),(0,s.kt)("p",null,"Single MSM mode should be used when batching isn't possible or when you have to run a single MSM."),(0,s.kt)("h3",{id:"how-do-i-toggle-between-msm-modes"},"How do I toggle between MSM modes?"),(0,s.kt)("p",null,"Toggling between MSM modes occurs automatically based on the number of results you are expecting from the ",(0,s.kt)("inlineCode",{parentName:"p"},"msm::msm")," function. If you are expecting an array of ",(0,s.kt)("inlineCode",{parentName:"p"},"msm_results"),", ICICLE will automatically split ",(0,s.kt)("inlineCode",{parentName:"p"},"scalars")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"points")," into equal parts and run them as multiple MSMs in parallel."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"...\n\nlet mut msm_result: HostOrDeviceSlice<'_, G1Projective> = HostOrDeviceSlice::cuda_malloc(1).unwrap();\nmsm::msm(&scalars, &points, &cfg, &mut msm_result).unwrap();\n\n...\n")),(0,s.kt)("p",null,"In the example above we allocate a single expected result which the MSM method will interpret as ",(0,s.kt)("inlineCode",{parentName:"p"},"batch_size=1")," and run a single MSM."),(0,s.kt)("p",null,"In the next example, we are expecting 10 results which sets ",(0,s.kt)("inlineCode",{parentName:"p"},"batch_size=10")," and runs 10 MSMs in batch mode."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"...\n\nlet mut msm_results: HostOrDeviceSlice<'_, G1Projective> = HostOrDeviceSlice::cuda_malloc(10).unwrap();\nmsm::msm(&scalars, &points, &cfg, &mut msm_results).unwrap();\n\n...\n")),(0,s.kt)("p",null,"Here is a ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/77a7613aa21961030e4e12bf1c9a78a2dadb2518/wrappers/rust/icicle-core/src/msm/mod.rs#L108"},"reference")," to the code which automatically sets the batch size. For more MSM examples have a look ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/77a7613aa21961030e4e12bf1c9a78a2dadb2518/examples/rust/msm/src/main.rs#L1"},"here"),"."),(0,s.kt)("h2",{id:"support-for-g2-group"},"Support for G2 group"),(0,s.kt)("p",null,"MSM also supports G2 group. "),(0,s.kt)("p",null,"Using MSM in G2 requires a G2 config, and of course your Points should also be G2 Points."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-rust"},"... \n\nlet scalars = HostOrDeviceSlice::Host(upper_scalars[..size].to_vec());\nlet g2_points = HostOrDeviceSlice::Host(g2_upper_points[..size].to_vec());\nlet mut g2_msm_results: HostOrDeviceSlice<'_, G2Projective> = HostOrDeviceSlice::cuda_malloc(1).unwrap();\nlet mut g2_cfg = msm::get_default_msm_config::();\n\nmsm::msm(&scalars, &g2_points, &g2_cfg, &mut g2_msm_results).unwrap();\n\n...\n")),(0,s.kt)("p",null,"Here you can ",(0,s.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/blob/5a96f9937d0a7176d88c766bd3ef2062b0c26c37/examples/rust/msm/src/main.rs#L114"},"find an example")," of MSM on G2 Points."))}u.isMDXComponent=!0},8209:(e,a,t)=>{t(7294)}}]); \ No newline at end of file diff --git a/assets/js/ec013bfd.0bc0bf0d.js b/assets/js/ec013bfd.cb089409.js similarity index 98% rename from assets/js/ec013bfd.0bc0bf0d.js rename to assets/js/ec013bfd.cb089409.js index 65d8347..42a630d 100644 --- a/assets/js/ec013bfd.0bc0bf0d.js +++ b/assets/js/ec013bfd.cb089409.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[541],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),c=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(a),h=n,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||o;return a?r.createElement(m,i(i({ref:t},p),{},{components:a})):r.createElement(m,i({ref:t},p))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:n,i[1]=l;for(var c=2;c{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=a(7462),n=(a(7294),a(3905));a(8209);const o={},i="What is ICICLE?",l={unversionedId:"icicle/overview",id:"icicle/overview",title:"What is ICICLE?",description:"Static Badge",source:"@site/docs/icicle/overview.md",sourceDirName:"icicle",slug:"/icicle/overview",permalink:"/icicle/overview",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/overview.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"",permalink:"/"},next:{title:"Getting started with ICICLE",permalink:"/icicle/introduction"}},s={},c=[{value:"Dont have access to a GPU?",id:"dont-have-access-to-a-gpu",level:2},{value:"Grants",id:"grants",level:3},{value:"Google Colab",id:"google-colab",level:3},{value:"Vast.ai",id:"vastai",level:3},{value:"What can you do with ICICLE?",id:"what-can-you-do-with-icicle",level:2},{value:"Circuit developers",id:"circuit-developers",level:3},{value:"Integrating into existing ZK provers",id:"integrating-into-existing-zk-provers",level:3},{value:"Developing your own ZK provers",id:"developing-your-own-zk-provers",level:3},{value:"Developing proof of concepts",id:"developing-proof-of-concepts",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...a}=e;return(0,n.kt)(u,(0,r.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"what-is-icicle"},"What is ICICLE?"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases"},(0,n.kt)("img",{parentName:"a",src:"https://img.shields.io/badge/Latest-v1.4.0-8a2be2",alt:"Static Badge"}))),(0,n.kt)("p",null,(0,n.kt)("img",{parentName:"p",src:"https://img.shields.io/badge/Machines%20running%20ICICLE-544-lightblue",alt:"Static Badge"})),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," is a cryptography library for ZK using GPUs. ICICLE implements blazing fast cryptographic primitives such as EC operations, MSM, NTT, Poseidon hash and more on GPU."),(0,n.kt)("p",null,"ICICLE allows developers with minimal GPU experience to effortlessly accelerate their ZK application; from our experiments, even the most naive implementation may yield 10X improvement in proving times."),(0,n.kt)("p",null,"ICICLE has been used by many leading ZK companies such as ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/celer-network"},"Celer Network"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark")," and others to accelerate their ZK proving pipeline."),(0,n.kt)("h2",{id:"dont-have-access-to-a-gpu"},"Dont have access to a GPU?"),(0,n.kt)("p",null,"We understand that not all developers have access to a GPU and we don't want this to limit anyone from developing with ICICLE.\nHere are some ways we can help you gain access to GPUs:"),(0,n.kt)("h3",{id:"grants"},"Grants"),(0,n.kt)("p",null,"At Ingonyama we are interested in accelerating the progress of ZK and cryptography. If you are an engineer, developer or an academic researcher we invite you to checkout ",(0,n.kt)("a",{parentName:"p",href:"https://www.ingonyama.com/blog/icicle-for-researchers-grants-challenges"},"our grant program"),". We will give you access to GPUs and even pay you to do your dream research!"),(0,n.kt)("h3",{id:"google-colab"},"Google Colab"),(0,n.kt)("p",null,"This is a great way to get started with ICICLE instantly. Google Colab offers free GPU access to a NVIDIA T4 instance, it's acquired with 16 GB of memory which should be enough for experimenting and even prototyping with ICICLE."),(0,n.kt)("p",null,"For an extensive guide on how to setup Google Colab with ICICLE refer to ",(0,n.kt)("a",{parentName:"p",href:"/icicle/colab-instructions"},"this article"),"."),(0,n.kt)("p",null,"If none of these options are appropriate for you reach out to us on ",(0,n.kt)("a",{parentName:"p",href:"https://t.me/RealElan"},"telegram")," we will do our best to help you."),(0,n.kt)("h3",{id:"vastai"},"Vast.ai"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://vast.ai/"},"Vast.ai")," is a global GPU marketplace where you can rent many different types of GPUs by the hour for ",(0,n.kt)("a",{parentName:"p",href:"https://vast.ai/pricing"},"competitive pricing"),". They provide on-demand and interruptible rentals depending on your need or use case; you can learn more about their rental types ",(0,n.kt)("a",{parentName:"p",href:"https://vast.ai/faq#rental-types"},"here"),"."),(0,n.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,n.kt)("div",{parentName:"div",className:"admonition-heading"},(0,n.kt)("h5",{parentName:"div"},(0,n.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,n.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,n.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,n.kt)("div",{parentName:"div",className:"admonition-content"},(0,n.kt)("p",{parentName:"div"},"If none of these options suit your needs, contact us on ",(0,n.kt)("a",{parentName:"p",href:"https://t.me/RealElan"},"telegram")," for assistance. We're committed to ensuring that a lack of a GPU doesn't become a bottleneck for you. If you need help with setup or any other issues, we're here to do our best to help you."))),(0,n.kt)("h2",{id:"what-can-you-do-with-icicle"},"What can you do with ICICLE?"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," can be used in the same way you would use any other cryptography library. While developing and integrating ICICLE into many proof systems, we found some use case categories:"),(0,n.kt)("h3",{id:"circuit-developers"},"Circuit developers"),(0,n.kt)("p",null,"If you are a circuit developer and are experiencing bottlenecks while running your circuits, an ICICLE integrated prover may be the solution."),(0,n.kt)("p",null,"ICICLE has been integrated into a number of popular ZK provers including ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark prover")," and ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/zkonduit/halo2"},"Halo2"),". This means that you can enjoy GPU acceleration for your existing circuits immediately without writing a single line of code by simply switching on the GPU prover flag!"),(0,n.kt)("h3",{id:"integrating-into-existing-zk-provers"},"Integrating into existing ZK provers"),(0,n.kt)("p",null,"From our collaborations we have learned that its possible to accelerate a specific part of your prover to solve for a specific bottleneck."),(0,n.kt)("p",null,"ICICLE can be used to accelerate specific parts of your prover without completely rewriting your ZK prover."),(0,n.kt)("h3",{id:"developing-your-own-zk-provers"},"Developing your own ZK provers"),(0,n.kt)("p",null,"If your goal is to build a ZK prover from the ground up, ICICLE is an ideal tool for creating a highly optimized and scalable ZK prover. A key benefit of using GPUs with ICICLE is the ability to scale your ZK prover efficiently across multiple machines within a data center."),(0,n.kt)("h3",{id:"developing-proof-of-concepts"},"Developing proof of concepts"),(0,n.kt)("p",null,"ICICLE is also ideal for developing small prototypes. ICICLE has Golang and Rust bindings so you can easily develop a library implementing a specific primitive using ICICLE. An example would be develop a KZG commitment library using ICICLE."))}d.isMDXComponent=!0},8209:(e,t,a)=>{a(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[541],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),c=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=c(a),h=n,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||o;return a?r.createElement(m,i(i({ref:t},p),{},{components:a})):r.createElement(m,i({ref:t},p))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:n,i[1]=l;for(var c=2;c{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=a(7462),n=(a(7294),a(3905));a(8209);const o={},i="What is ICICLE?",l={unversionedId:"icicle/overview",id:"icicle/overview",title:"What is ICICLE?",description:"Static Badge",source:"@site/docs/icicle/overview.md",sourceDirName:"icicle",slug:"/icicle/overview",permalink:"/icicle/overview",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/icicle/overview.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"",permalink:"/"},next:{title:"Getting started with ICICLE",permalink:"/icicle/introduction"}},s={},c=[{value:"Dont have access to a GPU?",id:"dont-have-access-to-a-gpu",level:2},{value:"Grants",id:"grants",level:3},{value:"Google Colab",id:"google-colab",level:3},{value:"Vast.ai",id:"vastai",level:3},{value:"What can you do with ICICLE?",id:"what-can-you-do-with-icicle",level:2},{value:"Circuit developers",id:"circuit-developers",level:3},{value:"Integrating into existing ZK provers",id:"integrating-into-existing-zk-provers",level:3},{value:"Developing your own ZK provers",id:"developing-your-own-zk-provers",level:3},{value:"Developing proof of concepts",id:"developing-proof-of-concepts",level:3}],p={toc:c},u="wrapper";function d(e){let{components:t,...a}=e;return(0,n.kt)(u,(0,r.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h1",{id:"what-is-icicle"},"What is ICICLE?"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/releases"},(0,n.kt)("img",{parentName:"a",src:"https://img.shields.io/badge/Latest-v1.5.0-8a2be2",alt:"Static Badge"}))),(0,n.kt)("p",null,(0,n.kt)("img",{parentName:"p",src:"https://img.shields.io/badge/Machines%20running%20ICICLE-544-lightblue",alt:"Static Badge"})),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," is a cryptography library for ZK using GPUs. ICICLE implements blazing fast cryptographic primitives such as EC operations, MSM, NTT, Poseidon hash and more on GPU."),(0,n.kt)("p",null,"ICICLE allows developers with minimal GPU experience to effortlessly accelerate their ZK application; from our experiments, even the most naive implementation may yield 10X improvement in proving times."),(0,n.kt)("p",null,"ICICLE has been used by many leading ZK companies such as ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/celer-network"},"Celer Network"),", ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark")," and others to accelerate their ZK proving pipeline."),(0,n.kt)("h2",{id:"dont-have-access-to-a-gpu"},"Dont have access to a GPU?"),(0,n.kt)("p",null,"We understand that not all developers have access to a GPU and we don't want this to limit anyone from developing with ICICLE.\nHere are some ways we can help you gain access to GPUs:"),(0,n.kt)("h3",{id:"grants"},"Grants"),(0,n.kt)("p",null,"At Ingonyama we are interested in accelerating the progress of ZK and cryptography. If you are an engineer, developer or an academic researcher we invite you to checkout ",(0,n.kt)("a",{parentName:"p",href:"https://www.ingonyama.com/blog/icicle-for-researchers-grants-challenges"},"our grant program"),". We will give you access to GPUs and even pay you to do your dream research!"),(0,n.kt)("h3",{id:"google-colab"},"Google Colab"),(0,n.kt)("p",null,"This is a great way to get started with ICICLE instantly. Google Colab offers free GPU access to a NVIDIA T4 instance, it's acquired with 16 GB of memory which should be enough for experimenting and even prototyping with ICICLE."),(0,n.kt)("p",null,"For an extensive guide on how to setup Google Colab with ICICLE refer to ",(0,n.kt)("a",{parentName:"p",href:"/icicle/colab-instructions"},"this article"),"."),(0,n.kt)("p",null,"If none of these options are appropriate for you reach out to us on ",(0,n.kt)("a",{parentName:"p",href:"https://t.me/RealElan"},"telegram")," we will do our best to help you."),(0,n.kt)("h3",{id:"vastai"},"Vast.ai"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://vast.ai/"},"Vast.ai")," is a global GPU marketplace where you can rent many different types of GPUs by the hour for ",(0,n.kt)("a",{parentName:"p",href:"https://vast.ai/pricing"},"competitive pricing"),". They provide on-demand and interruptible rentals depending on your need or use case; you can learn more about their rental types ",(0,n.kt)("a",{parentName:"p",href:"https://vast.ai/faq#rental-types"},"here"),"."),(0,n.kt)("div",{className:"admonition admonition-note alert alert--secondary"},(0,n.kt)("div",{parentName:"div",className:"admonition-heading"},(0,n.kt)("h5",{parentName:"div"},(0,n.kt)("span",{parentName:"h5",className:"admonition-icon"},(0,n.kt)("svg",{parentName:"span",xmlns:"http://www.w3.org/2000/svg",width:"14",height:"16",viewBox:"0 0 14 16"},(0,n.kt)("path",{parentName:"svg",fillRule:"evenodd",d:"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"}))),"note")),(0,n.kt)("div",{parentName:"div",className:"admonition-content"},(0,n.kt)("p",{parentName:"div"},"If none of these options suit your needs, contact us on ",(0,n.kt)("a",{parentName:"p",href:"https://t.me/RealElan"},"telegram")," for assistance. We're committed to ensuring that a lack of a GPU doesn't become a bottleneck for you. If you need help with setup or any other issues, we're here to do our best to help you."))),(0,n.kt)("h2",{id:"what-can-you-do-with-icicle"},"What can you do with ICICLE?"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle"},"ICICLE")," can be used in the same way you would use any other cryptography library. While developing and integrating ICICLE into many proof systems, we found some use case categories:"),(0,n.kt)("h3",{id:"circuit-developers"},"Circuit developers"),(0,n.kt)("p",null,"If you are a circuit developer and are experiencing bottlenecks while running your circuits, an ICICLE integrated prover may be the solution."),(0,n.kt)("p",null,"ICICLE has been integrated into a number of popular ZK provers including ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/Consensys/gnark"},"Gnark prover")," and ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/zkonduit/halo2"},"Halo2"),". This means that you can enjoy GPU acceleration for your existing circuits immediately without writing a single line of code by simply switching on the GPU prover flag!"),(0,n.kt)("h3",{id:"integrating-into-existing-zk-provers"},"Integrating into existing ZK provers"),(0,n.kt)("p",null,"From our collaborations we have learned that its possible to accelerate a specific part of your prover to solve for a specific bottleneck."),(0,n.kt)("p",null,"ICICLE can be used to accelerate specific parts of your prover without completely rewriting your ZK prover."),(0,n.kt)("h3",{id:"developing-your-own-zk-provers"},"Developing your own ZK provers"),(0,n.kt)("p",null,"If your goal is to build a ZK prover from the ground up, ICICLE is an ideal tool for creating a highly optimized and scalable ZK prover. A key benefit of using GPUs with ICICLE is the ability to scale your ZK prover efficiently across multiple machines within a data center."),(0,n.kt)("h3",{id:"developing-proof-of-concepts"},"Developing proof of concepts"),(0,n.kt)("p",null,"ICICLE is also ideal for developing small prototypes. ICICLE has Golang and Rust bindings so you can easily develop a library implementing a specific primitive using ICICLE. An example would be develop a KZG commitment library using ICICLE."))}d.isMDXComponent=!0},8209:(e,t,a)=>{a(7294)}}]); \ No newline at end of file diff --git a/assets/js/fdbbc319.0dcb1a13.js b/assets/js/fdbbc319.b8d6ecfd.js similarity index 97% rename from assets/js/fdbbc319.0dcb1a13.js rename to assets/js/fdbbc319.b8d6ecfd.js index 101768e..cec2a80 100644 --- a/assets/js/fdbbc319.0dcb1a13.js +++ b/assets/js/fdbbc319.b8d6ecfd.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[429],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=r.createContext({}),s=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,u=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=s(n),m=a,g=p["".concat(u,".").concat(m)]||p[m]||d[m]||i;return n?r.createElement(g,o(o({ref:t},c),{},{components:n})):r.createElement(g,o({ref:t},c))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[p]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(7462),a=(n(7294),n(3905));n(8209);const i={},o="Contributor's Guide",l={unversionedId:"contributor-guide",id:"contributor-guide",title:"Contributor's Guide",description:"We welcome all contributions with open arms. At Ingonyama we take a village approach, believing it takes many hands and minds to build a ecosystem.",source:"@site/docs/contributor-guide.md",sourceDirName:".",slug:"/contributor-guide",permalink:"/contributor-guide",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/contributor-guide.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708031264,formattedLastUpdatedAt:"2/15/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Ingonyama Grant programs",permalink:"/grants"}},u={},s=[{value:"Contributing to ICICLE",id:"contributing-to-icicle",level:2},{value:"Opening a pull request",id:"opening-a-pull-request",level:3},{value:"Questions?",id:"questions",level:2}],c={toc:s},p="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(p,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"contributors-guide"},"Contributor's Guide"),(0,a.kt)("p",null,"We welcome all contributions with open arms. At Ingonyama we take a village approach, believing it takes many hands and minds to build a ecosystem."),(0,a.kt)("h2",{id:"contributing-to-icicle"},"Contributing to ICICLE"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Make suggestions or report bugs via ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/issues"},"GitHub issues")),(0,a.kt)("li",{parentName:"ul"},"Contribute to the ICICLE by opening a ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/pulls"},"pull request"),"."),(0,a.kt)("li",{parentName:"ul"},"Contribute to our ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/developer-docs"},"documentation")," and ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle-examples"},"examples"),"."),(0,a.kt)("li",{parentName:"ul"},"Ask questions on Discord")),(0,a.kt)("h3",{id:"opening-a-pull-request"},"Opening a pull request"),(0,a.kt)("p",null,"When opening a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/pulls"},"pull request")," please keep the following in mind."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Clear Purpose")," - The pull request should solve a single issue and be clean of any unrelated changes."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Clear description")," - If the pull request is for a new feature describe what you built, why you added it and how its best that we test it. For bug fixes please describe the issue and the solution."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Consistent style")," - Rust and Golang code should be linted by the official linters (golang fmt and rust fmt) and maintain a proper style. For CUDA and C++ code we use ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/blob/main/.clang-format"},(0,a.kt)("inlineCode",{parentName:"a"},"clang-format")),", ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/blob/605c25f9d22135c54ac49683b710fe2ce06e2300/.github/workflows/main-format.yml#L46"},"here")," you can see how we run it."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Minimal Tests")," - please add test which cover basic usage of your changes .")),(0,a.kt)("h2",{id:"questions"},"Questions?"),(0,a.kt)("p",null,"Find us on ",(0,a.kt)("a",{parentName:"p",href:"https://discord.gg/6vYrE7waPj"},"Discord"),"."))}d.isMDXComponent=!0},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocusaurus=self.webpackChunkdocusaurus||[]).push([[429],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var u=r.createContext({}),s=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=s(e.components);return r.createElement(u.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,u=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),p=s(n),m=a,g=p["".concat(u,".").concat(m)]||p[m]||d[m]||i;return n?r.createElement(g,o(o({ref:t},c),{},{components:n})):r.createElement(g,o({ref:t},c))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[p]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>o,default:()=>d,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var r=n(7462),a=(n(7294),n(3905));n(8209);const i={},o="Contributor's Guide",l={unversionedId:"contributor-guide",id:"contributor-guide",title:"Contributor's Guide",description:"We welcome all contributions with open arms. At Ingonyama we take a village approach, believing it takes many hands and minds to build a ecosystem.",source:"@site/docs/contributor-guide.md",sourceDirName:".",slug:"/contributor-guide",permalink:"/contributor-guide",editUrl:"https://github.com/ingonyama-zk/developer-docs/tree/main/docs/contributor-guide.md",tags:[],version:"current",lastUpdatedBy:"Otsar",lastUpdatedAt:1708947542,formattedLastUpdatedAt:"2/26/2024",frontMatter:{},sidebar:"GettingStartedSidebar",previous:{title:"Ingonyama Grant programs",permalink:"/grants"}},u={},s=[{value:"Contributing to ICICLE",id:"contributing-to-icicle",level:2},{value:"Opening a pull request",id:"opening-a-pull-request",level:3},{value:"Questions?",id:"questions",level:2}],c={toc:s},p="wrapper";function d(e){let{components:t,...n}=e;return(0,a.kt)(p,(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h1",{id:"contributors-guide"},"Contributor's Guide"),(0,a.kt)("p",null,"We welcome all contributions with open arms. At Ingonyama we take a village approach, believing it takes many hands and minds to build a ecosystem."),(0,a.kt)("h2",{id:"contributing-to-icicle"},"Contributing to ICICLE"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Make suggestions or report bugs via ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/issues"},"GitHub issues")),(0,a.kt)("li",{parentName:"ul"},"Contribute to the ICICLE by opening a ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/pulls"},"pull request"),"."),(0,a.kt)("li",{parentName:"ul"},"Contribute to our ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/developer-docs"},"documentation")," and ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle-examples"},"examples"),"."),(0,a.kt)("li",{parentName:"ul"},"Ask questions on Discord")),(0,a.kt)("h3",{id:"opening-a-pull-request"},"Opening a pull request"),(0,a.kt)("p",null,"When opening a ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/ingonyama-zk/icicle/pulls"},"pull request")," please keep the following in mind."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Clear Purpose")," - The pull request should solve a single issue and be clean of any unrelated changes."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Clear description")," - If the pull request is for a new feature describe what you built, why you added it and how its best that we test it. For bug fixes please describe the issue and the solution."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Consistent style")," - Rust and Golang code should be linted by the official linters (golang fmt and rust fmt) and maintain a proper style. For CUDA and C++ code we use ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/blob/main/.clang-format"},(0,a.kt)("inlineCode",{parentName:"a"},"clang-format")),", ",(0,a.kt)("a",{parentName:"li",href:"https://github.com/ingonyama-zk/icicle/blob/605c25f9d22135c54ac49683b710fe2ce06e2300/.github/workflows/main-format.yml#L46"},"here")," you can see how we run it."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("inlineCode",{parentName:"li"},"Minimal Tests")," - please add test which cover basic usage of your changes .")),(0,a.kt)("h2",{id:"questions"},"Questions?"),(0,a.kt)("p",null,"Find us on ",(0,a.kt)("a",{parentName:"p",href:"https://discord.gg/6vYrE7waPj"},"Discord"),"."))}d.isMDXComponent=!0},8209:(e,t,n)=>{n(7294)}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.59ac1dd1.js b/assets/js/runtime~main.0d664441.js similarity index 77% rename from assets/js/runtime~main.59ac1dd1.js rename to assets/js/runtime~main.0d664441.js index be1b746..7418f1f 100644 --- a/assets/js/runtime~main.59ac1dd1.js +++ b/assets/js/runtime~main.0d664441.js @@ -1 +1 @@ -(()=>{"use strict";var e,t,r,a,o,c={},d={};function n(e){var t=d[e];if(void 0!==t)return t.exports;var r=d[e]={id:e,loaded:!1,exports:{}};return c[e].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}n.m=c,n.c=d,e=[],n.O=(t,r,a,o)=>{if(!r){var c=1/0;for(u=0;u=o)&&Object.keys(n.O).every((e=>n.O[e](r[f])))?r.splice(f--,1):(d=!1,o0&&e[u-1][2]>o;u--)e[u]=e[u-1];e[u]=[r,a,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);n.r(o);var c={};t=t||[null,r({}),r([]),r(r)];for(var d=2&a&&e;"object"==typeof d&&!~t.indexOf(d);d=r(d))Object.getOwnPropertyNames(d).forEach((t=>c[t]=()=>e[t]));return c.default=()=>e,n.d(o,c),o},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,r)=>(n.f[r](e,t),t)),[])),n.u=e=>"assets/js/"+({53:"935f2afb",58:"a8dc15ca",67:"0dca48ed",83:"584ea0b6",128:"a09c2993",131:"076f2345",244:"acd9d3d0",287:"46bc3aca",429:"fdbbc319",472:"3db59c3c",514:"1be78505",541:"ec013bfd",614:"2b850a9b",623:"bb0bd8d7",774:"62ce5d13",827:"90656eea",862:"0ec3cab9",918:"17896441",920:"1a4e3797",929:"03cb0a55",984:"93a51358"}[e]||e)+"."+{53:"43e2195e",58:"d72dd6a1",67:"bfa3c731",83:"c8828735",128:"b358e04d",131:"aced6b81",244:"ed9bd5c9",287:"cc5c1b6f",426:"e654100f",429:"0dcb1a13",472:"422f8b46",514:"5d6a80d6",541:"0bc0bf0d",608:"877c8809",614:"40ab3057",623:"d2ce985a",774:"2a27b3b1",827:"d15777d5",862:"2180a8ed",894:"fbf84e18",918:"60dfc074",920:"d7cc8439",929:"effbdeae",945:"a66b494f",984:"5e6e7172"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="docusaurus:",n.l=(e,t,r,c)=>{if(a[e])a[e].push(t);else{var d,f;if(void 0!==r)for(var i=document.getElementsByTagName("script"),u=0;u{d.onerror=d.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],d.parentNode&&d.parentNode.removeChild(d),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),f&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/",n.gca=function(e){return e={17896441:"918","935f2afb":"53",a8dc15ca:"58","0dca48ed":"67","584ea0b6":"83",a09c2993:"128","076f2345":"131",acd9d3d0:"244","46bc3aca":"287",fdbbc319:"429","3db59c3c":"472","1be78505":"514",ec013bfd:"541","2b850a9b":"614",bb0bd8d7:"623","62ce5d13":"774","90656eea":"827","0ec3cab9":"862","1a4e3797":"920","03cb0a55":"929","93a51358":"984"}[e]||e,n.p+n.u(e)},(()=>{var e={303:0,532:0};n.f.j=(t,r)=>{var a=n.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var c=n.p+n.u(t),d=new Error;n.l(c,(r=>{if(n.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),c=r&&r.target&&r.target.src;d.message="Loading chunk "+t+" failed.\n("+o+": "+c+")",d.name="ChunkLoadError",d.type=o,d.request=c,a[1](d)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,c=r[0],d=r[1],f=r[2],i=0;if(c.some((t=>0!==e[t]))){for(a in d)n.o(d,a)&&(n.m[a]=d[a]);if(f)var u=f(n)}for(t&&t(r);i{"use strict";var e,t,r,a,o,c={},d={};function n(e){var t=d[e];if(void 0!==t)return t.exports;var r=d[e]={id:e,loaded:!1,exports:{}};return c[e].call(r.exports,r,r.exports,n),r.loaded=!0,r.exports}n.m=c,n.c=d,e=[],n.O=(t,r,a,o)=>{if(!r){var c=1/0;for(b=0;b=o)&&Object.keys(n.O).every((e=>n.O[e](r[f])))?r.splice(f--,1):(d=!1,o0&&e[b-1][2]>o;b--)e[b]=e[b-1];e[b]=[r,a,o]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},r=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,n.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var o=Object.create(null);n.r(o);var c={};t=t||[null,r({}),r([]),r(r)];for(var d=2&a&&e;"object"==typeof d&&!~t.indexOf(d);d=r(d))Object.getOwnPropertyNames(d).forEach((t=>c[t]=()=>e[t]));return c.default=()=>e,n.d(o,c),o},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.f={},n.e=e=>Promise.all(Object.keys(n.f).reduce(((t,r)=>(n.f[r](e,t),t)),[])),n.u=e=>"assets/js/"+({53:"935f2afb",58:"a8dc15ca",67:"0dca48ed",83:"584ea0b6",128:"a09c2993",131:"076f2345",244:"acd9d3d0",287:"46bc3aca",429:"fdbbc319",472:"3db59c3c",514:"1be78505",541:"ec013bfd",614:"2b850a9b",623:"bb0bd8d7",774:"62ce5d13",827:"90656eea",862:"0ec3cab9",918:"17896441",920:"1a4e3797",929:"03cb0a55",984:"93a51358"}[e]||e)+"."+{53:"43e2195e",58:"d72dd6a1",67:"55ac5a02",83:"d52ce6af",128:"1d68ad2b",131:"e539f211",244:"782ff31b",287:"7b300224",426:"e654100f",429:"b8d6ecfd",472:"ed96355d",514:"5d6a80d6",541:"cb089409",608:"877c8809",614:"a413b9a9",623:"d2ce985a",774:"dd7fe865",827:"6292a4ae",862:"e355dffd",894:"fbf84e18",918:"60dfc074",920:"d7cc8439",929:"12036a44",945:"a66b494f",984:"2c386f0b"}[e]+".js",n.miniCssF=e=>{},n.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),a={},o="docusaurus:",n.l=(e,t,r,c)=>{if(a[e])a[e].push(t);else{var d,f;if(void 0!==r)for(var i=document.getElementsByTagName("script"),b=0;b{d.onerror=d.onload=null,clearTimeout(s);var o=a[e];if(delete a[e],d.parentNode&&d.parentNode.removeChild(d),o&&o.forEach((e=>e(r))),t)return t(r)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),f&&document.head.appendChild(d)}},n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.p="/",n.gca=function(e){return e={17896441:"918","935f2afb":"53",a8dc15ca:"58","0dca48ed":"67","584ea0b6":"83",a09c2993:"128","076f2345":"131",acd9d3d0:"244","46bc3aca":"287",fdbbc319:"429","3db59c3c":"472","1be78505":"514",ec013bfd:"541","2b850a9b":"614",bb0bd8d7:"623","62ce5d13":"774","90656eea":"827","0ec3cab9":"862","1a4e3797":"920","03cb0a55":"929","93a51358":"984"}[e]||e,n.p+n.u(e)},(()=>{var e={303:0,532:0};n.f.j=(t,r)=>{var a=n.o(e,t)?e[t]:void 0;if(0!==a)if(a)r.push(a[2]);else if(/^(303|532)$/.test(t))e[t]=0;else{var o=new Promise(((r,o)=>a=e[t]=[r,o]));r.push(a[2]=o);var c=n.p+n.u(t),d=new Error;n.l(c,(r=>{if(n.o(e,t)&&(0!==(a=e[t])&&(e[t]=void 0),a)){var o=r&&("load"===r.type?"missing":r.type),c=r&&r.target&&r.target.src;d.message="Loading chunk "+t+" failed.\n("+o+": "+c+")",d.name="ChunkLoadError",d.type=o,d.request=c,a[1](d)}}),"chunk-"+t,t)}},n.O.j=t=>0===e[t];var t=(t,r)=>{var a,o,c=r[0],d=r[1],f=r[2],i=0;if(c.some((t=>0!==e[t]))){for(a in d)n.o(d,a)&&(n.m[a]=d[a]);if(f)var b=f(n)}for(t&&t(r);i