Zero-knowledge proof system for verifying image authenticity on Mina blockchain
npm install authenticity-zkappA zero-knowledge proof system for verifying image authenticity on the Mina blockchain.
``sh`
npm install authenticity-zkapp
1. Install dependencies:
`sh`
npm install
2. Create a .env file with your private keys (see .env.example):`
# Devnet keys
DEVNET_PAYER_PRIVATE_KEY=EKE... # Account that pays transaction fees
DEVNET_ZKAPP_PRIVATE_KEY=EKE... # Deterministic zkApp deployment address
# Mainnet keys
MAINNET_PAYER_PRIVATE_KEY=EKE...
MAINNET_ZKAPP_PRIVATE_KEY=EKE...
# Zeko keys
ZEKO_PAYER_PRIVATE_KEY=EKE...
ZEKO_ZKAPP_PRIVATE_KEY=EKE...
`
Deploy the AuthenticityZkApp contract:
`shDeploy to devnet
npm run deploy:devnet
The deployment script will:
1. Compile the AuthenticityProgram (dependency)
2. Compile the AuthenticityZkApp contract
3. Deploy to the specified network
4. Save deployment info to
deployments/[network]-deployment.json$3
After successful deployment, you'll receive:
- Transaction hash for tracking
- zkApp address for contract interaction
- Explorer link to view the deployment
Example deployment info:
`json
{
"network": "devnet",
"zkAppAddress": "B62qj2zKtjxv1oaY4S9f5Noy3BKj7V3SWHX91u4vwuCDwyQVbsTeNF5",
"payerAddress": "B62qkifieqVmoequ7HrKisEPyFno14MP2fpAUnDYZ2krdMt7PbhtgG6",
"deployedAt": "2025-08-13T19:10:01.180Z",
"explorerUrl": "https://minascan.io/devnet/account/B62qj2zKtjxv1oaY4S9f5Noy3BKj7V3SWHX91u4vwuCDwyQVbsTeNF5",
"txHash": "5JvGN4pCvZDJpykvKHXzAkrbfe3q55GkZamN8qmYSgsnwtv8MSjD"
}
`Usage
$3
`sh
npm run example
`$3
`typescript
import {
AuthenticityProgram,
AuthenticityInputs,
FinalRoundInputs,
prepareImageVerification,
Bytes32
} from 'authenticity-zkapp';
import { PrivateKey, PublicKey, Signature } from 'o1js';// 1. Compile the zkProgram
await AuthenticityProgram.compile();
// 2. Prepare image for verification
const verificationInputs = prepareImageVerification('path/to/image.jpg');
// 3. Create a signature to prove ownership
const privateKey = PrivateKey.random();
const publicKey = PublicKey.fromPrivateKey(privateKey);
const signature = Signature.create(
privateKey,
verificationInputs.expectedHash.toFields()
);
// 4. Create public and private inputs
const publicInputs = new AuthenticityInputs({
commitment: verificationInputs.expectedHash,
signature,
publicKey
});
const privateInputs = new FinalRoundInputs({
state: verificationInputs.penultimateState,
initialState: verificationInputs.initialState,
messageWord: verificationInputs.messageWord,
roundConstant: verificationInputs.roundConstant
});
// 5. Generate the proof
const { proof } = await AuthenticityProgram.verifyAuthenticity(
publicInputs,
privateInputs
);
// 6. Verify the proof
const isValid = await AuthenticityProgram.verify(proof);
console.log('Proof is valid:', isValid);
`$3
To compute the exact commitment value that will be stored on-chain:
`typescript
import { computeOnChainCommitment } from 'authenticity-zkapp';
import fs from 'fs';const imageData = fs.readFileSync('path/to/image.jpg');
const commitment = computeOnChainCommitment(imageData);
console.log('On-chain commitment:', commitment.toString());
`API Reference
$3
-
AuthenticityProgram: The main zkProgram for generating and verifying proofs
- AuthenticityProof: The proof type returned by the program
- AuthenticityInputs: Public inputs (commitment, signature, publicKey)
- FinalRoundInputs: Private inputs for SHA-256 final round verification
- Bytes32: 32-byte type for SHA-256 hashes
- AuthenticityZkApp: Smart contract for on-chain verification (stores Poseidon hash of commitment)$3
-
prepareImageVerification(imagePath): Prepares all inputs needed for proof generation
- hashImageOffCircuit(imageData): Computes complete SHA-256 hash
- hashUntilFinalRound(imageData): Computes SHA-256 up to the final round
- performFinalSHA256Round(...): Executes final SHA-256 round in-circuit
- computeOnChainCommitment(imageData): Computes the exact commitment value stored on-chain (SHA-256 → Poseidon)How It Works
This zkApp optimizes proof generation by splitting SHA-256 computation:
1. Off-circuit: Computes rounds 0-62 of SHA-256 in JavaScript
2. In-circuit: Only verifies the final round (63) using zkSNARKs
Circuit Analysis
The AuthenticityProgram method
verifyAuthenticity has the following summary:`ts
{
'Total rows': 908,
Generic: 169,
EndoMulScalar: 218,
Rot64: 6,
RangeCheck0: 18,
Xor16: 36,
Zero: 147,
RangeCheck1: 6,
ForeignFieldAdd: 3,
Poseidon: 198,
CompleteAdd: 5,
VarBaseMul: 102
}
`Development
$3
`sh
npm run build
`$3
`sh
npm run test
`$3
`sh
npm run lint
npm run format
``- Node.js >= 18.14.0
- o1js >= 2.0.0