Has llegado al final de la sección de Anchoring
Vuelve a la Visión general del anchoring, o repasa el commitment exacto en Hashing y Merkle trees.
El sentido del anchoring es que un tercero puede demostrar que un punto de datos existió y no está alterado sin necesidad de confiar en CORE-M. Esta página muestra las dos APIs de verificación, el procedimiento manual que sigue un verificador, el bundle de proof portable y autocontenido, y qué es BEEF. Asume que conoces el hash canónico y el Merkle path de Hashing y Merkle trees.
Para verificar un punto solo necesitas:
device_id, timestamp (segundos Unix), y el payload
de telemetría.txid, y la transacción BEEF, de la API de
verificación de CORE-M, del proof store de PostgreSQL, o de un bundle portable
compartido fuera de banda.No se requiere acceso a los servicios en ejecución de CORE-M para la verificación en sí.
CORE-M expone dos endpoints que automatizan la búsqueda. Consulta Visión general de la API para la autenticación y las URLs base.
Úsalo cuando ya dispones del data_hash de 32 bytes.
GET /api/v1/verify/hash/<data_hash_hex>Busca en el proof store y devuelve la proof de ese hash. Si no existe ninguna proof,
la respuesta es NOT_FOUND con "no blockchain proof found for this data hash — it may be pending or nonexistent". Si el mismo hash se ancló en más de un batch
(re-anchoring), se devuelve la proof más reciente — la que tiene el
block_height más alto.
Úsalo cuando tienes los campos originales y quieres que CORE-M calcule el hash por
ti. Recomputa el leaf hash de doble SHA-256 definido en
Hashing y Merkle trees — el mismo algoritmo que el
servicio de telemetría — busca el resultado, y devuelve la misma forma de respuesta
que verificar-por-hash. El tenant_id es obligatorio: forma parte del preimage
del hash, y la API devuelve InvalidArgument (“tenant_id is required”) sin él.
curl -X POST https://<host>/api/v1/verify/raw \ -H "Content-Type: application/json" \ -d '{ "tenant_id": "T1", "device_id": "D1", "timestamp": "2024-03-21T05:46:40Z", "numeric_values": {"temperature": 22.5, "humidity": 65}, "string_values": {} }'Los endpoints de verificación (verify/hash, verify/raw, verify/batch) son
públicos — no se requiere ningún token Authorization, de modo que cualquier
tercero puede verificar un punto de datos de forma independiente. Solo ListProofs
(GET /api/v1/verify/proofs) requiere autenticación, porque está acotado por tenant.
Si los datos suministrados difieren aunque sea ligeramente de lo que se ancló, el
hash recomputado no coincidirá con ninguna proof almacenada y la respuesta es
NOT_FOUND.
Ambos endpoints devuelven la misma proof:
{ "txid": "c3d4e5f6a1b2...", "block_height": 850000, "block_hash": "00000000000000000abc...", "confirmed_at": "2024-03-21T08:31:12Z", "batch_id": "8f14e45f-ceea-467a-9f3b-2c1d4e5f6a7b", "merkle_path": [ { "hash": "9a0c...", "is_right": true }, { "hash": "4f7b...", "is_right": true } ], "beef_hex": "0100beef..."}merkle_path es un array de entradas {hash, direction} (la dirección se expresa
como is_right), y beef_hex es la transacción BEEF codificada en hex — explicada
más abajo.
Un verificador no tiene que confiar en el flag verified de la API — puede rehacer
la proof de principio a fin. Cuatro pasos:
Recomputa el data hash. A partir del tenant_id, el device_id, el
timestamp (segundos Unix) y el payload originales, calcula el leaf hash de
doble SHA-256 SHA256(SHA256(preimage)) exactamente como en
Hashing y Merkle trees — incluyendo el byte de
versión, los prefijos de longitud de tenant_id/device_id, y el propio
tenant_id. Confirma que equivale al data_hash de la proof. Esto prueba que
los datos no han sido alterados.
Recorre el Merkle path. Partiendo de data_hash, pliega (fold) cada hermano
usando su dirección hasta llegar al root (doble SHA-256 en cada paso):
current = data_hashfor step in merkle_path: if step.is_right: current = SHA256(SHA256(current || step.hash)) else: current = SHA256(SHA256(step.hash || current))# current is the reconstructed Merkle rootComprueba el OP_RETURN en la transacción BEEF. Decodifica el blob BEEF,
localiza la salida OP_FALSE OP_RETURN, y lee su payload:
"CORE-M" || merkle_root(32) || batch_id(16) || timestamp(8) || count(4).
Confirma que el merkle_root incrustado equivale al root que reconstruiste en el
paso 2. Esto prueba que tu punto está comprometido por esta transacción on-chain.
Confirma la inclusión en bloque. La proof registra el block_height y el
block_hash que ARC reportó al confirmar la transacción. CORE-M no verifica
de forma independiente la inclusión en bloque ni la pertenencia a la cadena más
larga offline — la confirmación confía en el bloque reportado por ARC. Para
comprobar la inclusión tú mismo, contrasta el txid contra cualquier nodo de la blockchain
o explorador de bloques en el block_height declarado. La posición del bloque en
la cadena es tu cota inferior de cuándo existieron los datos.
Toma el punto de Hashing y Merkle trees:
device_id="D1", timestamp=1711000000, payload
{"temperature":22.5,"humidity":65}.
{"humidity":65,"temperature":22.5}, luego
construye el preimage 0x01 · tenant_id (con prefijo de longitud, T1) ·
device_id (con prefijo de longitud, D1) · timestamp 0x0000000065FBC9C0 ·
los bytes del payload JCS, y haz SHA256(SHA256(...)). Para este punto el leaf
hash es 9774d8af1f5e5a0457275ec82b482e0e1b46f6fc421720a279d0e661f99755d2.
Confirma que equivale al data_hash devuelto por la API.merkle_path de arriba — ambas
is_right — plegando el hash hacia la derecha en cada paso para llegar al root.OP_RETURN de la transacción BEEF,
lee el merkle_root de 32 bytes en el offset 6, y comprueba que coincide con tu
root reconstruido.850000, y (opcionalmente) que un explorador de bloques coincide en que
el bloque a la altura 850000 tiene el hash 00000000000000000abc... y contiene
el txid.Si los cuatro pasos pasan, el punto existió de forma demostrable en el momento de ese bloque y no ha cambiado desde entonces.
Para cualquier punto de datos final, la API puede devolver un bundle de proof
portable autocontenido (solicita include_bundle=true en verificar-por-hash).
Lleva todo lo que un verificador externo necesita para validar el commitment sin
volver a llamar a CORE-M tras la descarga.
El bundle contiene:
| Campo | Propósito |
|---|---|
canonical_hash_inputs | El device_id exacto, el timestamp en segundos Unix, y el payload JCS usados para calcular el hash. |
merkle_path | Los hashes hermanos con direcciones, de la hoja al root. |
merkle_root | El root reconstruido/comprometido. |
txid | El ID de la transacción de anchoring. |
raw_tx o beef_hex | La transacción, como BEEF o cruda, para comprobación offline. |
block_header_chain | Cabeceras de bloque que establecen la inclusión y el contexto de cadena. |
confirmation_depth | Cuántas confirmaciones de profundidad tiene la transacción. |
anchor_mode | merkle, per_event o chain. |
verification_steps | Pasos legibles por humanos que reflejan el procedimiento de arriba. |
schema_version | Versión del schema del bundle. |
El bundle se valida contra el JSON schema publicado, de modo que un verificador puede comprobar su estructura por máquina antes de confiar en su contenido.
BEEF — Background Evaluation Extended Format — es un formato binario compacto asociado a las proofs SPV (Simplified Payment Verification). CORE-M almacena una variante interna de Core-M de BEEF BRC-62: una única transacción (la transacción de anchoring) más, cuando está disponible, su Merkle path on-chain (un BUMP). No agrupa transacciones ancestras (de financiación) ni cabeceras de bloque, y no está pensada para intercambiarse con consumidores externos de BEEF — es un formato de almacenamiento interno para el registro de proof.
CORE-M construye este blob cuando la transacción de anchoring se confirma y almacena
el hex con el registro de proof. Un verificador lo decodifica para extraer el
OP_RETURN y leer el merkle_root comprometido (paso 3). Como el blob no lleva
cabeceras de bloque, la inclusión en bloque no se re-verifica de forma
independiente a partir de él — ver el paso 4.
Las proofs confirmadas se persisten en PostgreSQL (anchor_proofs): data_hash,
batch_id, merkle_path (JSONB), txid, beef_hex, block_height, block_hash,
confirmed_at, tenant_id, y device_id.
Has llegado al final de la sección de Anchoring
Vuelve a la Visión general del anchoring, o repasa el commitment exacto en Hashing y Merkle trees.