Skip to content

Commit 68d0621

Browse files
committed
add simulated blockchain
1 parent 3832013 commit 68d0621

File tree

11 files changed

+425
-40
lines changed

11 files changed

+425
-40
lines changed

.gitignore

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Rust build artifacts
2+
/target/
3+
**/*.rs.bk
4+
5+
# Cargo package files
6+
Cargo.lock
7+
8+
# Node.js dependencies and build artifacts
9+
node_modules/
10+
npm-debug.log*
11+
yarn-debug.log*
12+
yarn-error.log*
13+
package-lock.json
14+
15+
# VSCode and JetBrains IDE settings
16+
.vscode/
17+
.idea/
18+
19+
# OS files
20+
.DS_Store
21+
Thumbs.db
22+
23+
# Byproducts
24+
*.log
25+
26+
# Ignore compiled Lambda zips (if any)
27+
*.zip
28+
29+
# Ignore dotenv files (if used)
30+
.env
31+
.env.*
32+
33+
# Ignore test output
34+
*.out

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ edition = "2021"
77
num-bigint = { version = "0.4", features = ["rand"] }
88
num-traits = "0.2"
99
rand = "0.8"
10+
reqwest = { version = "0.11", features = ["blocking", "json"] }
11+
serde = { version = "1.0", features = ["derive"] }
12+
serde_json = "1.0"
1013

1114
# Arkworks - all aligned to v0.4
1215
ark-ec = "0.4"

README.md

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,81 @@
1-
21
# Vi-Anonymous-Credential
32

43
This project implements a prototype of an anonymous credential issuance system using a bilinear pairing-based accumulator, designed to support an allow-list mechanism for revoking credentials and preventing misuse.
54

65
The accumulator logic is currently being updated based on the model proposed by Flamini et al. (2025).
76
👉 Read the paper here [https://eprint.iacr.org/2025/549.pdf]
87

9-
8+
---
109

11-
## 🔧 Project Components
10+
## Project Components
1211

13-
### 🧩 Accumulator
12+
### Accumulator
1413
Represents the core bilinear pairing-based accumulator structure.
1514
Includes logic for initializing, updating, and testing accumulator behavior via a simple `main` function.
1615

17-
### 📜 Credential
16+
### Credential
1817
Defines a credential that includes:
1918
- A BBS+ signature over a list of attribute values (messages).
2019
- The issuer's public key.
2120
This object models the credential held by the user.
2221

23-
### 🔐 Commitment
22+
### Commitment
2423
Implements Pedersen-style commitments to hide sensitive message values.
2524
Used during zero-knowledge proof generation to ensure privacy.
2625

27-
### 🧾 Witness
26+
### Witness
2827
Contains the data a credential holder maintains to prove non-revocation:
2928
- A private scalar `x`
3029
- A Pedersen commitment `c_x`
3130
- A trapdoor witness `w_x_t`
3231
- The credential's BBS+ signature
3332

34-
33+
---
34+
35+
## How to Test with the Blockchain
36+
37+
1. **Start the Blockchain Server**
38+
39+
Open a terminal and run:
40+
```
41+
node registry/blockchain_server.js
42+
```
43+
You should see:
44+
```
45+
Blockchain API running on port 3001
46+
```
47+
48+
2. **Run the Rust Tests**
49+
50+
In another terminal, from the project root, run:
51+
```
52+
cargo test --test issue_vc -- --nocapture
53+
cargo test --test revoke_vc -- --nocapture
54+
```
55+
This will:
56+
- Issue a credential and log it to the blockchain.
57+
- Revoke a credential and log the revocation to the blockchain.
58+
59+
3. **Check the Blockchain Server Terminal**
60+
61+
You will see logs like:
62+
```
63+
[ADD] Block added with data: "CredentialIssued:..."
64+
[ADD] Block added with data: "CredentialRevoked:..."
65+
[CHAIN] Chain requested
66+
[VERIFY] Chain verification: true
67+
```
68+
69+
4. **(Optional) Query the Blockchain API**
70+
71+
You can use `curl` or Postman to check the chain:
72+
```
73+
curl http://localhost:3001/chain
74+
```
75+
76+
---
3577

36-
🚧 In Progress
37-
Integration of the ZKP generation algorithm for the holder to prove validity and non-revocation of their credential.
78+
In Progress:
79+
- Integration of the ZKP generation algorithm for the holder to prove validity and non-revocation of their credential.
3880

39-
81+
---

registry/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# How to Test with the Blockchain
2+
3+
1. **Start the Blockchain Server**
4+
5+
Open a terminal in the `registry` folder and run:
6+
```
7+
node blockchain_server.js
8+
```
9+
You should see:
10+
```
11+
Blockchain API running on port 3001
12+
```
13+
14+
2. **Run the Rust Tests**
15+
16+
In a separate terminal, from the project root, run:
17+
```
18+
cargo test --test issue_vc -- --nocapture
19+
cargo test --test revoke_vc -- --nocapture
20+
```
21+
This will:
22+
- Issue a credential and add it to the blockchain.
23+
- Revoke a credential and add the revocation to the blockchain.
24+
25+
3. **Check Blockchain Server Output**
26+
27+
The blockchain server terminal will show logs like:
28+
```
29+
[ADD] Block added with data: "CredentialIssued:..."
30+
[ADD] Block added with data: "CredentialRevoked:..."
31+
[CHAIN] Chain requested
32+
[VERIFY] Chain verification: true
33+
```
34+
35+
4. **(Optional) Query the Blockchain API**
36+
37+
You can check the blockchain state using:
38+
```
39+
curl http://localhost:3001/chain
40+
```
41+
42+
**Note:**
43+
- The blockchain server must be running before you run the Rust tests.
44+
- Each test run will add new blocks to the blockchain.

registry/blockchain.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
const crypto = require('crypto');
2+
3+
class Block {
4+
constructor(index, timestamp, data, prevHash) {
5+
this.index = index;
6+
this.timestamp = timestamp;
7+
this.data = data;
8+
this.prevHash = prevHash;
9+
this.hash = this.computeHash();
10+
}
11+
12+
computeHash() {
13+
const str = this.index + this.timestamp + this.data + this.prevHash;
14+
return crypto.createHash('sha256').update(str).digest('hex');
15+
}
16+
}
17+
18+
class Blockchain {
19+
constructor() {
20+
this.chain = [new Block(0, Date.now(), 'genesis', '0')];
21+
}
22+
23+
addBlock(data) {
24+
const prev = this.chain[this.chain.length - 1];
25+
const block = new Block(
26+
prev.index + 1,
27+
Date.now(),
28+
data,
29+
prev.hash
30+
);
31+
this.chain.push(block);
32+
}
33+
34+
verifyChain() {
35+
for (let i = 1; i < this.chain.length; i++) {
36+
const prev = this.chain[i - 1];
37+
const curr = this.chain[i];
38+
if (curr.prevHash !== prev.hash || curr.hash !== curr.computeHash()) {
39+
return false;
40+
}
41+
}
42+
return true;
43+
}
44+
45+
getLatest() {
46+
return this.chain[this.chain.length - 1];
47+
}
48+
49+
findByData(data) {
50+
return this.chain.find(b => b.data === data);
51+
}
52+
}
53+
54+
module.exports = { Block, Blockchain };

registry/blockchain_server.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const express = require('express');
2+
const { Blockchain } = require('./blockchain');
3+
const app = express();
4+
app.use(express.json());
5+
6+
const chain = new Blockchain();
7+
8+
app.post('/add', (req, res) => {
9+
const { data } = req.body;
10+
chain.addBlock(data);
11+
console.log(`[ADD] Block added with data: ${JSON.stringify(data)}`);
12+
res.json({ message: 'Block added' });
13+
});
14+
15+
app.get('/chain', (req, res) => {
16+
console.log(`[CHAIN] Chain requested`);
17+
res.json(chain.chain);
18+
});
19+
20+
app.get('/verify', (req, res) => {
21+
const valid = chain.verifyChain();
22+
console.log(`[VERIFY] Chain verification: ${valid}`);
23+
res.json({ valid });
24+
});
25+
26+
app.listen(3001, () => console.log('Blockchain API running on port 3001'));

registry/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "registry",
3+
"version": "1.0.0",
4+
"main": "blockchain.js",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1"
7+
},
8+
"keywords": [],
9+
"author": "",
10+
"license": "ISC",
11+
"description": "",
12+
"dependencies": {
13+
"express": "^5.1.0"
14+
}
15+
}

src/acumulator.rs

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -169,29 +169,27 @@ impl Accumulator {
169169
// remove an accumulated values - send the updated message for each holder to re-calculate their witness
170170

171171
pub fn del(&mut self, sk: &SecretKey<Fr>, revoke_cred: Credential) -> Fr {
172-
173-
// Serialize the signature
174-
let mut hasher = Sha256::new();
175-
let mut sig_bytes = vec![];
176-
revoke_cred.signature.serialize_compressed(&mut sig_bytes).unwrap();
177-
hasher.update(sig_bytes);
178-
let hash = hasher.finalize();
179-
let cred_id = format!(
180-
"cred_{}",
181-
hash[..4].iter().map(|b| format!("{:02x}", b)).collect::<String>()
182-
);
183-
184-
// Get x associated with this credential
185-
let delta = *self.get_x_by_id(&cred_id).unwrap();
186-
// let delta = self.issued_x.get(&cred_id).unwrap(); // Option<&Fr>
187-
// the delta shall be stored in some-where for all un-update valid holder still work
188-
let sum = delta + sk.0;
189-
let inv = sum.inverse().unwrap();
190-
191-
// Update accumulator
192-
self.acc_val = self.acc_val.mul(inv);
193-
194-
return delta;
172+
// 1. Compute credential ID from signature
173+
let mut hasher = Sha256::new();
174+
let mut sig_bytes = vec![];
175+
revoke_cred.signature.serialize_compressed(&mut sig_bytes).unwrap();
176+
hasher.update(sig_bytes);
177+
let hash = hasher.finalize();
178+
let cred_id = format!(
179+
"cred_{}",
180+
hash[..4].iter().map(|b| format!("{:02x}", b)).collect::<String>()
181+
);
182+
183+
// 2. Get x associated with this credential
184+
let delta = *self.get_x_by_id(&cred_id).unwrap();
185+
186+
// 3. Update accumulator value to remove x
187+
let sum = delta + sk.0;
188+
let inv = sum.inverse().unwrap();
189+
self.acc_val = self.acc_val.mul(inv);
190+
191+
// 4. Return the revoked x (delta)
192+
return delta;
195193
}
196194

197195
fn get_x_by_id(&self, cred_id: &str) -> Option<&Fr> {
@@ -209,7 +207,4 @@ impl Accumulator {
209207
pub fn get_parameter(&self) -> BBParams {
210208
self.parameter.clone().expect("Parameter of accumulator not been setup")
211209
}
212-
213-
214-
}
215-
210+
}

src/main.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,20 @@ fn main() {
3131
let message_count = 2;
3232
let params = SignatureParamsG1::<Bls12_381>::generate_using_rng(&mut rng, message_count);
3333
let fr_messages: Vec<Fr> = (0..message_count).map(|_| Fr::rand(&mut rng)).collect();
34+
35+
// Step 4: Issuer creates a BBS+ signature over the holder's messages
3436
let signature = SignatureG1::new(&mut rng, &fr_messages, &sk, &params).unwrap();
3537

36-
// Step 4: Create credential
38+
// Step 5: Issuer constructs the Credential object
3739
let credential = Credential {
3840
signature: signature.clone(),
3941
messages: fr_messages.clone(),
40-
issuer_pk: None,
42+
issuer_pk: None, // Optionally, set issuer_pk to Some(pk)
4143
};
4244

45+
// Step 6: Issuer delivers the credential to the holder
46+
// (In practice, this would be sent securely to the holder)
47+
4348
println!(
4449
"type of signature: {}",
4550
std::any::type_name_of_val(&credential.signature)
@@ -59,4 +64,19 @@ fn main() {
5964
// println!("\n[Test Case] Credential revoked");
6065
// println!("- delta (x) = {:?}", delta);
6166
// println!("- acc_val (after) = {:?}", acc.acc_val);
67+
68+
// --- Registry/Blockchain demo ---
69+
// use registry::Blockchain;
70+
// use std::time::{SystemTime, UNIX_EPOCH};
71+
72+
// let mut vdr = Blockchain::new();
73+
// let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
74+
// vdr.add_block("CredentialIssued:12345".to_string(), now);
75+
// vdr.add_block("CredentialRevoked:12345".to_string(), now + 1);
76+
77+
// println!("\n[Registry] Blockchain state:");
78+
// for block in &vdr.chain {
79+
// println!("{:?}", block);
80+
// }
81+
// println!("Chain valid? {}", vdr.verify_chain());
6282
}

0 commit comments

Comments
 (0)