diff --git a/bin/darkirc/src/crypto/rln.rs b/bin/darkirc/src/crypto/rln.rs index 2c7e99b2e..c7b25c1e5 100644 --- a/bin/darkirc/src/crypto/rln.rs +++ b/bin/darkirc/src/crypto/rln.rs @@ -99,7 +99,7 @@ impl RlnIdentity { event: &Event, identity_tree: &MerkleTree, identity_pos: Position, - proving_key: ProvingKey, + proving_key: &ProvingKey, ) -> Result<(Proof, Vec)> { // 1. Construct share let epoch = pallas::Base::from(closest_epoch(event.timestamp)); @@ -136,12 +136,13 @@ impl RlnIdentity { let signal_zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?; let signal_circuit = ZkCircuit::new(witnesses, &signal_zkbin); - let proof = Proof::create(&proving_key, &[signal_circuit], &public_inputs, &mut OsRng)?; + let proof = Proof::create(proving_key, &[signal_circuit], &public_inputs, &mut OsRng)?; Ok((proof, vec![y, internal_nullifier])) } } /// Recover a secret from given secret shares +#[allow(dead_code)] pub fn sss_recover(shares: &[(pallas::Base, pallas::Base)]) -> pallas::Base { let mut secret = pallas::Base::zero(); for (j, share_j) in shares.iter().enumerate() { diff --git a/bin/darkirc/src/irc/client.rs b/bin/darkirc/src/irc/client.rs index 5e5a2e425..36b736fac 100644 --- a/bin/darkirc/src/irc/client.rs +++ b/bin/darkirc/src/irc/client.rs @@ -34,12 +34,12 @@ use darkfi::{ }; use darkfi_sdk::{ bridgetree::Position, - crypto::{pasta_prelude::PrimeField, MerkleTree}, + crypto::{pasta_prelude::PrimeField, poseidon_hash, MerkleTree}, pasta::pallas, }; use darkfi_serial::{deserialize_async, serialize_async}; use futures::FutureExt; -use log::{debug, error, warn}; +use log::{debug, error, info, warn}; use sled_overlay::sled; use smol::{ io::{self, AsyncBufReadExt, AsyncWriteExt, BufReader}, @@ -52,7 +52,9 @@ use super::{ server::{IrcServer, MAX_MSG_LEN}, Msg, NickServ, OldPrivmsg, SERVER_NAME, }; -use crate::crypto::rln::{closest_epoch, RlnIdentity, RLN2_SIGNAL_ZKBIN}; +use crate::crypto::rln::{ + closest_epoch, hash_event, RlnIdentity, RLN2_SIGNAL_ZKBIN, RLN_APP_IDENTIFIER, +}; const PENALTY_LIMIT: usize = 5; @@ -259,6 +261,49 @@ impl Client { } } + // If the Event contains an appended blob of data, try to check if it's + // a RLN Signal proof and verify it. + //if false { + let mut verification_failed = false; + #[allow(clippy::never_loop)] + loop { + let (event, blob) = (r.clone(), vec![0,1,2]); + let (proof, public_inputs): (Proof, Vec) = match deserialize_async(&blob).await { + Ok(v) => v, + Err(e) => { + // TODO: FIXME: This logic should be better written. + // Right now we don't enforce RLN so we can just fall-through. + //error!("[IRC CLIENT] Failed deserializing event ephemeral data: {}", e); + break + } + }; + + if public_inputs.len() != 2 { + error!("[IRC CLIENT] Received event has the wrong number of public inputs"); + verification_failed = true; + break + } + + info!("[IRC CLIENT] Verifying incoming Event RLN proof"); + if self.verify_rln_signal_proof( + &event, + proof, + [public_inputs[0], public_inputs[1]], + ).await.is_err() { + verification_failed = true; + break + } + + // TODO: Store for secret shares recovery + info!("[IRC CLIENT] RLN verification successful"); + break + } + + if verification_failed { + error!("[IRC CLIENT] Incoming Event proof verification failed"); + continue + } + // 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(), @@ -558,6 +603,34 @@ impl Client { let mut reader = Cursor::new(proving_key); let proving_key = ProvingKey::read(&mut reader, signal_circuit)?; - rln_identity.create_signal_proof(event, &identity_tree, identity_pos, proving_key) + rln_identity.create_signal_proof(event, &identity_tree, identity_pos, &proving_key) + } + + /// Abstraction for RLN signal proof verification + async fn verify_rln_signal_proof( + &self, + event: &Event, + proof: Proof, + public_inputs: [pallas::Base; 2], + ) -> Result<()> { + let epoch = pallas::Base::from(closest_epoch(event.timestamp)); + let external_nullifier = poseidon_hash([epoch, RLN_APP_IDENTIFIER]); + let x = hash_event(event); + let y = public_inputs[0]; + let internal_nullifier = public_inputs[1]; + + // Fetch the latest commitment Merkle tree + let Some(identity_tree) = self.server.server_store.get("rln_identity_tree")? else { + return Err(Error::DatabaseError( + "RLN Identity tree not found in server store".to_string(), + )) + }; + let identity_tree: MerkleTree = deserialize_async(&identity_tree).await?; + let identity_root = identity_tree.root(0).unwrap(); + + let public_inputs = + vec![epoch, external_nullifier, x, y, internal_nullifier, identity_root.inner()]; + + Ok(proof.verify(&self.server.rln_signal_vk, &public_inputs)?) } } diff --git a/bin/darkirc/src/irc/server.rs b/bin/darkirc/src/irc/server.rs index d28c820d3..2de36e30e 100644 --- a/bin/darkirc/src/irc/server.rs +++ b/bin/darkirc/src/irc/server.rs @@ -16,7 +16,13 @@ * along with this program. If not, see . */ -use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf, sync::Arc}; +use std::{ + collections::HashMap, + fs::File, + io::{BufReader, Cursor}, + path::PathBuf, + sync::Arc, +}; use darkfi::{ event_graph::Event, @@ -90,6 +96,8 @@ pub struct IrcServer { pub server_store: sled::Tree, /// RLN identity storage pub rln_identity_store: sled::Tree, + /// RLN Signal VerifyingKey + pub rln_signal_vk: VerifyingKey, } impl IrcServer { @@ -149,25 +157,32 @@ impl IrcServer { let rln_identity_store = darkirc.sled.open_tree("rln_identity_store")?; // 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); + if server_store.get("rlnv2-diff-signal-pk")?.is_none() { info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Signal ProvingKey"); - let zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?; - let circuit = ZkCircuit::new(empty_witnesses(&zkbin).unwrap(), &zkbin); - let provingkey = ProvingKey::build(zkbin.k, &circuit); + let provingkey = ProvingKey::build(rln_signal_zkbin.k, &rln_signal_circuit); let mut buf = vec![]; provingkey.write(&mut buf)?; 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 zkbin = ZkBinary::decode(RLN2_SIGNAL_ZKBIN)?; - 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-signal-vk", buf)?; - } + let rln_signal_vk = match server_store.get("rlnv2-diff-signal-vk")? { + Some(vk) => { + let mut reader = Cursor::new(vk); + VerifyingKey::read(&mut reader, rln_signal_circuit)? + } + 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)?; + verifyingkey + } + }; if server_store.get("rlnv2-diff-slash-pk")?.is_none() { info!(target: "irc::server", "[RLN] Creating RlnV2_Diff_Slash ProvingKey"); @@ -191,7 +206,7 @@ impl IrcServer { // Initialize RLN Incremental Merkle tree if necessary if server_store.get("rln_identity_tree")?.is_none() { - let tree = MerkleTree::new(0); + let tree = MerkleTree::new(1); server_store.insert("rln_identity_tree", serialize_async(&tree).await)?; } @@ -209,6 +224,7 @@ impl IrcServer { password, server_store, rln_identity_store, + rln_signal_vk, }); // Load any channel/contact configuration.