tinybio module
Minimal pure-Python library that implements a basic version of a secure decentralized biometric authentication functionality via a secure multi-party computation protocol.
- class tinybio.tinybio.node[source]
Bases:
tinynmc.tinynmc.node
Data structure for maintaining the information associated with a node and performing node operations.
Suppose that a workflows is supported by three nodes (parties performing the decentralized registration and authentication functions). The
node
objects would be instantiated locally by each of these three parties.>>> nodes = [node(), node(), node()]
The preprocessing phase that the nodes must execute can be simulated using the
preprocess
function. It is assumed that biometric descriptors used for registration and authentication are represented as lists offloat
values. All such descriptors must be of the same length, and this length must be supplied as the second argument to thepreprocess
function.>>> preprocess(nodes, length=4)
It is then possible for a client to register itself by obtaining a registration
token
. Suppose the client has a biometric descriptor represented as a vector of floating point values. The client can create arequest
for masks using therequest.registration
method.>>> reg_descriptor = [0.5, 0.3, 0.7, 0.1] >>> reg_request = request.registration(reg_descriptor)
The client can deliver the request to each node, at which point that node can locally use its
masks
method (inherited from thetinynmc.tinynmc.node
class) to generate masks that can be returned to the requesting client.>>> reg_masks = [node.masks(reg_request) for node in nodes]
The client can then generate locally a registration
token
(i.e., a masked descriptor) via thetoken.registration
method.>>> reg_token = token.registration(reg_masks, reg_descriptor)
At any later point, it is possible to perform an authentication workflow. Masks for the authentication descriptor can be requested via a process that parallels the one for registration (in this case using the
request.authentication
method).>>> auth_descriptor = [0.1, 0.4, 0.8, 0.2] >>> auth_request = request.authentication(auth_descriptor) >>> auth_masks = [node.masks(auth_request) for node in nodes]
Given the masks for the authentication descriptor, the authentication
token
(i.e., a masked descriptor) can be generated locally by the client via thetoken.authentication
method.>>> auth_token = token.authentication(auth_masks, auth_descriptor)
Finally, the client can broadcast its original registration token together with its authentication token. Each node can then compute locally its share of the authentication result. These shares can be reconstructed by the validating party using the
reveal
function to obtain the Euclidean distance between the registration and authentication descriptors.>>> shares = [node.authenticate(reg_token, auth_token) for node in nodes] >>> result = reveal(shares)
The tests below confirm that the computed result is indeed the Euclidean distance.
>>> abs(result - 0.43) <= 0.05 # Use comparison for floating point value. True >>> abs(result - math.sqrt(sum( ... (x - y) ** 2 ... for (x, y) in zip(reg_descriptor, auth_descriptor) ... ))) <= 0.05 True
- class tinybio.tinybio.request(iterable=(), /)[source]
-
Data structure for representing registration and authentication requests.
- static registration(descriptor)[source]
Encode descriptor into a registration request.
This request can be submitted to each node to obtain masks for the descriptor.
>>> reg_descriptor = [0.5, 0.3, 0.7, 0.1] >>> isinstance(request.registration(reg_descriptor), request) True
- Return type
- class tinybio.tinybio.token[source]
Bases:
Dict
[Tuple
[int
,int
],modulo.modulo.modulo
]Data structure for representing registration and authentication tokens.
- static registration(masks, descriptor)[source]
Mask descriptor and create a registration token.
- Parameters
Suppose masks have already been obtained from the nodes via the steps below.
>>> nodes = [node(), node(), node()] >>> preprocess(nodes, 4) >>> descriptor = [0.5, 0.3, 0.7, 0.1] >>> masks = [node.masks(request.registration(descriptor)) for node in nodes]
This method can be used to mask the original descriptor (in preparation for broadcasting it to the nodes).
>>> isinstance(token.registration(masks, descriptor), token) True
- Return type
- static authentication(masks, descriptor)[source]
Mask descriptor and create an authentication token.
- Parameters
Suppose masks have already been obtained from the nodes via the steps below.
>>> nodes = [node(), node(), node()] >>> preprocess(nodes, 4) >>> descriptor = [0.5, 0.3, 0.7, 0.1] >>> masks = [node.masks(request.authentication(descriptor)) for node in nodes]
This method can be used to mask the original descriptor (in preparation for broadcasting it to the nodes).
>>> isinstance(token.authentication(masks, descriptor), token) True
- Return type
- tinybio.tinybio.preprocess(nodes, length)[source]
Simulate a preprocessing phase among the collection of nodes for a workflow that supports registration and authentication descriptor vectors of the specified length.
- Parameters
>>> nodes = [node(), node(), node()] >>> preprocess(nodes, length=4)
- tinybio.tinybio.reveal(shares)[source]
Reconstruct the result of the overall workflow from its shares and convert it into a meaningful output (i.e., the Euclidean distance between the registration descriptor and the authentication descriptor).
Suppose the shares below are returned from the three nodes in a workflow.
>>> p = 4215209819 >>> shares = [modulo(2042458237, p), modulo(1046840547, p), modulo(1125923365, p)]
This method converts a collection of secret shares from the nodes into a floating point value representing the Euclidean distance between the registration and authentication descriptors.
>>> abs(reveal(shares) - 0.43) <= 0.05 # Use comparison for floating point value. True
- Return type