Olive oil traceability, step by step

7. Documents outside the chain

Goal: Understand why only the document fingerprint goes on the chain and how to recompute it to check.

A notary does not keep your 40-page contract in the register: they write the number, the date and a seal. If someone changes the contract, the seal no longer matches.

Why not put the PDF on the chain

Writing on the chain costs money and every item stays visible to everyone forever. A PDF or photo is heavy and may contain information we do not want to make public. So we put only the fingerprint on the chain, 32 bytes (type bytes32), while the file lives on the project's server (the backend).

How to compute it

import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";

// 1. Il file resta sul server: qui lo leggiamo come sequenza di byte.
const byte = readFileSync("referto.pdf");

// 2. L'impronta sha256 sono 32 byte: li scriviamo come 64 caratteri esadecimali.
const impronta = "0x" + createHash("sha256").update(byte).digest("hex");

console.log(impronta); // questo valore (bytes32) va nel contratto come docHash

Line by line

  1. The first two lines take two tools already included in Node.js: one for the fingerprint, one for reading files.
  2. readFileSync reads the PDF and turns it into bytes.
  3. createHash("sha256") prepares the calculation, update feeds it the bytes, digest("hex") returns the result as letters and digits.
  4. We prefix 0x so the contract recognises a bytes32 value.

The same function is used for verification: anyone who downloads the document can redo the calculation.

// Ricalcolo: l'impronta del file scaricato deve essere uguale a quella sulla catena.
function documentoIntegro(fileBytes, docHashSullaCatena) {
  const ora = "0x" + createHash("sha256").update(fileBytes).digest("hex");
  return ora === docHashSullaCatena.toLowerCase();
}

Line by line

  1. The function receives the bytes of the downloaded file and the fingerprint read from the chain.
  2. It recomputes the fingerprint with the same method.
  3. It returns true only if the two match; toLowerCase() ignores upper/lower case differences.

In the demo the backend computes the fingerprint when the file arrives (at most 5 MB, PDF, JPG or PNG only), stores the file and writes the fingerprint on the chain as docHash. At verification the public page compares the two fingerprints for each document.

A useful detail: the fingerprint proves the file has not changed since registration, not that its content was true.

Try it yourself

Save any text file, compute its fingerprint with the script above, then change one letter in the file and recompute. Compare the two fingerprints with the documentoIntegro function.

What you learned