darkfi/event_graph/
rln.rs

1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use std::collections::BTreeMap;
20
21use async_trait::async_trait;
22use darkfi_sdk::pasta::pallas;
23
24use std::io::Cursor;
25
26use darkfi_sdk::crypto::{pasta_prelude::FromUniformBytes, poseidon_hash, smt::SmtMemoryFp};
27use darkfi_serial::{FutAsyncWriteExt, SerialDecodable, SerialEncodable};
28use halo2_proofs::{arithmetic::Field, circuit::Value};
29use rand::rngs::OsRng;
30use sled_overlay::sled;
31use tracing::info;
32
33use crate::{
34    event_graph::Event,
35    zk::{empty_witnesses, Proof, ProvingKey, VerifyingKey, Witness, ZkCircuit},
36    zkas::ZkBinary,
37    Error, Result,
38};
39
40pub const RLN2_REGISTER_ZKBIN: &[u8] = include_bytes!("proof/rlnv2-diff-register.zk.bin");
41pub const RLN2_SIGNAL_ZKBIN: &[u8] = include_bytes!("proof/rlnv2-diff-signal.zk.bin");
42pub const RLN2_SLASH_ZKBIN: &[u8] = include_bytes!("proof/rlnv2-diff-slash.zk.bin");
43
44/// RLN epoch genesis in millis
45pub const RLN_GENESIS: u64 = 1_738_688_400_000;
46/// RLN epoch length in millis
47pub const RLN_EPOCH_LEN: u64 = 600_000; // 10 min
48
49#[derive(SerialEncodable, SerialDecodable)]
50pub struct Blob {
51    pub proof: Proof,
52    pub y: pallas::Base,
53    pub internal_nullifier: pallas::Base,
54    pub user_msg_limit: u64,
55}
56
57// pub type SmtAccntFp = SparseMerkleTree<
58//     'static,
59//     SMT_FP_DEPTH,
60//     { SMT_FP_DEPTH + 1 },
61//     pallas::Base,
62//     PoseidonFp,
63//     AccountStorage,
64// >;
65
66// #[derive(Clone)]
67// pub struct AccountStorage {
68//     pub tree: sled::Tree,
69// }
70
71// impl AccountStorage {
72//     pub fn new(sled_db: &sled::Db, name: String) -> Self {
73//         Self { tree: sled_db.open_tree(name).unwrap() }
74//     }
75// }
76
77// impl StorageAdapter for AccountStorage {
78//     type Value = pallas::Base;
79
80//     fn put(&mut self, key: BigUint, value: pallas::Base) -> ContractResult {
81//         self.tree.insert(key.to_bytes_le(), &value.to_repr()).unwrap();
82//         Ok(())
83//     }
84
85//     fn get(&self, key: &BigUint) -> Option<pallas::Base> {
86//         let value = match self.tree.get(&key.to_bytes_le()) {
87//             Ok(v) => v,
88//             Err(e) => {
89//                 error!("SledStorage::get(): Fetching key {:?} from Accounts tree: {}", key, e,);
90//                 return None
91//             }
92//         };
93
94//         let value = value?;
95//         let mut repr = [0; 32];
96//         repr.copy_from_slice(&value);
97
98//         pallas::Base::from_repr(repr).into()
99//     }
100
101//     fn del(&mut self, key: &BigUint) -> ContractResult {
102//         self.tree.remove(key.to_bytes_le()).unwrap();
103//         Ok(())
104//     }
105// }
106
107/// Hash message/event modulo `Fp`
108pub fn hash_event(event: &Event) -> pallas::Base {
109    let mut buf = [0u8; 64];
110    buf[..blake3::OUT_LEN].copy_from_slice(event.header.id().as_bytes());
111    pallas::Base::from_uniform_bytes(&buf)
112}
113
114/// Find closest epoch to given timestamp
115pub fn closest_epoch(timestamp: u64) -> u64 {
116    let time_diff = timestamp - RLN_GENESIS;
117    let epoch_idx = time_diff as f64 / RLN_EPOCH_LEN as f64;
118    let rounded = epoch_idx.round() as i64;
119    RLN_GENESIS + (rounded * RLN_EPOCH_LEN as i64) as u64
120}
121
122#[derive(Debug, Clone)]
123struct ShareData {
124    pub x_shares: Vec<pallas::Base>,
125    pub y_shares: Vec<pallas::Base>,
126}
127
128impl ShareData {
129    fn new() -> Self {
130        Self { x_shares: vec![], y_shares: vec![] }
131    }
132}
133
134#[derive(Debug, Default)]
135pub struct MessageMetadata {
136    data: BTreeMap<pallas::Base, BTreeMap<pallas::Base, ShareData>>,
137}
138
139impl MessageMetadata {
140    pub fn new() -> Self {
141        Self { data: BTreeMap::new() }
142    }
143
144    pub fn add_share(
145        &mut self,
146        external_nullifier: pallas::Base,
147        internal_nullifier: pallas::Base,
148        x: pallas::Base,
149        y: pallas::Base,
150    ) -> Result<()> {
151        let inner_map = self.data.entry(external_nullifier).or_default();
152        let share_data = inner_map.entry(internal_nullifier).or_insert_with(ShareData::new);
153
154        share_data.x_shares.push(x);
155        share_data.y_shares.push(y);
156
157        Ok(())
158    }
159
160    pub fn get_shares(
161        &self,
162        external_nullifier: &pallas::Base,
163        internal_nullifier: &pallas::Base,
164    ) -> Vec<(pallas::Base, pallas::Base)> {
165        if let Some(inner_map) = self.data.get(external_nullifier) {
166            if let Some(share_data) = inner_map.get(internal_nullifier) {
167                return share_data
168                    .x_shares
169                    .iter()
170                    .cloned()
171                    .zip(share_data.y_shares.iter().cloned())
172                    .collect()
173            }
174        }
175
176        vec![]
177    }
178
179    /// Check if the recieved message and its metadata are duplicated
180    pub fn is_duplicate(
181        &self,
182        external_nullifier: &pallas::Base,
183        internal_nullifier: &pallas::Base,
184        x: &pallas::Base,
185        y: &pallas::Base,
186    ) -> bool {
187        if let Some(inner_map) = self.data.get(external_nullifier) {
188            if let Some(share_data) = inner_map.get(internal_nullifier) {
189                return share_data.x_shares.contains(x) && share_data.y_shares.contains(y);
190            }
191        }
192
193        false
194    }
195
196    /// Check if the message has reused the nullifiers
197    pub fn is_reused(
198        &self,
199        external_nullifier: &pallas::Base,
200        internal_nullifier: &pallas::Base,
201    ) -> bool {
202        if let Some(inner_map) = self.data.get(external_nullifier) {
203            return inner_map.get(internal_nullifier).is_some()
204        }
205        false
206    }
207}
208
209#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
210pub enum RLNNode {
211    Registration(pallas::Base),
212    Slashing(pallas::Base),
213}
214
215pub fn process_commitment(node: RLNNode, identity_tree: &mut SmtMemoryFp) -> Result<()> {
216    match node {
217        RLNNode::Registration(commitment) => {
218            // Add to smt
219            let commitment = vec![commitment];
220            let commitment: Vec<_> = commitment.into_iter().map(|l| (l, l)).collect();
221            identity_tree.insert_batch(commitment)?;
222        }
223        RLNNode::Slashing(commitment) => {
224            // Remove from smt
225            let commitment = vec![commitment];
226            let commitment: Vec<_> = commitment.into_iter().map(|l| (l, l)).collect();
227            identity_tree.remove_leaves(commitment)?;
228        }
229    }
230
231    Ok(())
232}
233
234pub fn create_slash_proof(
235    secret: pallas::Base,
236    user_msg_limit: u64,
237    identities_tree: &mut SmtMemoryFp,
238    slash_pk: &ProvingKey,
239) -> Result<(Proof, pallas::Base)> {
240    let identity_secret_hash = poseidon_hash([secret, user_msg_limit.into()]);
241    let commitment = poseidon_hash([identity_secret_hash]);
242
243    let identity_root = identities_tree.root();
244    let identity_path = identities_tree.prove_membership(&commitment);
245    // TODO: Delete me later
246    assert!(identity_path.verify(&identity_root, &commitment, &commitment));
247
248    let witnesses = vec![
249        Witness::Base(Value::known(secret)),
250        Witness::Base(Value::known(pallas::Base::from(user_msg_limit))),
251        Witness::SparseMerklePath(Value::known(identity_path.path)),
252    ];
253
254    let public_inputs = vec![secret, pallas::Base::from(user_msg_limit), identity_root];
255
256    let slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false)?;
257    let slash_circuit = ZkCircuit::new(witnesses, &slash_zkbin);
258
259    let proof = Proof::create(slash_pk, &[slash_circuit], &public_inputs, &mut OsRng).unwrap();
260
261    Ok((proof, identity_root))
262}
263
264/// Recover secret using Shamir's secret sharing scheme
265pub fn sss_recover(shares: &[(pallas::Base, pallas::Base)]) -> pallas::Base {
266    let mut secret = pallas::Base::zero();
267    for (j, share_j) in shares.iter().enumerate() {
268        let mut prod = pallas::Base::one();
269        for (i, share_i) in shares.iter().enumerate() {
270            if i != j {
271                prod *= share_i.0 * (share_i.0 - share_j.0).invert().unwrap();
272            }
273        }
274
275        prod *= share_j.1;
276        secret += prod;
277    }
278
279    secret
280}
281
282/// Helper function to read or build register verifying key
283pub(super) fn build_register_vk(sled_db: &sled::Db) -> Result<()> {
284    // sanity check
285    if sled_db.get("rlnv2-diff-register-vk")?.is_some() {
286        return Ok(())
287    }
288    let register_zkbin = ZkBinary::decode(RLN2_REGISTER_ZKBIN, false).unwrap();
289    let register_empty_circuit =
290        ZkCircuit::new(empty_witnesses(&register_zkbin).unwrap(), &register_zkbin);
291
292    info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Register VerifyingKey");
293    let verifyingkey = VerifyingKey::build(register_zkbin.k, &register_empty_circuit);
294    let mut buf = vec![];
295    verifyingkey.write(&mut buf)?;
296    sled_db.insert("rlnv2-diff-register-vk", buf)?;
297    Ok(())
298}
299
300/// Helper function to read register verifying key
301pub(super) fn read_register_vk(sled_db: &sled::Db) -> Result<VerifyingKey> {
302    if let Some(vk) = sled_db.get("rlnv2-diff-register-vk")? {
303        let register_zkbin = ZkBinary::decode(RLN2_REGISTER_ZKBIN, false).unwrap();
304        let register_empty_circuit =
305            ZkCircuit::new(empty_witnesses(&register_zkbin).unwrap(), &register_zkbin);
306        let mut reader = Cursor::new(vk);
307        Ok(VerifyingKey::read(&mut reader, register_empty_circuit)?)
308    } else {
309        Err(Error::Custom("Error reading register verifying key".to_owned()))
310    }
311}
312
313/// Helper function to build signal verifying key
314pub(super) fn build_signal_vk(sled_db: &sled::Db) -> Result<()> {
315    // sanity check
316    if sled_db.get("rlnv2-diff-signal-vk")?.is_some() {
317        return Ok(())
318    }
319    let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false).unwrap();
320    let signal_empty_circuit =
321        ZkCircuit::new(empty_witnesses(&signal_zkbin).unwrap(), &signal_zkbin);
322
323    info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Signal VerifyingKey");
324    let verifyingkey = VerifyingKey::build(signal_zkbin.k, &signal_empty_circuit);
325    let mut buf = vec![];
326    verifyingkey.write(&mut buf)?;
327    sled_db.insert("rlnv2-diff-signal-vk", buf)?;
328    Ok(())
329}
330
331/// Helper function to read signal verifying key
332pub(super) fn read_signal_vk(sled_db: &sled::Db) -> Result<VerifyingKey> {
333    if let Some(vk) = sled_db.get("rlnv2-diff-signal-vk")? {
334        let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false).unwrap();
335        let signal_empty_circuit =
336            ZkCircuit::new(empty_witnesses(&signal_zkbin).unwrap(), &signal_zkbin);
337        let mut reader = Cursor::new(vk);
338        Ok(VerifyingKey::read(&mut reader, signal_empty_circuit)?)
339    } else {
340        Err(Error::Custom("Error Reading signal verifying key".to_owned()))
341    }
342}
343
344/// Helper function to build slash proving key
345pub(super) fn build_slash_pk(sled_db: &sled::Db) -> Result<()> {
346    // sanity check
347    if sled_db.get("rlnv2-diff-slash-pk")?.is_some() {
348        return Ok(())
349    }
350    let slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false).unwrap();
351    let slash_empty_circuit = ZkCircuit::new(empty_witnesses(&slash_zkbin).unwrap(), &slash_zkbin);
352
353    info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash ProvingKey");
354    let verifyingkey = VerifyingKey::build(slash_zkbin.k, &slash_empty_circuit);
355    let mut buf = vec![];
356    verifyingkey.write(&mut buf)?;
357    sled_db.insert("rlnv2-diff-slash-pk", buf)?;
358    Ok(())
359}
360
361/// Helper function to read slash proving key
362pub(super) fn read_slash_pk(sled_db: &sled::Db) -> Result<ProvingKey> {
363    if let Some(vk) = sled_db.get("rlnv2-diff-slash-pk")? {
364        let slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false).unwrap();
365        let slash_empty_circuit =
366            ZkCircuit::new(empty_witnesses(&slash_zkbin).unwrap(), &slash_zkbin);
367        let mut reader = Cursor::new(vk);
368        Ok(ProvingKey::read(&mut reader, slash_empty_circuit)?)
369    } else {
370        Err(Error::Custom("Error Reading slash proving key".to_owned()))
371    }
372}
373
374/// Helper function to build slash verifying key
375pub(super) fn build_slash_vk(sled_db: &sled::Db) -> Result<()> {
376    // sanity check
377    if sled_db.get("rlnv2-diff-slash-vk")?.is_some() {
378        return Ok(())
379    }
380    let slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false).unwrap();
381    let slash_empty_circuit = ZkCircuit::new(empty_witnesses(&slash_zkbin).unwrap(), &slash_zkbin);
382
383    info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash VerifyingKey");
384    let verifyingkey = VerifyingKey::build(slash_zkbin.k, &slash_empty_circuit);
385    let mut buf = vec![];
386    verifyingkey.write(&mut buf)?;
387    sled_db.insert("rlnv2-diff-slash-vk", buf)?;
388    Ok(())
389}
390
391/// Helper function to read slash proving key
392pub(super) fn read_slash_vk(sled_db: &sled::Db) -> Result<VerifyingKey> {
393    if let Some(vk) = sled_db.get("rlnv2-diff-slash-pk")? {
394        let slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false).unwrap();
395        let slash_empty_circuit =
396            ZkCircuit::new(empty_witnesses(&slash_zkbin).unwrap(), &slash_zkbin);
397        let mut reader = Cursor::new(vk);
398        Ok(VerifyingKey::read(&mut reader, slash_empty_circuit)?)
399    } else {
400        Err(Error::Custom("Error Reading slash verifying key".to_owned()))
401    }
402}