-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from hpicrypto/update/readme
Update/readme
- Loading branch information
Showing
4 changed files
with
169 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,150 @@ | ||
# Proof of Knowledge, Stateful Hash Object | ||
|
||
Python implementation of [poksho](https://github.com/signalapp/libsignal/tree/f71e1c6693486cb082124ba9c929d88f2193f585/rust/poksho). | ||
A python implementation for Non-Interactive Zero-Knowledge Proofs (NIZK) of | ||
Arbitrary Linear Relations and | ||
[Stateful Hash Objects](https://github.com/noiseprotocol/sho_spec/blob/master/sho.md). | ||
|
||
## Disclaimer | ||
|
||
This module was developed as part of the 2022/23 *Current Topics in Group Messaging* seminar at the | ||
[Hasso-Plattner-Institute (HPI)](https://hpi.de) trying to reproduce the Signal Private Group system described | ||
by the paper ["The Signal Private Group System and Anonymous Credentials Supporting Efficient Verifiable Encryption" by | ||
Chase et al.](https://eprint.iacr.org/2019/1416.pdf) Therefore, it is supposed to solely fulfill academic purposes. | ||
|
||
**THE AUTHORS DO NOT ASSUME RESPONSIBILITY FOR THE CORRECTNESS OF THE PERFORMED CRYPTOGRAPHIC OPERATIONS. | ||
THERE WAS NO REVIEW PERFORMED BY AN EXPERT. | ||
DO NOT USE THIS PROJECT IN A PRODUCTION ENVIRONMENT.** | ||
|
||
## Installation | ||
|
||
This project can be installed in multiple ways: | ||
|
||
`requirements.txt`: Add `git+https://github.com/hpicrypto/poksho.git@0.1.0#egg=poksho`. | ||
|
||
`pip(env)`: Run `pip(env) install git+https://github.com/hpicrypto/poksho.git@0.1.0#egg=poksho`. | ||
|
||
`poetry`: Run `poetry add git+https://github.com/hpicrypto/poksho.git@0.1.0`. | ||
|
||
## Usage | ||
|
||
### NIZK | ||
|
||
```python | ||
from poksho.equation import Element, Exponent, make_elements, make_exponents | ||
from poksho.statement import Statement, Equation | ||
|
||
# NIZKs can be performed on any group implementing the | ||
# poksho.group.group.GroupType interface. | ||
from poksho.group.ristretto import Group as RistrettoGroup | ||
group = RistrettoGroup | ||
|
||
# Create statement variables as symbolic group elements (without a value for now). | ||
# The variable names are not really used for anything, only for printing expressions. | ||
U = Element("U") | ||
V = Element("V") | ||
W = Element("W") | ||
|
||
# Helper for creating multiple variables. There is also a make_exponents helper that | ||
# can be used for symbolic exponent variables. | ||
G, H, I = make_elements("G", "H", "I") | ||
|
||
# Create a symbolic exponent. | ||
x = Exponent("x") | ||
# Bind a value to the already created exponent variable. | ||
# Note that in a real use case, the "real" values for the variables need to be input here. | ||
# The random values in this example are just for demonstration purposes. | ||
x.bind(group.exponent_cls.random()) | ||
|
||
# Value can also be bound at time of creation. | ||
y = Exponent("y", group.exponent_cls.random()) | ||
|
||
# Also bind the other values. | ||
G.bind(group.element_cls.random()) | ||
H.bind(group.element_cls.random()) | ||
I.bind(group.element_cls.random()) | ||
|
||
# Create a statement. This involves specifying the group implementation to use. | ||
# Equations that should be contained in the statement can be composed | ||
# from symbolic constants. | ||
statement = Statement(group, Equation(U, G**x * H**y), Equation(V, I**x)) | ||
|
||
# Equations can also be added to a statement later. | ||
statement.add_equation(Equation(W, G**y)) | ||
|
||
# Values can also be bound after they were used to describe a statement. | ||
U.bind((G**x * H**y).value) | ||
V.bind((I**x).value) | ||
W.bind((G**y).value) | ||
|
||
# Statement.prove() generates a NIZK proof for the statement using the | ||
# currently bound values. | ||
proof = statement.prove() | ||
|
||
# The same statement can be used to verify the proof. | ||
assert statement.verify(proof) | ||
|
||
# We can also create the same statement from completely new variables. | ||
G_ = Element("G_", G.value) | ||
H_ = Element("H_", H.value) | ||
I_ = Element("I_", I.value) | ||
U_ = Element("U_", U.value) | ||
V_ = Element("V_", V.value) | ||
W_ = Element("W_", W.value) | ||
# For verification, secrets (the exponents) don't have to have a value bound to them. | ||
x_, y_ = make_exponents("x_", "y_") | ||
statement_ = Statement(group, | ||
Equation(U_, G_**x_ * H_**y_), | ||
Equation(V_, I_**x_), | ||
Equation(W_, G_**y_) | ||
) | ||
|
||
# Verify the proof for a statement when the secret values are not bound. | ||
assert statement_.verify(proof) is True | ||
``` | ||
|
||
### SHO | ||
|
||
```python | ||
from poksho.sho import SHO | ||
|
||
# Create a SHO object | ||
sho = SHO( | ||
customization_label=b'label', | ||
hash_func='sha256', # refer to sho.ALLOWED_HASH_FUNCTIONS | ||
use_hmac=True | ||
) | ||
|
||
# Absorbing randomness (like a sponge). | ||
# Generating this randomness is out of scope for this module. | ||
sho.absorb(b"abc") | ||
sho.absorb_and_ratchet(b"def") | ||
sho.absorb(b"ghi") | ||
|
||
# The ratchet step must always be performed after we have absorbed values | ||
# and before extracting values from the SHO | ||
sho.ratchet() | ||
|
||
# Clone the sho if we want to perform operations on it but still keep the current SHO | ||
# state for another place in the code | ||
sho2 = sho.clone() | ||
|
||
# Deterministically "squeeze out" random output based on the random input | ||
# we provided earlier. | ||
# We can specify how long the output we receive should be | ||
output_length = 16 | ||
assert sho.squeeze_and_ratchet(output_length) == sho2.squeeze_and_ratchet(output_length) | ||
output = sho2.squeeze_and_ratchet(output_length) | ||
# output = sho2.squeeze() # --> Not supported by our implementation, raises NotImplementedError | ||
|
||
# If we forget to ratchet after absorb... | ||
sho.absorb(b'jkl') | ||
# sho.squeeze_and_ratchet(output_length) # --> raises ValueError here | ||
sho.ratchet() | ||
sho.squeeze_and_ratchet(output_length) | ||
``` | ||
|
||
## Testing | ||
|
||
``` | ||
PYTHONPATH=. pytest tests | ||
PYTHONPATH+=":$PWD" pytest tests/ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
__version__ = "0.0.1" | ||
__version__ = "0.1.0" | ||
|
||
from .sho import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters