Check out the Credible documentation here.
Credible is a native mobile wallet that supports W3C Verifiable Credentials and Decentralized Identifiers built on DIDKit and Flutter. We packaged the DIDKit library written in Rust into a Flutter application running on both Android and iOS, using C bindings and Dart’s FFI capabilities. This is the wallet counterpart to the rich, growing toolkit supplied by DIDKit, the two pillars of a reference architecture for creating trusted interactions at scale.
Credible has undergone the following security reviews:
We are setting up a process to accept contributions. Please feel free to open issues or PRs in the interim, but we cannot merge external changes until this process is in place.
To manually build Credible for either Android or iOS, you will need to install the following dependencies:
- Rust
- Java 17 or higher
- Flutter
wasm-pack
(WEB)binaryen
(WEB and targeting ASM.js)
It is recommended to use rustup to manage your Rust installation.
On Ubuntu you could run:
# apt update
# apt install openjdk-17-jdk
Please ensure you have JAVA_HOME set to the java 17 install when building this project.
For more information, please refer to the documentation of your favorite flavour of Java and your operating system/package manager.
Please follow the official instalation instructions available here to install Flutter, don't forget to also install the build dependencies for the platform you will be building (Android SDK/NDK, Xcode, etc).
We currently only support build this project using the dev
channel of Flutter.
To change your installation to the dev
channel, please execute the following command:
$ flutter channel dev
$ flutter upgrade
To confirm that everything is setup correctly, please run the following command and resolve any issues that arise before proceeding to the next steps.
$ flutter doctor
To build the WASM target you will need wasm-pack
, it can be obtained running:
$ curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
To build Credible for WEB using ASM.js you will need
binaryen, which allows the conversion
of DIDKit WASM to ASM.js. This is necessary when you don't have WASM support and
need to run your page in pure Javascript. More detailed instructions on
how to build binaryen
can be found here.
If you are in a UNIX-like distribution you just have to clone the repo and build,
we recommend cloning into your ${HOME}
, to avoid having to specify the
${BINARYEN_ROOT}
variable:
$ git clone https://github.com/WebAssembly/binaryen ~/binaryen
$ cd ~/binaryen
$ cmake . && make
To build Credible for Android, you will require both the Android SDK and NDK.
These two dependencies can be easily obtained with Android Studio, which install further dependencies upon first being opened after installation. Installing the appropriate Android NDK (often not the newest) in Android Studio can be accomplished by going to Settings > Appearance & Behavior > System Settings > Android SDK and selecting to install the "NDK (Side by Side)".
If your Android SDK doesn't live at $HOME/Android/Sdk
you will need to set
ANDROID_SDK_ROOT
like so:
$ export ANDROID_SDK_ROOT=/path/to/Android/Sdk
Make the above permanant by adding it to your shell initialization script,
~/.bashrc
for bash or ~/.cshrc
for mac
:::note Some users have experienced difficulties with cross-compilation artefacts missing from the newest NDK, which is downloaded by default in the installation process. If you experience errors of this kind, you may have to manually downgrade or install multiple NDK versions as [shown here])(img/ndk_downgrade.png) in the Android Studio installer (screengrabbed from an Ubuntu installation).
If your build-tools
and/or NDK
live in different locations than the default
ones inside /SDK/, or if you want to specify a specific NDK or build-tools
version, you can manually configure the following two environment variables:
$ export ANDROID_TOOLS=/path/to/SDK/build-tools/XX.X.X/
$ export ANDROID_NDK_HOME=/path/to/SDK/ndk/XX.X.XXXXX/
:::
To build Credible for iOS you will need to install CocoaPods, which can be done with Homebrew on MacOS.
$ brew install cocoapods
This project also depends on two other Spruce projects,
DIDKit
and
SSI
.
The correct commits for these projects are submodules in the deps directory. Fetch them by issuing, in the project root directory:
git submodule update --init --recursive
SSI does not need to be explicitly built, it is required only to build DIDkit.
Build DIDkit as:
cd deps/didkit
cargo build # Build the normal rust library
cd ../../
The above comand just builds DIDkit as a normal Rust library for the hardware you're currently running on. Now we must build it for mobile hardware.
cd deps/didkit/lib
# For Android development, we must cross compile the Rust library for
# several Android binary targets. You will see simmilar messages appear
# multiple times while this runs.
#
# You only need to do this when building for Android.
make ../target/test/android.stamp
# For iOS development, we must cross compile the Rust library for iOS
# binary targets.
#
# You only need to do this when building for iOS.
make ../target/test/ios.stamp
cd ../../../
To build DIDKit
for the Android targets, you will go to the root of DIDKit
and run:
$ make -C lib install-rustup-android
$ make -C lib ../target/test/java.stamp
$ make -C lib ../target/test/android.stamp
$ make -C lib ../target/test/flutter.stamp
$ cargo build
This may take some time as it compiles the entire project for multiple targets
$ flutter build apk
$ flutter build appbundle
To build DIDKit for the iOS targets, you will go to the root of DIDKit
and run
:
$ make -C lib install-rustup-ios
$ make -C lib ../target/test/ios.stamp
$ cargo build
$ make -C lib ../target/test/wasm.stamp
If you have installed bynarien
somewhere other than $HOME, you will have to
set BYNARIEN_ROOT
as shown below, otherwise, just run the make
command.
$ export BINARYEN_ROOT=/path/to/binaryen
$ make -C lib ../target/test/asmjs.stamp
You are now ready to build or run Credible.
If you want to run the project on your connected device, you can use:
$ flutter run
If you want to run the project on your browser, you can use:
$ flutter run -d chrome --csp --release
Otherwise, Flutter allows us to build many artifacts for Android, iOS and WEB, below you can find the most common and useful commands, all of which you should run from the root of Credible.
$ flutter build ios --simulator
$ flutter build ios --no-codesign
$ flutter build ipa
$ flutter build web \
--csp \
--release
If you don't have support for WASM, you'll probably need to provide your own
canvaskit
dependency without WASM as well as DIDKit, to do that you need to
specify the FLUTTER_WEB_CANVASKIT_URL
in the build command like below.
$ flutter build web \
--csp \
--dart-define=FLUTTER_WEB_CANVASKIT_URL=vendor/ \
--release
For more details about any of these commands you can run
$ flutter build $SUBCOMMAND --help
Since by default canvaskit
comes in a WASM
build, in order to the ASM.js
be fully supported canvaskit
was manually built for this target.
A prebuilt canvaskit
is already included in the Credible web folder.
If you want to build it by yourself, however, follow these steps:
- Install
emscripten
- Clone Skia repository and pull its dependencies
git clone https://skia.googlesource.com/skia.git --depth 1 --branch canvaskit/0.22.0
cd skia
python2 tools/git-sync-deps
- Modify build script
modules/canvaskit/compile.sh
diff --git a/modules/canvaskit/compile.sh b/modules/canvaskit/compile.sh
index 6ba58bfae9..51f0297eb6 100755
--- a/modules/canvaskit/compile.sh
+++ b/modules/canvaskit/compile.sh
@@ -397,6 +397,7 @@ EMCC_DEBUG=1 ${EMCXX} \
-s MODULARIZE=1 \
-s NO_EXIT_RUNTIME=1 \
-s INITIAL_MEMORY=128MB \
- -s WASM=1 \
+ -s WASM=0 \
+ -s NO_DYNAMIC_EXECUTION=1 \
$STRICTNESS \
-o $BUILD_DIR/canvaskit.js
- Build
canvaskit
$ cd modules/canvaskit
$ make debug
- Replace this line on
$SKIA/modules/canvaskit/canvaskit/bin/canvaskit.js
618c618
< var isNode = !(new Function('try {return this===window;}catch(e){ return false;}')());
---
> var isNode = false;
-
Copy
$SKIA/modules/canvaskit/canvaskit/bin/canvaskit.js
to$CREDIBLE/web/vendor/
-
Build Credible as described above.
If you encounter any errors in the build process described here, please first try clean builds of the projects listed.
For instance, on Flutter, you can delete build files to start over by running:
$ flutter clean
Also, reviewing the install_android_dependencies.sh script may be helpful.
All QRCode interactions start as listed below:
- User scans a QRCode containing a URL;
- User is presented the choice to trust the domain in the URL;
- App makes a GET request to the URL;
Then, depending on the type of message, one of the following protocols will be executed.
After receiving a CredentialOffer
from a trusted host, the app calls the API
with subject_id
in the form body, that value is the didKey obtained from the
private key stored in the FlutterSecureStorage
, which is backed by KeyStore
on Android and Keychain on iOS.
The flow of events and actions is listed below:
- User is presented a credential preview to review and make a decision;
- App generates
didKey
from the stored private key usingDIDKit.keyToDIDKey
; - App makes a POST request to the initial URL with the subject set to the
didKey
; - App receives and stores the new credential;
- User is redirect back to the wallet.
And below is another version of the step-by-step:
Wallet | 1 | Server | |
---|---|---|---|
Scan QRCode 2 | |||
Trust Host | ○ / × | ||
HTTP GET | → | https://domain.tld/endpoint | |
← | CredentialOffer | ||
Preview Credential | |||
Choose DID | ○ / × | ||
HTTP POST 3 | → | https://domain.tld/endpoint | |
← | VerifiableCredential | ||
Verify Credential | |||
Store Credential |
1 Whether this action requires user confirmation, exiting the flow
early when the user denies.
2 The QRCode should contain the HTTP endpoint where the requests
will be made.
3 The body of the request contains a field subject_id
set to the
chosen DID.
After receiving a VerifiablePresentationRequest
from a trusted host, the app
calls the API with presentation
the form body, that value is a JSON encoded
string with the presentation obtained from the selected credential and signed
with the credential's private key using DIDKit.issuePresentation
.
Here are some of the parameters used to generate a presentation:
presentation
id
is set to a randomUUID.v4
string;holder
is set to the selected credential'sdidKey
;verifiableCredential
is set to the credential value;
options
verificationMethod
is set to the DID'sverificationMethod
id
;proofPurpose
is set to'authentication'
;challenge
is set to the request's `challenge';domain
is set to the request's `domain';
key
is the credential's stored private key;
The flow of events and actions is listed below:
- User is presented a presentation request to review and make a decision;
- App generates
didKey
from the stored private key usingDIDKit.keyToDIDKey
; - App issues a presentation using
DIDKit.issuePresentation
; - App makes a POST request to the initial URL with the presentation;
- User is redirect back to the wallet.
And below is another version of the step-by-step:
Wallet | 1 | Server | |
---|---|---|---|
Scan QRCode 2 | |||
Trust Host | ○ / × | ||
HTTP GET | → | https://domain.tld/endpoint | |
← | VerifiablePresentationRequest | ||
Preview Presentation | |||
Choose Verifiable Credential | ○ / × | ||
HTTP POST 3 | → | https://domain.tld/endpoint | |
← | Result |
1 Whether this action requires user confirmation, exiting the flow
early when the user denies.
2 The QRCode should contain the HTTP endpoint where the requests
will be made.
3 The body of the request contains a field presentation
set to the
verifiable presentation.