diff --git a/app/src/main/java/com/futo/polycentric/core/MemoryStore.kt b/app/src/main/java/com/futo/polycentric/core/MemoryStore.kt
index 4157cc6cbb45e09c208cff182e6c7a0906d50533..14ed2439505ad2493a86d08a7a1e3ae2c7b85985 100644
--- a/app/src/main/java/com/futo/polycentric/core/MemoryStore.kt
+++ b/app/src/main/java/com/futo/polycentric/core/MemoryStore.kt
@@ -18,10 +18,7 @@ class MemoryStore : Store() {
         }
 
         override fun hashCode(): Int {
-            var result = system.hashCode()
-            result = 31 * result + process.contentHashCode()
-            result = 31 * result + logicalClock.hashCode()
-            return result
+            return combineHashCodes(listOf(system.hashCode(), process.contentHashCode(), logicalClock.hashCode()))
         }
     }
 
diff --git a/app/src/main/java/com/futo/polycentric/core/Models.kt b/app/src/main/java/com/futo/polycentric/core/Models.kt
index 1c52c1e7b34c79c4c1c9b45359005ecc57a379de..53675a84515b9a7cfb6534390d9ab879b624f9cf 100644
--- a/app/src/main/java/com/futo/polycentric/core/Models.kt
+++ b/app/src/main/java/com/futo/polycentric/core/Models.kt
@@ -51,7 +51,7 @@ class Digest(val digestType: Long, val digest: ByteArray) {
     }
 
     override fun hashCode(): Int {
-        return digestType.hashCode().times(31).plus(digest.contentHashCode())
+        return combineHashCodes(listOf(digestType.hashCode(), digest.contentHashCode()))
     }
 
     override fun toString(): String {
@@ -109,7 +109,7 @@ data class Pointer(
     }
 
     override fun hashCode(): Int {
-        return super.hashCode()
+        return combineHashCodes(listOf(system.hashCode(), process.hashCode(), logicalClock.hashCode(), digest.hashCode()))
     }
 
     override fun toString(): String {
@@ -146,7 +146,6 @@ data class Pointer(
             )
         }
 
-
         fun fromSignedEvent(signedEvent: SignedEvent): Pointer {
             val event = signedEvent.event
             return Pointer(
@@ -223,7 +222,7 @@ data class PublicKey(val keyType: Long, val key: ByteArray) {
     }
 
     override fun hashCode(): Int {
-        return 31 * keyType.hashCode() + key.contentHashCode()
+        return combineHashCodes(listOf(keyType.hashCode(), key.contentHashCode()))
     }
 
     companion object {
@@ -272,7 +271,7 @@ class PrivateKey(val keyType: Long, val key: ByteArray) {
     }
 
     override fun hashCode(): Int {
-        return 31 * keyType.hashCode() + key.contentHashCode()
+        return combineHashCodes(listOf(keyType.hashCode(), key.contentHashCode()))
     }
 
     override fun toString(): String {
diff --git a/app/src/main/java/com/futo/polycentric/core/Utility.kt b/app/src/main/java/com/futo/polycentric/core/Utility.kt
index 418331da40b0f07d0a3f0a78c4ebcc8ae9e086be..93ccc2a81b5602cb2aff04a70cab99d263e71187 100644
--- a/app/src/main/java/com/futo/polycentric/core/Utility.kt
+++ b/app/src/main/java/com/futo/polycentric/core/Utility.kt
@@ -21,6 +21,9 @@ fun ByteArray.toBase64(): String {
 fun ByteArray.toBase64Url(): String {
     return Base64.encodeToString(this, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
 }
+fun String.base64UrlToByteArray(): ByteArray {
+    return Base64.decode(this, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
+}
 
 fun String.base64ToByteArray(): ByteArray {
     return Base64.decode(this, Base64.NO_PADDING or Base64.NO_WRAP)
@@ -116,4 +119,12 @@ fun Protocol.PublicKey.systemToURLInfoSystemLinkUrl(servers: Iterable<String>):
         .build();
 
     return "polycentric://" + urlInfo.toByteArray().toBase64Url()
+}
+
+fun combineHashCodes(hashCodes: List<Int?>): Int {
+    var result = 1
+    for (hashCode in hashCodes) {
+        result = 31 * result + (hashCode ?: 0)
+    }
+    return result
 }
\ No newline at end of file