nthcommunity module

Python library for the nth.community secure, privacy-preserving data collaboration service platform and API.

An end-to-end example is presented in the documentation for the recipient class.

class nthcommunity.nthcommunity.collaboration

Bases: dict

Base class for tree data structure representing a data collaboration. Consult definitions of derived classes such as intersection and table for more details, and find in-context usage examples in the documentation for the recipient class.

static from_json(argument: Union[str, dict]) nthcommunity.nthcommunity.collaboration

Parse a dictionary or JSON string into an instance of this class. Find usage examples in the documentation for the recipient class.

to_json(*args, **kwargs) str

Convert an instance of this class into a JSON string. This method is a wrapper for the json.dumps method found in the built-in json library. Find usage examples in the documentation for the recipient class.

class nthcommunity.nthcommunity.recipient

Bases: object

A collaboration begins with a recipient party represented by a recipient object. The recipient defines a collaboration workflow, generates keys for individual contributors, accepts encrypted contributions, and computes the results in concert with the nth.community service platform.

>>> r = recipient()

Individual contributor objects represent and uniquely identify individual contributors.

>>> c_a = contributor()
>>> c_b = contributor()

The contributor class is derived from dict and contains a value under the 'identifier' key that corresponds to the unique identifier for that contributor. This value can also be retrieved using the contributor.identifier method.

>>> 'identifier' in c_a
True
>>> c_a.identifier() is not None
True

A collaboration is a tree-like data structure that defines how the overall result of the collaboration is computed. Each leaf node of the data structure must indicate which contributor must supply the encrypted data corresponding to that node. The internal, non-leaf nodes represent data operations such as count, summation, and intersection.

>>> w = count(intersection(table(contributor=c_a), table(contributor=c_b)))

The recipient can use the recipient.generate method (which internally leverages the nth.community service platform) to create a dictionary that maps each contributor identifier to its respective contribution key for that specific collaboration workflow.

>>> id_to_key = r.generate(w)

Each of these individual keys id_to_key[c_a.identifier()] and id_to_key[c_b.identifier()] can be converted to JSON using the collaboration.to_json method and delivered to their corresponding contributor.

>>> key_a_json = id_to_key[c_a.identifier()].to_json()
>>> key_b_json = id_to_key[c_b.identifier()].to_json()

Contributors can parse the JSON strings using collaboration.from_json.

>>> key_a = collaboration.from_json(key_a_json)
>>> key_b = collaboration.from_json(key_b_json)

Each contributor can then use the contributor.encrypt method to encrypt their data contribution using their key. After validating the contribution key, this method does not perform any external communications and encrypts the input data entirely within the host environment belonging to the contributor. In particular, it does not communicate with the nth.community service platform or the recipient during this process.

>>> table_a = [['a'], ['b'], ['c'], ['d']]
>>> enc_a = c_a.encrypt(key_a, table_a)
>>> table_b = [['b'], ['c'], ['d'], ['e']]
>>> enc_b = c_b.encrypt(key_b, table_b)

Because encrypted contributions are also collaboration objects, they can be easily converted to and from JSON strings. The recipient can then use the recipient.evaluate method (which again internally leverages the nth.community service platform) to evaluate the encrypted contributions and obtain a result.

>>> result = r.evaluate({c_a.identifier(): enc_a, c_b.identifier(): enc_b})
>>> result["value"]
3
generate(collaboration) dict

Submit a collaboration via the nth.community service platform API to receive the set of contributor keys that can be distributed to contributors. Find an in-context usage example in the documentation for the recipient class.

evaluate(collaborations) nthcommunity.nthcommunity.collaboration

Evaluate a collaboration workflow instantiated with encrypted data contributions (represented as a dictionary that maps each contributor’s identifier to that contributor’s encrypted contribution) by submitting it to the nth.community service platform. Find an in-context usage example in the documentation for the recipient class.

class nthcommunity.nthcommunity.contributor(identifier=None)

Bases: dict

Data structure and methods for an individual data contributor within a collaboration. A contributor receives a collaboration key from a recipient and encrypts their data contribution using that key.

>>> (r, c_a, c_b) = (recipient(), contributor(), contributor())
>>> w = count(intersection(table(contributor=c_a), table(contributor=c_b)))
>>> id_to_key = r.generate(w)

Each of the individual keys in id_to_key.values() can be delivered to their corresponding contributor. Each contributor can then use the key to encrypt their data contribution via the contributor.encrypt method, as shown below.

>>> id_a = c_a.identifier()
>>> table_a = [['a'], ['b'], ['c'], ['d']]
>>> table_a_encrypted = c_a.encrypt(id_to_key[id_a], table_a)
identifier() str

Return this contributor’s unique identifier.

>>> c = contributor()
>>> isinstance(c.identifier(), str)
True
static from_json(argument: Union[str, dict]) nthcommunity.nthcommunity.contributor

Parse a dictionary or JSON string into an instance of this class.

>>> s = '{"type": "contributor", "identifier": "b1a63caf"}'
>>> isinstance(contributor.from_json(s), contributor)
True
to_json(*args, **kwargs) str

Convert an instance of this class into a JSON string. This method is a wrapper for the json.dumps method found in the built-in json library.

>>> c = contributor('b1a63caf-a549-429e-8ed0-44cd5fbb0eeb')
>>> c.to_json()
'{"type": "contributor", "identifier": "b1a63caf-a549-429e-8ed0-44cd5fbb0eeb"}'
validate(collaboration) bool

Validate the certificate within a contribution key obtained from a recipient by submitting it to the nth.community service platform. The contributor.encrypt method automatically invokes this method before encrypting a contribution.

>>> (r, c_a, c_b) = (recipient(), contributor(), contributor())
>>> w = count(intersection(table(contributor=c_a), table(contributor=c_b)))
>>> key_a = r.generate(w)[c_a.identifier()]
>>> c_a.validate(key_a)
True
encrypt(collaboration, contribution) nthcommunity.nthcommunity.collaboration

Encrypt a data set as a contribution to a collaboration. Find an in-context usage example in the documentation for the recipient class.

>>> (r, c_a, c_b) = (recipient(), contributor(), contributor())
>>> w = count(intersection(table(contributor=c_a), table(contributor=c_b)))
>>> key_a = r.generate(w)[c_a.identifier()]
>>> table_a = [['a'], ['b'], ['c'], ['d']]
>>> enc_a = c_a.encrypt(key_a, table_a)

After validating the contribution key, this method does not perform any external communications and encrypts the input data entirely within the host environment belonging to the contributor. In particular, it does not communicate with the nth.community service platform or the recipient during this process.

class nthcommunity.nthcommunity.count(*arguments)

Bases: nthcommunity.nthcommunity.collaboration

Collaboration tree node for the count operation. A count operation can be applied to a single intersection collaboration.

>>> (c_a, c_b) = (contributor(), contributor())
>>> w = count(intersection(table(contributor=c_a), table(contributor=c_b)))

Any attempt to apply a count operation to a collaboration workflow that is not compatible with a count operation raises an exception.

>>> count(integer(123))
Traceback (most recent call last):
  ...
TypeError: count operation must be applied to a single intersection collaboration
class nthcommunity.nthcommunity.summation(*arguments)

Bases: nthcommunity.nthcommunity.collaboration

Collaboration tree node for the summation operation. A summation operation can be applied to two or more contributors’ integer contributions.

>>> (c_a, c_b) = (contributor(), contributor())
>>> w = summation(integer(contributor=c_a), integer(contributor=c_b))

Any attempt to apply a summation operation to a collaboration workflow that is not compatible with a summation operation raises an exception.

>>> summation(integer(123))
Traceback (most recent call last):
  ...
TypeError: summation operation must be applied to two or more integers
class nthcommunity.nthcommunity.intersection(*arguments)

Bases: nthcommunity.nthcommunity.collaboration

Collaboration tree node for the intersection operation. An intersection operation can be applied to two or more contributors’ table contributions.

>>> (c_a, c_b) = (contributor(), contributor())
>>> w = intersection(table(contributor=c_a), table(contributor=c_b))

Any attempt to apply an intersection operation to a collaboration workflow that is not compatible with an intersection operation raises an exception.

>>> intersection(table())
Traceback (most recent call last):
  ...
TypeError: intersection operation must be applied to two or more tables
class nthcommunity.nthcommunity.integer(value=None, contributor=None)

Bases: nthcommunity.nthcommunity.collaboration

Collaboration tree leaf node for a contributed integer value within a collaboration tree data structure. Only 32-bit non-negative integers are supported.

>>> c = contributor()
>>> w = integer(value=123, contributor=c)

Any attempt to construct an invalid integer contribution raises an exception.

>>> integer(-123)
Traceback (most recent call last):
  ...
ValueError: integer value must be a non-negative 32-bit integer
class nthcommunity.nthcommunity.table(value=None, contributor=None, limit=None)

Bases: nthcommunity.nthcommunity.collaboration

Collaboration tree leaf node for a contributed data table within a collaboration tree data structure. A contributed table must be a list of rows, and each row must a single-element list that contains exactly one string.

>>> c = contributor()
>>> w = table(value=[['a'], ['b'], ['c']], contributor=c)

Any attempt to construct a data table contribution that is invalid or that exceeds size limits raises an exception.

>>> table(['a', 'b', 'c'])
Traceback (most recent call last):
  ...
ValueError: table value must be a list of single-item lists, each containing a string
>>> table([['a']] * 1001)
Traceback (most recent call last):
  ...
ValueError: table length exceeds maximum of 1000
>>> table([['a'  * 257]])
Traceback (most recent call last):
  ...
ValueError: table field value length exceeds maximum of 256
exception nthcommunity.nthcommunity.ServiceError

Bases: RuntimeError

Exception indicating that the service platform responded to an API request but indicated an error has occurred service-side (due to either an improperly configured service instance or an improper request).

>>> (c_a, c_b) = (contributor(), contributor())
>>> w = count(intersection(table(contributor=c_a), table(contributor=c_b)))
>>> del w["type"]
>>> try:
...     recipient().generate(w)
... except ServiceError as e:
...     print(e)
service did not return a valid response