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
99 changes: 99 additions & 0 deletions .github/workflows/build-syso.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Build syso files

on:
workflow_dispatch: # Manual trigger
push:
paths:
- 'src/**'

jobs:
build-syso:
name: Build ${{ matrix.settings.name }}
runs-on: ${{ matrix.settings.runner }}
strategy:
fail-fast: false
matrix:
settings:
- name: Linux x86
runner: ubuntu-latest
syso_name: hashtree_amd64.syso
- name: macOS arm64
runner: macos-latest
syso_name: hashtree_darwin_arm64.syso
- name: Linux arm64
runner: ubuntu-latest
cc: aarch64-linux-gnu-gcc
cross_pkg: gcc-aarch64-linux-gnu
syso_name: hashtree_linux_arm64.syso
- name: Windows x86
runner: windows-latest
syso_name: hashtree_windows_amd64.syso
- name: Linux RISC-V 64
runner: ubuntu-latest
cc: riscv64-linux-gnu-gcc
cross_pkg: gcc-riscv64-linux-gnu
syso_name: hashtree_linux_riscv64.syso
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22.x'

- name: Install cross-compiler
if: ${{ matrix.settings.cross_pkg }}
run: |
sudo apt-get update
sudo apt-get install -y ${{ matrix.settings.cross_pkg }}

- name: Build (cross-compile)
if: ${{ matrix.settings.cc }}
shell: bash
run: |
CC=${{ matrix.settings.cc }} make go_bindings
mv -f hashtree.syso ${{ matrix.settings.syso_name }}

- name: Build (native)
if: ${{ !matrix.settings.cc }}
shell: bash
run: |
make go_bindings
mv -f hashtree.syso ${{ matrix.settings.syso_name }}

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.settings.syso_name }}
path: ${{ matrix.settings.syso_name }}

commit-syso:
name: Commit syso files
needs: build-syso
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: Move syso files to root
run: |
for dir in artifacts/*/; do
mv "$dir"/*.syso .
done
ls -la *.syso

- name: Commit and push
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add *.syso
git diff --staged --quiet || git commit -m "Update syso files"
git push
39 changes: 38 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,30 @@ jobs:
- name: Windows arm64
target: aarch64-pc-windows-msvc
runner: windows-latest
- name: Linux RISC-V 64
target: riscv64-unknown-linux-gnu
runner: ubuntu-latest
cc: riscv64-linux-gnu-gcc
qemu: qemu-riscv64
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install RISC-V toolchain and QEMU
if: ${{ matrix.settings.qemu }}
run: |
sudo apt-get update
sudo apt-get install -y gcc-riscv64-linux-gnu qemu-user
- name: Cross-Compile Build
if: ${{ matrix.settings.cc != '' }}
run: CC=${{ matrix.settings.cc }} make all
- name: Build
if: ${{ !matrix.settings.cc }}
run: make all
- name: Run tests with QEMU
if: ${{ matrix.settings.qemu }}
run: ${{ matrix.settings.qemu }} -cpu rv64,zbb=true,zbc=true,zbkb=true,zbkc=true,zbkx=true,zknd=true,zkne=true,zknh=true,zkt=true -L /usr/riscv64-linux-gnu ./build/test
- name: Run tests
if: ${{ !matrix.settings.qemu }}
run: ./build/test

go-bindings:
Expand Down Expand Up @@ -75,22 +89,45 @@ jobs:
- name: Windows arm64
target: aarch64-pc-windows-msvc
runner: windows-latest
- name: Linux RISC-V 64
target: riscv64-unknown-linux-gnu
runner: ubuntu-latest
cc: riscv64-linux-gnu-gcc
qemu: qemu-riscv64
goarch: riscv64
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Install RISC-V toolchain and QEMU
if: ${{ matrix.settings.qemu }}
run: |
sudo apt-get update
sudo apt-get install -y gcc-riscv64-linux-gnu qemu-user
- name: Cross-Compile Build
if: ${{ matrix.settings.cc != '' }}
if: ${{ matrix.settings.cc != '' && !matrix.settings.qemu }}
run: CC=${{ matrix.settings.cc }} make go_bindings
- name: Build
if: ${{ !matrix.settings.cc }}
run: make go_bindings
- name: Cross-Compile Build for RISC-V
if: ${{ matrix.settings.qemu }}
run: |
CC=${{ matrix.settings.cc }} make go_bindings
mv hashtree.syso hashtree_linux_riscv64.syso
- name: Run tests
if: ${{ !matrix.settings.qemu }}
run: go test .
- name: Run tests with QEMU
if: ${{ matrix.settings.qemu }}
run: |
CGO_ENABLED=1 CC=${{ matrix.settings.cc }} GOOS=linux GOARCH=${{ matrix.settings.goarch }} go test -c -o test.riscv64
${{ matrix.settings.qemu }} -cpu rv64,zbb=true,zbc=true,zbkb=true,zbkc=true,zbkx=true,zknd=true,zkne=true,zknh=true,zkt=true -L /usr/riscv64-linux-gnu ./test.riscv64
- name: Run benchmarks
if: ${{ !matrix.settings.qemu }}
run: go test -bench=.

rust-bindings:
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Cargo.lock
target
build
tests
.gitignore
.vscode
CLAUDE.md
6 changes: 6 additions & 0 deletions bindings_riscv64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build riscv64
// +build riscv64

package hashtree

var supportedCPU = true
Binary file modified hashtree_amd64.syso
Binary file not shown.
Binary file modified hashtree_darwin_arm64.syso
Binary file not shown.
Binary file modified hashtree_linux_arm64.syso
Binary file not shown.
Binary file added hashtree_linux_riscv64.syso
Binary file not shown.
Binary file modified hashtree_windows_amd64.syso
Binary file not shown.
12 changes: 11 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ else
endif
endif

# ARM architecture detection
# architecture detection
ifdef CC
ARM = $(shell $(CC) -dM -E - < /dev/null | grep "aarch" | awk '{ print $$3 }')
RISCV = $(shell $(CC) -dM -E - < /dev/null | grep "riscv 1" | awk '{ print $$3 }')
ifneq ($(findstring mingw, $(CC)),)
ifneq ($(ARM),1)
PLATFORM = Windows
Expand All @@ -69,6 +70,7 @@ ifdef CC
else
ARCH = $(shell uname -m)
ARM = $(shell echo $(ARCH) | grep -E '^(arm|aarch64)' >/dev/null && echo 1 || echo 0)
RISCV = $(shell echo $(ARCH) | grep -E '^riscv' >/dev/null && echo 1 || echo 0)
endif

# Cross-platform compiler selection
Expand Down Expand Up @@ -105,6 +107,14 @@ ifeq ($(ARM), 1)
$(OBJ_DIR)/sha256_armv8_crypto.o\
$(OBJ_DIR)/sha256_generic.o\
$(OBJ_DIR)/hashtree.o
else ifeq ($(RISCV), 1)
CFLAGS += -march=rv64gc_zbb_zk
ASFLAGS += -march=rv64gc_zbb_zk
OBJ_LIST = $(OBJ_DIR)/sha256_riscv_x1.o\
$(OBJ_DIR)/sha256_riscv_zbb_x1.o\
$(OBJ_DIR)/sha256_riscv_crypto.o\
$(OBJ_DIR)/sha256_generic.o\
$(OBJ_DIR)/hashtree.o
else
OBJ_LIST = $(OBJ_DIR)/sha256_shani.o\
$(OBJ_DIR)/sha256_avx_x16.o\
Expand Down
39 changes: 39 additions & 0 deletions src/bench.c
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,45 @@ UBENCH_EX(shani, shani_one_at_time) {
free(buffer);
}
#endif
#ifdef __riscv
UBENCH_EX(riscv, riscv_x1) {
int * buffer = (int *) malloc(buffer_size);
unsigned char * digest = (unsigned char *) malloc(buffer_size/2);
for (int i = 0; i < buffer_size/sizeof(int); i++) {
buffer[i] = rand();
}
UBENCH_DO_BENCHMARK() {
hashtree_sha256_riscv_x1(digest, (unsigned char *)buffer, buffer_size/64);
}
free(buffer);
free(digest);
}
UBENCH_EX(riscv, riscv_zbb_x1) {
int * buffer = (int *) malloc(buffer_size);
unsigned char * digest = (unsigned char *) malloc(buffer_size/2);
for (int i = 0; i < buffer_size/sizeof(int); i++) {
buffer[i] = rand();
}
UBENCH_DO_BENCHMARK() {
hashtree_sha256_riscv_zbb_x1(digest, (unsigned char *)buffer, buffer_size/64);
}
free(buffer);
free(digest);
}
UBENCH_EX(riscv, riscv_crypto) {
int * buffer = (int *) malloc(buffer_size);
unsigned char * digest = (unsigned char *) malloc(buffer_size/2);
for (int i = 0; i < buffer_size/sizeof(int); i++) {
buffer[i] = rand();
}
UBENCH_DO_BENCHMARK() {
hashtree_sha256_riscv_crypto(digest, (unsigned char *)buffer, buffer_size/64);
}
free(buffer);
free(digest);
}
#endif

#ifdef HAVE_OPENSSL
UBENCH_EX(openssl, openssl_one_at_time) {
int *buffer = (int *)malloc(buffer_size);
Expand Down
50 changes: 50 additions & 0 deletions src/hashtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,33 @@ SOFTWARE.
#include <sys/auxv.h>
#endif
#endif
#ifdef __riscv
#include <sys/syscall.h>
#include <unistd.h>

/* riscv_hwprobe syscall interface - available in Linux 6.4+ */
#ifndef __NR_riscv_hwprobe
#define __NR_riscv_hwprobe 258
#endif

struct riscv_hwprobe {
int64_t key;
uint64_t value;
};

#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
#define RISCV_HWPROBE_EXT_ZBB (1ULL << 1)
#define RISCV_HWPROBE_EXT_ZBC (1ULL << 2)
#define RISCV_HWPROBE_EXT_ZBKB (1ULL << 3)
#define RISCV_HWPROBE_EXT_ZBKC (1ULL << 4)
#define RISCV_HWPROBE_EXT_ZBKX (1ULL << 5)
#define RISCV_HWPROBE_EXT_ZKND (1ULL << 6)
#define RISCV_HWPROBE_EXT_ZKNE (1ULL << 7)
#define RISCV_HWPROBE_EXT_ZKNH (1ULL << 8)
#define RISCV_HWPROBE_EXT_ZKSED (1ULL << 9)
#define RISCV_HWPROBE_EXT_ZKSH (1ULL << 10)
#define RISCV_HWPROBE_EXT_ZKT (1ULL << 11)
#endif

static void init_and_hash(unsigned char *output, const unsigned char *input, uint64_t count);

Expand Down Expand Up @@ -64,6 +91,29 @@ static hashtree_hash_fcn hashtree_detect() {
return &hashtree_sha256_sse_x1;
}
#endif
#ifdef __riscv
struct riscv_hwprobe pairs[1] = {
{ .key = RISCV_HWPROBE_KEY_IMA_EXT_0 }
};

long ret = syscall(__NR_riscv_hwprobe, pairs, 1, 0, NULL, 0);
if (ret == 0) {
uint64_t ext = pairs[0].value;

/* Check for SHA-256 crypto extension (Zknh) + related extensions */
if ((ext & RISCV_HWPROBE_EXT_ZKNH) && (ext & RISCV_HWPROBE_EXT_ZBKB)) {
return &hashtree_sha256_riscv_crypto;
}

/* Check for Zbb bit manipulation extension */
if (ext & RISCV_HWPROBE_EXT_ZBB) {
return &hashtree_sha256_riscv_zbb_x1;
}
}

/* Fall back to basic RISC-V implementation */
return &hashtree_sha256_riscv_x1;
#endif
#ifdef __aarch64__
#ifdef __APPLE__
return &hashtree_sha256_sha_x1;
Expand Down
6 changes: 6 additions & 0 deletions src/hashtree.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ void hashtree_sha256_neon_x4(unsigned char* output, const unsigned char* input,
void hashtree_sha256_sha_x1(unsigned char* output, const unsigned char* input, uint64_t count);
#endif

#ifdef __riscv
void hashtree_sha256_riscv_x1(unsigned char* output, const unsigned char* input, uint64_t count);
void hashtree_sha256_riscv_zbb_x1(unsigned char* output, const unsigned char* input, uint64_t count);
void hashtree_sha256_riscv_crypto(unsigned char* output, const unsigned char* input, uint64_t count);
#endif

#ifdef __x86_64__
void hashtree_sha256_sse_x1(unsigned char* output, const unsigned char* input, uint64_t count);
void hashtree_sha256_avx_x1(unsigned char* output, const unsigned char* input, uint64_t count);
Expand Down
Loading
Loading