mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-04-28 03:00:18 -04:00
event_graph: added account registeration zk circuit, removed old privmsg struct, plust few small fixes
This commit is contained in:
3
Makefile
3
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)
|
||||
|
||||
|
||||
@@ -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<Proof> {
|
||||
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![
|
||||
|
||||
@@ -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 {
|
||||
// <file:./command.rs::async fn get_history(&self, channels: &HashSet<String>) -> Result<Vec<ReplyType>> {>
|
||||
// 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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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<Self> {
|
||||
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 {
|
||||
|
||||
@@ -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<T: Priv>(&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}");
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,16 +16,21 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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(),
|
||||
|
||||
@@ -238,7 +238,7 @@ pub fn parse_rln_identity(data: &toml::Value) -> Result<Option<RlnIdentity>> {
|
||||
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()),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -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<EventGraph>;
|
||||
pub type LayerUTips = BTreeMap<u64, HashSet<blake3::Hash>>;
|
||||
@@ -369,8 +373,12 @@ pub struct EventGraph {
|
||||
deg_publisher: PublisherPtr<DegEvent>,
|
||||
/// 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<Executor<'_>>,
|
||||
) -> Result<EventGraphPtr> {
|
||||
// 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<u8>) -> Result<()> {
|
||||
self.p2p.broadcast(&StaticPut(event, blob)).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
22
src/event_graph/proof/rlnv2-diff-register.zk
Normal file
22
src/event_graph/proof/rlnv2-diff-register.zk
Normal file
@@ -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);
|
||||
}
|
||||
@@ -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<u8>);
|
||||
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?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user