bolt4

Onion routing protocol, per BOLT #4.
git clone git://git.ppad.tech/bolt4.git
Log | Files | Refs | README | LICENSE

commit 7c32a438cf58b1f6a3a90a570e7f051a9bbaf76a
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun, 25 Jan 2026 14:16:37 +0400

ppad-bolt4: initial project skeleton

BOLT4 onion routing implementation for Lightning Network.

Includes:
- Library stub (Lightning.Protocol.BOLT4)
- Test/benchmark scaffolding
- Nix flake with deps: ppad-chacha, ppad-hmac-sha256,
  ppad-secp256k1, ppad-sha256

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Diffstat:
A.gitignore | 1+
AAGENTS.md | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ACHANGELOG | 4++++
ALICENSE | 20++++++++++++++++++++
AREADME.md | 20++++++++++++++++++++
Abench/Main.hs | 10++++++++++
Abench/Weight.hs | 9+++++++++
Aflake.nix | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib/Lightning/Protocol/BOLT4.hs | 23+++++++++++++++++++++++
Appad-bolt4.cabal | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/Main.hs | 9+++++++++
11 files changed, 382 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +dist-newstyle/ diff --git a/AGENTS.md b/AGENTS.md @@ -0,0 +1,76 @@ +# ppad-bolt4 + +A pure Haskell implementation of BOLT4 (onion routing) from the +Lightning Network specification. + +The implementation consists of the ppad-bolt4 library, a test suite, +and benchmarks (for time and space). + +## build + +Builds are handled via Nix and Cabal. Enter a development shell via: + + $ nix develop + +and then do Cabal stuff: + + $ cabal build + $ cabal test + $ cabal bench + +## deps + +The following dependencies are allowed freely: + +* Any GHC boot library or library included with GHC's normal + distribution (e.g. bytestring, primitive, etc.). +* Any 'ppad-' library, as found on github.com/ppad-tech or + git.ppad.tech. + +Any other library requires explicit confirmation before being used. + +Test and benchmark dependencies (e.g. tasty, criterion, QuickCheck, +etc.) are an exception. + +Never use Stack or any non-Nix build or dependency management +tool. Never use 'pip install' or 'npm install' or anything of the +sort. The Nix development environment includes everything one +needs. + +## style + +Please adhere to the following guidelines: + +* Keep lines at less than 80 characters in length. +* The codebase is Haskell2010. +* LANGUAGE pragmas should be added per-module. +* Haddock documentation where appropriate; use `{-# OPTIONS_HADDOCK + prune #-}` and `-- |`-style comments for public modules. +* Prefer total functions; avoid partial Prelude functions such + as 'head', 'tail', '!!', etc. +* Use strict annotations (bang patterns, etc.) liberally. Add + UNPACK pragmas in data types. +* Use newtypes for type safety. +* Use smart constructors for validation. +* Use Maybe/Either for fallible operations. +* Use MagicHash/UnboxedTuples for hot paths. +* Add INLINE pragmas for small functions. + +## git + +* Never update the git config. +* Never use destructive git commands (such as push --force, hard reset, + etc.) unless explicitly requested. +* Never skip hooks unless explicitly requested. +* The main branch is `master`, which mostly consists of merge commits. + Feature branches are branched from and merged (with `--no-ff`) back + to master. + +## misc + +* Be very cautious when suggesting changes to the flake.nix file. You + should fully understand the effect of any change before making it. +* Don't create markdown files, e.g. for documentation purposes. +* When producing plans, highlight any steps that could potentially be + executed by concurrent subagents. Place plans in the `plans/` + directory, e.g. as `plans/IMPL1.md`. diff --git a/CHANGELOG b/CHANGELOG @@ -0,0 +1,4 @@ +# Changelog + +- 0.0.1 (UNRELEASED) + * Initial release. diff --git a/LICENSE b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2025 Jared Tobin + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md @@ -0,0 +1,20 @@ +# ppad-bolt4 + +A pure Haskell implementation of [BOLT4][bolt4] (onion routing) from +the Lightning Network protocol specification. + +## Documentation + +Haddocks (API documentation, etc.) are hosted at +[docs.ppad.tech/bolt4][hadoc]. + +## Security + +This library is provided for educational purposes. It has not been +audited by a third party, and should not be used in production. + +If you discover any security-related issues, please contact +jared@ppad.tech. + +[bolt4]: https://github.com/lightning/bolts/blob/master/04-onion-routing.md +[hadoc]: https://docs.ppad.tech/bolt4 diff --git a/bench/Main.hs b/bench/Main.hs @@ -0,0 +1,10 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +import Criterion.Main + +main :: IO () +main = defaultMain [ + ] diff --git a/bench/Weight.hs b/bench/Weight.hs @@ -0,0 +1,9 @@ +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +import Weigh + +main :: IO () +main = mainWith (pure ()) diff --git a/flake.nix b/flake.nix @@ -0,0 +1,134 @@ +{ + description = "A Haskell implementation of BOLT4 (onion routing)."; + + inputs = { + ppad-base16 = { + type = "git"; + url = "git://git.ppad.tech/base16.git"; + ref = "master"; + inputs.ppad-nixpkgs.follows = "ppad-nixpkgs"; + }; + ppad-chacha = { + type = "git"; + url = "git://git.ppad.tech/chacha.git"; + ref = "master"; + inputs.ppad-nixpkgs.follows = "ppad-nixpkgs"; + }; + ppad-hmac-sha256 = { + type = "git"; + url = "git://git.ppad.tech/hmac-sha256.git"; + ref = "master"; + inputs.ppad-nixpkgs.follows = "ppad-nixpkgs"; + inputs.ppad-sha256.follows = "ppad-sha256"; + }; + ppad-secp256k1 = { + type = "git"; + url = "git://git.ppad.tech/secp256k1.git"; + ref = "master"; + inputs.ppad-nixpkgs.follows = "ppad-nixpkgs"; + inputs.ppad-sha256.follows = "ppad-sha256"; + }; + ppad-sha256 = { + type = "git"; + url = "git://git.ppad.tech/sha256.git"; + ref = "master"; + inputs.ppad-nixpkgs.follows = "ppad-nixpkgs"; + }; + ppad-nixpkgs = { + type = "git"; + url = "git://git.ppad.tech/nixpkgs.git"; + ref = "master"; + }; + flake-utils.follows = "ppad-nixpkgs/flake-utils"; + nixpkgs.follows = "ppad-nixpkgs/nixpkgs"; + }; + + outputs = { self, nixpkgs, flake-utils, ppad-nixpkgs + , ppad-base16, ppad-chacha, ppad-hmac-sha256 + , ppad-secp256k1, ppad-sha256 + }: + flake-utils.lib.eachDefaultSystem (system: + let + lib = "ppad-bolt4"; + + pkgs = import nixpkgs { inherit system; }; + hlib = pkgs.haskell.lib; + llvm = pkgs.llvmPackages_19.llvm; + clang = pkgs.llvmPackages_19.clang; + + base16 = ppad-base16.packages.${system}.default; + base16-llvm = + hlib.addBuildTools + (hlib.enableCabalFlag base16 "llvm") + [ llvm clang ]; + + chacha = ppad-chacha.packages.${system}.default; + chacha-llvm = + hlib.addBuildTools + (hlib.enableCabalFlag chacha "llvm") + [ llvm clang ]; + + hmac-sha256 = ppad-hmac-sha256.packages.${system}.default; + hmac-sha256-llvm = + hlib.addBuildTools + (hlib.enableCabalFlag hmac-sha256 "llvm") + [ llvm clang ]; + + secp256k1 = ppad-secp256k1.packages.${system}.default; + secp256k1-llvm = + hlib.addBuildTools + (hlib.enableCabalFlag secp256k1 "llvm") + [ llvm clang ]; + + sha256 = ppad-sha256.packages.${system}.default; + sha256-llvm = + hlib.addBuildTools + (hlib.enableCabalFlag sha256 "llvm") + [ llvm clang ]; + + hpkgs = pkgs.haskell.packages.ghc910.extend (new: old: { + ppad-base16 = base16-llvm; + ppad-chacha = chacha-llvm; + ppad-hmac-sha256 = hmac-sha256-llvm; + ppad-secp256k1 = secp256k1-llvm; + ppad-sha256 = sha256-llvm; + ${lib} = new.callCabal2nix lib ./. { + ppad-base16 = new.ppad-base16; + ppad-chacha = new.ppad-chacha; + ppad-hmac-sha256 = new.ppad-hmac-sha256; + ppad-secp256k1 = new.ppad-secp256k1; + ppad-sha256 = new.ppad-sha256; + }; + }); + + cc = pkgs.stdenv.cc; + ghc = hpkgs.ghc; + cabal = hpkgs.cabal-install; + in + { + packages.default = hpkgs.${lib}; + + packages.haddock = hpkgs.${lib}.doc; + + devShells.default = hpkgs.shellFor { + packages = p: [ + (hlib.doBenchmark p.${lib}) + ]; + + buildInputs = [ + cabal + cc + llvm + ]; + + shellHook = '' + PS1="[${lib}] \w$ " + echo "entering ${system} shell, using" + echo "cc: $(${cc}/bin/cc --version)" + echo "ghc: $(${ghc}/bin/ghc --version)" + echo "cabal: $(${cabal}/bin/cabal --version)" + ''; + }; + } + ); +} diff --git a/lib/Lightning/Protocol/BOLT4.hs b/lib/Lightning/Protocol/BOLT4.hs @@ -0,0 +1,23 @@ +{-# OPTIONS_HADDOCK prune #-} +{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} + +-- | +-- Module: Lightning.Protocol.BOLT4 +-- Copyright: (c) 2025 Jared Tobin +-- License: MIT +-- Maintainer: Jared Tobin <jared@ppad.tech> +-- +-- BOLT4 onion routing for the Lightning Network. + +module Lightning.Protocol.BOLT4 ( + -- placeholder exports + ) where + +import qualified Data.ByteString as BS + +-- XX placeholder +_placeholder :: BS.ByteString -> BS.ByteString +_placeholder = id diff --git a/ppad-bolt4.cabal b/ppad-bolt4.cabal @@ -0,0 +1,76 @@ +cabal-version: 3.0 +name: ppad-bolt4 +version: 0.0.1 +synopsis: BOLT4 (onion routing) for Lightning Network +license: MIT +license-file: LICENSE +author: Jared Tobin +maintainer: jared@ppad.tech +category: Cryptography +build-type: Simple +tested-with: GHC == 9.10.3 +description: + A pure Haskell implementation of BOLT4 (onion routing) from + the Lightning Network protocol specification. + +source-repository head + type: git + location: git://git.ppad.tech/bolt4.git + +library + default-language: Haskell2010 + hs-source-dirs: lib + ghc-options: + -Wall + exposed-modules: + Lightning.Protocol.BOLT4 + build-depends: + base >= 4.9 && < 5 + , bytestring >= 0.9 && < 0.13 + , ppad-chacha >= 0.1 && < 0.2 + , ppad-hmac-sha256 >= 0.1 && < 0.2 + , ppad-secp256k1 >= 0.3 && < 0.4 + , ppad-sha256 >= 0.3 && < 0.4 + +test-suite bolt4-tests + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: test + main-is: Main.hs + ghc-options: + -rtsopts -Wall -O2 + build-depends: + base + , bytestring + , ppad-base16 + , ppad-bolt4 + , tasty + , tasty-hunit + , tasty-quickcheck + +benchmark bolt4-bench + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: bench + main-is: Main.hs + ghc-options: + -rtsopts -O2 -Wall -fno-warn-orphans + build-depends: + base + , bytestring + , criterion + , deepseq + , ppad-bolt4 + +benchmark bolt4-weigh + type: exitcode-stdio-1.0 + default-language: Haskell2010 + hs-source-dirs: bench + main-is: Weight.hs + ghc-options: + -rtsopts -O2 -Wall -fno-warn-orphans + build-depends: + base + , bytestring + , ppad-bolt4 + , weigh diff --git a/test/Main.hs b/test/Main.hs @@ -0,0 +1,9 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Main where + +import Test.Tasty + +main :: IO () +main = defaultMain $ testGroup "ppad-bolt4" [ + ]