Skip to content

Commit

Permalink
fix(rln-relay): modify keystore credentials logic (#1956)
Browse files Browse the repository at this point in the history
* fix(rln-relay): modify keystore credentials logic

fix: bump version

* Update waku/waku_rln_relay/group_manager/on_chain/group_manager.nim

Co-authored-by: Ivan Folgueira Bande <128452529+Ivansete-status@users.noreply.github.com>

* Update tests/waku_rln_relay/test_waku_rln_relay.nim

Co-authored-by: Ivan Folgueira Bande <128452529+Ivansete-status@users.noreply.github.com>

* Update waku/waku_keystore/protocol_types.nim

Co-authored-by: Ivan Folgueira Bande <128452529+Ivansete-status@users.noreply.github.com>

* fix: greatly improve error handling

* fix: display proc and appropriate assert

---------

Co-authored-by: Ivan Folgueira Bande <128452529+Ivansete-status@users.noreply.github.com>
  • Loading branch information
rymnc and Ivansete-status committed Aug 29, 2023
1 parent ac25855 commit e7b2b88
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 318 deletions.
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

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()))

0 comments on commit e7b2b88

Please sign in to comment.