Generate and Verify Signatures for Data of Arbitrary Sizes
ZoKrates makes it possible to generate zero-knowledge proofs that verify the validity of digital signatures. However, its standard library currently supports only inputs up to 64 bytes, assuming the data has already been hashed using SHA-512.
In this tutorial, you’ll learn how to go beyond that limit. We’ll show you how to create and verify digital signatures for inputs of any size, without needing to hash the data with SHA-512 beforehand. This gives you more flexibility when working with real-world data in ZoKrates.
Prepare the Signature
The first step is using the python ZnaKes library to create Eddsa digital signatures for any input data. Here we are creating a digital signature over the string “Hello World!”.
from znakes.curves import BabyJubJub
from znakes.eddsa import PrivateKey, PublicKey
msg = b"Hello World!"
# Generate Key Pair
sk = PrivateKey.from_rand(curve=BabyJubJub)
pk = PublicKey.from_private(sk)
# Sign
sig = sk.sign(msg)
# Verify
is_verified = pk.verify(sig, msg)
# Print to stdout
sig_R, sig_S = sig
output = [
sig_R.x, sig_R.y, sig_S,
pk.point.x.n, pk.point.y.n,
*msg
]
serialized_output = " ".join([str(item) for item in output])
print(serialized_output)
The above produces an output that looks like:
19183337338677992848747478745020500596878328696652373860413484649446225630609 7135427168795771367746255243957256324383353456290015861285876789982371788795 6327109170697364372329047148605912275804596154812736086444289848953812016301 6271060698720755664541715559276410977268497611321454540143271218346252423842 12455790721558503611122475157730591952456391319859711283078570400671284385828 72 101 108 108 111 32 87 111 114 108 100 33
which can be plugged into a ZoKrates program.
Prepare the ZoKrates Verification Algorithm
The ZoKrates program will first need a slightly modified version of the original verifyEddsa implementation.
This modified version accepts input of any length, and is what you will use in your program.
Place the following code inside a file eddsa_arbitrary.zok
// eddsa_arbitrary.zok
from "hashes/sha256/sha256Padded" import sha256Padded;
import "ecc/edwardsScalarMult" as scalarMult;
import "ecc/edwardsAdd" as add;
import "utils/pack/bool/nonStrictUnpack256" as unpack256bool;
import "ecc/edwardsOnCurve" as onCurve;
import "ecc/edwardsOrderCheck" as orderCheck;
from "ecc/babyjubjubParams" import BabyJubJubParams;
import "utils/casts/u32_8_to_bool_256";
import "utils/casts/u8_to_bits";
def main<N>(field[2] R, field S, field[2] A, u8[N] M, BabyJubJubParams context) -> bool {
field[2] G = [context.Gu, context.Gv];
// Check if R is on curve and if it is not in a small subgroup. A is public input and can be checked offline
assert(onCurve(R, context)); // throws if R is not on curve
assert(orderCheck(R, context));
bool[256] Rx = unpack256bool(R[0]);
bool[256] Ax = unpack256bool(A[0]);
u32 L = N * 8;
bool[L] mut input_bits = [false; L];
for u32 i in 0..N {
bool[8] bits = u8_to_bits(M[i]);
for u32 j in 0..8 {
input_bits[i * 8 + j] = bits[j];
}
}
bool[256] hRAM = u32_8_to_bool_256(sha256Padded([...Rx, ...Ax, ...input_bits]));
bool[256] sBits = unpack256bool(S);
field[2] lhs = scalarMult(sBits, G, context);
field[2] AhRAM = scalarMult(hRAM, A, context);
field[2] rhs = add(R, AhRAM, context);
bool out = rhs[0] == lhs[0] && rhs[1] == lhs[1];
return out;
}
Prepare Your Final ZoKrates Program
Your ZoKrates program will now make use of eddsa_arbitrary.zok
for verifying digital signatures:
// main.zok
import "./eddsa_arbitrary" as eddsa;
from "ecc/babyjubjubParams" import BABYJUBJUB_PARAMS;
def main(field[2] R, field S, field[2] A, u8[12] M) {
bool result = eddsa(R, S, A, M, BABYJUBJUB_PARAMS);
assert(result == true);
return;
}
You can now use the output from the python code to generate a proof.
Leave a comment