Skip to content

franamaro-dev/verifactu-core

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

verifactu-core

Tamper-evident invoice hash chains for Spain's VeriFactu (RD 1007/2023). Zero runtime dependencies · fully typed · 98% test coverage · fails closed.

CI Python 3.11+ Zero deps Typed License: MIT


Why

Spain's anti-fraud law RD 1007/2023 (the VeriFactu regime) requires billing software to make issued invoices inalterable and traceable: each record must be cryptographically chained to the previous one, so any later deletion or edit is detectable.

Most teams reinvent this — usually with a subtly non-deterministic hash that breaks the moment a timezone or a decimal format changes. verifactu-core is the small, correct, dependency-free primitive that does only this, and does it right.

Scope: the integrity core (canonicalization + hash chain + verification). XAdES signing and AEAT transport are deliberately out of scope — they are replaceable adapters; the chain is forever.


Install

pip install verifactu-core      # once published to PyPI
# or, from source:
pip install -e ".[dev]"

No third-party runtime dependencies. Python 3.11+.


Quickstart

from datetime import datetime, timezone
from verifactu_core import InvoiceChain, InvoiceRecord

chain = InvoiceChain()

chain.append(InvoiceRecord(
    issuer_nif="B12345678",
    series="A",
    number="0001",
    issue_datetime=datetime(2026, 1, 15, 10, 30, tzinfo=timezone.utc),
    recipient_nif="X1234567L",
    total="121.00",
    tax="21.00",
    description="Consulting services",
))

chain.verify()            # raises ChainBrokenError if tampered
print(chain.head_hash)    # 64-char sha256 hex

See examples/quickstart.py for a full build → verify → tamper-detection demo.


How it works

flowchart LR
    R1["record #0<br/>prev = GENESIS"] --> R2["record #1<br/>prev = hash(#0)"]
    R2 --> R3["record #2<br/>prev = hash(#1)"]
    R3 --> R4["..."]
    style R1 fill:#2a9d8f,color:#fff
    style R2 fill:#2a9d8f,color:#fff
    style R3 fill:#2a9d8f,color:#fff
Loading
record_hash = sha256( previous_hash ‖ 0x1E ‖ canonical(record) )
genesis previous_hash = "0" * 64

Three guarantees, by construction:

Guarantee Mechanism
Determinism Frozen, versioned canonical format (fixed field order, UTC ISO-8601, 2-dp decimals, NFC text, 0x1F separator that is illegal in every field)
Tamper-evidence Previous hash bound into the digest — altering record N invalidates N..end and locate_tamper() returns N
Fail-closed Every malformed input or broken link raises; nothing is ever silently accepted

API

Symbol Purpose
InvoiceRecord Immutable, validated invoice (NIF shape, tz-aware datetime, 2-dp money, tax <= total)
InvoiceChain Append-only chain: .append(), .verify(), .locate_tamper(), .head_hash
compute_hash(record, prev) Pure chain-link function
canonicalize(record) The deterministic canonical string (v1, frozen)
verify_chain(records) Stateless verification of an externally stored chain
ChainBrokenError.index Zero-based index of the first broken record

Tests

pytest                       # 31 tests
pytest --cov=verifactu_core  # 98% coverage

The suite asserts the security property the law cares about, not just "the code runs":

  • test_tamper.py — altering, deleting or reordering any record is detected and localized
  • test_canonical.py — timezone, decimal precision, Unicode NFC and control-char injection
  • test_models.py — every validation invariant fails closed

Roadmap

  • to_aeic_dict() AEAT record mapper (optional extra)
  • XAdES signing adapter (separate package, keeps core dep-free)
  • QR payload helper per the VeriFactu spec
  • Property-based tests (Hypothesis) for canonicalization
  • PyPI release 0.1.0

License

MIT © Francisco Amaro Prieto

Companion work: VeriFactu-Integrity-Lab (write-up) · VeriStack · Barista case study


Built by Francisco Amaro — Backend Engineer & SOC L1 Analyst LinkedIn · Email

About

Tamper-evident invoice hash chains for Spain's VeriFactu (RD 1007/2023). Zero dependencies, fully typed, 98% coverage.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages