Skip to content
Merged
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 .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
third_party/bip39/english.txt text eol=lf
third_party/arborkdf-wordlists/en_tr_jp_131072.txt text eol=lf
third_party/arborkdf-wordlists/en_tr_jp_131072.manifest.json text eol=lf
include/arborkdf/generated/*.hpp text eol=lf
extras/*.py text eol=lf
tests/*.py text eol=lf
third_party/scowl/COPYRIGHT -whitespace
third_party/mecab-naist-jdic/COPYING -whitespace
79 changes: 79 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: CI

on:
push:
pull_request:

permissions:
contents: read

jobs:
linux:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y g++ make libssl-dev libargon2-dev zlib1g-dev
- name: Build and test
run: make check
- name: Sanitizers
run: ASAN_OPTIONS=detect_leaks=0 make sanitize
- name: Static build
run: |
make clean
make STATIC=1 check
- name: Verify static executable
run: |
file arborkdf-static
file arborkdf-static | grep -q "statically linked"

macos:
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: brew install argon2 openssl@3 zlib
- name: Build and test
run: |
dependency_cppflags="-I$(brew --prefix openssl@3)/include -I$(brew --prefix argon2)/include -I$(brew --prefix zlib)/include"
dependency_ldflags="-L$(brew --prefix openssl@3)/lib -L$(brew --prefix argon2)/lib -L$(brew --prefix zlib)/lib"
make TARGET_OS=darwin CPPFLAGS="$dependency_cppflags" LDFLAGS="$dependency_ldflags" check

windows:
runs-on: windows-2022
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- name: Enable native symlinks for tests
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
New-Item -Path $key -Force | Out-Null
New-ItemProperty -Path $key `
-Name AllowDevelopmentWithoutDevLicense `
-PropertyType DWord -Value 1 -Force | Out-Null
if ((Get-ItemPropertyValue -Path $key `
-Name AllowDevelopmentWithoutDevLicense) -ne 1) {
throw "failed to enable Developer Mode for native symlink tests"
}
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
make
python
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-openssl
mingw-w64-ucrt-x86_64-argon2
mingw-w64-ucrt-x86_64-zlib
- name: Build and test
env:
MSYS: winsymlinks:nativestrict
ARBORKDF_TEST_REQUIRE_NATIVE_SYMLINK: "1"
run: make TARGET_OS=windows check
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/arborkdf
/arborkdf-tests
/build/
*.o
*.d
*.a
*.so
*.dylib
*.dll
*.exe
*.out
__pycache__/
*.pyc
.DS_Store
171 changes: 171 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
CXX ?= c++
PYTHON ?= python3

UNAME_S := $(shell uname -s 2>/dev/null || echo Unknown)
ifeq ($(OS),Windows_NT)
TARGET_OS ?= windows
else ifeq ($(UNAME_S),Linux)
TARGET_OS ?= linux
else ifeq ($(UNAME_S),Darwin)
TARGET_OS ?= darwin
else
TARGET_OS ?= unknown
endif

ifeq ($(filter $(TARGET_OS),linux darwin windows),)
$(error unsupported TARGET_OS '$(TARGET_OS)'; use linux, darwin, or windows)
endif

EXEEXT :=
NULL_DEVICE := /dev/null
CLI_TEST_ENV :=
ifeq ($(TARGET_OS),windows)
EXEEXT := .exe
NULL_DEVICE := NUL
# MSYS2 otherwise rewrites virtual paths such as /testing/path before the
# native Windows program receives them.
CLI_TEST_ENV := MSYS2_ARG_CONV_EXCL='*' MSYS_NO_PATHCONV=1
endif

BUILD_MODE := dynamic
PROGRAM_STEM := arborkdf
TEST_STEM := arborkdf-tests
OPTFLAGS := -O2
ifeq ($(STATIC),1)
BUILD_MODE := static
PROGRAM_STEM := arborkdf-static
TEST_STEM := arborkdf-tests-static
ARBORKDF_LDFLAGS += -static
endif
ifeq ($(SANITIZE),1)
BUILD_MODE := $(BUILD_MODE)-sanitize
OPTFLAGS := -O1
ARBORKDF_CXXFLAGS += -g -fno-omit-frame-pointer -fsanitize=address,undefined
ARBORKDF_LDFLAGS += -fsanitize=address,undefined
endif

PROGRAM := $(PROGRAM_STEM)$(EXEEXT)
TEST_PROGRAM := $(TEST_STEM)$(EXEEXT)
BUILD_DIR := build/$(TARGET_OS)-$(BUILD_MODE)

ARBORKDF_CPPFLAGS += -Iinclude -Ithird_party/argon2
ARBORKDF_CXXFLAGS += -std=c++17 $(OPTFLAGS) -Wall -Wextra -Wpedantic -Wconversion \
-Wsign-conversion -Wshadow -Wformat=2 -Wnull-dereference -Wdouble-promotion \
-Werror -MMD -MP

OPENSSL_LIBS ?= -lcrypto
ARGON2_LIBS ?= -largon2
ZLIB_LIBS ?= -lz
ARBORKDF_LDLIBS += $(OPENSSL_LIBS) $(ARGON2_LIBS) $(ZLIB_LIBS)

ifeq ($(TARGET_OS),linux)
ARBORKDF_LDLIBS += -pthread -ldl
endif
ifeq ($(TARGET_OS),darwin)
ARBORKDF_LDLIBS += -pthread
endif
ifeq ($(TARGET_OS),windows)
ARBORKDF_LDLIBS += -luser32
endif

LIB_SOURCES := \
src/cli.cpp \
src/codec.cpp \
src/crypto.cpp \
src/entropy.cpp \
src/file.cpp \
src/openssl_context.cpp \
src/platform.cpp \
src/wordlist.cpp
PROGRAM_SOURCES := src/main.cpp
TEST_SOURCES := \
tests/test_main.cpp \
tests/test_codec.cpp \
tests/test_crypto.cpp \
tests/test_entropy.cpp

LIB_OBJECTS := $(LIB_SOURCES:%.cpp=$(BUILD_DIR)/%.o)
PROGRAM_OBJECTS := $(PROGRAM_SOURCES:%.cpp=$(BUILD_DIR)/%.o)
TEST_OBJECTS := $(TEST_SOURCES:%.cpp=$(BUILD_DIR)/%.o)
DEPENDENCIES := $(LIB_OBJECTS:.o=.d) $(PROGRAM_OBJECTS:.o=.d) $(TEST_OBJECTS:.o=.d)

.PHONY: all clean test check static sanitize verify-wordlists regenerate-wordlists

all: $(PROGRAM)

verify-wordlists:
$(PYTHON) extras/gen_wordlist_header.py --check

regenerate-wordlists:
$(PYTHON) extras/gen_wordlist_header.py

$(LIB_OBJECTS) $(PROGRAM_OBJECTS) $(TEST_OBJECTS): | verify-wordlists

$(PROGRAM): $(LIB_OBJECTS) $(PROGRAM_OBJECTS)
$(CXX) $(LDFLAGS) $(ARBORKDF_LDFLAGS) -o $@ $^ $(LDLIBS) $(ARBORKDF_LDLIBS)

$(TEST_PROGRAM): $(LIB_OBJECTS) $(TEST_OBJECTS)
$(CXX) $(LDFLAGS) $(ARBORKDF_LDFLAGS) -o $@ $^ $(LDLIBS) $(ARBORKDF_LDLIBS)

$(BUILD_DIR)/%.o: %.cpp
@mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(ARBORKDF_CPPFLAGS) $(CXXFLAGS) $(ARBORKDF_CXXFLAGS) -c $< -o $@

test: $(TEST_PROGRAM)
./$(TEST_PROGRAM)

check: test $(PROGRAM)
$(PYTHON) tests/test_wordlist_generator.py
./$(PROGRAM) --help >$(NULL_DEVICE)
./$(PROGRAM) subkey --help >$(NULL_DEVICE)
./$(PROGRAM) masterkey --help >$(NULL_DEVICE)
./$(PROGRAM) salt --help >$(NULL_DEVICE)
./$(PROGRAM) encoding --help >$(NULL_DEVICE)
./$(PROGRAM) wordlist --help >$(NULL_DEVICE)
./$(PROGRAM) subkey generate --help >$(NULL_DEVICE)
./$(PROGRAM) masterkey generate --help >$(NULL_DEVICE)
./$(PROGRAM) salt generate --help >$(NULL_DEVICE)
./$(PROGRAM) encoding encode --help >$(NULL_DEVICE)
./$(PROGRAM) encoding decode --help >$(NULL_DEVICE)
./$(PROGRAM) wordlist list --help >$(NULL_DEVICE)
./$(PROGRAM) wordlist export --help >$(NULL_DEVICE)
$(PYTHON) tests/test_wordlist_cli.py ./$(PROGRAM)
@test "$$(./$(PROGRAM) encoding encode \
--input-hex 0000000000000000000000 --wordlist embedded_bip39)" = \
"abandon abandon abandon abandon abandon abandon abandon abandon"
@test "$$(./$(PROGRAM) encoding encode \
--input-hex 0000000000000000000000 \
--wordlist ./third_party/bip39/english.txt)" = \
"abandon abandon abandon abandon abandon abandon abandon abandon"
@test "$$(./$(PROGRAM) encoding decode \
--input-words 'abandon abandon abandon abandon abandon abandon abandon abandon' \
--wordlist embedded_bip39)" = "0000000000000000000000"
@test "$$(printf '%s\n' \
'abandon ability able about above absent absorb abstract absurd abuse access accident' | \
$(CLI_TEST_ENV) ./$(PROGRAM) subkey generate \
--input-encoding wordlist --input-wordlist embedded_bip39 --master-stdin \
--salt-hex 000102030405060708090a0b0c0d0e0f \
--path /testing/path --pbkdf2-iterations 1 \
--argon2-memory-kib 8 --argon2-iterations 1 --argon2-parallelism 1 \
--security-target 128 --output-bits 264 --output-encoding wordlist \
--output-wordlist embedded_bip39)" = \
"faith recycle bullet shrug tortoise faith recall hospital save mixed super voice pattern satoshi refuse coin fall romance snake kitchen prize rule shift school"
@test "$$(printf 'test\n' | $(CLI_TEST_ENV) ./$(PROGRAM) subkey generate \
--input-encoding utf8 --master-stdin \
--salt-hex 000102030405060708090a0b0c0d0e0f \
--path /testing/path --pbkdf2-iterations 1 \
--argon2-memory-kib 8 --argon2-iterations 1 --argon2-parallelism 1 \
--security-target 128 --output-bits 256 --output-encoding hex)" = \
"455489cba2bf8306a4ee11ba39260d7e2ba61d14474d7948f02e9e13eca4348c"

static:
$(MAKE) STATIC=1 TARGET_OS=$(TARGET_OS) all

sanitize:
$(MAKE) SANITIZE=1 TARGET_OS=$(TARGET_OS) test

clean:
rm -rf -- build arborkdf arborkdf-tests arborkdf-static arborkdf-tests-static \
arborkdf.exe arborkdf-tests.exe arborkdf-static.exe arborkdf-tests-static.exe

-include $(DEPENDENCIES)
Loading
Loading