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(rln-relay): modify keystore credentials logic #1956

Merged
merged 6 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions apps/chat2/chat2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,10 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
let rlnConf = WakuRlnConfig(
rlnRelayDynamic: conf.rlnRelayDynamic,
rlnRelayCredIndex: conf.rlnRelayCredIndex,
rlnRelayMembershipGroupIndex: conf.rlnRelayMembershipGroupIndex,
rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress,
rlnRelayEthClientAddress: conf.rlnRelayEthClientAddress,
rlnRelayCredPath: conf.rlnRelayCredPath,
rlnRelayCredentialsPassword: conf.rlnRelayCredentialsPassword
rlnRelayCredPassword: conf.rlnRelayCredPassword
)

waitFor node.mountRlnRelay(rlnConf,
Expand Down
7 changes: 1 addition & 6 deletions apps/chat2/config_chat2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,6 @@ type
defaultValue: 0
name: "rln-relay-cred-index" }: uint

rlnRelayMembershipGroupIndex* {.
desc: "the index of credentials to use, within a specific rln membership set",
defaultValue: 0
name: "rln-relay-membership-group-index" }: uint

rymnc marked this conversation as resolved.
Show resolved Hide resolved
rlnRelayDynamic* {.
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
defaultValue: false
Expand All @@ -267,7 +262,7 @@ type
defaultValue: ""
name: "rln-relay-eth-contract-address" }: string

rlnRelayCredentialsPassword* {.
rlnRelayCredPassword* {.
desc: "Password for encrypting RLN credentials",
defaultValue: ""
name: "rln-relay-cred-password" }: string
Expand Down
3 changes: 1 addition & 2 deletions apps/wakunode2/app.nim
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,10 @@ proc setupProtocols(node: WakuNode,
let rlnConf = WakuRlnConfig(
rlnRelayDynamic: conf.rlnRelayDynamic,
rlnRelayCredIndex: conf.rlnRelayCredIndex,
rlnRelayMembershipGroupIndex: conf.rlnRelayMembershipGroupIndex,
rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress,
rlnRelayEthClientAddress: conf.rlnRelayEthClientAddress,
rlnRelayCredPath: conf.rlnRelayCredPath,
rlnRelayCredentialsPassword: conf.rlnRelayCredentialsPassword,
rlnRelayCredPassword: conf.rlnRelayCredPassword,
rlnRelayTreePath: conf.rlnRelayTreePath,
rlnRelayBandwidthThreshold: conf.rlnRelayBandwidthThreshold
)
Expand Down
7 changes: 1 addition & 6 deletions apps/wakunode2/external_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,6 @@ type
defaultValue: 0
name: "rln-relay-membership-index" }: uint

rlnRelayMembershipGroupIndex* {.
desc: "the index of credentials to use, within a specific rln membership set",
defaultValue: 0
name: "rln-relay-membership-group-index" }: uint

rlnRelayDynamic* {.
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
defaultValue: false
Expand All @@ -180,7 +175,7 @@ type
defaultValue: ""
name: "rln-relay-eth-contract-address" }: string

rlnRelayCredentialsPassword* {.
rlnRelayCredPassword* {.
desc: "Password for encrypting RLN credentials",
defaultValue: ""
name: "rln-relay-cred-password" }: string
Expand Down
115 changes: 25 additions & 90 deletions tests/test_waku_keystore.nim
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{.used.}

import
std/[algorithm, json, options, os],
testutils/unittests, chronos, stint
std/[os, json],
chronos,
testutils/unittests
import
../../waku/waku_keystore,
./testlib/common
Expand Down Expand Up @@ -44,7 +45,7 @@ procSuite "Credentials test suite":
keystore["appIdentifier"].getStr() == testAppInfo.appIdentifier
keystore["version"].getStr() == testAppInfo.version
# We assume the loaded keystore to not have credentials set (previous tests delete the keystore at filepath)
keystore["credentials"].getElems().len() == 0
keystore["credentials"].len() == 0

test "Add credentials to keystore":

Expand All @@ -61,30 +62,15 @@ procSuite "Credentials test suite":
var idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)

var contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
var index1 = MembershipIndex(1)
var membershipGroup1 = MembershipGroup(membershipContract: contract, treeIndex: index1)

let membershipCredentials1 = MembershipCredentials(identityCredential: idCredential,
membershipGroups: @[membershipGroup1])

# We generate a random identity credential (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
idTrapdoor = randomSeqByte(rng[], 32)
idNullifier = randomSeqByte(rng[], 32)
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)

idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)

var index2 = MembershipIndex(2)
var membershipGroup2 = MembershipGroup(membershipContract: contract, treeIndex: index2)

let membershipCredentials2 = MembershipCredentials(identityCredential: idCredential,
membershipGroups: @[membershipGroup2])
var index = MembershipIndex(1)

let membershipCredential = KeystoreMembership(membershipContract: contract,
treeIndex: index,
identityCredential: idCredential)
let password = "%m0um0ucoW%"

let keystoreRes = addMembershipCredentials(path = filepath,
credentials = @[membershipCredentials1, membershipCredentials2],
membership = membershipCredential,
password = password,
appInfo = testAppInfo)

Expand All @@ -98,93 +84,42 @@ procSuite "Credentials test suite":

# We generate two random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
var
idTrapdoor1 = randomSeqByte(rng[], 32)
idNullifier1 = randomSeqByte(rng[], 32)
idSecretHash1 = randomSeqByte(rng[], 32)
idCommitment1 = randomSeqByte(rng[], 32)
idCredential1 = IdentityCredential(idTrapdoor: idTrapdoor1, idNullifier: idNullifier1, idSecretHash: idSecretHash1, idCommitment: idCommitment1)

var
idTrapdoor2 = randomSeqByte(rng[], 32)
idNullifier2 = randomSeqByte(rng[], 32)
idSecretHash2 = randomSeqByte(rng[], 32)
idCommitment2 = randomSeqByte(rng[], 32)
idCredential2 = IdentityCredential(idTrapdoor: idTrapdoor2, idNullifier: idNullifier2, idSecretHash: idSecretHash2, idCommitment: idCommitment2)
idTrapdoor = randomSeqByte(rng[], 32)
idNullifier = randomSeqByte(rng[], 32)
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)
idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)

# We generate two distinct membership groups
var contract1 = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
var index1 = MembershipIndex(1)
var membershipGroup1 = MembershipGroup(membershipContract: contract1, treeIndex: index1)

var contract2 = MembershipContract(chainId: "6", address: "0x0000000000000000000000000000000000000000")
var index2 = MembershipIndex(2)
var membershipGroup2 = MembershipGroup(membershipContract: contract2, treeIndex: index2)

# We generate three membership credentials
let membershipCredentials1 = MembershipCredentials(identityCredential: idCredential1,
membershipGroups: @[membershipGroup1])

let membershipCredentials2 = MembershipCredentials(identityCredential: idCredential2,
membershipGroups: @[membershipGroup2])

let membershipCredentials3 = MembershipCredentials(identityCredential: idCredential1,
membershipGroups: @[membershipGroup2])
var contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
var index = MembershipIndex(1)
var membershipCredential = KeystoreMembership(membershipContract: contract,
treeIndex: index,
identityCredential: idCredential)

# This is the same as rlnMembershipCredentials3, should not change the keystore entry of idCredential
let membershipCredentials4 = MembershipCredentials(identityCredential: idCredential1,
membershipGroups: @[membershipGroup2])

let password = "%m0um0ucoW%"

# We add credentials to the keystore. Note that only 3 credentials should be effectively added, since rlnMembershipCredentials3 is equal to membershipCredentials2
let keystoreRes = addMembershipCredentials(path = filepath,
credentials = @[membershipCredentials1, membershipCredentials2, membershipCredentials3, membershipCredentials4],
membership = membershipCredential,
password = password,
appInfo = testAppInfo)

check:
keystoreRes.isOk()

# We test retrieval of credentials.
var expectedMembershipGroups1 = @[membershipGroup1, membershipGroup2]
expectedMembershipGroups1.sort(sortMembershipGroup)
let expectedCredential1 = MembershipCredentials(identityCredential: idCredential1,
membershipGroups: expectedMembershipGroups1)


var expectedMembershipGroups2 = @[membershipGroup2]
expectedMembershipGroups2.sort(sortMembershipGroup)
let expectedCredential2 = MembershipCredentials(identityCredential: idCredential2,
membershipGroups: expectedMembershipGroups2)
var expectedMembership = membershipCredential
let membershipQuery = KeystoreMembership(membershipContract: contract,
treeIndex: index)


# We retrieve all credentials stored under password (no filter)
var recoveredCredentialsRes = getMembershipCredentials(path = filepath,
password = password,
query = membershipQuery,
appInfo = testAppInfo)

check:
recoveredCredentialsRes.isOk()
recoveredCredentialsRes.get() == @[expectedCredential1, expectedCredential2]


# We retrieve credentials by filtering on an IdentityCredential
recoveredCredentialsRes = getMembershipCredentials(path = filepath,
password = password,
filterIdentityCredentials = @[idCredential1],
appInfo = testAppInfo)

check:
recoveredCredentialsRes.isOk()
recoveredCredentialsRes.get() == @[expectedCredential1]

# We retrieve credentials by filtering on multiple IdentityCredentials
recoveredCredentialsRes = getMembershipCredentials(path = filepath,
password = password,
filterIdentityCredentials = @[idCredential1, idCredential2],
appInfo = testAppInfo)

check:
recoveredCredentialsRes.isOk()
recoveredCredentialsRes.get() == @[expectedCredential1, expectedCredential2]
recoveredCredentialsRes.get() == expectedMembership

51 changes: 27 additions & 24 deletions tests/waku_rln_relay/test_waku_rln_relay.nim
Original file line number Diff line number Diff line change
Expand Up @@ -815,10 +815,14 @@ suite "Waku rln relay":

let index = MembershipIndex(1)

let rlnMembershipContract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
let rlnMembershipGroup = MembershipGroup(membershipContract: rlnMembershipContract, treeIndex: index)
let rlnMembershipCredentials = MembershipCredentials(identityCredential: idCredential, membershipGroups: @[rlnMembershipGroup])

let keystoreMembership = KeystoreMembership(
membershipContract: MembershipContract(
chainId: "5",
address: "0x0123456789012345678901234567890123456789"
),
treeIndex: index,
identityCredential: idCredential,
)
let password = "%m0um0ucoW%"

let filepath = "./testRLNCredentials.txt"
Expand All @@ -827,30 +831,29 @@ suite "Waku rln relay":
# Write RLN credentials
require:
addMembershipCredentials(path = filepath,
credentials = @[rlnMembershipCredentials],
password = password,
appInfo = RLNAppInfo).isOk()
membership = keystoreMembership,
password = password,
appInfo = RLNAppInfo).isOk()

let readCredentialsResult = getMembershipCredentials(path = filepath,
let readKeystoreRes = getMembershipCredentials(path = filepath,
password = password,
filterMembershipContracts = @[rlnMembershipContract],
# here the query would not include
# the identityCredential,
# since it is not part of the query
# but have used the same value
# to avoid re-declaration
query = keystoreMembership,
appInfo = RLNAppInfo)

require:
readCredentialsResult.isOk()

# getMembershipCredentials returns all credentials in keystore as sequence matching the filter
let allMatchingCredentials = readCredentialsResult.get()
# if any is found, we return the first credential, otherwise credentials is none
var credentials = none(MembershipCredentials)
if allMatchingCredentials.len() > 0:
credentials = some(allMatchingCredentials[0])

require:
credentials.isSome()
assert readKeystoreRes.isOk(), $readKeystoreRes.error

# getMembershipCredentials returns the credential in the keystore which matches
# the query, in this case the query is =
# chainId = "5" and
# address = "0x0123456789012345678901234567890123456789" and
# treeIndex = 1
let readKeystoreMembership = readKeystoreRes.get()
check:
credentials.get().identityCredential == idCredential
credentials.get().membershipGroups == @[rlnMembershipGroup]
readKeystoreMembership == keystoreMembership

test "histogram static bucket generation":
let buckets = generateBucketsForHistogram(10)
Expand Down
16 changes: 7 additions & 9 deletions tools/rln_keystore_generator/rln_keystore_generator.nim
Original file line number Diff line number Diff line change
Expand Up @@ -79,19 +79,17 @@ when isMainModule:
debug "Transaction hash", txHash = groupManager.registrationTxHash.get()

# 6. write to keystore
let keystoreCred = MembershipCredentials(
let keystoreCred = KeystoreMembership(
membershipContract: MembershipContract(
chainId: $groupManager.chainId.get(),
address: conf.rlnRelayEthContractAddress,
),
treeIndex: groupManager.membershipIndex.get(),
identityCredential: credential,
membershipGroups: @[MembershipGroup(
membershipContract: MembershipContract(
chainId: $groupManager.chainId.get(),
address: conf.rlnRelayEthContractAddress,
),
treeIndex: groupManager.membershipIndex.get(),
)]
)

let persistRes = addMembershipCredentials(conf.rlnRelayCredPath,
@[keystoreCred],
keystoreCred,
conf.rlnRelayCredPassword,
RLNAppInfo)
if persistRes.isErr():
Expand Down
16 changes: 9 additions & 7 deletions waku/waku_keystore/conversion_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,24 @@ import
stew/[results, byteutils],
./protocol_types

# Encodes a Membership credential to a byte sequence
proc encode*(credential: MembershipCredentials): seq[byte] =
# Encodes a KeystoreMembership credential to a byte sequence
proc encode*(credential: KeystoreMembership): seq[byte] =
# TODO: use custom encoding, avoid wordy json
var stringCredential: string
# NOTE: toUgly appends to the string, doesn't replace its contents
stringCredential.toUgly(%credential)
return toBytes(stringCredential)

# Decodes a byte sequence to a Membership credential
proc decode*(encodedCredential: seq[byte]): KeystoreResult[MembershipCredentials] =
# Decodes a byte sequence to a KeystoreMembership credential
proc decode*(encodedCredential: seq[byte]): KeystoreResult[KeystoreMembership] =
# TODO: use custom decoding, avoid wordy json
try:
# we parse the json decrypted keystoreCredential
let jsonObject = parseJson(string.fromBytes(encodedCredential))
return ok(to(jsonObject, MembershipCredentials))
return ok(to(jsonObject, KeystoreMembership))
except JsonParsingError:
return err(KeystoreJsonError)
return err(AppKeystoreError(kind: KeystoreJsonError,
msg: getCurrentExceptionMsg()))
except Exception: #parseJson raises Exception
return err(KeystoreOsError)
return err(AppKeystoreError(kind: KeystoreOsError,
msg: getCurrentExceptionMsg()))
Loading
Loading