Privacy-Preserving HR Verification

We started with a pretty simple question:

What if an HR person could verify something about a candidate without actually seeing the sensitive data they're verifying?

Take salary as an example.

An HR reviewer might need to know whether a candidate's salary expectation is within the company's approved budget. Normally, you'd just show them the salary and let them make the comparison.

But they don't really need to know the exact number.

They just need to know whether it passes the policy.

That's what we wanted to build with Midnight.

What we built

We made a small HR candidate review dashboard where a reviewer can select a candidate and run a compensation check.

For example, the company might have an approved budget of:

$95,000

while the candidate's actual salary expectation is stored privately by the HR verification service.

When the reviewer clicks verify, the salary is provided to the Midnight circuit as a private witness.

The circuit checks:

salary <= approved budget

and only the result is revealed.

So the HR reviewer gets something like:

✓ Eligible
The private salary expectation is within the approved company salary band.

They don't get:

Candidate salary: $88,000

The frontend doesn't get it either.

Why we thought this was useful

This pattern comes up in a lot more places than just salaries.

HR has heaps of sensitive information where someone might only need to know whether a condition is satisfied, rather than seeing the underlying data.

For example:

Does the candidate meet the required experience?
Does their compensation fit the approved range?
Does the candidate satisfy a particular eligibility policy?

In each case, there is a difference between seeing the data and being able to verify a claim about the data.

We wanted to explore what that could look like in an actual application instead of just building a standalone proof-of-concept circuit.

How it works

The project has three main parts:

Streamlit frontend

This is the HR dashboard the reviewer interacts with. It lets them select a candidate and start a verification.

Node.js HR verification service

This sits between the frontend and Midnight. It has access to the private candidate information and provides the salary to the circuit as a private witness.

Midnight / Compact circuit

This is where the actual policy check happens.

The core logic is intentionally pretty simple:

circuit verifySalary(
    budget: Uint<0..2^32>
): Boolean {
    const salary = candidateSalary();
    return disclose(salary <= budget);
}

The important part is that the salary itself isn't disclosed. The circuit only reveals whether the comparison is true or false.

Building it

One of the things we wanted to get right was making sure the privacy wasn't just a frontend trick.

It would be pretty pointless to hide the salary with some UI element if we were still sending the salary to the browser behind the scenes.

So the frontend only sends the information needed for the verification request, while the private salary stays inside the HR service.

We then had to get the Midnight wallet, contract deployment, witnesses, proof generation and ledger interaction all working together.

Getting the full flow working was probably one of the more challenging parts of the project. There is quite a bit going on between clicking a button in the UI and getting the final verification result back.

What we learned

The biggest thing we learned was that zero-knowledge isn't just about hiding a value. It's about changing what you actually need to reveal.

Instead of saying:

"Here's the candidate's salary. Check if it's within budget."

you can say:

"Here's a proof that the candidate's salary is within budget."

That distinction is what made Midnight interesting to us.

We also learned that the cryptography is only one part of building something like this. A real HR system would still need proper authentication, authorization, secure data storage, rate limiting, audit logs, key management and a lot more.

There is also an important privacy consideration with repeated queries. If someone can ask enough different budget questions, they could potentially narrow down a private value. So a production version would need controls around who can perform these checks and how often.

What's next

The salary check is just the starting point.

We could extend the same idea to things like:

  • checking whether a salary falls within a minimum and maximum range
  • proving a candidate has enough experience without revealing their exact experience
  • checking multiple private attributes against an internal hiring policy
  • creating different verification policies for different departments
  • keeping a verifiable history of policy checks

The bigger idea is pretty simple:

You shouldn't always have to reveal sensitive data just because someone needs to verify something about it.

That's the problem we wanted to explore with this project, and Midnight gave us a way to actually build it.

Built With

Share this project:

Updates

Submission history