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 of float values. All such descriptors must be of the same length, and this length must be supplied as the second argument to the preprocess 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 a request for masks using the request.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 the tinynmc.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 the token.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 the token.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
authenticate(registration_token, authentication_token)[source]

Perform computation associated with an authentication workflow.

Parameters
  • registration_token (token) – Registration token to be used in the local computation by this node.

  • authentication_token (token) – Authentication token to be used in the local computation by this node.

Return type

modulo

class tinybio.tinybio.request(iterable=(), /)[source]

Bases: List[Tuple[int, int]]

Data structure for representing registration and authentication requests.

static registration(descriptor)[source]

Encode descriptor into a registration request.

Parameters

descriptor (Sequence[float]) – Biometric descriptor to be used for registration.

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

request

static authentication(descriptor)[source]

Encode descriptor into an authentication request.

Parameters

descriptor (Sequence[float]) – Biometric descriptor to be used for authentication.

This request can be submitted to each node to obtain masks for the descriptor.

>>> auth_descriptor = [0.1, 0.4, 0.8, 0.2]
>>> isinstance(request.authentication(auth_descriptor), request)
True
Return type

request

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

token

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

token

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 (Sequence[node]) – Collection of nodes involved in the workflow.

  • length (int) – Number of components in each descriptor list to be used in the workflow.

>>> 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).

Parameters

shares (Iterable[modulo]) – Shares that can be reconstructed into a result.

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

float