Bladeren bron

event_graph: Move pregenerated identities to darkirc

x 1 maand geleden
bovenliggende
commit
d32e275bb3

+ 13 - 1
src/event_graph/genesis_commits.rs → bin/darkirc/src/genesis_commits.rs

@@ -16,7 +16,9 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-pub const GENESIS_COMMITMENTS_REPR: &[[u8; 32]] = &[
+use darkfi_sdk::{crypto::pasta_prelude::PrimeField, pasta::pallas};
+
+pub const DARKIRC_GENESIS_COMMITMENTS_REPR: &[[u8; 32]] = &[
     [
         131, 219, 95, 230, 186, 243, 69, 112, 39, 211, 74, 207, 93, 184, 73, 16, 123, 234, 173,
         122, 151, 74, 26, 138, 187, 46, 72, 160, 139, 74, 219, 0,
@@ -60018,3 +60020,13 @@ pub const GENESIS_COMMITMENTS_REPR: &[[u8; 32]] = &[
         129, 214, 148, 118, 196, 77, 69, 233, 86, 194, 108, 117, 31,
     ],
 ];
+
+/// Return DarkIRC's configured pregenerated RLN commitment set.
+pub fn pregenerated_identity_commitments() -> Vec<[u8; 32]> {
+    DARKIRC_GENESIS_COMMITMENTS_REPR.to_vec()
+}
+
+/// Check whether an RLN commitment belongs to DarkIRC's pregenerated set.
+pub fn is_pregenerated_commitment(commitment: &pallas::Base) -> bool {
+    DARKIRC_GENESIS_COMMITMENTS_REPR.contains(&commitment.to_repr())
+}

+ 2 - 4
bin/darkirc/src/irc/services/nickserv.rs

@@ -60,7 +60,6 @@ use std::{str::SplitAsciiWhitespace, sync::Arc};
 
 use darkfi::{
     event_graph::{
-        genesis_commits::GENESIS_COMMITMENTS_REPR,
         rln::{create_slash_proof, RLNNode, SlashBlob, GENESIS_USER_MSG_LIMIT},
         Event,
     },
@@ -71,7 +70,7 @@ use darkfi_serial::{deserialize_async, serialize_async};
 use smol::lock::RwLock;
 
 use super::super::{client::ReplyType, rpl::*};
-use crate::{crypto::rln::RlnIdentity, IrcServer};
+use crate::{crypto::rln::RlnIdentity, genesis_commits::is_pregenerated_commitment, IrcServer};
 
 pub const ACCOUNTS_DB_PREFIX: &str = "darkirc_account_";
 pub const ACCOUNTS_KEY_RLN_IDENTITY: &[u8] = b"rln_identity";
@@ -483,8 +482,7 @@ impl NickServ {
             last_epoch: 0,
         };
 
-        let is_genesis =
-            GENESIS_COMMITMENTS_REPR.contains(&new_rln_identity.commitment().to_repr());
+        let is_genesis = is_pregenerated_commitment(&new_rln_identity.commitment());
         if !is_genesis {
             return Ok(vec![notice(
                 nick,

+ 3 - 0
bin/darkirc/src/lib.rs

@@ -34,6 +34,9 @@ use crate::irc::server::MAX_NICK_LEN;
 /// Cryptography utilities
 pub mod crypto;
 
+/// Pregenerated DarkIRC RLN identity commitments.
+pub mod genesis_commits;
+
 /// JSON-RPC methods
 pub mod rpc;
 

+ 2 - 0
bin/darkirc/src/main.rs

@@ -39,6 +39,7 @@ use darkfi_sdk::crypto::pasta_prelude::PrimeField;
 
 use irc2::{
     crypto::{bcrypt::bcrypt_hash_password, rln::RlnIdentity},
+    genesis_commits,
     irc::server::IrcServer,
     rpc,
     settings::list_configured_contacts,
@@ -367,6 +368,7 @@ async fn realmain(args: Args, ex: Arc<Executor<'static>>) -> Result<()> {
         initial_genesis: DARKIRC_INITIAL_GENESIS,
         hours_rotation: DARKIRC_HOURS_ROTATION,
         genesis_contents: DARKIRC_GENESIS_CONTENTS.to_vec(),
+        pregenerated_identity_commitments: genesis_commits::pregenerated_identity_commitments(),
         max_dags: Some(DARKIRC_MAX_DAGS),
     };
     let event_graph = match EventGraph::new(

+ 1 - 0
bin/tau/taud/src/main.rs

@@ -567,6 +567,7 @@ async fn realmain(settings: Args, executor: Arc<smol::Executor<'static>>) -> Res
         initial_genesis: TAUD_INITIAL_GENESIS,
         hours_rotation: TAUD_HOURS_ROTATION,
         genesis_contents: TAUD_GENESIS_CONTENTS.to_vec(),
+        pregenerated_identity_commitments: Vec::new(),
         max_dags: Some(TAUD_MAX_DAGS),
     };
     let event_graph = match EventGraph::new(

+ 1 - 0
src/event_graph/event.rs

@@ -97,6 +97,7 @@ impl Header {
             initial_genesis: config.initial_genesis,
             hours_rotation: 1,
             genesis_contents: config.genesis_contents.clone(),
+            pregenerated_identity_commitments: Vec::new(),
             max_dags: config.max_dags,
         };
 

+ 56 - 13
src/event_graph/mod.rs

@@ -41,7 +41,6 @@ use tracing::{error, info, warn};
 use url::Url;
 
 use crate::{
-    event_graph::rln::genesis_commitments,
     net::{channel::Channel, P2pPtr},
     system::{msleep, Publisher, PublisherPtr, StoppableTask, StoppableTaskPtr, Subscription},
     Error, Result,
@@ -56,9 +55,6 @@ use proto::{EventRep, EventReq, HeaderRep, HeaderReq, StaticPut, SyncDirection,
 pub mod rln;
 use rln::{IdentityState, RlnState, ZkKeys};
 
-pub mod genesis_commits;
-use genesis_commits::GENESIS_COMMITMENTS_REPR;
-
 pub mod util;
 use util::{
     generate_genesis, millis_until_next_rotation, next_hour_timestamp, next_rotation_timestamp,
@@ -105,6 +101,13 @@ pub struct EventGraphConfig {
     /// Unique payload embedded in genesis events.
     /// Different protocols must use different values.
     pub genesis_contents: Vec<u8>,
+    /// App-provided pregenerated RLN identity commitments.
+    ///
+    /// EventGraph treats these as the only proof-less registration
+    /// commitments accepted with [`rln::GENESIS_BLOB_GUARD`]. Apps
+    /// that do not use pregenerated RLN identities should leave this
+    /// empty.
+    pub pregenerated_identity_commitments: Vec<[u8; 32]>,
     /// Maximum number of DAGs to keep in the rolling window.
     ///
     /// * `Some(n)` - keep n rotation periods.
@@ -126,7 +129,40 @@ pub type LayerUTips = BTreeMap<u64, HashSet<blake3::Hash>>;
 
 /// Generate the deterministic genesis event for the static DAG.
 fn generate_static_genesis(config: &EventGraphConfig) -> Event {
-    generate_genesis(&EventGraphConfig { hours_rotation: 0, ..config.clone() })
+    let header = Header {
+        timestamp: config.initial_genesis,
+        parents: NULL_PARENTS,
+        layer: 0,
+        content_hash: blake3::hash(&config.genesis_contents),
+    };
+
+    Event { header, content: config.genesis_contents.clone() }
+}
+
+fn validate_pregenerated_identity_commitments(
+    config: &EventGraphConfig,
+) -> Result<(Vec<pallas::Base>, HashSet<[u8; 32]>)> {
+    let mut commitments = Vec::with_capacity(config.pregenerated_identity_commitments.len());
+    let mut reprs = HashSet::with_capacity(config.pregenerated_identity_commitments.len());
+
+    for (index, repr) in config.pregenerated_identity_commitments.iter().enumerate() {
+        if !reprs.insert(*repr) {
+            return Err(Error::Custom(format!(
+                "duplicate pregenerated identity commitment at index {index}"
+            )))
+        }
+
+        let commitment: Option<pallas::Base> = pallas::Base::from_repr(*repr).into();
+        let Some(commitment) = commitment else {
+            return Err(Error::Custom(format!(
+                "invalid pregenerated identity commitment at index {index}"
+            )))
+        };
+
+        commitments.push(commitment);
+    }
+
+    Ok((commitments, reprs))
 }
 
 /// Bidirectional timestamp -> event-ID index.
@@ -462,6 +498,10 @@ pub struct EventGraph {
     pub static_pub: PublisherPtr<Event>,
     pub current_genesis: RwLock<Event>,
     pub config: EventGraphConfig,
+    /// Decoded app-provided pregenerated RLN commitments.
+    pregenerated_identity_commitments: Vec<pallas::Base>,
+    /// Canonical byte representations for fast admission checks.
+    pregenerated_identity_commitment_reprs: HashSet<[u8; 32]>,
     pub synced: AtomicBool,
     pub deg_enabled: AtomicBool,
     deg_publisher: PublisherPtr<DegEvent>,
@@ -508,6 +548,8 @@ impl EventGraph {
         let identity_state = IdentityState::new(&sled_db)?;
         let rln_app_id = rln::RlnAppId::from_genesis(&config.genesis_contents);
         let current_genesis = generate_genesis(&config);
+        let (pregenerated_identity_commitments, pregenerated_identity_commitment_reprs) =
+            validate_pregenerated_identity_commitments(&config)?;
         let dag_store = DagStore::new(sled_db.clone(), &config).await;
         let static_dag = Self::static_new(&sled_db, &config).await?;
         let static_dag_blobs = sled_db.open_tree("static-dag-blobs")?;
@@ -549,6 +591,8 @@ impl EventGraph {
             static_pub: Publisher::new(),
             current_genesis: RwLock::new(current_genesis.clone()),
             config: config.clone(),
+            pregenerated_identity_commitments,
+            pregenerated_identity_commitment_reprs,
             synced: AtomicBool::new(false),
             deg_enabled: AtomicBool::new(false),
             deg_publisher: Publisher::new(),
@@ -2279,12 +2323,12 @@ impl EventGraph {
         match rln_node {
             RLNNode::Registration(commitment) => {
                 // Current admission policy is pregenerated identities only.
-                // The guard blob is valid exclusively for commitments built
-                // into GENESIS_COMMITMENTS_REPR; pairing it with any other
-                // commitment is an unambiguous forgery attempt.
+                // The guard blob is valid exclusively for commitments supplied
+                // by the app config; pairing it with any other commitment is
+                // an unambiguous forgery attempt.
                 if blob == rln::GENESIS_BLOB_GUARD {
                     let repr = commitment.to_repr();
-                    if GENESIS_COMMITMENTS_REPR.contains(&repr) {
+                    if self.pregenerated_identity_commitment_reprs.contains(&repr) {
                         if self.identity_state.read().await.contains(commitment) {
                             return StaticEventCheck::Rejected
                         }
@@ -2294,7 +2338,7 @@ impl EventGraph {
                     }
                 }
 
-                // Free non-genesis registration is intentionally disabled:
+                // Free non-pregenerated registration is intentionally disabled:
                 // it is a sybil attack surface. Keep the proof scaffolding
                 // below for the future staked tier, where acceptance must be
                 // backed by a DarkFi smart-contract attestation.
@@ -2386,15 +2430,14 @@ impl EventGraph {
     /// event itself is inserted. Idempotent - skips any commitment
     /// already present in the identity tree.
     pub async fn bootstrap_genesis_identities(&self) -> Result<()> {
-        // Deterministic for premade identities.
+        // Deterministic for configured pregenerated identities.
         let genesis_event = generate_static_genesis(&self.config);
         let genesis_id = genesis_event.id();
         if !self.static_dag.contains_key(genesis_id.as_bytes())? {
             return Err(Error::Custom("static DAG genesis missing during bootstrap".into()))
         }
 
-        let genesis_commitments = genesis_commitments();
-        for commitment in genesis_commitments.iter() {
+        for commitment in self.pregenerated_identity_commitments.iter() {
             if self.identity_state.read().await.contains(commitment) {
                 continue
             }

+ 4 - 13
src/event_graph/rln.rs

@@ -46,7 +46,6 @@ use tracing::info;
 
 use super::Event;
 use crate::{
-    event_graph::genesis_commits::GENESIS_COMMITMENTS_REPR,
     zk::{empty_witnesses, Proof, ProvingKey, VerifyingKey, Witness, ZkCircuit},
     zkas::ZkBinary,
     Error, Result,
@@ -123,7 +122,7 @@ impl RlnAppId {
 
 /// Versioned attestation accompanying a registration.
 ///
-/// Runtime admission currently accepts only pregenerated genesis
+/// Runtime admission currently accepts only configured pregenerated
 /// identities. This enum is retained for the future staked tier,
 /// where a DarkFi smart-contract attestation must back new identity
 /// registration.
@@ -154,10 +153,9 @@ impl RegistrationAttestation {
 /// `(commitment, user_message_limit, max_message_limit)` tuple,
 /// and `attestation` carries the staking proof.
 ///
-/// Non-genesis registration is disabled until contract-backed
-/// staked admission is implemented; current production admission
-/// accepts only pregenerated commitments paired with
-/// [`GENESIS_BLOB_GUARD`].
+/// Non-pregenerated registration is disabled until contract-backed
+/// staked admission is implemented; current admission accepts only
+/// app-configured commitments paired with [`GENESIS_BLOB_GUARD`].
 #[derive(Clone, SerialEncodable, SerialDecodable)]
 pub struct RegistrationBlob {
     pub proof: Proof,
@@ -712,10 +710,3 @@ fn read_pk(sled_db: &sled::Db, key: &str, zkbin_bytes: &[u8]) -> Result<ProvingK
     let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
     Ok(ProvingKey::read(&mut Cursor::new(bytes), circuit)?)
 }
-
-pub fn genesis_commitments() -> Vec<pallas::Base> {
-    GENESIS_COMMITMENTS_REPR
-        .iter()
-        .filter_map(|repr| pallas::Base::from_repr(*repr).into())
-        .collect()
-}

+ 6 - 0
src/event_graph/test_helpers.rs

@@ -24,6 +24,7 @@ use std::{
     },
 };
 
+use darkfi_sdk::{crypto::pasta_prelude::PrimeField, pasta::pallas};
 use sled_overlay::sled;
 use smol::{channel, future, Executor};
 use url::Url;
@@ -34,11 +35,16 @@ use crate::{
     net::{session::SESSION_DEFAULT, settings::NetworkProfile, P2p, Settings},
 };
 
+pub fn test_pregenerated_identity_commitments() -> Vec<[u8; 32]> {
+    vec![pallas::Base::from(0x4556_4752_u64).to_repr()]
+}
+
 pub fn test_config() -> EventGraphConfig {
     EventGraphConfig {
         initial_genesis: 1_704_067_200_000, // 2024-01-01 UTC
         hours_rotation: 0,
         genesis_contents: b"darkfi-test-graph".to_vec(),
+        pregenerated_identity_commitments: test_pregenerated_identity_commitments(),
         max_dags: Some(24),
     }
 }

+ 6 - 5
src/event_graph/tests_rln.rs

@@ -28,7 +28,6 @@ use smol::Executor;
 
 use crate::{
     event_graph::{
-        genesis_commits::GENESIS_COMMITMENTS_REPR,
         rln::{
             epoch_of, epoch_start_millis, sss_recover, Blob, IdentityState, MessageMetadata,
             RLNNode, RegistrationAttestation, RegistrationBlob, RlnAppId, SignalCheck, SlashBlob,
@@ -529,15 +528,17 @@ fn placeholder_slash_blob(ish: pallas::Base, root: pallas::Base) -> SlashBlob {
     }
 }
 
-fn genesis_commitment_at(index: usize) -> pallas::Base {
-    pallas::Base::from_repr(GENESIS_COMMITMENTS_REPR[index]).into_option().unwrap()
+fn genesis_commitment_at(eg: &EventGraphPtr, index: usize) -> pallas::Base {
+    pallas::Base::from_repr(eg.config.pregenerated_identity_commitments[index])
+        .into_option()
+        .unwrap()
 }
 
 #[test]
 fn rln_static_event_pregenerated_guard_accepted() {
     smol::block_on(async {
         let eg = make_eg().await;
-        let commitment = genesis_commitment_at(0);
+        let commitment = genesis_commitment_at(&eg, 0);
         let node = RLNNode::Registration(commitment);
 
         let outcome = eg.rln_verify_static_event(&node, GENESIS_BLOB_GUARD, 0).await;
@@ -550,7 +551,7 @@ fn rln_static_event_guard_with_unknown_commitment_is_malicious() {
     smol::block_on(async {
         let eg = make_eg().await;
         let commitment = pallas::Base::from(0xdead_beefu64);
-        assert!(!GENESIS_COMMITMENTS_REPR.contains(&commitment.to_repr()));
+        assert!(!eg.config.pregenerated_identity_commitments.contains(&commitment.to_repr()));
 
         let node = RLNNode::Registration(commitment);
         let outcome = eg.rln_verify_static_event(&node, GENESIS_BLOB_GUARD, 0).await;