EIP-1271: Firma y verificación de firmas de contratos inteligentes
El estándar EIP-1271(opens in a new tab) permite que los contratos inteligentes verifiquen las firmas.
En este tutorial, damos una visión general de las firmas digitales, los antecedentes de EIP-1271 y la implementación específica de EIP-1271 utilizada por Safe(opens in a new tab) (anteriormente Gnosis Safe). En conjunto, esto puede servir como punto de partida para implementar el EIP-1271 en sus propios contratos.
¿Qué es una firma?
En este contexto, una firma (más precisamente, una «firma digital») es un mensaje, además de ser algún tipo de prueba de que el mensaje provino de una persona/remitente/dirección específica.
Por ejemplo, una firma digital podría tener el siguiente aspecto:
- Mensaje: "Quiero iniciar sesión en este sitio web con mi cartera de Ethereum."
- Firmante: Mi dirección es
0x000...
- Prueba: Aquí hay alguna prueba de que yo,
0x000...
, en realidad creé todo este mensaje (esto es generalmente algo criptográfico).
Es importante tener en cuenta que una firma digital incluye tanto un «mensaje» como una «firma».
¿Por qué? Por ejemplo, si me diera un contrato para firmar, y luego cortara la página de firma y le devolviera solo mis firmas sin el resto del contrato, el contrato no sería válido.
De la misma manera, ¡una firma digital no significa nada sin un mensaje asociado!
¿Por qué existe EIP-1271?
Con el fin de crear una firma digital para su uso en cadenas de bloques basadas en Ethereum, por lo general se necesita una clave privada secreta que nadie más sabe. Esto es lo que hace que su firma sea suya (nadie más puede crear la misma firma sin el conocimiento de la clave secreta).
Su cuenta de Ethereum (p. ej., su cuenta de propiedad externa/EOA) tiene una clave privada asociada a esta y suele utilizarse cuando un sitio web o una DApp le solicita una firma (p. ej., para «Iniciar sesión con Ethereum»).
Una aplicación puede verificar una firma(opens in a new tab) creada utilizando una biblioteca de terceros como ethers.js sin conocer su clave privada(opens in a new tab) y tener plena confianza en que tú usted creó la firma.
De hecho, porque las cuentas de propiedad externa utilizan la criptografía de clave pública, ¡estas pueden ser generadas y verificadas fuera de la cadena! Así es como funciona la votación DAO sin gas: en vez de enviar votos en la cadena, las firmas digitales pueden ser creadas y verificadas fuera de la cadena utilizando bibliotecas criptográficas.
Mientras las cuentas de propiedad externa tienen una clave privada, las cuentas de contratos inteligentes no tienen ningún tipo de clave privada o secreta (entonces el «Inicio de sesión con Ethereum», entre otros, no funcionan de manera nativa sin las cuentas de contratos inteligentes).
El problema que EIP-1271 busca solucionar: ¿cómo podemos decir que la firma de un contrato inteligente es válida si el contrato inteligente no tiene algún «secreto» que pueda incorporar en la firma?
¿Cómo funciona EIP-1271?
Los contratos inteligentes no tienen claves privadas que se puedan utilizar para firmar mensajes. ¿Entonces cómo podemos saber si una firma es auténtica?
Bueno, ¡una idea es que podemos preguntar al contrato inteligente si una firma es auténtica!
Lo que EIP-1271 hace es normalizar esta idea «preguntando» a un contrato inteligente si una firma proporcionada es válida.
Un contrato donde se implementa EIP-1271 debe tener una función llamada isValidSignature
que tiene lugar en un mensaje y una firma. Luego, el contrato puede ejecutar algo de lógica de validación (aquí la especificación no hace valer algo en específico) y luego devuelve un valor indicando si la firma es válida o no.
Si isValidSignature
devuelve un resultado válido, es como si el contrato hablara y dijera: «¡Sí, apruebo esta firma + mensaje!».
Interfaz
Aquí está la interfaz exacta en la especificación EIP-1271 (hablaremos sobre el parámetro _hash
abajo, pero por ahora, considérleo como el mensaje que se está verificando):
1pragma solidity ^0.5.0;23contract ERC1271 {45 // bytes4(keccak256("isValidSignature(bytes32,bytes)")6 bytes4 constant internal MAGICVALUE = 0x1626ba7e;78 /**9 * @dev Should return whether the signature provided is valid for the provided hash10 * @param _hash Hash of the data to be signed11 * @param _signature Signature byte array associated with _hash12 *13 * MUST return the bytes4 magic value 0x1626ba7e when function passes.14 * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)15 * MUST allow external calls16 */17 function isValidSignature(18 bytes32 _hash,19 bytes memory _signature)20 public21 view22 returns (bytes4 magicValue);23}Mostrar todo
Implementación EIP-1271 de ejemplo: Safe
Los contratos pueden implementar isValidSignature
de varias maneras, la especificación no dice mucho sobre la implementación exacta.
Un contrato destacado que implementa EIP-1271 es Safe (previamente Gnosis Safe).
En el código de Safe, isValidSignature
se implementa(opens in a new tab) para que las firmas se creen y comprueben en de dos maneras:(opens in a new tab):
- Mensajes en cadena
- Creación: un propietario seguro crea una nueva transacción segura para «firmar» un mensaje, pasando el mensaje como dato en la transacción. Una vez que suficientes propietarios han firmado la transacción para alcanzar el umbral multifirma, la transacción se transmite y se ejecuta. En la transacción, hay una función segura activada cuando añade el mensaje a un listado de mensajes «aprobados».
- Verificación: activa
isValidSignature
en el contrato Safe y pasa el mensaje por verificar como el parámetro del mensaje y un valor vacío para el parámetro de firma(opens in a new tab) (ej:0x
). Safe verá que el parámetro de firma está vacío y en vez de verificar criptográficamente la firma, sabrá que debe continuar y revisar si el mensaje se encuentra en el listado de mensajes «aprobados».
- Mensajes fuera de la cadena:
- Creación: un propietario seguro crea un mensaje fuera de cadena, luego solicita a otros propietarios seguros que cada uno firme el mensaje individualmente hasta que haya una cantidad suficiente de firmas para superar el umbral de aprobación multifirma.
- Verificación: activa
isValidSignature
. En el parámetro mensaje, pasa el mensaje por verificar. En el parámetro firma, pasa las firmas de cada propietario seguro de manera concatenada. Safe revisará que haya suficientes firmas para cumplir el umbral y que cada firma es válida. Si lo es, devuelve un valor indicando que la verificación de la firma se realizó correctamente.
¿Qué es exactamente el parámetro _hash
? ¿Por qué no pasar el mensaje completo?
Puede que haya notado que la función isValidSignature
en la interfaz EIP-1271(opens in a new tab) no toma el mensaje en sí mismo, en su lugar toma un parámetro _hash
. Esto significa que en vez de pasar completamente el mensaje arbitrariamente a isValidSignature
, para un hash de 32-bytes del mensaje (generalmente keccak256).
Cada byte de Calldata, p- ej., datos del parámetro función pasados a la función de un contrato inteligente, cuesta 16 gas (4 gas en si hay cero bytes)(opens in a new tab), por lo que puede ahorrar mucho gas si el mensaje es largo.
Especificaciones previas de EIP-1271
Hay especificaciones EIP-1271 en varias partes que tienen una función isValidSignature
con un primer parámetro del tipo bytes
(longitud arbitraria, en vez de una longitud fija de bytes32
) y el parámetro nombre message
. Esto es una versión anterior(opens in a new tab) del estándar EIP-1271.
¿Cómo debería implementar EIP-1271 en mis propios contratos?
Aquí la especificación tiene un final muy abierto. La implementación Safe tiene algunas buenas ideas:
- Puede considerar firmas EOA del «propietario» del contrato como válidas.
- Podría almacenar un listado de mensajes del aprobador y sólo considerar aquellos que sean válidos.
A fin de cuentas, ¡depende de usted, porque es el desarrollador del contrato!
Conclusión
EIP-1271(opens in a new tab) es un estándar versátil que permite a los contratos inteligentes verificar firmas. Esto abre la puerta para que los contratos inteligentes actúen más como EOA, por ejemplo, proporcionando una manera de «Iniciar sesión con Ethereum» para trabajar con contratos inteligentes, e implementarse de varias manereas (Safe tiene una implementación interesante y nada convencional que debería considerar).
Última edición: @nhsz(opens in a new tab), 15 de agosto de 2023