diff --git a/Cargo.lock b/Cargo.lock
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1719,6 +1719,7 @@
  "http 0.2.12",
  "once_cell",
  "rand 0.8.5",
+ "regex",
  "reqwest",
  "serde",
  "serde_json",
diff --git a/native/native_rust_library/Cargo.lock b/native/native_rust_library/Cargo.lock
--- a/native/native_rust_library/Cargo.lock
+++ b/native/native_rust_library/Cargo.lock
@@ -335,6 +335,7 @@
  "hex",
  "once_cell",
  "rand",
+ "regex",
  "serde",
  "serde_json",
  "sha2",
@@ -1587,14 +1588,14 @@
 
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.4.3",
- "regex-syntax 0.8.2",
+ "regex-automata 0.4.8",
+ "regex-syntax 0.8.5",
 ]
 
 [[package]]
@@ -1608,13 +1609,13 @@
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax 0.8.2",
+ "regex-syntax 0.8.5",
 ]
 
 [[package]]
@@ -1625,9 +1626,9 @@
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.2"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "remove_dir_all"
diff --git a/services/backup/Cargo.toml b/services/backup/Cargo.toml
--- a/services/backup/Cargo.toml
+++ b/services/backup/Cargo.toml
@@ -18,6 +18,7 @@
   "blob-client",
   "aws",
   "grpc_clients",
+  "crypto"
 ] }
 once_cell = { workspace = true }
 tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
diff --git a/services/identity/Cargo.toml b/services/identity/Cargo.toml
--- a/services/identity/Cargo.toml
+++ b/services/identity/Cargo.toml
@@ -17,6 +17,7 @@
   "aws",
   "grpc_clients",
   "blob-client",
+  "crypto"
 ] }
 tracing = { workspace = true }
 tracing-subscriber = { workspace = true, features = ["env-filter", "json"] }
diff --git a/services/identity/src/client_service.rs b/services/identity/src/client_service.rs
--- a/services/identity/src/client_service.rs
+++ b/services/identity/src/client_service.rs
@@ -45,7 +45,10 @@
   validate_remove_reserved_username_message,
 };
 use crate::siwe::{
-  is_valid_ethereum_address, parse_and_verify_siwe_message, SocialProof,
+  parse_and_verify_siwe_message, SocialProof,
+};
+use comm_lib::{
+  crypto,
 };
 use crate::token::{AccessTokenData, AuthType};
 pub use crate::grpc_services::protos::unauth::identity_client_service_server::{
@@ -110,7 +113,7 @@
     debug!("Received registration request for: {}", message.username);
 
     if !is_valid_username(&message.username)
-      || is_valid_ethereum_address(&message.username)
+      || crypto::siwe::is_valid_ethereum_address(&message.username)
     {
       return Err(tonic::Status::invalid_argument(
         tonic_status_messages::INVALID_USERNAME,
diff --git a/services/identity/src/siwe.rs b/services/identity/src/siwe.rs
--- a/services/identity/src/siwe.rs
+++ b/services/identity/src/siwe.rs
@@ -4,7 +4,6 @@
   aws::ddb::types::AttributeValue,
   database::{AttributeExtractor, AttributeMap, TryFromAttribute},
 };
-use regex::Regex;
 use siwe::{Message, VerificationOpts};
 use time::OffsetDateTime;
 use tonic::Status;
@@ -55,11 +54,6 @@
   Ok(siwe_message)
 }
 
-pub fn is_valid_ethereum_address(candidate: &str) -> bool {
-  let ethereum_address_regex = Regex::new(r"^0x[a-fA-F0-9]{40}$").unwrap();
-  ethereum_address_regex.is_match(candidate)
-}
-
 #[derive(derive_more::Constructor, Clone)]
 pub struct SocialProof {
   pub message: String,
@@ -107,46 +101,6 @@
 
   use super::*;
 
-  #[test]
-  fn test_valid_ethereum_address() {
-    assert!(is_valid_ethereum_address(
-      "0x1234567890123456789012345678901234567890"
-    ),);
-    assert!(is_valid_ethereum_address(
-      "0xABCDEF123456789012345678901234567890ABCD"
-    ));
-    assert!(is_valid_ethereum_address(
-      "0xabcdef123456789012345678901234567890abcd"
-    ));
-  }
-
-  #[allow(clippy::bool_assert_comparison)]
-  #[test]
-  fn test_invalid_ethereum_address() {
-    // Shorter than 42 characters
-    assert_eq!(
-      is_valid_ethereum_address("0x12345678901234567890123456789012345678"),
-      false
-    );
-    // Longer than 42 characters
-    assert_eq!(
-      is_valid_ethereum_address("0x123456789012345678901234567890123456789012"),
-      false
-    );
-    // Missing 0x prefix
-    assert_eq!(
-      is_valid_ethereum_address("1234567890123456789012345678901234567890"),
-      false
-    );
-    // Contains invalid characters
-    assert_eq!(
-      is_valid_ethereum_address("0x1234567890GHIJKL9012345678901234567890"),
-      false
-    );
-    // Empty string
-    assert_eq!(is_valid_ethereum_address(""), false);
-  }
-
   #[test]
   fn test_social_proof_ddb_format() {
     let message = "foo";
diff --git a/shared/comm-lib/Cargo.toml b/shared/comm-lib/Cargo.toml
--- a/shared/comm-lib/Cargo.toml
+++ b/shared/comm-lib/Cargo.toml
@@ -43,6 +43,7 @@
 hex = { workspace = true }
 uuid = { workspace = true, features = ["v4"] }
 sha2 = { workspace = true }
+regex = { workspace = true }
 # aws dependencies
 aws-config = { workspace = true, optional = true }
 aws-sdk-dynamodb = { workspace = true, optional = true }
diff --git a/shared/comm-lib/src/crypto/mod.rs b/shared/comm-lib/src/crypto/mod.rs
--- a/shared/comm-lib/src/crypto/mod.rs
+++ b/shared/comm-lib/src/crypto/mod.rs
@@ -1,2 +1,3 @@
 /// AES 256 GCM encryption and decryption.
 pub mod aes256;
+pub mod siwe;
diff --git a/shared/comm-lib/src/crypto/siwe.rs b/shared/comm-lib/src/crypto/siwe.rs
new file mode 100644
--- /dev/null
+++ b/shared/comm-lib/src/crypto/siwe.rs
@@ -0,0 +1,52 @@
+use regex::Regex;
+
+pub fn is_valid_ethereum_address(candidate: &str) -> bool {
+  let ethereum_address_regex = Regex::new(r"^0x[a-fA-F0-9]{40}$").unwrap();
+  ethereum_address_regex.is_match(candidate)
+}
+
+#[cfg(test)]
+mod tests {
+
+  use super::*;
+
+  #[test]
+  fn test_valid_ethereum_address() {
+    assert!(is_valid_ethereum_address(
+      "0x1234567890123456789012345678901234567890"
+    ),);
+    assert!(is_valid_ethereum_address(
+      "0xABCDEF123456789012345678901234567890ABCD"
+    ));
+    assert!(is_valid_ethereum_address(
+      "0xabcdef123456789012345678901234567890abcd"
+    ));
+  }
+
+  #[allow(clippy::bool_assert_comparison)]
+  #[test]
+  fn test_invalid_ethereum_address() {
+    // Shorter than 42 characters
+    assert_eq!(
+      is_valid_ethereum_address("0x12345678901234567890123456789012345678"),
+      false
+    );
+    // Longer than 42 characters
+    assert_eq!(
+      is_valid_ethereum_address("0x123456789012345678901234567890123456789012"),
+      false
+    );
+    // Missing 0x prefix
+    assert_eq!(
+      is_valid_ethereum_address("1234567890123456789012345678901234567890"),
+      false
+    );
+    // Contains invalid characters
+    assert_eq!(
+      is_valid_ethereum_address("0x1234567890GHIJKL9012345678901234567890"),
+      false
+    );
+    // Empty string
+    assert_eq!(is_valid_ethereum_address(""), false);
+  }
+}
diff --git a/web/backup-client-wasm/Cargo.lock b/web/backup-client-wasm/Cargo.lock
--- a/web/backup-client-wasm/Cargo.lock
+++ b/web/backup-client-wasm/Cargo.lock
@@ -17,6 +17,15 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -198,6 +207,7 @@
  "hex",
  "once_cell",
  "rand",
+ "regex",
  "serde",
  "serde_json",
  "sha2",
@@ -705,6 +715,35 @@
  "getrandom",
 ]
 
+[[package]]
+name = "regex"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+
 [[package]]
 name = "reqwest"
 version = "0.11.24"