Skip to content

Commit

Permalink
feat: create generate-rln-credentials subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
richard-ramos committed Aug 18, 2023
1 parent 2818c3d commit 6ff7116
Show file tree
Hide file tree
Showing 8 changed files with 465 additions and 60 deletions.
2 changes: 2 additions & 0 deletions cmd/waku/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
cli "github.com/urfave/cli/v2"
"github.com/urfave/cli/v2/altsrc"
"github.com/waku-org/go-waku/cmd/waku/keygen"
"github.com/waku-org/go-waku/cmd/waku/rlngenerate"
"github.com/waku-org/go-waku/waku/v2/node"
)

Expand Down Expand Up @@ -114,6 +115,7 @@ func main() {
},
Commands: []*cli.Command{
&keygen.Command,
&rlngenerate.Command,
},
}

Expand Down
19 changes: 19 additions & 0 deletions cmd/waku/rlngenerate/command_no_rln.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//go:build !gowaku_rln
// +build !gowaku_rln

package rlngenerate

import (
"errors"

cli "github.com/urfave/cli/v2"
)

// Command generates a key file used to generate the node's peerID, encrypted with an optional password
var Command = cli.Command{
Name: "generate-rln-credentials",
Usage: "Generate credentials for usage with RLN",
Action: func(cCtx *cli.Context) error {
return errors.New("not available. Execute `make RLN=true` to add RLN support to go-waku")
},
}
141 changes: 141 additions & 0 deletions cmd/waku/rlngenerate/command_rln.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//go:build gowaku_rln
// +build gowaku_rln

package rlngenerate

import (
"context"
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/ethclient"
cli "github.com/urfave/cli/v2"
"github.com/waku-org/go-waku/logging"
"github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts"
"github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager/dynamic"
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore"
"github.com/waku-org/go-waku/waku/v2/utils"
"github.com/waku-org/go-zerokit-rln/rln"
"go.uber.org/zap"
)

var options Options
var logger = utils.Logger().Named("rln-credentials")

// Command generates a key file used to generate the node's peerID, encrypted with an optional password
var Command = cli.Command{
Name: "generate-rln-credentials",
Usage: "Generate credentials for usage with RLN",
Action: func(cCtx *cli.Context) error {
err := verifyFlags()
if err != nil {
logger.Error("validating option flags", zap.Error(err))
return cli.Exit(err, 1)
}

err = execute(context.Background())
if err != nil {
logger.Error("registering RLN credentials", zap.Error(err))
return cli.Exit(err, 1)
}

return nil
},
Flags: flags,
}

func verifyFlags() error {
if options.CredentialsPath == "" {
logger.Warn("keystore: no credentials path set, using default path", zap.String("path", keystore.RLN_CREDENTIALS_FILENAME))
options.CredentialsPath = keystore.RLN_CREDENTIALS_FILENAME
}

if options.CredentialsPassword == "" {
logger.Warn("keystore: no credentials password set, using default password", zap.String("password", keystore.RLN_CREDENTIALS_PASSWORD))
options.CredentialsPassword = keystore.RLN_CREDENTIALS_PASSWORD
}

if options.ETHPrivateKey == nil {
return errors.New("a private key must be specified")
}

return nil
}

func execute(ctx context.Context) error {
ethClient, err := ethclient.Dial(options.ETHClientAddress)
if err != nil {
return err
}

rlnInstance, err := rln.NewRLN()
if err != nil {
return err
}

chainID, err := ethClient.ChainID(ctx)
if err != nil {
return err
}

rlnContract, err := contracts.NewRLN(options.MembershipContractAddress, ethClient)
if err != nil {
return err
}

// prepare rln membership key pair
logger.Info("generating rln credential")
identityCredential, err := rlnInstance.MembershipKeyGen()
if err != nil {
return err
}

// register the rln-relay peer to the membership contract
membershipIndex, err := register(ctx, ethClient, rlnContract, identityCredential.IDCommitment, chainID)
if err != nil {
return err
}

// TODO: clean private key from memory

err = persistCredentials(identityCredential, membershipIndex, chainID)
if err != nil {
return err
}

if logger.Level() == zap.DebugLevel {
logger.Info("registered credentials into the membership contract",
logging.HexString("IDCommitment", identityCredential.IDCommitment[:]),
logging.HexString("IDNullifier", identityCredential.IDNullifier[:]),
logging.HexString("IDSecretHash", identityCredential.IDSecretHash[:]),
logging.HexString("IDTrapDoor", identityCredential.IDTrapdoor[:]),
zap.Uint("index", membershipIndex),
)
} else {
logger.Info("registered credentials into the membership contract", logging.HexString("idCommitment", identityCredential.IDCommitment[:]), zap.Uint("index", membershipIndex))
}

ethClient.Close()

return nil
}

func persistCredentials(identityCredential *rln.IdentityCredential, membershipIndex rln.MembershipIndex, chainID *big.Int) error {
membershipGroup := keystore.MembershipGroup{
TreeIndex: membershipIndex,
MembershipContract: keystore.MembershipContract{
ChainId: fmt.Sprintf("0x%X", chainID.Int64()),
Address: options.MembershipContractAddress.String(),
},
}

keystoreIndex, membershipGroupIndex, err := keystore.AddMembershipCredentials(options.CredentialsPath, identityCredential, membershipGroup, options.CredentialsPassword, dynamic.RLNAppInfo, keystore.DefaultSeparator)
if err != nil {
return fmt.Errorf("failed to persist credentials: %w", err)
}

logger.Info("persisted credentials succesfully", zap.Int("keystoreIndex", keystoreIndex), zap.Int("membershipGroupIndex", membershipGroupIndex))

return nil
}
75 changes: 75 additions & 0 deletions cmd/waku/rlngenerate/flags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//go:build gowaku_rln
// +build gowaku_rln

package rlngenerate

import (
cli "github.com/urfave/cli/v2"
wcli "github.com/waku-org/go-waku/waku/cliutils"
"github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore"
)

var flags = []cli.Flag{
&cli.PathFlag{
Name: "cred-path",
Usage: "RLN relay membership credentials file",
Value: keystore.RLN_CREDENTIALS_FILENAME,
Destination: &options.CredentialsPath,
},
&cli.StringFlag{
Name: "cred-password",
Value: keystore.RLN_CREDENTIALS_PASSWORD,
Usage: "Password for encrypting RLN credentials",
Destination: &options.CredentialsPassword,
},
&cli.GenericFlag{
Name: "eth-account-private-key",
Usage: "Ethereum account private key used for registering in member contract",
Value: &wcli.PrivateKeyValue{
Value: &options.ETHPrivateKey,
},
},
&cli.StringFlag{
Name: "eth-client-address",
Usage: "Ethereum testnet client address",
Value: "ws://localhost:8545",
Destination: &options.ETHClientAddress,
},
&cli.GenericFlag{
Name: "eth-contract-address",
Usage: "Address of membership contract",
Value: &wcli.AddressValue{
Value: &options.MembershipContractAddress,
},
},
&cli.StringFlag{
Name: "eth-nonce",
Value: "",
Usage: "Set an specific ETH transaction nonce. Leave empty to calculate the nonce automatically",
Destination: &options.ETHNonce,
},
&cli.Uint64Flag{
Name: "eth-gas-limit",
Value: 0,
Usage: "Gas limit to set for the transaction execution (0 = estimate)",
Destination: &options.ETHGasLimit,
},
&cli.StringFlag{
Name: "eth-gas-price",
Value: "",
Usage: "Gas price in wei to use for the transaction execution (empty = gas price oracle)",
Destination: &options.ETHGasPrice,
},
&cli.StringFlag{
Name: "eth-gas-fee-cap",
Value: "",
Usage: "Gas fee cap in wei to use for the 1559 transaction execution (empty = gas price oracle)",
Destination: &options.ETHGasFeeCap,
},
&cli.StringFlag{
Name: "eth-gas-tip-cap",
Value: "",
Usage: "Gas priority fee cap in wei to use for the 1559 transaction execution (empty = gas price oracle)",
Destination: &options.ETHGasTipCap,
},
}
21 changes: 21 additions & 0 deletions cmd/waku/rlngenerate/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package rlngenerate

import (
"crypto/ecdsa"

"github.com/ethereum/go-ethereum/common"
)

// Options are settings used to create RLN credentials.
type Options struct {
CredentialsPath string
CredentialsPassword string
ETHPrivateKey *ecdsa.PrivateKey
ETHClientAddress string
MembershipContractAddress common.Address
ETHGasLimit uint64
ETHNonce string
ETHGasPrice string
ETHGasFeeCap string
ETHGasTipCap string
}
Loading

0 comments on commit 6ff7116

Please sign in to comment.