feat(labs): CryptographicAgeVerificationSandbox
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
d6b75e937f
commit
2116c75fc1
|
|
@ -0,0 +1,41 @@
|
||||||
|
package chat.revolt.internals
|
||||||
|
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
|
class CryptographicAgeVerification {
|
||||||
|
fun getProofHash(
|
||||||
|
seed: String,
|
||||||
|
userAge: Int,
|
||||||
|
minAllowedAge: Int
|
||||||
|
): Pair<ByteArray, ByteArray> {
|
||||||
|
var proof = MessageDigest.getInstance("SHA-256").digest(seed.toByteArray())
|
||||||
|
|
||||||
|
for (i in 1 until userAge - minAllowedAge) {
|
||||||
|
proof = MessageDigest.getInstance("SHA-256").digest(proof)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ageHash =
|
||||||
|
MessageDigest.getInstance("SHA-256").digest(seed.toByteArray())
|
||||||
|
|
||||||
|
for (i in 1 until userAge - 1) {
|
||||||
|
ageHash = MessageDigest.getInstance("SHA-256").digest(ageHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ageHash to proof
|
||||||
|
}
|
||||||
|
|
||||||
|
fun proveAge(
|
||||||
|
minAllowedAge: Int,
|
||||||
|
proofHash: ByteArray,
|
||||||
|
ageHash: ByteArray,
|
||||||
|
): Boolean {
|
||||||
|
var verifyHash =
|
||||||
|
MessageDigest.getInstance("SHA-256").digest(proofHash.toString().toByteArray())
|
||||||
|
|
||||||
|
for (i in 1 until minAllowedAge - 1) {
|
||||||
|
verifyHash = MessageDigest.getInstance("SHA-256").digest(verifyHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
return verifyHash.contentEquals(ageHash)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Home
|
import androidx.compose.material.icons.filled.Home
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
|
@ -36,6 +37,7 @@ import androidx.navigation.NavController
|
||||||
enum class LabsHomeScreenTab {
|
enum class LabsHomeScreenTab {
|
||||||
Home,
|
Home,
|
||||||
Mockups,
|
Mockups,
|
||||||
|
Sandboxes,
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -80,6 +82,19 @@ fun LabsHomeScreen(navController: NavController) {
|
||||||
Text("UI Mockups")
|
Text("UI Mockups")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
NavigationBarItem(
|
||||||
|
selected = currentTab.value == LabsHomeScreenTab.Sandboxes,
|
||||||
|
onClick = { currentTab.value = LabsHomeScreenTab.Sandboxes },
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.PlayArrow,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text("Sandboxes")
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
|
@ -128,6 +143,22 @@ fun LabsHomeScreen(navController: NavController) {
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabsHomeScreenTab.Sandboxes -> {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text("Cryptographic Age Verification")
|
||||||
|
},
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
navController.navigate("sandboxes/cryptoageverif")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import chat.revolt.api.settings.FeatureFlags
|
import chat.revolt.api.settings.FeatureFlags
|
||||||
import chat.revolt.screens.labs.ui.mockups.CallScreenMockup
|
import chat.revolt.screens.labs.ui.mockups.CallScreenMockup
|
||||||
|
import chat.revolt.screens.labs.ui.sandbox.CryptographicAgeVerificationSandbox
|
||||||
|
|
||||||
annotation class LabsFeature
|
annotation class LabsFeature
|
||||||
|
|
||||||
|
|
@ -62,6 +63,10 @@ fun LabsRootScreen(topNav: NavController) {
|
||||||
composable("mockups/call") {
|
composable("mockups/call") {
|
||||||
CallScreenMockup()
|
CallScreenMockup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composable("sandboxes/cryptoageverif") {
|
||||||
|
CryptographicAgeVerificationSandbox(labsNav)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
package chat.revolt.screens.labs.ui.sandbox
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import chat.revolt.api.REVOLT_KJBOOK
|
||||||
|
import chat.revolt.internals.CryptographicAgeVerification
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun CryptographicAgeVerificationSandbox(navController: NavController) {
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
"Crypto Age Verify Sandbox",
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = { navController.popBackStack() }) {
|
||||||
|
Icon(Icons.AutoMirrored.Default.ArrowBack, "Back")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { pv ->
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.padding(pv)
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
Button(onClick = {
|
||||||
|
val cav = CryptographicAgeVerification()
|
||||||
|
val (ageHash, verifyHash) = cav.getProofHash(
|
||||||
|
seed = REVOLT_KJBOOK,
|
||||||
|
userAge = 21,
|
||||||
|
minAllowedAge = 18
|
||||||
|
)
|
||||||
|
|
||||||
|
Log.d(
|
||||||
|
"CryptographicAgeVerificationSandbox",
|
||||||
|
"ageHash: ${ageHash.contentToString()}"
|
||||||
|
)
|
||||||
|
Log.d(
|
||||||
|
"CryptographicAgeVerificationSandbox",
|
||||||
|
"verifyHash: ${verifyHash.contentToString()}"
|
||||||
|
)
|
||||||
|
|
||||||
|
val verification = cav.proveAge(
|
||||||
|
minAllowedAge = 18,
|
||||||
|
proofHash = verifyHash,
|
||||||
|
ageHash = ageHash
|
||||||
|
)
|
||||||
|
|
||||||
|
Log.d("CryptographicAgeVerificationSandbox", "Verification result: $verification")
|
||||||
|
}) {
|
||||||
|
Text("Run Cryptographic Age Verification")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue