Skip to content
Open
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
17 changes: 17 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,20 @@ jobs:
uses: Swatinem/rust-cache@v2
- name: "Build fuzz targets"
run: cd fuzz && cargo build

Embedded:
name: Embedded build
env:
CARGO_PROFILE_DEV_DEBUG: "0"
runs-on: ubuntu-26.04
steps:
- name: "Checkout repo"
uses: actions/checkout@v6
- name: "Use cache"
uses: Swatinem/rust-cache@v2
- name: "Install nix"
uses: DeterminateSystems/determinate-nix-action@main
- name: "Build embedded target v2"
run: nix develop .#embedded -c cargo build -p payjoin --no-default-features --features "alloc,v2" --target thumbv7em-none-eabihf -Zbuild-std=core,alloc
- name: "Build embedded target v1"
run: nix develop .#embedded -c cargo build -p payjoin --no-default-features --features "alloc,v2" --target thumbv7em-none-eabihf -Zbuild-std=core,alloc
15 changes: 8 additions & 7 deletions Cargo-minimal.lock
Original file line number Diff line number Diff line change
Expand Up @@ -452,9 +452,9 @@ dependencies = [

[[package]]
name = "base64"
version = "0.21.3"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"

[[package]]
name = "base64"
Expand Down Expand Up @@ -542,7 +542,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf93e61f2dbc3e3c41234ca26a65e2c0b0975c52e0f069ab9893ebbede584d3"
dependencies = [
"base58ck",
"base64 0.21.3",
"base64 0.21.7",
"bech32",
"bitcoin-internals 0.3.0",
"bitcoin-io",
Expand Down Expand Up @@ -2569,6 +2569,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
name = "payjoin"
version = "1.0.0-rc.8"
dependencies = [
"base64 0.21.7",
"bhttp",
"bitcoin",
"bitcoin-hpke",
Expand Down Expand Up @@ -2736,7 +2737,7 @@ version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3163d2912b7c3b52d651a055f2c7eec9ba5cd22d26ef75b8dd3a59980b185923"
dependencies = [
"base64 0.21.3",
"base64 0.21.7",
"serde",
]

Expand Down Expand Up @@ -3258,7 +3259,7 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64 0.21.3",
"base64 0.21.7",
"bitflags 2.5.0",
"serde",
"serde_derive",
Expand Down Expand Up @@ -3355,7 +3356,7 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35e4980fa29e4c4b212ffb3db068a564cbf560e51d3944b7c88bd8bf5bec64f4"
dependencies = [
"base64 0.21.3",
"base64 0.21.7",
"rustls-pki-types",
]

Expand Down Expand Up @@ -3589,7 +3590,7 @@ version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
dependencies = [
"base64 0.21.3",
"base64 0.21.7",
"chrono",
"hex",
"indexmap 1.8.0",
Expand Down
1 change: 1 addition & 0 deletions Cargo-recent.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2700,6 +2700,7 @@ checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
name = "payjoin"
version = "1.0.0-rc.8"
dependencies = [
"base64 0.21.7",
"bhttp",
"bitcoin",
"bitcoin-hpke",
Expand Down
19 changes: 19 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,24 @@
AR_wasm32_unknown_unknown = "${pkgs.llvmPackages.bintools-unwrapped}/bin/llvm-ar";
};

embeddedRustToolchain = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml).override {
extensions = [
"rust-src"
"rustfmt"
"llvm-tools-preview"
];
targets = [ "thumbv7em-none-eabihf" ];
};

embeddedDevShell = pkgs.mkShell {
name = "embedded-dev";
packages = with pkgs; [
embeddedRustToolchain
gcc-arm-embedded
];
CC_thumbv7em_none_eabihf = "arm-none-eabi-gcc";
};

dartDevShell = pkgs.mkShell {
name = "dart-dev";
packages =
Expand Down Expand Up @@ -484,6 +502,7 @@
javascript = javascriptDevShell;
csharp = csharpDevShell;
dart = dartDevShell;
embedded = embeddedDevShell;
};
formatter = treefmtEval.config.build.wrapper;
checks =
Expand Down
1 change: 1 addition & 0 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ home = "=0.5.11"
libfuzzer-sys = { version = "0.4.10" }
payjoin = { path = "../payjoin", default-features = false, features = [
"_core",
"std",
"v1",
"v2",
] }
Expand Down
2 changes: 1 addition & 1 deletion payjoin-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ path = "src/main.rs"
default = ["v2"]
native-certs = ["reqwest/rustls-tls-native-roots"]
_manual-tls = ["reqwest/rustls-tls", "payjoin/_manual-tls", "tokio-rustls"]
v1 = ["payjoin/v1", "hyper", "hyper-util", "http-body-util"]
v1 = ["payjoin/v1", "payjoin/std", "hyper", "hyper-util", "http-body-util"]
v2 = ["payjoin/v2", "payjoin/io"]

[dependencies]
Expand Down
43 changes: 30 additions & 13 deletions payjoin/Cargo.toml
Comment thread
benalleng marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,41 @@ exclude = ["tests"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
default = ["v2"]
#[doc = "Core features for payjoin state machines"]
_core = [
default = ["std", "v2", "v2-ohttp"]

alloc = []

std = [
"alloc",
"bitcoin/rand-std",
"dep:http",
"bitcoin/base64",
"serde_json",
"dep:percent-encoding-rfc3986",
"bitcoin_uri",
"bitcoin_uri/std",
"serde",
"bitcoin/serde",
]
directory = []
v1 = ["_core"]
v2 = ["_core", "hpke", "hkdf", "bhttp", "ohttp", "directory"]
#[doc = "Core features for payjoin state machines"]
_core = ["alloc", "serde", "bitcoin/serde"]

directory = ["alloc", "_core"]
v1 = ["_core", "alloc", "dep:base64"]

v2 = ["_core", "directory", "hkdf", "dep:base64"]

v2-ohttp = ["v2", "std", "dep:hpke", "dep:bhttp", "dep:ohttp", "dep:http"]
#[doc = "Functions to fetch OHTTP keys via CONNECT proxy using reqwest. Enables `v2` since only `v2` uses OHTTP."]
io = ["v2", "reqwest/rustls-tls"]
_manual-tls = ["rustls"]
io = ["v2-ohttp", "reqwest/rustls-tls", "dep:reqwest"]
_manual-tls = ["reqwest/rustls-tls", "rustls"]

[dependencies]
base64 = { version = "0.21.7", default-features = false, features = [
"alloc",
], optional = true }
bhttp = { version = "0.6.1", optional = true }
bitcoin = { version = "0.32.9", features = ["base64"] }
bitcoin-units = "0.1.3"
bitcoin = { version = "0.32.9", default-features = false, features = ["rand"] }
bitcoin-units = { version = "0.1.3", default-features = false }
bitcoin_uri = { version = "0.1.0", optional = true }
hkdf = { version = "0.12.3", optional = true }
hpke = { package = "bitcoin-hpke", version = "0.13.0", optional = true }
Expand All @@ -54,7 +66,9 @@ rustls = { version = "0.23.38", optional = true, default-features = false, featu
] }
serde = { version = "1.0.228", default-features = false, optional = true }
serde_json = { version = "1.0.149", optional = true }
tracing = "0.1.41"
tracing = { version = "0.1.41", default-features = false, features = [
"attributes",
] }

[target.'cfg(target_arch = "wasm32")'.dependencies]
web-time = "1.1.0"
Expand All @@ -67,7 +81,10 @@ ignored = ["bitcoin-units", "hkdf"]
once_cell = "1.21.3"
payjoin-test-utils = { path = "../payjoin-test-utils", features = ["v2"] }
tokio = { version = "1.52.3", features = ["full"] }
tracing = "0.1.41"
tracing = { version = "0.1.41", default-features = false, features = [
"attributes",
] }


[package.metadata.docs.rs]
all-features = true
Expand Down
2 changes: 2 additions & 0 deletions payjoin/contrib/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ features=("v1" "v2")

cargo test --locked --package payjoin --verbose --all-features --lib
cargo test --locked --package payjoin --verbose --all-features --test integration
cargo test --locked --package payjoin --verbose --all-features --test e2e
cargo test --locked --package payjoin --verbose --no-default-features --features alloc,v1 --test e2e

for feature in "${features[@]}"; do
cargo test --locked --package payjoin --verbose --no-default-features --features "$feature" --lib --no-run
Expand Down
5 changes: 5 additions & 0 deletions payjoin/src/bech32.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[cfg(feature = "alloc")]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;

use bitcoin::bech32::primitives::decode::{CheckedHrpstring, CheckedHrpstringError};
use bitcoin::bech32::{self, EncodeError, Hrp, NoChecksum};

Expand Down
39 changes: 33 additions & 6 deletions payjoin/src/core/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
use std::fmt::Debug;
use std::{error, fmt};
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(feature = "v2")]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use core::error;
use core::fmt::{self, Debug};
#[cfg(feature = "std")]
use std::error;
#[derive(Debug)]
pub struct StdRequiredError;

impl fmt::Display for StdRequiredError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "std is required for this operation")
}
}

#[cfg(feature = "std")]
impl std::error::Error for StdRequiredError {}

#[cfg(not(feature = "std"))]
impl core::error::Error for StdRequiredError {}

impl ImplementationError {
pub fn std_required() -> Self { ImplementationError(Box::new(StdRequiredError)) }
}
#[derive(Debug)]
pub struct ImplementationError(Box<dyn error::Error + Send + Sync>);

Expand All @@ -11,7 +35,7 @@ impl ImplementationError {
}

impl fmt::Display for ImplementationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { std::fmt::Display::fmt(&self.0, f) }
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
}

impl error::Error for ImplementationError {
Expand All @@ -34,16 +58,17 @@ impl From<&str> for ImplementationError {
ImplementationError::from(error)
}
}

/// Errors that can occur when replaying a session event log
#[cfg(feature = "v2")]
#[derive(Debug)]
pub struct ReplayError<SessionState, SessionEvent>(InternalReplayError<SessionState, SessionEvent>);

#[cfg(feature = "v2")]
impl<SessionState: Debug, SessionEvent: Debug> std::fmt::Display
impl<SessionState: Debug, SessionEvent: Debug> fmt::Display
for ReplayError<SessionState, SessionEvent>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use InternalReplayError::*;
match &self.0 {
NoEvents => write!(f, "No events found in session"),
Expand All @@ -58,8 +83,9 @@ impl<SessionState: Debug, SessionEvent: Debug> std::fmt::Display
}
}
}

#[cfg(feature = "v2")]
impl<SessionState: Debug, SessionEvent: Debug> std::error::Error
impl<SessionState: Debug, SessionEvent: Debug> error::Error
for ReplayError<SessionState, SessionEvent>
{
}
Expand Down Expand Up @@ -93,6 +119,7 @@ impl<SessionState, SessionEvent> ReplayError<SessionState, SessionEvent> {

#[cfg(feature = "v2")]
#[derive(Debug)]
#[allow(dead_code)]
pub(crate) enum InternalReplayError<SessionState, SessionEvent> {
/// No events in the event log
NoEvents,
Expand Down
7 changes: 7 additions & 0 deletions payjoin/src/core/hpke.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#![cfg(any(feature = "v2", feature = "v2-ohttp"))]
use alloc::vec::Vec;
#[cfg(not(feature = "std"))]
use core::error;
use core::fmt;
#[cfg(feature = "std")]
use std::error;

use bitcoin::key::constants::{ELLSWIFT_ENCODING_SIZE, PUBLIC_KEY_SIZE};
Expand Down Expand Up @@ -182,6 +187,7 @@ pub fn decrypt_message_a(
message_a: &[u8],
receiver_sk: &HpkeSecretKey,
) -> Result<(Vec<u8>, HpkePublicKey), HpkeError> {
#[cfg(feature = "std")]
use std::io::{Cursor, Read};

let mut cursor = Cursor::new(message_a);
Expand Down Expand Up @@ -230,6 +236,7 @@ pub fn encrypt_message_b(
Ok(message_b)
}

#[cfg(feature = "std")]
pub fn decrypt_message_b(
message_b: &[u8],
receiver_pk: HpkePublicKey,
Expand Down
9 changes: 6 additions & 3 deletions payjoin/src/core/into_url.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use alloc::string::String;
use core::{error, fmt};

use crate::core::{Url, UrlParseError};

#[derive(Debug, PartialEq, Eq)]
Expand All @@ -7,8 +10,8 @@ pub enum Error {
ParseError(UrlParseError),
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Error::*;

match self {
Expand All @@ -18,7 +21,7 @@ impl std::fmt::Display for Error {
}
}

impl std::error::Error for Error {}
impl error::Error for Error {}

impl From<UrlParseError> for Error {
fn from(err: UrlParseError) -> Error { Error::ParseError(err) }
Expand Down
3 changes: 2 additions & 1 deletion payjoin/src/core/io.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
//! IO-related types and functions. Specifically, fetching OHTTP keys from a payjoin directory.
#[cfg(feature = "std")]
use std::time::Duration;

use http::header::ACCEPT;
use reqwest::{Client, Proxy};

use crate::into_url::IntoUrl;
use crate::OhttpKeys;
use crate::ohttp::OhttpKeys;

/// Fetch the ohttp keys from the specified payjoin directory via proxy.
///
Expand Down
Loading
Loading