Prechádzať zdrojové kódy

zkrunner: Add previous work

freerangedev 3 rokov pred
rodič
commit
ccff4b250f

+ 17 - 0
bin/zkrunner/README.md

@@ -0,0 +1,17 @@
+# Installation
+
+For now, you'd need to install maturin manually to run this tool.
+
+```
+# New vene and maturin
+python3 -m venv ~/.venv-zkrunner
+source ~/.venv-zkrunner/bin/activate
+pip install maturin
+
+# Install shared module onto Python
+cd $DARKFI/src/sdk-py
+maturin develop
+
+
+# You can run zkrunner.py now!
+```

+ 85 - 0
bin/zkrunner/exploratory/prove_verify.py

@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+
+"""
+Script for playing around with the Python SDK
+"""
+
+from darkfi_sdk_py import Base
+from darkfi_sdk_py import Scalar
+from darkfi_sdk_py import Point
+from darkfi_sdk_py import Affine
+from darkfi_sdk_py import Proof
+from darkfi_sdk_py import VerifyingKey
+from darkfi_sdk_py import ProvingKey
+from darkfi_sdk_py import Affine
+from darkfi_sdk_py import ZkCircuit
+from darkfi_sdk_py import ZkBinary
+from time import time
+from sys import getsizeof
+
+##### get circuit #####
+
+f = open("simple.zk.bin", "rb")
+bincode = f.read()
+f.close()
+print(f"bincode {bincode}")
+zkbin = ZkBinary.decode(bincode)
+print(f"zkbin {zkbin}")
+
+##### prover #####
+k = 13
+value = 42
+value_blind = Scalar.random()
+
+zkcircuit = ZkCircuit(zkbin)
+zkcircuit.witness_base(Base.from_u128(value))
+zkcircuit.witness_scalar(value_blind)
+zkcircuit = zkcircuit.build(zkbin)
+
+##### proving key #####
+print("making proving key...")
+proving_key = ProvingKey.build(k, zkcircuit)
+
+# pedersen commitment
+comm = Point.mul_short(value)
+comm_r = Point.blinding_point(value_blind)
+valcom = comm.add(comm_r)
+print(f"valcom {valcom}")
+(x, y) = valcom.to_affine().coordinates()
+print(f"x {x}")
+print(f"y {y}")
+print(x)
+print(y)
+publics = [x, y]
+
+start = time()
+print("making proof...")
+proof = Proof.create(proving_key, [zkcircuit], publics)
+print(f"time {time() - start}")
+
+
+#################### VERIFICATION
+
+print("verification starts.....")
+
+start = time()
+zkcircuit_v = zkcircuit.verifier_build(zkbin)
+
+print(f"building verifying key")
+start = time()
+# IMPORTANT QUESTION: can this be uploaded to an eth smart contract
+verifying_key = VerifyingKey.build(k, zkcircuit_v)
+print(f"time {time() - start}")
+
+
+print(f"verifying")
+start = time()
+proof.verify(verifying_key, publics)
+print(f"time {time() - start}")
+
+print(f"size of proof        : {getsizeof(proof)}")
+print(f"size of proving key  : {getsizeof(proving_key)}")
+print(f"size of verifying key: {getsizeof(verifying_key)}")
+
+## SHOULD FAILLLLLL
+proof.verify(verifying_key, [x])

+ 103 - 0
bin/zkrunner/exploratory/zkrunner.py~

@@ -0,0 +1,103 @@
+############################################################
+# Version that supports (de)serializastion
+# Archived for now
+############################################################
+# """
+# Acceptable format:
+# 
+# A witness or public input = [<type>, <value>]
+# 
+# <type> = Base|Scalar|EcPoint
+# 
+# <value> = "NUMBER|HEX_NUMBER" for Base or Scalar
+#         = "HEX_NUMBER" for Point
+# """
+# def serialize_input(input):
+#     input = ['Base', '42']
+#     vartype, varserial = input
+#     if vartype == 'Base':
+#         return Base.from_u64(varserial)
+#     pass
+# 
+# def deserialize_input():
+#     pass
+# 
+# def make_publics(args):
+#     print(f"make_publics: {args}")
+# 
+# def prove(args):
+#     print(f"prove: {args}")
+# 
+# def verify(args):
+#     print(f"verify: {args}")
+#     
+# """
+# TODO:
+# 
+# * Why did EcNiPoint fail to be witnessed (when building the proving key and in vm.rs)?
+#     * This is the last opcode that is not supported by ZkRunner
+# * Why do the witness type and heap var type have different sets of variants?
+#     * Need to confirm the simplications of types, i.e. Rust has more types than Python, do not have gotchas
+# * If we want to send publics around in a file, we need to figure out the serialization format
+# """
+# if __name__ == "__main__":
+#     desc = "ZkRunner helps compute public inputs, and prove and verify Darkfi zero knowledge proofs."
+#     global_parser = ArgumentParser(
+#         prog="ZkRunner",
+#         description=desc
+#     )
+#     subparsers = global_parser.add_subparsers(title="commands")
+# 
+#     # make_publics
+#     m_parser = subparsers.add_parser("make-publics", help="Make public inputs",)
+#     m_parser.add_argument(
+#             "--witnesses",
+#             default="witnesses.json",
+#             help="[default: witnesses.json] Path for where the witnesses are stored"
+#     )
+#     m_parser.add_argument(
+#             "--publics",
+#             default="publics.json",
+#             help="[default: publics.json] Path for where to store the computed public inputs for proving and verifying"
+#     )
+#     m_parser.set_defaults(func=make_publics)
+# 
+# 
+#     # prove
+#     p_parser = subparsers.add_parser("prove", help="Generate proving key and prove")
+#     p_parser.add_argument(
+#             "--witnesses",
+#             default="witnesses.json",
+#             help="[default: witnesses.json] Path for where the witnesses are stored"
+#     )
+#     p_parser.add_argument(
+#             "--publics",
+#             default="publics.json",
+#             help="[default: publics.json] Path for where to store the computed public inputs for proving and verifying"
+#     )
+#     p_parser.add_argument(
+#             "--proof",
+#             default="proof.json",
+#             help="[default: proof.json] Path for where to store the computed proof"
+#     )
+#     p_parser.set_defaults(func=prove)
+# 
+# 
+#     # verify
+#     v_parser = subparsers.add_parser("verify", help="Generate verifying key and verify")
+#     v_parser.add_argument(
+#             "--publics",
+#             default="publics.json",
+#             help="[default: publics.json] Path for where to store the computed public inputs for proving and verifying"
+#     )
+#     v_parser.add_argument(
+#             "--proof",
+#             default="proof.json",
+#             help="[default: proof.json] Path for where to store the computed proof"
+#     )
+#     v_parser.set_defaults(func=verify)
+# 
+# 
+#     args = global_parser.parse_args()
+#     # calls the command
+#     args.func(args)     

+ 72 - 0
bin/zkrunner/opcodes.no-nipoint.zk

@@ -0,0 +1,72 @@
+constant "Opcodes" {
+	EcFixedPointShort VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
+	EcFixedPointBase NULLIFIER_K,
+}
+
+witness "Opcodes" {
+	Base value,
+	Scalar value_blind,
+
+	Base blind,
+
+	Base a,
+	Base b,
+
+	Base secret,
+
+	# EcNiPoint pubkey,
+	# Base ephem_secret,
+
+	Uint32 leaf_pos,
+	MerklePath path,
+
+	Base cond,
+}
+
+circuit "Opcodes" {
+	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit = ec_add(vcv, vcr);
+	value_commit_x = ec_get_x(value_commit);
+	value_commit_y = ec_get_y(value_commit);
+	constrain_instance(ec_get_x(value_commit));
+	constrain_instance(ec_get_y(value_commit));
+
+	vcv2 = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr2 = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit2 = ec_add(vcv2, vcr2);
+	constrain_equal_point(value_commit, value_commit2);
+
+	one = witness_base(1);
+	two = witness_base(2);
+	c = poseidon_hash(one, two, blind);
+	constrain_instance(c);
+
+	d = poseidon_hash(one, blind, ec_get_x(value_commit), ec_get_y(value_commit));
+	constrain_instance(d);
+
+	d2 = poseidon_hash(one, blind, ec_get_x(value_commit2), ec_get_y(value_commit2));
+	constrain_equal_base(d, d2);
+
+	range_check(64, a);
+	range_check(253, b);
+	less_than_strict(a, b);
+	less_than_loose(a, b);
+
+	root = merkle_root(leaf_pos, path, c);
+	constrain_instance(root);
+
+	public = ec_mul_base(secret, NULLIFIER_K);
+	constrain_instance(ec_get_x(public));
+	constrain_instance(ec_get_y(public));
+
+	bool_check(one);
+
+	# ephem_public = ec_mul_var_base(ephem_secret, pubkey);
+	# constrain_instance(ec_get_x(ephem_public));
+	# constrain_instance(ec_get_y(ephem_public));
+
+	out = cond_select(cond, a, b);
+	constrain_instance(out);
+}

+ 72 - 0
bin/zkrunner/opcodes.zk

@@ -0,0 +1,72 @@
+constant "Opcodes" {
+	EcFixedPointShort VALUE_COMMIT_VALUE,
+	EcFixedPoint VALUE_COMMIT_RANDOM,
+	EcFixedPointBase NULLIFIER_K,
+}
+
+witness "Opcodes" {
+	Base value,
+	Scalar value_blind,
+
+	Base blind,
+
+	Base a,
+	Base b,
+
+	Base secret,
+
+	EcNiPoint pubkey,
+	Base ephem_secret,
+
+	Uint32 leaf_pos,
+	MerklePath path,
+
+	Base cond,
+}
+
+circuit "Opcodes" {
+	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit = ec_add(vcv, vcr);
+	value_commit_x = ec_get_x(value_commit);
+	value_commit_y = ec_get_y(value_commit);
+	constrain_instance(ec_get_x(value_commit));
+	constrain_instance(ec_get_y(value_commit));
+
+	vcv2 = ec_mul_short(value, VALUE_COMMIT_VALUE);
+	vcr2 = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
+	value_commit2 = ec_add(vcv2, vcr2);
+	constrain_equal_point(value_commit, value_commit2);
+
+	one = witness_base(1);
+	two = witness_base(2);
+	c = poseidon_hash(one, two, blind);
+	constrain_instance(c);
+
+	d = poseidon_hash(one, blind, ec_get_x(value_commit), ec_get_y(value_commit));
+	constrain_instance(d);
+
+	d2 = poseidon_hash(one, blind, ec_get_x(value_commit2), ec_get_y(value_commit2));
+	constrain_equal_base(d, d2);
+
+	range_check(64, a);
+	range_check(253, b);
+	less_than_strict(a, b);
+	less_than_loose(a, b);
+
+	root = merkle_root(leaf_pos, path, c);
+	constrain_instance(root);
+
+	public = ec_mul_base(secret, NULLIFIER_K);
+	constrain_instance(ec_get_x(public));
+	constrain_instance(ec_get_y(public));
+
+	bool_check(one);
+
+	ephem_public = ec_mul_var_base(ephem_secret, pubkey);
+	constrain_instance(ec_get_x(ephem_public));
+	constrain_instance(ec_get_y(ephem_public));
+
+	out = cond_select(cond, a, b);
+	constrain_instance(out);
+}

+ 194 - 0
bin/zkrunner/zkrunner.py

@@ -0,0 +1,194 @@
+#!/usr/bin/env python3
+
+from argparse import ArgumentParser
+from darkfi_sdk_py.affine import Affine
+from darkfi_sdk_py.base import Base
+from darkfi_sdk_py.scalar import Scalar
+from darkfi_sdk_py.proof import Proof
+from darkfi_sdk_py.proving_key import ProvingKey
+from darkfi_sdk_py.point import Point
+from darkfi_sdk_py.verifying_key import VerifyingKey
+from darkfi_sdk_py.zk_circuit import ZkCircuit
+from darkfi_sdk_py.zk_binary import ZkBinary
+from time import time
+from sys import getsizeof
+
+def insert_heap(heap, element):
+    print(f"Heap before: {heap}, element: {element}")
+    heap.append(element)
+
+def insert_publics(publics, element):
+    print(f"Publics before: {publics}, element: {element}")
+    publics.append(element)
+   
+def get_publics(statements, witnesses, constant_count, literals):
+    # Python heap for executing zk statements
+    heap = [None] * constant_count + witnesses
+    publics = []
+    for stmt in statements:
+        print('---------------- BEGIN ------------------')
+        print(f"Statement: {stmt}")
+        opcode, args = stmt[0], stmt[1]
+        if opcode == 'BaseAdd':
+            a = heap[args[0][1]]
+            b = heap[args[1][1]]
+            insert_heap(heap, a.add(b))
+        elif opcode == 'BaseMul':
+            a = heap[args[0][1]]
+            b = heap[args[1][1]]
+            insert_heap(heap, a.mul(b))
+        elif opcode == 'BaseSub':
+            a = heap[args[0][1]]
+            b = heap[args[1][1]]
+            insert_heap(heap, a.sub(b))
+        elif opcode == 'EcAdd':
+            a = heap[args[0][1]]
+            b = heap[args[1][1]]
+            insert_heap(heap, a.add(b))
+        elif opcode == 'EcMul':
+            a = heap[args[0][1]]
+            insert_heap(heap, Point.mul_r_generator(a))
+        elif opcode in {'EcMulBase', 'EcMulVarBase'}:
+            i = args[0][1]
+            base = heap[i]
+            product = Point.mul_base(base)
+            insert_heap(heap, product)
+        elif opcode == 'EcMulShort':
+            value = heap[args[0][1]]
+            insert_heap(heap, Point.mul_short(value))
+        elif opcode == 'EcGetX':
+            i = args[0][1]
+            point = heap[i] 
+            x, _ = point.to_affine().coordinates()
+            insert_heap(heap, x)
+        elif opcode == 'EcGetY':
+            i = args[0][1]
+            point = heap[i] 
+            _, y = point.to_affine().coordinates()
+            insert_heap(heap, y)
+        elif opcode == 'PoseidonHash':
+            messages = [heap[m[1]] for m in args]
+            insert_heap(heap, Base.poseidon_hash(messages))
+        elif opcode == 'MerkleRoot':
+            i = heap[args[0][1]]
+            p = heap[args[1][1]]
+            a = heap[args[2][1]]
+            insert_heap(heap, Base.merkle_root(i, p, a))
+        elif opcode == 'ConstrainInstance':
+            i = args[0][1]
+            element = heap[i] 
+            insert_publics(publics, element)
+        elif opcode == 'WitnessBase':
+            type = args[0][0]
+            assert type == 'Lit', f"type should LitType instead of {type}"
+            print(args)
+            i = args[0][1]
+            element = int(literals[i][1]) # (LitType, Lit)
+            base = Base(element)
+            insert_heap(heap, base)        
+        elif opcode == 'CondSelect':
+            cnd = heap[args[0][1]]
+            thn = heap[args[1][1]]
+            els = heap[args[2][1]]
+            assert cnd.eq(Base(0)) or cnd.eq(Base(1)), "Failed bool check"
+            res = thn if cnd.eq(Base(1)) else els
+            insert_heap(heap, res)
+        elif opcode in IGNORED_OPCODES:
+            print(f"Processed opcode: {opcode}")
+        else:
+            print(f"Missing implementation: {opcode}")
+    
+    print("-------------------- END --------------------")
+
+    print("-----------------------------------")
+    print(f"Publics: {publics}")
+    print("-----------------------------------")
+    
+    return publics
+
+def bincode_data(bincode):
+    with open(bincode, "rb") as f:
+        bincode = f.read()
+        zkbin = ZkBinary.decode(bincode)
+        return {"zkbin": zkbin,
+                "namespace": zkbin.namespace(),
+                "witnesses": zkbin.witnesses(),
+                "constant_count": zkbin.constant_count(),
+                "statements": zkbin.opcodes(),
+                "literals": zkbin.literals()}
+    
+IGNORED_OPCODES = {
+    'Noop',
+    'RangeCheck',
+    'LessThanStrict',
+    'LessThanLoose',
+    'BoolCheck',
+    'ConstrainEqualBase',
+    'ConstrainEqualPoint',
+    'DebugPrint'
+}
+K = 13
+
+if __name__ ==  "__main__":
+
+    ##### Script inputs #####
+
+    bincode_path = "opcodes.no-nipoint.zk.bin"
+    # bincode_path = "../../example/simple.zk.bin"
+    bincode_data_ = bincode_data(bincode_path)
+    zkbin, statements, constant_count, literals = bincode_data_['zkbin'], bincode_data_['statements'], bincode_data_['constant_count'], bincode_data_['literals']
+    witnesses = [
+        Base(3),
+        Scalar(4),
+        Base(5),
+        Base(6),
+        Base(7),
+        Base(8),
+        10,
+        [Base(42)] * 32,
+        Base(1),
+    ]
+    
+    ##### Proving #####
+    
+    print("Making public inputs based off witnesses......")
+    publics = get_publics(statements, witnesses, constant_count, literals)
+    
+    print("Witnessing into prover's circuit.....")
+    zkcircuit = ZkCircuit(zkbin)
+    zkcircuit.witness_base(witnesses[0])
+    zkcircuit.witness_scalar(witnesses[1])
+    zkcircuit.witness_base(witnesses[2])
+    zkcircuit.witness_base(witnesses[3])
+    zkcircuit.witness_base(witnesses[4])
+    zkcircuit.witness_base(witnesses[5])
+    zkcircuit.witness_u32(witnesses[6])
+    zkcircuit.witness_merkle_path(witnesses[7])
+    zkcircuit.witness_base(witnesses[8])
+    zkcircuit = zkcircuit.build(zkbin)
+    
+    print("Making proving key.....")
+    start = time()
+    proving_key = ProvingKey.build(K, zkcircuit)
+    print(f"Time for making proving key: {time() - start}")
+    
+    print("Proving.....")
+    start = time()
+    proof = Proof.create(proving_key, [zkcircuit], publics)
+    print(f"Time for proving: {time() - start}")
+    
+    
+    ##### Verifiying #####
+    
+    zkcircuit_v = zkcircuit.verifier_build(zkbin)
+    
+    print(f"Making verifying key.....")
+    start = time()
+    verifying_key = VerifyingKey.build(K, zkcircuit_v)
+    print(f"Time for making verifying key: {time() - start}")
+    
+    print("Verifying.....")
+    start = time()
+    proof.verify(verifying_key, publics)
+    print(f"Time for verifying {time() - start}")
+