Skip to content

Commit

Permalink
reference: Clarify what belongs to public API
Browse files Browse the repository at this point in the history
by introducing the convention that the public API are all functions
with a docstring
  • Loading branch information
real-or-random committed Jun 28, 2024
1 parent f1f235b commit 7df860d
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 56 deletions.
22 changes: 17 additions & 5 deletions reference/chilldkg.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Reference implementation of BIP DKG.
"""Reference implementation of ChillDKG.
The public API consists of all functions with docstrings, including the types in
their arguments and return values, and the exceptions they raise). All other
definitions are internal.
"""

from secrets import token_bytes as random_bytes
from typing import Tuple, List, NamedTuple, NewType, Optional

Expand All @@ -19,6 +25,11 @@
SessionNotFinalizedError,
)

# TODO
# __all__ = []

# TODO Document in all public functions what exceptions they can raise
# TODO What about DKGOutput? It should be here.

###
### Certifying equality check
Expand Down Expand Up @@ -204,6 +215,7 @@ class ParticipantState2(NamedTuple):
dkg_output: DKGOutput


"""TODO Write docstring. Or just remove it and make it bytes"""
RecoveryData = NewType("RecoveryData", bytes)


Expand All @@ -221,7 +233,6 @@ def participant_step1(
:raises ValueError: if the participant's host public key is not in
params.hostpubkeys
:raises ValueError: if the length of seed is not 32 bytes
"""
hostseckey, hostpubkey = hostkey_gen(seed)
(hostpubkeys, t) = params
Expand Down Expand Up @@ -377,12 +388,13 @@ async def coordinator(
###


# Recovery requires the seed (can be None if recovering the coordinator) and the
# public recovery data
def recover(
seed: Optional[bytes], recovery: RecoveryData
) -> Tuple[DKGOutput, SessionParams]:
"""TODO"""
"""TODO
Recovery requires the seed (can be None if recovering the coordinator) and
the public recovery data
"""
try:
(t, sum_vss_commit, hostpubkeys, enc_shares_sums, cert) = (
deserialize_recovery_data(recovery)
Expand Down
4 changes: 4 additions & 0 deletions reference/network.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#
# Network mocks to simulate full DKG sessions
#

import asyncio


Expand Down
47 changes: 14 additions & 33 deletions reference/simplpedpop.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


###
### Proofs of possession (Pops)
### Proofs of possession (pops)
###


Expand Down Expand Up @@ -36,15 +36,11 @@ def pop_verify(pop: Pop, pubkey: bytes, idx: int):


class ParticipantMsg(NamedTuple):
"""Round 1 message from participant to coordinator"""

com: VSSCommitment
pop: Pop


class CoordinatorMsg(NamedTuple):
"""Round 1 message from coordinator to all participants"""

coms_to_secrets: List[GE]
sum_coms_to_nonconst_terms: List[GE]
pops: List[Pop]
Expand All @@ -63,8 +59,6 @@ def to_bytes(self) -> bytes:
###


# TODO This should probably moved somewhere else as its common to all DKGs.
# Hm, moving it to reference.py is difficult due to cylic module dependencies.
class DKGOutput(NamedTuple):
secshare: Optional[Scalar] # None for coordinator
threshold_pubkey: GE
Expand All @@ -81,10 +75,10 @@ def assemble_sum_vss_commitment(


def common_dkg_output(vss_commit, n: int) -> Tuple[GE, List[GE]]:
"""Derive the common parts of the DKG output from the sum of all VSS commitments
The common parts are the threshold public key and the individual public shares of
all participants."""
# Derive the common parts of the DKG output from the sum of all VSS commitments
#
# The common parts are the threshold public key and the individual public shares of
# all participants.
threshold_pubkey = vss_commit.ges[0]
pubshares = []
for i in range(0, n):
Expand Down Expand Up @@ -119,15 +113,6 @@ class ParticipantState(NamedTuple):
def participant_step1(
seed: bytes, t: int, n: int, participant_idx: int
) -> Tuple[ParticipantState, ParticipantMsg, List[Scalar]]:
"""
Generate SimplPedPop messages to be sent to the coordinator.
:param bytes seed: FRESH, UNIFORMLY RANDOM 32-byte string
:param int t: threshold
:param int n: number of participants
:param int participant_idx: index of this participant in the participant list
:return: the participant's state, the VSS commitment and the generated shares
"""
assert t < 2 ** (4 * 8)
assert participant_idx < 2 ** (4 * 8)

Expand All @@ -147,14 +132,6 @@ def participant_step2(
cmsg: CoordinatorMsg,
shares_sum: Scalar,
) -> Tuple[DKGOutput, bytes]:
"""
Take the messages received from the coordinator and return eq_input to be compared and DKG output
:param ParticipantState state: the participant's state after round 1 (output by participant_round1)
:param CoordinatorMsg cmsg: round 1 broadcast message received from the coordinator
:param Scalar shares_sum: sum of shares for this participant received from all participants (including this participant)
:return: the data `eq_input` that must be input to an equality check protocol, the final share, the threshold pubkey, the individual participants' pubshares
"""
t, n, idx, com_to_secret = state
coms_to_secrets, sum_coms_to_nonconst_terms, pops = cmsg
assert len(coms_to_secrets) == n
Expand Down Expand Up @@ -194,15 +171,19 @@ def participant_step2(
###


# Sum the commitments to the i-th coefficients from the given vss_commitments
# for i > 0. This procedure is introduced by Pedersen in section 5.1 of
# 'Non-Interactive and Information-Theoretic Secure Verifiable Secret Sharing'.
def coordinator_step(
pmsgs: List[ParticipantMsg], t: int, n: int
) -> Tuple[CoordinatorMsg, DKGOutput, bytes]:
# We cannot sum the commitments to the secrets because they'll be necessary
# to check the PoPs.
# Sum the commitments to the i-th coefficients for i > 0
#
# This procedure is introduced by Pedersen in Section 5.1 of
# 'Non-Interactive and Information-Theoretic Secure Verifiable Secret
# Sharing'.

# We cannot sum the commitments to the secrets (i == 0) because they'll be
# necessary to check the pops.
coms_to_secrets = [pmsg.com.commitment_to_secret() for pmsg in pmsgs]

# But we can sum the commitments to the non-constant terms.
sum_coms_to_nonconst_terms = [
GE.sum(*(pmsg.com.commitment_to_nonconst_terms()[j] for pmsg in pmsgs))
Expand Down
4 changes: 4 additions & 0 deletions reference/tests.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#
# Tests
#

from itertools import combinations
from random import randint
from typing import Tuple, List
Expand Down
3 changes: 0 additions & 3 deletions reference/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ def prf(seed: bytes, tag: str, extra_input: bytes = b"") -> bytes:
return tagged_hash_bip_dkg(tag, seed + extra_input)


# TODO Document in all functions what exceptions they can raise


class InvalidContributionError(Exception):
def __init__(self, participant, error):
self.participant = participant
Expand Down
33 changes: 18 additions & 15 deletions reference/vss.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ def __init__(self):


class Polynomial(NamedTuple):
"""A scalar polynomial.
A polynomial f of degree at most t - 1 is represented by a list `coeffs` of
t coefficients, i.e., f(x) = coeffs[0] + ... + coeffs[t-1] * x^(t-1)."""
# A scalar polynomial.
#
# A polynomial f of degree at most t - 1 is represented by a list `coeffs`
# of t coefficients, i.e., f(x) = coeffs[0] + ... + coeffs[t-1] *
# x^(t-1)."""

coeffs: List[Scalar]

def eval(self, x: Scalar) -> Scalar:
"""Evaluate a polynomial at position x."""
# Evaluate a polynomial at position x.

value = Scalar(0)
# Reverse coefficients to compute evaluation via Horner's method
Expand All @@ -44,8 +45,8 @@ def verify(self, i: int, share: Scalar) -> bool:
)
return P == Q

# Returns commitments to the coefficients of f
def to_bytes(self) -> bytes:
# Return commitments to the coefficients of f.
return b"".join([P.to_bytes_compressed_with_infinity() for P in self.ges])

def __add__(self, other):
Expand Down Expand Up @@ -78,24 +79,26 @@ def generate(seed, t):
return VSS(Polynomial(coeffs))

def share_for(self, i: int):
"""Return the secret share to be sent to the participant with index i.
# Return the secret share for the participant with index i.
#
# This computes f(i+1).

This computes f(i+1)."""
x = Scalar(i + 1)
assert x != Scalar(0) # Ensure we don't compute f(0), which is the secret.
# Ensure we don't compute f(0), which is the secret.
assert x != Scalar(0)
return self.f(x)

def shares(self, n: int) -> List[Scalar]:
"""Return the secret shares to be sent to participants with indices 0..n-1.
This computes [f(1), ..., f(n)]."""
# Return the secret shares for the participants with indices 0..n-1.
#
# This computes [f(1), ..., f(n)].
return [self.share_for(i) for i in range(0, n)]

def commit(self) -> VSSCommitment:
return VSSCommitment([c * G for c in self.f.coeffs])

def secret(self):
"""Return the secret to be shared.
This computes f(0)."""
# Return the secret to be shared.
#
# This computes f(0).
return self.f.coeffs[0]

0 comments on commit 7df860d

Please sign in to comment.