zkay v0.2: Practical Data Privacy for Smart Contracts
Nick Baumann, Samuel Steffen, Benjamin Bichsel, Petar Tsankov, Martin Vechev
zzkay v0.2: Practical Data Privacyfor Smart Contracts
Technical Report
NICK BAUMANN,
ETH Zürich, Switzerland
SAMUEL STEFFEN,
ETH Zürich, Switzerland
BENJAMIN BICHSEL,
ETH Zürich, Switzerland
PETAR TSANKOV,
ETH Zürich, Switzerland
MARTIN VECHEV,
ETH Zürich, Switzerland
BSTRACT
Recent work introduces zkay, a system for specifying and enforcing data privacy in smart contracts. Whilethe original prototype implementation of zkay (v0.1) demonstrates the feasibility of the approach, its proof-of-concept implementation suffers from severe limitations such as insecure encryption and lack of importantlanguage features.In this report, we present zkay v0.2, which addresses its predecessor’s limitations. The new implementationsignificantly improves security, usability, modularity, and performance of the system. In particular, zkay v0.2supports state-of-the-art asymmetric and hybrid encryption, introduces many new language features (such asfunction calls, private control flow, and extended type support), allows for different zk-SNARKs backends, andreduces both compilation time and on-chain costs.
ONTENTS
AbstractContents 1Security Disclaimer 41 Introduction 51.1 An Improved Implementation of zkay 51.2 Terminology 52 Limitations of zkay v0.1 72.1 Security 72.2 Language Fragment 72.3 Usability 72.4 Modularity and Extensibility 82.5 Performance 83 Architecture 93.1 Compiler 93.1.1 Parsing, Analysis and Type Checks 103.1.2 AST Transformation and Abstract Circuit Generation 113.1.3 Transaction Interface Generation 123.1.4 Concrete Circuit Generation and Compilation 133.1.5 Verification Contract Generation 143.2 Transaction Transformation Runtime 153.2.1 Python Contract Interface 153.2.2 Zkay Runtime 163.2.3 Using the Contract Interface 174 New Language Features 184.1 Function Calls 184.1.1 Restrictions 184.1.2 Function Calls not Requiring Verification 184.1.3 Function Calls Requiring Verification 184.2 Cryptocurrency Functionality 204.3 If-Statements 204.3.1 Public Conditions 204.3.2 Private Conditions 214.4 Short-circuit Evaluation 224.5 Public Loops 224.6 Tuples 22 .7 Integer Variants 224.7.1 Integer Sizes 234.7.2 Signed Integers 234.8 Address and Enum Types 234.9 Type Casts 234.10 More Operators 245 Security Features 255.1 Asymmetric Encryption 255.1.1 Public Key Infrastructure 255.1.2 Verifying Encryption 255.1.3 Verifying Decryption 265.1.4 Available Backends 265.1.5 Limitations 275.2 Hybrid Encryption 275.2.1 Public Key Infrastructure 275.2.2 Verifying Encryption 275.2.3 Verifying Decryption 285.2.4 Available Backends 285.3 Default Initialization for Private Variables 295.4 Checking Contract Integrity 296 Performance 316.1 Optimizations 316.1.1 Optimized Input Hashing 316.1.2 Constant Folding 316.1.3 Circuit Input Caching 316.1.4 Public Key Caching 316.1.5 Prover and Verifier Key Caching 326.1.6 Parallelization 326.2 Benchmarks 326.2.1 Compilation Performance 336.2.2 On-chain Gas Costs 346.2.3 Off-chain Transaction Performance 346.2.4 Comparison of Proving Schemes 377 Usability Improvements 397.1 Installation 397.2 Error Messages 39 .3 Contract Distribution 397.4 Configuration Files 397.5 Command-line Interface 39References 41 ECURITY DISCLAIMER
Zkay v0.2 is a research project and its implementation should not be considered secure (e.g., it maycontain bugs and has not undergone any security review)! Do not use zkay v0.2 in a productivesystem or to process sensitive confidential data. Zkay v0.2 is licensed under the MIT license andhence subject to the following disclaimer. The software is provided “as is”, without warranty of any kind, express or implied, including butnot limited to the warranties of merchantability, fitness for a particular purpose and noninfringement.In no event shall the authors or copyright holders be liable for any claim, damages or other liability,whether in an action of contract, tort or otherwise, arising from, out of or in connection with thesoftware or the use or other dealings in the software. https://opensource.org/licenses/MIT 4 INTRODUCTION1.1 An Improved Implementation of zkay
Zkay [31] is a system for specifying and enforcing data privacy in smart contracts. The originalpublication comes with a prototype implementation of zkay [10], which however suffers fromvarious limitations. We refer to this prototype implementation as zkay v0.1 .This technical report presents zkay v0.2 [11], a significantly improved implementation of zkayin terms of security, usability, modularity, and performance. The report describes features andimplementation details of zkay v0.2, and is targeted at both users and developers. It assumes that thereader is familiar with the language and key ideas of zkay according to the original publication [31].In summary, zkay v0.2: ▷ Adds support for state-of-the-art asymmetric and hybrid encryption; ▷ introduces essential language features including function calls, cryptocurrency-related func-tionality, private control flow, extended type support, and many more; ▷ supports different zk-SNARKs backends; ▷ provides a live transaction runtime automatically transforming transactions, computing thenecessary zero-knowledge proofs, and directly interacting with a blockchain; ▷ features various usability improvements such as improved error messages and simplifiedinstallation; and ▷ reduces both compilation time and on-chain costs. We now introduce some terms which are commonly used in this report. ▷ Zkay v0.1 : The proof-of-concept implementation from [10]. ▷ Zkay v0.2 : The new version of zkay [11] described in this report. ▷ Public computation/value : An expression/value whose owner is all . ▷ Private computation/value : An expression/value which is not public. ▷ Public function : A function whose arguments and return values are public, and whose bodyonly contains public computations and calls to public functions. Note that unless explicitlystated otherwise, this does not refer to the visibility modifier of the function. ▷ Private function : A function which is not public. Note that unless explicitly stated otherwise,this does not refer to the visibility modifier of the function. ▷ Internal function call : Calling a contract function from within the same contract. ▷ External function call : Calling a contract function from an external account (i.e., a user or adifferent contract). ▷ On-chain : Execution on the blockchain as part of a smart contract transaction. Increasedon-chain computation results in higher Ethereum gas costs. ▷ Off-chain : Local execution on a machine of a single user. ▷ Non-interactive zero-knowledge (NIZK) proof:
A proof of a statement about secret valueswhich does not leak any information about these values besides their existence [3, 13]. The tatement can be parameterized by public values. A NIZK proof is generated by a prover knowing the secret values, and verified by a verifier . In particular, NIZK proofs can be usedto prove the correct execution of a computation out pub = ϕ ( in pub , in priv ) accepting publicand private inputs in pub resp. in priv , and producing a public result out pub . ▷ Zk-SNARKs : An efficient instantiation of NIZKs [2]. Zk-SNARKS require a trusted setup phase,which generates a common reference string for proof generation and verification. In practice,most proving schemes generate a keypair ( k p , k v ) from a constraint system representingthe proof statement ϕ and secret randomness during the trusted setup phase. The keypair ( k p , k v ) is publicly known: the prover key k p is used to generate proofs for ϕ and arbitraryinputs, while the verification key k v is required to verify such proofs. ▷ Abstract proof circuit : A high-level, NIZK-framework agnostic representation of a proofstatement (the computation ϕ to be proven) internally used by zkay. Such circuits are compiledto framework-specific concrete proof circuits (see below) by different backends. ▷ (Concrete) proof circuit : An arithmetic prime field circuit expressing a proof statement. Acircuit can have multiple input parameters, which can be private or public (see below). Zk-SNARK frameworks such as jsnark [23] generate low-level constraint systems from suchcircuits, which are then used to generate NIZK key pairs and proofs. ▷ Private (circuit) input : Input representing a secret to be hidden from the verifier. Privateinputs are known to the prover. ▷ Public (circuit) input : Input representing public knowledge, which is supplied to verifiers onthe blockchain. LIMITATIONS OF ZKAY V0.1
This section summarizes the main limitations of zkay v0.1 [10]. The key design goal of zkay v0.2 isto address these limitations.
Insecure Encryption.
A major limitation of zkay v0.1 is its lack of secure encryption. In particular,it uses the surrogate encryption function Enc ( v , k ) = v + k to encrypt plaintext v with key k , whichdoes not ensure confidentiality. Zkay v0.1 leverages the ZoKrates framework [5, 32] for NIZKproof generation and verification, which at the time of development did not support more realisticencryption functions. Missing Integrity Verification. zkay v0.1 does not provide tool support for verifying whether thebytecode of a deployed smart contract corresponds to a given zkay contract. Doing this manually ischallenging due to the involvement of multiple contracts (main, library, and verification contracts),and because exactly reproducing the bytecode compilation output requires the same verificationkeys to be used.
Undefined Behavior.
The transaction transformation in zkay v0.1 uses arbitrary-precision integersinstead of emulating the under- and overflow semantics of fixed-sized integers. The user is requiredto ensure the absence of under- and overflows as these may result in security vulnerabilities suchas the possibility of permanently locking the funds of a contract.Additionally, zkay v0.1 assumes that variables are always initialized and does not model thezero-initialization semantics of Solidity. When reading an uninitialized variable, transaction trans-formation in zkay v0.1 may therefore produce an invalid proof. zkay v0.1 only supports a small subset of Solidity as indicated below. This significantly restrictsexpressivity of zkay contracts. ▷ only bool , uint (256-bit unsigned integer) and mapping types; no integer variant, enum , orprivate address types ▷ no user-defined types ▷ no tuples or multiple return values ▷ only basic statements ( require and assignment); no control flow except return at the endof function bodies ▷ only a basic set of operators; no bitwise or shift operators ▷ no function calls ▷ no cryptocurrency features (e.g., transfer and payable ) Transaction Transformation.
Automatic transformation of transactions in zkay v0.1 is very limitedand does involve direct interaction with a blockchain. In particular, the public keys of all involvedparties and the current blockchain state need to be manually provided to zkay together with thetransaction parameters. Issuing the resulting transformed transaction is not part of zkay v0.1 and eeds to be done separately. Overall, issuing a zkay v0.1 transaction is much more complicatedthan issuing a standard Ethereum transaction. Uninterpretable Compiler Errors.
In general, error reporting in zkay v0.1 is very limited and errormessages often only consist of internal stack traces not easily interpretable for users.
No Standardized Contract Distribution. zkay v0.1 does not provide a specification how to distributea zkay contract to its users. Each user of a contract at least needs access to the original zkaysource code and all involved NIZK proving keys, which need to be distributed using off-chaincommunication.
The implementation of zkay v0.1 is not very modular, which impedes extensibility of the tool. Inparticular, the compiler is tightly coupled to ZoKrates [32], making it difficult to integrate otherNIZK frameworks. Additionally, key and cipher text sizes are hard-coded.
Off-chain computation and compilation performance of zkay v0.1 is suboptimal and reducesdevelopment productivity. In particular, compiling a simple contract can take up to several minutes. kay (Python) Transaction RuntimeCompile zkay FrontendParsingAnalysis andType Checks AST TransformationConcrete Circuit Generationand CompilationVerification Contract GenerationTransaction Interface Generationcontract.zkay contract.pycircuit.javacontract.solverifier.solAST zkay jsnark (Java)zkay libsnark (C++)out UserKey Generation outout extends jsnarklibsnarkinvoke keygen input Proving.keyVerifying.keyCommand-lineInterface Command-lineInterface outoutzkay compi l e cont r act . zkayoutout circuit.arithZkayCircuitBaseManifest Generation manifest.jsonoutOff-chain APIContractSimulator extendsusesimports andcallsincorporated intoSolidity Code GenerationAbstract Proof Circuits Fig. 1. Architecture overview and compilation pipeline of zkay v0.2.
This section describes the architecture of zkay v0.2, which consists of a compiler compiling zkay toEthereum contracts (Section 3.1) and a runtime for transaction transformation (Section 3.2). Fig. 1provides an overview of the architecture and the interactions between the different components.
The compiler accepts a zkay contract and produces various output files as described below (seedark green items in Fig. 1). ▷ contract.sol: The main transformed Solidity contract performing on-chain computation (exceptproof verification, see next). This contract is deployed to the blockchain. ▷ verifier.sol: Solidity contracts (one per proof circuit) performing NIZK proof verification on-chain, also deployed to the blockchain. The main contract calls these verification contracts. ▷ Proving.key, Verifying.key:
NIZK proof key pairs (one key pair per verification contract).The prover keys are used by users of the main contract to generate valid NIZK proofs. Theverification keys are integrated into the verification contracts (see previous). ▷ manifest.json: A manifest file storing all zkay compiler settings such that the compiler outputcan be exactly reproduced later. kay Compilerzkay Core Circuit Compilation Backends jsnarkZokrates(removed) Proving Scheme Backends
GM17Groth16
2. Analysis and Type Checks
2. Alias Analysis3. Undefined Behavior Check 4. Privacy Type Check1. Solc Type Check5. Circuit Compatibility Check 6. Loop Check
1. Parsing
1. Parser 2. AST Construction
3. AST Transformation and Abstract Circuit Generation
ContractTransformerDeclarationTransformer StatementTransformerExpressionTransformer CircuitTransformerCircuitHelper
4. Transaction Interface Generation
Python Off-chain Visitor (Transaction Interface Generator)Contract Simulator(Transaction Interface Base Class)
5. Concrete Circuit and Verification Contract Generation
Circuit Generator (Base Class)Proving Scheme (Base Class)1. cipher text size2. asymmetric / hybrid differs slightly in key management and type of encryption constraint added to abstract circuit Slightly different key management for hybrid backendsextends zkay Frontend public zkay API, used by the cli generates verification contracts using extends
Encryption Backends
HybridECDH_AESECDH_ChaskeyAsymmetricDummyRSA_PKCS1.5RSA_OAEP
Fig. 2. Architecture of the zkay compiler and its interaction with different backends.
As indicated in Fig. 1, the compiler first parses the input zkay contract, and performs various typechecks and analyses to ensure the contract’s validity. Next, the compiler transforms the abstractsyntax tree (AST) of the contract to generate Solidity code and abstract proof circuits. These circuitsare then transformed to concrete circuits used as inputs for the zk-SNARKs tools jsnark [23] andlibsnark [24]. After generating NIZK key pairs, the compiler generates the verification contracts.From the transformed AST, the compiler also generates a transaction interface that will later beused together with the transaction runtime. Finally, the compiler also generates a manifest file.Fig. 2 depicts the building blocks realising these phases. The following sections discuss thecompiler phases in more detail.
The input contract is parsed using an extension of the grammar used in zkay v0.1, supporting thenew language features described in Section 4. Then, we run several type checks and analyses onthe constructed AST (see steps 1 and 2 in Fig. 2).
Solc Type Check.
This check ensures that when ignoring all privacy features specific to zkay, thecontract is a valid Solidity contract. It (i) replaces all comments and privacy features in the inputcontract by a matching amount of whitespace, (ii) invokes the solc Solidity compiler via its jsoninterface, and (iii) displays any warnings or errors from solc in the context of the original code. Dueto the whitespace replacement, the source code locations match the locations in the zkay contract.Users can perform the “stripping” of zkay features in isolation using the zkay solify command.This allows easy use of linters and other program analysis tools designed for Solidity.The remaining analyses only have to deal with zkay’s privacy types and features. For example,we don’t need to re-implement Solidities data type checks. lias Analysis. Like in zkay v0.1, the compiler performs alias analysis on the contract to determinereferences which are guaranteed to point to the caller’s address at runtime. This information islater used by the privacy type check. Compared to zkay v0.1, the precision of the alias analysis inzkay v0.2 is slightly more precise. For example, the join operation no longer removes final addressvariables from equivalence sets.
Undefined Behavior Check.
This check ensures that the zkay contract is free of undefined behaviordue to expressions relying on subexpression evaluation order. In particular, the check forbidsexpressions where two subexpressions have side-effects on the same variable, or where a variableis written and read in two different subexpressions.
Privacy Type Check.
Here, the compiler checks zkay’s privacy types as described in [31]. Forinstance, it ensures that no implicit information leaks are possible and that the zkay contract isrealizable using encryption and NIZK proofs. The typing rules of zkay v0.1 have been extended toaccount for the new language features of zkay v0.2 (see Section 4). Circuit compatibility and loopsare analyzed in two separate checks, see below.
Circuit Compatibility Check.
This check ensures that private expressions do not contain privateoperations that are not expressible inside a NIZK proof circuit. Since zkay v0.2 supports functioncalls (see Section 4.1), this involves (i) recursively checking the bodies of any called functions, and(ii) ensuring that the body of any function called within a private expression does not involverecursion or loops. Also, the compiler enforces private expressions to be side-effect free in order tosimplify circuit optimization.
Loop Check.
Finally, the compiler checks that all loops in the contract are fully public, meaningthat no private expressions appear within any loop exit condition or body.
Next, the analyzed AST is transformed to yield abstract proof circuits and Solidity code for themain contract as described below (see Fig. 1 and step 3 in Fig. 2).
AST Transformation.
Zkay v0.2 transforms the AST using an extension of the translation rulesfrom [31] to produce representations of the on-chain computation and proof circuits.
Code Generation.
During code generation, zkay traverses the on-chain computation AST andemits Solidity code. The resulting Solidity file is the main contract to be deployed on the blockchain.Due to the improved modularity, additional target languages can easily be incorporated in zkayv0.2 by adapting the code generator.
Abstract Circuit Generation.
Unlike zkay v0.1, where contract transformation is heavily coupledwith the ZoKrates framework [5, 32], zkay v0.2 constructs framework-agnostic abstract represen-tations of proof circuits from the transformed AST. Such an abstract proof circuit maintains a listof public and private circuit inputs, and holds a sequence of abstract circuit statements from thefollowing list. ▷ Variable Declaration and Assignment:
Assigns the (plaintext) value of a private expression toa new temporary circuit variable. ▷ Guard Condition Modification:
Adds or removes a boolean circuit variable to resp. from theguard condition (see §5.3 in [31] for more information on guard conditions). ontract Test {constructor(uint x ) { // ... }function f (uint@ me val ) { // ... }} Listing 1. Example zkay contract. class
Test ( ContractSimulator ):@staticmethoddef deploy ( x : int , *, account : Addr ) ->
Test : @staticmethoddef connect ( address : Addr , account : Addr ) ->
Test : def f ( val : int ): val = enc ( val , my_pk ) zk_out = [..] = gen_proof ( 'f' , zk_in , zk_out ) transact ( 'f' , val , zk_out , proof ) Listing 2. Generated transaction interface (pseudocode). ▷ Encryption/Decryption Constraint:
An assertion of the form cipher == Enc ( plain , rnd , k ) ,ensuring correct encryption of a plaintext plain using key k and randomness rnd . Suchconstraints are used for private function arguments and whenever the result of a privateexpression is stored to a private variable.An analogous decryption assertion exists, which is used whenever a private variable is readwithin a private expression. ▷ Equality Constraint:
An assertion of the form val == val
2. Such constraints are usedwhenever a private value is declassified. ▷ Function Call:
A pointer to the abstract circuit of a called function. The concrete circuitgenerator (see below) will inline the target circuit at this position.Note that there is no arbitrary assignment statement for proof circuits. Zkay v0.2 relies on staticsingle assignments, using the “Variable Declaration and Assignment” statement. For simplicity, onlythis type of statement can contain arbitrary expressions. All other statements may only referencevariables directly. Therefore, any compound expression is first assigned to a temporary circuitvariable before being used in any of the other statement types.
The transformed AST is further processed to generate a transaction interface for the contract.More specifically, this step generates Python code serving as a user interface to the contract andtransforming transactions by generating NIZK proofs and encrypting function arguments.Listings 1 and 2 show the structure of the generated Python code for an example contract. At a highlevel, zkay creates a Python class which matches the original contract structure, where each methodinternally performs transaction transformation (transaction simulation, argument encryption, proofgeneration) for the corresponding contract function. Users can naturally interact with objects ofthis python class as if they would interact with the contract directly. The generated class makesheavy use of transaction runtime functionality provided by the superclass
ContractSimulator .See Section 3.2.1 for more details.This design has some important advantages over the design of zkay v0.1. Interpretability : The generated Python code can be manually inspected by users to see howtransactions are transformed. ▷ Simplified Debugging : To debug contracts (and also the zkay implementation itself), one canuse standard Python debugging tools. ▷ Improved Performance : Since there is no additional overhead for interpreting zkay code (asdone in zkay v0.1), performance is slightly better.
In this step, abstract proof circuits are compiled to a NIZK-framework-specific concrete circuitrepresentation. Zkay v0.2 uses different circuit compilation backends to target different NIZKframeworks. Each backend must implement zkay’s abstract
CircuitGenerator interface, whichprovides functions for (i) transforming abstract circuits into a backend-specific representation withequivalent semantics, (ii) generating prover and verification keys for a given circuit and provingscheme, and (iii) marshalling generated verification keys into a standard format only depending onthe proving scheme (but not the particular backend).Zkay v0.2 currently supports only one circuit compilation backend, which relies on the jsnarkframework [23] and is described below. The ZoKrates integration from zkay v0.1 has been removeddue to ZoKrates’ lack of cryptographic primitives.
Jsnark Backend.
Jsnark is one of the few currently available frameworks with comprehensivebuilt-in support for cryptographic primitives. In zkay v0.2, a concrete jsnark circuit is representedas a Java subclass of
CircuitGenerator . It uses a Java API (see below) to (i) define public andprivate circuit input wires, and (ii) combine wires using a variety of boolean, arithmetic, and bitwiseoperations. The jsnark backend generates this Java class and executes it to generate an outputfile ( circuit.arith in Fig. 1) in libsnark-specific format. Then, a separate libsnark [24] interfacebinary (see below) is used to generate prover and verification keys for the circuit.
Zkay Jsnark API.
To increase readability and reduce the amount of boilerplate code in thegenerated circuit files, zkay v0.2 implements a higher-level Java API [8] on top of jsnark. Inparticular, the API provides the following items.(i) A custom abstract
CircuitGenerator subclass
ZkayCircuitBase , which includes helperfunctions to define encryption constraints, add circuit inputs with a specific emulated type,and reference input wires by name.(ii) Adapter classes for jsnark’s cryptographic primitive gadgets, which unpack/pack the in-puts/outputs as required for zkay.(iii) A
TypedWire wrapper class, which associates data types to wires and correctly emulates thesemantics of arithmetic overflows, signed operations, etc. (see Section 4.7).As an example, Listing 4 shows the jsnark Java circuit corresponding to the zkay function inListing 3 and making use of the jsnark Java API.
Zkay Libsnark Interface.
The original libsnark interface included in jsnark is not very flexible as ite.g. does not support the GM17 [17] proving scheme. For that reason, zkay v0.2 uses its own customC++ libsnark interface [9], which extends the existing interface with further proving schemes andserialization of verification keys. unction buy (uint amount ) public { require ( registered [ me ]); balance [ me ] = balance [ me ] + amount ;} Listing 3. Example zkay code. public class
ZkayCircuit extends
ZkayCircuitBase {public
ZkayCircuit () {super( "zk__Verify_Token_buy" , "dummy" , 248, 3, 1, 3, true);}private void __zk__buy () { stepIn ( "_zk__buy" ); addS ( "secret0_plain" , 1, ZkUint (256)); addS ( "zk__in0_cipher_R" , 1, ZkUint (256)); addS ( "zk__out0_cipher_R" , 1, ZkUint (256)); addIn ( "zk__in0_cipher" , 1, ZkUint (256)); addIn ( "zk__in1_plain_amount" , 1, ZkUint (256)); addOut ( "zk__out0_cipher" , 1, ZkUint (256)); //[ --- balance[me] + reveal(amount, me) ---// secret0_plain = dec(balance[me]) [zk__in0_cipher]checkDec ( "secret0_plain" , "glob_key_me" , "zk__in0_cipher_R" , "zk__in0_cipher" ); // zk__in1_plain_amount = amountdecl ( "tmp0_plain" , o_ ( get ( "secret0_plain" ), '+' , get ( "zk__in1_plain_amount" ))); // zk__out0_cipher = enc(tmp0_plain, glob_key_me)checkEnc ( "tmp0_plain" , "glob_key_me" , "zk__out0_cipher_R" , "zk__out0_cipher" ); //] --- balance[me] + reveal(amount, me) ---stepOut ();}@Overrideprotected void buildCircuit () {super. buildCircuit (); addK ( "glob_key_me" , 1); __zk__buy ();}public static void main ( String [] args ) { ZkayCircuit circuit = new
ZkayCircuit (); circuit . run ( args );}} Listing 4. Circuit using high-level jsnark Java API.
In this step, zkay generates Solidity contracts performing on-chain NIZK proof verification. As theformat of such verification contracts depends on the used proving scheme, zkay v0.2 uses different proving scheme backends for this task. Each backend implements the abstract
ProvingScheme interface and is responsible for (i) defining a verification key data structure, and (ii) generatingverification contracts for a given verification key and list of public circuit inputs. Zkay v0.2 providesbackends for two proving schemes: GM17 [17], which is already used by zkay v0.1, and the moreefficient Groth16 [16] scheme (default in zkay v0.2).In contrast to zkay v0.1, where verification contracts are directly generated by ZoKrates, theproving scheme backends in zkay v0.2 have full control over the verification contracts and canapply specific optimizations such as loop unrolling, avoiding unnecessary copy operations, andhashing optimizations (see Section 6.1.1). .2 Transaction Transformation Runtime The second core component of zkay v0.2 is a transaction runtime which transforms functioncalls and executes them on the blockchain. It consists of two parts: the Python contract interfacegenerated by the compiler (see Section 3.2.1) and the actual runtime providing core functionalityvia an API (see Section 3.2.2). In Section 3.2.3, we describe how users can interact with a zkaycontract using its Python interface, either programmatically or via an interactive shell.
The Python contract interface ( contract.py in Fig. 1) transforms and forwards function calls tothe Solidity contract deployed on the blockchain ( contract.sol ). Its goal is to prepare encryptedfunction arguments and generate NIZK proofs to be accepted by the verifier contracts. Becausethese generally depend on blockchain state and the results of public or private operations in thezkay contract, the interface needs to simulate the execution of the zkay contract in Python.For many simple operations, the compiler simply emits the transformed AST as equivalentPython code. However, the contract interface also performs more complex operations as describedbelow, often leveraging the zkay runtime API (see Section 3.2.2). ▷ To make transaction transformation transparent to users, the signature of each externalfunction matches the original zkay function. Its body encrypts private arguments and addstheir plaintext values to the secret circuit arguments. At the beginning of the function, the msg , block and tx objects are populated with current blockchain data using the runtime API. ▷ At the end of each external function that requires verification, the interface uses the runtimeAPI to generate a NIZK proof for the collected circuit arguments. Then, the transformedtransaction is issued using the runtime API. ▷ Parameter or function names conflicting with Python keywords or other reserved names aresanitized by adding a special suffix that is prevented to be used in user code. ▷ Key lookups in the PKI are replaced by a runtime API call retrieving the requested key fromthe blockchain state. ▷ The values of state variables are lazily retrieved from the blockchain and cached for repeatedaccess. Each state variable reference is replaced by an index operation into a dedicated statedictionary that requests the value from the blockchain (via the runtime API) if it is not cached. ▷ Due to the missing support for nested local scopes in Python, zkay v0.2 uses context managersand a special local variable dictionary aware of scoping (provided by the runtime API) toemulate nested block scopes. ▷ Whenever a private circuit value is included in the circuit inputs, it is immediately decrypted(using the runtime API) and its plaintext value is added to the secret circuit arguments. ▷ For each private expression, the simulator computes the expression’s output value, encrypts it(using the runtime API) if required, and stores it in the corresponding circuit output variable. ▷ Each require statement is replaced by an if-statement raising a
RequireException if thecondition does not hold. ▷ For all arithmetic operations and type casts, correct over-/underflow behavior is emulatedusing the runtime API (see Section 4.7 for details). ▷ Two additional static methods connect and deploy are added to the contract interface. Thefunction connect verifies the integrity of the remote Solidity contract at the specified address kay Transaction Runtimezkay Core Prover Backends jsnarkZokrates(removed)User Crypto Backends
HybridECDH_AESECDH_ChaskeyAsymmetricDummyRSA_PKCS1.5RSA_OAEP Contract.py(Transaction Interface)Contract Simulator(Base Class) extendsRuntimecommunicateKeystore Interactive Shell 1. exec "circuit.java prove
Blockchain Backends w3-eth-tester w3-ganacheWeb3 (Ethereum)w3-http w3-websocketw3-ipcWeb3Blockchain(Base Class) Proving.key Contract.sol zkay Compilation Output
Local Ethereum Nodecircuit.in producesproof.out producesused byCircuit.java extends deploys and interacts withEthereum Blockchain zkay jsnarkzkay libsnark used bygenerate / load keysannounce / request key
Fig. 3. Architecture of the zkay transaction runtime. (see Section 5.4) and creates a Python interface for it. The function deploy calls the contractconstructor, which results in a deployment transaction. See Section 3.2.3 for details.
The interface contract.py extends the base class
ContractSimulator , which provides access tothe zkay runtime API and maintains the transaction simulation’s internal state. The API providescore functionality such as access to local and state variables, type casting and under-/overflow em-ulation, blockchain interaction, cryptographic operations, and key management (see Section 3.2.1).Fig. 3 shows an overview of the transaction runtime architecture. Zkay v0.2 supports differentencryption schemes, which are realized using different crypto backends . To generate NIZK proofs,the runtime further uses a prover backend . The runtime can interact with a variety of Ethereumblockchain interfaces, which are exposed to the runtime as blockchain backends . We next describethese backends.
Crypto backends.
These backends implement key generation, encryption and decryption opera-tions for different encryption schemes. Zkay v0.2 includes 5 crypto backends: “dummy encryption”(the insecure surrogate encryption function used in zkay v0.1), RSA with either PKCS1.5 ([26],section 7.2) or OAEP ([26], section 7.1), as well as ECDH [4, 22, 25] in combination with AES [14]or Chaskey LTS [27] block ciphers. See Section 5 for details. rover backends. A prover backend is responsible for generating NIZK proofs for a given circuitand input values. Zkay v0.2 supports only one prover backend, which is based on jsnark. Toconstruct a NIZK proof, the jsnark backend first executes the Java circuit ( circuit.java in Fig. 3)produced by the jsnark circuit generator in proof generation mode to create a jsnark input file( circuit.in ). This input file is then passed to the libsnark interface, which performs the actualproof generation.
Blockchain backends.
These backends connect zkay with different Ethereum blockchain interfaces.They implement contract deployment, transactions, state queries (e.g., state variable and accountbalance queries), and integrity checks (see Section 5.4). All five currently supported blockchainbackends are based on web3py [19]. The w3-eth-tester [12] and w3-ganache [18] backends areused for testing with local blockchains, while the remaining backends are used to connect zkaywith real Ethereum nodes over IPC, HTTP, or WebSocket. For security reasons, zkay prevents usingdummy encryption for non-local blockchains.
Users can use the deploy and connect commands of zkay’s command-line interface to easily createand interact with zkay v0.2 contracts. Using deploy , a user can deploy a zkay contract to theconfigured Ethereum blockchain. Then, an instance of the contract interface can be obtained usingthe connect command. When running this command, zkay enters an interactive shell in the contextof the created interface object, which allows users to issue transactions in an interactive manner.All external contract functions are available with identical signature as in the zkay contract. Whencalling any such function, zkay v0.2 transparently transforms the transaction (see Section 3.2.1)and issues it on the configured Ethereum blockchain.The deploy and connect functions can also be accessed using the programmatic interface inthe module zkay.zkay_frontend . NEW LANGUAGE FEATURES
In this section, we describe the new language features introduced in zkay v0.2.
As a major extension of zkay v0.1, zkay v0.2 supports internal function calls.
Expressions with side-effects (e.g., an expression modifying a state variable) cannot be moved to theproof circuit. Inside private expressions (i.e., if there exists a non-public ancestor in the expressiontree), zkay v0.2 hence enforces called functions to be annotated as pure or view .In general, calls to functions with private return value are inlined in the proof circuit if they occurwithin a private expression. As a result, the called function bodies may not contain any operationsunsupported in the proof circuit (such as loops or recursive function calls). This is enforced by thetype system of zkay v0.2. In contrast, calls to functions with public return value are generally notintegrated in the proof circuit. If such a function call appears inside a private expression, the returnvalue is computed on-chain and passed to the proof circuit as a public input. There are two cases where an internal function call does not require any verification, namely if(i) the function is fully public, or (ii) the only private expressions in the function are its privatearguments. There are no restrictions on such function calls, as they are not transformed by zkayv0.2 in any way.
Internal function calls outside private expressions require verification if the called function containsprivate expressions beyond any private arguments. In general, there are two ways to ensure thatthe required proof circuit is included in a NIZK proof and verified:(i)
Callee-driven . Here, the callee is responsible for verifying the proof circuit induced by its ownbody, excluding nested function calls. With each nested function call, an additional NIZKproof is introduced that has to be tunneled through the caller.(ii)
Caller-driven . Here, the caller is responsible for verifying the proof circuit induced by any transitively called function. In this case, the external top-level function performs verificationof a single large proof circuit combined from smaller sub-circuits induced by nested functioncalls. Only a single NIZK proof is introduced per external function.As the gas cost for verifying a NIZK proof on the blockchain is virtually independent of the proofcircuit size (see Section 6.1.1), option (ii), which induces less proof verifications, is more efficient.Accordingly, zkay v0.2 follows the caller-driven approach. For this approach, the following itemshave to be considered. Case (ii) particularly applies to a function that merely stores the value of its private argument in a state variable. Whilecalls to such functions require verification when being called externally (the correct encryption of private user-providedarguments is checked in the proof circuit), this is not the case for internal calls.18 i r cui t I nput Ar r ayMemor y Layoutf ( )g( ) 1.h( )1. p( )2. f I nput sg I nput sh I nput sp I nput s ent er f :i n_i dx@f = 0ent er g:i n_i dx@g = i n_i dx@f + si ze( f )ent er h:i n_i dx@h = i n_i dx@g + si ze( g)ent er p af t er g:i n_i dx@p = i n_i dx@f + si ze( f ) + t r ans_si ze( g)
Fig. 4. Memory layout of proof circuit input array. ▷ For each external function, the compiler needs to statically determine all transitively called in-ternal functions and construct the required proof circuit. For this to work, the type system hasto guarantee the absence of recursive calls and function calls within loops (see Section 3.1.1). ▷ External functions need access to the public proof circuit inputs and outputs for all transitivelycalled internal functions. ▷ Each internally called function needs access to its own circuit outputs. ▷ Verifying correct encryption of private function parameters is required if and only if thefunction is called externally. In all other cases (internal or private functions), the functioncan rely on the fact that its arguments have already been verified by the caller.
Circuit Input and Output Arrays.
In order to manage public circuit inputs, zkay v0.2 uses alarge dynamic array shared by transitively called functions. This array is (implicitly) divided into ahierarchy of sections according to the tree of nested function calls. Each section stores the function’sown circuit inputs as well as the sections of all called functions. An analogous second array is usedfor circuit outputs.Fig. 4 visualizes the input array memory layout for an example call tree. Here, function f is calledexternally and calls functions g and p in its function body. Functions with Private or Internal Visibility Modifier.
These functions cannot be called externally.Zkay v0.2 adds four parameters to the signature of such functions: dynamic arrays in and out usedto propagate circuit inputs (resp. outputs) along the call tree, and two integer indices in_idx and out_idx used to indicate the section start offsets for the current function.The indices in_idx and out_idx act as relocation base addresses and are set by the caller of thefunction. The transformed Solidity code accesses entries of the in and out array relative to theseoffsets, which makes it possible to use the same function definition independently of the function’slocation in the call tree.To work around Solidity’s stack size limit and lack of array slice operators, the circuit outputs aredeserialized from the out array into a struct at the beginning of the function body. Analogously, thepublic circuit inputs are serialized from a struct into the in array before the function returns. Withinthe function body, all circuit outputs resp. inputs are read from resp. stored into the correspondingstruct. unctions with Public Visibility Modifier. Functions with public visibility modifier may be calledboth internally and externally. Hence, these are split into two functions during compilation. ▷ An internal function, which is simply a copy of the original function transformed as anyother internal function (see above). ▷ An external function with two additional parameters proof and out , allowing the user topass a NIZK proof and a circuit output array according to the memory layout described above.The body of the external function performs the following steps.(i) Allocate an array large enough to store the circuit inputs of all transitively calledfunctions.(ii) Request all encryption keys required by any transitively called function from the PKIcontract.(iii) Store all encrypted parameters in the circuit input array (the correct encryption of theseparameters will be verified).(iv) Call the corresponding internal function (see above), passing the in and out arrays withinitial indices. The called function will populate the in array.(v) Invoke the NIZK proof verifier for proof , in and out . Incorporating Circuits of Nested Calls.
The zkay compiler generates a separate abstract proof circuit(see Section 3.1.2) for each function definition. Abstract proof circuits use a special
CircuitCall statement to include (sub-)circuits of nested function calls. The circuit compilation backend (seeSection 3.1.4) is then responsible for inlining the sub-circuits into the main top-level proof circuit,respecting the memory layout of the in and out arrays. Example.
Figure 5 demonstrates how zkay v0.2 complies function calls to Solidity. To removeclutter, range checks are omitted and a Python-style slicing syntax is used to indicate array ranges.
Zkay v0.2 allows functions to be declared payable . Further, it supports address types (see Section 4.8)and querying the balance of an address using the member function balance . Outside privateexpressions, payable addresses can be used to transfer funds using the member functions send and transfer .Further, zkay v0.2 provides access to the msg (only sender and value ), block , and tx globals.During transaction simulation (see Section 3.2), they are represented as Python objects, which arepopulated by the blockchain backend. Zkay v0.2 supports control-flow using if-statements, both with public and private conditions.
Zkay v0.2 adds support for if-statements with public conditions and makes use of guard conditionsas introduced in [31]: if any of the branches contains private expressions, an appropriate guardcondition is added to all proof circuit constraints generated for that branch. ol i di t y Out putZkay Code f unct i on f ( ui nt @me x) publ i c {g( x) ;}f unct i on g( ui nt @me x) i nt er nal {x++;} f unct i on f ( ui nt [ ci pher _sz] x, ui nt [ ] out , ui nt [ pr oof _sz] pr oof ) ext er nal {r equi r e( out . l engt h == ci pher _sz) ;/ / Cr eat e i n ar r ay f or al l t r ansi t i ve ci r cui t i nput sui nt [ ] i n = new ui nt [ ci pher _sz + ci pher _sz] ; / / i nput si ze _f + i nput si ze g/ / Request r equi r ed publ i c keysi n[ 0] = Pki Cont r act . get Pk( msg. sender ) ;/ / Add ext er nal ar gument s t o ci r cui t i nput s ( si nce cor r ect encr ypt i on must be pr oven)i n[ 1: ( 1 + ci pher _sz) ] = x[ : ] ;/ / Cal l i nt er nal f unct i on_f ( x, i n, 1 + ci pher _sz, out , 0) ;/ / Ver i f y pr oofVer i f yCont r act . ver i f y( pr oof , i n, out )}st r uct dat a_g {ui nt [ ci pher _sz] out 0_ci pher ;ui nt [ ci pher _sz] i n0_ci pher _x;}f unct i on g( ui nt [ ci pher _sz] x, ui nt [ ] i n, ui nt i n_i dx, ui nt [ ] out , ui nt out _i dx) i nt er nal {dat a_g dat a;/ / Deser i al i ze Out put sdat a. out 0_ci pher [ : ] = out [ out _i dx: ( out _i dx + ci pher _sz) ] ; / / == enc( x + 1)/ / x++dat a. i n1_ci pher _x = x;x = dat a. out 0_ci pher ;/ / Ser i al i ze i nput si n[ i n_i dx: ( i n_i dx + ci pher _sz) ] = dat a. i n0_ci pher _x[ : ] ;}f unct i on _f ( ui nt [ ci pher _sz] x, ui nt [ ] i n, ui nt i n_i dx, ui nt [ ] out , ui nt out _i dx) i nt er nal {g( x, i n, i n_i dx + 0, out , out _i dx + 0) ;}f unct i on h( ) i nt er nal {f ( 1) ; / / i nt er nal cal l t o f} st r uct dat a_h {ui nt [ ci pher _sz] out 0_ci pher ;}f unct i on h( ui nt [ ] i n, ui nt i n_i dx, ui nt [ ] out , ui nt out _i dx) i nt er nal {dat a_h dat a;/ / Deser i al i ze Out put sdat a. out 0_ci pher [ : ] = out [ out _i dx: ( out _i dx + ci pher _sz) ] ; / / == enc( 1) _f ( dat a. out 0_ci pher , i n i n_i dx, out , out _i dx + ci pher _sz) ;}cr eat e ext er nal ver i f i cat i on wr apper Fig. 5. Simplified example of compiling nested function calls to Solidity. uint p = ...;uint@ me o ;if ( p == 2) { o = 3;} o = o + 1; Listing 5. If-condition in zkay. uint p = ...;uint[ cipher_sz ] o ; // proof circuit: in[0] = ( p == 2); // guard = in[0] if (in[0]) { o = out [0]; // assert guard => (enc(3) == out[0]) }in[1:] = o ; // tmp = in[0] + 1o = out [1]; // assert enc(tmp) == out[1] Listing 6. Transformed code (simplified).
For example, consider the zkay code in Listing 5. Its transformed version and generated proofcircuit are shown in Listing 6. Using the implication guard => (enc(3) == out[0]) for theassertion ensures that the condition enc(3) == out[0] is only checked in the proof circuit if theguard condition p == 2 is true.
If-statements with private conditions are supported, however with some restrictions making surethat the visible trace of a transaction does not leak any information about the value of the condition.In particular, no branch is allowed to contain operations unsupported in proof circuits or anyside-effects apart from assignments to primitive type variables which are private to the caller. kay first collects the set X of all variables which are assigned in at least one branch. Then, itreplaces the if-condition by an assignment to all variables in X . The correctness of the right-handside is verified in the proof circuit, which (i) evaluates both branches of the if-statement, and (ii) usesconditional assignment expressions to select the appropriate values for the variables in X accordingto the value of the condition. In particular, all variables in X get assigned new re-encrypted values,even if the underlying plaintext values were not modified in the branch taken. Certain operators such as || and && are subject to short-circuit evaluation in Solidity (i.e., notall operands are necessarily evaluated). Zkay v0.2 correctly handles this using appropriate guardconditions in the proof circuits.For example, consider the zkay code in Listing 7, where the function call priv() is skipped if b is true due to short-circuit evaluation. When creating the proof circuit for test , zkay adds a guardcondition to the encryption assertion in priv to make sure it is only checked if b is false. function priv () returns(bool) {uint@ me v = 2; // encryption assertion is only checked in the proof circuit if !b return true;}function test (bool b ) {bool val = b || priv ();} Listing 7. Guard condition necessary due to short-circuit evaluation.
Zkay v0.2 supports while , do ... while and for loops whose condition, update statement and bodydo not contain any private expressions or calls to functions requiring verification (see Section 4.1). Zkay v0.2 supports Solidity tuples. This can e.g. be used to pack multiple return values or swapvariables. Nesting and mixing values with different privacy types is supported. As a tuple is only asyntactic group, it does not have a privacy type itself.
Zkay v0.2 provides advanced support for integer variants, including fixed-sized (see Section 4.7.1)and signed (see Section 4.7.2) integers.The zk-SNARKs frameworks underlying the circuit compilation backends require all proofcircuit operations to be expressed using finite arithmetic in a prime field. Prime field numbers areinherently unsigned and restricted in size by the field prime. For instance, the field prime involvedin the elliptic Barreto-Naehrig curve “alt_bn128” used in libsnark is roughly 253.5 bits in size, https://github.com/scipr-lab/libff/tree/master/libff/algebra/curves/alt_bn128 (accessed 2020-08-25).22 aking it impossible to accurately represent 256-bit operations. Directly translating Solidity uint operations to operations in the prime field (as done in zkay v0.1) is hence incorrect.Zkay v0.2 correctly emulates the semantics of different integer variants (e.g., signed arithmetic,under- and overflow behavior) in the used prime field whenever possible. Otherwise, compilererrors or warnings are raised. Like Solidity, zkay v0.2 supports different integer sizes (i.e., uint8 , uint16 , ..., uint248 , uint256 ). Up to 248 bits.
For sizes up to 248 bits, the jsnark circuit compilation backend emulates correctoverflow behavior using the low-level finite field operation primitives provided by jsnark. ▷ Addition
Emulated by restricting the field addition output (which can have at most 249 bitsand hence does not overflow at the field prime) to the desired bit width. ▷ Negation : Emulated by constructing the “two’s complement”, see Section 4.7.2. ▷ Subtraction : Emulated by adding the negated value. ▷ Multiplication : The result of multiplying two n -bit integers can have up to 2 n bits, whichmeans that a field prime overflow can already occur when multiplying integers with aslittle as n ≥
128 bits. For this reason, multiplication of ( n ≥ n -bit multiplications, whose results do not overflow.
256 bits.
Zkay v0.2 uses a single prime field element to represent 256-bit integers, even thoughthis leads to a semantic mismatch between prime field and Solidity operations. In particular:(i) all private arithmetic operations overflow at the field prime, and(ii) private comparison operations fail for values ≥ .Because private 256-bit operations are safe as long as they only involve values below 2 , zkayv0.2 does not generally forbid such operations. Instead, it raises an according compiler warning tomake developers aware of potential issues. Zkay v0.2 uses the “two’s complement” representation for signed integers and correctly emulatessigned integer arithmetic for at most 248 bits. Private 256-bit signed integers are not supported.
Zkay v0.2 supports address and address payable variables, both of which can be private.Cryptocurrency-related members such as balance (see Section 4.2) are only accessible on publicaddresses.Further, zkay v0.2 supports declaring and using custom enum types. These are fully supportedinside private expressions.
Like Solidity, zkay v0.2 allows explicit type conversions between many primitive types. Also, zkayv0.2 reflects the implicit type conversions of Solidity (e.g., conversions from smaller to larger integer izes). Type casts are valid operations inside private expressions. The privacy type of a type castexpression is inherited from its source expression. Assignment Operators.
Zkay v0.2 introduces assignment operators such as += and *= . These aresyntactic sugar and can only appear as statements (i.e., they are not expressions). One notableexception are loop update expressions, where assignment operators can be used for convenience.
Pre- and Post-increments.
Zkay v0.2 supports ++ and -- as prefix or postfix operators. Similarly asassignment operators, pre- and post-increments are statements and cannot be used as expressions,except for loop update expressions. Bitwise Operators.
The bitwise operators & , | , ~ and ^ are supported by zkay v0.2, except forprivate 256-bit integers. Shifts.
The shift operators << and >> are supported by zkay v0.2, except for private 256-bitintegers. For public operands, there are no further restrictions. When shifting private values, theshift amount must be a public constant. Because of Solidity’s unspecified expression evaluation order, treating assignment operators as expressions would lead tounspecified behavior and side-effects. 24 unction f (uint val ) {uint@ other x = val ;} Listing 8. Example zkay code. function f (uint val , Cipher c , proof ) {uint m = val ; Key pk = PKI . get ( other ); Cipher x = c ; // c == enc(val)verify ([ m , pk ], [ c ], proof );} Listing 9. Transformed Solidity code. def f ( val ): m = valpk = request_key ( other ) c , rnd = enc ( m , pk ) x = cproof = prove_f ([ rnd ], [ m , pk ], [ c ]) transact ( 'f' , [ val , c , proof ]) Listing 10. Python contract interface. priv_in : rndpub_in : m, pkpub_out : cproof :- assert c == enc(m, pk, rnd) Listing 11. Proof circuit (pseudocode).Fig. 6. Verifying correct encryption for an asymmetric encryption backend.
In this section, we present the security features of zkay v0.2. In particular, we show how zkayemploys asymmetric (Section 5.1) and hybrid (Section 5.2) encryption to protect private data, andhow private variables are initialized in this context (Section 5.3). Further, we describe how zkaychecks the integrity of deployed contracts (Section 5.4).
Zkay v0.2 supports asymmetric encryption, where data is encrypted under the owner’s public key.
Each user account a creates an asymmetric key pair ( sk a , pk a ) , whose public part pk a is publishedto a dedicated zkay public key infrastructure (PKI) contract. Whenever a compiled zkay contractrequires the public key of an address, it requests the key from the PKI contract. Often, a compiled zkay contract needs to verify that some plaintext m was correctly encrypted forsome target address a . More specifically, for a given ciphertext c , the contract must ensure that c was obtained by encrypting the plaintext m with a ’s public key pk a and some secret randomness r .Fig. 6 exemplifies how zkay v0.2 verifies correctness of encryption for an asymmetric encryptionbackend. The code in Listing 8 is compiled to the Solidity code in Listing 9, which verifies that c isthe result of encrypting val under the public key of other and some secret randomness rnd . Thisis captured in the proof circuit shown in Listing 11, which takes public circuit inputs m and pk , theprivate circuit input rnd , and returns the (public) output c . unction f () {uint@ me val ;uint x = reveal ( val , all );} Listing 12. Example zkay code. function f (uint m , Proof proof ) {
Cipher val ; Cipher c = val ; Key pk = PKI . get ( msg.sender );uint x = m ; verify ([ c , pk ], [ m ], proof );} Listing 13. Transformed Solidity code. def f (): val = Cipher () c = valpk = request_key ( msg . sender ) m , rnd = dec ( val , get_sk ( msg . sender )) x = mproof = prove_f ([ rnd ], [ c , pk ], [ m ]) transact ( 'f' , [ m , proof ]) Listing 14. Python contract interface. priv_in : rndpub_in : c, pkpub_out : mproof :- assert c == enc(m, pk, rnd) Listing 15. Proof circuit (pseudocode).Fig. 7. Verifying correct decryption for an asymmetric encryption backend.
Whenever a private variable c is used in a private expression e , the value of c must be decrypted toits plaintext value m by the contract interface to allow local computation of the (plaintext) valueof e . The correctness of this decryption operation is checked in the proof circuit.For many asymmetric encryption schemes, decryption is more expensive than encryption. Hence,zkay v0.2 checks correctness using the inverse encryption operation in the proof circuit. Morespecifically, it checks whether the value of c can be obtained by encrypting the plaintext m withthe owner’s public key and some secret randomness. This is exemplified in Fig. 7. Zkay v0.2 supports two asymmetric crypto backends described below, both of which are basedon RSA [30]. The backends rely on PyCryptodome’s [29] RSA implementation for the contractinterfaces, and jsnark’s RSA gadges for the proof circuits.
RSA PKCS1.5.
This backend uses RSA encryption with PKCS
RSA OAEP.
This backend uses RSA encryption with PKCS .1.5 Limitations RSA crypto backends come with some efficiency drawbacks (see Section 6.2 for an experimentalevaluation). In particular: ▷ RSA requires large key and cipher text sizes. In particular, these items have at least 2048 bits,which amounts to 9 proof circuit inputs. As the cost for NIZK proof verification is linear inthe number of public proof circuit inputs, this leads to high gas costs. ▷ RSA encryption, particularly with OAEP, is a very expensive operation in the proof circuit.This leads to high memory consumption and long execution times for proof generation.For these reasons, zkay v0.2 also offers hybrid encryption as described in the next section.
Zkay v0.2 supports hybrid encryption, where an elliptic curve (EC) key exchange is used incombination with a symmetric block cipher. At a high level, hybrid encryption in zkay v0.2 worksas follows. ▷ Each account a creates an asymmetric EC key pair ( sk a , pk a ) , whose public part pk a ispublished in the PKI. ▷ Whenever an account a wants to encrypt data for a target account b , it uses elliptic curveDiffie-Hellman (ECDH) [4, 22, 25] to obtain a shared secret from sk a and pk b . From thisshared secret, a shared symmetric key k a , b = k b , a is derived. ▷ Account a then uses a symmetric block cipher to encrypt the plaintext using key k a , b andobtain the ciphertext c , which includes an initialization vector (IV). The ciphertext is extendedby the public key of a to obtain the tuple ( c , pk a ) , which is stored on the blockchain. ▷ When decrypting a ciphertext tuple ( c , pk a ) , account b uses ECDH to obtain k a , b from sk b and the public key pk a in the tuple. Then, b can decrypt c using k a , b . The PKI for hybrid encryption works analogously as for asymmetric encryption (see Section 5.1.1).EC keys are much smaller than RSA keys for equivalent levels of security. In particular, for theelliptic curve supported by jsnark, a strong EC key equivalent to a 2048-bit RSA key fits within asingle proof circuit input.
When verifying that a ciphertext tuple ( c , pk a ) is the result of encrypting a plaintext m for a targetaddress b , the compiled zkay contract must ensure that (i) c was obtained by encrypting m with thekey k a , b derived from pk b and some secret key sk a , and (ii) pk a and sk a form an EC key pair.Fig. 8 exemplifies how zkay v0.2 verifies correctness of encryption for a hybrid encryptionbackend. The Solidity code in Listing 17 verifies that c is the result of encrypting val for theaccount other . In particular, it sets the public key for c to the public key of the sender, loads thepublic key of other , and calls the verifier. The proof circuit shown in Listing 19 takes as publicarguments the public key pk_me of the sender, the plaintext m , and the public key pk of other . Asa private argument, it takes the secret key sk_me of the sender. The circuit (i) asserts that pk_me Technically, the implementation uses a uint[3] array to combine the IV, actual cipher text c and public key pk a of theoriginator a instead of a ciphertext tuple ( c , pk a ) . 27 unction f (uint val ) {uint@ other x = val ;} Listing 16. Example zkay code. function f (uint val , IvCipher c , proof ) { Key pk_me = PKI . get ( msg.sender ); c . src = pk_me ;uint m = val ; Key pk = PKI . get ( other ); IvCipher x = c ; // c == enc(val)verify ([ pk_me , m , pk ], [ c ], proof );} Listing 17. Transformed Solidity code. def f ( val ): pk_me = request_key ( msg . sender ) sk_me = get_sk ( msg . sender ) m = valpk = request_key ( other ) iv_c = enc ( m , ecdh ( pk , sk_me )) x = iv_cproof = prove_f ([ sk_me ], [ pk_me , m , pk ], [ iv_c ]) transact ( 'f' , [ val , iv_c , proof ]) Listing 18. Python contract interface. priv_in : sk_mepub_in : pk_me, m, pkpub_out : iv_cproof :- - assert pk_me == G · sk_me- - k = ECDH(sk_me, pk) - - iv = iv_c[:128] Listing 19. Proof circuit (pseudocode).Fig. 8. Verifying correct encryption for a hybrid encryption backend. and sk_me form an EC key pair, (ii) constructs the symmetric key k shared between the sender and other using ECDH, and (iii) asserts c has been encrypted correctly. Like for asymmetric encryption (see Section 5.1.3), zkay proves correct decryption using an en-cryption operation in the proof circuit. Verifying decryption works similarly as for encryption (seeFig. 8), however the shared encryption key is derived from the originator’s public key stored aspart of the ciphertext.
Zkay v0.2 supports two hybrid crypto backends described below. The shared key is derived from theECDH shared secret by taking the 128 leftmost bits of its SHA-256 digest [15]. As an optimization,shared keys are only computed once per proof circuit.
ECDH AES.
This backend combines SHA-256-ECDH key derivation with AES-128 [14] encryptionin CBC mode [6]. The implementation relies on PyCryptodome’s AES-CBC implementation andjsnark’s CBC, AES and ECDH gadgets. CDH Chaskey.
This backend is a more lightweight alternative to ECDH AES. It uses the ChaskeyLTS block cipher [27], which is natively supported by jsnark and allows for more efficient proofcircuits than AES. The implementation relies on jsnark’s CBC, Chaskey and ECDH gadgets. Thecontract interface combines BouncyCastle’s [28] CBC mode with a custom Chaskey LTS blockcipher implementation.
In Solidity, variables are implicitly initialized with zero-equivalent values (e.g., reading an uninitial-ized integer variable is guaranteed to return zero). While this is a useful feature often leveraged bySolidity contracts, it is an issue for compiled zkay contracts, where private variables would have tobe implicity initialized with the encryption of zero . For this reason, zkay v0.1 restricts support fordefault initialization and has undefined behavior when reading uninitialized private variables.Zkay v0.2 adds support for zero-initialized private variables. The general idea is to rely onSolidity’s initialization but treat private variables with values zero as if they were encrypted. Morespecifically, proof circuit assertions of the form cipher = enc ( plain , k ) are actually implemented as ( cipher = ⇒ plain = )∧( cipher (cid:44) ⇒ cipher = enc ( plain , k )) . Also, decrypting the ciphertext 0in the contract interface is configured to return the plaintext 0. Finally, an additional constraintasserting that user-provided ciphertexts are never 0 is included in proof circuits. In the extremelyunlikely event that encrypting a plaintext in the contract interface leads to the ciphertext 0, theplaintext is re-encrypted using fresh randomness. In order to interact with a compiled zkay contract deployed on the blockchain, a user needs accessto the following items: (i) the original zkay contract, (ii) the NIZK prover and verifier keys, and(iii) the manifest file specifying the originally used compiler version and options. These itemsprovide enough information to locally reconstruct the contract interface. Zkay v0.2 comes withutilities to bundle these items in an archive that can be distributed to and imported by users via anout-of-band channel.
Integrity of Remote Contracts.
When using a deployed contract, users need to verify that itcorresponds to the local archive they have obtained via an out-of-band channel. This is, the remoteEVM bytecode must be verified to match the result of compiling (i) using (ii–iii).Zkay v0.2 automatically performs this verification whenever the Python contract interface isattached to a remote contract C by the connect command (see Section 3.2.3). In particular, itperforms the following steps.(i) Zkay compiles the local zkay contract using the compiler settings in the manifest file and aspecial mode that uses the existing prover and verifier keys instead of re-generating them.The compiler outputs the transformed Solidity contract C local , all verification contracts, thePKI contract, and any required library contracts.(ii) The addresses of the remote PKI, library and verification contracts as used by the remotecontract are retrieved from bytecode.(iii) The PKI and verifier address placeholders in C local are replaced with the concrete addressesof the corresponding remote contracts obtained in the previous step. Similarly, the remotelibrary addresses are linked to the local verification contracts. iv) C local and all locally generated verification contracts, PKI contract, and library contracts arecompiled with solc using the compiler settings in the manifest file.(v) The bytecode of C , the remote PKI, library and verification contracts is compared to thecompilation results from the previous step. If the bytecode is not equal, zkay raises an errorand aborts the connection. Trusted Setup Phase.
Like in any NIKZ-proof framework based on zk-SNARKs, prover and verifierkey generation in zkay v0.2 relies on a trusted setup phase. The entity running key generation mustdestroy a secret string generated during this phase, commonly referred to as “toxic waste”. If thisstring is retained by a malicious user, the user can construct arbitrary fake proofs accepted by theverifier and hence break zkay’s correctness guarantees (however, not it’s privacy guarantees) [20].The user creating and distributing a zkay contract archive must therefore be trusted to execute thesetup phase correctly and destroy the toxic waste.In practice, trusted setup phases are often implemented using complex ceremonies based onsecure multi-party computation in order to weaken trust assumptions [7]. While zkay users canmanually establish such ceremonies, zkay v0.2 does not come with built-in support for establishingsuchlike. PERFORMANCE
Next, we present the various optimizations employed in zkay v0.2 to reduce compilation time,off-chain runtime and memory requirements, and on-chain gas costs (Section 6.1). Further, wecompare the performance of zkay v0.2 to zkay v0.1 using a set of benchmarks (Section 6.2).
This section presents important optimizations employed by zkay v0.2.
The size of the verification key and the gas cost of NIZK proof verification are linear in the number ofpublic circuit inputs and outputs. The number of public circuit inputs can be reduced by (i) makingpublic circuit inputs in , . . . in n private, and (ii) providing a hash h over these inputs as a singlepublic circuit input, which is computed on-chain and verified in the proof circuit. This leads tolow verification costs that are almost constant in the number of circuit inputs, except for a smalllinearly-increasing cost for computing h on-chain. In zkay v0.1, h was computed as h = sha256 ( sha256 ( sha256 ( . . . , in n − ) , in n − ) , in n ) , which resultsin 2 n SHA-256 compressions for n public 256-bit circuit inputs. Zkay v0.2 improves this by usinga single SHA-256 hash over the concatenated inputs: h = sha256 ( in , in , . . . ) . This constructiononly requires ⌊ n ⌋ + n public 256-bit circuit inputs. Further, zkayv0.2 provides a configurable threshold on the number n of public circuit inputs above which thisconstruction should be applied. Like in Solidity, zkay v0.2 uses dedicated number literal types for constants and applies constantfolding. In particular, the value of a public constant sub-expression within a private expression iscomputed at compile time and integrated into the proof circuit.
In zkay v0.1, multiple accesses of the same variable within a proof circuit led to multiple redundantcircuit inputs. Zkay v0.2 performs caching of circuit inputs and re-uses these inputs for all accessesof the same variable provided it is not modified. If a variable is modified in the zkay contract, thecache is evicted and the variable is re-imported into the proof circuit.
Zkay v0.1 requests the required public key from the PKI and imports it using a new circuit inputevery time it constructs an encryption or decryption constraint in the proof circuit. If the samepublic key is required multiple times, this leads to redundant circuit inputs and PKI lookups. We note that this comes at the cost of increased proof generation runtime and memory consumption. Each call of sha256 needs to hash a 512 bit payload (input and previous digest) plus another 512-bits due to Merkle-Damgårdlength padding. 31 able 1. Contract compilation time [s]. “dummy encryption” zkay v0.2Contract zkay v0.1 zkay v0.2 ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaepexam 291.91 18.63 61.77 88.42 318.17 488.14income 124.27 14.30 41.23 55.50 162.82 245.37insurance 416.16 35.65 104.74 140.07 467.49 710.10lottery 83.66 10.07 34.28 45.80 96.33 153.99med-stats 235.46 16.35 51.68 70.88 236.99 356.09power-grid 123.05 14.31 44.75 59.49 192.59 288.25receipts 183.11 19.73 63.54 83.30 263.37 405.42reviews 305.95 23.50 78.35 107.02 357.54 545.39sum-ring 123.17 12.43 45.69 60.15 179.96 274.94token 295.18 23.50 72.82 98.67 331.52 508.55Mean 218.19 18.85 59.88 80.93 260.68 397.62Speedup - 11.58 3.64 2.70 0.84 0.55In zkay v0.2, public keys are cached and only imported once whenever possible. In particular, asthe owner of a private variable remains constant during an entire transaction, zkay v0.2 imports allpublic keys required for a transaction once , in the external top-level function. Zkay v0.2 caches generated prover and verifier keys to re-use them during compilation if thecorresponding proof circuit did not change since the previous compilation. As key generationamounts for a large part of the compilation time, this often leads to significantly lower compilationtimes and higher development productivity.
Zkay v0.2 compiles different proof circuits in parallel to speed up compilation. Also, it leveragesthe multi-threading support of libsnark for key and proof generation.
In this section, we compare the performance of zkay v0.2 to its predecessor zkay v0.1. In partic-ular, we compare compilation time, memory and output size (Section 6.2.1); on-chain gas costs(Section 6.2.2); and off-chain transaction runtime and memory (Section 6.2.3). In Section 6.2.4, wecompare the performance for different proving schemes.For our comparison in Sections 6.2.1 to 6.2.3, we use the GM17 [17] proving scheme availablein both implementations. We evaluate zkay v0.2 on all its crypto backends (see Section 5). Thisincludes “dummy encryption”, which enables a direct comparison to zkay v0.1. We evaluate bothimplementations on the 10 example contracts analyzed in zkay’s original publication [31, Tab. 1]. For tagged mapping entries (e.g. mapping (address!x => uint@x) ), this optimization is not applied as the owner dependson the mapping index, which may change dynamically at runtime.32 able 2. Peak memory usage during compilation [MB]. “dummy encryption” zkay v0.2Contract zkay v0.1 zkay v0.2 ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaepexam 3299.56 774.21 2782.38 6865.15 19700.89 19219.52income 1639.13 592.68 1564.26 7070.88 8737.90 11608.73insurance 3131.96 1166.66 2713.01 11092.28 24591.12 23332.04lottery 586.27 672.40 1116.64 8201.20 4427.00 5501.43med-stats 3234.79 580.10 1899.68 6233.57 11719.60 14476.78power-grid 1505.89 768.29 1574.00 7275.74 8329.46 11176.63receipts 1411.74 739.35 1519.86 9460.97 9652.18 16056.25reviews 3820.18 874.72 3100.03 5668.42 18955.75 22539.82sum-ring 1473.79 511.28 1831.28 6844.18 8752.44 11597.67token 3230.38 946.04 2342.00 10268.23 12664.50 17110.29Mean 2333.37 762.57 2044.31 7898.06 12753.08 15261.92Reduction Factor - 3.06 1.14 0.30 0.18 0.15All experiments are conducted on a system with the following specifications. ▷ CPU : Intel i7-8700K 6x4.7GHz (+SMT) ▷ RAM : 32 GB DDR4-3200 ▷ OS : MX Linux 19.1 x64, Kernel 4.19 ▷ Compiler : GCC 8.3.0, OpenJDK 11.0.7, Python 3.7.3
We now analyze zkay’s compilation time and memory requirements, as well as the compilationoutput size.
Compilation Time.
Table 1 compares the compilation time of zkay v0.1 and zkay v0.2 with differentcrypto backends for the 10 evaluated contracts. The majority of compilation time is due to circuitcompilation and key generation in the proving scheme backends. As a result, the compilation timesfor different crypto backends (which induce different proof circuit complexities) vary significantly.Zkay v0.2 reduces the compilation time for “dummy encryption” by a factor of around 11.6.Even though RSA backends induce much more complex proof circuits, compilation times for thesebackends in zkay v0.2 are similar than for “dummy encryption” in zkay v0.1. This is due to thestrong optimizations performed in zkay v0.2. ECDH based hybrid backends are more efficient andeven allow for faster compilation than zkay v0.1 with “dummy encryption”.
Compilation RAM Usage.
Table 2 compares the peak RAM usage during compilation of the 10evaluated contracts in zkay v0.1 and zkay v0.2 with different crypto backends. For the insurancecontract, the RSA PKCS1.5 backend required almost 25 GB (resp. 10 GB) of RAM during circuitcompilation (resp. key generation), which makes compilation on low-end machines impossible. Incontrast, hybrid crypto backends are much more memory efficient. able 3. Compiled contract storage requirement [MB]. “dummy encryption” zkay v0.2Contract zkay v0.1 zkay v0.2 ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaepexam 1447 286 1299 1754 7245 10940income 581 213 795 1004 3594 5276insurance 2027 553 2138 2753 10604 15755lottery 368 137 639 776 2146 3266med-stats 1157 252 1057 1370 5246 7790power-grid 581 213 881 1118 4231 6177receipts 870 299 1271 1605 5959 8789reviews 1519 369 1649 2117 8198 12204sum-ring 581 186 928 1160 3964 5912token 1443 357 1482 1923 7526 11172Mean 1057.40 286.50 1213.90 1558.00 5871.30 8728.10Reduction Factor - 3.69 0.87 0.68 0.18 0.12 Output Size.
Table 3 compares the storage of the compilation output. This is dominated by theprover keys, whose size depends on the complexity of the proof circuit. With RSA backends, proverkeys become very large (several GB per circuit), which makes contract distribution expensive. Thecompilation output of hybrid backends is much smaller, but still in the order of 1 GB.
Summary.
In Fig. 9, we visualize the relative differences in compilation time, memory usage, andoutput size for the different backends in zkay v0.2. All values are normalized with respect to zkayv0.1 (which uses “dummy encryption”). In general, hybrid crypto backends are more efficient thanRSA backends for all considered metrics.
We now analyze the on-chain costs of zkay transactions for a set of scenarios, which comprisemultiple transactions executed on the same contract (see [31] for details). Table 4 compares theaverage transaction gas costs for the scenarios using zkay v0.1 and zkay v0.2 with different cryptobackends. The numbers exclude the (one-time) costs for deployments and public key announcementsin the PKI contract. In Fig. 10, we show the mean transaction gas cost per crypto backend.The “dummy encryption” backend in zkay v0.2 is around 11.7% more gas-efficient than zkayv0.1. Also, the hybrid crypto backends result in lower transaction costs. Only RSA backends lead toincreased costs, likely due to the significantly larger ciphertext and key sizes.
We now analyze zkay’s off-chain performance when creating and issuing transactions. Moreprecisely, we analyze the runtime and peak memory usage of issuing transactions using thecontract interface of zkay v0.2 (resp. the transaction transformation of zkay v0.1). Both runtimeand memory are dominated by NIZK proof generation.
Runtime.
Table 5 compares the total runtime for creating and issuing all transactions in thegiven scenarios using zkay v0.1 and zkay v0.2 with different crypto primitives. The numbers kay v0.1 dummy ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaep0200400600800 N o r m a l i z e d V a l u e [ % ] Compilation Time Peak Memory Usage Output Storage Requirements
Fig. 9. Mean compilation time, memory usage and output size for different backends in zkay v0.2, normalizedw.r.t. zkay v0.1. Table 4. Average transaction gas cost (w/o deployment transactions) [gas]. “dummy encryption” zkay v0.2Scenario zkay v0.1 zkay v0.2 ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaepexam 975867 867507 942841 942916 1368591 1368527income 958761 844096 862339 862323 938187 938043insurance 863896 759457 805235 805219 961517 961525lottery 961293 870737 915360 915440 1313058 1313090med-stats 963358 841806 874977 874897 996628 996612power-grid 955134 842065 875727 875684 998738 998674receipts 956674 843245 878341 878266 1002490 1002565reviews 968579 852586 901632 901632 1071598 1071521sum-ring 958754 846932 877017 876985 983056 982944token 971990 855217 890301 890301 1025587 1025459Mean 953430.56 842364.74 882376.90 882366.24 1065945.00 1065895.99Reduction Factor - 1.13 1.08 1.08 0.89 0.89include deployment transactions, NIZK proof generation, and transaction execution on a local testblockchain (ganache-cli for zkay v0.1, eth-tester with py-evm backend for zkay v0.2). Zkay v0.2 isfaster than zkay v0.1 for “dummy encryption” as well as for hybrid crypto backends. kay v0.1 dummy ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaep0 . . . · M e a n T r a n s a c t i o n C o s t [ g a s ] Fig. 10. Mean transaction gas cost (w/o deployment transactions) for different crypto backends.Table 5. Total off-chain runtime for executing all scenario transactions [s]. “dummy encryption” zkay v0.2Scenario zkay v0.1 zkay v0.2 ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaepexam 243.47 28.48 102.13 158.64 512.09 708.31income 115.14 18.44 52.44 81.69 208.82 278.49insurance 229.06 41.19 115.08 173.61 484.45 661.19lottery 83.04 19.11 44.60 73.59 123.06 165.33med-stats 198.24 26.59 83.14 126.40 360.82 491.32power-grid 89.11 14.48 40.67 62.02 155.76 206.74receipts 167.25 34.18 104.30 155.31 410.89 558.92reviews 188.67 36.17 112.62 159.67 473.02 654.75sum-ring 140.72 24.83 81.75 119.67 326.09 430.86token 154.25 24.77 70.39 109.05 298.09 410.35Mean 160.89 26.82 80.71 121.97 335.31 456.63Speedup - 6.00 1.99 1.32 0.48 0.35
RAM Usage.
Table 6 compares the peak memory usage during scenario execution. Like forcompilation, RSA backends are very memory-intensive. However, the memory requirements forhybrid crypto backends are moderate.
Summary.
In Fig. 11, we visualize the relative differences in the scenario runtime and memoryusage for the different backends in zkay v0.2. All values are normalized with respect to zkay v0.1(which uses “dummy encryption”). In general, hybrid crypto backends are more efficient than RSAbackends in terms of both scenario runtime and memory usage. able 6. Peak memory usage during scenario execution [MB]. “dummy encryption” zkay v0.2Scenario zkay v0.1 zkay v0.2 ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaepexam 1584.79 502.45 2341.76 3204.56 11348.01 17132.19income 1562.11 291.39 1205.80 3072.60 9444.64 9543.21insurance 1548.90 533.97 2152.11 3133.64 9789.28 12879.11lottery 1222.43 278.02 759.79 2608.45 2342.67 2703.75med-stats 1215.16 382.98 1633.88 2874.27 10100.89 11413.27power-grid 1861.60 293.80 1203.95 3105.70 9278.91 9502.40receipts 1217.36 313.16 1261.17 2954.74 9266.15 9434.11reviews 1218.19 611.86 2749.75 3296.79 12893.10 18672.79sum-ring 1199.20 371.73 1488.59 3235.51 9609.82 9470.62token 1481.12 443.35 2024.75 3245.45 9985.55 13182.52Mean 1411.09 402.27 1682.15 3073.17 9405.90 11393.40Reduction Factor - 3.51 0.84 0.46 0.15 0.12zkay v0.1 dummy ecdh-chaskey ecdh-aes rsa-pkcs1.5 rsa-oaep0200400600800 N o r m a l i z e d V a l u e [ % ] Scenario Runtime Peak Memory Usage
Fig. 11. Mean scenario runtime and peak memory usage for different backends in zkay v0.2, normalized w.r.t.zkay v0.1.
So far, we have analyzed zkay v0.2 with the GM17 [17] proving scheme, which is also availablein zkay v0.1. We now demonstrate how using the Groth16 [16] proving scheme improves zkay’sperformance. able 7. Comparison of zkay v0.2 proving schemes for the ECDH AES crypto backend. Metric (mean across all scenarios) GM17 Groth16Compilation Time [s] 80.93 56.59Compilation Peak Memory [MB] 7898.06 7025.70Output Size [MB] 1558.00 1081.2Scenario Time [s] 121.97 100.48Scenario Peak Memory [MB] 3073.17 3021.79Avg. Transaction Cost [gas] 882366.24 626593.67In Table 7, we compare the average performance, memory usage and gas costs over all scenariosfor the two proving schemes using the ECDH AES crypto backend. Groth16 is more efficient overall:While there is no significant effect on memory usage, Groth16 decreases average compilation timeand output size by roughly 30%, gas costs by 25%, and scenario runtime by 20% compared to GM17.In zkay v0.2, Groth16 is the default proving scheme. USABILITY IMPROVEMENTS7.1 Installation
Zkay v0.2 can be packaged and installed using setuptools. Package installation automaticallycompiles the required libsnark interface binary from source and makes the zkay command goballyavailable.
In contrast to zkay v0.1, zkay v0.2 displays human-readable and descriptive error messages. Forexample, the command-line interface provides precise source code locations for type errors.
Zkay v0.2 simplifies contract distribution by providing built-in support for bundling and export-ing/importing zkay contracts along with all relevant information such as prover keys (see Section 5.4for details).For example, Alice can deploy and share a contract contract.zkay with Bob as follows.(i) Alice compiles and deploys contract.zkay using her local zkay compiler.(ii) Next, she bundles the locally compiled contract to an archive contract.zkp using zkay’s export command.(iii) Alice then sends the archive contract.zkp to Bob using an off-chain channel and informshim about the address of the deployed contract.(iv) Bob can now import contract.zkp on his local computer using zkay’s import command.He can then connect to and interact with Alice’s deployed contract.
Zkay v0.2 allows rich customization and comes with support for configuration files.The default settings are configured in config_user.py , any of which can be overridden via ahierarchy of configuration files. The user may create the following configuration files: (i) a system-wide configuration file in $SITE_CONFIG_DIR/zkay/config.json , (ii) a user-wide configurationfile in $USER_CONFIG_DIR/zkay/config.json , and (iii) a local configuration file in the workingdirectory or in a location provided using a command line flag. It is further possible to override any setting via a command-line parameter of the same name,which takes precedence over all configuration files.
The command-line interface of zkay v0.2 is based on sub-commands, which are described be-low. All commands support context-aware bash-autocompletion powered by argcomplete [21].Programmatic access to all features is available through the the zkay_frontend module.
Development. ▷ zkay check : Run the type checker on the given zkay file. Zkay v0.2 uses the appdirs library [1] to determine the location of $SITE_CONFIG and $USER_CONFIG .39 zkay solify : Strip zkay-specific features from the given zkay file and output the resultingSolidity code. This makes it possible to analyze zkay code with tools designed for Solidity. ▷ zkay compile : Compile the given zkay file. This includes type-checking, code transformation,circuit construction and compilation, NIZK key generation, and contract interface generation. ▷ zkay update-solc : Download and install the latest compatible version of solc. Distribution. ▷ zkay export : Package the necessary data (contract, manifest and prover keys) of the givencompilation output directory as a *.zkp archive. ▷ zkay import : Import a given *.zkp archive. Deployment and Interaction. ▷ zkay deploy-pki : Deploy the PKI contract. ▷ zkay deploy-crypto-libs : Deploy library contracts required for the GM17 proving scheme. ▷ zkay run : Open an interactive shell in the context of the contract interface of a givencompilation output directory. ▷ zkay deploy : Deploy the contract of a given compilation output directory. ▷ zkay connect : Connect to the contract of a given compilation output directory at a givenaddress and start an interactive shell in the context of the contract interface. EFERENCES [1] ActiveState. [n. d.]. appdirs GitHub Repository. https://github.com/ActiveState/appdirs. Accessed: 2020-03-30.[2] Nir Bitansky, Ran Canetti, Alessandro Chiesa, and Eran Tromer. 2012. From Extractable Collision Resistance toSuccinct Non-Interactive Arguments of Knowledge, and Back Again. In
Proceedings of the 3rd Innovations in TheoreticalComputer Science Conference (ITCS ’12) . Association for Computing Machinery, New York, NY, USA, 326–349. https://doi.org/10.1145/2090236.2090263[3] Manuel Blum, Paul Feldman, and Silvio Micali. 1988. Non-Interactive Zero-Knowledge and Its Applications. In
Proceedings of the Twentieth Annual ACM Symposium on Theory of Computing (STOC ’88) . Association for ComputingMachinery, New York, NY, USA, 103–112. https://doi.org/10.1145/62212.62222[4] Whitfield Diffie and Martin Hellman. 1976. New directions in cryptography.
IEEE transactions on Information Theory
22, 6 (1976), 644–654.[5] J. Eberhardt and S. Tai. 2018. ZoKrates - Scalable Privacy-Preserving Off-Chain Computations. In . 1084–1091.[6] William F Ehrsam, Carl HW Meyer, John L Smith, and Walter L Tuchman. 1978. Message verification and transmissionerror detection by block chaining. US Patent 4,074,066.[7] Electronic Coin Company. [n. d.]. Zcash Parameter Generation. https://z.cash/technology/paramgen/. Accessed:2020-08-20.[8] SRI Lab ETH. [n. d.]. Zkay jsnark interface GitHub Repository. https://github.com/eth-sri/zkay-jsnark/tree/master/JsnarkCircuitBuilder/src/zkay. Accessed: 2020-03-29.[9] SRI Lab ETH. [n. d.]. Zkay libsnark fork GitHub Repository. https://github.com/eth-sri/zkay-libsnark. Accessed:2020-03-29.[10] SRI Lab ETH. 2019. Zkay v0.1 Implementation GitHub Repository. https://github.com/eth-sri/zkay/tree/ccs2019.Accessed: 2020-09-02.[11] SRI Lab ETH. 2019. Zkay v0.2 Implementation GitHub Repository. https://github.com/eth-sri/zkay/tree/v0.2. Accessed:2020-09-02.[12] Ethereum. [n. d.]. eth-tester GitHub Repository. https://github.com/ethereum/eth-tester. Accessed: 2020-03-28.[13] Uriel Feige, Dror Lapidot, and Adi Shamir. 1999. Multiple NonInteractive Zero Knowledge Proofs Under GeneralAssumptions.
SIAM J. Comput.
29, 1 (Sept. 1999), 1–28. https://doi.org/10.1137/S0097539792230010[14] FIPS. 2001. FIPS PUB 197, Advanced Encryption Standard (AES). https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.197.pdf. Accessed: 2020-03-28.[15] FIPS. 2015. FIPS PUB 180-4, Secure Hash Standard (SHS). https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf.Accessed: 2020-03-28.[16] Jens Groth. 2016. On the Size of Pairing-Based Non-interactive Arguments. In
Advances in Cryptology – EUROCRYPT2016 , Marc Fischlin and Jean-Sébastien Coron (Eds.). Springer Berlin Heidelberg, Berlin, Heidelberg, 305–326.[17] Jens Groth and Mary Maller. 2017. Snarky signatures: Minimal signatures of knowledge from simulation-extractableSNARKs. In
Annual International Cryptology Conference
Mathematics of computation
48, 177 (1987), 203–209.[23] Ahmed Kosba. [n. d.]. Jsnark GitHub Repository. https://github.com/akosba/jsnark. Accessed: 2020-03-03.[24] SCIPR Lab. [n. d.]. Libsnark GitHub Repository. https://github.com/scipr-lab/libsnark. Accessed: 2020-03-03.[25] Victor S. Miller. 1985. Use of Elliptic Curves in Cryptography. In
Advances in Cryptology (CRYPTO ’85) . Springer-Verlag,Berlin, Heidelberg, 417–426.[26] K. Moriarty, B. Kaliski, J. Jonsson, and A. Rusch. 2016.
PKCS . RFC 8017.RFC Editor.[27] Nicky Mouha, Bart Mennink, Anthony Van Herrewege, Dai Watanabe, Bart Preneel, and Ingrid Verbauwhede. 2014.Chaskey: an efficient MAC algorithm for 32-bit microcontrollers. In
International Conference on Selected Areas inCryptography . Springer, 306–323.[28] Legion of the Bouncy Castle Inc. 2013. BouncyCastle Official Webpage. https://bouncycastle.org/. Accessed: 2020-03-28.4129] PyCryptodome. [n. d.]. PyCryptodome GitHub Repository. https://github.com/Legrandin/pycryptodome. Accessed:2020-03-28.[30] R. L. Rivest, A. Shamir, and L. Adleman. 1978. A Method for Obtaining Digital Signatures and Public-Key Cryptosystems.
Commun. ACM
21, 2 (Feb. 1978), 120–126. https://doi.org/10.1145/359340.359342[31] Samuel Steffen, Benjamin Bichsel, Mario Gersbach, Noa Melchior, Petar Tsankov, and Martin Vechev. 2019. Zkay:Specifying and Enforcing Data Privacy in Smart Contracts. In