
Las Crónicas de ZK: Argumentos de Producto Interno
El próximo paso en nuestro viaje nos llevará a ver un nuevo e importante mecanismo de compromiso, diseñado para polinomios
La última vez, construimos nuestro primer esquema de compromiso polinomial completamente funcional.
Es uno de esos mecanismos que, al menos para mí, se siente extremadamente elegante y hasta un poco mágico. O sea, para comprometerte necesitas un único elemento de grupo, para probar una apertura necesitas un único elemento de grupo, y todo queda atado usando una prolijísima igualdad de emparejamientos.
Lo que por supuesto muestra el poder de los emparejamientos, aprovechando la capacidad de mover el álgebra de un lado a otro para que todas las piezas encajen perfectamente.
Vamos a seguir construyendo sobre esas capacidades, pero por ahora, quiero dejar esto planteado desde el vamos: KZG no es la única forma de abordar los compromisos polinomiales.
Hasta ahora, nos acercamos a este objetivo a través de la narrativa de la "evaluación en un punto oculto". ¿Pero qué pasaría si te dijera que podemos tomar una perspectiva radicalmente distinta?

Ah sí. Hoy, vamos a trabajar con vectores en lugar de polinomios. Y aunque suena desconcertante, en retrospectiva no debería ser tan loco: ya cubrimos compromisos vectoriales usando compromisos de Pedersen, después de todo. Sin embargo, vamos a ver una estrategia distinta (más específica, por así decirlo), y una vez que empecemos a meternos de lleno, va a tener más sentido por qué siquiera nos interesaría explorar otras opciones en primer lugar.
Toca entonces sumergirnos en un nuevo mecanismo, que responde al nombre de argumentos de producto interno. Los ingredientes, al menos en principio, son bastante distintos, pero los resultados son igual de poderosos.
Así que, para arrancar, ¡veamos cuáles son esos ingredientes!
El Producto Interno
Si la memoria no me falla, esta es la primera vez en la serie que menciono a los productos internos, así que es lógico empezar es con su definición.
Dados dos vectores y (vamos a escribir los vectores en negrita), su producto interno o producto punto se define como la suma de la multiplicación componente a componente de y . Si eso suena como un trabalenguas, quizás escribirlo como una expresión ayude - así que para vectores de longitud , obtendríamos:
Aunque simples en apariencia, los productos internos son extremadamente útiles por varias razones.
Por ejemplo, proveen una medida de colinealidad entre vectores. Un producto interno de significa que los vectores son completamente ortogonales.
En nuestro caso, nos interesa el aspecto de la computación verificable, así que los productos internos deben servir algún propósito en torno a probar afirmaciones. Y, efectivamente, hay un mecanismo muy bonito que podemos construir a su alrededor.
Argumentos de Producto Interno
La idea central se presenta mejor con un ejemplo simple. Supongamos que tenemos un vector secreto y un vector público , y de alguna forma nos comprometimos a a usando un esquema de compromiso de vectores como un compromiso de Pedersen.
Con esto, afirmamos que:
¿Cómo podemos, como probadores, convencer a un verificador de que esta afirmación es verdadera, sin revelar ?
Esta es la esencia de lo que hace un argumento de producto interno (o IPA, por sus siglas en inglés): le permite a un probador convencer a un verificador de que un vector comprometido satisface una relación lineal específica, mientras mantiene el vector oculto. Como nunca se revela, el IPA debe incorporar el compromiso a en la mezcla, para que el probador quede atado al valor de dicho vector.
En esa afirmación de recién, mencioné dos cosas importantes: los IPAs deberían ser tanto ocultantes (el vector permanece oculto) como vinculantes (la prueba solo debería funcionar para ). Y a esta altura, sabemos bien que esas son características de los esquemas de compromiso ...entonces, ¿cuál es la trampa?
Bueno, para ser precisos, los IPAs son realmente más un sistema de prueba o argumento que un esquema de compromiso, como veremos pronto. Sin embargo, hay una conexión linda y simple que podemos hacer con los esquemas de compromiso polinomial - tanto así, que los IPAs realmente pueden usarse como PCS (¡entre otras cosas!).
El secreto yace en una conexión algo inesperada: los productos internos están estrechamente relacionados con las evaluaciones polinomiales.

¿Cómo, te estarás preguntando? Bueno, cuando tenemos un polinomio de grado , podemos escribir sus coeficientes como un vector . También podemos tomar algún valor , y escribir un vector con todas sus potencias, así que obtenemos . Ahora... ¿qué pasa si tomamos el producto interno de estos vectores?
¡Ajá! Acabamos de toparnos con una forma alternativa de escribir una evaluación polinomial como un producto interno - ¡lo que significa que podemos usar IPAs para probar la correctitud de evaluaciones polinomiales!
¡Muy bien entonces! Con eso ya resuelto, y ahora que entendemos mejor con qué estamos lidiando, es hora de ensuciarnos un poco las manos, y ver uno de estos argumentos en acción.
Prepárense - ¡se va a poner un poco desprolijo!
Bulletproofs
Quizás la realización más conocida de un argumento de producto interno aparece en las Bulletproofs.

Popularizaron un IPA particularmente elegante que comprime una afirmación de producto interno en una prueba de tamaño logarítmico, lo cual es notable. Y lo hacen de una forma transparente, sin requerir un setup confiable.
Antes de empezar, quiero tomarme un momento para aclarar algo de entrada. Uno de los principales casos de uso de Bulletproofs son las pruebas de rango: probar que un número pertenece a un rango dado entre y algún otro entero .
¡Así fue en realidad como los enmarqué la primera vez que escribí sobre este tema!
Pero en realidad, la construcción central que usan puede aplicarse a cualquier producto interno. Simplemente pasa que uno de los componentes principales de una prueba de rango es un producto interno en sí mismo, ¡así que la construcción encaja naturalmente con ese propósito!
Esta vez entonces, quiero enfocarme mucho más en la técnica general en lugar de en un caso de uso específico.
Solo tengan en cuenta que este tipo de sistema de argumento puede ser útil en múltiples escenarios.
Dicho esto, ¡pasemos a la acción!
Notación
De nuevo vamos a estar lidiando con un vector secreto de elementos de un campo finito. Sin embargo, nuestra historia arranca un poco distinto esta vez: asumamos que nos comprometimos a este vector a través de un compromiso de Pedersen:
Usando un vector de generadores para algún grupo .
A simple vista, esto no se parece mucho a un producto interno. Pero hay una transformación útil que podemos aplicar acá: ¡un isomorfismo! Si pensamos en como un grupo aditivo en lugar de uno multiplicativo, y si convenientemente omitimos el factor de cegado, obtendríamos algo como esto:
Y eso... ¡se parece bastante a un producto interno! El único problema es que involucra elementos de un campo finito de un lado, y elementos de grupo del otro. Así que acá, vamos a abusar un poco de la notación, y aún así escribir el compromiso de Pedersen como:
Solo omitimos el factor de cegado (blinding factor) por simplicidad en nuestro tratamiento, ¡pero tengan en cuenta que debería tenerse en cuenta en la construcción completa!
La Construcción Central
Muy bien, con ese pequeño cambio en la notación, el objetivo de este IPA es muy simple de enunciar: el probador quiere probar el conocimiento de un vector de forma que el compromiso esté correctamente formado, mientras también satisface una relación de producto interno específica.
Para hacer que esto funcione, vamos a necesitar hacer uso de un recurso que hemos explotado una y otra vez a lo largo de la serie: ¡la recursión!

La idea principal es que el probador va a intentar convencer al verificador de que la afirmación inicial está atada a una afirmación más pequeña (en este caso, de la mitad del tamaño) de la misma forma que la original. A esto lo llamamos plegado o doblado (folding).
En el sentido de que, casi literalmente, plegamos (doblamos) la afirmación por la mitad.
Todo lo que hacemos es repetir este proceso hasta llegar a una condición que sea directamente verificable - ¡y eso es prácticamente todo!
Sin embargo (e importantemente), tenemos que hacer que el argumento sea robusto, es decir, que sea imposiblemente difícil para el probador hacer trampa. Para reforzar esto, hacemos lo que hemos estado haciendo a lo largo de todos los sistemas de prueba que vimos hasta ahora: pedimos desafíos del verificador. Al usarlos en el proceso de plegado en sí, atamos al probador a esa impredecibilidad, que es el ingrediente clave que previene la falsificación de pruebas.
Y esto se hace de la siguiente manera: primero, el probador divide tanto como limpiamente en dos mitades:
Por simplicidad, vamos a asumir que la longitud de los vectores es una potencia de , para que siempre podamos dividirlos a la mitad a medida que avanzamos por los pasos recursivos.
Lo que significa que también podemos dividir trivialmente nuestro producto interno original mediante:
También va a calcular un par de términos cruzados, cuya utilidad está en el centro de la construcción de hoy: el verificador va a necesitarlos durante la verificación para poder reconstruir algunas cosas por su cuenta.
Solo confíen en mí por ahora - ¡sin estos términos cruzados, no habría Bulletproofs en absoluto!
De acá en adelante, va a tener lugar un pequeño protocolo interactivo entre el probador y el verificador. Primero, el probador va a enviar los valores de los términos cruzados (que son elementos de grupo). Tengan en cuenta que el verificador no conoce , así que no podrían haber calculado estos valores por su cuenta.
El verificador va a responder con un desafío . Y acá viene la parte divertida: el probador va a usar este desafío para actualizar su vector , mientras que el verificador puede simultáneamente actualizar el compromiso para que coincida con el vector actualizado.
Decimos que hacen esta actualización de forma homomórfica.
Bueno... esto suena más fácil de lo que realmente es. Es decir, las actualizaciones del vector son bastante directas, aunque no va a quedar inmediatamente claro por qué elegimos la forma particular, que se ve así:
Pero, ¿cómo diablos actualizamos el compromiso? No es como si el verificador pudiera dividirlo a la mitad ni nada por el estilo...
Vayamos paso a paso. Lo que necesitamos es una forma de hacer que el verificador actualice su compromiso a y , a este nuevo par de vectores y . Así que intentemos ver cómo se vería eso, usando la linealidad de los productos internos:
Podemos mover esas hacia afuera de los productos internos usando la linealidad una vez más:
¿Oh? ¿Qué es eso? ¡Como por arte de magia, parece que los términos cruzados que calculamos antes aparecieron! Y con algunos reacomodos finales, llegamos a la forma final, prolija:
¡Et voilà! ¡Usando los términos cruzados, el verificador es capaz de obtener un compromiso al vector plegado por su cuenta!
Como un detalle sutil pero importante, el verificador también puede plegar por su cuenta, ya que es público. Esto es crucial para la verificación final.
Y créanlo o no, ¡eso es prácticamente todo lo que hay! Una vez que somos capaces de reducir una afirmación a la mitad de su tamaño, podemos seguir haciendo esto recursivamente con nuevos desafíos, hasta plegar el vector original en un único elemento de campo . La verificación final para el verificador es simplemente:
Y si eso se cumple, entonces podemos decir con bastante confianza que, ¡el probador conocía el vector original !
Monedas Públicas
En este punto, necesitamos formalizar algo que hemos estado usando todo este tiempo sin darle un nombre concreto: la aleatoriedad pública.
Noten que la derivación del compromiso plegado incluye . Este valor es público, pero se elige en exactamente el momento correcto para prevenir que el probador haga trampa. Es decir, el probador no tiene forma de influenciar la derivación a menos que conozca de antemano.
Y si recuerdan de nuestro análisis de solidez en el protocolo de verificación de la suma, esto es extremadamente improbable. Efectivamente, esta es una forma de fijar el resultado de un paso previo antes de empezar el siguiente.
Este uso de desafíos aleatorios es tan central para el análisis de solidez de los protocolos interactivos, que reciben un nombre especial: monedas públicas. Y, por supuesto, llamamos a los protocolos que usan esta estrategia protocolos de moneda pública.
A diferencia de los protocolos de moneda privada, donde la selección aleatoria no se hace pública.
Los protocolos de moneda pública proveen fuertes garantías de solidez, y encima de eso, son conceptualmente muy limpios: la transcripción completa del protocolo está determinada por la combinación de los mensajes del probador y los desafíos públicos del verificador. No hay trucos ocultos.
Y para colmo, como toda la aleatoriedad es pública, ¡podemos usar la transformada de Fiat-Shamir para eliminar la interacción por completo!
¡Así que eso es la esencia de Bulletproofs en pocas palabras! La idea del plegado nos deja con un prolijo sistema de argumento que no requiere setup confiable, y corre en rondas.
Tengan en cuenta que omitimos el factor de cegado para un tratamiento matemático más simple, ¡pero la construcción completa debería incluirlo para que el compromiso sea ocultante!
Podríamos terminar la historia acá. Sin embargo, no quiero que se queden con la impresión de que Bulletproofs es el único IPA disponible, y que solo usamos este IPA o KZG para evaluaciones polinomiales.
Hay mucho más por ahí. Así que para darles un pequeño vistazo, quiero hablar brevemente sobre otra técnica que se ubica en un punto medio entre las técnicas de las que hablamos hasta ahora.
Dory
Vamos a ver brevemente Dory, un PCS un poco más moderno que también se apoya en emparejamientos, pero los usa con un propósito distinto al de KZG. Porque Dory es, en su esencia, ¡un argumento de producto interno!
Pero no nos confundamos: es muy distinto en naturaleza a los Bulletproofs, por cómo maneja los productos internos en su totalidad.
Productos de Emparejamiento Interno
¡Usa emparejamientos!
¡Sí! En lugar de usar compromisos al estilo Pedersen, Dory se apoya en compromisos basados en emparejamientos. Lo hace aprovechando lo que se llama un producto de emparejamiento interno (o IPP, por sus siglas en inglés), que es lo que vamos a ver a continuación.
El escenario es similar al de KZG: necesitamos tres grupos , , y de orden primo , un emparejamiento entre ellos, y un campo finito .
Con esto, podemos definir:
¿Por qué definirlo de esta manera? Bueno, noten que acá, y son vectores de elementos de grupo, no elementos de un campo finito. Por lo tanto, no podemos usar el producto interno estándar (ni el ligeramente modificado que usamos en Bulletproofs), porque no hay forma de multiplicar elementos de dos grupos distintos entre sí.
¡Pero podemos lograr un efecto similar usando el emparejamiento!
Lo lindo de esto es que se comporta exactamente como un producto interno: ¡tiene las mismas propiedades lineales, gracias a la bilinealidad de los emparejamientos!
¡Salvo por un isomorfismo, hasta podríamos representar el IPP como una suma en lugar de un producto! Es solo que estamos asumiendo que es un grupo multiplicativo.
Así que, de acá en adelante, vamos a abusar de la notación una vez más, y simplemente escribir la expresión para representar .
Ahora bien, no es como que Dory sea simplemente Bulletproofs con esteroides de emparejamiento. Todavía se construye sobre el paradigma del producto interno, sí, y todavía se apoya en la recursión, pero hay un cambio fundamental en qué se está comprimiendo y cómo se está comprimiendo.
Esto va a quedar mucho más claro luego de decir esto: el compromiso a algún vector ahora se calcula usando una clave de compromiso que ya no es pública:
Esa es la diferencia clave, en realidad. Como no es pública, el verificador no puede plegarla por su cuenta, y por lo tanto el proceso de plegado al estilo Bulletproofs no puede aplicarse. En otras palabras, el objeto que definía el compromiso en Bulletproofs era público y plegable. ¡Acá, es parte de la estructura misma del compromiso!
Noten que en Bulletproofs, la propiedad ocultante del compromiso se otorga mediante el uso de un factor de cegado explícito . Acá, no necesitamos ese factor.
En cambio, lo ocultante surge de la estructura de la clave de compromiso y de las suposiciones de dificultad subyacentes del grupo de emparejamiento. No necesitamos preocuparnos por los detalles acá, sin embargo. Lo importante de saber es que esto sigue siendo ocultante, ¡solo que por razones distintas!
"Pero Frank" - se estarán preguntando -, "¿cómo podemos probar algo sobre el compromiso si no es pública?". ¡Esa es exactamente la pregunta correcta! Y es la diferencia estructural clave en Dory: ¡tenemos que realizar un paso de setup transparente para hacer que todo esto funcione!
El Setup Transparente
Para entender cómo funcionaría esto, intentemos pasar juntos por un par de rondas de plegado.
La ronda procedería de forma similar a Bulletproofs: el probador divide el vector y la clave de compromiso , envía los términos cruzados al verificador, y el verificador responde con un desafío . El probador entonces pliega tanto como normalmente en y , y el verificador pliega el compromiso .
Hasta acá, esto se ve familiar. Sin embargo, hay un problema: ¡el verificador no puede plegar , porque simplemente no la conoce!

Sin embargo, no hay necesidad de entrar en pánico: hay luz al final del túnel. ¡Todo lo que necesitamos es un poco de preprocesamiento!
La solución a este asunto es también recurrir a un IPA, pero para la clave de compromiso. Sé que suena desafiante, pero en realidad es bastante simple.
Para esto, el probador selecciona un vector de elementos de grupo aleatorios que llamaremos , que necesita tener la mitad de la longitud de . Luego, el probador divide en sus porciones izquierda y derecha, y calcula un par de compromisos IPP a cada mitad:
¿Por qué? Porque estos ahora pueden compartirse con el verificador, y pueden usarlos para calcular un compromiso a :
Tomémonos un momento para apreciar lo que acaba de pasar acá: el verificador empezó esta ronda con un único compromiso en forma de una igualdad de producto interno, y terminó con dos productos internos:
Una pequeña sutileza acá: originalmente era un vector de elementos de , pero acá, se está tratando como un vector de elementos de .
Estrictamente hablando, este paso asume un emparejamiento simétrico. ¡De lo contrario, tenemos que llevar registro de en qué grupo vive cada vector!
Entonces, ¿qué hacemos a partir de acá? Bueno, ¡probamos el conocimiento de las aperturas de ambos compromisos! Es decir, ¡podemos correr exactamente la misma estrategia de plegado que acabamos de usar para los dos compromisos en paralelo!
Por brevedad, simplemente delineemos cómo continúa esto. Si fuéramos a pasar por otra ronda, el probador necesitaría enviar nuevos valores precomputados asociados con una nueva clave de compromiso de la mitad de la longitud de . Y a su vez, esto agregaría otro producto interno más para que el probador verifique.
Y el objetivo es simple, incluso si el camino hasta ahí no lo es: al comprometerse a la clave de compromiso en sí en cada ronda, el verificador puede mantenerse sincronizado con el plegado del probador. ¡Simplemente rastrean compromisos de compromisos, todo el camino hacia abajo!
Esto continúa hasta que se pliega en un único valor , momento en el cual el probador puede enviar tanto como , y todas las claves de compromiso intermedias plegadas .
Finalmente, el verificador chequea igualdades de producto, ¡y si todas se cumplen, entonces aceptan la prueba!
Entonces, ¿dónde está el preprocesamiento? ¡Es la selección de todos los vectores , y el cómputo de todos los valores ! ¡Todos estos pueden calcularse de antemano, así que el probador puede hacer esto una vez por producto interno, y enviarlo al verificador antes de que envíen ningún desafío!
Transformar esto en un esquema de compromiso polinomial requiere un poco de trabajo extra, pero no necesitamos preocuparnos por eso ahora.
Además, Dory tiene varios detalles más para cubrir, y eso nos distraería bastante. ¡Solo las ideas centrales ya son más que suficiente para que sigamos avanzando hacia el territorio de ZK!
Resumen
Madre santa. Este sí que fue un artículo un poco hardcore, sin duda.

No hay forma de endulzar esto. Las matemáticas son complicadas, y van a seguir siéndolo.
¡Perdón!
Lo que me importa más es enfocarme en el panorama general, y construir intuición sobre las ideas centrales que conforman la computación verificable.
En ese sentido, hoy fue muy instructivo, ya que exploramos la idea del plegado en el contexto de una familia de técnicas realmente importante: los IPAs. Y vimos cómo son mucho más que solo una forma alternativa de pensar sobre los compromisos polinomiales: son más bien un patrón de diseño para sistemas de prueba.
Hay un aspecto sutil y crucial que solo insinuamos implícitamente: ¿son estos argumentos de conocimiento cero?
En Bulletproofs, el probador convence al verificador de que una relación de producto interno se cumple, aparentemente sin revelar ninguna información sobre el vector oculto.
Eso no es un accidente, pero tampoco es automáticamente obvio. Entonces, ¿cómo cuantificamos esto?
Y así, en el próximo artículo, vamos a tomarnos un descanso de las construcciones y finalmente enfocarnos en la propiedad central de toda nuestra exploración: el conocimiento cero.
¡Porque probar algo eficientemente es solo la mitad de la historia!
¡Espero que estén entusiasmados por el próximo artículo! ¡Nos vemos ahí!
¿Te resultó útil este contenido?
Apoya a Frank Mangone enviando un café. Todos los ingresos van directamente al autor.