Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix group #55

Merged
merged 15 commits into from
Jul 18, 2018
32 changes: 17 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ been warned.**

Sure thing, here you go:

1. Make sure that you have a working [Docker installation](https://docs.docker.com/engine/installation/).
1. Make sure that you have a working [Docker installation](https://docs.docker.com/engine/installation/).
2. Then run:
```bash
./run_local.sh
Expand Down Expand Up @@ -65,9 +65,9 @@ A drand distributed randomness beacon involves a set of nodes and has two phases

### Private Randomness

The private randomness functionality can be used when one needs some high entropy randomness.
The private randomness functionality can be used when one needs some high entropy randomness.
A client can contact many different drand nodes individually and retrieve a portion of their
local randomness. This randomness can later be used to generate private key, nonces, etc. It
local randomness. This randomness can later be used to generate private key, nonces, etc. It
is particularly useful when the local randomness generator lacks external entropy, for example
in embedded devices.

Expand All @@ -77,19 +77,19 @@ Upon reception of the request, the server produces 32 random bytes locally
(using Go's `crypto/rand` interface), and encrypts back the randomness to the
client's public key. Of course, this is only a first version and much more thinking must be put
into the chicken-and-egg problem: how to generate an ephemereal key pair to get randomness
if we have bad randomness in the first place. We can later assume that the device is given an
initial key pair which uses it to gather randomness from drand nodes. This is not yet formally
if we have bad randomness in the first place. We can later assume that the device is given an
initial key pair which uses it to gather randomness from drand nodes. This is not yet formally
decided nor implemented yet and any comments/ideas on this are most welcomed.

## Installation
## Installation

Drand can be installed via [Golang](https://golang.org/) or [Docker](https://www.docker.com/).
By default, drand saves the configuration files such as the long-term key pair, the group file,
Drand can be installed via [Golang](https://golang.org/) or [Docker](https://www.docker.com/).
By default, drand saves the configuration files such as the long-term key pair, the group file,
and the collective public key in `$HOME/.drand/`.

### Via Docker

Make sure that you have a working [Docker installation](https://docs.docker.com/engine/installation/).
Make sure that you have a working [Docker installation](https://docs.docker.com/engine/installation/).

### Via Golang

Expand Down Expand Up @@ -172,7 +172,7 @@ The group file is generated in the current directory under `group.toml`.

After receiving the `drand_group.toml` file, participants can start drand via:
```
drand run --tls-cert <cert path> --tls-key <key path> <group_file.toml>
drand run --tls-cert <cert path> --tls-key <key path> --group-init <group_file.toml>
```
where `<cert path>` is the path of your TLS certificate and `<key path>` is the
path of your TLS private key. If you need non-secured channel, you can use the
Expand All @@ -182,7 +182,7 @@ One of the nodes has to function as the leader which finalizes the setup and
later also initiates regular randomness generation rounds. To start the drand
daemon in leader mode, execute:
```
drand run --leader --tls-cert <cert path> --tls-key <key path> <group_file.toml>
drand run --leader --tls-cert <cert path> --tls-key <key path> --group-init <group_file.toml>
```

Once running, the leader initiates the distributed key generation protocol to
Expand All @@ -194,6 +194,9 @@ Once the DKG phase is done, the distributed public key is saved in the local dir

### Randomness Generation

We now assume that the setup is done and we can switch to randomness generation.
Note : if a group file is given at this point, the existing beacon database will be erased.

The leader initiates a new randomness generation round automatically as per the
specified time interval (default interval: `1m`). All beacon values are stored
using [`BoltDB`](https://github.com/coreos/bbolt), a Go native fast key/value
Expand All @@ -202,7 +205,7 @@ database engine.
To change the [duration](https://golang.org/pkg/time/#ParseDuration) of the
randomness generation interval, e.g., to `30s`, start drand via
```
drand run --leader --period 30s --tls-cert <cert path> --tls-key <key path> <group_file.toml>
drand run --leader --period 30s --tls-cert <cert path> --tls-key <key path>
```

### Randomness Gathering
Expand Down Expand Up @@ -252,7 +255,7 @@ custom certificate.


The command outputs a 32-byte base64-encoded random value coming from the local
randomness engine of the contacted server. If the encryption is not correct, the
randomness engine of the contacted server. If the encryption is not correct, the
command outputs an error instead.


Expand All @@ -264,7 +267,7 @@ Drand relies on the following cryptographic constructions:
- For the setup of the distributed key, drand uses an implementation of
[Pedersen's distributed key generation protocol](https://link.springer.com/article/10.1007/s00145-006-0347-3).
There are more [advanced DKG protocols](https://eprint.iacr.org/2012/377.pdf) which we plan to implement in the future.
- For the randomness generation, drand uses an implementation of threshold
- For the randomness generation, drand uses an implementation of threshold
[BLS signatures](https://www.iacr.org/archive/asiacrypt2001/22480516.pdf).
- For the encryption used in the private randomness gathering, see the [ECIES
scheme](https://en.wikipedia.org/wiki/Integrated_Encryption_Scheme).
Expand Down Expand Up @@ -303,4 +306,3 @@ exchanged over the general drand design.
Thanks to [@Bren2010](https://github.com/Bren2010) and
[@grittygrease](https://github.com/grittygrease) for providing the native Golang
bn256 implementation and for their help in the design of drand.

1 change: 1 addition & 0 deletions core/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func WithDbFolder(folder string) ConfigOption {
func WithConfigFolder(folder string) ConfigOption {
return func(d *Config) {
d.configFolder = folder
d.dbFolder = path.Join(d.configFolder, DefaultDbFolder)
}
}

Expand Down
66 changes: 46 additions & 20 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package main

import (
"bufio"
"bytes"
"encoding/json"
"fmt"
Expand Down Expand Up @@ -47,11 +48,6 @@ func main() {
Value: core.DefaultConfigFolder(),
Usage: "Folder to keep all drand cryptographic informations, in absolute form.",
}
dbFlag := cli.StringFlag{
Name: "db",
Value: path.Join(configFlag.Value, core.DefaultDbFolder),
Usage: "Folder in which to keep the database (boltdb file)",
}
seedFlag := cli.StringFlag{
Name: "seed",
Value: string(core.DefaultSeed),
Expand Down Expand Up @@ -104,6 +100,11 @@ func main() {
Usage: "indicates to use a non TLS server or connection",
}

groupFlag := cli.StringFlag{
Name: "group-init",
Usage: "the group file to use during the DKG. If specified, drand erases any existing beacon database, as it supports only being part of one group at a time.",
}

app.Commands = []cli.Command{
cli.Command{
Name: "keygen",
Expand All @@ -126,10 +127,9 @@ func main() {
},
},
cli.Command{
Name: "dkg",
Usage: "Run the DKG protocol",
ArgsUsage: "GROUP.TOML the group file listing all participant's identities",
Flags: toArray(leaderFlag, listenFlag, tlsCertFlag, tlsKeyFlag, certsDirFlag),
Name: "dkg",
Usage: "Run the DKG protocol",
Flags: toArray(leaderFlag, listenFlag, tlsCertFlag, tlsKeyFlag, certsDirFlag, groupFlag),
Action: func(c *cli.Context) error {
banner()
return dkgCmd(c)
Expand All @@ -145,10 +145,9 @@ func main() {
},
},
cli.Command{
Name: "run",
Usage: "Run the daemon, first do the dkg if needed then run the beacon",
ArgsUsage: "<group file> is the group.toml generated with `group`. This argument is only needed if the DKG has NOT been run yet.",
Flags: toArray(leaderFlag, periodFlag, seedFlag, listenFlag, tlsCertFlag, tlsKeyFlag, certsDirFlag, insecureFlag),
Name: "run",
Usage: "Run the daemon, first do the dkg if needed then run the beacon",
Flags: toArray(leaderFlag, periodFlag, seedFlag, listenFlag, tlsCertFlag, tlsKeyFlag, certsDirFlag, insecureFlag, groupFlag),
Action: func(c *cli.Context) error {
banner()
return runCmd(c)
Expand Down Expand Up @@ -180,7 +179,7 @@ func main() {
},
},
}
app.Flags = toArray(verboseFlag, configFlag, dbFlag)
app.Flags = toArray(verboseFlag, configFlag)
app.Before = func(c *cli.Context) error {
if c.GlobalIsSet("debug") {
slog.Level = slog.LevelDebug
Expand Down Expand Up @@ -280,11 +279,14 @@ func groupCmd(c *cli.Context) error {
}

func dkgCmd(c *cli.Context) error {
if c.NArg() < 1 {
if !c.IsSet("group-init") {
slog.Fatal("dkg requires a group.toml file")
}
group := getGroup(c)
conf := contextToConfig(c)
if exit := resetBeaconDB(conf); exit {
os.Exit(0)
}
fs := key.NewFileStore(conf.ConfigFolder())
drand, err := core.NewDrand(fs, group, conf)
if err != nil {
Expand Down Expand Up @@ -332,9 +334,11 @@ func runCmd(c *cli.Context) error {
fs := key.NewFileStore(conf.ConfigFolder())
var drand *core.Drand
var err error
if c.NArg() > 0 {
// we assume it is the group file
if c.IsSet("group-init") {
group := getGroup(c)
if exit := resetBeaconDB(conf); exit {
os.Exit(0)
}
drand, err = core.NewDrand(fs, group, conf)
if err != nil {
slog.Fatal(err)
Expand Down Expand Up @@ -421,8 +425,6 @@ func contextToConfig(c *cli.Context) *core.Config {

config := c.GlobalString("config")
opts = append(opts, core.WithConfigFolder(config))
db := path.Join(config, c.GlobalString("db"))
opts = append(opts, core.WithDbFolder(db))
period := c.Duration("period")
opts = append(opts, core.WithBeaconPeriod(period))

Expand Down Expand Up @@ -455,13 +457,37 @@ func contextToConfig(c *cli.Context) *core.Config {

func getGroup(c *cli.Context) *key.Group {
g := &key.Group{}
if err := key.Load(c.Args().First(), g); err != nil {
if err := key.Load(c.String("group-init"), g); err != nil {
slog.Fatal(err)
}
slog.Infof("group file loaded with %d participants", g.Len())
return g
}

func resetBeaconDB(config *core.Config) bool {
if _, err := os.Stat(config.DBFolder()); err == nil {
// using fmt so does not get the new line at the end.
// XXX allow slog for that behavior
fmt.Print("INCONSISTENT STATE: the group-init flag is set, but a beacon database exists already.\ndrand support only one identity at the time and thus needs to delete the existing beacon database.\nAccept to delete database ? [Y/n]: ")
reader := bufio.NewReader(os.Stdin)
answer, err := reader.ReadString('\n')
if err != nil {
slog.Fatal("error reading: ", err)
}
answer = strings.ToLower(strings.TrimSpace(answer))
if answer != "y" {
slog.Print("Not deleting the database. Exiting drand.")
return true
}

if err := os.RemoveAll(config.DBFolder()); err != nil {
slog.Fatal(err)
}
slog.Print("Removed existing beacon database.")
}
return false
}

func askPort() string {
slog.Print("asking for port")
for {
Expand Down