-
Notifications
You must be signed in to change notification settings - Fork 75
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 #38 from getamis/add_example
Add DKG example
- Loading branch information
Showing
14 changed files
with
1,018 additions
and
9 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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# TSS example | ||
|
||
This example demonstrates a simple p2p application using our TSS library. Let's assume we have 3 nodes where their ranks are all 0. These 3 nodes will interact with each other by using `go-libp2p` library. After each process (DKG, signer, and reshare), the results will be written in files located in `config/`. | ||
|
||
## Build | ||
```sh | ||
> make tss-example | ||
``` | ||
|
||
## Usage | ||
### DKG | ||
|
||
First, we run 3 hosts on different terminals. These 3 nodes will try to connect to each other. Once it connects to a peer, it will send the peer message out. After the peer messages are fully transmitted, each node will try to get the result and write it to the respective config file. | ||
|
||
On node A, | ||
```sh | ||
> ./example -config config/id-1.yaml | ||
``` | ||
|
||
On node B, | ||
```sh | ||
> ./example -config config/id-2.yaml | ||
``` | ||
|
||
On node C, | ||
```sh | ||
> ./example -config config/id-3.yaml | ||
``` |
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 |
---|---|---|
@@ -0,0 +1,68 @@ | ||
// Copyright © 2020 AMIS Technologies | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package main | ||
|
||
import ( | ||
"io/ioutil" | ||
|
||
"gopkg.in/yaml.v2" | ||
) | ||
|
||
type Threshold struct { | ||
DKG uint32 `yaml:"dkg"` | ||
Signer uint32 `yaml:"signer"` | ||
Reshare uint32 `yaml:"reshare"` | ||
} | ||
|
||
type Pubkey struct { | ||
X string `yaml:"x"` | ||
Y string `yaml:"y"` | ||
} | ||
|
||
type DKGResult struct { | ||
Share string `yaml:"share"` | ||
Pubkey Pubkey `yaml:"pubkey"` | ||
BKs map[string]string `yaml:"bks"` | ||
} | ||
|
||
type Config struct { | ||
Port int64 `yaml:"port"` | ||
Rank uint32 `yaml:"rank"` | ||
Threshold Threshold `yaml:"threshold"` | ||
Peers []int64 `yaml:"peers"` | ||
DKGResult DKGResult `yaml:"dkgResult"` | ||
} | ||
|
||
func readYamlFile(filaPath string) (*Config, error) { | ||
c := &Config{} | ||
yamlFile, err := ioutil.ReadFile(filaPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = yaml.Unmarshal(yamlFile, c) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return c, nil | ||
} | ||
|
||
func writeYamlFile(yamlData interface{}, filaPath string) error { | ||
data, err := yaml.Marshal(yamlData) | ||
if err != nil { | ||
return err | ||
} | ||
ioutil.WriteFile(filaPath, data, 0644) | ||
return nil | ||
} |
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 |
---|---|---|
@@ -0,0 +1,9 @@ | ||
port: 10001 | ||
rank: 0 | ||
threshold: | ||
dkg: 3 | ||
signer: 2 | ||
reshare: 3 | ||
peers: | ||
- 10002 | ||
- 10003 |
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 |
---|---|---|
@@ -0,0 +1,9 @@ | ||
port: 10002 | ||
rank: 0 | ||
threshold: | ||
dkg: 3 | ||
signer: 2 | ||
reshare: 3 | ||
peers: | ||
- 10001 | ||
- 10003 |
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 |
---|---|---|
@@ -0,0 +1,9 @@ | ||
port: 10003 | ||
rank: 0 | ||
threshold: | ||
dkg: 3 | ||
signer: 2 | ||
reshare: 3 | ||
peers: | ||
- 10001 | ||
- 10002 |
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 |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Copyright © 2020 AMIS Technologies | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package main | ||
|
||
import ( | ||
"flag" | ||
|
||
"github.com/getamis/sirius/log" | ||
"github.com/libp2p/go-libp2p-core/network" | ||
) | ||
|
||
const ( | ||
dkgProtocol = "/dkg/1.0.0" | ||
) | ||
|
||
func main() { | ||
configPath := flag.String("config", "", "config path") | ||
flag.Parse() | ||
if *configPath == "" { | ||
log.Crit("empty config path") | ||
} | ||
|
||
config, err := readYamlFile(*configPath) | ||
if err != nil { | ||
log.Crit("Failed to read config file", "configPath", *configPath, err) | ||
} | ||
|
||
// Make a host that listens on the given multiaddress. | ||
host, err := makeBasicHost(config.Port) | ||
if err != nil { | ||
log.Crit("Failed to create a basic host", "err", err) | ||
} | ||
|
||
// Create a new peer manager. | ||
pm := newPeerManager(getPeerIDFromPort(config.Port), host) | ||
err = pm.addPeers(config.Peers) | ||
if err != nil { | ||
log.Crit("Failed to add peers", "err", err) | ||
} | ||
|
||
// Create a new service. | ||
service, err := NewService(config, pm) | ||
if err != nil { | ||
log.Crit("Failed to new service", "err", err) | ||
} | ||
// Set a stream handler on the host. | ||
host.SetStreamHandler(dkgProtocol, func(s network.Stream) { | ||
service.Handle(s) | ||
}) | ||
|
||
// Ensure all peers are connected before starting DKG process. | ||
pm.EnsureAllConnected() | ||
|
||
// Start DKG process. | ||
service.Process() | ||
} |
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 |
---|---|---|
@@ -0,0 +1,150 @@ | ||
// Copyright © 2020 AMIS Technologies | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"math/rand" | ||
|
||
"github.com/getamis/sirius/log" | ||
ggio "github.com/gogo/protobuf/io" | ||
"github.com/golang/protobuf/proto" | ||
"github.com/libp2p/go-libp2p" | ||
"github.com/libp2p/go-libp2p-core/crypto" | ||
"github.com/libp2p/go-libp2p-core/helpers" | ||
"github.com/libp2p/go-libp2p-core/host" | ||
"github.com/libp2p/go-libp2p-core/peer" | ||
"github.com/multiformats/go-multiaddr" | ||
) | ||
|
||
// makeBasicHost creates a LibP2P host. | ||
func makeBasicHost(port int64) (host.Host, error) { | ||
sourceMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
priv, err := generateIdentity(port) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
opts := []libp2p.Option{ | ||
libp2p.ListenAddrs(sourceMultiAddr), | ||
libp2p.Identity(priv), | ||
} | ||
|
||
basicHost, err := libp2p.New(context.Background(), opts...) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return basicHost, nil | ||
} | ||
|
||
// getPeerAddr gets peer full address from port. | ||
func getPeerAddr(port int64) (string, error) { | ||
priv, err := generateIdentity(port) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
pid, err := peer.IDFromPrivateKey(priv) | ||
if err != nil { | ||
return "", err | ||
} | ||
return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/p2p/%s", port, pid), nil | ||
} | ||
|
||
// getPeerIDFromPort gets peer ID from port. | ||
func getPeerIDFromPort(port int64) string { | ||
// For convenience, we set peer ID as "id-" + port | ||
return fmt.Sprintf("id-%d", port) | ||
} | ||
|
||
// generateIdentity generates a fixed key pair by using port as random source. | ||
func generateIdentity(port int64) (crypto.PrivKey, error) { | ||
// Use the port as the randomness source in this example. | ||
r := rand.New(rand.NewSource(port)) | ||
|
||
// Generate a key pair for this host. | ||
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.ECDSA, 2048, r) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return priv, nil | ||
} | ||
|
||
// send sends the proto message to specified peer. | ||
func send(ctx context.Context, host host.Host, target string, data proto.Message) error { | ||
// Turn the destination into a multiaddr. | ||
maddr, err := multiaddr.NewMultiaddr(target) | ||
if err != nil { | ||
log.Warn("Cannot parse the target address", "target", target, "err", err) | ||
return err | ||
} | ||
|
||
// Extract the peer ID from the multiaddr. | ||
info, err := peer.AddrInfoFromP2pAddr(maddr) | ||
if err != nil { | ||
log.Warn("Cannot parse addr", "addr", maddr, "err", err) | ||
return err | ||
} | ||
|
||
s, err := host.NewStream(ctx, info.ID, dkgProtocol) | ||
if err != nil { | ||
log.Warn("Cannot create a new stream", "from", host.ID(), "to", target, "err", err) | ||
return err | ||
} | ||
writer := ggio.NewFullWriter(s) | ||
err = writer.WriteMsg(data) | ||
if err != nil { | ||
log.Warn("Cannot write message to IO", "err", err) | ||
return err | ||
} | ||
err = helpers.FullClose(s) | ||
if err != nil { | ||
log.Warn("Cannot close the stream", "err", err) | ||
return err | ||
} | ||
|
||
log.Info("Sent message", "peer", target) | ||
return nil | ||
} | ||
|
||
// connect connects the host to the specified peer. | ||
func connect(ctx context.Context, host host.Host, target string) error { | ||
// Turn the destination into a multiaddr. | ||
maddr, err := multiaddr.NewMultiaddr(target) | ||
if err != nil { | ||
log.Warn("Cannot parse the target address", "target", target, "err", err) | ||
return err | ||
} | ||
|
||
// Extract the peer ID from the multiaddr. | ||
info, err := peer.AddrInfoFromP2pAddr(maddr) | ||
if err != nil { | ||
log.Error("Cannot parse addr", "addr", maddr, "err", err) | ||
return err | ||
} | ||
|
||
// Connect the host to the peer. | ||
err = host.Connect(ctx, *info) | ||
if err != nil { | ||
log.Warn("Failed to connect to peer", "err", err) | ||
return err | ||
} | ||
return nil | ||
} |
Oops, something went wrong.