Skip to content

Commit 3c729c4

Browse files
Dart Derping (#371)
1 parent bab8ef6 commit 3c729c4

File tree

89 files changed

+11129
-144
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+11129
-144
lines changed

.github/workflows/build-dart.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Dart
2+
3+
on:
4+
workflow_call:
5+
workflow_dispatch:
6+
pull_request:
7+
branches:
8+
- main
9+
paths:
10+
- "dart/**"
11+
- "proto/**"
12+
- ".github/workflows/*dart*"
13+
- "devops/**"
14+
push:
15+
branches:
16+
- main
17+
paths:
18+
- "dart/**"
19+
- "proto/**"
20+
- ".github/workflows/*dart*"
21+
- "devops/**"
22+
23+
jobs:
24+
build-and-test-dart:
25+
name: Test Dart code
26+
runs-on: ${{ matrix.os-artifact[0] }}
27+
strategy:
28+
fail-fast: false
29+
matrix:
30+
os-artifact: [ [ubuntu-latest, linux], [windows-latest, windows], [macos-latest, macos] ]
31+
steps:
32+
- uses: actions/checkout@v2
33+
- name: Set up Dart
34+
uses: dart-lang/setup-dart@v1
35+
- name: Set up Python
36+
uses: actions/setup-python@v2
37+
with:
38+
python-version: 3.9
39+
40+
- name: Download workflow artifact
41+
uses: dawidd6/[email protected]
42+
with:
43+
workflow: "build-libs.yml"
44+
path: ./libs/${{ matrix.os-artifact[1] }}
45+
github_token: ${{ secrets.GITHUB_TOKEN }}
46+
name: ${{ matrix.os-artifact[1] }}
47+
48+
- name: Install Dart dependencies
49+
run: dart pub get
50+
shell: pwsh
51+
working-directory: dart
52+
53+
- name: Build, Test, Pack
54+
run: |
55+
python ../devops/build_sdks.py --language=python
56+
dart test ./lib/test/test-okapi.dart
57+
shell: pwsh
58+
working-directory: dart
59+
env:
60+
API_GITHUB_TOKEN: ${{ secrets.API_GITHUB_TOKEN }}
61+
LD_LIBRARY_PATH: "${{ github.workspace }}/libs"

dart/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Files and directories created by pub.
2+
.dart_tool/
3+
.packages
4+
5+
# Conventional directory for build output.
6+
build/

dart/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 1.0.0
2+
3+
- Initial version.

dart/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Dart bindings for okapi binary

dart/analysis_options.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This file configures the static analysis results for your project (errors,
2+
# warnings, and lints).
3+
#
4+
# This enables the 'recommended' set of lints from `package:lints`.
5+
# This set helps identify many issues that may lead to problems when running
6+
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
7+
# style and format.
8+
#
9+
# If you want a smaller set of lints you can change this to specify
10+
# 'package:lints/core.yaml'. These are just the most critical lints
11+
# (the recommended set includes the core lints).
12+
# The core lints are also what is used by pub.dev for scoring packages.
13+
14+
include: package:lints/recommended.yaml
15+
16+
# Uncomment the following section to specify additional rules.
17+
18+
# linter:
19+
# rules:
20+
# - camel_case_types
21+
22+
# analyzer:
23+
# exclude:
24+
# - path/to/excluded/files/**
25+
26+
# For more information about the core and recommended set of lints, see
27+
# https://dart.dev/go/core-lints
28+
29+
# For additional information about configuring this file, see
30+
# https://dart.dev/guides/language/analysis-options

dart/lib/okapi.dart

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import 'dart:ffi';
2+
3+
import 'package:okapi_dart/okapi_native.dart';
4+
import 'package:okapi_dart/proto/okapi/hashing/v1/hashing.pb.dart';
5+
import 'package:okapi_dart/proto/okapi/keys/v1/keys.pb.dart';
6+
import 'package:okapi_dart/proto/okapi/proofs/v1/proofs.pb.dart';
7+
import 'package:okapi_dart/proto/okapi/security/v1/security.pb.dart';
8+
import 'package:okapi_dart/proto/okapi/transport/v1/transport.pb.dart';
9+
10+
class DidComm {
11+
static final _didcommPack = OkapiNative.library
12+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_pack');
13+
static final _didcommUnpack = OkapiNative.library
14+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_unpack');
15+
static final _didcommSign = OkapiNative.library
16+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_sign');
17+
static final _didcommVerify = OkapiNative.library
18+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didcomm_verify');
19+
20+
PackResponse pack(PackRequest request) =>
21+
OkapiNative.nativeCall(_didcommPack, request, PackResponse());
22+
23+
UnpackResponse unpack(UnpackRequest request) =>
24+
OkapiNative.nativeCall(_didcommUnpack, request, UnpackResponse());
25+
26+
SignResponse sign(SignRequest request) =>
27+
OkapiNative.nativeCall(_didcommSign, request, SignResponse());
28+
29+
VerifyResponse verify(VerifyRequest request) =>
30+
OkapiNative.nativeCall(_didcommVerify, request, VerifyResponse());
31+
}
32+
33+
class DidKey {
34+
static final _didkeyGenerate = OkapiNative.library
35+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didkey_generate');
36+
static final _didkeyResolve = OkapiNative.library
37+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('didkey_resolve');
38+
39+
static GenerateKeyResponse generate(GenerateKeyRequest request) =>
40+
OkapiNative.nativeCall(_didkeyGenerate, request, GenerateKeyResponse());
41+
42+
static ResolveResponse resolve(ResolveRequest request) =>
43+
OkapiNative.nativeCall(_didkeyResolve, request, ResolveResponse());
44+
}
45+
46+
class LdProofs {
47+
static final _ldproofsCreateProof = OkapiNative.library
48+
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
49+
'ldproofs_create_proof');
50+
static final _ldproofsVerifyProof = OkapiNative.library
51+
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
52+
'ldproofs_verify_proof');
53+
54+
static CreateProofResponse createProof(CreateProofRequest request) =>
55+
OkapiNative.nativeCall(
56+
_ldproofsCreateProof, request, CreateProofResponse());
57+
58+
static VerifyProofResponse verifyProof(VerifyProofRequest request) =>
59+
OkapiNative.nativeCall(
60+
_ldproofsVerifyProof, request, VerifyProofResponse());
61+
}
62+
63+
class Oberon {
64+
static final _oberonCreateKey = OkapiNative.library
65+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('oberon_create_key');
66+
static final _oberonCreateProof = OkapiNative.library
67+
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
68+
'oberon_create_proof');
69+
static final _oberonCreateToken = OkapiNative.library
70+
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
71+
'oberon_create_token');
72+
static final _oberonBlindToken = OkapiNative.library
73+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('oberon_blind_token');
74+
static final _oberonUnBlindToken = OkapiNative.library
75+
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
76+
'oberon_unblind_token');
77+
static final _oberonVerifyProof = OkapiNative.library
78+
.lookupFunction<OkapiFunctionNative, OkapiFunction>(
79+
'oberon_verify_proof');
80+
81+
static CreateOberonKeyResponse CreateKey(CreateOberonKeyRequest request) =>
82+
OkapiNative.nativeCall(
83+
_oberonCreateKey, request, CreateOberonKeyResponse());
84+
85+
static CreateOberonProofResponse CreateProof(
86+
CreateOberonProofRequest request) =>
87+
OkapiNative.nativeCall(
88+
_oberonCreateProof, request, CreateOberonProofResponse());
89+
static CreateOberonTokenResponse CreateToken(
90+
CreateOberonTokenRequest request) =>
91+
OkapiNative.nativeCall(
92+
_oberonCreateToken, request, CreateOberonTokenResponse());
93+
static BlindOberonTokenResponse BlindToken(BlindOberonTokenRequest request) =>
94+
OkapiNative.nativeCall(
95+
_oberonBlindToken, request, BlindOberonTokenResponse());
96+
static UnBlindOberonTokenResponse UnBlindToken(
97+
UnBlindOberonTokenRequest request) =>
98+
OkapiNative.nativeCall(
99+
_oberonUnBlindToken, request, UnBlindOberonTokenResponse());
100+
static VerifyOberonProofResponse VerifyProof(
101+
VerifyOberonProofRequest request) =>
102+
OkapiNative.nativeCall(
103+
_oberonVerifyProof, request, VerifyOberonProofResponse());
104+
}
105+
106+
class Hashing {
107+
static final _blake3Hash = OkapiNative.library
108+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('blake3_hash');
109+
static final _blake3KeyedHash = OkapiNative.library
110+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('blake3_keyed_hash');
111+
static final _blake3DeriveKey = OkapiNative.library
112+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('blake3_derive_key');
113+
static final _sha256Hash = OkapiNative.library
114+
.lookupFunction<OkapiFunctionNative, OkapiFunction>('sha256_hash');
115+
116+
static Blake3HashResponse blake3Hash(Blake3HashRequest request) =>
117+
OkapiNative.nativeCall(_blake3Hash, request, Blake3HashResponse());
118+
static Blake3KeyedHashResponse blake3KeyedHash(
119+
Blake3KeyedHashRequest request) =>
120+
OkapiNative.nativeCall(
121+
_blake3KeyedHash, request, Blake3KeyedHashResponse());
122+
static Blake3DeriveKeyResponse blake3DeriveKey(
123+
Blake3DeriveKeyRequest request) =>
124+
OkapiNative.nativeCall(
125+
_blake3DeriveKey, request, Blake3DeriveKeyResponse());
126+
static SHA256HashResponse sha256Hash(SHA256HashRequest request) =>
127+
OkapiNative.nativeCall(_sha256Hash, request, SHA256HashResponse());
128+
}

dart/lib/okapi_native.dart

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import 'dart:ffi';
2+
import 'dart:io' show Platform, Directory;
3+
import 'dart:typed_data';
4+
5+
import 'package:ffi/ffi.dart';
6+
import 'package:path/path.dart' as path;
7+
import 'package:protobuf/protobuf.dart' as $pb;
8+
9+
class OkapiByteBuffer extends Struct {
10+
@Int64()
11+
external int len;
12+
external Pointer<Int8> data;
13+
}
14+
15+
typedef ErrorCode = Int32;
16+
17+
class ExternError extends Struct {
18+
@ErrorCode()
19+
external int code;
20+
external Pointer<Utf8> message;
21+
}
22+
23+
typedef OkapiFunctionNative = Int32 Function(
24+
OkapiByteBuffer, Pointer<OkapiByteBuffer>, Pointer<ExternError>);
25+
typedef OkapiFunction = int Function(
26+
OkapiByteBuffer, Pointer<OkapiByteBuffer>, Pointer<ExternError>);
27+
typedef OkapiFreeFunctionNative = Void Function(OkapiByteBuffer);
28+
typedef OkapiFreeFunction = void Function(OkapiByteBuffer);
29+
30+
class OkapiNative {
31+
static final DynamicLibrary library = loadNativeLibrary();
32+
static final okapiByteBufferFree = OkapiNative.library
33+
.lookupFunction<OkapiFreeFunctionNative, OkapiFreeFunction>(
34+
'okapi_bytebuffer_free');
35+
static final okapiStringFree = OkapiNative.library
36+
.lookupFunction<OkapiFreeFunctionNative, OkapiFreeFunction>(
37+
'okapi_string_free');
38+
39+
static T nativeCall<T extends $pb.GeneratedMessage>(
40+
Function nativeFunction, $pb.GeneratedMessage request, T response) {
41+
final requestBufferPtr = createRequestBuffer(request);
42+
final responseBufferPtr =
43+
calloc<OkapiByteBuffer>(sizeOf<OkapiByteBuffer>());
44+
final err = calloc<ExternError>(sizeOf<ExternError>());
45+
nativeFunction(requestBufferPtr.ref, responseBufferPtr, err);
46+
final errCode = err.ref.code;
47+
if (errCode != 0) {
48+
final errString = err.ref.message.toDartString();
49+
throw Exception("Okapi native error code=$errCode, message=$errString");
50+
}
51+
52+
response.mergeFromBuffer(
53+
responseBufferPtr.ref.data.asTypedList(responseBufferPtr.ref.len));
54+
// Free native and managed memory
55+
freeNativeMemory(requestBufferPtr, okapiByteBufferFree, responseBufferPtr);
56+
return response;
57+
}
58+
59+
static DynamicLibrary loadNativeLibrary() {
60+
// Support LD_LIBRARY_PATH
61+
String libraryPath = Platform.environment["LD_LIBRARY_PATH"] ??
62+
path.join(Directory.current.path, '..', 'libs');
63+
String libraryName = "";
64+
if (Platform.isWindows) {
65+
libraryName = path.join("windows", "okapi.dll");
66+
} else if (Platform.isLinux) {
67+
libraryName = path.join("linux", "libokapi.so");
68+
} else if (Platform.isMacOS) {
69+
libraryName = path.join("macos", "libokapi.dylib");
70+
}
71+
// TODO - Support Android, and maybe iOS?
72+
libraryPath = path.join(libraryPath, libraryName);
73+
final nativeLib = DynamicLibrary.open(libraryPath);
74+
return nativeLib;
75+
}
76+
77+
static Pointer<Int8> byteDataToPointer(ByteBuffer byteBuffer) {
78+
final uint8List = byteBuffer.asInt8List();
79+
final length = byteBuffer.lengthInBytes;
80+
final result = calloc<Int8>(length);
81+
82+
for (var i = 0; i < length; ++i) {
83+
result[i] = uint8List[i];
84+
}
85+
86+
return result;
87+
}
88+
89+
static void freeNativeMemory(
90+
Pointer<OkapiByteBuffer> requestBuffer,
91+
OkapiFreeFunction okapiByteBufferFree,
92+
Pointer<OkapiByteBuffer> responseBuffer) {
93+
calloc.free(requestBuffer.ref.data);
94+
calloc.free(requestBuffer);
95+
okapiByteBufferFree(responseBuffer.ref);
96+
}
97+
98+
static Pointer<OkapiByteBuffer> createRequestBuffer(
99+
$pb.GeneratedMessage request) {
100+
final Pointer<OkapiByteBuffer> requestBuffer = calloc<OkapiByteBuffer>();
101+
final buffer = request.writeToBuffer().buffer;
102+
requestBuffer.ref.len = buffer.lengthInBytes;
103+
requestBuffer.ref.data = byteDataToPointer(buffer);
104+
return requestBuffer;
105+
}
106+
}

0 commit comments

Comments
 (0)