1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

add latest flag to releases, remove useless stdlib components, put stdlib doc in source, add stdlib summary to book

This commit is contained in:
schaeff 2020-07-28 15:50:17 +02:00
parent 60f19fefcd
commit 18a0b5c105
37 changed files with 86 additions and 272 deletions

View file

@ -28,6 +28,7 @@ docker push zokrates/zokrates:$TAG
echo "Published zokrates/zokrates:$TAG"
# Release on Github
git tag latest
git tag $TAG
git push origin $TAG

View file

@ -4,20 +4,22 @@ The following table lists the precedence and associativity of all available oper
| Operator | Description | Associativity | Remarks |
|------------------------------|--------------------------------------------------------------|------------------------------------|---------|
| ** <br> | Power | Left | (1) |
| ** <br> | Power | Left | [^1] |
| * <br> /<br> | Multiplication <br> Division <br> | Left <br> Left | |
| + <br> - <br> | Addition <br> Subtraction <br> | Left <br> Left | |
| << <br> >> <br> | Left shift <br> Right shift <br> | Left <br> Left | (2) |
| << <br> >> <br> | Left shift <br> Right shift <br> | Left <br> Left | [^2] |
| & | Bitwise AND | Left <br> Left | |
| \| | Bitwise OR | Left <br> Left | |
| ^ | Bitwise XOR | Left <br> Left | |
| >= <br><br> > <br> <= <br> < | Greater or equal <br> Greater <br> Lower or equal <br> Lower | Left <br> Left <br> Left <br> Left | (3) |
| >= <br><br> > <br> <= <br> < | Greater or equal <br> Greater <br> Lower or equal <br> Lower | Left <br> Left <br> Left <br> Left | [^3] |
| != <br> == <br> | Not Equal <br> Equal <br> | Left <br> Left | |
| && | Boolean AND | Left | |
| \|\| | Boolean OR | Left | |
1. The exponent must be a compile-time constant
2. The right operand must be a compile time constant
3. Both operands are be asserted to be strictly lower than the biggest power of 2 lower than `p/2`
[^1]: The exponent must be a compile-time constant
[^2]: The right operand must be a compile time constant
[^3]: Both operands are be asserted to be strictly lower than the biggest power of 2 lower than `p/2`

View file

@ -1,97 +1,44 @@
## Standard library
ZoKrates comes with a number of reusable components which are defined at `./stdlib/` in the ZoKrates root repository. In order to import the standard library as described in the [imports](./imports.html) section the `$ZOKRATES_HOME` environment variable needs to be set to the `stdlib` folder.
ZoKrates comes with a number of reusable components in the form of a Standard Library. In order to import it as described in the [imports](./imports.html) section, the `$ZOKRATES_HOME` environment variable must be set to the `stdlib` folder.
The following section highlights a subset of available imports:
The full ZoKrates Standard Library can be found [here](https://github.com/Zokrates/ZoKrates/tree/latest/zokrates_stdlib/stdlib).
### Hashes
#### sha256
#### Sha256
```zokrates
import "hashes/sha256/512Padded.zok"
```
The sha526 hash function comes in a variety of flavours. It can be a good choice when pseudo-randomness, or compatibility with off-circuit systems such as the EVM are required, at the cost of a higher number of constraints.
A function that takes 2 `u32[8]` arrays as inputs and returns their sha256 compression function as a `u32[8]`.
#### Pedersen
#### sha256compression
Pedersen hashing takes advantage of the BabyJubJub embedded elliptic curve on ALT_BN128 to provide a collision-resistant, cheap hash function. One tradeoff is a relatively high cost when computing it inside the EVM.
```zokrates
import "hashes/sha256/512bit.zok"
```
#### MiMC
A function that takes 2 `u32[8]` arrays as inputs and returns their sha256 compression function as a `u32[8]`.
The difference with `512Padded` is that no padding is added at the end of the message, which makes it more efficient but also less compatible with Solidity.
MiMC is an alternative hash function which comes at a reduced cost and is also relatively cheap inside the EVM.
There also is support for 2-round (1024-bit input) and 3-round (1536-bit input) variants, using `hashes/1024bit.zok` and `hashes/1536bit.zok` respectively.
### Elliptic curve cryptography
#### sha256packed
Thanks to the existence of BabyJubJub, an efficient elliptic curve embedded in ALT_BN128, we provide tools to perform elliptic curve operations such as:
```zokrates
import "hashes/sha256/512bitPacked.zok"
```
- Point operations
- Proving knowledge of a private EdDSA key
- Proving validity of an EdDSA signature
A function that takes an array of 4 field elements as inputs, unpacks each of them to 128 bits (big-endian), concatenates them and applies sha256. It then returns an array of 2 field elements, each representing 128 bits of the result.
Check out this [python repository](https://github.com/Zokrates/pycrypto) for tooling, for example to generate EdDSA signatures to then check in a SNARK.
### Public-key Cryptography
### Utils
#### Proof of private-key ownership
#### Packing / Unpacking
```zokrates
import "ecc/proofOfOwnership.zok"
```
As some operations require their input to be provided in the form of bits, we provide tools to convert back and forth between field elements and their bit representations.
Verifies match of a given public/private keypair. Checks if the following equation holds for the provided keypair:
`pk = sk*G`
where `G` is the chosen base point of the subgroup and `*` denotes scalar multiplication in the subgroup.
#### Casts
#### Signature verification
Helpers to convert between types representing binary data.
```zokrates
import "signatures/verifyEddsa.zok"
```
#### Multiplexer
Verifies an EdDSA Signature. Checks the correctness of a given EdDSA Signature `(R,S)` for the provided public key `A` and message `(M0, M1)`. Check out this [python repository](https://github.com/Zokrates/pycrypto) for tooling to create valid signatures.
### Packing / Unpacking
#### pack128
```zokrates
import "utils/pack/u32/pack128"
```
Packs a `u32[4]` as one field element.
#### unpack128
```zokrates
import "utils/pack/unpack128"
```
Unpacks a field element to a `u32[4]`, throwing if it doesn't fit.
#### pack256
```zokrates
import "utils/pack/u32/pack256"
```
Packs a `u32[8]` as one field element. Overflows can occur.
#### nonStrictUnpack256
```zokrates
import "utils/pack/u32/nonStrictUnpack256"
```
Unpacks a field element to a `u32[4]`. Uniqueness of the output is not guaranteed.
### Casts
Different helpers to convert between types.
```zokrates
import "utils/casts/bool_128_to_u32_4"
```
Optimised tools to branch inside circuits.

View file

@ -8,7 +8,7 @@ ZoKrates currently exposes two primitive types and two complex types:
This is the most basic type in ZoKrates, and it represents a positive integer in `[0, p - 1]` where `p` is a (large) prime number.
The prime `p` is set to `21888242871839275222246405745257275088548364400416034343698204186575808495617` as imposed by the pairing curve supported by Ethereum.
As an example, `p` is set to `21888242871839275222246405745257275088548364400416034343698204186575808495617` when working with the [ALT_BN128](/reference/proving_schemes.html#alt_bn128) curve supported by Ethereum.
While `field` values mostly behave like unsigned integers, one should keep in mind that they overflow at `p` and not some power of 2, so that we have:
@ -26,11 +26,11 @@ Unsigned integers enable implementing programs which rely bit strings, such as h
## Complex Types
ZoKrates provides two complex types, Arrays and Structs.
ZoKrates provides two complex types: arrays and structs.
### Arrays
ZoKrates supports static arrays, i.e., their length needs to be known at compile time.
ZoKrates supports static arrays, i.e., whose length needs to be known at compile time.
Arrays can contain elements of any type and have arbitrary dimensions.
The following example code shows examples of how to use arrays:

View file

@ -1,4 +1,4 @@
from "hashes/sha256/512bitPacked" import main
import "hashes/sha256/512bitPacked" as sha256packed
def main(private field a, private field b, private field c, private field d) -> (field[2]):
field[2] h = sha256packed([a, b, c, d])

View file

@ -4,8 +4,11 @@ import "ecc/babyjubjubParams" as context
from "ecc/babyjubjubParams" import BabyJubJubParams
import "hashes/utils/256bitsDirectionHelper" as multiplex
def multiplex(bool selector, u32[8] left, u32[8] right) -> (u32[8]):
return if selector then right else left fi
// Merke-Tree inclusion proof for tree depth 3 using SNARK efficient pedersen hashes
// directionSelector=> 1/true if current digest is on the rhs of the hash
// directionSelector=> true if current digest is on the rhs of the hash
def main(u32[8] rootDigest, private u32[8] leafDigest, private bool[3] directionSelector, u32[8] PathDigest0, private u32[8] PathDigest1, private u32[8] PathDigest2) -> ():
BabyJubJubParams context = context()

View file

@ -1,5 +1,7 @@
import "hashes/sha256/512bit" as sha256
import "utils/multiplexer/256bit" as multiplex
def multiplex(bool selector, u32[8] left, u32[8] right) -> (u32[8]):
return if selector then right else left fi
// Merkle-Tree inclusion proof for tree depth 3

View file

@ -1,21 +0,0 @@
import "utils/multiplexer/lookup3bitSigned" as sel3s
import "utils/multiplexer/lookup2bit" as sel2
import "ecc/babyjubjubParams" as context
from "ecc/babyjubjubParams" import BabyJubJubParams
import "ecc/edwardsAdd" as add
def main(bool[6] e) -> (field[2]):
BabyJubJubParams context = context()
field[2] a = context.INFINITY //Infinity
//Round 0
field cx = sel3s([e[0], e[1], e[2]], [13418723823902222986275588345615650707197303761863176429873001977640541977977 , 8366451672790208592553809639953117385619257483837439526516290319251622927412, 1785026334726838136757054176272745265857971873904476677125553010508875025629, 15763987975760561753692294837740043971877392788040801334205375164715487005236])
field cy = sel2([e[0], e[1]], [15255921313433251341520743036334816584226787412845488772781699434149539664639 , 10916775373885716961512013142444429405184550001421868906213743991404593770484, 18533662942827602783563125901366807026309605479742251601915445402562880550265, 12754584346112149619040942896930712185968371085994381911052593922432846916845])
a = add(a, [cx, cy], context)
//Round 1
cx = sel3s([e[3], e[4], e[5]], [10096735692467598736728394557736034054031417419721869067082824451240861468728 , 6979151010236415881632946866847657030447196774231162748523315765559549846746, 12137947022495312670974525048647679757468392619153927921382150023166867027471, 10624360821702266736197468438435445939719745367234393212061381062942588576905])
cy = sel2([e[3], e[4]], [16704592219657141368520262522286248296157931669321735564513068002743507745908 , 11518684165372839249156788740134693928233608013641661856685773776747280808438, 21502372109496595498116676984635248026663470429940273577484250291841812814697, 17522620677401472201433112250371604936150385414760411280739362011041111141253])
a = add(a, [cx, cy], context)
return a

View file

@ -1,8 +1,10 @@
import "./IVconstants" as IVconstants
import "./shaRound" as sha256
// A function that takes 4 bool[256] arrays as inputs
// and applies 2 rounds of sha256 compression.
// A function that takes 4 u32[8] arrays as inputs, concatenates them,
// and returns their sha256 compression as a u32[8].
// Note: no padding is applied
def main(u32[8] a, u32[8] b, u32[8] c, u32[8] d) -> (u32[8]):
u32[8] IV = IVconstants()

View file

@ -1,6 +1,7 @@
import "./1536bit" as sha256
// Take two bool[256] arrays as input
// and returns their sha256 full round output as an array of 256 bool.
// A function that takes four u32[8] array as input, concatenates them, pads the result,
// and returns the sha256 output as a u32[8]
def main(u32[8] a, u32[8] b, u32[8] c, u32[8] d) -> (u32[8]):
// Hash is computed on the full 1024bit block size

View file

@ -1,9 +1,10 @@
import "./IVconstants" as IVconstants
import "./shaRound" as sha256
// A function that takes 6 u32[8] arrays as inputs
// and applies 3 rounds of sha256 compression.
// It returns an array of 256 bool.
// A function that takes 6 u32[8] arrays as inputs, concatenates them,
// and returns their sha256 compression as a u32[8].
// Note: no padding is applied
def main(u32[8] a, u32[8] b, u32[8] c, u32[8] d, u32[8] e, u32[8] f) -> (u32[8]):
u32[8] IV = IVconstants()

View file

@ -1,7 +1,7 @@
import "./512bit" as sha256
// A function that takes 1 bool[256] array as input
// and returns the sha256 full round output as an array of 256 bool.
// A function that takes a u32[8] array as input, pads it,
// and returns the sha256 output as a u32[8]
def main(u32[8] a) -> (u32[8]):
// Hash is computed on 256 bits of input

View file

@ -1,8 +1,9 @@
import "./IVconstants" as IVconstants
import "./shaRound" as sha256
// A function that takes 2 u32[8] arrays as inputs
// and returns their sha256 compression function as an array of 8 u32.
// A function that takes 2 u32[8] arrays as inputs, concatenates them,
// and returns their sha256 compression as a u32[8].
// Note: no padding is applied
def main(u32[8] a, u32[8] b) -> (u32[8]):

View file

@ -1,7 +1,7 @@
import "../../utils/pack/u32/pack128" as pack128
import "../../utils/pack/u32/unpack128" as unpack128
import "./512bitPadded" as sha256
// A function that takes an array of 4 field elements as inputs, unpacks each of them to 128
// A function that takes an array of 4 field elements as input, unpacks each of them to 128
// bits (big endian), concatenates them and applies sha256.
// It then returns an array of two field elements, each representing 128 bits of the result.
def main(field[4] preimage) -> (field[2]):

View file

@ -1,7 +1,7 @@
import "./1024bit" as sha256
// A function that takes 2 bool[256] arrays as inputs
// and returns their sha256 full round output as an array of 256 bool.
// A function that takes 2 u32[8] arrays as inputs, concatenates them, pads them,
// and returns their sha256 hash as a u32[8]
def main(u32[8] a, u32[8] b) -> (u32[8]):
// Hash is computed on the full 512bit block size

View file

@ -67,6 +67,8 @@ def temp2(u32 a, u32 b, u32 c) -> (u32):
// temp2 := S0 + maj
return S0 + maj
// A function that computes one round of the SHA256 compression function given an input and the current value of the hash
// this is used by other components however many times needed
def main(u32[16] input, u32[8] current) -> (u32[8]):
u32 h0 = current[0]

View file

@ -1,2 +1,3 @@
// Concatenate two u32[8] arrays in an order defined by a boolean selector
def main(bool selector, u32[8] lhs, u32[8] rhs) -> (u32[16]):
return if selector then [...rhs, ...lhs] else [...lhs, ...rhs] fi

View file

@ -1,3 +1,2 @@
def main(bool[1024] input) -> (bool[256], bool[256], bool[256], bool[256]):
return input[0..256], input[256..512], input[512..768], input[768..1024]

View file

@ -1,2 +0,0 @@
def main(bool selector, u32[8] lhs, u32[8] rhs) -> (u32[8]):
return if selector then rhs else lhs fi

View file

@ -1,2 +0,0 @@
def main(bool selector, bool[2] lhs, bool[2] rhs) -> (bool[2]):
return if selector then rhs else lhs fi

View file

@ -1,6 +1,4 @@
// /**
// * One-bit window lookup table using one constraint
// */
// One-bit window lookup table using one constraint
def main(bool selector, field[2] target) -> (field):
field out = if selector then target[1] else target[0] fi

View file

@ -1,7 +1,5 @@
// /**
// * Two-bit window lookup table using one constraint
// * Maps the bits `b` to a list of constant `c`
// */
// Two-bit window lookup table using one constraint
// Maps the bits `b` to a list of field elements `c`
def main(bool[2] b, field[4] c) -> (field):
field alpha = c[1] - c[0] + if b[1] then (c[3] - c[2] - c[1] + c[0]) else 0 fi

View file

@ -1,8 +1,6 @@
import "./lookup2bit" as lookup
// /**
// * Three-bit window lookup (2bits + signature bit) in 2bit table
// * using two constraints. Maps the bits `b` to a list of constants `c`
// */
// Three-bit window lookup (2bits + signature bit) in 2bit table
// using two constraints. Maps the bits `b` to a list of constants `c`
def main(bool[3] b, field[4] c) -> (field):
field alpha = lookup([b[0], b[1]], c)

View file

@ -1,11 +1,10 @@
#pragma curve bn128
// Non-strict version:
// Note that this does not strongly enforce that the commitment is
// in the field.
import "EMBED/unpack" as unpack
// Unpack a field element as 256 big-endian bits
// Note: uniqueness of the output is not guaranteed
// For example, `0` can map to `[0, 0, ..., 0]` or to `bits(p)`
def main(field i) -> (bool[256]):
bool[254] b = unpack(i)

View file

@ -1,5 +1,6 @@
#pragma curve bn128
// pack 128 big-endian bits into one field element
def main(bool[128] bits) -> (field):
field out = 0

View file

@ -1,5 +1,8 @@
#pragma curve bn128
// pack 256 big-endian bits into one field element
// Note: This is not a injective operation as `p` is smaller than `2**256 - 1` for bn128
// For example, `[0, 0,..., 0]` and `bits(p)` both point to `0`
def main(bool[256] input) -> (field):
field out = 0

View file

@ -2,6 +2,8 @@
import "EMBED/unpack" as unpack
// Unpack a field element as 128 big-endian bits
// Precondition: the input is smaller or equal to `2**128 - 1`
def main(field i) -> (bool[128]):
bool[254] b = unpack(i)

View file

@ -1,12 +1,11 @@
#pragma curve bn128
// Non-strict version:
// Note that this does not strongly enforce that the commitment is
// in the field.
import "../bool/nonStrictUnpack256" as unpack
import "../../casts/bool_256_to_u32_8" as from_bits
// Unpack a field element as a u32[8] (big-endian)
// Note: uniqueness of the output is not guaranteed
// For example, `0` can map to `[0, 0, ..., 0]` or to `bits(p)`
def main(field i) -> (u32[8]):
return from_bits(unpack(i))

View file

@ -3,6 +3,7 @@
import "EMBED/u32_to_bits" as to_bits
import "../bool/pack128"
// pack 128 big-endian bits into one field element
def main(u32[4] input) -> (field):
bool[128] bits = [...to_bits(input[0]), ...to_bits(input[1]), ...to_bits(input[2]), ...to_bits(input[3])]

View file

@ -3,6 +3,9 @@
import "EMBED/u32_to_bits" as to_bits
import "../bool/pack256"
// pack 256 big-endian bits into one field element
// Note: This is not a injective operation as `p` is smaller than `2**256 - 1 for bn128
// For example, `[0, 0,..., 0]` and `bits(p)` both point to `0`
def main(u32[8] input) -> (field):
bool[256] bits = [...to_bits(input[0]), ...to_bits(input[1]), ...to_bits(input[2]), ...to_bits(input[3]), ...to_bits(input[4]), ...to_bits(input[5]), ...to_bits(input[6]), ...to_bits(input[7])]

View file

@ -3,5 +3,7 @@
import "../bool/unpack128" as unpack
import "../../casts/bool_128_to_u32_4" as from_bits
// Unpack a field element as 128 big-endian bits
// Precondition: the input is smaller or equal to `2**128 - 1`
def main(field i) -> (u32[4]):
return from_bits(unpack(i))

View file

@ -1,16 +0,0 @@
{
"entry_point": "./tests/tests/hashes/pedersen/6bit.zok",
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": []
}
}
}
]
}

View file

@ -1,19 +0,0 @@
//Python code used to create test vector:
//
// from zokrates.gadgets.pedersenHasher import PedersenHasher
// import bitstring
// hasher = PedersenHasher("test", 2)
// bs = bitstring.BitArray('0b110000')
// hasher.hash_bits(bs)
import "hashes/pedersen/6bit" as pedersen
def main() -> ():
bool[6] e = [true, true, false, false, false, false]
field[2] d = pedersen(e)
assert(5483803361072598088157572477433311028290255512997784196805059543720485966024 == d[0])
assert(8712718144085345152615259409576985937188455136179509057889474614313734076278 == d[1])
return

View file

@ -1,16 +0,0 @@
{
"entry_point": "./tests/tests/utils/multiplexer/256bit.zok",
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": []
}
}
}
]
}

View file

@ -1,32 +0,0 @@
import "utils/multiplexer/256bit" as multiplex
def left() -> (bool):
bool bit = false //left
u32[8] a = [0x1b19dea8, 0xba4e3c16, 0x43eb67a4, 0x2667fd3c, 0xc50a189f, 0x54977e2f, 0x8ab0beee, 0x332b2a38]
u32[8] b = [0x03f3f628, 0xe067520d, 0x9a36f714, 0xa5ba86cd, 0x2dbcae1d, 0x37e034b3, 0x84786de3, 0xedb8b557]
u32[8] output = [0x1b19dea8, 0xba4e3c16, 0x43eb67a4, 0x2667fd3c, 0xc50a189f, 0x54977e2f, 0x8ab0beee, 0x332b2a38]
assert(output == multiplex(bit, a, b))
return true
def right() -> (bool):
bool bit = true //right
u32[8] a = [0x1b19dea8, 0xba4e3c16, 0x43eb67a4, 0x2667fd3c, 0xc50a189f, 0x54977e2f, 0x8ab0beee, 0x332b2a38]
u32[8] b = [0x03f3f628, 0xe067520d, 0x9a36f714, 0xa5ba86cd, 0x2dbcae1d, 0x37e034b3, 0x84786de3, 0xedb8b557]
u32[8] output = [0x03f3f628, 0xe067520d, 0x9a36f714, 0xa5ba86cd, 0x2dbcae1d, 0x37e034b3, 0x84786de3, 0xedb8b557]
assert(output == multiplex(bit, a, b))
return true
def main() -> ():
assert(left())
assert(right())
return

View file

@ -1,16 +0,0 @@
{
"entry_point": "./tests/tests/utils/multiplexer/2bit.zok",
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": []
},
"output": {
"Ok": {
"values": []
}
}
}
]
}

View file

@ -1,28 +0,0 @@
import "utils/multiplexer/2bit" as multiplex
def left() -> (bool):
bool bit = false //left
bool[2] a = [false, true]
bool[2] b = [true, false]
bool[2] output = [false, true]
assert(output == multiplex(bit, a, b))
return true
def right() -> (bool):
bool bit = true //right
bool[2] a = [false, true]
bool[2] b = [true, false]
bool[2] output = [true, false]
assert(output == multiplex(bit, a, b))
return true
def main() -> ():
assert(left())
assert(right())
return