Saltearse al contenido

Cómo Funciona Keyless

Aptos Keyless permite a una dApp derivar y acceder a una cuenta de blockchain para un usuario que se registró exitosamente en la dApp a través de un proveedor OIDC (ej., Google). Importante, esta cuenta de blockchain está limitada a la dApp. Esto significa que otras dApps, que pueden registrar al mismo usuario de manera similar, a través del mismo proveedor OIDC, no pueden acceder a esta cuenta y en su lugar obtienen su propia cuenta.

¿Pero cómo funciona esto?

Este artículo explicará el flujo completo de keyless representado abajo, desde que el usuario primero se registra en una dapp, hasta obtener su prueba de conocimiento cero y, finalmente, transaccionar en cadena.

Resumen de Keyless

A un nivel muy alto, un registro exitoso en la dApp a través del proveedor OIDC resultará en que la dApp reciba un JSON Web Token (JWT) firmado por el proveedor OIDC. El JWT contendrá, entre otras cosas, tres piezas importantes de información:

  1. La identidad del usuario (contenida en el campo sub del JWT)
  2. La identidad de la dApp (contenida en el campo aud del JWT)
  3. Datos específicos de la aplicación; específicamente, una clave pública efímera (EPK) (contenida en el campo nonce del JWT), cuya clave secreta efímera (ESK) asociada solo el usuario conoce.

Ahora, asume que la dirección de cuenta blockchain del usuario es (más o menos) un hash de la identidad del usuario en sub y la identidad de la dApp en aud de arriba.

Entonces, la observación clave es que el JWT firmado actúa efectivamente como un certificado digital, vinculando temporalmente esta dirección de blockchain a la EPK, y permitiendo que la EPK firme TXNs para ella. En otras palabras, delega de forma segura los derechos de firma de TXN para esta cuenta de blockchain a la EPK (Nota: La EPK contiene una fecha de expiración y por lo tanto es de corta duración).

Importante, si el usuario pierde su ESK, el usuario puede obtener un nuevo JWT firmado sobre una nueva EPK a través de la aplicación simplemente registrándose nuevamente a través del proveedor OIDC (O, en algunos casos, solicitando un nuevo JWT firmado usando un token de actualización OAuth).

Con este sistema, el desafío es mantener la privacidad, ya que revelar el JWT en cadena filtraría la identidad del usuario. Además, revelar la EPK al proveedor OIDC le permitiría rastrear las TXNs del usuario en cadena.

Explicamos abajo cómo funcionan las cuentas Keyless y cómo abordan estos desafíos.

Flujo: Derivar una cuenta keyless para un usuario en una dApp

Sección titulada «Flujo: Derivar una cuenta keyless para un usuario en una dApp»

Primero, veamos cómo una dApp puede registrar un usuario a través de (digamos) Google, derivar la dirección de blockchain keyless de ese usuario y, por ejemplo, enviar a ese usuario un activo.

Diagrama de cuenta keyless

Paso 1: El usuario genera un par de claves efímeras: una EPK con una fecha de expiración, y su ESK asociada. La dApp mantiene la EPK y almacena de forma segura la ESK del lado del usuario (ej., en el almacenamiento local del navegador, o en un enclave confiable si la ESK es una passkey WebAuthn).

Paso 2: La dApp se compromete con la EPK como H(epk,ρ)H(\mathsf{epk}, \rho), donde ρ\rho es un factor de cegamiento. Cuando el usuario hace clic en el botón “Iniciar sesión con Google”, la dApp redirige al usuario a la página de inicio de sesión de Google y, importante, establece el parámetro nonce en la URL a este compromiso EPK. Esto oculta la EPK de Google, manteniendo la privacidad de la actividad TXN del usuario.

Paso 3: Típicamente, el usuario tiene una cookie HTTP de haber iniciado sesión previamente en su cuenta de Google, así que Google simplemente verifica esta cookie. Si el usuario tiene múltiples cuentas de Google, Google pide al usuario seleccionar cuál quiere usar para iniciar sesión en la dApp (El camino menos común es que el usuario tenga que escribir su nombre de usuario y contraseña de Google).

Paso 4: Una vez que el usuario ha iniciado sesión, Google envía a la dApp un JWT firmado, que incluye el identificador sub del usuario (ej., uid-123), el identificador aud de la aplicación (ej., "dapp-xyz") y el nonce con el compromiso EPK (Esto asume que la dApp se ha registrado previamente con Google y recibió este identificador "dapp-xyz").

Paso 5: La dApp ahora tiene casi todo lo que necesita para derivar una cuenta keyless para el usuario: el identificador del usuario (sub) y el identificador de la dApp (aud). Pero, para preservar la privacidad del usuario, la dApp usará una tercera pieza de información: un factor de cegamiento rr llamado pepper. La dApp contactará a un llamado guardián que derivará determinísticamente un rr aleatorio del (sub, aud) dado. Importante, el guardián solo revelará rr a la dApp al ver un JWT válidamente firmado para el (sub, aud) consultado.

Paso 6: La dApp deriva la dirección de la cuenta como addr=H("uid-123","dapp-xyz",r)\mathsf{addr} = H(\texttt{"uid-123"}, \texttt{"dapp-xyz"}, r), donde HH es una función hash criptográfica.

Nota que el pepper rr se usa para ocultar la identidad del usuario y la aplicación dentro de la dirección ya que, como describimos arriba, solo un usuario autorizado con un JWT válido podrá obtener este pepper.

También, nota que la dirección es independiente de la EPK. Por esto la ESK no necesita ser de larga duración y puede perderse.

Finalmente, la dApp puede, por ejemplo, enviar un NFT al usuario a su dirección addr\mathsf{addr}.

¿Pero cómo puede la dApp autorizar TXN desde esta cuenta en addr\mathsf{addr}? Discutimos eso a continuación.

Flujo: Obtener una prueba de conocimiento cero antes de transaccionar

Sección titulada «Flujo: Obtener una prueba de conocimiento cero antes de transaccionar»

En el flujo anterior, mostramos cómo una dApp puede registrar un usuario de Google y derivar su dirección keyless que preserva la privacidad, con la ayuda de un guardián.

A continuación, mostramos cómo esta dApp puede obtener una prueba de conocimiento cero (ZKP), que le permitirá autorizar transacciones desde esta dirección para el usuario. Importante, la transacción ocultará la información de identificación del usuario (ej., el campo sub).

Diagrama de prueba keyless

Paso 1: La dApp envía toda la información pública necesaria (i.e., epk\mathsf{epk}, GPK\mathsf{GPK}) e información privada (i.e., JWT, firma σ_G\sigma\_G de Google, factor de cegamiento EPK ρ\rho, y pepper rr) al servicio de prueba.

Paso 2: El probador deriva la dirección del usuario addr\mathsf{addr} y computa una prueba de conocimiento cero (ZKP) π\pi para la relación keyless R_keyless\mathcal{R}\_\mathsf{keyless} (descrita abajo). Esta prueba actúa como un certificado digital que preserva la privacidad, y vincula la dirección del usuario addr\mathsf{addr} a la clave pública efímera epk\mathsf{epk}. El probador luego envía π\pi a la dApp.

Para vincular la epk\mathsf{epk} con la dirección del usuario addr\mathsf{addr}, la ZKP se usará para convencer a los validadores que el usuario está en posesión de (1) un JWT firmado por Google, (2) que se compromete con la epk\mathsf{epk} en su campo nonce, y (3) contiene la misma información que en la dirección, sin filtrar nada sobre el JWT, su firma σ_G\sigma\_G, ρ\rho, o rr.

Más formalmente, la ZKP π\pi convence a un verificador (i.e., la blockchain), que tiene entradas públicas (addr,epk,GPK)(\mathsf{addr}, \mathsf{epk}, \mathsf{GPK}), que el probador conoce entradas secretas (jwt,σ_G,ρ,r)(\mathsf{jwt}, \sigma\_G, \rho, r) tales que la relación R_keyless\mathcal{R}\_\mathsf{keyless} representada abajo se mantiene:

Diagrama de relación keyless

Recuerda de antes que el JWT firmado en sí mismo vincula la dirección de blockchain addr\mathsf{addr} a epk\mathsf{epk}, para que epk\mathsf{epk} pueda firmar transacciones para addr\mathsf{addr}. Sin embargo, el JWT filtraría la identidad del usuario, así que la ZKP sirve para ocultar el JWT (y otra información privada) mientras argumenta que las verificaciones apropiadas se mantienen (i.e., las verificaciones en R_keyless\mathcal{R}\_\mathsf{keyless}).

A continuación, mostramos cómo la dApp puede ahora autorizar TXNs desde addr\mathsf{addr}.

Flujo: Enviar una TXN desde una cuenta keyless

Sección titulada «Flujo: Enviar una TXN desde una cuenta keyless»

El flujo anterior explicó cómo una dApp puede obtener una ZKP del servicio de prueba. A continuación, describimos cómo la dApp aprovecha esta ZKP para transaccionar para la cuenta.

Diagrama de firma keyless

Paso 1: La dApp obtiene una firma efímera σ_eph\sigma\_\mathsf{eph} sobre la TXN del usuario. Esto podría hacerse detrás del usuario, por la dApp misma que podría gestionar la ESK. O, podría ser una solicitud de firma real enviada al usuario, como cuando la ESK es una passkey WebAuthn, que se almacena en el hardware confiable del usuario.

Paso 2: La dApp envía la TXN, la ZKP π\pi, la clave pública efímera epk\mathsf{epk}, y la firma efímera σ_eph\sigma\_\mathsf{eph} a los validadores de blockchain.

Paso 3: Para verificar que la TXN está válidamente firmada, los validadores realizan varios pasos: (1) verificar que epk\mathsf{epk} no ha expirado, (2) obtener la dirección del usuario addr\mathsf{addr} de la TXN, (3) verificar la ZKP contra (addr,epk,GPK)(\mathsf{addr}, \mathsf{epk}, \mathsf{GPK}), y (4) verificar la firma efímera σ_eph\sigma\_\mathsf{eph} en la TXN contra la epk\mathsf{epk}. Si todas estas verificaciones pasan, pueden ejecutar de forma segura la TXN.

Las ideas clave detrás de las cuentas keyless también se explican en esta presentación de 20 minutos abajo.

Play