darkirc: Add RLN proof verification on incoming events

This commit is contained in:
parazyd
2025-02-05 14:50:11 +01:00
parent 2492203bf5
commit 868306637b
3 changed files with 110 additions and 20 deletions

View File

@@ -99,7 +99,7 @@ impl RlnIdentity {
event: &Event,
identity_tree: &MerkleTree,
identity_pos: Position,
proving_key: ProvingKey,
proving_key: &ProvingKey,
) -> Result<(Proof, Vec<pallas::Base>)> {
// 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() {

View File

@@ -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<pallas::Base>) = 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)?)
}
}

View File

@@ -16,7 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
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.