mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
Merge branch 'master' into feature/lisp
This commit is contained in:
@@ -4,7 +4,7 @@ except ImportError:
|
||||
from itertools import izip_longest as zip_longest
|
||||
import fractions
|
||||
|
||||
from numbertype import *
|
||||
from .numbertype import *
|
||||
|
||||
# strip all copies of elt from the end of the list
|
||||
def strip(L, elt):
|
||||
|
||||
103
scripts/zk/3.3-encrypted-polynomial.py
Normal file
103
scripts/zk/3.3-encrypted-polynomial.py
Normal file
@@ -0,0 +1,103 @@
|
||||
from bls_py import bls12381
|
||||
from bls_py import pairing
|
||||
from bls_py import ec
|
||||
from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
# Section 3.3.4 from "Why and How zk-SNARK Works"
|
||||
|
||||
def rand_scalar():
|
||||
return random.randrange(1, bls12381.q)
|
||||
|
||||
#x = rand_scalar()
|
||||
#y = ec.y_for_x(x)
|
||||
|
||||
g1 = ec.generator_Fq(bls12381)
|
||||
g2 = ec.generator_Fq2(bls12381)
|
||||
|
||||
null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
|
||||
assert g1 + null == g1
|
||||
|
||||
#################################
|
||||
# Verifier (trusted setup)
|
||||
#################################
|
||||
|
||||
# samples a random value (a secret)
|
||||
s = rand_scalar()
|
||||
|
||||
# calculates encryptions of s for all powers i in 0 to d
|
||||
# E(s^i) = g^s^i
|
||||
d = 10
|
||||
encrypted_powers = [
|
||||
g1 * (s**i) for i in range(d)
|
||||
]
|
||||
|
||||
# evaluates unencrypted target polynomial with s: t(s)
|
||||
target = (s - 1) * (s - 2)
|
||||
|
||||
# encrypted values of s provided to the prover
|
||||
# Actual values of s are toxic waste and discarded
|
||||
|
||||
#################################
|
||||
# Prover
|
||||
#################################
|
||||
|
||||
# E(p(s)) = p(s)G
|
||||
# = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
|
||||
# = s^3 G - 3 s^2 G + 2 s G
|
||||
# E(h(s)) = sG
|
||||
# t(s) = s^2 - 3s + 2
|
||||
# E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
|
||||
|
||||
# Lets test these manually:
|
||||
|
||||
e_s = encrypted_powers
|
||||
e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
|
||||
e_h_s = e_s[1]
|
||||
t_s = s**2 - 3*s + 2
|
||||
assert t_s == target
|
||||
assert e_p_s == e_h_s * t_s
|
||||
|
||||
#############################
|
||||
|
||||
# x^3 - 3x^2 + 2x
|
||||
main_poly = np.poly1d([1, -3, 2, 0])
|
||||
# (x - 1)(x - 2)
|
||||
target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
|
||||
|
||||
# Calculates polynomial h(x) = p(x) / t(x)
|
||||
cofactor, remainder = main_poly / target_poly
|
||||
assert remainder == np.poly1d([0])
|
||||
|
||||
# Using encrypted powers and coefficients, evaluates
|
||||
# E(p(s)) and E(h(s))
|
||||
def evaluate(poly, encrypted_powers):
|
||||
coeffs = list(poly.coef)[::-1]
|
||||
result = null
|
||||
for power, coeff in zip(encrypted_powers, coeffs):
|
||||
#print(coeff, power)
|
||||
coeff = int(coeff)
|
||||
# I have to do this for some strange reason
|
||||
# Because if coeff is negative and I do += power * coeff
|
||||
# then it gives me a different result than what I expect
|
||||
if coeff < 0:
|
||||
result -= power * (-coeff)
|
||||
else:
|
||||
result += power * coeff
|
||||
return result
|
||||
|
||||
encrypted_poly = evaluate(main_poly, encrypted_powers)
|
||||
assert encrypted_poly == e_p_s
|
||||
encrypted_cofactor = evaluate(cofactor, encrypted_powers)
|
||||
|
||||
# resulting g^p and g^h are provided to the verifier
|
||||
|
||||
#################################
|
||||
# Verifier
|
||||
#################################
|
||||
|
||||
# Last check that p = t(s) h
|
||||
|
||||
assert encrypted_poly == encrypted_cofactor * target
|
||||
|
||||
119
scripts/zk/3.4-restricted-polynomial.py
Normal file
119
scripts/zk/3.4-restricted-polynomial.py
Normal file
@@ -0,0 +1,119 @@
|
||||
from bls_py import bls12381
|
||||
from bls_py import pairing
|
||||
from bls_py import ec
|
||||
from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
# Section 3.4 from "Why and How zk-SNARK Works"
|
||||
|
||||
def rand_scalar():
|
||||
return random.randrange(1, bls12381.q)
|
||||
|
||||
#x = rand_scalar()
|
||||
#y = ec.y_for_x(x)
|
||||
|
||||
g1 = ec.generator_Fq(bls12381)
|
||||
g2 = ec.generator_Fq2(bls12381)
|
||||
|
||||
null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
|
||||
assert g1 + null == g1
|
||||
|
||||
#################################
|
||||
# Verifier (trusted setup)
|
||||
#################################
|
||||
|
||||
# samples a random value (a secret)
|
||||
s = rand_scalar()
|
||||
|
||||
# calculate the shift
|
||||
a = rand_scalar()
|
||||
|
||||
# calculates encryptions of s for all powers i in 0 to d
|
||||
# E(s^i) = g^s^i
|
||||
d = 10
|
||||
encrypted_powers = [
|
||||
g1 * (s**i) for i in range(d)
|
||||
]
|
||||
encrypted_shifted_powers = [
|
||||
g1 * (a * s**i) for i in range(d)
|
||||
]
|
||||
|
||||
# evaluates unencrypted target polynomial with s: t(s)
|
||||
target = (s - 1) * (s - 2)
|
||||
|
||||
# encrypted values of s provided to the prover
|
||||
# Actual values of s are toxic waste and discarded
|
||||
|
||||
#################################
|
||||
# Prover
|
||||
#################################
|
||||
|
||||
# E(p(s)) = p(s)G
|
||||
# = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
|
||||
# = s^3 G - 3 s^2 G + 2 s G
|
||||
# E(h(s)) = sG
|
||||
# t(s) = s^2 - 3s + 2
|
||||
# E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
|
||||
|
||||
# Lets test these manually:
|
||||
|
||||
e_s = encrypted_powers
|
||||
e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
|
||||
e_h_s = e_s[1]
|
||||
t_s = s**2 - 3*s + 2
|
||||
assert t_s == target
|
||||
assert e_p_s == e_h_s * t_s
|
||||
|
||||
e_as = encrypted_shifted_powers
|
||||
e_p_as = e_as[3] - 3 * e_as[2] + 2 * e_as[1]
|
||||
assert e_p_s * a == e_p_as
|
||||
|
||||
#############################
|
||||
|
||||
# x^3 - 3x^2 + 2x
|
||||
main_poly = np.poly1d([1, -3, 2, 0])
|
||||
# (x - 1)(x - 2)
|
||||
target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
|
||||
|
||||
# Calculates polynomial h(x) = p(x) / t(x)
|
||||
cofactor, remainder = main_poly / target_poly
|
||||
assert remainder == np.poly1d([0])
|
||||
|
||||
# Using encrypted powers and coefficients, evaluates
|
||||
# E(p(s)) and E(h(s))
|
||||
def evaluate(poly, encrypted_powers):
|
||||
coeffs = list(poly.coef)[::-1]
|
||||
result = null
|
||||
for power, coeff in zip(encrypted_powers, coeffs):
|
||||
#print(coeff, power)
|
||||
coeff = int(coeff)
|
||||
# I have to do this for some strange reason
|
||||
# Because if coeff is negative and I do += power * coeff
|
||||
# then it gives me a different result than what I expect
|
||||
if coeff < 0:
|
||||
result -= power * (-coeff)
|
||||
else:
|
||||
result += power * coeff
|
||||
return result
|
||||
|
||||
encrypted_poly = evaluate(main_poly, encrypted_powers)
|
||||
assert encrypted_poly == e_p_s
|
||||
encrypted_cofactor = evaluate(cofactor, encrypted_powers)
|
||||
|
||||
# Alpha shifted powers
|
||||
encrypted_shift_poly = evaluate(main_poly, encrypted_shifted_powers)
|
||||
|
||||
# resulting g^p and g^h are provided to the verifier
|
||||
|
||||
#################################
|
||||
# Verifier
|
||||
#################################
|
||||
|
||||
# Last check that p = t(s) h
|
||||
|
||||
assert encrypted_poly == encrypted_cofactor * target
|
||||
|
||||
# Verify (g^p)^a == g^p'
|
||||
|
||||
assert encrypted_poly * a == encrypted_shift_poly
|
||||
129
scripts/zk/3.5-zero-knowledge.py
Normal file
129
scripts/zk/3.5-zero-knowledge.py
Normal file
@@ -0,0 +1,129 @@
|
||||
from bls_py import bls12381
|
||||
from bls_py import pairing
|
||||
from bls_py import ec
|
||||
from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
# Section 3.5 from "Why and How zk-SNARK Works"
|
||||
|
||||
def rand_scalar():
|
||||
return random.randrange(1, bls12381.q)
|
||||
|
||||
#x = rand_scalar()
|
||||
#y = ec.y_for_x(x)
|
||||
|
||||
g1 = ec.generator_Fq(bls12381)
|
||||
g2 = ec.generator_Fq2(bls12381)
|
||||
|
||||
null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
|
||||
assert g1 + null == g1
|
||||
|
||||
#################################
|
||||
# Verifier (trusted setup)
|
||||
#################################
|
||||
|
||||
# samples a random value (a secret)
|
||||
s = rand_scalar()
|
||||
|
||||
# calculate the shift
|
||||
a = rand_scalar()
|
||||
|
||||
# calculates encryptions of s for all powers i in 0 to d
|
||||
# E(s^i) = g^s^i
|
||||
d = 10
|
||||
encrypted_powers = [
|
||||
g1 * (s**i) for i in range(d)
|
||||
]
|
||||
encrypted_shifted_powers = [
|
||||
g1 * (a * s**i) for i in range(d)
|
||||
]
|
||||
|
||||
# evaluates unencrypted target polynomial with s: t(s)
|
||||
target = (s - 1) * (s - 2)
|
||||
|
||||
# encrypted values of s provided to the prover
|
||||
# Actual values of s are toxic waste and discarded
|
||||
|
||||
#################################
|
||||
# Prover
|
||||
#################################
|
||||
|
||||
# delta shift
|
||||
delta = rand_scalar()
|
||||
|
||||
# E(p(s)) = p(s)G
|
||||
# = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
|
||||
# = s^3 G - 3 s^2 G + 2 s G
|
||||
# E(h(s)) = sG
|
||||
# t(s) = s^2 - 3s + 2
|
||||
# E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
|
||||
|
||||
# Lets test these manually:
|
||||
|
||||
e_s = encrypted_powers
|
||||
e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
|
||||
e_h_s = e_s[1]
|
||||
t_s = s**2 - 3*s + 2
|
||||
# exponentiate with delta
|
||||
e_p_s *= delta
|
||||
e_h_s *= delta
|
||||
assert t_s == target
|
||||
assert e_p_s == e_h_s * t_s
|
||||
|
||||
e_as = encrypted_shifted_powers
|
||||
e_p_as = e_as[3] - 3 * e_as[2] + 2 * e_as[1]
|
||||
# exponentiate with delta
|
||||
e_p_as *= delta
|
||||
assert e_p_s * a == e_p_as
|
||||
|
||||
#############################
|
||||
|
||||
# x^3 - 3x^2 + 2x
|
||||
main_poly = np.poly1d([1, -3, 2, 0])
|
||||
# (x - 1)(x - 2)
|
||||
target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
|
||||
|
||||
# Calculates polynomial h(x) = p(x) / t(x)
|
||||
cofactor, remainder = main_poly / target_poly
|
||||
assert remainder == np.poly1d([0])
|
||||
|
||||
# Using encrypted powers and coefficients, evaluates
|
||||
# E(p(s)) and E(h(s))
|
||||
def evaluate(poly, encrypted_powers):
|
||||
coeffs = list(poly.coef)[::-1]
|
||||
result = null
|
||||
for power, coeff in zip(encrypted_powers, coeffs):
|
||||
#print(coeff, power)
|
||||
coeff = int(coeff)
|
||||
# I have to do this for some strange reason
|
||||
# Because if coeff is negative and I do += power * coeff
|
||||
# then it gives me a different result than what I expect
|
||||
if coeff < 0:
|
||||
result -= power * (-coeff)
|
||||
else:
|
||||
result += power * coeff
|
||||
# Add delta to the result
|
||||
# Free extra obfuscation to the polynomial
|
||||
return result * delta
|
||||
|
||||
encrypted_poly = evaluate(main_poly, encrypted_powers)
|
||||
assert encrypted_poly == e_p_s
|
||||
encrypted_cofactor = evaluate(cofactor, encrypted_powers)
|
||||
|
||||
# Alpha shifted powers
|
||||
encrypted_shift_poly = evaluate(main_poly, encrypted_shifted_powers)
|
||||
|
||||
# resulting g^p and g^h are provided to the verifier
|
||||
|
||||
#################################
|
||||
# Verifier
|
||||
#################################
|
||||
|
||||
# Last check that p = t(s) h
|
||||
|
||||
assert encrypted_poly == encrypted_cofactor * target
|
||||
|
||||
# Verify (g^p)^a == g^p'
|
||||
|
||||
assert encrypted_poly * a == encrypted_shift_poly
|
||||
152
scripts/zk/3.6-trusted-setup.py
Normal file
152
scripts/zk/3.6-trusted-setup.py
Normal file
@@ -0,0 +1,152 @@
|
||||
from bls_py import bls12381
|
||||
from bls_py import pairing
|
||||
from bls_py import ec
|
||||
from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
# Section 3.6 from "Why and How zk-SNARK Works"
|
||||
|
||||
def rand_scalar():
|
||||
return random.randrange(1, bls12381.q)
|
||||
|
||||
#x = rand_scalar()
|
||||
#y = ec.y_for_x(x)
|
||||
|
||||
g1 = ec.generator_Fq(bls12381)
|
||||
g2 = ec.generator_Fq2(bls12381)
|
||||
|
||||
null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
|
||||
assert g1 + null == g1
|
||||
null2 = ec.AffinePoint(Fq2.zero(Q), Fq2.zero(Q), True, bls12381)
|
||||
assert null2 + g2 == g2
|
||||
|
||||
#################################
|
||||
# Verifier (trusted setup)
|
||||
#################################
|
||||
|
||||
# samples a random value (a secret)
|
||||
s = rand_scalar()
|
||||
|
||||
# calculate the shift
|
||||
a = rand_scalar()
|
||||
|
||||
# calculates encryptions of s for all powers i in 0 to d
|
||||
# E(s^i) = g^s^i
|
||||
d = 10
|
||||
encrypted_powers = [
|
||||
g1 * (s**i) for i in range(d)
|
||||
]
|
||||
encrypted_powers_g2 = [
|
||||
g2 * (s**i) for i in range(d)
|
||||
]
|
||||
encrypted_shifted_powers = [
|
||||
g1 * (a * s**i) for i in range(d)
|
||||
]
|
||||
|
||||
# evaluates unencrypted target polynomial with s: t(s)
|
||||
target = (s - 1) * (s - 2)
|
||||
# CRS = common reference string = trusted setup parameters
|
||||
target_crs = g1 * target
|
||||
alpha_crs = g2 * a
|
||||
|
||||
# Proving key = (encrypted_powers, encrypted_shifted_powers)
|
||||
# Verify key = (target_crs, alpha_crs)
|
||||
|
||||
# encrypted values of s provided to the prover
|
||||
# Actual values of s are toxic waste and discarded
|
||||
|
||||
#################################
|
||||
# Prover
|
||||
#################################
|
||||
|
||||
# delta shift
|
||||
delta = rand_scalar()
|
||||
|
||||
# E(p(s)) = p(s)G
|
||||
# = c_d s^d G + ... + c_1 s^1 G + c_0 s^0 G
|
||||
# = s^3 G - 3 s^2 G + 2 s G
|
||||
# E(h(s)) = sG
|
||||
# t(s) = s^2 - 3s + 2
|
||||
# E(h(s)) t(s) = s^3 G - 3 s^2 G + 2 s G
|
||||
|
||||
# Lets test these manually:
|
||||
|
||||
e_s = encrypted_powers
|
||||
e_p_s = e_s[3] - 3 * e_s[2] + 2 * e_s[1]
|
||||
e_h_s = e_s[1]
|
||||
t_s = s**2 - 3*s + 2
|
||||
# exponentiate with delta
|
||||
e_p_s *= delta
|
||||
e_h_s *= delta
|
||||
assert t_s == target
|
||||
assert e_p_s == e_h_s * t_s
|
||||
|
||||
e_as = encrypted_shifted_powers
|
||||
e_p_as = e_as[3] - 3 * e_as[2] + 2 * e_as[1]
|
||||
# exponentiate with delta
|
||||
e_p_as *= delta
|
||||
assert e_p_s * a == e_p_as
|
||||
|
||||
#############################
|
||||
|
||||
# x^3 - 3x^2 + 2x
|
||||
main_poly = np.poly1d([1, -3, 2, 0])
|
||||
# (x - 1)(x - 2)
|
||||
target_poly = np.poly1d([1, -1]) * np.poly1d([1, -2])
|
||||
|
||||
# Calculates polynomial h(x) = p(x) / t(x)
|
||||
cofactor, remainder = main_poly / target_poly
|
||||
assert remainder == np.poly1d([0])
|
||||
|
||||
# Using encrypted powers and coefficients, evaluates
|
||||
# E(p(s)) and E(h(s))
|
||||
def evaluate(poly, encrypted_powers, identity):
|
||||
coeffs = list(poly.coef)[::-1]
|
||||
result = identity
|
||||
for power, coeff in zip(encrypted_powers, coeffs):
|
||||
#print(coeff, power)
|
||||
coeff = int(coeff)
|
||||
# I have to do this for some strange reason
|
||||
# Because if coeff is negative and I do += power * coeff
|
||||
# then it gives me a different result than what I expect
|
||||
if coeff < 0:
|
||||
result -= power * (-coeff)
|
||||
else:
|
||||
result += power * coeff
|
||||
# Add delta to the result
|
||||
# Free extra obfuscation to the polynomial
|
||||
return result * delta
|
||||
|
||||
encrypted_poly = evaluate(main_poly, encrypted_powers, null)
|
||||
assert encrypted_poly == e_p_s
|
||||
encrypted_cofactor = evaluate(cofactor, encrypted_powers_g2, null2)
|
||||
|
||||
# Alpha shifted powers
|
||||
encrypted_shift_poly = evaluate(main_poly, encrypted_shifted_powers, null)
|
||||
|
||||
# resulting g^p and g^h are provided to the verifier
|
||||
|
||||
# proof = (encrypted_poly, encrypted_cofactor, encrypted_shift_poly)
|
||||
|
||||
#################################
|
||||
# Verifier
|
||||
#################################
|
||||
|
||||
# Last check that p = t(s) h
|
||||
|
||||
# Check polynomial cofactors:
|
||||
#assert encrypted_poly == encrypted_cofactor * target
|
||||
# e(g^p, g) == e(g^t, g^h)
|
||||
res1 = pairing.ate_pairing(encrypted_poly, g2)
|
||||
res2 = pairing.ate_pairing(target_crs, encrypted_cofactor)
|
||||
assert res1 == res2
|
||||
|
||||
# Verify (g^p)^a == g^p'
|
||||
# Check polynomial restriction:
|
||||
|
||||
res1 = pairing.ate_pairing(encrypted_shift_poly, g2)
|
||||
res2 = pairing.ate_pairing(encrypted_poly, alpha_crs)
|
||||
assert res1 == res2
|
||||
#assert encrypted_poly * a == encrypted_shift_poly
|
||||
|
||||
146
scripts/zk/4.4-proof-of-operation.py
Normal file
146
scripts/zk/4.4-proof-of-operation.py
Normal file
@@ -0,0 +1,146 @@
|
||||
from bls_py import bls12381
|
||||
from bls_py import pairing
|
||||
from bls_py import ec
|
||||
from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
# Section 3.6 from "Why and How zk-SNARK Works"
|
||||
|
||||
def rand_scalar():
|
||||
return random.randrange(1, bls12381.q)
|
||||
|
||||
#x = rand_scalar()
|
||||
#y = ec.y_for_x(x)
|
||||
|
||||
g1 = ec.generator_Fq(bls12381)
|
||||
g2 = ec.generator_Fq2(bls12381)
|
||||
|
||||
null = ec.AffinePoint(Fq(Q, 0), Fq(Q, 1), True, bls12381)
|
||||
assert g1 + null == g1
|
||||
null2 = ec.AffinePoint(Fq2.zero(Q), Fq2.zero(Q), True, bls12381)
|
||||
assert null2 + g2 == g2
|
||||
|
||||
#################################
|
||||
# Verifier (trusted setup)
|
||||
#################################
|
||||
|
||||
# samples a random value (a secret)
|
||||
s = rand_scalar()
|
||||
|
||||
# calculate the shift
|
||||
a = rand_scalar()
|
||||
|
||||
# calculates encryptions of s for all powers i in 0 to d
|
||||
# E(s^i) = g^s^i
|
||||
d = 10
|
||||
encrypted_powers = [
|
||||
g1 * (s**i) for i in range(d)
|
||||
]
|
||||
encrypted_powers_g2 = [
|
||||
g2 * (s**i) for i in range(d)
|
||||
]
|
||||
encrypted_shifted_powers = [
|
||||
g1 * (a * s**i) for i in range(d)
|
||||
]
|
||||
encrypted_shifted_powers_g2 = [
|
||||
g2 * (a * s**i) for i in range(d)
|
||||
]
|
||||
|
||||
# evaluates unencrypted target polynomial with s: t(s)
|
||||
target = (s - 1)
|
||||
# CRS = common reference string = trusted setup parameters
|
||||
target_crs = g1 * target
|
||||
alpha_crs = g2 * a
|
||||
alpha_crs_g1 = g1 * a
|
||||
|
||||
# Proving key = (encrypted_powers, encrypted_shifted_powers)
|
||||
# Verify key = (target_crs, alpha_crs)
|
||||
|
||||
# encrypted values of s provided to the prover
|
||||
# Actual values of s are toxic waste and discarded
|
||||
|
||||
#################################
|
||||
# Prover
|
||||
#################################
|
||||
|
||||
left_poly = np.poly1d([3])
|
||||
right_poly = np.poly1d([2])
|
||||
out_poly = np.poly1d([6])
|
||||
|
||||
# x^3 - 3x^2 + 2x
|
||||
main_poly = left_poly * right_poly - out_poly
|
||||
# (x - 1)
|
||||
target_poly = np.poly1d([1, -1])
|
||||
|
||||
# Calculates polynomial h(x) = p(x) / t(x)
|
||||
cofactor, remainder = main_poly / target_poly
|
||||
assert remainder == np.poly1d([0])
|
||||
|
||||
# Using encrypted powers and coefficients, evaluates
|
||||
# E(p(s)) and E(h(s))
|
||||
def evaluate(poly, encrypted_powers, identity):
|
||||
coeffs = list(poly.coef)[::-1]
|
||||
result = identity
|
||||
for power, coeff in zip(encrypted_powers, coeffs):
|
||||
#print(coeff, power)
|
||||
coeff = int(coeff)
|
||||
# I have to do this for some strange reason
|
||||
# Because if coeff is negative and I do += power * coeff
|
||||
# then it gives me a different result than what I expect
|
||||
if coeff < 0:
|
||||
result -= power * (-coeff)
|
||||
else:
|
||||
result += power * coeff
|
||||
return result
|
||||
|
||||
assert left_poly * right_poly == out_poly
|
||||
|
||||
encrypted_left_poly = evaluate(left_poly, encrypted_powers, null)
|
||||
encrypted_right_poly = evaluate(right_poly, encrypted_powers_g2, null2)
|
||||
encrypted_out_poly = evaluate(out_poly, encrypted_powers, null)
|
||||
|
||||
#assert encrypted_poly == e_p_s
|
||||
encrypted_cofactor = evaluate(cofactor, encrypted_powers_g2, null2)
|
||||
|
||||
# Alpha shifted powers
|
||||
encrypted_shift_left_poly = evaluate(left_poly, encrypted_shifted_powers, null)
|
||||
encrypted_shift_right_poly = evaluate(right_poly, encrypted_shifted_powers_g2, null2)
|
||||
encrypted_shift_out_poly = evaluate(out_poly, encrypted_shifted_powers, null)
|
||||
|
||||
# resulting g^p and g^h are provided to the verifier
|
||||
|
||||
# proof = (encrypted_poly, encrypted_cofactor, encrypted_shift_poly)
|
||||
|
||||
#################################
|
||||
# Verifier
|
||||
#################################
|
||||
|
||||
# Last check that p = t(s) h
|
||||
|
||||
assert pairing.ate_pairing(2 * g1, g2) == pairing.ate_pairing(g1, g2) * pairing.ate_pairing(g1, g2)
|
||||
|
||||
# Verify (g^p)^a == g^p'
|
||||
# Check polynomial restriction:
|
||||
|
||||
def check_polynomial_restriction(encrypted_shift_poly, encrypted_poly):
|
||||
res1 = pairing.ate_pairing(encrypted_shift_poly, g2)
|
||||
res2 = pairing.ate_pairing(encrypted_poly, alpha_crs)
|
||||
assert res1 == res2
|
||||
|
||||
def check_polynomial_restriction_swapped(encrypted_shift_poly, encrypted_poly):
|
||||
res1 = pairing.ate_pairing(g1, encrypted_shift_poly)
|
||||
res2 = pairing.ate_pairing(alpha_crs_g1, encrypted_poly)
|
||||
assert res1 == res2
|
||||
|
||||
check_polynomial_restriction(encrypted_shift_left_poly, encrypted_left_poly)
|
||||
check_polynomial_restriction_swapped(encrypted_shift_right_poly, encrypted_right_poly)
|
||||
check_polynomial_restriction(encrypted_shift_out_poly, encrypted_out_poly)
|
||||
|
||||
# Valid operation check
|
||||
# e(g^l, g^r) == e(g^t, g^h) * e(g^o, g)
|
||||
res1 = pairing.ate_pairing(encrypted_left_poly, encrypted_right_poly)
|
||||
res2 = pairing.ate_pairing(target_crs, encrypted_cofactor) * \
|
||||
pairing.ate_pairing(encrypted_out_poly, g2)
|
||||
assert res1 == res2
|
||||
|
||||
30
scripts/zk/4.5.1-polynomial-interpolation.py
Normal file
30
scripts/zk/4.5.1-polynomial-interpolation.py
Normal file
@@ -0,0 +1,30 @@
|
||||
import numpy as np
|
||||
|
||||
def lagrange(points):
|
||||
result = np.poly1d([0])
|
||||
for i, (x_i, y_i) in enumerate(points):
|
||||
poly = np.poly1d([y_i])
|
||||
for j, (x_j, y_j) in enumerate(points):
|
||||
if i == j:
|
||||
continue
|
||||
poly *= np.poly1d([1, -x_j]) / (x_i - x_j)
|
||||
#print(poly)
|
||||
#print(poly(1), poly(2), poly(3))
|
||||
result += poly
|
||||
return result
|
||||
|
||||
left = lagrange([
|
||||
(1, 2), (2, 2), (3, 6)
|
||||
])
|
||||
print(left)
|
||||
|
||||
right = lagrange([
|
||||
(1, 1), (2, 3), (3, 2)
|
||||
])
|
||||
print(right)
|
||||
|
||||
out = lagrange([
|
||||
(1, 2), (2, 6), (3, 12)
|
||||
])
|
||||
print(out)
|
||||
|
||||
167
scripts/zk/4.5.2-multi-operation-polynomials.py
Normal file
167
scripts/zk/4.5.2-multi-operation-polynomials.py
Normal file
@@ -0,0 +1,167 @@
|
||||
from bls_py import bls12381
|
||||
from bls_py import pairing
|
||||
from bls_py import ec
|
||||
from bls_py.fields import Fq, Fq2, Fq6, Fq12, bls12381_q as Q
|
||||
from finite_fields.modp import IntegersModP
|
||||
from finite_fields.polynomial import polynomialsOver
|
||||
import random
|
||||
|
||||
n = bls12381.n
|
||||
|
||||
g1 = ec.generator_Fq(bls12381)
|
||||
g2 = ec.generator_Fq2(bls12381)
|
||||
|
||||
null = ec.AffinePoint(Fq(n, 0), Fq(n, 1), True, bls12381)
|
||||
assert null + g1 == g1
|
||||
null2 = ec.AffinePoint(Fq2.zero(n), Fq2.zero(n), True, bls12381)
|
||||
assert null2 + g2 == g2
|
||||
|
||||
mod_field = IntegersModP(n)
|
||||
poly = polynomialsOver(mod_field).factory
|
||||
|
||||
def lagrange(points):
|
||||
result = poly([0])
|
||||
for i, (x_i, y_i) in enumerate(points):
|
||||
p = poly([y_i])
|
||||
for j, (x_j, y_j) in enumerate(points):
|
||||
if i == j:
|
||||
continue
|
||||
p *= poly([-x_j, 1]) / (x_i - x_j)
|
||||
#print(poly)
|
||||
#print(poly(1), poly(2), poly(3))
|
||||
result += p
|
||||
return result
|
||||
|
||||
def poly_call(poly, x):
|
||||
result = mod_field(0)
|
||||
for degree, coeff in enumerate(poly):
|
||||
result += coeff * (x**degree)
|
||||
return result.n
|
||||
|
||||
left_points = [
|
||||
(1, 2), (2, 2), (3, 6)
|
||||
]
|
||||
left_poly = lagrange(left_points)
|
||||
#l = poly([2]) * poly([1, -1])
|
||||
print("Left:")
|
||||
print(left_poly)
|
||||
for x, y in left_points:
|
||||
assert poly_call(left_poly, x) == y
|
||||
|
||||
right_points = [
|
||||
(1, 1), (2, 3), (3, 2)
|
||||
]
|
||||
right_poly = lagrange(right_points)
|
||||
print("Right:")
|
||||
print(right_poly)
|
||||
for x, y in right_points:
|
||||
assert poly_call(right_poly, x) == y
|
||||
|
||||
out_points = [
|
||||
(1, 2), (2, 6), (3, 12)
|
||||
]
|
||||
out_poly = lagrange(out_points)
|
||||
print("Out:")
|
||||
print(out_poly)
|
||||
for x, y in out_points:
|
||||
assert poly_call(out_poly, x) == y
|
||||
|
||||
target_poly = poly([-1, 1]) * poly([-2, 1]) * poly([-3, 1])
|
||||
assert poly_call(target_poly, 1) == 0
|
||||
assert poly_call(target_poly, 2) == 0
|
||||
assert poly_call(target_poly, 3) == 0
|
||||
|
||||
main_poly = left_poly * right_poly - out_poly
|
||||
cofactor_poly = main_poly / target_poly
|
||||
|
||||
assert left_poly * right_poly - out_poly == target_poly * cofactor_poly
|
||||
|
||||
def rand_scalar():
|
||||
return random.randrange(1, bls12381.q)
|
||||
|
||||
#################################
|
||||
# Verifier (trusted setup)
|
||||
#################################
|
||||
|
||||
# samples a random value (a secret)
|
||||
toxic_scalar = rand_scalar()
|
||||
# calculate the shift
|
||||
alpha_shift = rand_scalar()
|
||||
|
||||
# calculates encryptions of s for all powers i in 0 to d
|
||||
# E(s^i) = g^s^i
|
||||
degree = 10
|
||||
enc_s1 = [
|
||||
g1 * (toxic_scalar**i) for i in range(degree)
|
||||
]
|
||||
enc_s2 = [
|
||||
g2 * (toxic_scalar**i) for i in range(degree)
|
||||
]
|
||||
enc_s1_shift = [
|
||||
g1 * (alpha_shift * toxic_scalar**i) for i in range(degree)
|
||||
]
|
||||
enc_s2_shift = [
|
||||
g2 * (alpha_shift * toxic_scalar**i) for i in range(degree)
|
||||
]
|
||||
|
||||
# evaluates unencrypted target polynomial with s: t(s)
|
||||
toxic_target = (toxic_scalar - 1) * (toxic_scalar - 2) * (toxic_scalar - 3)
|
||||
# CRS = common reference string = trusted setup parameters
|
||||
target_crs = g1 * toxic_target
|
||||
alpha_crs = g2 * alpha_shift
|
||||
alpha_crs_g1 = g1 * alpha_shift
|
||||
|
||||
# Proving key = (encrypted_powers, encrypted_shifted_powers)
|
||||
# Verify key = (target_crs, alpha_crs)
|
||||
|
||||
# encrypted values of s provided to the prover
|
||||
# Actual values of s are toxic waste and discarded
|
||||
|
||||
#################################
|
||||
# Prover
|
||||
#################################
|
||||
|
||||
# Using encrypted powers and coefficients, evaluates
|
||||
# E(p(s)) and E(h(s))
|
||||
def evaluate(poly, encrypted_powers, identity):
|
||||
result = identity
|
||||
for power, coeff in zip(encrypted_powers, poly):
|
||||
result += power * coeff.n
|
||||
return result
|
||||
|
||||
enc_left = evaluate(left_poly, enc_s1, null)
|
||||
enc_right = evaluate(right_poly, enc_s2, null2)
|
||||
enc_out = evaluate(out_poly, enc_s1, null)
|
||||
|
||||
enc_cofactor = evaluate(cofactor_poly, enc_s2, null2)
|
||||
|
||||
# Alpha shifted powers
|
||||
enc_left_shift = evaluate(left_poly, enc_s1_shift, null)
|
||||
enc_right_shift = evaluate(right_poly, enc_s2_shift, null2)
|
||||
enc_out_shift = evaluate(out_poly, enc_s1_shift, null)
|
||||
|
||||
#################################
|
||||
# Verifier
|
||||
#################################
|
||||
|
||||
def restrict_polynomial_g1(encrypted_shift_poly, encrypted_poly):
|
||||
res1 = pairing.ate_pairing(encrypted_shift_poly, g2)
|
||||
res2 = pairing.ate_pairing(encrypted_poly, alpha_crs)
|
||||
assert res1 == res2
|
||||
|
||||
def restrict_polynomial_g2(encrypted_shift_poly, encrypted_poly):
|
||||
res1 = pairing.ate_pairing(g1, encrypted_shift_poly)
|
||||
res2 = pairing.ate_pairing(alpha_crs_g1, encrypted_poly)
|
||||
assert res1 == res2
|
||||
|
||||
restrict_polynomial_g1(enc_left_shift, enc_left)
|
||||
restrict_polynomial_g2(enc_right_shift, enc_right)
|
||||
restrict_polynomial_g1(enc_out_shift, enc_out)
|
||||
|
||||
# Valid operation check
|
||||
# e(g^l, g^r) == e(g^t, g^h) * e(g^o, g)
|
||||
res1 = pairing.ate_pairing(enc_left, enc_right)
|
||||
res2 = pairing.ate_pairing(target_crs, enc_cofactor) * \
|
||||
pairing.ate_pairing(enc_out, g2)
|
||||
assert res1 == res2
|
||||
|
||||
Reference in New Issue
Block a user