Skip to content

Commit

Permalink
Update README and build process ready for publication
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewLM committed Jul 30, 2023
1 parent 52afeff commit 73326be
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 146 deletions.
68 changes: 44 additions & 24 deletions coinlib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@ Coinlib is a straight-forward and modular library for Peercoin and other similar
cryptocoins. This library allows for the construction and signing of
transactions and management of BIP32 wallets.

## Usage
## Installation and Usage

Unless using the flutter plugin (See `coinlib_flutter`), this library requires a
shared or dynamic library for linux or macOS, and a WebAssembly module for web.
The WebAssembly module is precompiled and included with the library, but the
linux and macOS libraries are not and must be built before use. See
["Building Native & WebAssembly"](#building-native-and-webassembly) below.
If you are using flutter, please see `coinlib_flutter` instead. Otherwise you
may add `coinlib` to your project via:

```
dart pub add coinlib
```

If you are using the library for web, the library is ready to use. If you are
using the library on Linux or macOS then please see
["Building for Linux"](#building-for-linux) and
["Building for macOS"](#building-for-maxos) below.

No script is included for building on Windows at the present time, however a
`secp256k1.dll` may be built into your `build/` directory separately.

The library can be imported via:

Expand All @@ -21,35 +30,46 @@ import 'package:coinlib/coinlib.dart';
```

The library must be asynchronously loaded by awaiting the `loadCoinlib()`
function.
function before any part of the library is used.

## Building for Linux

Docker or Podman is required to build the library for Linux.

The linux shared library can be built using `dart run coinlib:build_linux` in
the root directory of your package which will produce a shared library into
`build/libsecp256k1.so`. This can also be run in the `coinlib` root directory
via `dart run bin/build_linux.dart`.

## Building Native and WebAssembly
This library must be in the `build` directory under the PWD, must be installed
as a system library, or within `$LD_LIBRARY_PATH`.

The secp256k1 dependency must be provided to the library as a shared/dynamic
library or as a WebAssembly module for web. Build scripts are provided and can
be run from the root project directory.
## Building for macOS

Docker or Podman is required to build the library for linux or web. macOS
requires autotools that may be installed using homebrew:
Building for macOS requires autotools that may be installed using homebrew:

```
brew install autoconf automake libtool
```

The WebAssembly module has been pre-built to
`lib/src/generated/secp256k1.wasm.g.dart`. It may be rebuilt using `dart run
bin/build_wasm.dart`.
The macOS dynamic library must either be provided as
`$PWD/build/libsecp256k1.dylib` when running dart code, or provided as a system
framework named `secp256k1.framework`.

The linux shared library can be built using `bin/build_linux.dart` which will
produce a shared library into `build/libsecp256k1.so`.

The macOS dynamic library can be built using `bin/build_macos.dart` which will
produce a universal library for both x86_64 and arm64 to
The dylib can be built in the root directory of coinlib by running `dart run
bin/build_macos.dart` which will create the library under
`build/libsecp256k1.dylib`.

No script is included for Windows at the present time, however a `secp256k1.dll`
may be built into the `build/` directory separately.
## Bindings and WebAssembly

The WebAssembly (WASM) module is pre-compiled and ready to use. FFI bindings
are pre-generated. These only need to be updated when the underlying secp256k1
library is changed.

Bindings for the native libraries (excluding WebAssembly) are generated from the
`headers/secp256k1.h` file using `dart run ffigen`. These are already included.
`headers/secp256k1.h` file using `dart run ffigen` within the `coinlib` package.

The WebAssembly module has been pre-built to
`lib/src/generated/secp256k1.wasm.g.dart`. It may be rebuilt using `dart run
bin/build_wasm.dart` in the `coinlib` root directory.

38 changes: 36 additions & 2 deletions coinlib/bin/build_linux.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,41 @@
import 'dart:io';
import 'docker_util.dart';

/// Build the linux shared library for secp256k1 using the dockerfile
/// Build the linux shared library for secp256k1 using the Dockerfile string
String dockerfile = r"""
FROM debian:bullseye
# Install dependenices
RUN apt-get update -y \
&& apt-get install -y autoconf libtool build-essential git
# Clone libsecp256k1.
# Could use secp256k1 already in code-base but this makes the dockerfile more
# independent and avoids complexity of copying everything into the correct
# context. It's not a large library to download.
# Use 0.3.1 release
RUN git clone https://github.com/bitcoin-core/secp256k1 \
&& cd secp256k1 \
&& git checkout 346a053d4c442e08191f075c3932d03140579d47
WORKDIR /secp256k1
# Build shared library for linux
RUN ./autogen.sh
RUN ./configure \
--enable-module-recovery --disable-tests \
--disable-exhaustive-tests --disable-benchmark \
CFLAGS="-O2"
RUN make
# Build shared library into /usr/local/lib as usual and then copy into output
# Unused symbols could be stripped. But for future ease, all symbols are
# maintained.
RUN make install
RUN mkdir output
RUN cp /usr/local/lib/libsecp256k1.so.2.0.1 output/libsecp256k1.so
""";

void main() async {

Expand All @@ -11,7 +45,7 @@ void main() async {
// Build secp256k1 and copy shared library to build directory
if (!await dockerBuild(
cmd,
"build_secp256k1_linux.Dockerfile",
dockerfile,
"coinlib_build_secp256k1_linux",
"/secp256k1/output/libsecp256k1.so",
)) {
Expand Down
5 changes: 3 additions & 2 deletions coinlib/bin/build_macos.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:io';
import 'util.dart';
import 'package:path/path.dart' show dirname;

/// Build a universal macOS framework for secp256k1 directly on a mac machine
Expand All @@ -12,7 +13,7 @@ void main() async {
final libDir = "$tmpDir/secp256k1";

var exitCode = await execWithStdio(
"cp", ["-r", "$thisDir/../src/secp256k1", libDir],
"cp", ["-r", "${dirname(Platform.script.path)}/../src/secp256k1", libDir],
);
if (exitCode != 0) {
print("Could not copy secp256k1 to temporary build directory");
Expand Down Expand Up @@ -59,7 +60,7 @@ void main() async {
}

// Copy framework to build directory
final buildDir = "$thisDir/../build";
final buildDir = "${Directory.current.path}/build";
Directory(buildDir).create();
final libFile = File("$libDir/build/lib/libsecp256k1.2.dylib");
await libFile.copy("$buildDir/libsecp256k1.dylib");
Expand Down
31 changes: 0 additions & 31 deletions coinlib/bin/build_secp256k1_linux.Dockerfile

This file was deleted.

68 changes: 0 additions & 68 deletions coinlib/bin/build_secp256k1_wasm.Dockerfile

This file was deleted.

79 changes: 75 additions & 4 deletions coinlib/bin/build_wasm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,79 @@ import 'dart:io';
import 'docker_util.dart';
import 'util.dart';

/// Run Dockerfile to generate wasm file and then convert into a dart file with
/// the wasm as a Uint8List static variable
/// Run Dockerfile content to generate wasm file and then convert into a dart
/// file with the wasm as a Uint8List static variable
String dockerfile = r"""
FROM debian:bullseye
# Install dependenices
RUN apt-get update -y \
&& apt-get install -y autoconf libtool build-essential git wget
# Download and install wasi-sdk
ENV WASI_VERSION=19
ENV WASI_VERSION_FULL=${WASI_VERSION}.0
ENV WASI_SDK_PATH=/wasi-sdk-${WASI_VERSION_FULL}
ENV WASI_ARCHIVE=wasi-sdk-${WASI_VERSION_FULL}-linux.tar.gz
RUN wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-${WASI_VERSION}/$WASI_ARCHIVE
RUN tar xvf $WASI_ARCHIVE
RUN rm $WASI_ARCHIVE
# Clone libsecp256k1 and use v0.3.1
RUN git clone https://github.com/bitcoin-core/secp256k1 \
&& cd secp256k1 \
&& git checkout 346a053d4c442e08191f075c3932d03140579d47
WORKDIR /secp256k1
# Build using wasi-sdk
RUN ./autogen.sh
RUN ./configure \
--enable-module-recovery --disable-tests --disable-shared \
--disable-exhaustive-tests --disable-benchmark \
--with-sysroot=${WASI_SDK_PATH}/share/wasi-sysroot \
--host=wasm32 --target=wasm32-unknown-wasi \
CFLAGS="-O2 -fPIC" CC=${WASI_SDK_PATH}/bin/clang
RUN make
# Link output with wasi standard library and export required functions
RUN mkdir output
RUN ${WASI_SDK_PATH}/bin/wasm-ld \
-o output/secp256k1.wasm \
--no-entry \
--export malloc \
--export free \
--export secp256k1_context_create \
--export secp256k1_context_randomize \
--export secp256k1_ec_seckey_verify \
--export secp256k1_ec_pubkey_create \
--export secp256k1_ec_pubkey_serialize \
--export secp256k1_ec_pubkey_parse \
--export secp256k1_ecdsa_sign \
--export secp256k1_ecdsa_signature_serialize_compact \
--export secp256k1_ecdsa_signature_parse_compact \
--export secp256k1_ecdsa_signature_normalize \
--export secp256k1_ecdsa_verify \
--export secp256k1_ecdsa_signature_serialize_der \
--export secp256k1_ecdsa_signature_parse_der \
--export secp256k1_ecdsa_recoverable_signature_serialize_compact \
--export secp256k1_ecdsa_recoverable_signature_parse_compact \
--export secp256k1_ecdsa_sign_recoverable \
--export secp256k1_ecdsa_recover \
--export secp256k1_ec_seckey_tweak_add \
--export secp256k1_ec_pubkey_tweak_add \
# The secp256k1 library object files
src/libsecp256k1_la-secp256k1.o \
src/libsecp256k1_precomputed_la-precomputed_ecmult.o \
src/libsecp256k1_precomputed_la-precomputed_ecmult_gen.o \
# Need to include libc for wasi here as it isn't done for us
${WASI_SDK_PATH}/share/wasi-sysroot/lib/wasm32-wasi/libc.a \
# Need to include another library from clang that isn't included either
# See https://github.com/WebAssembly/wasi-libc/issues/98
${WASI_SDK_PATH}/lib/clang/15.0.7/lib/wasi/libclang_rt.builtins-wasm32.a
""";

void binaryFileToDart(String inPath, String outPath, String name) {
final bytes = File(inPath).readAsBytesSync();
Expand All @@ -26,7 +97,7 @@ void main() async {
// Build secp256k1 to wasm and copy wasm file to tempdir
if (!await dockerRun(
cmd,
"build_secp256k1_wasm.Dockerfile",
dockerfile,
"coinlib_build_secp256k1_wasm",
tmpDir,
"cp /secp256k1/output/secp256k1.wasm /host/secp256k1.wasm",
Expand All @@ -37,7 +108,7 @@ void main() async {
// Convert secp256k1.wasm file into Uint8List in dart file
binaryFileToDart(
"$tmpDir/secp256k1.wasm",
"$thisDir/../lib/src/generated/secp256k1.wasm.g.dart",
"${Directory.current.path}/lib/src/generated/secp256k1.wasm.g.dart",
"secp256k1WasmData",
);
print("Output secp256k1.wasm.g.dart successfully");
Expand Down
Loading

0 comments on commit 73326be

Please sign in to comment.