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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The output of this transformation is the protected template.

# Workflow

In this section we report the sequence diagrams are included for integrating PolyProtect in the opserations of enrolment, verification, and indentification.
In this section we report the sequence diagrams are included for integrating PolyProtect in the operations of enrolment, verification, and identification.

## Enrolment

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.nonTransitiveRClass=true
Binary file modified images/Enrolment.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 9 additions & 10 deletions images/Enrolment.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ database AuxData
database RefData


note over PolyProtect:Pre-configured parameters (with getter/setter):\n\n""private var **_OVERLAP**: Int = 2\nprivate var **_COEFFICIENTABSMAX**: Int = 100\nprivate var **_POLYNOMIALDEGREE**: Int = 7""\n\nData classes:""\n\ndata class **secretAuxDataRecord**(\nval subjectId: String,\nval coefficients: IntArray,\nval exponents: IntArray)\n\ndata class **protectedTemplateRecord**(\nval subjectId: String,\nval protectedTemplate: DoubleArray)\n""\nMethods:""\n\nfun **generateSecretAuxDataRecord**(\nsubjectId: String):\nsecretAuxDataRecord\n\nfun **transformTemplate**(\nunprotectedTemplate: DoubleArray,\nsubjectSecretAuxData: secretAuxDataRecord):\n protectedTemplateRecord\n\nfun **computeScore**(array1: DoubleArray,\narray2: DoubleArray): Double""

Unprotected Biometric System->PolyProtect:""**generateSecretAuxDataRecord**(subjectId)""
PolyProtect-->Unprotected Biometric System:""**return**\nsecretAuxDataRecord(subjectId, coefficients, exponents)""
note over PolyProtect:Pre-configured parameters (with getter/setter):\n\n""private var **_OVERLAP**: Int = 2\nprivate var **_COEFFICIENTABSMAX**: Int = 100\nprivate var **_POLYNOMIALDEGREE**: Int = 7""\n\nData classes:""\n\ndata class **AuxData**(\nval coefficients: ByteArray,\nval exponents: ByteArray)\n""\nMethods:""\n\nfun **generateAuxData**():\n AuxData\n\nfun **transformTemplate**(\nunprotectedTemplate: ByteArray,\nauxData: AuxData):\n ByteArray\n\nfun **computeSimilarityScore**(array1: ByteArray,\narray2: ByteArray):\n Double""
Unprotected Biometric System->PolyProtect:""**generateAuxData**()""
PolyProtect-->Unprotected Biometric System:""**return**\n AuxData(coefficients, exponents)""


group #2f2e7b While Loop #white [condition: check#1 == true or check#2 == true]
Expand All @@ -20,16 +19,16 @@ AuxData-->Unprotected Biometric System:<color:#blue>check#1</color>: ""true"" or
Unprotected Biometric System->AuxData:<color:#blue>check#2</color>: ""exponents"" already assigned to previously enrolled subject?
AuxData-->Unprotected Biometric System:<color:#blue>check#2</color>: ""true"" or ""false""

Unprotected Biometric System->PolyProtect:""**generateSecretAuxDataRecord**(subjectId)""
PolyProtect-->Unprotected Biometric System:""**return**\nsecretAuxDataRecord(subjectId, coefficients, exponents)""
Unprotected Biometric System->PolyProtect:""**generateAuxData**()""
PolyProtect-->Unprotected Biometric System:""**return**\n AuxData""
end

Unprotected Biometric System->AuxData:Save ""secretAuxDataRecord(subjectId, coefficients, exponents)""
Unprotected Biometric System->AuxData:Save ""AuxData""


Unprotected Biometric System->PolyProtect:""**transformTemplate**(unprotectedTemplate,\nsubjectSecretAuxData)
Unprotected Biometric System->PolyProtect:""**transformTemplate**(unprotectedTemplate, AuxData)

PolyProtect-->Unprotected Biometric System:""**return**\nprotectedTemplateRecord(subjectId, protectedTemplate)""
PolyProtect-->Unprotected Biometric System:""**return**\n ByteArray"" (protected template)


Unprotected Biometric System->RefData:Save ""protectedTemplateRecord(subjectId, protectedTemplate)""
Unprotected Biometric System->RefData:Save protected template
Binary file modified images/Identification.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 10 additions & 13 deletions images/Identification.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,27 @@ participant PolyProtect
database AuxData
database RefData


note over PolyProtect:Pre-configured parameters (with getter/setter):\n\n""private var **_OVERLAP**: Int = 2\nprivate var **_COEFFICIENTABSMAX**: Int = 100\nprivate var **_POLYNOMIALDEGREE**: Int = 7""\n\nData classes:""\n\ndata class **secretAuxDataRecord**(\nval subjectId: String,\nval coefficients: IntArray,\nval exponents: IntArray)\n\ndata class **protectedTemplateRecord**(\nval subjectId: String,\nval protectedTemplate: DoubleArray)\n""\nMethods:""\n\nfun **generateSecretAuxDataRecord**(\nsubjectId: String):\nsecretAuxDataRecord\n\nfun **transformTemplate**(\nunprotectedTemplate: DoubleArray,\nsubjectSecretAuxData: secretAuxDataRecord):\n protectedTemplateRecord\n\nfun **computeScore**(array1: DoubleArray,\narray2: DoubleArray): Double""


note over Unprotected Biometric System: Create list\n""identificationList""\nfor identification\nscores
note over PolyProtect:Pre-configured parameters (with getter/setter):\n\n""private var **_OVERLAP**: Int = 2\nprivate var **_COEFFICIENTABSMAX**: Int = 100\nprivate var **_POLYNOMIALDEGREE**: Int = 7""\n\nData classes:""\n\ndata class **AuxData**(\nval coefficients: ByteArray,\nval exponents: ByteArray)\n""\nMethods:""\n\nfun **generateAuxData**():\n AuxData\n\nfun **transformTemplate**(\nunprotectedTemplate: ByteArray,\nauxData: AuxData):\n ByteArray\n\nfun **computeSimilarityScore**(array1: ByteArray,\narray2: ByteArray):\n Double""
note over Unprotected Biometric System: Create empty list\n""identificationList""\nfor identification\nscores

group #2f2e7b For Loop #white [condition: for subjectId in enrolledSubjectIds]

Unprotected Biometric System->AuxData: Given the ""subjectId"" to be verified, retrieve the corresponding ""secretAuxDataRecord""
Unprotected Biometric System->AuxData: Given the ""subjectId"" to be compared, retrieve the corresponding ""AuxData""

AuxData-->Unprotected Biometric System: **return**\n""secretAuxDataRecord(subjectId, coefficients, exponents)""
AuxData-->Unprotected Biometric System: **return**\n""AuxData""

Unprotected Biometric System->PolyProtect:""**transformTemplate**(unprotectedQueryTemplate,\nsubjectSecretAuxData)
Unprotected Biometric System->PolyProtect:""**transformTemplate**(unprotectedQueryTemplate, AuxData)

PolyProtect-->Unprotected Biometric System:""**return**\nprotectedTemplateRecord(subjectId, protectedQueryTemplate)""
PolyProtect-->Unprotected Biometric System:""**return**\nByteArray"" (protected query template)

Unprotected Biometric System->RefData: Given the ""subjectId"" to be verified, retrieve the corresponding ""protectedTemplateRecord""
Unprotected Biometric System->RefData: Given the ""subjectId"" to be compared, retrieve the corresponding protected reference template

RefData-->Unprotected Biometric System: **return**\n""protectedTemplateRecord(subjectId, protectedTemplate)""
RefData-->Unprotected Biometric System: **return**\n""ByteArray"" (protected reference template)


Unprotected Biometric System->PolyProtect:""**computeScore**(protectedQueryTemplate,\nprotectedReferenceTemplate)
Unprotected Biometric System->PolyProtect:""**computeSimilarityScore**(ByteArray, ByteArray)""\n (corresponding to protected query and reference templates

PolyProtect-->Unprotected Biometric System:""**return**\nDouble""
PolyProtect-->Unprotected Biometric System:""**return**\nDouble"" (score)


note over Unprotected Biometric System: append\n""[subjectId, score]""\nto ""identificationList""
Expand Down
Binary file modified images/Verification.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 7 additions & 8 deletions images/Verification.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,21 @@ database AuxData
database RefData


note over PolyProtect:Pre-configured parameters (with getter/setter):\n\n""private var **_OVERLAP**: Int = 2\nprivate var **_COEFFICIENTABSMAX**: Int = 100\nprivate var **_POLYNOMIALDEGREE**: Int = 7""\n\nData classes:""\n\ndata class **secretAuxDataRecord**(\nval subjectId: String,\nval coefficients: IntArray,\nval exponents: IntArray)\n\ndata class **protectedTemplateRecord**(\nval subjectId: String,\nval protectedTemplate: DoubleArray)\n""\nMethods:""\n\nfun **generateSecretAuxDataRecord**(\nsubjectId: String):\nsecretAuxDataRecord\n\nfun **transformTemplate**(\nunprotectedTemplate: DoubleArray,\nsubjectSecretAuxData: secretAuxDataRecord):\n protectedTemplateRecord\n\nfun **computeScore**(array1: DoubleArray,\narray2: DoubleArray): Double""
note over PolyProtect:Pre-configured parameters (with getter/setter):\n\n""private var **_OVERLAP**: Int = 2\nprivate var **_COEFFICIENTABSMAX**: Int = 100\nprivate var **_POLYNOMIALDEGREE**: Int = 7""\n\nData classes:""\n\ndata class **AuxData**(\nval coefficients: ByteArray,\nval exponents: ByteArray)\n""\nMethods:""\n\nfun **generateAuxData**():\n AuxData\n\nfun **transformTemplate**(\nunprotectedTemplate: ByteArray,\nauxData: AuxData):\n ByteArray\n\nfun **computeSimilarityScore**(array1: ByteArray,\narray2: ByteArray):\n Double""

Unprotected Biometric System->AuxData: Given the ""subjectId"" to be verified, retrieve the corresponding ""secretAuxDataRecord"".
Unprotected Biometric System->AuxData: Given the ""subjectId"" to be verified,\n retrieve the corresponding ""AuxData"".

AuxData-->Unprotected Biometric System: **return**\n""secretAuxDataRecord(subjectId, coefficients, exponents)""
AuxData-->Unprotected Biometric System: **return**\n""AuxData""


Unprotected Biometric System->PolyProtect:""**transformTemplate**(unprotectedQueryTemplate,\nsubjectSecretAuxData)
Unprotected Biometric System->PolyProtect:""**transformTemplate**(unprotectedQueryTemplate,\nAuxData)

PolyProtect-->Unprotected Biometric System:""**return**\nprotectedTemplateRecord(subjectId, protectedQueryTemplate)""
PolyProtect-->Unprotected Biometric System:""**return** ByteArray"" (protected query template)


Unprotected Biometric System->RefData: Given the ""subjectId"" to be verified, retrieve the corresponding ""protectedTemplateRecord"".

RefData-->Unprotected Biometric System: **return**\n""protectedTemplateRecord(subjectId, protectedTemplate)""
Unprotected Biometric System->RefData: Given the ""subjectId"" to be verified,\nretrieve the corresponding\nprotected reference template.

RefData-->Unprotected Biometric System: **return**\n""ByteArray"" (protected reference template)

Unprotected Biometric System->PolyProtect:""**computeScore**(protectedQueryTemplate,\nprotectedReferenceTemplate)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ package com.simprints.biometrics.polyprotect
* @param exponents of a polynomial function
*/
data class AuxData(
val coefficients: IntArray,
val exponents: IntArray,
val coefficients: ByteArray,
val exponents: ByteArray,
)
31 changes: 18 additions & 13 deletions src/main/kotlin/com/simprints/biometrics/polyprotect/PolyProtect.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,39 +37,44 @@ class PolyProtect(
*
* **NOTE**: The size of the protected templates depends on `polynomialDegree` and `overlap`.
*
* @param unprotectedTemplate
* @param unprotectedTemplateByteArray
* @param auxData a set of coefficients and exponents associated with specific biometric record
*
* @return protected template
*/
fun transformTemplate(
unprotectedTemplate: DoubleArray,
unprotectedTemplate: ByteArray,
auxData: AuxData
): DoubleArray {
): ByteArray {
val (coefficients, exponents) = auxData // For convenience
require(exponents.size == coefficients.size) { "Auxiliary data sizes must be equal." }
require(exponents.size == polynomialDegree) {
require(Utils.byteArrayToIntArray(exponents).size == polynomialDegree) {
"Auxiliary data sizes must be equal to polynomial degree."
}

val stepSize = exponents.size - overlap
// Converting from ByteArray
val unprotectedTemplateDoubleArray = Utils.byteArrayToDoubleArray(unprotectedTemplate)
val coefficientsIntArray = Utils.byteArrayToIntArray(coefficients)
val exponentsIntArray = Utils.byteArrayToIntArray(exponents)

val stepSize = exponentsIntArray.size - overlap

val protectedTemplate = mutableListOf<Double>()
for (templateIndex in 0..(unprotectedTemplate.lastIndex - overlap) step stepSize) {
val s = exponents.indices.map { i ->
for (templateIndex in 0..(unprotectedTemplateDoubleArray.lastIndex - overlap) step stepSize) {
val s = exponentsIntArray.indices.map { i ->
// If the target element is out of bounds, consider it 0 since 0^n==0
// This would be the same as padding the provided array up to certain size
if (templateIndex + i > unprotectedTemplate.lastIndex) {
if (templateIndex + i > unprotectedTemplateDoubleArray.lastIndex) {
0.0
} else {
unprotectedTemplate[templateIndex + i]
.pow(exponents[i])
.times(coefficients[i])
unprotectedTemplateDoubleArray[templateIndex + i]
.pow(exponentsIntArray[i])
.times(coefficientsIntArray[i])
}
}.sum()
protectedTemplate.add(s)
}
return protectedTemplate.toDoubleArray()
return Utils.doubleArrayToByteArray(protectedTemplate.toDoubleArray())
}

/**
Expand All @@ -90,7 +95,7 @@ class PolyProtect(
// Shuffle the list randomly
val exponents = exponentRange.shuffled().toIntArray()

return AuxData(coefficients, exponents)
return AuxData(Utils.intArrayToByteArray(coefficients), Utils.intArrayToByteArray(exponents))
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ import kotlin.math.sqrt
* @return a value in in the `[0,1]` range
*/
fun computeSimilarityScore(
array1: DoubleArray,
array2: DoubleArray,
array1ByteArray: ByteArray,
array2ByteArray: ByteArray,
): Double {
require(array1.size == array2.size) { "Arrays must be of the same size." }
require(array1ByteArray.size == array2ByteArray.size) { "Arrays must be of the same size." }

val array1 = Utils.byteArrayToDoubleArray(array1ByteArray)
val array2 = Utils.byteArrayToDoubleArray(array2ByteArray)

// Calculate the dot product of array1 and array2
val dotProduct = array1.zip(array2) { x, y -> x * y }.sum()
Expand Down
52 changes: 52 additions & 0 deletions src/main/kotlin/com/simprints/biometrics/polyprotect/Utils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import java.nio.ByteBuffer
import java.nio.ByteOrder

object Utils {
/**
* Converts a DoubleArray to a ByteArray.
*
* @param doubleArray The DoubleArray to convert.
* @return A ByteArray representing the DoubleArray.
*/
fun doubleArrayToByteArray(doubleArray: DoubleArray): ByteArray {
val byteBuffer = ByteBuffer.allocate(doubleArray.size * 8).order(ByteOrder.nativeOrder())
byteBuffer.asDoubleBuffer().put(doubleArray)
return byteBuffer.array()
}

/**
* Converts a ByteArray back to a DoubleArray.
*
* @param byteArray The ByteArray to convert.
* @return A DoubleArray reconstructed from the ByteArray.
*/
fun byteArrayToDoubleArray(byteArray: ByteArray): DoubleArray {
val byteBuffer = ByteBuffer.wrap(byteArray).order(ByteOrder.nativeOrder())
val doubleBuffer = byteBuffer.asDoubleBuffer()
return DoubleArray(doubleBuffer.remaining()).apply { doubleBuffer.get(this) }
}

/**
* Converts an IntArray to a ByteArray.
*
* @param intArray The IntArray to convert.
* @return A ByteArray representing the IntArray.
*/
fun intArrayToByteArray(intArray: IntArray): ByteArray {
val byteBuffer = ByteBuffer.allocate(intArray.size * 4).order(ByteOrder.nativeOrder())
byteBuffer.asIntBuffer().put(intArray)
return byteBuffer.array()
}

/**
* Converts a ByteArray back to an IntArray.
*
* @param byteArray The ByteArray to convert.
* @return An IntArray reconstructed from the ByteArray.
*/
fun byteArrayToIntArray(byteArray: ByteArray): IntArray {
val byteBuffer = ByteBuffer.wrap(byteArray).order(ByteOrder.nativeOrder())
val intBuffer = byteBuffer.asIntBuffer()
return IntArray(intBuffer.remaining()).apply { intBuffer.get(this) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ class ComputeSimilarityScoreTest {
@Test
fun `similarity between two protected templates should be between 0 and 1`() {
// Creation of two unprotected templates (randomly generated)
val unprotectedTemplate1 = DoubleArray(512) { Random.nextDouble() - 0.5 }
val unprotectedTemplate2 = DoubleArray(512) { Random.nextDouble() - 0.5 }
val unprotectedTemplateDoubleArray1 = DoubleArray(512) { Random.nextDouble() - 0.5 }
val unprotectedTemplateDoubleArray2 = DoubleArray(512) { Random.nextDouble() - 0.5 }

val unprotectedTemplate1 = Utils.doubleArrayToByteArray(unprotectedTemplateDoubleArray1)
val unprotectedTemplate2 = Utils.doubleArrayToByteArray(unprotectedTemplateDoubleArray2)


// Custom parameters
val polyProtect = PolyProtect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ class PolyProtectUnitTest {
val secrets1 = polyProtect.generateAuxData()

assertEquals(
"Exponents count is same as provided polynomial degree", 7, secrets1.exponents.size
"Exponents count is same as provided polynomial degree", 7, Utils.byteArrayToIntArray(secrets1.exponents).size
)
assertTrue(
"The exponents should include values from 1 to PolyProtect.POLYNOMIALDEGREE.",
secrets1.exponents.sortedArray().contentEquals(IntArray(7) { it + 1 })
Utils.byteArrayToIntArray(secrets1.exponents).sortedArray().contentEquals(IntArray(7) { it + 1 })
)

assertEquals(
"Coefficient count is same as provided polynomial degree", 7, secrets1.coefficients.size
"Coefficient count is same as provided polynomial degree", 7, Utils.byteArrayToIntArray(secrets1.coefficients).size
)
assertTrue("The coefficient values should not be outside the allowed range",
secrets1.coefficients.all { it in -100..100 })
assertTrue("The coefficient values must not be 0", secrets1.coefficients.none { it == 0 })
Utils.byteArrayToIntArray(secrets1.coefficients).all { it in -100..100 })
assertTrue("The coefficient values must not be 0", Utils.byteArrayToIntArray(secrets1.coefficients).none { it == 0 })

}

Expand All @@ -45,7 +45,7 @@ class PolyProtectUnitTest {
val exponents = intArrayOf(1, 5, 3, 4, 6, 2, 7)

val subjectSecretAuxData = AuxData(
coefficients = coefficients, exponents = exponents
coefficients = Utils.intArrayToByteArray(coefficients), exponents = Utils.intArrayToByteArray(exponents)
)

// Custom parameters (relevant to the generation of secret auxiliary data record)
Expand All @@ -56,9 +56,12 @@ class PolyProtectUnitTest {
)

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

// PolyProtect trandformation: the unprotected templates are transformed using the
// Transformation of unprotected template into ByteArray
val unprotectedTemplate = Utils.doubleArrayToByteArray(unprotectedTemplateDoubleArray)

// PolyProtect transformation: the unprotected templates are transformed using the
// subject-specific secret auxiliary data
val protectedTemplate = polyProtect.transformTemplate(
unprotectedTemplate = unprotectedTemplate, auxData = subjectSecretAuxData
Expand Down
Loading