AsisteFácil Documentación técnica · AsisteFacil.com
Documentación técnica · v1

Protocolo de Verificación de Evidencia

Cómo AsisteFácil sella criptográficamente cada checada, de manera que su integridad se pueda comprobar de forma independiente — sin necesidad de confiar en AsisteFácil como operador.

SHA-256 Árbol de Merkle Constancia NOM-151 Verificación independiente
Ejemplos en vivo, sin pedir acceso a nadie: registro público · registro privado · árbol de Merkle con varios movimientos.
01 · Modelo de confianza

Alcance y modelo de confianza

El diseño es "trust-minimizing": AsisteFácil publica los datos y la constancia; cualquier tercero recalcula todo por su cuenta. Si algo no cuadra, el recálculo lo delata — no hace falta creerle a AsisteFácil.

Qué prueba este protocolo

IntegridadUn movimiento incluido en un sello no ha sido alterado desde entonces. Cualquier cambio a un campo cubierto por el hash rompe la hoja y, por lo tanto, la raíz del árbol.
Completitud del díaNo se añadieron ni quitaron movimientos del conjunto del día después del sellado — cambiar el número de hojas cambia la raíz.
Anterioridad temporalLa raíz —y todo el conjunto de movimientos que representa— existía antes del sello de tiempo, emitido por un tercero acreditado e independiente de AsisteFácil.
No repudio del certificadorLa constancia está firmada con el certificado del Prestador de Servicios de Certificación (PSC); su validez se comprueba contra el propio PSC y contra cadenas de confianza públicas.

Qué no prueba

Que la checada corresponda a una persona física real presente en un lugar — eso lo aportan la foto, la geolocalización y el resto de controles del producto. Tampoco prueba nada anterior a la fecha del primer sello, ni la existencia de un movimiento que nunca se incluyó en un sello.

Quién necesita confiar en quién

ParteHace falta confiar en…No hace falta confiar en…
AsisteFácilnada, para la verificación criptográfica
El PSCsu acreditación y su firmasu disponibilidad continua — la constancia se verifica sin conexión
El perito / tercerosus propias herramientas (`sha256sum`, un visor ASN.1)
02 · Estructuras de datos

Estructura de los datos

Cada checada se convierte en un objeto JSON plano con un esquema fijo y versionado (identificado como MOV-1). Es exactamente lo que ya se muestra en la ficha pública de cualquier movimiento:

{
	"key":               "identificador público del movimiento",
	"fecha":             "YYYY-MM-DD",
	"hora":              "HH:MM:SS",
	"creadoEl":          "YYYY-MM-DD HH:MM:SS",
	"empleadoId":        entero,
	"empleado":          "nombre completo",
	"tipoAsistenciaId":  "entero — 1 = entrada, 2 = salida",
	"tipoAsistencia":    "texto",
	"centroDeTrabajoId": entero,
	"centroDeTrabajo":   "texto",
	"latitud":           "cadena de texto",
	"longitud":          "cadena de texto",
	"imagenArchivo":     "nombre del archivo de la foto",
	"imagenHash":        "SHA-256 (hex) de la foto",
	"altaManual":        booleano,
	"origenRegistroId":  entero,
	"origenRegistro":    "texto",
	"registranteId":     entero,
	"registrante":       "texto",
	"hashVersion":       "MOV-1",
	"hashAlgoritmo":     "SHA-256",
	"hashAnterior":      "hoja del movimiento inmediatamente anterior, o null"
}

tipoAsistenciaId es el dato capturado al momento del registro y ya inmutable — forma parte de lo que se sella. Cualquier reclasificación operativa posterior se maneja en un campo aparte que queda fuera del hash, precisamente para que reclasificar un movimiento no invalide su evidencia original.

Latitud y longitud se guardan como texto, no como número, para preservar exactamente la precisión capturada sin ambigüedad de redondeo.

El árbol diario (MK-1)

Cada día, por empresa, se consolida un árbol de Merkle cuya raíz es lo único que se sella ante el PSC. El objeto que respalda ese árbol incluye la especificación, la raíz en hexadecimal y en Base64, el número de hojas, y el árbol completo nivel por nivel — todo publicado junto con la constancia.

Ejemplo real: esta ficha privada muestra el objeto MOV-1 completo tal como lo vería cualquier visitante, incluyendo su HASH.
03 · Canonicalización

Algoritmo de canonicalización

Antes de hashear, el objeto JSON se convierte a una representación determinista, para que cualquier reimplementación en cualquier lenguaje produzca, byte a byte, la misma cadena.

Reglas

Orden de llavesAscendente, comparación de cadenas byte a byte (equivalente a strcmp; para llaves ASCII, orden de código de punto).
EspaciosNinguno. {"a":1,"b":2}, nunca {"a": 1, "b": 2}. Sin saltos de línea ni sangría.
UnicodeCaracteres multibyte (acentos, ñ) se emiten literales en UTF-8, no como secuencias de escape.
Diagonales /No se escapan.
Comillas y barra invertida"\", \\\. Caracteres de control se escapan.
Nulos y booleanosnull, true, false literales, sin comillas.

Vector de prueba (normativo)

Objeto de ejemplo:

{"key":"Ab12Cd34","fecha":"2026-09-08","hora":"08:01:15","creadoEl":"2026-09-08 08:01:17","empleadoId":42,"empleado":"María Núñez","tipoAsistenciaId":1,"tipoAsistencia":"Entrada","centroDeTrabajoId":7,"centroDeTrabajo":"Obra Centro","latitud":"19.4326","longitud":"-99.1332","imagenArchivo":"Ab12Cd34.jpg","imagenHash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","altaManual":false,"origenRegistroId":2,"origenRegistro":"App","registranteId":1,"registrante":"María Núñez","hashVersion":"MOV-1","hashAlgoritmo":"SHA-256","hashAnterior":null}

Cadena canónica (llaves reordenadas):

{"altaManual":false,"centroDeTrabajo":"Obra Centro","centroDeTrabajoId":7,"creadoEl":"2026-09-08 08:01:17","empleado":"María Núñez","empleadoId":42,"fecha":"2026-09-08","hashAlgoritmo":"SHA-256","hashAnterior":null,"hashVersion":"MOV-1","hora":"08:01:15","imagenArchivo":"Ab12Cd34.jpg","imagenHash":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","key":"Ab12Cd34","latitud":"19.4326","longitud":"-99.1332","origenRegistro":"App","origenRegistroId":2,"registrante":"María Núñez","registranteId":1,"tipoAsistencia":"Entrada","tipoAsistenciaId":1}

SHA-256 esperado:

637f7f91b4a751d5948e04385dcb4ba0b9f01bf6d7cf240b10f63fac52a3dad7
04 · Hash

Algoritmo de hash

05 · Encadenamiento

Encadenamiento de movimientos

Cada movimiento incorpora, dentro del propio objeto que se hashea, el campo hashAnterior: la hoja del movimiento inmediatamente anterior del sistema.

El efecto es una cadena: hoja_n = SHA-256( … ‖ hoja_{n-1} ). Alterar o intentar retirar un movimiento antiguo invalida, en cascada, todas las hojas posteriores — y por lo tanto todas las raíces diarias siguientes, no solo la de su propio día.

06 · Árbol de Merkle

Construcción del árbol de Merkle

Un árbol independiente por empresa y por día. Las hojas son la huella de cada movimiento del día calendario (incluidos los marcados como eliminados, porque un hecho que ocurrió sigue siendo un hecho), en el orden en que se dieron de alta.

mientras el nivel tenga más de un nodo:
	para cada par de nodos (izquierdo, derecho):
		si no hay derecho (nivel impar): derecho = izquierdo   // se duplica el último
		padre = SHA-256( izquierdo + derecho )                  // concatenación de los hex
	siguiente_nivel = [ todos los padres ]

el nivel que queda con un solo nodo es la raíz

Esa raíz —y solo esa raíz— es lo que se sella ante el PSC.

Ejemplo real: este árbol de Merkle muestra los seis movimientos de un día, nivel por nivel, hasta la raíz — con el recálculo hecho en el navegador de quien lo visita.
07 · Prueba de inclusión

Formato de la prueba de inclusión

Cualquier hoja puede verificarse contra la raíz sin necesitar el árbol completo, con una lista ordenada de "hashes hermanos" y su posición:

[
	{ "hash": "<hex del hermano>", "posicion": "izquierda|derecha" },
	…  // un elemento por nivel, de la hoja hacia la raíz
]

Verificación: partiendo del hash de la hoja, en cada paso se calcula SHA-256(acumulado + hermano) o SHA-256(hermano + acumulado) según la posición indicada, hasta llegar a la raíz y compararla con la raíz sellada. Esto ya está disponible públicamente en la ficha de cada árbol, y se puede recalcular en cualquier navegador sin llamar a ningún servidor de AsisteFácil.

08 · Comunicación con el PSC

Qué se envía exactamente al certificador

Únicamente la raíz diaria de cada empresa — 32 bytes de SHA-256. Nunca se envían datos personales, fotografías, ni el árbol completo. Para el Prestador de Servicios de Certificación, la raíz es indistinguible del hash de cualquier otro archivo: no tiene forma de saber qué representa.

09 · Constancia NOM-151

Qué se recibe: la constancia NOM-151

La constancia es un objeto ASN.1/DER firmado (CMS/PKCS#7 SignedData con sello de tiempo conforme a NOM-151 / RFC 3161), que contiene el hash sellado, la marca de tiempo confiable, la firma del PSC y su cadena de certificados.

Adicionalmente se genera un PDF de "evidencia", pensado para lectura humana — es informativo y no sustituye a la constancia, que es la prueba primaria.

10 · Verificación

Cómo se verifica

La verificación completa tiene cinco niveles. Los primeros tres son criptografía pura que cualquiera puede reproducir sin depender de nadie; los dos últimos se apoyan en el certificador.

#Qué se compruebaCómo
1Cada hoja corresponde a los datos del movimientoRecalcular el objeto canónico y su SHA-256
2El árbol reduce correctamente las hojas a la raízReconstruir el árbol completo
3La raíz coincide con la publicadaComparación directa
4La raíz está contenida en la constanciaValidador del PSC o un visor ASN.1
5La constancia la firmó un PSC acreditado y su sello de tiempo es válidoValidación de firma contra cadenas de certificados públicas

Las fichas públicas de AsisteFácil ya hacen el nivel 1-3 en el propio navegador de quien las visita, usando únicamente funciones criptográficas nativas — sin llamar a ningún servidor.

Puedes verlo ahora: este registro público, tal y como lo vería RH o un perito, incluyen el JSON canónico y recalcula su propio HASH en tu navegador al abrirlo, y muestra si coincide con el sellado.
11 · Reconstrucción independiente

Cómo un tercero reconstruye todo sin confiar en AsisteFácil

Para verificar un día completo, un perito necesita: la constancia (.asn1), el objeto del árbol (JSON), la raíz, y el objeto MOV-1 de cada movimiento incluido. Todo descargable desde la ficha pública correspondiente — por ejemplo, este Merkle con seis movimientos, que incluye el archivo .asn1 para descarga directa.

Script de referencia (Python)

import hashlib

def sha256_hex(s: str) -> str:
	return hashlib.sha256(s.encode("utf-8")).hexdigest()

def merkle_root(hojas: list[str]) -> str | None:
	if not hojas:
		return None
	nivel = [h.lower() for h in hojas]
	while len(nivel) > 1:
		siguiente = []
		for i in range(0, len(nivel), 2):
			izq = nivel[i]
			der = nivel[i + 1] if i + 1 < len(nivel) else izq   # impar: duplica
			siguiente.append(sha256_hex(izq + der))
		nivel = siguiente
	return nivel[0]

# assert merkle_root(hojas) == raiz_publicada

Con la raíz reconstruida, el último paso es independiente de AsisteFácil por completo: subir la constancia y la raíz (en Base64) al validador público del PSC, que confirma si esa raíz está contenida en la constancia y si la firmó el certificador acreditado.

Si los cinco niveles pasan, los movimientos del día —con todos sus campos— existían y tenían exactamente esos valores antes del sello de tiempo del PSC, y ninguno se añadió o quitó después. AsisteFácil no interviene en esa conclusión.

¿Necesitas mostrarle esto a tu área legal o a un perito?

Con gusto te compartimos una constancia real (ambiente de pruebas) para que la validen con su propia herramienta, sin depender de la nuestra.

Solicitar una demostración