Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
.gradle
build
local.properties
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ In this section we provide a description of the ```PolyProtect``` class.

**NOTE 2**: The size of the protected templates depends on ```_POLYNOMIALDEGREE``` and ```_OVERLAP```.


# Workflow

In this section we report the sequence diagrams are included for integrating PolyProtect in the opserations of enrolment, verification, and indentification.
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {

val projectGroupId = "com.simprints"
val projectArtifactId = "biometrics_simpolyprotect"
val projectVersion = "0.0.2-SNAPSHOT"
val projectVersion = "2024.4.0"

android {
namespace = "$projectGroupId.$projectArtifactId"
Expand Down
2 changes: 1 addition & 1 deletion src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<manifest/>
<manifest package="com.simprints.biometrics_simpolyprotect" />
8 changes: 6 additions & 2 deletions src/main/kotlin/biometrics_simpolyprotect/PolyProtect.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,14 @@ class PolyProtect {
}

fun transformTemplate(unprotectedTemplate: DoubleArray,
subjectSecretAuxData: secretAuxDataRecord
subjectSecretAuxData: secretAuxDataRecord
): protectedTemplateRecord {

val (_, c, e) = subjectSecretAuxData // For convenience
assert(e.size == c.size) { "Auxiliary data sizes must be equal." }

assert(e.size == POLYNOMIALDEGREE) { "Auxiliary data sizes must be equal to PolyProtect.POLYNOMIALDEGREE." }

val stepSize = e.size - OVERLAP
val eIndices = e.indices

Expand Down Expand Up @@ -108,7 +110,9 @@ class PolyProtect {
// Calculate cosine similarity
val cosineSimilarity = dotProduct / (magnitudeA * magnitudeB)
// Calculate cosine distance
return (2.0-1.0 * cosineSimilarity)/2
val cosineDistance = 1 - cosineSimilarity

return (2.0-1.0*cosineDistance)/2
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.simprints.biometrics_simpolyprotect
import PolyProtect
import org.junit.Test
import kotlin.random.Random


class PolyProtectIntegrationTest {
@Test

fun `PolyProtect operations in sequence`() {

val subjectId1 = "myUniqueId1"
val subjectId2 = "myUniqueId2"

// Creation of two unprotected templates (randomly generated)
val unprotectedTemplate1 = DoubleArray(512) { Random.nextDouble() - 0.5 }
val unprotectedTemplate2 = DoubleArray(512) { Random.nextDouble() - 0.5 }

val polynomialDegree = 7
val coefficientAbsMax = 100
val overlap = 2

assert((polynomialDegree <= 14) and (polynomialDegree >= 5))
{"Assertion failed: the degree of the polynomial should be >=5 and <=14."}

assert((coefficientAbsMax > 0))
{"Assertion failed: the maximum coefficient value should be a positive integer."}

assert((overlap >= 0) and (overlap <= polynomialDegree-1))
{"Assertion failed: the overlap value should be >=0 and <= polynomial degree - 1."}

// Custom parameters
PolyProtect.POLYNOMIALDEGREE = polynomialDegree
PolyProtect.COEFFICIENTABSMAX = coefficientAbsMax
PolyProtect.OVERLAP = overlap

// Generation of subject-specific secret parameters (auxiliary data)
val secrets1 = PolyProtect.generateSecretAuxDataRecord(subjectId = subjectId1)
val secrets2 = PolyProtect.generateSecretAuxDataRecord(subjectId = subjectId2)

/*
PolyProtect tranformation: the unprotected templates are transformed using the
subject-specific secret auxiliary data
*/
val protectedRecord1 = PolyProtect.transformTemplate(unprotectedTemplate = unprotectedTemplate1,
subjectSecretAuxData = secrets1)
val protectedRecord2 = PolyProtect.transformTemplate(unprotectedTemplate = unprotectedTemplate2,
subjectSecretAuxData = secrets2)

// Score in the [0, 1] range based on cosine similarity: 1 = perfect match
val score = PolyProtect.computeScore(protectedRecord1.protectedTemplate,
protectedRecord2.protectedTemplate)

assert(score in 0.0..1.0) { "Value $score should be between 0 and 1." }

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.simprints.biometrics_simpolyprotect
import PolyProtect
import org.junit.Test
import kotlin.random.Random


class PolyProtectUnitTest {

@Test
fun `test generate secret auxiliary data record`() {

val subjectId1 = "myUniqueId1"

// Custom parameters (relevant to the generation of secret auxiliary data record)
PolyProtect.POLYNOMIALDEGREE = 7
PolyProtect.COEFFICIENTABSMAX = 100

// Generation of subject-specific secret parameters (auxiliary data)
val secrets1 = PolyProtect.generateSecretAuxDataRecord(subjectId = subjectId1)

assert(secrets1::class.simpleName == "secretAuxDataRecord")
{"Secrets should be objects of the secretAuxDataRecord class."}
assert(secrets1.subjectId::class.simpleName == "String")
{"The subjectId should be a String."}
assert(secrets1.coefficients::class.simpleName == "IntArray")
{"The coefficients should be an IntArray."}
assert(secrets1.exponents::class.simpleName == "IntArray")
{"The exponents should be an IntArray."}
}

@Test
fun `test transform a template`() {

val subjectId = "myUniqueId"

// Dummy coefficients
val coefficients = intArrayOf(18, -26, 30, 4, 59, 10, -91)

// Check that all elements are within the appropriate range.
assert(coefficients.all { it in -PolyProtect.COEFFICIENTABSMAX..PolyProtect.COEFFICIENTABSMAX })
{ "The coefficient values should not be outside the allowed range." }

// Check that the array does not contain 0
assert(coefficients.none { it == 0 })
{ "The coefficient values must not be 0." }

// Dummy exponents
val exponents = intArrayOf(1, 5, 3, 4, 6, 2, 7)

assert(exponents.sortedArray().contentEquals(IntArray(exponents.size) { it + 1 }))
{ "The exponents should include values from 1 to PolyProtect.POLYNOMIALDEGREE." }

val subjectSecretAuxData = PolyProtect.secretAuxDataRecord(subjectId = subjectId,
coefficients = coefficients,
exponents = exponents)

val overlapValue = 2

assert((0 < overlapValue) and (overlapValue < PolyProtect.POLYNOMIALDEGREE))
{ "The overlap value should be >=0 and <= polynomial degree - 1." }

// Custom parameters (relevant to the generation of secret auxiliary data record)
PolyProtect.OVERLAP = overlapValue

// Creation of two unprotected templates (randomly generated)
val unprotectedTemplate = DoubleArray(512) { Random.nextDouble() - 0.5 }

/*
PolyProtect tranformation: the unprotected templates are transformed using the
subject-specific secret auxiliary data
*/
val protectedRecord = PolyProtect.transformTemplate(unprotectedTemplate = unprotectedTemplate,
subjectSecretAuxData = subjectSecretAuxData)

assert(protectedRecord.subjectId::class.simpleName == "String")
{"The coefficients should be an IntArray."}

assert(protectedRecord.protectedTemplate::class.simpleName == "DoubleArray")
{"The coefficients should be an IntArray."}

}

@Test
fun `test compute scores`() {

val randomArray1 = DoubleArray(512) { Random.nextDouble() - 0.5 }
val randomArray2 = DoubleArray(512) { Random.nextDouble() - 0.5 }

assert(randomArray1.size == randomArray2.size)
{ "The arrays should have the same size." }

val score = PolyProtect.computeScore(randomArray1, randomArray2)

assert(score in 0.0..1.0) { "Value $score should be between 0 and 1." }

}

}