Four backends are currently supported:
Switching is trivial: ZkBackend::new(BackendType::Plonk).setup().
libzkfpdll is written in Rust, with C and Python bindings. Its internal design follows four layers:
The code structure of libzkfpdll reflects its age and origin. It is likely written in C or C++, utilizing stdcall calling conventions. This is evident in how it handles memory. libzkfpdll
Modern languages like C# or Python interact with libzkfpdll via P/Invoke (Platform Invocation Services). This requires developers to manually map the C++ structs to managed code objects—a process prone to memory leaks. For example, the library expects the caller to allocate a buffer for the image data, but if the caller misjudges the size or fails to free the memory, the application crashes.
This highlights a "deep" flaw in the design: it assumes the consumer is a low-level systems programmer. In an era of rapid application development, integrating libzkfpdll is a friction point because it lacks the safety guarantees of modern managed SDKs.
Note: different SDK versions vary; the list below describes common capabilities found across many libzkfpdll variants. Four backends are currently supported:
libzkfpdll.dll is a Dynamic Link Library (DLL) file. In the Windows ecosystem, a DLL is a collection of code that different programs can share.
Think of a ZKTeco fingerprint scanner as a foreign diplomat who only speaks "Biometrics." The Windows computer wants to talk to it, but only speaks "Software." libzkfpdll.dll is the translator standing between them.
When a developer writes a program to enroll a new employee, they don't write the complex code to analyze the ridges and valleys of a fingerprint from scratch. Instead, they write a simple command: Switching is trivial: ZkBackend::new(BackendType::Plonk)
"Hey,
libzkfpdll, ask the scanner for an image."
The DLL takes that request, dives down into the low-level drivers, talks to the USB port, activates the sensor, captures the raw data, processes it, and hands a neat digital image back to the software.
Instead of writing arithmetic circuits or R1CS constraints directly, developers define relations using FPDL:
relation "AgeVerifier"
public: user_pubkey
private: birthdate, secret_salt
assert: (current_date - birthdate) >= 6570 days
assert: hash(birthdate, secret_salt) == user_pubkey
The FPDL compiler compiles this into an intermediate representation (IR) and then into the native constraint format of the chosen backend.
The team previewed features for 2027: