From e9141d583115941edc8cd76c5daf959dfa0508e2 Mon Sep 17 00:00:00 2001 From: dasman Date: Sat, 10 Jan 2026 20:00:33 +0300 Subject: [PATCH] event_graph: added account registeration zk circuit, removed old privmsg struct, plust few small fixes --- Makefile | 3 +- bin/darkirc/src/crypto/rln.rs | 47 +++++++++-- bin/darkirc/src/irc/client.rs | 29 ++++--- bin/darkirc/src/irc/command.rs | 8 +- bin/darkirc/src/irc/mod.rs | 77 +---------------- bin/darkirc/src/irc/server.rs | 83 ++++++++++++------- bin/darkirc/src/irc/services/nickserv.rs | 47 +++++++---- bin/darkirc/src/settings.rs | 2 +- src/event_graph/mod.rs | 57 ++++++++++++- src/event_graph/proof/rlnv2-diff-register.zk | 22 +++++ .../{proofs => proof}/rlnv2-diff-signal.zk | 0 .../{proofs => proof}/rlnv2-diff-slash.zk | 0 src/event_graph/proto.rs | 59 +++++++++---- src/event_graph/util.rs | 6 +- 14 files changed, 273 insertions(+), 167 deletions(-) create mode 100644 src/event_graph/proof/rlnv2-diff-register.zk rename src/event_graph/{proofs => proof}/rlnv2-diff-signal.zk (100%) rename src/event_graph/{proofs => proof}/rlnv2-diff-slash.zk (100%) diff --git a/Makefile b/Makefile index 0c428645b..a3b7b927c 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,7 @@ RUST_TARGET = $(shell rustc -Vv | grep '^host: ' | cut -d' ' -f2) # List of zkas circuits to compile, used for tests PROOFS_SRC = \ - $(shell find proof -type f -name '*.zk') \ - $(shell find bin/darkirc/proof -type f -name '*.zk') + $(shell find proof -type f -name '*.zk') PROOFS_BIN = $(PROOFS_SRC:=.bin) diff --git a/bin/darkirc/src/crypto/rln.rs b/bin/darkirc/src/crypto/rln.rs index ab6fdabf6..d7e4443a5 100644 --- a/bin/darkirc/src/crypto/rln.rs +++ b/bin/darkirc/src/crypto/rln.rs @@ -43,13 +43,15 @@ pub const RLN_GENESIS: u64 = 1_738_688_400_000; /// RLN epoch length in millis pub const RLN_EPOCH_LEN: u64 = 600_000; // 10 min +pub const RLN2_REGISTER_ZKBIN: &[u8] = + include_bytes!("../../../../src/event_graph/proof/rlnv2-diff-register.zk.bin"); pub const RLN2_SIGNAL_ZKBIN: &[u8] = - include_bytes!("../../../../src/event_graph/proofs/rlnv2-diff-signal.zk.bin"); + include_bytes!("../../../../src/event_graph/proof/rlnv2-diff-signal.zk.bin"); pub const RLN2_SLASH_ZKBIN: &[u8] = - include_bytes!("../../../../src/event_graph/proofs/rlnv2-diff-slash.zk.bin"); + include_bytes!("../../../../src/event_graph/proof/rlnv2-diff-slash.zk.bin"); /// TODO: this should be configurable -pub const USER_MSG_LIMIT: u64 = 6; +pub const MAX_MSG_LIMIT: u64 = 20; /// Find closest epoch to given timestamp pub fn closest_epoch(timestamp: u64) -> u64 { @@ -85,8 +87,8 @@ impl RlnIdentity { pallas::Base::random(&mut rng), ]), trapdoor: poseidon_hash([RLN_TRAPDOOR_DERIVATION_PATH, pallas::Base::random(&mut rng)]), - user_message_limit: USER_MSG_LIMIT, - message_id: 1, + user_message_limit: MAX_MSG_LIMIT, + message_id: 0, last_epoch: closest_epoch(UNIX_EPOCH.elapsed().unwrap().as_millis() as u64), } } @@ -98,6 +100,36 @@ impl RlnIdentity { poseidon_hash([identity_secret_hash]) } + pub fn create_register_proof( + &self, + event: &Event, + identities_tree: &mut SmtMemoryFp, + register_pk: &ProvingKey, + ) -> Result { + let witnesses = vec![ + Witness::Base(Value::known(self.nullifier)), + Witness::Base(Value::known(self.trapdoor)), + Witness::Base(Value::known(pallas::Base::from(self.user_message_limit))), + Witness::Base(Value::known(pallas::Base::from(MAX_MSG_LIMIT))), + ]; + + let commitment = self.commitment(); + let public_inputs = vec![commitment, pallas::Base::from(self.user_message_limit)]; + + info!(target: "crypto::rln::create_register_proof", "[RLN] Creating register proof for account {}", event.header.id()); + let register_zkbin = ZkBinary::decode(RLN2_REGISTER_ZKBIN)?; + let register_circuit = ZkCircuit::new(witnesses, ®ister_zkbin); + + let proof = + Proof::create(®ister_pk, &[register_circuit], &public_inputs, &mut OsRng).unwrap(); + + let leaf = vec![commitment]; + let leaf: Vec<_> = leaf.into_iter().map(|l| (l, l)).collect(); + // TODO: Recipients should verify that identity doesn't exist already before insert. + identities_tree.insert_batch(leaf.clone()).unwrap(); // leaf == pos + Ok(proof) + } + pub fn create_signal_proof( &self, event: &Event, @@ -117,10 +149,11 @@ impl RlnIdentity { let internal_nullifier = poseidon_hash([a_1]); // 2. Inclusion proof + let commitment = self.commitment(); let identity_root = identity_tree.root(); - let identity_path = identity_tree.prove_membership(&self.commitment()); + let identity_path = identity_tree.prove_membership(&commitment); // TODO: Delete me later - assert!(identity_path.verify(&identity_root, &self.commitment(), &self.commitment())); + assert!(identity_path.verify(&identity_root, &commitment, &commitment)); // 3. Create ZK proof let witnesses = vec![ diff --git a/bin/darkirc/src/irc/client.rs b/bin/darkirc/src/irc/client.rs index 733626701..b488bcc07 100644 --- a/bin/darkirc/src/irc/client.rs +++ b/bin/darkirc/src/irc/client.rs @@ -47,7 +47,7 @@ use tracing::{debug, error, info, warn}; use super::{ server::{IrcServer, MAX_MSG_LEN}, - Msg, NickServ, OldPrivmsg, SERVER_NAME, + NickServ, Privmsg, SERVER_NAME, }; use crate::crypto::rln::{closest_epoch, RlnIdentity, RLN2_SIGNAL_ZKBIN}; @@ -214,7 +214,7 @@ impl Client { // If we have a RLN identity, now we'll build a ZK proof. // Also I really want GOTO in Rust... Fags. - if let Some(mut rln_identity) = *self.server.rln_identity.write().await { + if let Some(ref mut rln_identity) = *self.server.rln_identity.write().await { // If the current epoch is different, we can reset the message counter if rln_identity.last_epoch != closest_epoch(event.header.timestamp) { rln_identity.last_epoch = closest_epoch(event.header.timestamp); @@ -266,7 +266,6 @@ impl Client { // ) -> Result> {> // for which the logic for delivery should be kept in sync r = self.incoming.receive().fuse() => { - info!("incoming: {:?}", r); // We will skip this if it's our own message. let event_id = r.header.id(); if *self.last_sent.read().await == event_id { @@ -284,11 +283,10 @@ impl Client { } // Try to deserialize the `Event`'s content into a `Privmsg` - let mut privmsg = match Msg::deserialize(r.content()).await { - Ok(Msg::V1(old_msg)) => old_msg.into_new(), - Ok(Msg::V2(new_msg)) => new_msg, + let mut privmsg = match deserialize_async_partial(r.content()).await { + Ok((v, _)) => v, Err(e) => { - error!("[IRC CLIENT] Failed deserializing incoming Privmsg event: {e}"); + error!(target: "irc::client", "[IRC CLIENT] Failed deserializing event: {e}"); continue } }; @@ -370,7 +368,7 @@ impl Client { { Ok((v, _)) => v, Err(e) => { - error!(target: "irc::server", "[RLN] Failed deserializing incoming RLN Identity events: {}", e); + error!(target: "irc::client", "[RLN] Failed deserializing incoming RLN Identity events: {}", e); continue } }; @@ -542,11 +540,18 @@ impl Client { // Truncate messages longer than MAX_MSG_LEN let msg = if msg.len() > MAX_MSG_LEN { msg.split_at(MAX_MSG_LEN).0 } else { msg }; - OldPrivmsg { channel, nick, msg: msg.to_string() } - } - // Internal helper function that creates an Event from PRIVMSG arguments - async fn privmsg_to_event(&self, mut privmsg: OldPrivmsg) -> Event { + // TODO: This is kept as old version of privmsg, since now we + // can deserialize both old and new versions, after some time + // this will be replaced with Privmsg (new version) + let mut privmsg = Privmsg { + version: 0, + channel, + nick: self.nickname.read().await.to_string(), + msg: msg.to_string(), + msg_type: 0, + }; + // Encrypt the Privmsg if an encryption method is available. self.server.try_encrypt(&mut privmsg).await; diff --git a/bin/darkirc/src/irc/command.rs b/bin/darkirc/src/irc/command.rs index fb33c0639..f60bd5ff8 100644 --- a/bin/darkirc/src/irc/command.rs +++ b/bin/darkirc/src/irc/command.rs @@ -52,13 +52,14 @@ use std::{collections::HashSet, sync::atomic::Ordering::SeqCst}; use darkfi::Result; +use darkfi_serial::deserialize_async_partial; use tracing::{error, info}; use super::{ client::{Client, ReplyType}, rpl::*, server::MAX_NICK_LEN, - IrcChannel, Msg, SERVER_NAME, + IrcChannel, SERVER_NAME, }; use crate::crypto::bcrypt::bcrypt_hash_password; @@ -931,9 +932,8 @@ impl Client { } // Try to deserialize it. (Here we skip errors) - let mut privmsg = match Msg::deserialize(event.content()).await { - Ok(Msg::V1(old_msg)) => old_msg.into_new(), - Ok(Msg::V2(new_msg)) => new_msg, + let mut privmsg = match deserialize_async_partial(event.content()).await { + Ok((v, _)) => v, Err(_) => continue, }; diff --git a/bin/darkirc/src/irc/mod.rs b/bin/darkirc/src/irc/mod.rs index 73801da41..964539016 100644 --- a/bin/darkirc/src/irc/mod.rs +++ b/bin/darkirc/src/irc/mod.rs @@ -19,8 +19,7 @@ use std::{collections::HashSet, sync::Arc}; use crypto_box::ChaChaBox; -use darkfi::{Error, Result}; -use darkfi_serial::{async_trait, deserialize_async_partial, SerialDecodable, SerialEncodable}; +use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable}; /// IRC client state pub(crate) mod client; @@ -41,32 +40,6 @@ pub(crate) mod rpl; /// Hardcoded server name const SERVER_NAME: &str = "irc.dark.fi"; -pub trait Priv { - fn channel(&mut self) -> &mut String; - fn nick(&mut self) -> &mut String; - fn msg(&mut self) -> &mut String; -} - -/// IRC PRIVMSG (old version) -#[derive(Clone, Debug, SerialEncodable, SerialDecodable)] -pub struct OldPrivmsg { - pub channel: String, - pub nick: String, - pub msg: String, -} - -impl OldPrivmsg { - pub fn into_new(self) -> Privmsg { - Privmsg { - version: 0, - msg_type: 0, - channel: self.channel.clone(), - nick: self.nick.clone(), - msg: self.msg.clone(), - } - } -} - /// IRC PRIVMSG (new version) #[derive(Clone, Debug, SerialEncodable, SerialDecodable)] pub struct Privmsg { @@ -77,54 +50,6 @@ pub struct Privmsg { pub msg: String, } -impl Priv for OldPrivmsg { - fn channel(&mut self) -> &mut String { - &mut self.channel - } - - fn nick(&mut self) -> &mut String { - &mut self.nick - } - - fn msg(&mut self) -> &mut String { - &mut self.msg - } -} -impl Priv for Privmsg { - fn channel(&mut self) -> &mut String { - &mut self.channel - } - - fn nick(&mut self) -> &mut String { - &mut self.nick - } - - fn msg(&mut self) -> &mut String { - &mut self.msg - } -} - -pub enum Msg { - V1(OldPrivmsg), - V2(Privmsg), -} - -impl Msg { - pub async fn deserialize(bytes: &[u8]) -> Result { - let old_privmsg = deserialize_async_partial(bytes).await; - if let Ok((old_msg, _)) = old_privmsg { - return Ok(Msg::V1(old_msg)) - } - - let new_privmsg = deserialize_async_partial(bytes).await; - if let Ok((new_msg, _)) = new_privmsg { - return Ok(Msg::V2(new_msg)) - } - - Err(Error::Custom("Unknown message format".into())) - } -} - /// IRC channel definition #[derive(Clone)] pub struct IrcChannel { diff --git a/bin/darkirc/src/irc/server.rs b/bin/darkirc/src/irc/server.rs index 8922bdefa..bc6cb631f 100644 --- a/bin/darkirc/src/irc/server.rs +++ b/bin/darkirc/src/irc/server.rs @@ -22,7 +22,7 @@ use darkfi::{ event_graph::Event, system::{StoppableTask, StoppableTaskPtr, Subscription}, util::path::expand_path, - zk::{empty_witnesses, ProvingKey, VerifyingKey, ZkCircuit}, + zk::{empty_witnesses, ProvingKey, ZkCircuit}, zkas::ZkBinary, Error, Result, }; @@ -49,11 +49,11 @@ use url::Url; use super::{ client::Client, services::nickserv::{ACCOUNTS_DB_PREFIX, ACCOUNTS_KEY_RLN_IDENTITY}, - IrcChannel, IrcContact, Priv, Privmsg, + IrcChannel, IrcContact, Privmsg, }; use crate::{ crypto::{ - rln::{RlnIdentity, RLN2_SIGNAL_ZKBIN, RLN2_SLASH_ZKBIN}, + rln::{RlnIdentity, RLN2_REGISTER_ZKBIN, RLN2_SIGNAL_ZKBIN, RLN2_SLASH_ZKBIN}, saltbox, }, settings::{ @@ -156,7 +156,28 @@ impl IrcServer { let mut identity_tree = SmtMemoryFp::new(store, hasher.clone(), &EMPTY_NODES_FP); // Generate RLN proving and verifying keys, if needed - let rln_signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false)?; + let rln_register_zkbin = ZkBinary::decode(RLN2_REGISTER_ZKBIN)?; + let rln_register_circuit = + ZkCircuit::new(empty_witnesses(&rln_register_zkbin)?, &rln_register_zkbin); + + if server_store.get("rlnv2-diff-register-pk")?.is_none() { + info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Register ProvingKey"); + let provingkey = ProvingKey::build(rln_register_zkbin.k, &rln_register_circuit); + let mut buf = vec![]; + provingkey.write(&mut buf)?; + server_store.insert("rlnv2-diff-register-pk", buf)?; + } + + // if server_store.get("rlnv2-diff-register-vk")?.is_none() { + // info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Register VerifyingKey"); + // let verifyingkey = VerifyingKey::build(rln_register_zkbin.k, &rln_register_circuit); + // let mut buf = vec![]; + // verifyingkey.write(&mut buf)?; + // server_store.insert("rlnv2-diff-register-vk", buf)?; + // } + + // Generate RLN proving and verifying keys, if needed + let rln_signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?; let rln_signal_circuit = ZkCircuit::new(empty_witnesses(&rln_signal_zkbin)?, &rln_signal_zkbin); @@ -168,33 +189,37 @@ impl IrcServer { server_store.insert("rlnv2-diff-signal-pk", buf)?; } - if server_store.get("rlnv2-diff-signal-vk")?.is_none() { - info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Signal VerifyingKey"); - let verifyingkey = VerifyingKey::build(rln_signal_zkbin.k, &rln_signal_circuit); - let mut buf = vec![]; - verifyingkey.write(&mut buf)?; - server_store.insert("rlnv2-diff-signal-vk", buf)?; - } + // if server_store.get("rlnv2-diff-signal-vk")?.is_none() { + // info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Signal VerifyingKey"); + // let verifyingkey = VerifyingKey::build(rln_signal_zkbin.k, &rln_signal_circuit); + // let mut buf = vec![]; + // verifyingkey.write(&mut buf)?; + // server_store.insert("rlnv2-diff-signal-vk", buf)?; + // } + + // Generate RLN proving and verifying keys, if needed + let rln_slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN)?; + let rln_slash_circuit = + ZkCircuit::new(empty_witnesses(&rln_slash_zkbin)?, &rln_slash_zkbin); if server_store.get("rlnv2-diff-slash-pk")?.is_none() { info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash ProvingKey"); let zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false)?; let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin); let provingkey = ProvingKey::build(zkbin.k, &circuit); + let provingkey = ProvingKey::build(rln_slash_zkbin.k, &rln_slash_circuit); let mut buf = vec![]; provingkey.write(&mut buf)?; server_store.insert("rlnv2-diff-slash-pk", buf)?; } - if server_store.get("rlnv2-diff-slash-vk")?.is_none() { - info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash VerifyingKey"); - let zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false)?; - let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin); - let verifyingkey = VerifyingKey::build(zkbin.k, &circuit); - let mut buf = vec![]; - verifyingkey.write(&mut buf)?; - server_store.insert("rlnv2-diff-slash-vk", buf)?; - } + // if server_store.get("rlnv2-diff-slash-vk")?.is_none() { + // info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash VerifyingKey"); + // let verifyingkey = VerifyingKey::build(rln_slash_zkbin.k, &rln_slash_circuit); + // let mut buf = vec![]; + // verifyingkey.write(&mut buf)?; + // server_store.insert("rlnv2-diff-slash-vk", buf)?; + // } // Construct SMT from static DAG let mut events = darkirc.event_graph.static_fetch_all().await?; @@ -403,28 +428,28 @@ impl IrcServer { } /// Try encrypting a given `Privmsg` if there is such a channel/contact. - pub async fn try_encrypt(&self, privmsg: &mut T) { - if let Some((name, channel)) = self.channels.read().await.get_key_value(privmsg.channel()) { + pub async fn try_encrypt(&self, privmsg: &mut Privmsg) { + if let Some((name, channel)) = self.channels.read().await.get_key_value(&privmsg.channel) { if let Some(saltbox) = &channel.saltbox { // We will use a dummy channel value of MAX_NICK_LEN, // since its not used, so all encrypted messages look the same. - *privmsg.channel() = saltbox::encrypt(saltbox, &[0x00; MAX_NICK_LEN]); + privmsg.channel = saltbox::encrypt(saltbox, &[0x00; MAX_NICK_LEN]); // We will pad the name to MAX_NICK_LEN so they all look the same - *privmsg.nick() = saltbox::encrypt(saltbox, &Self::pad(privmsg.nick())); - *privmsg.msg() = saltbox::encrypt(saltbox, privmsg.msg().as_bytes()); + privmsg.nick = saltbox::encrypt(saltbox, &Self::pad(&privmsg.nick)); + privmsg.msg = saltbox::encrypt(saltbox, privmsg.msg.as_bytes()); debug!("Successfully encrypted message for {name}"); return } }; - if let Some((name, contact)) = self.contacts.read().await.get_key_value(privmsg.channel()) { + if let Some((name, contact)) = self.contacts.read().await.get_key_value(&privmsg.channel) { // We will use dummy channel and nick values of MAX_NICK_LEN, // since they are not used, so all encrypted messages look the same. - *privmsg.channel() = saltbox::encrypt(&contact.saltbox, &[0x00; MAX_NICK_LEN]); + privmsg.channel = saltbox::encrypt(&contact.saltbox, &[0x00; MAX_NICK_LEN]); // We will encrypt the dummy nick value using our own self saltbox, // so we can identify our messages. - *privmsg.nick() = saltbox::encrypt(&contact.self_saltbox, &[0x00; MAX_NICK_LEN]); - *privmsg.msg() = saltbox::encrypt(&contact.saltbox, privmsg.msg().as_bytes()); + privmsg.nick = saltbox::encrypt(&contact.self_saltbox, &[0x00; MAX_NICK_LEN]); + privmsg.msg = saltbox::encrypt(&contact.saltbox, privmsg.msg.as_bytes()); debug!("Successfully encrypted message for {name}"); }; } diff --git a/bin/darkirc/src/irc/services/nickserv.rs b/bin/darkirc/src/irc/services/nickserv.rs index 663376116..13f50780f 100644 --- a/bin/darkirc/src/irc/services/nickserv.rs +++ b/bin/darkirc/src/irc/services/nickserv.rs @@ -16,16 +16,21 @@ * along with this program. If not, see . */ -use std::{str::SplitAsciiWhitespace, sync::Arc, time::UNIX_EPOCH}; +use std::{io::Cursor, str::SplitAsciiWhitespace, sync::Arc, time::UNIX_EPOCH}; -use darkfi::{event_graph::Event, Result}; +use darkfi::{ + event_graph::Event, + zk::{empty_witnesses, ProvingKey, ZkCircuit}, + zkas::ZkBinary, + Error, Result, +}; use darkfi_sdk::{crypto::pasta_prelude::PrimeField, pasta::pallas}; use darkfi_serial::serialize_async; use smol::lock::RwLock; use super::super::{client::ReplyType, rpl::*}; use crate::{ - crypto::rln::{closest_epoch, RlnIdentity, USER_MSG_LIMIT}, + crypto::rln::{closest_epoch, RlnIdentity, RLN2_REGISTER_ZKBIN}, IrcServer, }; @@ -139,7 +144,8 @@ impl NickServ { let account_name = account_name.unwrap(); let identity_nullifier = identity_nullifier.unwrap(); let identity_trapdoor = identity_trapdoor.unwrap(); - let _user_msg_limit = user_msg_limit.unwrap(); + let user_msg_limit: u64 = + user_msg_limit.unwrap().parse().expect("msg limit must be a number"); // Open the sled tree let db = @@ -188,9 +194,9 @@ impl NickServ { let new_rln_identity = RlnIdentity { nullifier: identity_nullifier, trapdoor: identity_trapdoor, - user_message_limit: USER_MSG_LIMIT, - message_id: 1, // TODO - last_epoch: closest_epoch(UNIX_EPOCH.elapsed().unwrap().as_secs()), + user_message_limit: user_msg_limit, + message_id: 0, // TODO + last_epoch: closest_epoch(UNIX_EPOCH.elapsed().unwrap().as_millis() as u64), }; // Store account @@ -204,17 +210,30 @@ impl NickServ { *self.server.rln_identity.write().await = Some(new_rln_identity); // Update SMT, DAG and broadcast - let mut identities_tree = self.server.rln_identity_tree.write().await; let rln_commitment = new_rln_identity.commitment(); - - let commitment = vec![rln_commitment]; - let commitment: Vec<_> = commitment.into_iter().map(|l| (l, l)).collect(); - identities_tree.insert_batch(commitment)?; - let evgr = &self.server.darkirc.event_graph; let event = Event::new_static(serialize_async(&rln_commitment).await, evgr).await; + + let mut identity_tree = self.server.rln_identity_tree.write().await; + + // Retrieve the register ZK proving key from the db + let register_zkbin = ZkBinary::decode(RLN2_REGISTER_ZKBIN)?; + let register_circuit = ZkCircuit::new(empty_witnesses(®ister_zkbin)?, ®ister_zkbin); + let Some(proving_key) = self.server.server_store.get("rlnv2-diff-register-pk")? else { + return Err(Error::DatabaseError( + "RLN register proving key not found in server store".to_string(), + )) + }; + let mut reader = Cursor::new(proving_key); + let proving_key = ProvingKey::read(&mut reader, register_circuit)?; + + let proof = + new_rln_identity.create_register_proof(&event, &mut identity_tree, &proving_key)?; + + let blob = serialize_async(&(proof, user_msg_limit)).await; + evgr.static_insert(&event).await?; - evgr.static_broadcast(event).await?; + evgr.static_broadcast(event, blob).await?; Ok(vec![ReplyType::Notice(( "NickServ".to_string(), diff --git a/bin/darkirc/src/settings.rs b/bin/darkirc/src/settings.rs index abc7f3924..96018aeab 100644 --- a/bin/darkirc/src/settings.rs +++ b/bin/darkirc/src/settings.rs @@ -238,7 +238,7 @@ pub fn parse_rln_identity(data: &toml::Value) -> Result> { user_message_limit, // TODO: FIXME: We should probably keep track of these rather than // resetting here - message_id: 1, + message_id: 0, last_epoch: closest_epoch(UNIX_EPOCH.elapsed().unwrap().as_secs()), })) } diff --git a/src/event_graph/mod.rs b/src/event_graph/mod.rs index afd2bf236..7b5c3fd08 100644 --- a/src/event_graph/mod.rs +++ b/src/event_graph/mod.rs @@ -101,6 +101,10 @@ pub const NULL_PARENTS: [Hash; N_EVENT_PARENTS] = [NULL_ID; N_EVENT_PARENTS]; /// Maximum number of DAGs to store, this should be configurable pub const DAGS_MAX_NUMBER: i8 = 24; +pub const RLN2_REGISTER_ZKBIN: &[u8] = include_bytes!("proof/rlnv2-diff-register.zk.bin"); +pub const RLN2_SIGNAL_ZKBIN: &[u8] = include_bytes!("proof/rlnv2-diff-signal.zk.bin"); +pub const RLN2_SLASH_ZKBIN: &[u8] = include_bytes!("proof/rlnv2-diff-slash.zk.bin"); + /// Atomic pointer to an [`EventGraph`] instance. pub type EventGraphPtr = Arc; pub type LayerUTips = BTreeMap>; @@ -369,8 +373,12 @@ pub struct EventGraph { deg_publisher: PublisherPtr, /// Run in fast mode where if set we sync only headers. fast_mode: bool, + /// Registering verify key + register_vk: VerifyingKey, /// Signaling verify key signal_vk: VerifyingKey, + /// Slashing verify key + slash_vk: VerifyingKey, } impl EventGraph { @@ -396,8 +404,27 @@ impl EventGraph { ex: Arc>, ) -> Result { // Read or build signal verifying key - let signal_zkbin = include_bytes!("proofs/rlnv2-diff-signal.zk.bin"); - let signal_zkbin = ZkBinary::decode(signal_zkbin, false).unwrap(); + let register_zkbin = ZkBinary::decode(RLN2_REGISTER_ZKBIN, false).unwrap(); + let register_empty_circuit = + ZkCircuit::new(empty_witnesses(®ister_zkbin).unwrap(), ®ister_zkbin); + + let register_vk = match sled_db.get("rlnv2-diff-register-vk")? { + Some(vk) => { + let mut reader = Cursor::new(vk); + VerifyingKey::read(&mut reader, register_empty_circuit)? + } + None => { + info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Register VerifyingKey"); + let verifyingkey = VerifyingKey::build(register_zkbin.k, ®ister_empty_circuit); + let mut buf = vec![]; + verifyingkey.write(&mut buf)?; + sled_db.insert("rlnv2-diff-register-vk", buf)?; + verifyingkey + } + }; + + // Read or build signal verifying key + let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN, false).unwrap(); let signal_empty_circuit = ZkCircuit::new(empty_witnesses(&signal_zkbin).unwrap(), &signal_zkbin); @@ -416,6 +443,26 @@ impl EventGraph { } }; + // Read or build slash verifying key + let slash_zkbin = ZkBinary::decode(RLN2_SLASH_ZKBIN, false).unwrap(); + let slash_empty_circuit = + ZkCircuit::new(empty_witnesses(&slash_zkbin).unwrap(), &slash_zkbin); + + let slash_vk = match sled_db.get("rlnv2-diff-slash-vk")? { + Some(vk) => { + let mut reader = Cursor::new(vk); + VerifyingKey::read(&mut reader, slash_empty_circuit)? + } + None => { + info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash VerifyingKey"); + let verifyingkey = VerifyingKey::build(slash_zkbin.k, &slash_empty_circuit); + let mut buf = vec![]; + verifyingkey.write(&mut buf)?; + sled_db.insert("rlnv2-diff-slash-vk", buf)?; + verifyingkey + } + }; + let broadcasted_ids = RwLock::new(HashSet::new()); let event_pub = Publisher::new(); let static_pub = Publisher::new(); @@ -449,7 +496,9 @@ impl EventGraph { synced: RwLock::new(false), deg_enabled: RwLock::new(false), deg_publisher: Publisher::new(), + register_vk, signal_vk, + slash_vk, }); // Check if we have it in our DAG. @@ -1285,8 +1334,8 @@ impl EventGraph { Ok(()) } - pub async fn static_broadcast(&self, event: Event) -> Result<()> { - self.p2p.broadcast(&StaticPut(event)).await; + pub async fn static_broadcast(&self, event: Event, blob: Vec) -> Result<()> { + self.p2p.broadcast(&StaticPut(event, blob)).await; Ok(()) } diff --git a/src/event_graph/proof/rlnv2-diff-register.zk b/src/event_graph/proof/rlnv2-diff-register.zk new file mode 100644 index 000000000..b83ccfe8e --- /dev/null +++ b/src/event_graph/proof/rlnv2-diff-register.zk @@ -0,0 +1,22 @@ +k = 11; +field = "pallas"; + +constant "Rlnv2Diff_Register" {} + +witness "Rlnv2Diff_Register" { + Base identity_nullifier, + Base identity_trapdoor, + Base user_message_limit, + Base message_limit, +} + +circuit "Rlnv2Diff_Register" { + identity_secret = poseidon_hash(identity_nullifier, identity_trapdoor); + identity_secret_hash = poseidon_hash(identity_secret, user_message_limit); + identity_commitment = poseidon_hash(identity_secret_hash); + + less_than_strict(user_message_limit, message_limit); + + constrain_instance(identity_commitment); + constrain_instance(user_message_limit); +} diff --git a/src/event_graph/proofs/rlnv2-diff-signal.zk b/src/event_graph/proof/rlnv2-diff-signal.zk similarity index 100% rename from src/event_graph/proofs/rlnv2-diff-signal.zk rename to src/event_graph/proof/rlnv2-diff-signal.zk diff --git a/src/event_graph/proofs/rlnv2-diff-slash.zk b/src/event_graph/proof/rlnv2-diff-slash.zk similarity index 100% rename from src/event_graph/proofs/rlnv2-diff-slash.zk rename to src/event_graph/proof/rlnv2-diff-slash.zk diff --git a/src/event_graph/proto.rs b/src/event_graph/proto.rs index 4401d7b24..473c5e6a8 100644 --- a/src/event_graph/proto.rs +++ b/src/event_graph/proto.rs @@ -26,7 +26,10 @@ use std::{ }, }; -use darkfi_sdk::{crypto::poseidon_hash, pasta::pallas}; +use darkfi_sdk::{ + crypto::{poseidon_hash, util::FieldElemAsStr}, + pasta::{pallas, Fp}, +}; use darkfi_serial::{ async_trait, deserialize_async, deserialize_async_partial, SerialDecodable, SerialEncodable, }; @@ -146,7 +149,7 @@ impl_p2p_message!(EventPut, "EventGraph::EventPut", 0, 0, DEFAULT_METERING_CONFI /// A P2P message representing publishing an event of a static graph /// (most likely RLN_identities) on the network #[derive(Clone, SerialEncodable, SerialDecodable)] -pub struct StaticPut(pub Event); +pub struct StaticPut(pub Event, pub Vec); impl_p2p_message!(StaticPut, "EventGraph::StaticPut", 0, 0, DEFAULT_METERING_CONFIGURATION); /// A P2P message representing an event request @@ -299,6 +302,9 @@ impl ProtocolEventGraph { let mut verification_failed = false; #[allow(clippy::never_loop)] loop { + if blob.is_empty() { + break + } let (proof, y, internal_nullifier, identity_root): ( Proof, pallas::Base, @@ -325,15 +331,15 @@ impl ProtocolEventGraph { let public_inputs = vec![identity_root, external_nullifier, x, y, internal_nullifier]; - metadata.add_share(external_nullifier, internal_nullifier, x, y)?; - if metadata.is_duplicate(&external_nullifier, &internal_nullifier, &x, &y) { - error!("[Signal] Duplicate Message!"); + error!(target: "event_graph::protocol::handle_event_put()", "[EVENTGRAPH] Duplicate Message!"); verification_failed = true; break } + info!("internal nullifier: {}", internal_nullifier.to_string()); if metadata.is_reused(&external_nullifier, &internal_nullifier) { + info!(target: "event_graph::protocol::handle_event_put()", "[EVENTGRAPH] Metadata is reused.. slashing.."); let shares = metadata.get_shares(&external_nullifier, &internal_nullifier); let _secret = sss_recover(&shares); @@ -346,6 +352,9 @@ impl ProtocolEventGraph { break } + // At this point we can safely add the shares + metadata.add_share(external_nullifier, internal_nullifier, x, y)?; + info!(target: "event_graph::protocol::handle_event_put()", "[EVENTGRAPH] Verifying incoming Event RLN proof"); verification_failed = proof.verify(&self.event_graph.signal_vk, &public_inputs).is_err(); @@ -354,7 +363,7 @@ impl ProtocolEventGraph { } if verification_failed { - error!(target: "event_graph::protocol::handle_event_put()", "[EVENTGRAPH] Incoming Event RLN proof verification failed"); + error!(target: "event_graph::protocol::handle_event_put()", "[EVENTGRAPH] Incoming Event RLN Signaling proof verification failed"); continue } @@ -611,21 +620,19 @@ impl ProtocolEventGraph { let mut bantimes = MovingWindow::new(WINDOW_EXPIRY_TIME); loop { - let event = match self.st_put_sub.receive().await { - Ok(v) => v.0.clone(), + let (event, blob) = match self.st_put_sub.receive().await { + Ok(v) => (v.0.clone(), v.1.clone()), Err(_) => continue, }; trace!( - target: "event_graph::protocol::handle_event_put()", - "Got EventPut: {} [{}]", event.id(), self.channel.address(), + target: "event_graph::protocol::handle_static_put()", + "Got StaticPut: {} [{}]", event.id(), self.channel.address(), ); - info!("Received a static event: {:?}", event); - // Check if node has finished syncing its DAG if !*self.event_graph.synced.read().await { debug!( - target: "event_graph::protocol::handle_event_put", + target: "event_graph::protocol::handle_static_put", "DAG is still syncing, skipping..." ); continue @@ -640,6 +647,30 @@ impl ProtocolEventGraph { continue } + if !blob.is_empty() { + let (proof, user_msg_limit): (Proof, u64) = match deserialize_async_partial(&blob) + .await + { + Ok((v, _)) => v, + Err(e) => { + error!(target: "event_graph::protocol::handle_static_put()","[EVENTGRAPH] Failed deserializing event ephemeral data: {}", e); + continue + } + }; + let commitment: Fp = match deserialize_async_partial(&event.content()).await { + Ok((v, _)) => v, + Err(e) => { + error!(target: "event_graph::protocol::handle_static_put()","[EVENTGRAPH] Failed deserializing event ephemeral data: {}", e); + continue + } + }; + let public_inputs = vec![commitment, user_msg_limit.into()]; + + if proof.verify(&self.event_graph.register_vk, &public_inputs).is_err() { + error!(target: "event_graph::protocol::handle_static_put()", "[EVENTGRAPH] Incoming Event RLN Registration proof verification failed"); + continue + } + } // Check if event's parents are in the static DAG for parent in event.header.parents.iter() { if *parent == NULL_ID { @@ -679,7 +710,7 @@ impl ProtocolEventGraph { ); self.event_graph.static_insert(&event).await?; - self.event_graph.static_broadcast(event).await? + self.event_graph.static_broadcast(event, blob).await? } } diff --git a/src/event_graph/util.rs b/src/event_graph/util.rs index e0669edb2..1d6dc4c83 100644 --- a/src/event_graph/util.rs +++ b/src/event_graph/util.rs @@ -304,11 +304,9 @@ impl MessageMetadata { external_nullifier: &pallas::Base, internal_nullifier: &pallas::Base, ) -> bool { - let inner_map = self.data.get(external_nullifier); - if inner_map.is_some() { - return inner_map.unwrap().get(internal_nullifier).is_some() + if let Some(inner_map) = self.data.get(external_nullifier) { + return inner_map.get(internal_nullifier).is_some() } - false } }