Multiplicación de Conocimiento Cero de Polinomios
Usando el esquema de compromiso polinómico del capítulo anterior, un probador (prover) puede demostrar que tiene tres polinomios , y y probar que .
Para que este algoritmo funcione, el verificador debe creer que las evaluaciones polinómicas son correctas – pero esto es algo que mostramos en el capítulo anterior. La mayoría de los pasos aquí son simplemente repetir el algoritmo de compromiso polinómico que hicimos previamente.
A un alto nivel, el probador se compromete con , y y envía los compromisos al verificador. Luego, el verificador elige un valor aleatorio para como y le pide al probador que evalúe los polinomios en . El verificador entonces comprueba que las evaluaciones se hicieron correctamente y que la evaluación de multiplicada por la evaluación de es igual a la evaluación de .
Por ejemplo, supongamos que el primer polinomio es y el segundo es . Entonces . El verificador puede muestrear cualquier valor aleatorio , y el resultado del producto será . El gráfico a continuación muestra un ejemplo donde el verificador elige :

El verificador luego comprobaría que y aceptaría la afirmación del probador.
El lema de Schwartz-Zippel establece que si entonces la probabilidad de que para algún valor aleatorio es menor que donde es el grado máximo de los dos polinomios y es el orden del campo finito. Si ( mucho menor que ), entonces la probabilidad de que sea un punto de intersección de dos polinomios no iguales es insignificante.
Específicamente, supongamos que el probador está mintiendo y . En ese caso, para un aleatorio, con una probabilidad extremadamente alta. Si , entonces y solo se intersectan en como máximo puntos (el grado máximo ya sea de o de ), y es extremadamente improbable que el verificador elija aleatoriamente un que sea uno de los puntos de intersección.
Para tener una idea de la escala, en nuestro caso es 2, pero el orden de la curva de nuestras curvas elípticas (y por lo tanto el orden del campo) es de aproximadamente . Así que si , entonces la probabilidad de es , la cual es insignificantemente pequeña.
Ahora describimos el algoritmo en detalle, y luego mostramos una optimización.
Pasos para probar el conocimiento de la multiplicación de polinomios
El probador se compromete con dos polinomios lineales (de grado 1) , , un polinomio cuadrático (de grado 2) , y envía los compromisos al verificador. El verificador responde con un valor aleatorio , y el probador evalúa , , y junto con las pruebas de evaluación . El verificador comprueba que todos los polinomios fueron evaluados correctamente y que .
Configuración
El probador y el verificador acuerdan los puntos de la curva elíptica y con una relación de logaritmo discreto desconocida (es decir, los puntos se eligen aleatoriamente).
El probador se compromete con , y
El probador crea tres polinomios:
Por lo tanto, necesitan producir un total de 7 compromisos de Pedersen para cada uno de los coeficientes, lo que requerirá siete términos de cegamiento
El probador envía al verificador.
El verificador genera un escalar aleatorio
… y envía el elemento del campo al probador.
El probador evalúa los tres polinomios y crea tres pruebas
El probador sustituye en los polinomios y calcula la suma de los términos de cegamiento de los compromisos de los coeficientes polinómicos cuando se aplica .
El probador envía los valores al verificador. Ten en cuenta que todos estos son elementos del campo, no puntos de la curva elíptica.
Paso final de verificación
El verificador comprueba que cada uno de los polinomios fue evaluado correctamente y que la evaluación de es el producto de la evaluación de y . Las primeras tres comprobaciones son pruebas de que el polinomio se evaluó correctamente con respecto al compromiso de los coeficientes, y la última comprobación verifica que la salida de los polinomios tiene la relación de producto afirmada.
Cuando expandimos los términos, vemos que se equilibran si el probador fue honesto:
Optimización: enviando menos compromisos
En el primer paso, el probador envía 7 puntos de la curva elíptica, y en el paso final, el verificador comprueba 4 igualdades. Podemos mejorar el algoritmo para enviar solo 5 puntos de la curva elíptica y hacer 3 comprobaciones de igualdad.
Esto se hace poniendo los coeficientes constantes de y en un solo compromiso y los coeficientes lineales de esos polinomios en un compromiso separado. A modo de recordatorio, definimos y como
así que y son los coeficientes constantes, y y son los coeficientes lineales.
Esto es similar a cómo comprometeríamos un vector. En cierto sentido, estamos comprometiendo los coeficientes constantes como un vector y los coeficientes lineales como otro vector.
Configuración
Durante la configuración, ahora necesitamos 3 puntos de la curva elíptica: , y .
Compromiso polinómico
Nota que los coeficientes de se aplican a y los coeficientes de se aplican a . El probador envía al verificador, quien responde con .
Evaluación polinómica
, , , y se calculan como antes, pero la prueba de evaluaciones para y , que antes eran y , se combinan en una sola: .
Verificación final
La comprobación se expande a
Con cierta reorganización en el lado izquierdo, podemos ver que la comprobación de igualdad verifica simultáneamente que tanto como fueron evaluados correctamente.
Como otra forma de ver la comprobación , considera la siguiente visualización:
Multiplicación de Conocimiento Cero de Escalares
Nuestra prueba de que multiplicamos dos polinomios correctamente para obtener un tercero puede ser usada para probar que multiplicamos dos escalares para obtener un tercero. No se necesitan cambios en el algoritmo, solo un cambio menor en la semántica (cómo interpretamos los compromisos).
Supongamos que queremos probar que llevamos a cabo la multiplicación .
Planteamiento del problema
es un compromiso de y , y es un compromiso de donde . Deseamos probar que y están comprometidos según lo afirmado sin revelar , o .
Solución
La idea a alto nivel es que un escalar puede convertirse en un polinomio agregando un término lineal elegido arbitrariamente, por ejemplo, se convierte en y se convierte en . y son elegidos aleatoriamente por el probador.
Cuando los polinomios y se multiplican entre sí, la multiplicación de ocurre “dentro” de la multiplicación polinómica.
Recuerda que el probador comienza el algoritmo enviando compromisos:
Simplemente cambiamos la “interpretación” de de ser los términos constantes de los polinomios a las constantes y que estamos multiplicando. Cambiamos a para reflejar el cambio de interpretación como un compromiso de en la multiplicación que estamos tratando de probar que hicimos correctamente, es decir, .
Ejercicio: Completa el código Python faltante para implementar el algoritmo descrito anteriormente.
from py_ecc.bn128 import G1, multiply, add, FQ, eq
from py_ecc.bn128 import curve_order as p
import random
def random_element():
return random.randint(0, p)
# these EC points have unknown discrete logs:
G = (FQ(6286155310766333871795042970372566906087502116590250812133967451320632869759), FQ(2167390362195738854837661032213065766665495464946848931705307210578191331138))
H = (FQ(13728162449721098615672844430261112538072166300311022796820929618959450231493), FQ(12153831869428634344429877091952509453770659237731690203490954547715195222919))
B = (FQ(12848606535045587128788889317230751518392478691112375569775390095112330602489), FQ(18818936887558347291494629972517132071247847502517774285883500818572856935411))
# utility function
def addd(A, B, C):
return add(A, add(B, C))
# scalar multiplication example: multiply(G, 42)
# EC addition example: add(multiply(G, 42), multiply(G, 100))
# remember to do all arithmetic modulo p
def commit(a, sL, b, sR, alpha, beta, gamma, tau_1, tau_2):
pass
# return (A, S, V, T1, T2)
def evaluate(f_0, f_1, f_2, u):
return (f_0 + f_1 * u + f_2 * u**2) % p
def prove(blinding_0, blinding_1, blinding_2, u):
# fill this in
# return pi
pass
## step 0: Prover and verifier agree on G and B
## step 1: Prover creates the commitments
a = ...
b = ...
sL = ...
sR = ...
t1 = ...
t2 = ...
### blinding terms
alpha = ...
beta = ...
gamma = ...
tau_1 = ...
tau_2 = ...
A, S, V, T1, T2 = commit(a, sL, b, sR, alpha, beta, gamma, tau_1, tau_2)
## step 2: Verifier picks u
u = ...
## step 3: Prover evaluates l(u), r(u), t(u) and creates evaluation proofs
l_u = evaluate(a, sL, 0, u)
r_u = evaluate(b, sR, 0, u)
t_u = evaluate(a*b, t1, t2, u)
pi_lr = prove(alpha, beta, 0, u)
pi_t = prove(gamma, tau_1, tau_2, u)
## step 4: Verifier accepts or rejects
assert t_u == (l_u * r_u) % p, "tu != lu*ru"
assert eq(add(A, multiply(S, u)), addd(multiply(G, l_u), multiply(H, r_u), multiply(B, pi_lr))), "l_u or r_u not evaluated correctly"
assert eq(add(multiply(G, t_u), multiply(B, pi_t)), addd(V, multiply(T1, u), multiply(T2, u**2 % p))), "t_u not evaluated correctly"
Aprende más
Este artículo es parte de una serie sobre Bulletproof ZKPs.