Welcome to the Zenroom documentation wiki!

Getting started

Build instructions

This section is optional for those who want to build this software from source. The following build instructions contain generic information meant for an expert audience.

The Zenroom compiles the same sourcecode to run on Linux in the form of 2 different POSIX compatible ELF binary formats using GCC (linking shared libraries) or musl-libc (fully static) targeting both X86 and ARM architectures. It also compiles to a Windows 64-bit native and fully static executable. At last, it compiles to Javascript/Webassembly using the LLVM based emscripten SDK. To recapitulate some Makefile targets:

  1. make shared its the simpliest, builds a shared executable linked to a system-wide libc, libm and libpthread (mostly for debugging)
  2. make static builds a fully static executable linked to musl-libc (to be operated on embedded platforms)
  3. make javascript-node, make javascript-wasm (need EMSDK env) builds different flavors of Javascript modules to be operated from a browser or NodeJS (for client side operations)
  4. make win builds a Windows 64bit executable with no DLL dependancy, containing the LUA interpreter and all crypto functions (for client side operations on windows desktops)
  5. make javascript-demo creates in the docs/demo folder a simple web page with a REPL and some boilerplate code to show how to use the WebAssembly binary (visible online here)

Remember that if after cloning this source code from git, one should do:

git submodule update --init --recursive

Then first build the shared executable environment:

make shared

To run tests:

make check-shared

To build the static environment:

make bootstrap
make static
make check-static

For the Javascript and WebAssembly modules the Zenroom provides various targets provided by emscripten which must be installed and loaded in the environment according to the emsdk’s instructions :

make javascript-node
make javascript-wasm
make javascript-demo

NB. for the javascript-demo target the generated files should be served by a http server and not directly opened in a browser eg.

$ make javascript-demo
$ cd docs/demo
$ python3 -m http.server

Build instructions for Mobile libraries

iOS

You need to have install Xcode with the commandline-tools

There are 3 different targets ios-sim ios-armv7 ios-arm64 these targets creates an static library with the correct architecture (x86_64, ARMV7, ARM64).

Finally once done all the libraries there is a final target ios-fat that put them together creating a fat-binary that you can include into your app.

Or you can just use the build-ios.sh that does all the steps for you!

For using the library just copy zenroom.a somewhere in your project and include the zenroom.h file.

Android

You need to have installed android-sdk (if you have Android Studio installed is already there) and set the ANDROID_HOME variable.

Also you need to install NDK inside the android-sdk using the Android Studio -> Tools -> Android -> SDK Manager

Finally use the builld-android.sh script (be sure that the ANDROID_HOME environment var is set) and you will have at the end libzenroom-arm.so and libzenroom-x86.so

To use it in your project just drop src/Zenroom.java inside your codebase and the put the *.so as following:

src/
    main/
         java/
         jniLibs/
                 x86/ 
                      libzenroom.so
                 armeabi/ 
                      libzenroom.so

Embedding Zenroom

Zenroom is designed to facilitate embedding into other native applications and high-level scripting languages. The stable releases distribute compiled library components for Apple/iOS and Google/Android platforms, as well MS/Windows DLL. Golang bindings and a Jupyter kernel are also in experimental phase.

To call Zenroom from an host program is very simple, since there isn’t an API of calls, but a single call to execute scripts and return their results. The call is called zenroom_exec and prints results to the "stderr/stdout" terminal output. Its prototype is common to all libraries:

int zencode_exec(char *script, char *conf, char *keys, char *data);

in case buffers should be used instead of stdout/err file descriptors, this call defines where to print out the output and the maximum sizes allowed for it. Output is NULL terminated. The input buffers are all read-only, here their functions:

  • script: a long string containing the script to be executed
  • conf: a short configuration string (for now only umm supported as value)
  • keys: a string often JSON formatted that contains keys (sensitive information)
  • data: a string (also JSON formatted) that contains data

In addition to this function there is another one that copies results (error messages and printed output) inside memory buffers:

int zenroom_exec_tobuf(char *script, char *conf, char *keys, char *data,
                       char *stdout_buf, size_t stdout_len,
                       char *stderr_buf, size_t stderr_len);

In addition to the previously explained arguments, the new ones are:

  • stdout_buf: pre-allocated buffer by the caller where to copy stdout
  • stdout_len: maximum length of the pre-allocated stdout buffer
  • stderr_buf: pre-allocated buffer by the called where to copy stderr
  • stderr_len: maximum length of the pre-allocated stderr buffer

Language bindings

-This API can be called in similar ways from a variety of languages and wrappers that already facilitate its usage.

Javascript

Javascript NPM package

? Installation

npm install zenroom

or

yarn add zenroom

? Quick Usage

const zenroom = require('zenroom').default

const script = `print("Hello World!")`
zenroom.script(script).zenroom_exec()

// prints in the console.log "Hello World!"

Python

Python language bindings

? Installation

pip install zenroom

? Quick Usage

from zenroom import zenroom

script = "print('Hello world!')"
result = zenroom.zenroom_exec(script)
print(result.stdout) # guess what

Golang

Go language bindings

? Installation

import "github.com/DECODEproject/Zenroom/bindings/golang/zenroom"

? Quick Usage

script := []byte(`print("Hello World!")`)
res, _ := zenroom.Exec(script)
fmt.Println(string(res))

How to execute Zenroom scripts

This section explains how to invoke the Zenroom to execute scripts in various situations: from commandline, from javascript and various other languages.

Javascript has its own way to call zenroom_exec(...) without losing all the context for execution.

Other languages are recommended to exec() the Zenroom in a separate process and gather its stdout and its return value (1 on error and 0 on success).

Commandline

From command-line the Zenroom is operated passing files as
arguments:

Usage: zenroom [-dh] [-c config] [-k KEYS] [-a DATA] [ SCRIPT.lua | - ]

The -d flag activates more verbose output for debugging.

The SCRIPT.lua can be the path to a script or a single dash (-) to instruct zenroom to process the script piped from stdin.

Interactive console

Just executing zenroom will open an interactive console with limited functionalities, which is capable to parse finite instruction blocks on each line. To facilitate editing of lines is possible to prefix it with readline using the rlwrap zenroom command instead.

The content of the KEYS, DATA and SCRIPT files cannot exceed 500KB.

Try:

./zenroom-static      [enter]
print("Hello World!") [enter]
                      [Ctrl-D] to quit

Will print Zenroom’s execution details on stderr and the "Hello World!" string on stdout.

Hashbang executable script

Zenroom also supports being used as an "hashbang" interpreter at the beginning of executable scripts. Just use:

#!/usr/bin/env zenroom-static -

in the header, please note the final dash which is pretty important to tell zenroom to process the script from stdin.

Javascript

For javascript :tada: now a npm module is available on https://www.npmjs.com/package/zenroom


From javascript the function zenroom_exec() is exposed with four arguments: four strings and one number from 1 to 3 indicating the verbosity of output on the console.

This is the prototype of the javascript function:

const zenroom = (script_file, conf_file=null, keys_file=null,
                 data_file=null, verbosity=3)

Only the script_file argument is mandatory, other arguments can be omitted, then defaults are used. For example after a make js build we can invoke the zenroom in src/zenroom.js creating such a script:

const fs = require('fs')
const zenroom_module = require(process.argv[2])

const zenroom = (script_file, conf_file=null, keys_file=null, 
                 data_file=null, verbosity=3) => {
  const enc = { encoding: 'utf8' }
  const script = fs.readFileSync(script_file, enc)
  const conf = (conf_file) ? fs.readFileSync(conf_file, env) : null
  const keys = (keys_file) ? fs.readFileSync(keys_file, env) : null
  const data = (data_file) ? fs.readFileSync(data_file, env) : null
  return zenroom_module.ccall('zenroom_exec', 'number',
                              ['string', 'string', 'string', 'string', 'number'],
                              [script, conf, keys, data, verbosity])
}
console.log("[JS] zenroom_exec %s %s", process.argv[2], process.argv[3])
zenroom(process.argv[3])

If the above script is saved in zenroom_exec.js then on the commandline it can be invoked with the path to zenroom.js as first parameter and the path to a script as second parameter:

nodejs src/zenroom.js zenroom_exec.js examples/hello.lua

The contents of the three strings cannot exceed 500KB in size.

Data string

The data is a simple string, but can be also a json map used to pass multiple arguments and complex data structures. Its contents can be accessed by the script using the global variable DATA (all uppercase).

For example create a json file containing a map (this can be a string
passed from javascript)

{
    "secret": "zen and the art of programming",
    "salt": "OU9Qxl3xfClMeiCz"
}

Then run zenroon -a arguments.json and pass the following script as
final argument, or pipe from stdin or passed as a string argument to
zenroom_exec() from javascript:

i = require "inspect"
json = require "json"
args = json.decode(DATA)
-- args is now a lua table containing values for each args.argname
i.print(args)

Keys string

The keys is also a simple string passed from arguments, separated from DATA since its access permission from caller may be different due to specific privacy restrinctions that may be adopted on the variable. It is accessed by the script using the global variable KEYS.

So for instance if we want to encrypt a secret message for multiple
recipients who have provided us with their public keys, one would load
this example keyfile:

{
    "keyring": {
        "public":"GoTdVYbTWEoZ4KtCeMghV7UcpJyhvny1QjVPf8K4oi1i",
        "secret":"9PSbkNgsbgPnX3hM19MHVMpp2mzvmHcXCcz6iV8r7RyZ"
    },
    "recipients": {
        "jaromil": "A1g6CwFobiMEq6uj4kPxfouLw1Vxk4utZ2W5z17dnNkv",
        "francesca": "CQ9DE4E5Ag2e71dUW2STYbwseLLnmY1F9pR85gLWkEC6",
        "jimb": "FNUdjaPchQsxSjzSbPsMNVPA2v1XUhNPazStSRmVcTwu",
        "mark": "9zxrLG7kwheF3FMa852r3bZ4NEmowYhxdTj3kVfoipPV",
        "paulus": "2LbUdFSu9mkvtVE6GuvtJxiFnUWBWdYjK2Snq4VhnzpB",
        "mayo": "5LrSGTwmnBFvm3MekxSxE9KWVENdSPtcmx3RZbktRiXc"
    }
}

And then with this code encrypt a message to all recipients:

secret="this is a secret that noone knows"
-- this should be a random string every time
nonce="eishai7Queequot7pooc3eiC7Ohthoh1"

json = require "json"
crypto = require "crypto"

keys = json.decode(KEYS)

res = {}

for name,pubkey in pairs(keys.recipients) do
   k = crypto.exchange_session_x25519(
      crypto.decode_b58(keys.keyring.secret),
      crypto.decode_b58(pubkey))
   enc = crypto.encrypt_norx(k,nonce,secret)
   -- insert in results
   res[name]=crypto.encode_b58(enc)
end
print(json.encode(res))

The above script will print out the encrypted message for each recipient reorganised in a similar json structure:

{
   "jaromil" : "Ha8185xZoiMiJhfquKRHvtT6vZPWifGaXmD4gxjyfHV9ASNaJF2Xq85NCmeyy4hWLGns4MTbPsRmZ2H7uJh9vEuWt",
   "mark" : "13nhCBWKbPAYyhJXD7aeHtiFKb89fycBnoKy2nosJdSqfS2vhhHqBvVKb2oasiga9P3UyaEJZQdyYRfiBBKEswdmQ",
   "francesca" : "7ro9u2ViXjp3AaLzvve4E4ebZNoBPLtxAja8wd8YNn51TD9LjMXNGsRvm85UQ2vmhdTeJuvcmBvz5WuFkdgh3kQxH",
   "mayo" : "FAjQSYXZdZz3KRuw1MX4aLSjky6kbpRdXdAzhx1YeQxu3JiGDD7GUFK2rhbUfD3i5cEc3tU1RBpoK5NCoWbf2reZc",
   "jimb" : "7gb5SLYieoFsP4jYfaPM46Vm4XUP2jbCUnkFRQfwNrnJfqaew5VpwqjbNbLJrqGsgJJ995bP2867nYLcn96wuMDMw",
   "paulus" : "8SGBpRjZ21pgYZhXmy7uWGNEEN7wnHkrWtHEKeh7uCJgsDKtoGZHPk29itCV6oRxPbbiWEuN9Sm83jeZ1vinwQyXM"
}

Zencode

Smart contracts in human language

Zenroom is software inspired by the language-theoretical security research and it allows to express cryptographic operations in a readable domain-specific language called Zencode.

For the theoretical background see the Zencode Whitepaper.

For an introduction see this blog post: Smart contracts for the English speaker.

Here we go with the tutorial to learn the Zencode language!

Syntax and Memory model

Zencode contracts operate in 3 phases:

  1. Given – validates the input
  2. When – processes the contents
  3. Then – prints out the results

The 3 separate blocks of code also correspond to 3 separate memory areas, sealed by security measures.

If any single line in a Zencode contract fails, Zenroom stops executing and returns the error.

Zencode documentation diagram

All data processed has first to pass the validation phase according to scenario specific data schemas.


Good Practice: start your Zencode noting down the Zenroom version you are using!

rule check version 1.0.0

Traditional cryptography in Zenroom

Symmetric encryption

This is a simple technique to hide a secret using a common password known to all participants.

The algorithm used is
AES-GCM with a random IV and an optional authenticated header (AEAD)

The encryption is applied using 3 arguments:

  • password can be any string (or file) used to lock and unlock the secret
  • message can be any string (or file) to be encrypted and decrypted
  • header is a fixed name and optional argument to indicate an authenticated header

These 3 arguments can be written or imported, but must given before using the I encrypt block:

{! examples/SYM02.zen !}

The output is returned in secret message and it looks like:

{"secret_message":{"iv":"u64:-tU2gbox9kATCeC2k_zkhYM-PBA3IzvN7HtfyVXdzB4",
    "header":"u64:dGhpc19pc19mb3JfQm9i",
    "text":"u64:cw4M3FBO3zaPRAB26d6y8SMPGgAo_0AmJUrhg5dmKwoEB7BWLAAD_A2h",
    "checksum":"u64:UugLrIuxRX46BETc1-XkrA"}}

To decode make sure to have that secret password and that a valid secret message is given, then use:

{! examples/SYM03.zen !}

So let’s imagine I want to share a secret with someone and send secret messages encrypted with it:

Zencode to encrypt with password

Of course the password must be known by all participants and that’s the
dangerous part, since it could be stolen.

We mitigate this risk using public-key cryptography, also known as
a-symmetric encryption, explained below.

Asymmetric encryption

We use asymmetric encryption (or public key
cryptography)

when we want to introduce the possession of keypairs (public and private) both by
Alice and Bob: this way there is no need for a single secret to be known to both.

Fortunately it is pretty simple to do using Zencode in 2 steps

  • Key generation and exchange (SETUP)
  • Public-key Encryption or signature (ECDH and ECDSA)

Key generation and exchange

In this phase each participant will create his/her own keypair, store it and communicate the public key to the other.

The statement to generate a keypair (public and private keys) is simple:

{! examples/AES01.zen !}

It will produce something like this:

"Alice": {
   "keypair": {
      "private_key": "u64:F_NaS3Y6Xw6BW...",
      "public_key": "u64:BLG0OGDwzP_gY41TZgGpUB4lTYCgpx9BJVScxSQAfwqEi..."
   }
}

Where the public key is usually a longer octet and actually an Elliptic Curve Point coordinate.

There is nothing preventing an host application to separate these JSON
fields and store them in any secure way.

Here we demonstrate how to create keypairs as well separate them using
Zencode:

  • 2 contracts to create Alice and Bob keypairs
  • 2 contracts to separate the public key from the private key for each

Zencode to generate asymmetric keypairs

After both Alice and Bob have their own keypairs and they both know
each other public key we can move forward to do asymmetric encryption
and signatures.

{! examples/AES01.zen !}




"Alice": {
   "keypair": {
      "private_key": "u64:F_NaS3Y6Xw6BW...",
      "public_key": "u64:BLG0OGDwzP_gY41TZgGpUB4lTYCgpx9BJVScxSQAfwqEi..."
   }
}




{! examples/AES02.zen !}




"Alice": {
   "public_key": "u64:BLG0OGDwzP_gY41TZgGpUB4lTYCgpx9BJVScxSQAfwqEi..."
}

The advantage of using Zencode here is the use of the valid keyword which effectively parses the public key object and verifies it as valid, in this case as being a valid point on the elliptic curve in use. This greatly reduces the possibility of common mistakes.

Public-key Encryption (ECDH)

Public key encryption is similar to the asymmetric
encryption
explained in the previous section,
with a difference: the from and for clauses indicating the public
key of the recipient.

Before getting to the encryption 2 other objects must be given:

  • keypair is one’s own public and private keys
  • public key from the intended recipient

So with an input separated between DATA and KEYS or grouped together in an array like:

[
  {"Bob": {"public_key":"u64:BGF59uMP0DkHoTjMT..."} },
  {"Alice": { "keypair": {
      "private_key": "u64:F_NaS3Y6Xw6BW...",
      "public_key": "u64:BLG0OGDwzP_gY41TZgGpUB4lTYCgpx9BJVScxSQAfwqEi..." } } }
]




{! examples/AES05.zen !}

which encrypts and stores results in secret message; also in this case header may be given, then is included in the encryption as an authenticated clear-text section.

Zencode to encrypt using asymmetric keypairs

1. Alice encrypts the message using Bob’s public key

{! examples/AES05.zen !}

2. Bob prepares a keyring with Alice’s public key

{! examples/AES06.zen !}

3. Bob decrypts the message using Alice’s public key

{! examples/AES07.zen !}

In this basic example the session key for encryption is made combining
the private key of Alice and the public key of Bob (or
vice versa).

When I write 'my secret for you' in 'message'
and I write 'an authenticated message' in 'header'

The decryption will always check that the header hasn’t changed,
maintaining the integrity of the string which may contain important
public information that accompany the secret.

Public-key Signature (ECDSA)

Public-key signing allows to verify the integrity of a message by
knowing the public key of all those who have signed it.

It is very useful when in need of authenticating documents: any change
to the content of a document, even one single bit, will make the
verification fail, showing that something has been tampered with.

The one signing only needs his/her own keypair, so the key setup will
be made by the lines:

Given that I am known as 'Alice'
and I have my valid 'keypair'

then assuming that the document to sign is in draft, Alice can
proceed signing it with:

and I create the signature of 'draft'

which will produce a new object signature to be printed along the
draft: the original message stays intact and the signature is detached.

On the other side Bob will need Alice’s public key to verify the
signature with the line:

When I verify the 'draft' is signed by 'Alice'

which will fail in case the signature is invalid or the document has
been tampered with.

Zencode to sign using asymmetric keypairs

Here we continue assuming that the keyrings are already prepared with
public/private keypairs and the public keypair of the correspondent.

1. Alice signs a message for Bob

{! examples/DSA01.zen !}

1. Bob verifies the signed message from Alice

{! examples/DSA02.zen !}

In this example Alice uses her private key to sign and authenticate a
message. Bob or anyone else can use Alice’s public key to prove that
the integrity of the message is kept intact and that she signed it.

Advanced cryptographic flows in Zenroom

Attribute Based Credentials

Alice in Wonderland

Attribute Based Credentials are a powerful and complex feature
implemented using the Coconut crypto
scheme
. This is the most
complex functionality available in Zenroom and it will show how the
Zencode language really simplifies it.

Let’s imagine 3 different subjects for our scenarios:

  1. Mad Hatter is a well known issuer in Wonderland
  2. Wonderland is an open space (a blockchain!) and all inhabitants can check the validity of proofs
  3. Alice just arrived: to create proofs she’ll request a credential to the issuer MadHatter

When Alice is in possession of credentials then she can
create a proof any time she wants using as input:

  • the credentials
  • her credential keypair
  • the verifier by MadHatter
    {! examples/create_proof.zen !}

All these "things" (credentials, proofs, etc.) are data structures that can be used as input and received as output of Zencode functions. For instance a proof can be print in JSON format and looks a bit list this:

{
   "credential_proof" : {
      "pi_v" : {
         "c" : "u64:tBrCGawWYEAi55_hHIPq0JT3OaapOebSHVW0GhjJcAk",
         "rr" : "u64:J7R3FXsI2dcfyZRCqWA8fDYijG39P16LvGpX90wtCWw",
         "rm" : "u64:QoG-28CNTAY3Ir4SQqVoK1ZpTlzOnXxX6Xtq5KMIxpo"
      },
      "nu" : "u64:BA77WYvBRsc53uAyrqTjuUdptJPZbcTlzr9icizm0...",
      "sigma_prime" : {
         "h_prime" : "u64:BB9AM5xjWPxsZ47zh1WAmFymru66W6YuK...",
         "s_prime" : "u64:BAGYNM6JO0wRAGE87_-bQVuhUXeEoeJrh..."
      },
      "kappa" : "u64:GFVYsudbHOJNzPl3ZL0_VzB_DRvrPKF26OCZR9..."
   },
   "zenroom" : {
      "scenario" : "coconut", "encoding" : "url64", "version" : "1.0.0"
   }
}

Anyone can verify proofs using as input:

  • the credential proof
  • the verifier by MadHatter
    {! examples/verify_proof.zen !}

What is so special about these proofs? Well! Alice cannot be followed
by her trail of proofs: she can produce an infinite number of
proofs, always different from one another
, for anyone to recognise
the credential without even knowing who she is.

even the MadHatter is surprised

Imagine that once Alice is holding credentials she can enter
any room in Wonderland and drop a proof in the chest at its
entrance: this proof can be verified by anyone without disclosing
Alice’s identity.

The flow described above is pretty simple, but the steps to setup the
credential are a bit more complex. Lets start using real names
from now on:

  • Alice is a credential Holder
  • MadHatter is a credential Issuer
  • Wonderland is a public Blockchain
  • Anyone is any peer connected to the blockchain

Zencode flow for ABC

To add more detail, the sequence is:

Zencode sequence for ABC

1 MadHatter generates an issuer keypair

InputZencodeOutput
{! examples/issuer_keygen.zen !}
issuer_keypair

1a MadHatter publishes the verification key

InputZencodeOutput
issuer_keypair
{! examples/publish_verifier.zen !}
issuer_verifier

2 Alice generates her credential keypair

InputZencodeOutput
{! examples/credential_keygen.zen !}
credential_keypair

3 Alice sends her credential signature request

InputZencodeOutput
credential_keypair
{! examples/create_request.zen !}
credential_request

4 MadHatter decides to sign a credential signature request

InputZencodeOutput
credential_request
issuer_keypair
{! examples/issuer_sign.zen !}
issuer_signature

5 Alice receives and aggregates the signed credential

InputZencodeOutput
issuer_signature
credential_keypair
{! examples/aggregate_signature.zen !}
credential

Centralized credential issuance

Lets see how flexible is Zencode.

The flow described above is for a fully decentralized issuance of
credentials where only the Holder is in possession of the
credential keypair needed to produce a credential proof.

But let’s imagine a much more simple use-case for a more centralized
system where the Issuer provides the Holder with everything
ready to go to produce zero knowledge credential proofs.

The implementation is very, very simple: just line up all the When
blocks where the different operations are done at different times and
print the results all together!

Scenario coconut
Given that I am known as 'Issuer'
When I create the issuer keypair
and I create the credential keypair
and I create the credential request
and I create the credential signature
and I create the credentials
Then print the 'credentials'
and print the 'credential keypair'

This will produce credentials that anyone can take and run. Just
beware that in this simplified version of ABC the Issuer may
maliciously keep the credential keypair and impersonate the
Holder.



Try it on your system!

Impatient to give it a spin? run Zencode scripts locally to see what
are the files produced!

Make sure that Zenroom is installed on your PC
and then go to the…


Online Interactive Demo


Shell Script Examples

Zero Knowledge Proofs

There is more to this of course: Zencode supports several features
based on pairing elliptic curve arithmetics and in particular:

  • non-interactive zero knowledge proofs (also known as ZKP or ZK-Snarks)
  • threshold credentials with multiple decentralised issuers
  • homomorphic encryption for numeric counters

These are all very useful features for architectures based on the
decentralisation of trust, typical of DLT and blockchain based
systems, as well for off-line and non-interactive authentication
.

The Zencode language leverages two main scenarios, more will be
implemented in the future.

  1. Attribute Based Credentials (ABC) where issuer verification keys
    represent specific credentials
  2. A Petition system based on ABC and homomorphic encryption

Three more are in the work and they are:

  1. Anonymous proxy validation scheme
  2. Token thumbler to privately transfer numeric assets
  3. Private credential revocation

Import, validate and transform data

Given

Self introduction

This affects my statements

Given I introduce myself as ''
Given I am known as ''
Given I am ''
Given I have my ''
Given I have my valid ''

Data provided as input (from data and keys) is all imported
automatically from JSON or CBOR binary formats.

Scenarios can add Schema for specific data validation mapped to words like: signature, proof or secret.

Data input

Given I have a ''
Given I have a valid ''
Given I have a '' inside ''
Given I have a valid '' inside ''
Given I have a '' from ''
Given I have a valid '' from ''
Given the '' is valid

or check emptiness:

Given nothing

When valid is specified then extra checks are made on input value,
mostly according to the scenario

Settings

rule input encoding [ url64 | base64 | hex | bin ]
rule input format [ json | cbor ]

When

Processing data is done in the when block. Also scenarios add statements to this block.

Without extensions, these are the basic functions available

when:
  - {when: 'I append '''' to '''''}
  - {when: 'I write '''' in '''''}
  - {when: 'I set '''' to '''''}
  - {when: 'I create a random '''''}
  - {when: 'I create a random array of '''' elements'}
  - {when: 'I create a random '''' bit array of '''' elements'}
  - {when: 'I set '''' as '''' with '''''}
  - {when: 'I append '''' as '''' to '''''}
  - {when: 'I write '''' as '''' in '''''}

Then

Output is all exported in JSON or CBOR

then:
  - {then: 'print '''' '''''}
  - {then: 'print all data'}
  - {then: 'print my data'}
  - {then: 'print my data'}
  - {then: 'print my '''''}
  - {then: 'print as '''' my '''''}
  - {then: 'print my '''' as '''''}
  - {then: 'print the '''''}
  - {then: 'print as '''' the '''''}
  - {then: 'print as '''' the '''' inside '''''}

Settings:

rule output encoding [ url64 | base64 | hex | bin ]
rule output format [ json | cbor ]

Crypto modeling with Zenroom and Lua

The Zenroom VM uses the Lua direct-syntax parser to securely interpret
and execute operations including complex arithmetics on Elliptic Curve
primitives ECP module as well Pairing
operations on twisted curves (ECP2).

The resulting scripting language is a restricted Lua dialect
without any external extension, customised to resemble as much as
possible the scripting language used by cryptographers in software, as
for instance Mathematica.

With Zenroom we want to lower the friction that cryptographers face
when implementing new crypto models. One can see this software as a
sort of templating system bridging the work of cryptographers and
programmers.

The Zencode
Whitepaper

explains in depth the issues at stake.

The intended audience of this documentation chapter are
cryptographers.

Short path from math to production

Examples speak more than a thousand words. We will dive into two
implementations to make it evident how easy is to go from an
academic paper to a portable implementation
running efficiently on
any platform.

ElGamal

As a basic introduction we propose the implementation of ElGamal
encryption
system
. The code
below makes use of the ECP arithmetics
provided by Zenroom to produce ElGamal commitments useful to
zero-knowledge proofs.

G = ECP.generator()
O = ECP.order()
salt = ECP.hashtopoint("Constant random string")
secret = INT.new(sha256("Secret message to be hashed to a number"))
r = INT.modrand(O)
commitment = G * r + salt * secret
-- keygen
seckey = INT.modrand(O)
pubkey = seckey * G
-- sign
k = INT.modrand(O)
cipher = { a = G * k,
           b = pubkey * k + commitment * secret }
-- verify
assert(cipher.b - cipher.a * seckey
          ==
       commitment * secret)

One can play around with this code already by using our online demo.

BLS signatures

The pairing property of some elliptiv curves can be exploited for
short signatures as defined by Boneh-Lynn-Schacham
(BLS)

in 2001.

Here the Zenroom implementation:

msg = str("This is the authenticated message")
G1 = ECP.generator()
G2 = ECP2.generator()
O  = ECP.order()
-- keygen: δ = r.O ; γ = δ.G2
sk = INT.modrand(O)
pk = G2 * sk
-- sign: σ = δ * ( H(msg)*G1 )
sm = ECP.hashtopoint(msg) * sk
-- verify: ε(γ,H(msg)) == ε(G2,σ)
hm = ECP.hashtopoint(msg)
assert( ECP2.miller(pk, hm) == ECP2.miller(G2, sm),
        "Signature doesn't validates")

One-round tripartite shared secret

This secret sharing protocol uses BLS curve pairing in a rather simple way, it was first described by Antonine Joux in the paper A One Round Protocol for Tripartite Diffie–Hellman (2000).

Here the Zenroom demonstration of the protocol:

-- Joux’s one-round Tripartite Diffie-Hellman
-- Setup
local G1 = ECP.generator()
local G2 = ECP2.generator()
local O  = ECP.order()
-- Parties A,B,C generate random a,b,c ∈ Zr
a = INT.modrand(O)
b = INT.modrand(O)
c = INT.modrand(O)
-- Parties A,B,C broadcast to all aG, bG, cG
aG1 = G1 * a
aG2 = G2 * a
bG1 = G1 * b
bG2 = G2 * b
cG1 = G1 * c
cG2 = G2 * c
-- Theoretical proof of ε(G, G)^abc
K  = ECP2.miller(G2,  G1)  ^ ( a * b * c )
-- A computes KA = ε(bG, cG)^a
KA = ECP2.miller(bG2, cG1) ^ a
-- B computes KB = ε(aG, cG)^b
KB = ECP2.miller(aG2, cG1) ^ b
-- C computes KC = ε(aG, bG)^c
KC = ECP2.miller(aG2, bG1) ^ c
-- Shared key is K = KA = KB = KC
assert(K == KA)
assert(K == KB)
assert(K == KC)

ECQV

For a practical example we will now use the Zenroom implementation of
the Elliptic Curve Qu-Vanstone
(ECQV)
scheme also known as
"Implicit
Certificate
" and
widely used by Blackberry technologies.

Mathematical Formula

ECQV mathematical formula

Zenroom Implementation

G = ECP.generator()
function rand() -- random modulo
    return BIG.modrand(ECP.order())
end
-- make a request for certification
ku = BIG.modrand(ECP.order())
Ru = G * ku
-- keypair for CA
dCA = BIG.modrand(ECP.order()) -- private
QCA = G * dCA       -- public (known to Alice)
-- from here the CA has received the request
k = BIG.modrand(ECP.order())
kG = G * k
-- public key reconstruction data
Pu = Ru + kG
declaration =
    { public = Pu:octet(),
      requester = str("Alice"),
      statement = str("I am stuck in Wonderland.") }
declhash = sha256(OCTET.serialize(declaration))
hash = BIG.new(declhash, ECP.order())
-- private key reconstruction data
r = (hash * k + dCA) % ECP.order()
-- verified by the requester, receiving r,Certu
du = (r + hash * ku) % ECP.order()
Qu = Pu * hash + QCA
assert(Qu == G * du)

Elliptic Curve Point arithmetics

The brief demonstration above shows how easy it can be to implement a
cryptographic scheme in Zenroom’s Lua dialect, which gives immediately
the advantage of a frictionless deployment on all targets covered by
our VM.

Arithmetic operations also involving Elliptic Curve Points
(ECP)
are applied using simple operators on
BIG integers.

All this is possible without worrying about library dependencies, OS
versioning, interpreter’s availability etc.

Main advantages of this approach

Putting the mathematical formula and the code side by side while using
the same variable names greatly helps to review the correctness of the
implementation.

The tooling inherited from Zenroom allows to swiftly build test
coverage and benchmarks.

Future Zenroom developments will improve the provability of the
calculations and their results
, as well provide testing techniques as
fuzzing: this will automatically benefit all implementations.

Cryptographers can work independently from programmers, by modeling
their formulas using their best known tools and then provide the
script as a payload to be uploaded inside the VM.

System integrators can work on embedding Zenroom as a VM
without worrying about cryptographic libraries APIs and moving
dependencies required by the cryptographic implementations.

All in all, by using Zenroom your cryptographic model implementation
is ready for an accellerating future where crypto technologies will
grow in diversity and possibilities
!

More reference here: https://dev.zenroom.org/lua/