[WIP] Guard Tower: Initial interface and struct setups for distributed key generation - #32
Conversation
Includes a healthy dose of documentation, as well as a NewMember constructor function. There are still some open questions around how to handle the id, but this should be a good starting point.
|
|
||
| // Message represents a message to communicate over a broadcast channel. | ||
| // TODO Combine with Raghav's work on protobuf messages. | ||
| type Message struct { |
There was a problem hiding this comment.
This works for now, and I can write the rpc/proto messages that can have an Unmarshal and Marshal into this type
There was a problem hiding this comment.
That way we can isolate the rpc stuff
There was a problem hiding this comment.
Will need to see it to fully understand, but that sounds good 👍
| } | ||
|
|
||
| // NewMember creates a new member with the given id. The id should be a base-10 | ||
| // string and is encoded into a bls.ID for use with the built-in secret sharing. |
There was a problem hiding this comment.
We'll really want to accept an arbitrary string, encode it as hex, and use that for the bls.ID. Either that or we'll need to take a numeric type for the id, which I don't love…
Basically the “the id should be a base-10 string” bit is just begging for something to go wrong heh.
The one Member struct becomes a LocalMember, SharingMember, JustifyingMember, and Member struct. Each one of these represents a phase in DKG, except SharingMember which represents both the commitment and private share receiving/validation phase. These can occur at the same time without any issues, so we combine the struct. Each struct has an associated method to transition it to the next phase, in which we do any final work (e.g., when we go from LocalMember to SharingMember we compute the private member shares that are to be sent to each member of the threshold group). Each struct also exposes the various methods that make sense for its phase. The Member struct now represents a fully-fleshed-out member, ready to participate in threshold signatures. Note that there are still a few todos around properly tracking accusation/justification. There is also some validation that needs to happen so that we don't generate a final Member if we've failed to meet our threshold requirements for qualified members.
|
Ok, fleshed out the member structure… Interested in feedback around how I've done it. I made ~1 struct per DKG phase, and allow the member to transition between the structs. They compose, so that the struct from justification contains the struct from previous phases. The idea is that this captures the current phase of the member, and allows us to set some type restrictions in our code so that we don't start making an uninitialized member sign things and such. Rather than breaking down out the structs, we could also use one big struct and make the transitions be transitions between interfaces that allow various operations. I'm interested in thoughts around whether this approach or the interface one is better… Or if there's another one altogether that I haven't considered. @keep-network/go lemme know! |
|
Superseded by #35 because I'm silly and accidentally hit some buttons in my editor <_< |
The docker build was failing locally with errors: ``` (...) => ERROR [gobuild 24/24] RUN GOOS=linux go build -ldflags "-X main.version=$VERSION -X main.revision=$REVISION" -a -o keep-clie 1.1s ------ > [gobuild 24/24] RUN GOOS=linux go build -ldflags "-X main.version=$VERSION -X main.revision=$REVISION" -a -o keep-client ./ && mv keep-client /usr/local/bin: \#32 1.096 pkg/tbtc/marshaling.go:9:2: no required module provides package github.com/keep-network/keep-core/pkg/tbtc/gen/pb; to add it: \#32 1.096 go get github.com/keep-network/keep-core/pkg/tbtc/gen/pb \#32 1.096 pkg/tecdsa/dkg/marshaling.go:10:2: no required module provides package github.com/keep-network/keep-core/pkg/tecdsa/dkg/gen/pb; to add it: \#32 1.096 go get github.com/keep-network/keep-core/pkg/tecdsa/dkg/gen/pb '#32 1.096 pkg/tecdsa/marshaling.go:10:2: no required module provides package github.com/keep-network/keep-core/pkg/tecdsa/gen/pb; to add it: '#32 1.096 go get github.com/keep-network/keep-core/pkg/tecdsa/gen/pb (...) ``` It turned out that we don't copy following directories for generation: ``` COPY ./pkg/tbtc/gen $APP_DIR/pkg/tbtc/gen COPY ./pkg/tecdsa/dkg/gen $APP_DIR/pkg/tecdsa/dkg/gen COPY ./pkg/tecdsa/gen $APP_DIR/pkg/tecdsa/gen ``` We add them here. Also we took and opportunity to sort the directories alphabeticaly.
Add missing gen directories to the Dockerfile The docker build was failing locally with errors: ``` (...) => ERROR [gobuild 24/24] RUN GOOS=linux go build -ldflags "-X main.version=$VERSION -X main.revision=$REVISION" -a -o keep-clie 1.1s ------ > [gobuild 24/24] RUN GOOS=linux go build -ldflags "-X main.version=$VERSION -X main.revision=$REVISION" -a -o keep-client ./ && mv keep-client /usr/local/bin: \#32 1.096 pkg/tbtc/marshaling.go:9:2: no required module provides package github.com/keep-network/keep-core/pkg/tbtc/gen/pb; to add it: \#32 1.096 go get github.com/keep-network/keep-core/pkg/tbtc/gen/pb \#32 1.096 pkg/tecdsa/dkg/marshaling.go:10:2: no required module provides package github.com/keep-network/keep-core/pkg/tecdsa/dkg/gen/pb; to add it: \#32 1.096 go get github.com/keep-network/keep-core/pkg/tecdsa/dkg/gen/pb '#32 1.096 pkg/tecdsa/marshaling.go:10:2: no required module provides package github.com/keep-network/keep-core/pkg/tecdsa/gen/pb; to add it: '#32 1.096 go get github.com/keep-network/keep-core/pkg/tecdsa/gen/pb (...) ``` It turned out that we don't copy the following directories for a generation: ``` COPY ./pkg/tbtc/gen $APP_DIR/pkg/tbtc/gen COPY ./pkg/tecdsa/dkg/gen $APP_DIR/pkg/tecdsa/dkg/gen COPY ./pkg/tecdsa/gen $APP_DIR/pkg/tecdsa/gen ``` We add them here. Also, we took an opportunity to sort the directories alphabetically.
New Merkle Distribution for Sep 30th
Integration branch for the Tier 0 + Tier 1 testing/correctness work. Feature PRs are stacked onto this branch and reviewed/merged one by one; this branch then merges to main as a single epic. Stack (bottom -> top): 1. threshold-network#29 ci: -race job + ruleguard accessor lint (Tier 0) 2. threshold-network#30 test: native fuzz targets (Tier 1 / 1a) 3. threshold-network#31 ci: ClusterFuzzLite continuous fuzzing (Tier 1 / 1b) 4. threshold-network#32 test: rapid property tests (Tier 1 / 1c)
… property The property's comment promised 'every source field exactly' but Redeemer and RedeemerOutputScript were hard-coded constants that were never asserted, so cross-wiring either field would have passed. Draw both with rapid — the script as raw bytes wrapped in the var-len encoding the converter parses — and assert the converted values, closing the gap between the claim and the coverage. Note for reviewers of the open PR threshold-network#32 thread on this file: comparing the parsed script against the raw length-prefixed ABI bytes would be wrong — the converter strips the var-len prefix, so the assertion must target the decoded payload.
Integration branch for the Tier 0 + Tier 1 testing/correctness work. Feature PRs are stacked onto this branch and reviewed/merged one by one; this branch then merges to main as a single epic. Stack (bottom -> top): 1. threshold-network#29 ci: -race job + ruleguard accessor lint (Tier 0) 2. threshold-network#30 test: native fuzz targets (Tier 1 / 1a) 3. threshold-network#31 ci: ClusterFuzzLite continuous fuzzing (Tier 1 / 1b) 4. threshold-network#32 test: rapid property tests (Tier 1 / 1c)
… property The property's comment promised 'every source field exactly' but Redeemer and RedeemerOutputScript were hard-coded constants that were never asserted, so cross-wiring either field would have passed. Draw both with rapid — the script as raw bytes wrapped in the var-len encoding the converter parses — and assert the converted values, closing the gap between the claim and the coverage. Note for reviewers of the open PR threshold-network#32 thread on this file: comparing the parsed script against the raw length-prefixed ABI bytes would be wrong — the converter strips the var-len prefix, so the assertion must target the decoded payload.
This is turbo-incomplete, but wanted to get it out there to start getting feedback, and to start aligning with/informing the libp2p work. I'll fill in some more details tomorrow and update the description accordingly.
Extracted/refactored from the work in #27 .