Claves públicas de propietario y remitente de un contrato inteligente

Soy bastante nuevo en ethereum. Me gustaría saber si es posible escribir un contrato en el que pueda conocer la Ownerclave pública y la clave pública del remitente.

Por curiosidad, ¿por qué necesita la clave pública en el contrato, en lugar de la dirección?
@NickJohnson Quería cifrar algunos datos con la clave pública y enviarlos al remitente.
¿Sabe que los datos sin cifrar serán visibles en la cadena de bloques para cualquiera que quiera mirar?
@NickJohnson Sí. Así que quería enviar una transacción utilizando la cadena de bloques cifrada con la clave pública para que otros no puedan leerla.
Sin embargo, eso no ayudará: cualquiera puede reproducir su transacción y ver los datos antes de que se cifraran.
@NickJohnson ¿Qué sucede si el propietario solo sabe qué datos cifrar? Si el remitente envía alguna transacción y la recibe el propietario. cifrará los datos y los incluirá en la cadena de bloques.
Si se hace fuera de la cadena de bloques, entonces no necesita un contrato que pueda obtener la clave privada de una cuenta: puede obtenerla usted mismo de cualquier transacción creada por esa cuenta.

Respuestas (4)

Esto no es posible directamente: La clave pública no está directamente disponible para el contrato. El contrato solo tiene la dirección del remitente, que se deriva de su clave pública.

Sin embargo, es posible que un contrato haga la derivación al revés, por lo que si le pasas una clave pública como parámetro, puede averiguar a qué dirección corresponde.

Aunque el contrato no puede ver la clave pública, técnicamente es posible recuperarla de la cadena de bloques y/o de la red utilizando un código que se ejecuta fuera del contrato, siempre que la dirección se haya utilizado al menos una vez. Esto es posible porque cada vez que envía una transacción, verificar la firma implica primero recuperar la clave pública de la firma, luego calcular la dirección y verificar que coincida.

Entonces, una cosa que usted (o alguien más) podría hacer sería hacer un contrato de directorio que mantenga una lista de direcciones en claves públicas y ejecutar un bot para consultar las direcciones faltantes, recuperar la clave pública de la cadena de bloques y enviarla. al contrato de directorio.

Si no desea ejecutar el bot usted mismo, puede modificar el contrato de directorio para administrar una recompensa por cada clave pública faltante. Entonces, su contrato enviaría una pequeña cantidad de ETH al contrato de directorio cada vez que quisiera una clave pública, y una persona desconocida en Internet buscaría la clave pública, la enviaría al contrato de directorio y reclamaría la recompensa.

Veo este tipo de pregunta apareciendo en muchos lugares diferentes y (desafortunadamente) a menudo se responde con "no necesitas eso" o "por qué querrías eso".

Cuando se habla estrictamente de Blockchain, este tipo de respuesta es correcta, suponiendo que toda la "comunicación" se realiza mediante el envío de una transacción firmada a la cadena de bloques. Aquí, conocer la clave pública suele ser inútil.

De todos modos, si uno ve Blockchain (léase "Ethereum") como un libro mayor de registros distribuido, público y verificable (y estados de contratos inteligentes para el caso) y no como la base de todos los datos de una aplicación/servicio, la pregunta de repente hace mucho. de sentido

Un escenario podría ser que dos socios de comunicación estén ubicados en dispositivos fuera de la cadena (servidores, teléfonos móviles, computadoras portátiles, ...). Ambos tienen un par de claves que se utiliza para la identificación y el cifrado/descifrado/firma. El libro mayor registraría entonces las direcciones de ambos usuarios (parte de los hash de las claves públicas), que luego se utilizan como identificadores (probables). Entonces, la comunicación ocurriría completamente fuera de la cadena, es decir, directamente entre los dispositivos de los dos usuarios.

Si el usuario A ahora recibe un mensaje firmado del usuario B, A puede verificar fácilmente que el mensaje no ha sido manipulado y que en realidad proviene del propietario de la clave privada asociada con la dirección de A. (A obtendría la clave pública de B de la firma del mensaje, calcule la dirección a partir de ella y verifique que sea la dirección real de B).

De todos modos, si A y B aún no se han puesto en contacto y A quiere enviar un mensaje CIFRADO a B, no hay forma de que A conozca la clave pública de B simplemente conociendo la dirección de B.

Por lo tanto, los usuarios deben publicar en algún lugar una asignación de sus direcciones a sus claves públicas. Esto es básicamente (parte de) la idea detrás de SSI (DID y documentos DID).

Ahora, dicho esto, hay algunas opciones para lograrlo:

  1. De alguna manera, requiere que cada usuario cree una firma digital que esté disponible públicamente y que se pueda descubrir solo desde la dirección del usuario. Como estamos hablando de EC-crypto, uno puede derivar la clave pública de esa firma. Una forma de hacer esto sin tener un registro específico en algún lugar sería hacer que cada usuario realice de alguna manera una transacción con Ethereum. Desde aquí, puede enviar/firmar transacciones desde esta dirección (consulte un ejemplo aleatorio tonto https://etherscan.io/address/0x39ec1d8f3d431770a8c79b33ead5a2e9e3c02d25 ) y obtener la firma y la clave pública desde allí.

  2. Cree un registro público con una asignación de dirección a clave pública. Puede ser un contrato inteligente que tenga una asignación o un registro DID que se vincule a documentos DID (potencialmente fuera de la cadena) address. stringConsulte el ERC1056 de uPort, por ejemplo.

Para proponer directamente un MWE para la opción 2, se podría hacer algo como esto:

contract registry {
  mapping (address => string) private keys;
  
  function getKey(address a) public view returns (string) {
    return keys[a];
  }

  function setKey(string key) public returns (address) {
    address a = address(keccak256(key));
    keys[a] = key;
    return a;
  }
}

EDITAR: abofeteó un ejemplo que realmente funciona:

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;

contract KeyRegistry
{
    mapping (address => bytes) private keys;
    
    function getKey(address a) public view returns (bytes)
    {
        if(keys[a] == 0x0)
            revert("Error: Unknown address");
            
        return keys[a];
    }
    
    function setKey(bytes key) public returns (address)
    {
        if(key.length == 0)
            revert("Error: Key cant be empty");
        
        address a = address(uint160(bytes20(key)));
        
        if(a != msg.sender)
            revert("Error: Only the owner of a key can register this key");
        
        if(keys[a] != 0)
            revert("Error: Key is already registered");
        
        keys[a] = key;
        
        return a;
    }
}

Parece que estás tratando de hacer algún tipo de dapp de mensajería encriptada. Muy genial.

Algo que podría hacer es crear un registro de usuarios y hacer que los usuarios se "registren" para el DAPP proporcionando su propia clave pública, así como el tipo de clave. Luego, fuera de la cadena en la capa JS, recupere los metadatos del usuario y realice los costosos cálculos de cifrado, luego almacene el producto del cifrado en un mapeo de mensajes.

Así que podrías hacer algo como esto.

struct User{
  string pubKey;
  string keyType;
}

struct Message{
  string body;
}

mapping(address=>User) public users;
mapping(bytes32=>Message) public msgs;

Use algún tipo de identificador único para el mapeo de mensajes

Para el lenguaje del contrato de Solidity
: Siempre que envíe una transacción a un contrato

  1. para llamar a una función,
  2. para transferir ETH al contrato (aquí se utiliza una función alternativa anónimafunction() {...}

tiene acceso a un msgobjeto que contiene la clave pública del remitente: msg.sender.
Esto también es cierto en su constructor, donde el remitente es el propietario/creador del contrato.

kofier es el public keyo el addressde la User.
Veo que quieres la clave pública, ya que la dirección es un hash, tienes razón, no es lo mismo. No hay forma de conocer la clave pública directamente, AFAIK.