Skip to content

fluree/fluree.crypto

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Cryptography Library for Fluree

A collection of cryptography functions for Fluree, implemented in Clojure/ClojureScript with platform-specific optimizations.

Features

  • Ed25519 Digital Signatures - Fast, secure signatures using Noble Ed25519 (JS) and Java 17+ native support (JVM)
  • JWS (JSON Web Signatures) - RFC 7515/8037 compliant JWS creation and verification
  • DID Support - Decentralized identifier generation and verification (did:key method)
  • SHA-2 Hashing - SHA-256 and SHA-512 implementations
  • AES Encryption - Symmetric encryption/decryption
  • Cross-platform - Consistent API across JVM, Node.js, and browser environments
  • GraalVM Native Image Support - Can be compiled to native executables

Installation

Clojure/ClojureScript

Add to your deps.edn:

{:deps {com.fluree/crypto {:mvn/version "4.0.0"}}}

Node.js

npm install @fluree/crypto

Browser

The browser build is available at dist/browser/fluree-crypto.js after building.

API Reference

Key Generation

Generate Key Pair

;; Clojure
(require '[fluree.crypto :as crypto])

;; Generate a new Ed25519 key pair
(crypto/generate-key-pair)
;; => {:private "hex-string", :public "hex-string"}

;; Generate from existing private key
(crypto/generate-key-pair "your-private-key-hex")
// JavaScript
// Generate a new Ed25519 key pair
const keyPair = crypto.generateKeyPair();
// Returns: { private: "hex-string", public: "hex-string" }

// Generate from existing private key
const keyPair2 = crypto.generateKeyPair("your-private-key-hex");

Public Key from Private

;; Clojure
(crypto/public-key-from-private "private-key-hex")
;; => "public-key-hex"
// JavaScript
const publicKey = crypto.publicKeyFromPrivate("private-key-hex");
// Returns: "public-key-hex"

Account IDs and DIDs

Account ID from Public Key

;; Clojure
(crypto/account-id-from-public "public-key-hex")
;; => "base58-account-id" (e.g., "TfGvAdKH2nRdV4zP4yBz4kJ2R9WzYHDe2EV")

;; With output format
(crypto/account-id-from-public "public-key-hex" {:output-format :multibase})
;; => "did:key:z6Mk..." format
// JavaScript
const accountId = crypto.accountIdFromPublic("public-key-hex");
// Returns: "base58-account-id" (e.g., "TfGvAdKH2nRdV4zP4yBz4kJ2R9WzYHDe2EV")

Account ID from Private Key

;; Clojure
(crypto/account-id-from-private "private-key-hex")
;; => "base58-account-id"
// JavaScript
const accountId = crypto.accountIdFromPrivate("private-key-hex");
// Returns: "base58-account-id"

DID from Public Key

;; Clojure
(crypto/did-from-public "public-key-hex")
;; => "did:key:z6Mk..." (multibase-encoded DID)
// JavaScript
const did = crypto.didFromPublic("public-key-hex");
// Returns: "did:key:z6Mk..." (multibase-encoded DID)

Digital Signatures

Sign Message

;; Clojure
(crypto/sign-message "message" "private-key-hex")
;; => "signature-hex"

;; With key pair map
(crypto/sign-message "message" {:private "private-key-hex" :public "public-key-hex"})
// JavaScript
const signature = crypto.signMessage("message", "private-key-hex");
// Returns: "signature-hex"

Verify Signature

;; Clojure
(crypto/verify-signature "public-key-hex" "message" "signature-hex")
;; => true or false
// JavaScript
const isValid = crypto.verifySignature("public-key-hex", "message", "signature-hex");
// Returns: true or false

JWS (JSON Web Signatures)

Create JWS

;; Clojure
;; Basic JWS
(crypto/create-jws "payload" keypair)
;; => "header.payload.signature"

;; With embedded public key (for self-contained verification)
(crypto/create-jws "payload" keypair {:include-pubkey true})

;; With key ID (account ID)
(crypto/create-jws "payload" keypair {:account-id true})

;; With custom key ID
(crypto/create-jws "payload" keypair {:kid "my-key-id"})
// JavaScript
// Basic JWS
const jws = crypto.createJWS("payload", keyPair);
// Returns: "header.payload.signature"

// With embedded public key (for self-contained verification)
const jws2 = crypto.createJWS("payload", keyPair, { includePublicKey: true });

// With key ID (account ID)
const jws3 = crypto.createJWS("payload", keyPair, { accountId: true });

// With custom key ID
const jws4 = crypto.createJWS("payload", keyPair, { kid: "my-key-id" });

Verify JWS

;; Clojure
;; Verify with explicit public key
(crypto/verify-jws jws "public-key-hex")
;; => {:payload "original-payload", :pubkey "public-key-hex", :header {...}}

;; Verify self-contained JWS (with embedded key or account ID)
(crypto/verify-jws jws)
;; => {:payload "...", :pubkey "...", :header {...}, :kid "..."}

;; Error case returns an Exception
(crypto/verify-jws "invalid-jws")
;; => #error {:cause "..." :data {...}}
// JavaScript
// Verify with explicit public key
const result = crypto.verifyJWS(jws, "public-key-hex");
// Returns: { payload: "original-payload", pubkey: "public-key-hex", header: {...} }

// Verify self-contained JWS (with embedded key or account ID)
const result2 = crypto.verifyJWS(jws2);
// Returns: { payload: "...", pubkey: "...", header: {...}, kid: "..." }

// Error case returns an Error object
const error = crypto.verifyJWS("invalid-jws");
// Returns: Error instance

Hashing

SHA-256

;; Clojure
;; Basic usage
(crypto/sha2-256 "message")
;; => "hex-string"

;; With output format
(crypto/sha2-256 "message" :bytes)
;; Valid formats: :hex, :bytes, :base64, :base58, :string

;; With input and output format
(crypto/sha2-256 "68656c6c6f" :base64 :hex)
// JavaScript
// Basic usage
const hash = crypto.sha2_256("message");
// Returns: "hex-string"

// With output format
const hashBytes = crypto.sha2_256("message", "bytes");
// Valid formats: "hex", "bytes", "base64", "base58", "string"

// With input and output format
const hash2 = crypto.sha2_256("68656c6c6f", "base64", "hex");

SHA-256 Normalize

Normalizes the input string using NFKC before hashing:

;; Clojure
(crypto/sha2-256-normalize "message")
;; => "hex-string"

;; With output format
(crypto/sha2-256-normalize "message" :base64)
// JavaScript
const hash = crypto.sha2_256_normalize("message");
// Returns: "hex-string"

SHA-512

;; Clojure
(crypto/sha2-512 "message")
;; => "hex-string"

;; With formats (same as SHA-256)
(crypto/sha2-512 "message" :base64)
// JavaScript
const hash = crypto.sha2_512("message");
// Returns: "hex-string"

// With formats (same as SHA-256)
const hashBase64 = crypto.sha2_512("message", "base64");

Encryption

AES Encrypt

;; Clojure
(def iv [6 224 71 170 241 204 115 21 30 8 46 223 106 207 55 42])
(crypto/aes-encrypt "message" iv "password")
;; => "hex-string"

;; With output format
(crypto/aes-encrypt "message" iv "password" :base64)
// JavaScript
const iv = [6, 224, 71, 170, 241, 204, 115, 21, 30, 8, 46, 223, 106, 207, 55, 42];
const encrypted = crypto.aesEncrypt("message", iv, "password");
// Returns: "hex-string"

// With output format
const encryptedBase64 = crypto.aesEncrypt("message", iv, "password", "base64");

AES Decrypt

;; Clojure
(crypto/aes-decrypt encrypted iv "password")
;; => "message"

;; With input/output formats
(crypto/aes-decrypt encrypted-base64 iv "password" :string :base64)
// JavaScript
const decrypted = crypto.aesDecrypt(encrypted, iv, "password");
// Returns: "message"

// With input/output formats
const decrypted2 = crypto.aesDecrypt(encryptedBase64, iv, "password", "string", "base64");

Utility Functions

Normalize String

;; Clojure
(crypto/normalize-string "\u0041\u030apple")
;; => NFKC normalized string
// JavaScript
const normalized = crypto.normalizeString("\u0041\u030apple");
// Returns NFKC normalized string

String to Byte Array

;; Clojure
(crypto/string->byte-array "hello")
;; => [104 101 108 108 111]
// JavaScript
const bytes = crypto.stringToByteArray("hello");
// Returns: [104, 101, 108, 108, 111]

Byte Array to String

;; Clojure
(crypto/byte-array->string [104 101 108 108 111])
;; => "hello"
// JavaScript
const str = crypto.byteArrayToString([104, 101, 108, 108, 111]);
// Returns: "hello"

Platform-Specific Implementation Details

JavaScript (Node.js/Browser)

  • Uses @noble/ed25519 v2.3.0 for Ed25519 operations
  • Pure JavaScript implementation ensures consistent behavior

JVM

  • Uses Java 17+ native Ed25519 support via JCA/JCE
  • EdECPrivateKeySpec and EdECPublicKeySpec for key management
  • Hardware-accelerated when available

Development

Prerequisites

  • Clojure CLI tools
  • Node.js and npm
  • Java 17+

Building

# Build everything
make all

# Build JAR only
make jar

# Build Node.js package
make node

# Build browser package
make browser

Testing

# Run all tests
make test

# Run specific test suites
make cljtest      # JVM tests
make cljstest     # ClojureScript tests
make node-test    # Node.js integration tests

GraalVM Native Image

The library supports GraalVM native image compilation. See README-graalvm.md for details.

Changes from v3.x

  • Ed25519 only: Removed SECP256K1 support (use v3.x if needed)
  • No SHA-3/RIPEMD: Removed to improve GraalVM compatibility
  • Upgraded dependencies: Noble Ed25519 v2.3.0, Java 17+ required
  • New features: DID support, automatic public key derivation in JWS

Contributing

  1. Fork and clone the repository
  2. Create a branch for your feature
  3. Write tests for new functionality
  4. Ensure all tests pass with make test
  5. Submit a pull request

License

Copyright © 2025 Fluree, PBC

Distributed under the MIT License.

About

Clojure(script) Cryptography used by Fluree

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 5