Skip to content

Commit

Permalink
Dart Derping (#371)
Browse files Browse the repository at this point in the history
  • Loading branch information
fundthmcalculus committed May 12, 2022
1 parent bab8ef6 commit 3c729c4
Show file tree
Hide file tree
Showing 89 changed files with 11,129 additions and 144 deletions.
61 changes: 61 additions & 0 deletions .github/workflows/build-dart.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Dart

on:
workflow_call:
workflow_dispatch:
pull_request:
branches:
- main
paths:
- "dart/**"
- "proto/**"
- ".github/workflows/*dart*"
- "devops/**"
push:
branches:
- main
paths:
- "dart/**"
- "proto/**"
- ".github/workflows/*dart*"
- "devops/**"

jobs:
build-and-test-dart:
name: Test Dart code
runs-on: ${{ matrix.os-artifact[0] }}
strategy:
fail-fast: false
matrix:
os-artifact: [ [ubuntu-latest, linux], [windows-latest, windows], [macos-latest, macos] ]
steps:
- uses: actions/checkout@v2
- name: Set up Dart
uses: dart-lang/setup-dart@v1
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9

- name: Download workflow artifact
uses: dawidd6/action-download-artifact@v2.17.0
with:
workflow: "build-libs.yml"
path: ./libs/${{ matrix.os-artifact[1] }}
github_token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ matrix.os-artifact[1] }}

- name: Install Dart dependencies
run: dart pub get
shell: pwsh
working-directory: dart

- name: Build, Test, Pack
run: |
python ../devops/build_sdks.py --language=python
dart test ./lib/test/test-okapi.dart
shell: pwsh
working-directory: dart
env:
API_GITHUB_TOKEN: ${{ secrets.API_GITHUB_TOKEN }}
LD_LIBRARY_PATH: "${{ github.workspace }}/libs"
6 changes: 6 additions & 0 deletions dart/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Files and directories created by pub.
.dart_tool/
.packages

# Conventional directory for build output.
build/
3 changes: 3 additions & 0 deletions dart/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
1 change: 1 addition & 0 deletions dart/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dart bindings for okapi binary
30 changes: 30 additions & 0 deletions dart/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

# linter:
# rules:
# - camel_case_types

# analyzer:
# exclude:
# - path/to/excluded/files/**

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints

# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
128 changes: 128 additions & 0 deletions dart/lib/okapi.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import 'dart:ffi';

import 'package:okapi_dart/okapi_native.dart';
import 'package:okapi_dart/proto/okapi/hashing/v1/hashing.pb.dart';
import 'package:okapi_dart/proto/okapi/keys/v1/keys.pb.dart';
import 'package:okapi_dart/proto/okapi/proofs/v1/proofs.pb.dart';
import 'package:okapi_dart/proto/okapi/security/v1/security.pb.dart';
import 'package:okapi_dart/proto/okapi/transport/v1/transport.pb.dart';

class DidComm {
static final _didcommPack = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_pack');
static final _didcommUnpack = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_unpack');
static final _didcommSign = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_sign');
static final _didcommVerify = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_verify');

PackResponse pack(PackRequest request) =>
OkapiNative.nativeCall(_didcommPack, request, PackResponse());

UnpackResponse unpack(UnpackRequest request) =>
OkapiNative.nativeCall(_didcommUnpack, request, UnpackResponse());

SignResponse sign(SignRequest request) =>
OkapiNative.nativeCall(_didcommSign, request, SignResponse());

VerifyResponse verify(VerifyRequest request) =>
OkapiNative.nativeCall(_didcommVerify, request, VerifyResponse());
}

class DidKey {
static final _didkeyGenerate = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didkey_generate');
static final _didkeyResolve = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didkey_resolve');

static GenerateKeyResponse generate(GenerateKeyRequest request) =>
OkapiNative.nativeCall(_didkeyGenerate, request, GenerateKeyResponse());

static ResolveResponse resolve(ResolveRequest request) =>
OkapiNative.nativeCall(_didkeyResolve, request, ResolveResponse());
}

class LdProofs {
static final _ldproofsCreateProof = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
'ldproofs_create_proof');
static final _ldproofsVerifyProof = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
'ldproofs_verify_proof');

static CreateProofResponse createProof(CreateProofRequest request) =>
OkapiNative.nativeCall(
_ldproofsCreateProof, request, CreateProofResponse());

static VerifyProofResponse verifyProof(VerifyProofRequest request) =>
OkapiNative.nativeCall(
_ldproofsVerifyProof, request, VerifyProofResponse());
}

class Oberon {
static final _oberonCreateKey = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('oberon_create_key');
static final _oberonCreateProof = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
'oberon_create_proof');
static final _oberonCreateToken = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
'oberon_create_token');
static final _oberonBlindToken = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('oberon_blind_token');
static final _oberonUnBlindToken = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
'oberon_unblind_token');
static final _oberonVerifyProof = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
'oberon_verify_proof');

static CreateOberonKeyResponse CreateKey(CreateOberonKeyRequest request) =>
OkapiNative.nativeCall(
_oberonCreateKey, request, CreateOberonKeyResponse());

static CreateOberonProofResponse CreateProof(
CreateOberonProofRequest request) =>
OkapiNative.nativeCall(
_oberonCreateProof, request, CreateOberonProofResponse());
static CreateOberonTokenResponse CreateToken(
CreateOberonTokenRequest request) =>
OkapiNative.nativeCall(
_oberonCreateToken, request, CreateOberonTokenResponse());
static BlindOberonTokenResponse BlindToken(BlindOberonTokenRequest request) =>
OkapiNative.nativeCall(
_oberonBlindToken, request, BlindOberonTokenResponse());
static UnBlindOberonTokenResponse UnBlindToken(
UnBlindOberonTokenRequest request) =>
OkapiNative.nativeCall(
_oberonUnBlindToken, request, UnBlindOberonTokenResponse());
static VerifyOberonProofResponse VerifyProof(
VerifyOberonProofRequest request) =>
OkapiNative.nativeCall(
_oberonVerifyProof, request, VerifyOberonProofResponse());
}

class Hashing {
static final _blake3Hash = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('blake3_hash');
static final _blake3KeyedHash = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('blake3_keyed_hash');
static final _blake3DeriveKey = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('blake3_derive_key');
static final _sha256Hash = OkapiNative.library
.lookupFunction<OkapiFunctionNative, OkapiFunction>('sha256_hash');

static Blake3HashResponse blake3Hash(Blake3HashRequest request) =>
OkapiNative.nativeCall(_blake3Hash, request, Blake3HashResponse());
static Blake3KeyedHashResponse blake3KeyedHash(
Blake3KeyedHashRequest request) =>
OkapiNative.nativeCall(
_blake3KeyedHash, request, Blake3KeyedHashResponse());
static Blake3DeriveKeyResponse blake3DeriveKey(
Blake3DeriveKeyRequest request) =>
OkapiNative.nativeCall(
_blake3DeriveKey, request, Blake3DeriveKeyResponse());
static SHA256HashResponse sha256Hash(SHA256HashRequest request) =>
OkapiNative.nativeCall(_sha256Hash, request, SHA256HashResponse());
}
106 changes: 106 additions & 0 deletions dart/lib/okapi_native.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import 'dart:ffi';
import 'dart:io' show Platform, Directory;
import 'dart:typed_data';

import 'package:ffi/ffi.dart';
import 'package:path/path.dart' as path;
import 'package:protobuf/protobuf.dart' as $pb;

class OkapiByteBuffer extends Struct {
@Int64()
external int len;
external Pointer<Int8> data;
}

typedef ErrorCode = Int32;

class ExternError extends Struct {
@ErrorCode()
external int code;
external Pointer<Utf8> message;
}

typedef OkapiFunctionNative = Int32 Function(
OkapiByteBuffer, Pointer<OkapiByteBuffer>, Pointer<ExternError>);
typedef OkapiFunction = int Function(
OkapiByteBuffer, Pointer<OkapiByteBuffer>, Pointer<ExternError>);
typedef OkapiFreeFunctionNative = Void Function(OkapiByteBuffer);
typedef OkapiFreeFunction = void Function(OkapiByteBuffer);

class OkapiNative {
static final DynamicLibrary library = loadNativeLibrary();
static final okapiByteBufferFree = OkapiNative.library
.lookupFunction<OkapiFreeFunctionNative, OkapiFreeFunction>(
'okapi_bytebuffer_free');
static final okapiStringFree = OkapiNative.library
.lookupFunction<OkapiFreeFunctionNative, OkapiFreeFunction>(
'okapi_string_free');

static T nativeCall<T extends $pb.GeneratedMessage>(
Function nativeFunction, $pb.GeneratedMessage request, T response) {
final requestBufferPtr = createRequestBuffer(request);
final responseBufferPtr =
calloc<OkapiByteBuffer>(sizeOf<OkapiByteBuffer>());
final err = calloc<ExternError>(sizeOf<ExternError>());
nativeFunction(requestBufferPtr.ref, responseBufferPtr, err);
final errCode = err.ref.code;
if (errCode != 0) {
final errString = err.ref.message.toDartString();
throw Exception("Okapi native error code=$errCode, message=$errString");
}

response.mergeFromBuffer(
responseBufferPtr.ref.data.asTypedList(responseBufferPtr.ref.len));
// Free native and managed memory
freeNativeMemory(requestBufferPtr, okapiByteBufferFree, responseBufferPtr);
return response;
}

static DynamicLibrary loadNativeLibrary() {
// Support LD_LIBRARY_PATH
String libraryPath = Platform.environment["LD_LIBRARY_PATH"] ??
path.join(Directory.current.path, '..', 'libs');
String libraryName = "";
if (Platform.isWindows) {
libraryName = path.join("windows", "okapi.dll");
} else if (Platform.isLinux) {
libraryName = path.join("linux", "libokapi.so");
} else if (Platform.isMacOS) {
libraryName = path.join("macos", "libokapi.dylib");
}
// TODO - Support Android, and maybe iOS?
libraryPath = path.join(libraryPath, libraryName);
final nativeLib = DynamicLibrary.open(libraryPath);
return nativeLib;
}

static Pointer<Int8> byteDataToPointer(ByteBuffer byteBuffer) {
final uint8List = byteBuffer.asInt8List();
final length = byteBuffer.lengthInBytes;
final result = calloc<Int8>(length);

for (var i = 0; i < length; ++i) {
result[i] = uint8List[i];
}

return result;
}

static void freeNativeMemory(
Pointer<OkapiByteBuffer> requestBuffer,
OkapiFreeFunction okapiByteBufferFree,
Pointer<OkapiByteBuffer> responseBuffer) {
calloc.free(requestBuffer.ref.data);
calloc.free(requestBuffer);
okapiByteBufferFree(responseBuffer.ref);
}

static Pointer<OkapiByteBuffer> createRequestBuffer(
$pb.GeneratedMessage request) {
final Pointer<OkapiByteBuffer> requestBuffer = calloc<OkapiByteBuffer>();
final buffer = request.writeToBuffer().buffer;
requestBuffer.ref.len = buffer.lengthInBytes;
requestBuffer.ref.data = byteDataToPointer(buffer);
return requestBuffer;
}
}
Loading

0 comments on commit 3c729c4

Please sign in to comment.