Proovik
Especificación de verificación · PVK-PROOF/1

Cómo comprobar una prueba de Proovik sin fiarse de Proovik

Esta página describe, paso a paso y con valores reales, cómo se verifica por medios exclusivamente matemáticos que un documento existía antes de una fecha determinada. No hace falta un nodo, ni nuestra API, ni nuestra colaboración: solo el fichero de prueba, una calculadora de hashes y esta página.

Versión 1 Red: Kaspa mainnet Verificador de referencia: 248 líneas de Python, sin dependencias

Qué se afirma exactamente

La precisión aquí importa más que la elocuencia, porque de esto depende que la prueba aguante un contradictorio.

Lo que la prueba acredita

Que una cadena de bytes cuyo SHA-256 es un valor determinado fue incorporada a una transacción de la red Kaspa, que esa transacción quedó comprometida dentro de la cabecera de un bloque, y que sobre esa cabecera —que incluye una marca temporal— se ejecutó una prueba de trabajo válida. Como la marca temporal está dentro del dato sobre el que se hizo el trabajo, alterarla invalida el trabajo. La fecha no es una declaración de nadie: es una magnitud física ya gastada.

Lo que la prueba NO acredita

Quién creó el documento, si su contenido es cierto, si su autor tenía derecho a crearlo, ni que el documento no existiera antes. Acredita anterioridad a un instante, no autoría ni veracidad. Proovik no ve el documento en ningún momento: solo recibe su hash.

Sobre el hash

SHA-256 es una función resumen de 256 bits. Encontrar dos documentos distintos con el mismo resumen no se ha conseguido nunca y el esfuerzo estimado excede lo que la humanidad puede computar. Por eso, si el resumen del documento aportado coincide con el que está en la cadena, el documento es el mismo, sin margen práctico de duda.

Los cuatro eslabones

La verificación es una cadena. Cada eslabón enlaza con el siguiente, y basta que uno falle para que la prueba no valga. Los valores que aparecen a continuación son reales: corresponden a un certificado emitido el 24 de enero de 2026.

1

El dato de la transacción es el resumen del documento

Enlaza el documento con la cadena de bloques

Toda transacción de Kaspa admite un campo libre, payload. Proovik escribe ahí los 32 bytes del SHA-256 del documento, y nada más. La comprobación es una comparación literal.

SHA-256(documento) == transaccion.payload
documento
8ea578dd12b3e8c55b8b53f3db80f6cd23fe1ed22a0d7af5c46fc8e25f45294c
payload
8ea578dd12b3e8c55b8b53f3db80f6cd23fe1ed22a0d7af5c46fc8e25f45294c
Coincide
2

La transacción está comprometida en la cabecera del bloque

Enlaza la transacción con el bloque · testigo de 64 bytes

Kaspa registra en cada cabecera de la cadena un compromiso con las transacciones que ese bloque acepta. Desde la entrada en vigor de KIP-15 ese campo, acceptedIdMerkleRoot, no es una raíz Merkle simple sino un valor encadenado: combina el compromiso del bloque padre con la raíz de las transacciones aceptadas. Un recálculo que ignore ese encadenamiento falla, y ésa es la causa más frecuente de verificaciones erróneas.

nodo(a,b) = blake2b-256( clave = "MerkleBranchHash", a ‖ b ) AIMR = raiz Merkle sobre las transacciones aceptadas, en orden canonico SeqCommit = nodo( SeqCommit_del_padre_seleccionado , AIMR ) valido ⟹ SeqCommit == cabecera.acceptedIdMerkleRoot
AIMR
b3bc256951640ff6468511fb62ec8fb280dafb99ebf7ecd00245d0cc3c9debb3
seq. padre
2b3265225d51e5b051e46b9f164dc116cf2e21d566827abc8a7b1ae036d8330d
calculado
7843221eda25f05ddf9872ed57b59fb95c4f15aa7bf15017105e9797ef09caa5
en cabecera
7843221eda25f05ddf9872ed57b59fb95c4f15aa7bf15017105e9797ef09caa5
Coincide
Dos trampas verificadas

El orden de las transacciones aceptadas es el canónico que fija KIP-15, no el orden en que las devuelva una API ni el orden por hash. Y las hojas del árbol de un bloque —cuando se verifica inclusión en lugar de aceptación— no son los txid, sino los tx::hash, calculados con la codificación completa (incluidos los signature scripts y el compromiso de masa de almacenamiento).

3

La cabecera produce el hash de bloque declarado

Enlaza el bloque con su identidad

El hash de un bloque es el resumen de su cabecera serializada. Recalcularlo demuestra que la cabecera aportada es exactamente la que dice ser, y que ninguno de sus campos —incluida la marca temporal— ha sido tocado.

h = blake2b-256( clave = "BlockHash" ) h ← version u16 little-endian h ← numero de niveles u64 little-endian para cada nivel: h ← numero de padres u64 little-endian h ← cada hash de padre 32 bytes h ← hashMerkleRoot 32 bytes h ← acceptedIdMerkleRoot 32 bytes h ← utxoCommitment 32 bytes h ← timestamp u64 little-endian ← la marca temporal h ← bits u32 little-endian h ← nonce u64 little-endian h ← daaScore u64 little-endian h ← blueScore u64 little-endian h ← longitud de blueWork u64 little-endian h ← blueWork big-endian, sin ceros a la izquierda h ← pruningPoint 32 bytes
Requisito no negociable

La cabecera se compromete a todos los niveles de padres —hoy son 56, con más de doscientos hashes—. Si falta uno solo, el resumen no se puede reconstruir. Éste es el motivo por el que el fichero de prueba debe capturar la cabecera íntegra en el momento del anclaje: pasadas unas treinta horas, la red descarta esos datos y los servicios públicos devuelven la cabecera recortada.

4

Sobre esa cabecera se ejecutó una prueba de trabajo válida

Convierte el bloque en un hecho físico y fecha el documento

Aquí es donde la prueba deja de ser una afirmación y pasa a ser una constatación. Kaspa exige que el resultado de aplicar su función de trabajo (kHeavyHash) a la cabecera quede por debajo de un umbral. Alcanzarlo requiere miles de billones de intentos: energía real, irreversiblemente gastada.

pre = hash_de_cabecera( con timestamp = 0 y nonce = 0 ) M = matriz 64x64 generada con xoshiro256++ sembrado con pre, regenerada hasta que su rango sea 64 p = cSHAKE256("ProofOfWorkHash")( pre ‖ timestamp ‖ 32 ceros ‖ nonce ) r = cSHAKE256("HeavyHash")( (M · nibbles(p)) ⊕ p ) valido ⟹ entero_little_endian(r) ≤ objetivo(bits)
pre
6e4f2ca8feb279a54f2c4ac8d57c867917f1766a7936a5bd7bd9351557d3c6f7
resultado
0x15222b53caabb3b049ec84e25d0a0c7a35512f9d557adb4bc20
objetivo
0x2345b0000000000000000000000000000000000000000000000
Trabajo válido

Por qué la fecha es una magnitud física y no una declaración

Ésta es la parte que suele exigir el contradictorio, así que conviene enseñarla en vez de argumentarla. La marca temporal está dentro de la cabecera, y la cabecera es la entrada de la prueba de trabajo. Modificar la hora modifica la entrada, y el trabajo deja de ser válido. Se comprueba experimentalmente alterando la cabecera verificada en el paso 4 y repitiendo el cálculo:

Cabecera Resultado del trabajo Veredicto
Original, sin tocar0x15222b53caabb3b049ec…Válido
nonce + 10x6775abc19ba960657f66…Inválido
timestamp adelantado un segundo0xaee1e8274b1d268866ed…Inválido
La consecuencia

Para presentar el documento con una fecha distinta habría que rehacer la prueba de trabajo de esa cabecera contra la dificultad real de la red. No es una barrera de coste: es una barrera de cómputo del orden de la potencia agregada de toda la red durante el intervalo que se pretenda falsear. Nadie declara la fecha. La fecha se paga.

¿Seguirá funcionando tras futuros hardforks?

La respuesta honesta es , y conviene entender por qué. Una prueba capturada no es una consulta viva a la red: es un hecho histórico, verificado con las reglas vigentes en el momento en que se ancló. Kaspa cambia con el tiempo —la transición Crescendo/Toccata modificó, por ejemplo, el ritmo del DAA y el conteo de dificultad—, pero eso no borra el pasado: solo significa que un bloque de enero de 2026 se verifica con las reglas de enero de 2026, y uno de dentro de tres años con las de dentro de tres años.

El verificador de referencia está construido para eso: distingue eras. Conoce el punto de activación de cada cambio de consenso (por ejemplo, la constante CRESCENDO_DAA_MAINNET) y aplica a cada bloque las reglas de su época, no las de hoy. Un hardfork posterior añade una era nueva; no invalida las anteriores.

La permanencia de la prueba descansa entonces en tres condiciones, todas bajo control de quien la posee:

01
Capturar dentro de la ventana

Guardar la cabecera íntegra en el momento del anclaje, antes de que la red descarte los datos completos (unas 30-40 horas).

02
Guardar la prueba

El fichero de prueba (o el PDF que lo lleva embebido) es autosuficiente: no remite a ningún servidor ni consulta en línea.

03
Mantener el verificador de referencia

248 líneas de código abierto, sin dependencias, re-derivables del código fuente público de Kaspa. Aunque se perdiera, se reescribe.

Verifíquelo usted mismo

El verificador de referencia son 248 líneas de Python sin dependencias externas: implementa blake2b con clave, la permutación Keccak-f[1600], el generador xoshiro256++ y la aritmética de la matriz. Se lee en una tarde y se audita en dos.

$ python3 verificador_kaspa.py prueba.json 8ea578dd12b3e8c55b8b53f3db80f6cd23fe1ed22a0d7af5c46fc8e25f45294c

  OK    1. El payload on-chain es el hash del documento
  OK    2. La transaccion esta en el arbol Merkle del bloque
  OK    3. La cabecera produce el hash de bloque declarado
  OK    4. La prueba de trabajo de esa cabecera es valida

RESULTADO: PRUEBA VALIDA
Descargar el verificador de referencia

Dos ficheros. Colóquelos en la misma carpeta y ejecute el primero. No instalan nada ni salen a la red.

Quien prefiera no ejecutar código ajeno puede reimplementarlo: los cuatro algoritmos están descritos arriba sin ambigüedad, y todos los parámetros proceden del código fuente público de rusty-kaspa. Es igualmente legítimo consultar la transacción en cualquier explorador público de Kaspa como contraste, pero conviene entender la diferencia: el explorador es un testimonio; el cálculo es una demostración. Esta especificación existe para no depender del primero.

Alcance jurídico

Proovik presta un servicio de sello de tiempo electrónico no cualificado en el sentido del artículo 3.16.i) del Reglamento (UE) 910/2014. Conviene ser explícito sobre lo que eso significa.

  • Conforme al artículo 41.1 del citado Reglamento, no pueden negarse efectos jurídicos ni admisibilidad como prueba en juicio a un sello de tiempo electrónico por el solo hecho de estar en formato electrónico o de no ser cualificado.
  • Un sello no cualificado no goza de la presunción de exactitud de fecha y hora del artículo 41.2, reservada a los cualificados. En caso de impugnación, la carga de acreditar la prueba recae sobre quien la aporta.
  • Precisamente por eso esta especificación existe: para que esa carga se satisfaga con una comprobación aritmética reproducible por cualquiera, en lugar de con la declaración del prestador.

Proovik no verifica el contenido, la autoría ni la licitud de los documentos, y en ningún momento accede a ellos: recibe únicamente su resumen criptográfico. Lo que se acredita es una prueba de existencia y anterioridad a un instante determinado.