feat: install tools/oracle as the paperspec package

Other repositories (paperstack, then paperpack) import the reference
implementation instead of reimplementing the specification; scienting-core
will take the role later behind the same vectors.

- pyproject.toml: distribution and import name `paperspec`, version 0.1.0,
  Python >= 3.12, no base dependencies; `tools/oracle` is the package, and
  `schemas/`, `sql/` and `vectors/` ship as the data subpackages
  `paperspec.schemas`, `paperspec.sql` and `paperspec.vectors`. Extras
  `schema`, `crypto` and `tools`.
- tools/oracle/__init__.py: the Python 3.14 and cryptography/jsonschema gate
  runs only when imported as `tools.oracle` by the repository's own tools.
- crypto.py imports `cryptography` on first use of HKDF and Ed25519, with an
  ImportError naming `paperspec[crypto]`; schema.py imports `jsonschema` and
  `referencing` in `Store.validator` and `Store.registry`. package.py, db.py
  and receipts.py then import on a bare interpreter.
- pixi.toml installs the package editable (pixi.lock re-solved; no conda pin
  changed), so the tools and the package resolve to the same code.
- tools/README.md names the library surface and the extras; CHANGELOG.md
  records the packaging change under 0.1.0, since check.py requires the
  changelog's first heading to equal the format version.

No computed value, vector, fixture, schema or SQL file changed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
alexmandClaude committed 2026-10-15 07:53:27 -04:00
1 parent 0dc0c2b12a
commit 2b4467d315
8 files changed
+279 -24

No files matched your search

+23 -11
View File
@@ -1,22 +1,31 @@
"""Keyed hashing, key derivation, Merkle roots and Ed25519.
Non-normative; see spec/05-hashes.md and spec/08-fidelity.md.
HKDF and Ed25519 come from the `cryptography` package.
HKDF and Ed25519 come from the `cryptography` package, imported on first use so that the hashing, Merkle
and did:key functions work without it.
"""
import hashlib
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey, Ed25519PublicKey
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from . import jcs
def _cryptography():
"""The `cryptography` modules HKDF and Ed25519 use: exceptions, hashes, ed25519 and hkdf."""
try:
from cryptography import exceptions
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ed25519
from cryptography.hazmat.primitives.kdf import hkdf
except ImportError:
raise ImportError("HKDF and Ed25519 need the cryptography package: install paperspec[crypto]") from None
return exceptions, hashes, ed25519, hkdf
def hkdf(ikm, salt, info, length=32):
"""HKDF-SHA-256, RFC 5869."""
return HKDF(algorithm=hashes.SHA256(), length=length, salt=salt, info=info).derive(ikm)
_, hashes, _, kdf = _cryptography()
return kdf.HKDF(algorithm=hashes.SHA256(), length=length, salt=salt, info=info).derive(ikm)
def team_key(secret):
@@ -199,20 +208,23 @@ def verify_consistency(root_m, root_n, m, n, proof):
def ed25519_public(secret):
"""The 32-byte public key of a 32-byte Ed25519 secret."""
return Ed25519PrivateKey.from_private_bytes(secret).public_key().public_bytes_raw()
_, _, ed25519, _ = _cryptography()
return ed25519.Ed25519PrivateKey.from_private_bytes(secret).public_key().public_bytes_raw()
def ed25519_sign(secret, msg):
return Ed25519PrivateKey.from_private_bytes(secret).sign(msg)
_, _, ed25519, _ = _cryptography()
return ed25519.Ed25519PrivateKey.from_private_bytes(secret).sign(msg)
def ed25519_verify(public, msg, signature):
"""True when `signature` is a valid Ed25519 signature of `msg` under `public`; never raises."""
if len(public) != 32 or len(signature) != 64:
return False
exceptions, _, ed25519, _ = _cryptography()
try:
Ed25519PublicKey.from_public_bytes(public).verify(signature, msg)
except (InvalidSignature, ValueError):
ed25519.Ed25519PublicKey.from_public_bytes(public).verify(signature, msg)
except (exceptions.InvalidSignature, ValueError):
return False
return True