ZPiE: Zero-Knowledge Proofs in Embedded Systems

: Zero-Knowledge Proofs (ZKPs) are cryptographic primitives allowing a party to prove to another party that the former knows some information while keeping it secret. Such a premise can lead to the development of numerous privacy-preserving protocols in different scenarios, like proving knowledge of some credentials to a server without leaking the identity of the user. Even when the applications of ZKPs were endless, they were not exploited in the wild for a couple of decades due to the fact that computing and verifying proofs was too computationally expensive. However, the advent of efﬁcient schemes (in particular, zk-SNARKs) made this primitive to break into the scene in ﬁelds like cryptocurrencies, smart-contracts, and more recently, self-sovereign scenarios: private-by-design identity management and authentication. Nevertheless, its adoption in environments like the Internet of Things (IoT) remains unexplored due to the computational limitations of embedded systems. In this paper, we introduce ZPiE, a C library intended to create ZKP applications to be executed in embedded systems. Its main feature is portability: it can be compiled, executed, and used out-of-the-box in a wide variety of devices. Moreover, our proof-of-concept has been proved to work smoothly in different devices with limited resources, which can execute state-of-the-art ZKP authentication protocols.


Introduction
The inclusion of 5G communications [1] involves the deployment of network slices , dedicated physical and logical networks for different use cases such as the Internet of Things (IoT) [2]. In this scenario, 5G grants a large bandwidth and a low latency to be able to handle a large density of IoT devices. This fact has a big impact on the evolution of the smartcities paradigm, where the amount of IoT devices is growing exponentially [3]. In that regard, exposure to cyberattacks like identity spoofing [4] is a big concern. To prevent this specific issue, several solutions have been designed, for instance, using physical unclonable functions [5], which has been proved to be a secure way to identify IoT devices. However, such authentication mechanisms cannot be completed with a single-message protocol, which introduces some latency to the scheme. Other solutions like in [6] present a way to authenticate IoT devices using Blockchains [7], distributed networks sharing a unique ledger containing transactions made by different nodes in the network. This builds a decentralized way to authenticate devices, which is also lightweight and applicable to a large number of scenarios.
However, even when most authentication mechanisms are secure against spoofing attacks, users' privacy is still an issue to be addressed. Examples of this are medical devices exchanging patients' private information, or autonomous cars sharing their location with a server. The common point between all these devices is that they need to share sensitive data over the network, data which should not be traced by any Internet Service Provider (ISP) or eavesdropper. Self-sovereign identity systems [8] become an essential feature to implement in this scenario: systems where users can control, access, and transparently consent their identities, preventing entities to track and collect their data. Research integrating such features into IoT environments has been conducted, like in [9], where the authors combine self-sovereign identity systems with distributed ledger technologies. The main elements required to get these features are Zero-Knowledge Proofs (ZKPs).
ZKPs are cryptographic primitives gaining a lot of momentum thanks to technologies such as Blockchain. While cryptocurrencies like Bitcoin [10] allow any node to review the transactions, knowing the sender, receiver, and the amount of exchanged money (among all the information involving the transaction), cryptocurrencies such as Zcash [11] use a specific ZKP scheme that allows its users to make anonymous payments. ZKPs allow a party (the prover) to prove to another party (the verifier) that he knows some information while keeping it secret. In other words, the sender, the receiver, and the amount of exchanged money is kept secret while everyone in the network agrees on the correctness of the transaction.

Motivation
Beyond cryptocurrencies, ZKPs are also used in protocols such as SANS [12], a privacypreserving authentication scheme where users prove their right to access a service, based on some previously granted attributes. On the other hand, blockchains like Ethereum [13] provide an architecture capable of executing programs on-chain. These programs, called smart-contracts, can be combined with ZKP schemes to grant more privacy to its users: for instance, issuing a payment after using some service, while keeping the identity of the user secret. Protocols based on such approaches would be desirable in IoT scenarios, where many services are used, and most of them (such as medical applications) collect sensitive data. However, ZKP schemes require high computational resources, especially when the proof is generated. Even when current ZKP implementations do a great job in terms of efficiency, they are far from being portable, especially for embedded systems, as most of them focus on web applications, with the usage of programming languages like JavaScript, Webassembly, or Python. Some solutions [14] try to distribute the operations to be done to generate the proof between trusted servers. However, such approaches require a trusted environment and a persistent and fast connection with the server. Optimal solutions would be novel implementations focused on devices with low resources.

Contributions
We introduce ZPiE, a portable C library for generating and verifying ZKPs. As an initial proof-of-concept, ZPiE implements the specific ZKP construction called zk-SNARK. Our library provides a clear API to create proofs, and to verify them. Upon doing several tests on different devices, we have proved that, unlike other state-of-the-art solutions, ZPiE can be executed in x86, x86_64, aarch64 and arm32 CPU architectures out-of-thebox. In addition, after performing several experiments using a x86_64 CPU (compatible with other state-of-the-art libraries) and comparing the results with other solutions, we have proved that ZPiE has similar performance. Furthermore, our solution can be easily integrated with existing implementations to be used in smart-contracts.

Roadmap
In Section 2 we survey the relevant use cases and libraries developed to work with ZKPs. In Section 3 we expose the building blocks required to understand the primitive we are implementing. In Section 4 we present ZPiE with all details. In Section 5 we include the performed experiments and their results. Conclusions and future work are provided in Section 6.

Related Work
In this section, we first introduce the main use cases of ZKPs. Later, we explain the different ZKP schemes and libraries used in real scenarios.

ZKP Use Cases
One of the main uses of ZKPs is enhancing privacy in cryptocurrencies. Along with the previously stated Zcash, other cryptocurrencies like Monero (https://www.getmonero. org/, accessed on 12 October 2021) use ZKPs to provide anonymous transactions when sending and receiving money over its network. Far from being limited to cryptocurrencies, ZKPs are used in Self-Sovereign Identity (SSI) systems as well, where users can control, consent, and widely use their identities among different services, along with other properties. A recent example of this is the solution introduced in [15], where authors introduce a Blockchain-based protocol combined with ZKPs, for enabling privacy-preserving authentication while removing the need for a central authority. They apply such an approach in electric vehicles scenarios, specifically when the vehicles need to charge the battery, and identification is requested by a charging provider.
Another recent research topic is introduced in SANS [12], where ZKPs could be used to authenticate users in scenarios like in 5G services. Such a protocol works as follows: upon signing up for using a 5G service, the service provider grants the user a digital signature signed by him, along with other parameters. Later, each time the user wants to use the service, he can do it anonymously: he computes a ZKP to demonstrate that he possesses a valid signature computed by the service provider, without leaking any other information. The service provider can validate the proof and grant the service without learning the identity of the user. Moreover, such an approach enhances privacy in distributed applications (DApps) as well. DApps are blockchain applications built using smart-contracts, which are binaries executed on-chain. For instance in Ethereum, such binaries are the result of compiling Solidity code (https://solidity.readthedocs.io/en/v0 .5.3/, accessed on 12 October 2021) . Like this, a program that verifies proofs could be executed on-chain. This technology can grant more privacy to users using different kinds of DApps, not solely using ZKPs but also using approaches like the one introduced in [16]. However, as stated, even when the verification is executed on-chain, the proof still needs to be computed by the proving device. As such, it is still hard to use DApps based on ZKPs on IoT devices due to its hardware limitations.

ZKP Schemes
Currently, there are several ZKP constructions used in the wild, each with its advantages and drawbacks. As shown in Table 1, one of the first efficient schemes was a zk-SNARK introduced in BSCTV'13 [17]. Such a scheme was later improved by the zk-SNARK introduced in Groth'16 [18], which is still one of the most efficient zk-SNARK schemes, especially when it comes to the verification algorithm. One of the main drawbacks of this kind of construction is the need for a trusted party that performs a trusted setup: a phase where some public parameters are generated, which will be used to generate and verify proofs. In this regard, Sonic [19] is a zk-SNARK that introduces a scheme where the setup can be updated for different circuits without the need to repeat the trusted setup generation. Another efficient zk-SNARK is Libra [20], which prover is guaranteed to outperform, even when the verifier does not have constant complexity. The most recent work on this topic was done by the authors in [21]. They introduce PlonK, a scheme with the same advantages that Sonic has, but improving the speed of the prover. Finally, recent research such as [22] shows a way to design a more efficient prover, while not compromising the verifier.  [17] no [18] no [19] no [20] no q-SBDH, q-PKE Bulletproofs [23] no no O(n) O(n) O(log n) DLP zk-STARKs [24] no yes On the other hand, and beyond zk-SNARKs, we can find other ZKP schemes like Bulletproofs [23], which have the main advantage of not requiring a trusted setup. They are especially useful when the prover needs to compute a range proof [25], instead of an arithmetic circuit. Moreover, other concerns like post-quantum security have also arisen in the Zero-Knowledge field, and in this regard we have a scheme supposed to be postquantum secure, called zk-STARKs (Zero-Knowledge Succinct Transparent ARgument of Knowledge) [24]. Post-quantum security is not a property of zk-SNARKs or Bulletproofs.
Finally, the soundness property of each of the schemes described relies on different security assumptions [26]. Most of the zk-SNARK constructions use a strong assumption called q-Power Knowledge of Exponent (q-PKE), which is not the best solution. On the other hand, Bulletproofs or zk-STARKs use better assumptions: the Discrete Logarithm Problem (DLP) and Collision Resistant Hash Functions (CRHF), respectively.
To develop ZKP applications, libraries like the one provided in this paper are required. One of the main libraries to accomplish this purpose is libsnark (https://github.com/ scipr-lab/libsnark, accessed on 12 October 2021) a C++ library for constructing zk-SNARKs, which was used for some time by Zcash [11], based on the specific zk-SNARK construction introduced in [17], but supporting [18] as well, among others. Even when this library provides excellent benchmarks, one of the main drawbacks of this library, as the authors state, is not being well-optimized for ARM architectures.
Another library with similar benchmarks is bellman (https://github.com/zkcrypto/ bellman/, accessed on 12 October 2021) implemented in Rust and meant for constructing zk-SNARKs, developed and currently used by Zcash.
Moreover, when it comes to developing DApps for the Ethereum blockchain, we previously stated that a verifier coded in Solidity is required. ZoKrates (https://github. com/Zokrates/ZoKrates, accessed on 12 October 2021) is a python toolbox for zk-SNARKs intended to generate Solidity verifiers, to be deployed into the Ethereum blockchain. Furthermore, a similar approach is snarkjs (https://github.com/iden3/snarkjs, accessed on 12 October 2021) a JavaScript library for constructing zk-SNARKs. It includes a clear API for generating trusted setups using a fairly secure MPC protocol, for generating proofs, and for verifying them. Plus, it also provides an easy way to export the verifier in Solidity, to deploy it into the Ethereum blockchain.

Building Blocks: zk-SNARKs
In this section, we introduce the required building blocks in regards to our solution. We do a high-level overview of how to construct a zk-SNARK (based on the construction introduced in [18]), which is also the scheme used in our proof-of-concept.

Preliminaries
A Zero-Knowledge Proof (ZKP) [27] is a cryptographic primitive which allows a prover P to convince a verifier V that a statement is true, without leaking any secret information. A statement is a set of elements known by both parties, defined as u ∈ L, where L is a Language. We have a witness w (the secret information only known by P) for a statement u if (u, w) ∈ R, where R is a polynomial-time decidable binary relation associated with L. Formally speaking, ZKPs must satisfy 3 properties: • Completeness: If the statement is true, P must be able to convince V. • Soundness: If the statement is false, P must not be able to convince V that the statement is true, except with negligible probability. • Zero-knowledge: V must not learn any information from the proof beyond the fact that the statement is true.
Moreover, V might request a proof of knowledge, a property to guarantee that P knows a witness w. Such a witness is a vector of elements for which a set of operations hold. These operations are defined by a graph composed of different wires and gates called circuit. Such a circuit leads to a set of equations representing the inputs and the outputs of these gates. The equations are also called constraints.
Even when first schemes required P and V to interact several times, Non-Interactive ZKPs (NIZKPs) [28] emerged, allowing P to prove statements to V by sending him a single message.
zk-SNARKs are Zero-Knowledge Succinct and Non-interactive ARguments of Knowledge [17]. They are the most used ZKPs, because they are short and succinct: the proofs can be verified in a few milliseconds. However, they require a trusted setup where some public parameters are generated. These parameters, called the Common Reference String (CRS), are used either by P and V to generate and verify proofs. In the process of generating the CRS, a secret randomness τ is used, and such a randmoness should be destroyed afterwards. If an attacker gets τ, the soundness property of the scheme breaks: the attacker would be able to compute false proofs that anyone could verify as if they were correct. As such, the CRS is commonly computed using a secure Multi-Party Computation (MPC) protocol [29], where τ can only be leaked if all the participants are malicious. Therefore, zk-SNARKs are composed of three main algorithms: setup, prove and verify. The computing complexity of these algorithms depends on the number of operations that we do in the circuit, which is also the the number of gates n.
Regarding the security of zk-SNARKs, it mainly relies on the security of elliptic curves. Breaking the security of the elliptic curve used by a specific construction would lead to being able to generate false proofs and thus, breaking the soundness property of the scheme. Among the most used curves in ZKPs we have a Barreto-Naehrig curve [30] called BN128, which security level in practice is estimated to be 110-bits [31]. Another common curve in this scenario is BLS12-381 [11], which has around 128-bits of security, with the drawback of heavier group operations. More recent research is introduced in [32], where a new curve called BW6-761 is introduced. As stated by its authors, verification of proofs is at least five times faster than other state-of-the-art curves.
The zk-SNARK construction we will work on requires a pairing-friendly elliptic curve E over a finite field F q , where q is a prime number, with the bilinear groups (G 1 , G 2 , G T ) of prime order r and a pairing e : G 1 × G 2 → G T being a bilinear map. We need the following generators: an element g being a generator for G 1 , an element h being a generator for G 2 , and e(g, h) being a generator for G T . In order to represent group elements, we use the widely used additive notation: we write [a] 1 for g a , [b] 2 for g b , and [c] T for e(g, h) c .
Arithmetic circuit. A circuit is a directed acyclic graph composed of different wires and gates, which lead to a set of equations relating the inputs and the outputs of these gates. The inputs and the output of this circuit, as well as the operations defined in the gates, are elements over a prime field F r , where r is the order of E.
Rank 1 Constraint System. A Rank 1 Constraint System (R1CS) is a system of equations which checks the correctness of all the operations in our circuit, by grouping them in constraints. Each constraint is composed of a multiplicative gate with its two inputs and its output. Having a statement u and a witness w such that (u, w) ∈ R, a R1CS is defined as a set of vectors (a, b, c) defining our circuit, whose solution is a vector s = (u, w) such that the following equation is satisfied: Quadratic Arithmetic Program. A Quadratic Arithmetic Program (QAP) is a polynomial representation of the R1CS, which bundles all its constraints into one. It is a tuple of the polynomials (A They satisfy the following equation:

Protocol
Let R be a relation composed of the elliptic curve E over F q , the pairing e and a QAP (A, B, C, Z(x)) representing a circuit. The Groth'16 construction is divided into three algorithms (further details can be found in Appendix A), as depicted in Figure 1: • pk, vk ← Setup(R): given the relation R, the first step of the protocol generates a common reference string (CRS) σ = ([σ 1 ] 1 , [σ 2 ] 2 ). From the CRS, some elements will be extracted into what we call the proving key pk, sent to the prover P to generate proofs. Moreover, other required elements will be taken into the verifying key vk, and sent to the verifier V to verify the proofs generated by P. In order to generate the CRS (i.e., pk and vk), a random set of values τ is used. This τ, also known as trapdoor, should be destroyed after performing the setup, as any party having τ would be able to generate false proofs. To solve this last drawback, the setup must be generated by a trusted party (i.e., a set of entities performing a secure MPC protocol). In scenarios such as cryptocurrencies using zk-SNARKs (i.e., Zcash), an untrusty setup could lead to malicious parties using τ to create false transactions, thus leading to losses of money. • π ← Prove(R, pk, u, w): the prover generates a proof π = ([π A ] 1 , [π B ] 2 , [π C ] 1 ), by multiplying u and w by some polynomials provided in σ. The prover also needs to compute the coefficients h of H(x), which can be achieved in O(n log n) using Fast Fourier Transform (FFT) techniques, as explained in detail in Appendix B. Then, h is multiplied by a polynomial provided in σ. The number of multi-exponentiations required to compute π are (note that multi-exponentiations in G 2 are more expensive than multi-exponentiations in G 1 ): -to compute [π A ] 1 : |u| + |w| multi-exponentiations in G 1 . -to compute [π B ] 2 : |u| + |w| multi-exponentiations in G 2 . -to compute [π C ] 1 : |u| + 2 · |w| + |h| multi-exponentiations in G 1 . • 0/1 ← Veri f y(R, vk, u, π): the verifier accepts the proof (1) if an equation composed of three pairings [33] holds. Otherwise, the proof is rejected (0). Moreover, modifying a single bit of the proof leads to a proof that cannot be verified.
As such, the workflow of these algorithms in real applications would work as follows: we first need to compute the setup by means of a trusted party (step 1 in Figure 1). Later, this party shall share the required values with each of the involved parties, the prover and the verifier (step 2 in Figure 1). As shown in the steps 3 and 4, the prover computes the proof π and sends it to the verifier, who verifies it (step 5 in Figure 1). Steps 1 and 2 are performed only once, and later, the prover can compute as many proofs as he wants using the same values computed during the setup.

Setup
Prover Verifier

Our Solution: ZPiE
In this section, we provide all details regarding ZPiE. We start with a comprehensive explanation about how it was designed, to later move to the technical details. We later provide the techniques used to improve the efficiency of the code. Finally, we provide an explanation on how to use the library.

Design
Our solution (https://github.com/xevisalle/zpie, accessed on 12 October 2021) has been designed to provide a clear interface for developing ZKP applications. As such, it provides an API to design circuits, perform the setup phase, generate proofs, and verify them. Furthermore, our solution can easily integrate the verifier in Solidity applications (i.e., using ZoKrates or snarkjs), in order to deploy smart-contracts into the Ethereum network. ZPiE can be used in devices with very low resources like a Raspberry Pi Zero, and in a wide variety of CPU architectures: x86, x86_64, aarch64, and arm32.

Implementation
Our solution has been designed with portability and scalability in mind. For such a reason, we decided to use C to code it, which is still widely used in embedded systems, and allows us full control over the hardware resources. For dealing with big numbers we use GNU GMP (https://gmplib.org/, accessed on 12 October 2021) which is one of the fastest approaches to do operations with large numbers in C. For the group operations over elliptic curves, and pairings, we rely on the MCL library (https://github.com/herumi/mcl, accessed on 12 October 2021) , a well-optimized set of functions that offer us support for all the operations we need to perform. Both GMP and MCL offer support for x86, x86_64, aarch64, and arm32 CPU architectures. Moreover, all the code has been designed to split the workload into threads, to increase the performance especially when the prover is executed in a multicore CPU. Regarding the circuit design, either the circuit parser and the circuit' code developed by the user are coded in pure C, so they are both compiled altogether along with all the other code for maximum performance.

Efficiency
The first step to being able to use our proof system is to generate the CRS through the setup algorithm. Using Groth'16, the setup has a complexity of O(n), so we need to compute a number of elements that depends only on the size of the circuit. Regarding the verifier, where the complexity time is constant (O(1)), he only needs to compute 3 pairings and verify that an equation holds, which is not expensive in terms of power consumption. Plus, the operations which require more power consumption are done by the prover when computing the proof. That is computing the h coefficients, and doing the multi-exponentiations in G 1 and G 2 .

Computing h Coefficients
As stated in Appendix B, we rely on a FFT function to compute the coefficients in O(n log n). Our FFT function has been designed to be as efficient as possible. The size of the domain used for the FFTs in N e = 2 l , where l is a big integer, so |h| = N e . In total, the prover has to perform 3 inverse FFTs over a domain S, 3 FFTs over a shifted domain T, and one last inverse FFT over T. As depicted in Figure 2, this set of operations is, for any number of constraints, the same small percentage of all the operations performed to generate the proof.

Multi-Exponentiations
Our solution uses three different multi-exponentiation approaches: the naive multiexponentiation (which is a serial approach), the multi-exponentiation function provided MCL, and a Bos-Coster multi-exponentiation algorithm (further details provided in Appendix C). While the former achieves the worst results, MCL gets better marks. However, our Bos-Coster implementation achieves the best results. We split the Bos-Coster operations into chunks to increase the performance when using multithreading. As depicted in Figure 2, the multi-exponentiations represent a huge percentage of the operations to be done. In addition, the heap sorting, a step required after each Bos-Coster execution, increases exponentially in terms of global percentage.

Applications
Some of the use cases of ZKPs involve proving to another party that we know the preimage of a hashed value, or that we have a valid signature for a secret message. We implemented both approaches using ZPiE, and provide an API to easily use them.
To use our library, we need to write a circuit which will be parsed later. To do so, Listing 1 shows an example on how to compute the MiMC [34] hash of a preimage x i n. As can be seen, we set a public output h, the hash of the secret preimage x i n (in such a process some randomness k is used as well). In other words, this circuit will compute a proof that, once verified, the verifier will be sure that who computed the proof knows x i n. As can be seen in Listing 2, ZPiE can compute the setup, the proof, and verify it by simply executing each algorithm as shown in the snippet.
In addition, and as shown in Listing 3, ZPiE can easily verify an EdDSA [35] signature by calling the function verify_eddsa(\dots), providing the required parameters as shown in the snippet. In this scenario, the prover is proving to the verifier that he knows a valid signature for some secret message. In such regard, the code can be modified depending on the use case, to select which values are public or secret.

Experiments and Results
In this section, we perform several experiments to prove the efficiency of our solution. In order to do so, we implemented a circuit composed of 16,384 constraints as shown in Listing 4. As stated previously, zk-SNARKs are composed of three algorithms. The setup is performed only once, so the performance of this algorithm is not of big importance in practice. However, using ZPiE, the setup of a circuit of 16,384 constraints can be performed in 17 s using a laptop CPU in single-thread. Regarding the proof verification, our zk-SNARK construction has a succinct verifier which verifies any proof in just 0.0011 s.
Moreover, we performed several experiments to prove the performance of ZPiE when computing proofs. First, we compared our solution with a well-optimized library intended to generate proofs in desktop applications, libsnark. As depicted in Figure 3, ZPiE achieves great results, similar to the ones achieved by libsnark, either in single or multi-thread modes.
Then, as depicted in Figure 4, we executed our solution with different constraint amounts in two different processors, either in single and multi-thread modes. As can be seen, the laptop processor i7-11370H (x86_64) achieves excellent results either in single or multi-thread modes. Regarding the mobile processor Snapdragon 845 (aarch64), the results are still excellent in multi-thread. In single-thread mode, the difference is bigger, yet the proofs can still be executed in a fairly small amount of time. Furthermore, we successfully computed proofs using a Raspberry Pi Zero W, which CPU architecture is ARM6l (arm32) and has a very low clock frequency (700 MHz). As depicted in Figure 5, the results are much higher than using mobile or desktop processors, yet the proofs can still be executed. As such, ZKP applications could be executed in embedded devices, at least when speed is not of paramount importance. For instance, protocols such as SANS, which needs around 5000 constraints, could be executed in less than a minute using a Raspberry Pi Zero W. This allows IoT devices to use privacy-preserving protocols based on zk-SNARKs.

Conclusions
In this paper, we introduced a novel library intended to generate Zero-Knowledge Proofs in devices with low computing resources. After performing several experiments, the results prove how zk-SNARKs can be computed using processors such as the ARM11 of a Raspberry Pi Zero W. After stating the need for privacy-preserving protocols that use zk-SNARKs in IoT scenarios, we demonstrated that their development and execution in such devices is feasible.
ZPiE allows us to develop ZKP applications in embedded devices, by using the specific Groth'16 zk-SNARK. However, we have seen how other schemes exist, each having different features. Implementing other schemes for embedded devices would be an interesting future work to do, in order to expand the uses cases of ZKPs in IoT devices. Overall, being able to use ZKPs in IoT devices should open the door to designing and implementing more protocols for IoT devices based on ZKPs, not solely for authentication purposes but also for any other privacy matter where ZKPs could be useful.
Moreover, even when we get excellent results, there is still room for improvement. It would be interesting to work on boosting even further the performance of ZPiE, by testing other elliptic curve libraries rather than MCL, or by designing new algorithms to reduce the overhead of the executions. Moreover, allowing users to speed up the library using GPUs would be another interesting feature to implement, to allow the usage of our library in scenarios other than IoT devices.

Conflicts of Interest:
The authors declare no conflict of interest.

Abbreviations
The following abbreviations are used in this manuscript:

Appendix B. FFT Techniques for Computing h Coefficients
Our QAP is a 3-matrix set of size N × M. Working on F r , where r is a prime number and the order of the used elliptic curve, we find a generator g for our field. Having this, we find two values k and an extended size for N, called N e = 2 l (where l is an integer 'large enough') such that r = kN e + 1. As can be seen, N e is a power of 2, as 2-addicity is a desirable property for more efficient FFT algorithms. With this, now we can find our N e th primitive root of unity: ω ≡ g k mod r where Lag 1 (z) = z N e − 1 N e Lag j+1 (z) = ωLag j (z) (A8) As such, the setup has defined three polynomials A(x), B(x), C(x). Now, using a solution to our circuit w the prover computes the following values: And we can check: Now, the prover computes the evaluation of three polynomials: Now, the prover will use A(z), B(z), C(z) to compute the coefficients h of H(x): In order to do so, the prover selects a random σ and computes a shifted domain T = {σ, σω, . . . , σω N e −1 }. He also sets Z = σ N e − 1 and does what follows:

Appendix C. Bos-Coster
Let the pairs (s 1 , P 1 ), (s 2 , P 2 ), . . . , (s n , P n ) be the elements of the multi-exponentiations to perform. We sort the list from large to small s i , by means of a well-optimised binary heap. Then, while the list is larger than 1: • (s 1 , P 1 ) = (s 1 − s 2 , P 1 ) • (s 2 , P 2 ) = (s 2 , P 1 + P 2 ) • if s 1 = 0, we remove this pair • We sort the list again When only one pair remains, s 1 P 1 is our solution.