Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased]

### Added
- **`ed25519_verify`** checks an RFC 8032 Ed25519 signature. The public key is
32 bytes as 64 hex characters, the signature is 64 bytes as 128 hex
characters, and the signed bytes are the UTF-8 encoding of the message text.
Valid signatures return `yes`; wrong keys or tampered messages return `no`;
malformed or unsupported encodings raise a generic error that does not echo
the inputs. Messages are capped at 1 MiB. Verification uses `ed25519-dalek`;
WFL does not implement the primitive or expose signing. Existing HMAC licence
keys are unchanged.
- **`wfl init`** creates a simple `.wflcfg`, an `AGENTS.md` pointer, and a
`CLAUDE.md` application guide in the current directory. The guide covers WFL
syntax, CLI validation, LSP and MCP setup, Docker testing, and documentation
Expand Down
105 changes: 104 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ bcrypt = "0.19"
# a fresh random nonce per seal without a counter, so callers never touch nonces
# and cannot reuse one. `zeroize` wipes the expanded key on drop.
chacha20poly1305 = { version = "0.11.0", features = ["zeroize"] }
# Ed25519 (RFC 8032) verification for `ed25519_verify`. dalek is the maintained
# implementation; WFL does not ship its own Edwards arithmetic. Default features
# stay off so this crate only pulls verify/std — no signing API is exposed.
ed25519-dalek = { version = "2.2", default-features = false, features = ["std"] }
# Force newer version to fix future incompatibility warning
num-bigint-dig = "0.8.6"
# Direct dep so the lib can expose `init_rustls_crypto_provider()` (called by
Expand Down
5 changes: 4 additions & 1 deletion Docs/01-introduction/key-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,12 @@ store integrity_tag as sha256 of wfl_digest

// Standard MAC for external services
store mac as hmac_sha256 of "message" and "secret key"

// Public-key verification (RFC 8032 Ed25519)
store accepted as ed25519_verify of public_key and message and signature
```

**Note:** WFLHASH is **experimental** and not externally audited. Please test it. For sensitive data (passwords especially), use **more than one hash** — e.g. WFLHASH then `sha256`, and for passwords always finish with `hash_password`. Use `sha256` / `hmac_sha256` alone for external interop.
**Note:** WFLHASH is **experimental** and not externally audited. Please test it. For sensitive data (passwords especially), use **more than one hash** — e.g. WFLHASH then `sha256`, and for passwords always finish with `hash_password`. Use `sha256` / `hmac_sha256` alone for external interop. Use `ed25519_verify` when the other party signs with Ed25519.

## 8. Developer-Friendly Tooling

Expand Down
55 changes: 54 additions & 1 deletion Docs/05-standard-library/crypto-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The Crypto module provides cryptographic functions in four groups:
- **Password hashing** — `hash_password`/`verify_password` and the algorithm-specific Argon2id, bcrypt, scrypt and PBKDF2 functions. Use these to store user passwords safely.
- **Auth & session primitives** — `pbkdf2_hmac_sha256` (raw key derivation), `constant_time_equals` (timing-safe comparison), and `secure_random_bytes` (CSPRNG bytes for salts, tokens, and session IDs).
- **Standard hashing/MAC** — `sha256` and `hmac_sha256` for interoperating with external services (webhook verification, API signing).
- **Public-key signatures** — `ed25519_verify` for RFC 8032 Ed25519 verification (activation and other offline signatures). WFL verifies only; it does not mint keys or sign.
- **WFLHASH (experimental)** — WFL's own hash family. Please try it, report results, and help us harden it. For production integrity, **pair it with a known-good hash** so a battle-tested algorithm always has your back.

> **Hashing a password? Use `hash_password`, never `sha256` or `wflhash256` alone.** Fast hashes are built to be quick, which is exactly what makes them a poor way to store passwords — an attacker can try billions of guesses per second. The password hashing functions below are deliberately slow and salted to prevent that. For sensitive material, also prefer **more than one hash** (see below).
Expand Down Expand Up @@ -90,6 +91,7 @@ store standard_digest as sha256 of payload
| Try / test / feedback on WFLHASH | `wflhash256` / `wflhash512` alone — please do |
| Production integrity (files, caches, internal digests) | **Multi-hash:** WFLHASH then `sha256` (or another known-good hash) |
| Interop with Stripe, GitHub, other APIs | `sha256` / `hmac_sha256` only (they will not speak WFLHASH) |
| Ed25519 signatures (activation, offline verify) | `ed25519_verify` — hex public key, UTF-8 message, hex signature |
| Passwords (sensitive) | **Multi-hash pre-mix** (e.g. WFLHASH then `sha256`) **then** `hash_password` — never store fast hashes alone |
| FIPS / regulatory validated crypto | Standard algorithms only (`sha256`, etc.) |

Expand All @@ -105,7 +107,7 @@ store standard_digest as sha256 of payload
- External protocols that require a specific standard algorithm
- Environments that demand only FIPS-validated or formally audited primitives (use the standard alone)

**Interoperability still needs standards alone.** WFL's `sha256` and `hmac_sha256` builtins are required when talking to external services (e.g. Stripe or GitHub webhook signatures). A custom algorithm cannot stand in there.
**Interoperability still needs standards alone.** WFL's `sha256` and `hmac_sha256` builtins are required when talking to external services (e.g. Stripe or GitHub webhook signatures). A custom algorithm cannot stand in there. Use `ed25519_verify` when the other party produces an RFC 8032 Ed25519 signature.

## Password Hashing

Expand Down Expand Up @@ -529,6 +531,54 @@ end check

---

### ed25519_verify

**Purpose:** Verify an Ed25519 public-key signature (RFC 8032). This is the activation-prerequisite verifier: a site can later sign an offline payload with a private key and check it here with the matching public key. WFL does not generate keys or create signatures.

**Signature:**
```wfl
ed25519_verify of <public_key> and <message> and <signature>
```

**Parameters:**
- `public_key` (Text): 32-byte Ed25519 public key as 64 hexadecimal characters
- `message` (Text): The exact signed payload. The verified bytes are this text's UTF-8 encoding — no extra prefix, suffix, or hash is applied
- `signature` (Text): 64-byte Ed25519 signature as 128 hexadecimal characters

**Returns:** Boolean — `yes` only when the signature is valid for that public key and those message bytes

**Encodings:** Hex digits `0-9` `a-f` `A-F` only. PEM, OpenSSH, Base64, `0x` prefixes, and whitespace are unsupported.

**Limits:** Messages longer than 1,048,576 UTF-8 bytes are rejected. Public keys and signatures have fixed sizes.

**Behavior:**
- Valid signature → `yes`
- Wrong key, tampered message, or invalid signature → `no`
- Truncated, non-hex, or unsupported encodings → runtime error naming `ed25519_verify` and the expected hex length. The error does not echo the key, message, or signature.

**Example (RFC 8032 TEST 2):**
```wfl
store public_key as "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c"
store signature as "92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00"
store accepted as ed25519_verify of public_key and "r" and signature

check if accepted:
display "Signature is valid"
otherwise:
display "Signature is not valid"
end check
```

**Library:** Verification is implemented with [`ed25519-dalek`](https://crates.io/crates/ed25519-dalek) 2.x. WFL does not implement Edwards arithmetic itself.

**Use Cases:**
- Future Logbie website / logger activation (offline public-key check)
- Verifying any RFC 8032 Ed25519 signature whose payload is UTF-8 text

**Note:** Existing Logbie licence keys remain `LOGBIE-<id>-<HMAC-SHA256>` and still use `hmac_sha256`. `ed25519_verify` does not replace that path.

---

### pbkdf2_hmac_sha256

**Purpose:** Derive a key from a password using PBKDF2-HMAC-SHA256 with a caller-supplied salt, iteration count, and output length. Runs the iteration loop in native code, so the per-call cost is bounded and predictable.
Expand Down Expand Up @@ -894,6 +944,7 @@ display "Unique items: " with unique_items
✅ **Use salts for domain separation:** `wflhash256_with_salt` keeps contexts apart

✅ **Use standard MACs for external auth:** `hmac_sha256` for webhooks and third-party APIs
✅ **Use `ed25519_verify` for Ed25519 signatures:** hex public key, UTF-8 message, hex signature

✅ **Keep keys secret:** Never expose keys in logs

Expand Down Expand Up @@ -937,6 +988,7 @@ display "Unique items: " with unique_items
**Production passwords:** multi-hash pre-mix recommended, then always `hash_password` (Argon2id) or the algorithm-specific helpers
**Regulatory / FIPS-only paths:** `sha256` (or another validated standard) without depending on WFLHASH
**External webhooks / API signing:** `hmac_sha256`
**Ed25519 public-key signatures:** `ed25519_verify`
**Digital signatures / encryption:** Not provided by this module — use appropriate external tooling

**WFLHASH is experimental: test it freely; for production integrity and sensitive data, bring a strong friend (`sha256` or another known-good hash) — and for passwords, finish with a password KDF.**
Expand All @@ -949,6 +1001,7 @@ In this module, you learned:
✅ **hash_password / verify_password** - Required password KDF (Argon2id by default)
✅ **argon2 / bcrypt / scrypt / pbkdf2** - Algorithm-specific password hashing
✅ **sha256 / hmac_sha256** - Standard hashing and MAC for interoperability
✅ **ed25519_verify** - RFC 8032 Ed25519 public-key verification
✅ **wflhash256 / wflhash512** - Experimental WFLHASH (test it!)
✅ **Dual-hash production pattern** - WFLHASH then a known-good hash
✅ **wflhash256_with_salt** - Salted / domain-separated hashing
Expand Down
2 changes: 2 additions & 0 deletions Docs/05-standard-library/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ WFL's standard library provides:
- `hash_password` / `verify_password` - Safe password storage (Argon2id by default)
- `argon2_hash`, `bcrypt_hash`, `scrypt_hash`, `pbkdf2_hash` (+ matching `*_verify`) - Password hashing
- `sha256` / `hmac_sha256` - Standard hash and MAC
- `ed25519_verify` - RFC 8032 Ed25519 signature verification
- `wflhash256` / `wflhash512` - Experimental WFLHASH (dual-hash with `sha256` for production)
- `wflhash256_with_salt` - Experimental salted WFLHASH
- `wflmac256` - Experimental WFL message authentication code
Expand Down Expand Up @@ -222,6 +223,7 @@ Try every function interactively!
### Crypto Module
- Password hashing: hash_password, verify_password, argon2/bcrypt/scrypt/pbkdf2 (_hash and _verify)
- Standard: sha256, hmac_sha256
- Public-key signatures: ed25519_verify
- WFLHASH (experimental): wflhash256, wflhash512, wflhash256_with_salt, wflmac256 — dual-hash with sha256 for production
- Tokens: generate_csrf_token

Expand Down
1 change: 1 addition & 0 deletions Docs/05-standard-library/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ store upper as touppercase of "text"
- [Managed authentication](auth-module.md): session stores, rotation and revocation, request CSRF guards, secure cookies, and account attempt limits
- Authenticated encryption: `seal`, `unseal` (XChaCha20-Poly1305) — for secrets you must read back
- Standard hashing/MAC: `sha256`, `hmac_sha256`
- Public-key signatures: `ed25519_verify` (RFC 8032 Ed25519; verify only)
- WFLHASH (experimental): `wflhash256`, `wflhash512`, `wflhash256_with_salt`, `wflmac256` — dual-hash with `sha256` for production

### Configuration (TOML)
Expand Down
2 changes: 1 addition & 1 deletion Docs/06-best-practices/security-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ If WFLHASH were ever weaker than expected, the outer standard hash still provide

❌ **WFLHASH alone as the only integrity guarantee** for high-stakes data
❌ **Password hashing** — Use `hash_password`/`verify_password` (Argon2id, bcrypt, scrypt, PBKDF2)
❌ **External protocols** that require a specific standard (`hmac_sha256` for Stripe/GitHub, etc.)
❌ **External protocols** that require a specific standard (`hmac_sha256` for Stripe/GitHub, `ed25519_verify` for RFC 8032 Ed25519, etc.)
❌ **FIPS-only / formally validated crypto paths** — use the standard algorithm alone

**[Complete crypto guidelines →](../05-standard-library/crypto-module.md)**
Expand Down
3 changes: 2 additions & 1 deletion Docs/reference/builtin-functions-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,13 @@ Store user passwords with these — never with fast hashes like `sha256` or `wfl
| `constant_time_equals` | `constant_time_equals of <a> and <b>` | Boolean | Timing-safe string comparison |
| `secure_random_bytes` | `secure_random_bytes of <n>` | Text | `n` CSPRNG bytes as hex (for salts, tokens, session IDs) |

### Hashing & MAC (7 functions)
### Hashing, MAC & signatures (8 functions)

| Function | Signature | Returns | Description |
|----------|-----------|---------|-------------|
| `sha256` | `sha256 of <text>` | Text | Standard SHA-256 (FIPS 180-4) |
| `hmac_sha256` | `hmac_sha256 of <message> and <key>` | Text | Standard HMAC-SHA256 (RFC 2104) |
| `ed25519_verify` | `ed25519_verify of <public_key> and <message> and <signature>` | Boolean | RFC 8032 Ed25519 verification (hex key and signature) |
| `wflhash256` | `wflhash256 of <text>` | Text | Experimental 256-bit WFLHASH |
| `wflhash256_with_salt` | `wflhash256_with_salt of <text> and <salt>` | Text | Experimental salted WFLHASH |
| `wflhash512` | `wflhash512 of <text>` | Text | Experimental 512-bit WFLHASH |
Expand Down
Loading
Loading