Persisting rln credentials (#1037)

* Persisting Credentials implemented by writing json of keypair and rlnindex to files

* Removing testing files and ignores

* Update waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim

Co-authored-by: Daniel Kaiser <git@kais3r.de>

* Update waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim

Co-authored-by: Daniel Kaiser <git@kais3r.de>

* Comments

* Comments

* Security warning in comments

* Redundant echos. Omitting unused variables.

* Update waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim

Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com>

* Limit line lengths using line breaks and indents

* Membership file paths declared as const

* Const fix

* Rln Credentials Merged.
Reading credentials from file abstracted away.

* Spaces

* Spaces

* Dangling constants removed. Comments position.

* Import sequence.

* Path as argument to readPersistentKeys.
Spaces in comments

* readPersistentKeys test

* Debug and info

* Index check in test

* Update tests/v2/test_waku_rln_relay.nim

Co-authored-by: G. <28568419+s1fr0@users.noreply.github.com>

* Abstracted writeRlnCredentials.
Fix var name in test.

* Usage of writeRlnCredentials in test

* Dnsclient?

* Test reverted to direct call to writeFile.
Abstrated writePersistentRlnCredentials usage causing error,
with readPersistentRlnCredentials

* Indentation

* Revert "Dnsclient?"

This reverts commit 3f4dba1a0b.

* Reverting abstraction of writing..
..persiting credential

Co-authored-by: Daniel Kaiser <git@kais3r.de>
Co-authored-by: Keshav Gupta <keshav.pg@hotmail.com>
Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com>
Co-authored-by: G. <28568419+s1fr0@users.noreply.github.com>
This commit is contained in:
Keshav Gupta 2022-08-05 12:48:01 +02:00 committed by GitHub
parent eebaffdfce
commit 115982f5c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 8 deletions

4
.gitignore vendored
View File

@ -36,4 +36,6 @@ node_modules/
/.update.timestamp
# Ignore Jetbrains IDE files
.idea/
.idea/
rlnCredentials.txt
testPath.txt

View File

@ -6,6 +6,7 @@ import
testutils/unittests, chronos, chronicles, stint,
stew/byteutils, stew/shims/net as stewNet,
libp2p/crypto/crypto,
json,
../../waku/v2/protocol/waku_rln_relay/[rln, waku_rln_relay_utils,
waku_rln_relay_types],
../../waku/v2/node/wakunode2,
@ -720,3 +721,39 @@ suite "Waku rln relay":
# check that the conversion has not distorted the original value
check:
keypair.get().idCommitment == idCommitment
test "Read Persistent RLN credentials":
# create an RLN instance
var rlnInstance = createRLNInstance()
check:
rlnInstance.isOk == true
var key = membershipKeyGen(rlnInstance.value)
var empty: array[32, byte]
check:
key.isSome
key.get().idKey.len == 32
key.get().idCommitment.len == 32
key.get().idKey != empty
key.get().idCommitment != empty
debug "the generated membership key pair: ", key
let
k = key.get()
index = MembershipIndex(1)
var rlnMembershipCredentials = RlnMembershipCredentials(membershipKeyPair: k, rlnIndex: index)
let path = "testPath.txt"
# Write RLN credentials
writeFile(path, pretty(%rlnMembershipCredentials))
var credentials = readPersistentRlnCredentials(path)
check:
credentials.membershipKeyPair == k
credentials.rlnIndex == index

View File

@ -38,6 +38,12 @@ type MembershipKeyPair* = object
# more details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
idCommitment*: IDCommitment
type MembershipIndex* = uint
type RlnMembershipCredentials* = object
membershipKeyPair*: MembershipKeyPair
rlnIndex*: MembershipIndex
type RateLimitProof* = object
## RateLimitProof holds the public inputs to rln circuit as
## defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Public-Inputs
@ -56,8 +62,6 @@ type RateLimitProof* = object
## see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Nullifiers
nullifier*: Nullifier
type MembershipIndex* = uint
type ProofMetadata* = object
nullifier*: Nullifier
shareX*: MerkleNode
@ -87,6 +91,10 @@ type WakuRLNRelay* = ref object
type MessageValidationResult* {.pure.} = enum
Valid, Invalid, Spam
# RLN membership key and index files path
const
RLN_CREDENTIALS_FILEPATH* = "rlnCredentials.txt"
# inputs of the membership contract constructor
# TODO may be able to make these constants private and put them inside the waku_rln_relay_utils
const

View File

@ -2,6 +2,8 @@
import
std/sequtils, tables, times,
std/streams,
std/os,
chronicles, options, chronos, stint,
confutils,
web3, json,
@ -741,7 +743,6 @@ proc mountRlnRelayStatic*(node: WakuNode,
node.wakuRlnRelay = rlnPeer
proc mountRlnRelayDynamic*(node: WakuNode,
ethClientAddr: string = "",
ethAccAddr: web3.Address,
@ -788,9 +789,19 @@ proc mountRlnRelayDynamic*(node: WakuNode,
else: # if no eth private key is available, skip registration
debug "running waku-rln-relay in relay-only mode"
else:
debug "Peer is already registered to the membership contract"
keyPair = memKeyPair.get()
rlnIndex = memIndex.get()
var
rlnMembershipCredentials = RlnMembershipCredentials(membershipKeyPair: keyPair, rlnIndex: rlnIndex)
# Since the files are stored as a raw text file, it is highly susceptible to theft.
# The files needs some encryption to resolve this.
# Write RLN credentials
writeFile(RLN_CREDENTIALS_FILEPATH, pretty(%rlnMembershipCredentials))
# create the WakuRLNRelay
var rlnPeer = WakuRLNRelay(membershipKeyPair: keyPair,
membershipIndex: rlnIndex,
@ -821,8 +832,21 @@ proc mountRlnRelayDynamic*(node: WakuNode,
node.wakuRlnRelay = rlnPeer
proc readPersistentRlnCredentials*(path: string) : RlnMembershipCredentials {.raises: [Defect, OSError, IOError, Exception].} =
info "Rln credentials exist in file"
# With regards to printing the keys, it is purely for debugging purposes so that the user becomes explicitly aware of the current keys in use when nwaku is started.
# Note that this is only until the RLN contract being used is the one deployed on Goerli testnet.
# These prints need to omitted once RLN contract is deployed on Ethereum mainnet and using valuable funds for staking.
let entireRlnCredentialsFile = readFile(path)
proc mountRlnRelay*(node: WakuNode, conf: WakuNodeConf|Chat2Conf, spamHandler: Option[SpamHandler] = none(SpamHandler)) {.raises: [Defect, ValueError, IOError, CatchableError].} =
let jsonObject = parseJson(entireRlnCredentialsFile)
let deserializedRlnCredentials = to(jsonObject, RlnMembershipCredentials)
debug "Deserialized Rln credentials", rlnCredentials=deserializedRlnCredentials
result = deserializedRlnCredentials
proc mountRlnRelay*(node: WakuNode, conf: WakuNodeConf|Chat2Conf, spamHandler: Option[SpamHandler] = none(SpamHandler)) {.raises: [Defect, ValueError, IOError, CatchableError, Exception].} =
if not conf.rlnRelayDynamic:
info " setting up waku-rln-relay in on-chain mode... "
# set up rln relay inputs
@ -866,9 +890,18 @@ proc mountRlnRelay*(node: WakuNode, conf: WakuNodeConf|Chat2Conf, spamHandler: O
let keyPair = @[(rlnRelayId, rlnRelayIdCommitmentKey)]
let memKeyPair = keyPair.toMembershipKeyPairs()[0]
# mount the rln relay protocol in the on-chain/dynamic mode
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, memKeyPair = some(memKeyPair), memIndex = some(rlnRelayIndex), ethAccAddr = ethAccountAddr, ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler)
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr,
memKeyPair = some(memKeyPair), memIndex = some(rlnRelayIndex), ethAccAddr = ethAccountAddr,
ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler)
elif fileExists(RLN_CREDENTIALS_FILEPATH):
var credentials = readPersistentRlnCredentials(RLN_CREDENTIALS_FILEPATH)
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr,
memKeyPair = some(credentials.membershipKeyPair), memIndex = some(credentials.rlnIndex), ethAccAddr = ethAccountAddr,
ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler)
else:
# no rln credential is provided
# mount the rln relay protocol in the on-chain/dynamic mode
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccAddr = ethAccountAddr, ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler)
info "no rln credential is provided"
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr,
ethAccAddr = ethAccountAddr, ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, pubsubTopic = conf.rlnRelayPubsubTopic,
contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler)