Skip to content

Commit

Permalink
Merge pull request #49 from BlockstreamResearch/202410-clarify-seed
Browse files Browse the repository at this point in the history
  • Loading branch information
real-or-random authored Oct 3, 2024
2 parents 46a64a7 + aee1329 commit b76b40b
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 12 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,11 @@ A detailed treatment of these out-of-band methods is out of scope of this docume
Instead of performing an out-of-band check as the last step of the DKG,
ChillDKG relies on a more direct approach:
ChillDKG is a wrapper around EncPedPop,
It is a wrapper around EncPedPop,
which instantiates the required equality check protocol with a concrete in-band protocol CertEq.
CertEq assumes that each participant holds a long-term key pair of a signature scheme, called the *host key pair*.
ChillDKG repurposes the host key pairs by passing them down as ECDH key pairs to EncPedPop.[^joint-security]
ChillDKG repurposes the host key pairs as the ECDH key pairs required by EncPedPop,[^joint-security]
and it repurposes the host secret key as the seed required by EncPedPop.
[^joint-security]: Schnorr signatures and ECDH-based KEMs are known to be jointly secure [Theorem 2, [DLPSS11](https://eprint.iacr.org/2011/615)]
under the combination of the gap-DH and gap-DL assumptions, and this result can be adapted to the MR-KEM used in EncPedPop.
Expand Down
21 changes: 16 additions & 5 deletions python/chilldkg_ref/chilldkg.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,15 @@ def participant_step1(

idx = hostpubkeys.index(hostpubkey) # ValueError if not found
enc_state, enc_pmsg = encpedpop.participant_step1(
hostseckey, t, hostpubkeys, idx, random
# We know that EncPedPop uses its seed only by feeding it to a hash
# function. Thus, it is sufficient that the seed has a high entropy,
# and so we can simply pass the hostseckey as seed.
seed=hostseckey,
t=t,
# This requires the joint security of Schnorr signatures and ECDH.
enckeys=hostpubkeys,
idx=idx,
random=random,
) # SecKeyError if len(hostseckey) != 32
state1 = ParticipantState1(params, idx, enc_state)
return state1, ParticipantMsg1(enc_pmsg)
Expand Down Expand Up @@ -452,7 +460,10 @@ def participant_step2(
enc_cmsg, enc_secshares = cmsg1

enc_dkg_output, eq_input = encpedpop.participant_step2(
enc_state, hostseckey, enc_cmsg, enc_secshares[idx]
state=enc_state,
deckey=hostseckey,
cmsg=enc_cmsg,
enc_secshare=enc_secshares[idx],
)
# Include the enc_shares in eq_input to ensure that participants agree on all
# shares, which in turn ensures that they have the right recovery data.
Expand Down Expand Up @@ -541,7 +552,7 @@ def coordinator_step1(
(hostpubkeys, t) = params

enc_cmsg, enc_dkg_output, eq_input, enc_secshares = encpedpop.coordinator_step(
[pmsg1.enc_pmsg for pmsg1 in pmsgs1], t, hostpubkeys
pmsgs=[pmsg1.enc_pmsg for pmsg1 in pmsgs1], t=t, enckeys=hostpubkeys
)
eq_input += b"".join([bytes_from_int(int(share)) for share in enc_secshares])
dkg_output = DKGOutput._make(enc_dkg_output) # Convert to chilldkg.DKGOutput type
Expand Down Expand Up @@ -639,7 +650,7 @@ def recover(

# Decrypt share
enc_context = encpedpop.serialize_enc_context(t, hostpubkeys)
session_seed = encpedpop.derive_session_seed(
simpl_seed = encpedpop.derive_simpl_seed(
hostseckey, pubnonces[idx], enc_context
)
secshare = encpedpop.decrypt_sum(
Expand All @@ -652,7 +663,7 @@ def recover(
)

# Derive my_share
vss = VSS.generate(session_seed, t)
vss = VSS.generate(simpl_seed, t)
my_share = vss.secshare_for(idx)
secshare += my_share

Expand Down
10 changes: 5 additions & 5 deletions python/chilldkg_ref/encpedpop.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def serialize_enc_context(t: int, enckeys: List[bytes]) -> bytes:
return t.to_bytes(4, byteorder="big") + b"".join(enckeys)


def derive_session_seed(seed: bytes, pubnonce: bytes, enc_context: bytes) -> bytes:
def derive_simpl_seed(seed: bytes, pubnonce: bytes, enc_context: bytes) -> bytes:
return prf(seed, "encpedpop seed", pubnonce + enc_context)


Expand All @@ -147,12 +147,12 @@ def participant_step1(
# to deserialize it again, which involves computing a square root to obtain
# the y coordinate.
pubnonce = pubkey_gen_plain(secnonce)
# Add enc_context again to the derivation of the session seed, just in case
# someone derives secnonce differently.
session_seed = derive_session_seed(seed, pubnonce, enc_context)
# Add enc_context again to the derivation of the SimplPedPop seed, just in
# case someone derives secnonce differently.
simpl_seed = derive_simpl_seed(seed, pubnonce, enc_context)

simpl_state, simpl_pmsg, shares = simplpedpop.participant_step1(
session_seed, t, n, idx
simpl_seed, t, n, idx
)
assert len(shares) == n

Expand Down

0 comments on commit b76b40b

Please sign in to comment.