fix(rln-relay): feature guard

This commit is contained in:
rymnc 2022-11-11 16:28:24 +05:30
parent 07833ce313
commit 9344f41a34
No known key found for this signature in database
GPG Key ID: C740033EE3F41EBD
5 changed files with 1610 additions and 1602 deletions

View File

@ -86,6 +86,7 @@ type
wakuFilter*: WakuFilter wakuFilter*: WakuFilter
wakuFilterClient*: WakuFilterClient wakuFilterClient*: WakuFilterClient
wakuSwap*: WakuSwap wakuSwap*: WakuSwap
when defined(rln):
wakuRlnRelay*: WakuRLNRelay wakuRlnRelay*: WakuRLNRelay
wakuLightPush*: WakuLightPush wakuLightPush*: WakuLightPush
wakuLightpushClient*: WakuLightPushClient wakuLightpushClient*: WakuLightPushClient

View File

@ -40,6 +40,7 @@ type WakuMessage* = object
# the proof field indicates that the message is not a spam # the proof field indicates that the message is not a spam
# this field will be used in the rln-relay protocol # this field will be used in the rln-relay protocol
# XXX Experimental, this is part of https://rfc.vac.dev/spec/17/ spec and not yet part of WakuMessage spec # XXX Experimental, this is part of https://rfc.vac.dev/spec/17/ spec and not yet part of WakuMessage spec
when defined(rln):
proof*: RateLimitProof proof*: RateLimitProof
# The ephemeral field indicates if the message should # The ephemeral field indicates if the message should
# be stored. bools and uints are # be stored. bools and uints are
@ -56,6 +57,7 @@ proc encode*(message: WakuMessage): ProtoBuffer =
buf.write3(2, message.contentTopic) buf.write3(2, message.contentTopic)
buf.write3(3, message.version) buf.write3(3, message.version)
buf.write3(10, zint64(message.timestamp)) buf.write3(10, zint64(message.timestamp))
when defined(rln):
buf.write3(21, message.proof.encode()) buf.write3(21, message.proof.encode())
buf.write3(31, uint64(message.ephemeral)) buf.write3(31, uint64(message.ephemeral))
buf.finish3() buf.finish3()
@ -75,6 +77,7 @@ proc decode*(T: type WakuMessage, buffer: seq[byte]): ProtoResult[T] =
msg.timestamp = Timestamp(timestamp) msg.timestamp = Timestamp(timestamp)
# XXX Experimental, this is part of https://rfc.vac.dev/spec/17/ spec # XXX Experimental, this is part of https://rfc.vac.dev/spec/17/ spec
when defined(rln):
var proofBytes: seq[byte] var proofBytes: seq[byte]
discard ?pb.getField(21, proofBytes) discard ?pb.getField(21, proofBytes)
msg.proof = ?RateLimitProof.init(proofBytes) msg.proof = ?RateLimitProof.init(proofBytes)

View File

@ -1,41 +1,43 @@
import import
stint stint
# Acceptable roots for merkle root validation of incoming messages when defined(rln):
const AcceptableRootWindowSize* = 5
# RLN membership key and index files path # Acceptable roots for merkle root validation of incoming messages
const const AcceptableRootWindowSize* = 5
# RLN membership key and index files path
const
RlnCredentialsFilename* = "rlnCredentials.txt" RlnCredentialsFilename* = "rlnCredentials.txt"
# inputs of the membership contract constructor # inputs of the membership contract constructor
# TODO may be able to make these constants private and put them inside the waku_rln_relay_utils # TODO may be able to make these constants private and put them inside the waku_rln_relay_utils
const const
MembershipFee* = 1000000000000000.u256 MembershipFee* = 1000000000000000.u256
# the current implementation of the rln lib supports a circuit for Merkle tree with depth 20 # the current implementation of the rln lib supports a circuit for Merkle tree with depth 20
MerkleTreeDepth* = 20 MerkleTreeDepth* = 20
EthClient* = "ws://127.0.0.1:8540" EthClient* = "ws://127.0.0.1:8540"
const const
# the size of poseidon hash output in bits # the size of poseidon hash output in bits
HashBitSize* = 256 HashBitSize* = 256
# the size of poseidon hash output as the number hex digits # the size of poseidon hash output as the number hex digits
HashHexSize* = int(HashBitSize/4) HashHexSize* = int(HashBitSize/4)
const const
# The relative folder where the circuit, proving and verification key for RLN can be found # The relative folder where the circuit, proving and verification key for RLN can be found
# Note that resources has to be compiled with respect to the above MerkleTreeDepth # Note that resources has to be compiled with respect to the above MerkleTreeDepth
RlnResourceFolder* = "vendor/zerokit/rln/resources/tree_height_" & $MerkleTreeDepth & "/" RlnResourceFolder* = "vendor/zerokit/rln/resources/tree_height_" & $MerkleTreeDepth & "/"
# temporary variables to test waku-rln-relay performance in the static group mode # temporary variables to test waku-rln-relay performance in the static group mode
const const
StaticGroupSize* = 100 StaticGroupSize* = 100
# StaticGroupKeys is a static list of 100 membership keys in the form of (identity key, identity commitment) # StaticGroupKeys is a static list of 100 membership keys in the form of (identity key, identity commitment)
# keys are created locally, using createMembershipList proc from waku_rln_relay_utils module, and the results are hardcoded in here # keys are created locally, using createMembershipList proc from waku_rln_relay_utils module, and the results are hardcoded in here
# this list is temporary and is created to test the performance of waku-rln-relay for the static groups # this list is temporary and is created to test the performance of waku-rln-relay for the static groups
# in the later versions, this static hardcoded group will be replaced with a dynamic one # in the later versions, this static hardcoded group will be replaced with a dynamic one
const const
StaticGroupKeys* = @[("2c0198101a2828a0ac6c9e58fc131e1bd83326a4f748ef592588eeb8c3112dc1", StaticGroupKeys* = @[("2c0198101a2828a0ac6c9e58fc131e1bd83326a4f748ef592588eeb8c3112dc1",
"1ca742a54641e2de14c5cb87ad707fd869693f682cedb901e47b8138918aecb3"), ( "1ca742a54641e2de14c5cb87ad707fd869693f682cedb901e47b8138918aecb3"), (
"095177fd334629dbc29c5fc9e32addecfcb6a42f9673268810fa9f70d1a8191a", "095177fd334629dbc29c5fc9e32addecfcb6a42f9673268810fa9f70d1a8191a",

View File

@ -16,11 +16,12 @@ import
type RlnRelayResult*[T] = Result[T, string] type RlnRelayResult*[T] = Result[T, string]
## RLN is a Nim wrapper for the data types used in zerokit RLN when defined(rln):
type RLN* {.incompleteStruct.} = object ## RLN is a Nim wrapper for the data types used in zerokit RLN
type RLNResult* = RlnRelayResult[ptr RLN] type RLN* {.incompleteStruct.} = object
type RLNResult* = RlnRelayResult[ptr RLN]
type type
# identity key as defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership # identity key as defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
IDKey* = array[32, byte] IDKey* = array[32, byte]
# hash of identity key as defined ed in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership # hash of identity key as defined ed in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
@ -31,8 +32,8 @@ type
RlnIdentifier* = array[32, byte] RlnIdentifier* = array[32, byte]
ZKSNARK* = array[128, byte] ZKSNARK* = array[128, byte]
# Custom data types defined for waku rln relay ------------------------- # Custom data types defined for waku rln relay -------------------------
type MembershipKeyPair* = object type MembershipKeyPair* = object
## user's identity key (a secret key) which is selected randomly ## user's identity key (a secret key) which is selected randomly
## see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership ## see details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
idKey*: IDKey idKey*: IDKey
@ -41,7 +42,7 @@ type MembershipKeyPair* = object
# more details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership # more details in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
idCommitment*: IDCommitment idCommitment*: IDCommitment
type RateLimitProof* = object type RateLimitProof* = object
## RateLimitProof holds the public inputs to rln circuit as ## RateLimitProof holds the public inputs to rln circuit as
## defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Public-Inputs ## defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Public-Inputs
## the `proof` field carries the actual zkSNARK proof ## the `proof` field carries the actual zkSNARK proof
@ -61,18 +62,18 @@ type RateLimitProof* = object
## Application specific RLN Identifier ## Application specific RLN Identifier
rlnIdentifier*: RlnIdentifier rlnIdentifier*: RlnIdentifier
type MembershipIndex* = uint type MembershipIndex* = uint
type RlnMembershipCredentials* = object type RlnMembershipCredentials* = object
membershipKeyPair*: MembershipKeyPair membershipKeyPair*: MembershipKeyPair
rlnIndex*: MembershipIndex rlnIndex*: MembershipIndex
type ProofMetadata* = object type ProofMetadata* = object
nullifier*: Nullifier nullifier*: Nullifier
shareX*: MerkleNode shareX*: MerkleNode
shareY*: MerkleNode shareY*: MerkleNode
type WakuRLNRelay* = ref object type WakuRLNRelay* = ref object
membershipKeyPair*: MembershipKeyPair membershipKeyPair*: MembershipKeyPair
# membershipIndex denotes the index of a leaf in the Merkle tree # membershipIndex denotes the index of a leaf in the Merkle tree
# that contains the pk of the current peer # that contains the pk of the current peer
@ -97,7 +98,7 @@ type WakuRLNRelay* = ref object
lastSeenMembershipIndex*: MembershipIndex # the last seen membership index lastSeenMembershipIndex*: MembershipIndex # the last seen membership index
lastProcessedBlock*: BlockNumber # the last processed block number lastProcessedBlock*: BlockNumber # the last processed block number
type type
MessageValidationResult* {.pure.} = enum MessageValidationResult* {.pure.} = enum
Valid, Valid,
Invalid, Invalid,
@ -105,8 +106,8 @@ type
MerkleNodeResult* = RlnRelayResult[MerkleNode] MerkleNodeResult* = RlnRelayResult[MerkleNode]
RateLimitProofResult* = RlnRelayResult[RateLimitProof] RateLimitProofResult* = RlnRelayResult[RateLimitProof]
# Protobufs enc and init # Protobufs enc and init
proc init*(T: type RateLimitProof, buffer: seq[byte]): ProtoResult[T] = proc init*(T: type RateLimitProof, buffer: seq[byte]): ProtoResult[T] =
var nsp: RateLimitProof var nsp: RateLimitProof
let pb = initProtoBuffer(buffer) let pb = initProtoBuffer(buffer)
@ -140,7 +141,7 @@ proc init*(T: type RateLimitProof, buffer: seq[byte]): ProtoResult[T] =
return ok(nsp) return ok(nsp)
proc encode*(nsp: RateLimitProof): ProtoBuffer = proc encode*(nsp: RateLimitProof): ProtoBuffer =
var output = initProtoBuffer() var output = initProtoBuffer()
output.write3(1, nsp.proof) output.write3(1, nsp.proof)

View File

@ -63,7 +63,8 @@ proc toBuffer*(x: openArray[byte]): Buffer =
let output = Buffer(`ptr`: cast[ptr uint8](baseAddr), len: uint(temp.len)) let output = Buffer(`ptr`: cast[ptr uint8](baseAddr), len: uint(temp.len))
return output return output
proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult = when defined(rln):
proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult =
## generates an instance of RLN ## generates an instance of RLN
## An RLN instance supports both zkSNARKs logics and Merkle tree data structure and operations ## An RLN instance supports both zkSNARKs logics and Merkle tree data structure and operations
## d indicates the depth of Merkle tree ## d indicates the depth of Merkle tree
@ -81,7 +82,7 @@ proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult =
return err("error in parameters generation") return err("error in parameters generation")
return ok(rlnInstance) return ok(rlnInstance)
proc membershipKeyGen*(ctxPtr: ptr RLN): RlnRelayResult[MembershipKeyPair] = proc membershipKeyGen*(ctxPtr: ptr RLN): RlnRelayResult[MembershipKeyPair] =
## generates a MembershipKeyPair that can be used for the registration into the rln membership contract ## generates a MembershipKeyPair that can be used for the registration into the rln membership contract
## Returns an error if the key generation fails ## Returns an error if the key generation fails
@ -112,7 +113,7 @@ proc membershipKeyGen*(ctxPtr: ptr RLN): RlnRelayResult[MembershipKeyPair] =
return ok(keypair) return ok(keypair)
proc createRLNInstance*(d: int = MerkleTreeDepth): RLNResult = proc createRLNInstance*(d: int = MerkleTreeDepth): RLNResult =
## Wraps the rln instance creation for metrics ## Wraps the rln instance creation for metrics
## Returns an error if the instance creation fails ## Returns an error if the instance creation fails
var res: RLNResult var res: RLNResult
@ -120,26 +121,26 @@ proc createRLNInstance*(d: int = MerkleTreeDepth): RLNResult =
res = createRLNInstanceLocal(d) res = createRLNInstanceLocal(d)
return res return res
proc toUInt256*(idCommitment: IDCommitment): UInt256 = proc toUInt256*(idCommitment: IDCommitment): UInt256 =
let pk = UInt256.fromBytesLE(idCommitment) let pk = UInt256.fromBytesLE(idCommitment)
return pk return pk
proc toIDCommitment*(idCommitmentUint: UInt256): IDCommitment = proc toIDCommitment*(idCommitmentUint: UInt256): IDCommitment =
let pk = IDCommitment(idCommitmentUint.toBytesLE()) let pk = IDCommitment(idCommitmentUint.toBytesLE())
return pk return pk
proc inHex*(value: IDKey or IDCommitment or MerkleNode or Nullifier or Epoch or RlnIdentifier): string = proc inHex*(value: IDKey or IDCommitment or MerkleNode or Nullifier or Epoch or RlnIdentifier): string =
var valueHex = (UInt256.fromBytesLE(value)).toHex var valueHex = (UInt256.fromBytesLE(value)).toHex
# We pad leading zeroes # We pad leading zeroes
while valueHex.len < value.len * 2: while valueHex.len < value.len * 2:
valueHex = "0" & valueHex valueHex = "0" & valueHex
return valueHex return valueHex
proc toMembershipIndex(v: UInt256): MembershipIndex = proc toMembershipIndex(v: UInt256): MembershipIndex =
let membershipIndex: MembershipIndex = cast[MembershipIndex](v) let membershipIndex: MembershipIndex = cast[MembershipIndex](v)
return membershipIndex return membershipIndex
proc register*(idComm: IDCommitment, ethAccountAddress: Option[Address], ethAccountPrivKey: keys.PrivateKey, ethClientAddress: string, membershipContractAddress: Address, registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)): Future[Result[MembershipIndex, string]] {.async.} = proc register*(idComm: IDCommitment, ethAccountAddress: Option[Address], ethAccountPrivKey: keys.PrivateKey, ethClientAddress: string, membershipContractAddress: Address, registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)): Future[Result[MembershipIndex, string]] {.async.} =
# TODO may need to also get eth Account Private Key as PrivateKey # TODO may need to also get eth Account Private Key as PrivateKey
## registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress ## registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress
@ -201,7 +202,7 @@ proc register*(idComm: IDCommitment, ethAccountAddress: Option[Address], ethAcco
handler(toHex(txHash)) handler(toHex(txHash))
return ok(toMembershipIndex(eventIndex)) return ok(toMembershipIndex(eventIndex))
proc register*(rlnPeer: WakuRLNRelay, registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)): Future[RlnRelayResult[bool]] {.async.} = proc register*(rlnPeer: WakuRLNRelay, registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)): Future[RlnRelayResult[bool]] {.async.} =
## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey ## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey
## into the membership contract whose address is in rlnPeer.membershipContractAddress ## into the membership contract whose address is in rlnPeer.membershipContractAddress
let pk = rlnPeer.membershipKeyPair.idCommitment let pk = rlnPeer.membershipKeyPair.idCommitment
@ -210,7 +211,7 @@ proc register*(rlnPeer: WakuRLNRelay, registrationHandler: Option[RegistrationHa
return err(regResult.error()) return err(regResult.error())
return ok(true) return ok(true)
proc appendLength*(input: openArray[byte]): seq[byte] = proc appendLength*(input: openArray[byte]): seq[byte] =
## returns length prefixed version of the input ## returns length prefixed version of the input
## with the following format [len<8>|input<var>] ## with the following format [len<8>|input<var>]
## len: 8-byte value that represents the number of bytes in the `input` ## len: 8-byte value that represents the number of bytes in the `input`
@ -222,7 +223,7 @@ proc appendLength*(input: openArray[byte]): seq[byte] =
output = concat(@len, @input) output = concat(@len, @input)
return output return output
proc hash*(rlnInstance: ptr RLN, data: openArray[byte]): MerkleNode = proc hash*(rlnInstance: ptr RLN, data: openArray[byte]): MerkleNode =
## a thin layer on top of the Nim wrapper of the Poseidon hasher ## a thin layer on top of the Nim wrapper of the Poseidon hasher
debug "hash input", hashhex = data.toHex() debug "hash input", hashhex = data.toHex()
var lenPrefData = appendLength(data) var lenPrefData = appendLength(data)
@ -237,7 +238,7 @@ proc hash*(rlnInstance: ptr RLN, data: openArray[byte]): MerkleNode =
return output return output
proc serialize(idKey: IDKey, memIndex: MembershipIndex, epoch: Epoch, proc serialize(idKey: IDKey, memIndex: MembershipIndex, epoch: Epoch,
msg: openArray[byte]): seq[byte] = msg: openArray[byte]): seq[byte] =
## a private proc to convert RateLimitProof and the data to a byte seq ## a private proc to convert RateLimitProof and the data to a byte seq
## this conversion is used in the proofGen proc ## this conversion is used in the proofGen proc
@ -248,7 +249,7 @@ proc serialize(idKey: IDKey, memIndex: MembershipIndex, epoch: Epoch,
let output = concat(@idKey, @memIndexBytes, @epoch, lenPrefMsg) let output = concat(@idKey, @memIndexBytes, @epoch, lenPrefMsg)
return output return output
proc proofGen*(rlnInstance: ptr RLN, data: openArray[byte], proc proofGen*(rlnInstance: ptr RLN, data: openArray[byte],
memKeys: MembershipKeyPair, memIndex: MembershipIndex, memKeys: MembershipKeyPair, memIndex: MembershipIndex,
epoch: Epoch): RateLimitProofResult = epoch: Epoch): RateLimitProofResult =
@ -308,7 +309,7 @@ proc proofGen*(rlnInstance: ptr RLN, data: openArray[byte],
return ok(output) return ok(output)
proc serialize(proof: RateLimitProof, data: openArray[byte]): seq[byte] = proc serialize(proof: RateLimitProof, data: openArray[byte]): seq[byte] =
## a private proc to convert RateLimitProof and data to a byte seq ## a private proc to convert RateLimitProof and data to a byte seq
## this conversion is used in the proof verification proc ## this conversion is used in the proof verification proc
## [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ] ## [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
@ -324,16 +325,16 @@ proc serialize(proof: RateLimitProof, data: openArray[byte]): seq[byte] =
return proofBytes return proofBytes
# Serializes a sequence of MerkleNodes # Serializes a sequence of MerkleNodes
proc serialize(roots: seq[MerkleNode]): seq[byte] = proc serialize(roots: seq[MerkleNode]): seq[byte] =
var rootsBytes: seq[byte] = @[] var rootsBytes: seq[byte] = @[]
for root in roots: for root in roots:
rootsBytes = concat(rootsBytes, @root) rootsBytes = concat(rootsBytes, @root)
return rootsBytes return rootsBytes
# validRoots should contain a sequence of roots in the acceptable windows. # validRoots should contain a sequence of roots in the acceptable windows.
# As default, it is set to an empty sequence of roots. This implies that the validity check for the proof's root is skipped # As default, it is set to an empty sequence of roots. This implies that the validity check for the proof's root is skipped
proc proofVerify*(rlnInstance: ptr RLN, proc proofVerify*(rlnInstance: ptr RLN,
data: openArray[byte], data: openArray[byte],
proof: RateLimitProof, proof: RateLimitProof,
validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] = validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] =
@ -359,7 +360,7 @@ proc proofVerify*(rlnInstance: ptr RLN,
else: else:
return ok(true) return ok(true)
proc insertMember*(rlnInstance: ptr RLN, idComm: IDCommitment): bool = proc insertMember*(rlnInstance: ptr RLN, idComm: IDCommitment): bool =
## inserts a member to the tree ## inserts a member to the tree
## returns true if the member is inserted successfully ## returns true if the member is inserted successfully
## returns false if the member could not be inserted ## returns false if the member could not be inserted
@ -370,7 +371,7 @@ proc insertMember*(rlnInstance: ptr RLN, idComm: IDCommitment): bool =
let memberAdded = update_next_member(rlnInstance, pkBufferPtr) let memberAdded = update_next_member(rlnInstance, pkBufferPtr)
return memberAdded return memberAdded
proc serializeIdCommitments*(idComms: seq[IDCommitment]): seq[byte] = proc serializeIdCommitments*(idComms: seq[IDCommitment]): seq[byte] =
## serializes a seq of IDCommitments to a byte seq ## serializes a seq of IDCommitments to a byte seq
## the serialization is based on https://github.com/status-im/nwaku/blob/37bd29fbc37ce5cf636734e7dd410b1ed27b88c8/waku/v2/protocol/waku_rln_relay/rln.nim#L142 ## the serialization is based on https://github.com/status-im/nwaku/blob/37bd29fbc37ce5cf636734e7dd410b1ed27b88c8/waku/v2/protocol/waku_rln_relay/rln.nim#L142
## the order of serialization is |id_commitment_len<8>|id_commitment<var>| ## the order of serialization is |id_commitment_len<8>|id_commitment<var>|
@ -385,7 +386,7 @@ proc serializeIdCommitments*(idComms: seq[IDCommitment]): seq[byte] =
return idCommsBytes return idCommsBytes
proc insertMembers*(rlnInstance: ptr RLN, proc insertMembers*(rlnInstance: ptr RLN,
index: MembershipIndex, index: MembershipIndex,
idComms: seq[IDCommitment]): bool = idComms: seq[IDCommitment]): bool =
## Insert multiple members i.e., identity commitments ## Insert multiple members i.e., identity commitments
@ -402,11 +403,11 @@ proc insertMembers*(rlnInstance: ptr RLN,
let membersAdded = set_leaves_from(rlnInstance, index, idCommsBufferPtr) let membersAdded = set_leaves_from(rlnInstance, index, idCommsBufferPtr)
return membersAdded return membersAdded
proc removeMember*(rlnInstance: ptr RLN, index: MembershipIndex): bool = proc removeMember*(rlnInstance: ptr RLN, index: MembershipIndex): bool =
let deletion_success = delete_member(rlnInstance, index) let deletion_success = delete_member(rlnInstance, index)
return deletion_success return deletion_success
proc getMerkleRoot*(rlnInstance: ptr RLN): MerkleNodeResult = proc getMerkleRoot*(rlnInstance: ptr RLN): MerkleNodeResult =
# read the Merkle Tree root after insertion # read the Merkle Tree root after insertion
var var
root {.noinit.}: Buffer = Buffer() root {.noinit.}: Buffer = Buffer()
@ -420,7 +421,7 @@ proc getMerkleRoot*(rlnInstance: ptr RLN): MerkleNodeResult =
var rootValue = cast[ptr MerkleNode] (root.`ptr`)[] var rootValue = cast[ptr MerkleNode] (root.`ptr`)[]
return ok(rootValue) return ok(rootValue)
proc updateValidRootQueue*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): void = proc updateValidRootQueue*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): void =
## updates the valid Merkle root queue with the latest root and pops the oldest one when the capacity of `AcceptableRootWindowSize` is reached ## updates the valid Merkle root queue with the latest root and pops the oldest one when the capacity of `AcceptableRootWindowSize` is reached
let overflowCount = wakuRlnRelay.validMerkleRoots.len() - AcceptableRootWindowSize let overflowCount = wakuRlnRelay.validMerkleRoots.len() - AcceptableRootWindowSize
if overflowCount >= 0: if overflowCount >= 0:
@ -430,7 +431,7 @@ proc updateValidRootQueue*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): void =
# Push the next root into the queue # Push the next root into the queue
wakuRlnRelay.validMerkleRoots.addLast(root) wakuRlnRelay.validMerkleRoots.addLast(root)
proc insertMembers*(wakuRlnRelay: WakuRLNRelay, proc insertMembers*(wakuRlnRelay: WakuRLNRelay,
index: MembershipIndex, index: MembershipIndex,
idComms: seq[IDCommitment]): RlnRelayResult[void] = idComms: seq[IDCommitment]): RlnRelayResult[void] =
## inserts a sequence of id commitments into the local merkle tree, and adds the changed root to the ## inserts a sequence of id commitments into the local merkle tree, and adds the changed root to the
@ -445,7 +446,7 @@ proc insertMembers*(wakuRlnRelay: WakuRLNRelay,
wakuRlnRelay.updateValidRootQueue(rootAfterUpdate) wakuRlnRelay.updateValidRootQueue(rootAfterUpdate)
return ok() return ok()
proc removeMember*(wakuRlnRelay: WakuRLNRelay, index: MembershipIndex): RlnRelayResult[void] = proc removeMember*(wakuRlnRelay: WakuRLNRelay, index: MembershipIndex): RlnRelayResult[void] =
## removes a commitment from the local merkle tree at `index`, and adds the changed root to the ## removes a commitment from the local merkle tree at `index`, and adds the changed root to the
## queue of valid roots ## queue of valid roots
## Returns an error if the removal fails ## Returns an error if the removal fails
@ -458,11 +459,11 @@ proc removeMember*(wakuRlnRelay: WakuRLNRelay, index: MembershipIndex): RlnRelay
wakuRlnRelay.updateValidRootQueue(rootAfterUpdate) wakuRlnRelay.updateValidRootQueue(rootAfterUpdate)
return ok() return ok()
proc validateRoot*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): bool = proc validateRoot*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): bool =
## Validate against the window of roots stored in wakuRlnRelay.validMerkleRoots ## Validate against the window of roots stored in wakuRlnRelay.validMerkleRoots
return root in wakuRlnRelay.validMerkleRoots return root in wakuRlnRelay.validMerkleRoots
proc toMembershipKeyPairs*(groupKeys: seq[(string, string)]): RlnRelayResult[seq[ proc toMembershipKeyPairs*(groupKeys: seq[(string, string)]): RlnRelayResult[seq[
MembershipKeyPair]] = MembershipKeyPair]] =
## groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format ## groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format
## the toMembershipKeyPairs proc populates a sequence of MembershipKeyPairs using the supplied groupKeys ## the toMembershipKeyPairs proc populates a sequence of MembershipKeyPairs using the supplied groupKeys
@ -482,7 +483,7 @@ proc toMembershipKeyPairs*(groupKeys: seq[(string, string)]): RlnRelayResult[seq
return err("could not convert the group key to bytes: " & err.msg) return err("could not convert the group key to bytes: " & err.msg)
return ok(groupKeyPairs) return ok(groupKeyPairs)
proc calcMerkleRoot*(list: seq[IDCommitment]): RlnRelayResult[string] = proc calcMerkleRoot*(list: seq[IDCommitment]): RlnRelayResult[string] =
## returns the root of the Merkle tree that is computed from the supplied list ## returns the root of the Merkle tree that is computed from the supplied list
## the root is in hexadecimal format ## the root is in hexadecimal format
## Returns an error if the computation fails ## Returns an error if the computation fails
@ -499,7 +500,7 @@ proc calcMerkleRoot*(list: seq[IDCommitment]): RlnRelayResult[string] =
let root = rln.getMerkleRoot().value().inHex() let root = rln.getMerkleRoot().value().inHex()
return ok(root) return ok(root)
proc createMembershipList*(n: int): RlnRelayResult[( proc createMembershipList*(n: int): RlnRelayResult[(
seq[(string, string)], string seq[(string, string)], string
)] = )] =
## createMembershipList produces a sequence of membership key pairs in the form of (identity key, id commitment keys) in the hexadecimal format ## createMembershipList produces a sequence of membership key pairs in the form of (identity key, id commitment keys) in the hexadecimal format
@ -535,7 +536,7 @@ proc createMembershipList*(n: int): RlnRelayResult[(
let root = rln.getMerkleRoot().value().inHex() let root = rln.getMerkleRoot().value().inHex()
return ok((output, root)) return ok((output, root))
proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): RlnRelayResult[(Option[seq[ proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): RlnRelayResult[(Option[seq[
IDCommitment]], Option[MembershipKeyPair], Option[ IDCommitment]], Option[MembershipKeyPair], Option[
MembershipIndex])] = MembershipIndex])] =
## rlnRelayStaticSetUp is a proc that is used to initialize the static group keys and the static membership index ## rlnRelayStaticSetUp is a proc that is used to initialize the static group keys and the static membership index
@ -575,7 +576,7 @@ proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): RlnRelayRes
return ok((groupOpt, memKeyPairOpt, memIndexOpt)) return ok((groupOpt, memKeyPairOpt, memIndexOpt))
proc hasDuplicate*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] = proc hasDuplicate*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] =
## returns true if there is another message in the `nullifierLog` of the `rlnPeer` with the same ## returns true if there is another message in the `nullifierLog` of the `rlnPeer` with the same
## epoch and nullifier as `msg`'s epoch and nullifier but different Shamir secret shares ## epoch and nullifier as `msg`'s epoch and nullifier but different Shamir secret shares
## otherwise, returns false ## otherwise, returns false
@ -608,7 +609,7 @@ proc hasDuplicate*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool
except KeyError as e: except KeyError as e:
return err("the epoch was not found") return err("the epoch was not found")
proc updateLog*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] = proc updateLog*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] =
## extracts the `ProofMetadata` of the supplied messages `msg` and ## extracts the `ProofMetadata` of the supplied messages `msg` and
## saves it in the `nullifierLog` of the `rlnPeer` ## saves it in the `nullifierLog` of the `rlnPeer`
## Returns an error if it cannot update the log ## Returns an error if it cannot update the log
@ -632,7 +633,7 @@ proc updateLog*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] =
except KeyError as e: except KeyError as e:
return err("the epoch was not found") return err("the epoch was not found")
proc toEpoch*(t: uint64): Epoch = proc toEpoch*(t: uint64): Epoch =
## converts `t` to `Epoch` in little-endian order ## converts `t` to `Epoch` in little-endian order
let bytes = toBytes(t, Endianness.littleEndian) let bytes = toBytes(t, Endianness.littleEndian)
debug "bytes", bytes = bytes debug "bytes", bytes = bytes
@ -640,22 +641,22 @@ proc toEpoch*(t: uint64): Epoch =
discard epoch.copyFrom(bytes) discard epoch.copyFrom(bytes)
return epoch return epoch
proc fromEpoch*(epoch: Epoch): uint64 = proc fromEpoch*(epoch: Epoch): uint64 =
## decodes bytes of `epoch` (in little-endian) to uint64 ## decodes bytes of `epoch` (in little-endian) to uint64
let t = fromBytesLE(uint64, array[32, byte](epoch)) let t = fromBytesLE(uint64, array[32, byte](epoch))
return t return t
proc calcEpoch*(t: float64): Epoch = proc calcEpoch*(t: float64): Epoch =
## gets time `t` as `flaot64` with subseconds resolution in the fractional part ## gets time `t` as `flaot64` with subseconds resolution in the fractional part
## and returns its corresponding rln `Epoch` value ## and returns its corresponding rln `Epoch` value
let e = uint64(t/EpochUnitSeconds) let e = uint64(t/EpochUnitSeconds)
return toEpoch(e) return toEpoch(e)
proc getCurrentEpoch*(): Epoch = proc getCurrentEpoch*(): Epoch =
## gets the current rln Epoch time ## gets the current rln Epoch time
return calcEpoch(epochTime()) return calcEpoch(epochTime())
proc absDiff*(e1, e2: Epoch): uint64 = proc absDiff*(e1, e2: Epoch): uint64 =
## returns the absolute difference between the two rln `Epoch`s `e1` and `e2` ## returns the absolute difference between the two rln `Epoch`s `e1` and `e2`
## i.e., e1 - e2 ## i.e., e1 - e2
@ -670,7 +671,7 @@ proc absDiff*(e1, e2: Epoch): uint64 =
else: else:
return epoch2 - epoch1 return epoch2 - epoch1
proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage, proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage,
timeOption: Option[float64] = none(float64)): MessageValidationResult = timeOption: Option[float64] = none(float64)): MessageValidationResult =
## validate the supplied `msg` based on the waku-rln-relay routing protocol i.e., ## validate the supplied `msg` based on the waku-rln-relay routing protocol i.e.,
## the `msg`'s epoch is within MaxEpochGap of the current epoch ## the `msg`'s epoch is within MaxEpochGap of the current epoch
@ -751,7 +752,7 @@ proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage,
waku_rln_valid_messages_total.observe(rootIndex.toFloat()) waku_rln_valid_messages_total.observe(rootIndex.toFloat())
return MessageValidationResult.Valid return MessageValidationResult.Valid
proc toRLNSignal*(wakumessage: WakuMessage): seq[byte] = proc toRLNSignal*(wakumessage: WakuMessage): seq[byte] =
## it is a utility proc that prepares the `data` parameter of the proof generation procedure i.e., `proofGen` that resides in the current module ## it is a utility proc that prepares the `data` parameter of the proof generation procedure i.e., `proofGen` that resides in the current module
## it extracts the `contentTopic` and the `payload` of the supplied `wakumessage` and serializes them into a byte sequence ## it extracts the `contentTopic` and the `payload` of the supplied `wakumessage` and serializes them into a byte sequence
let let
@ -759,7 +760,7 @@ proc toRLNSignal*(wakumessage: WakuMessage): seq[byte] =
output = concat(wakumessage.payload, contentTopicBytes) output = concat(wakumessage.payload, contentTopicBytes)
return output return output
proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage, proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage,
senderEpochTime: float64): bool = senderEpochTime: float64): bool =
## returns true if it can create and append a `RateLimitProof` to the supplied `msg` ## returns true if it can create and append a `RateLimitProof` to the supplied `msg`
## returns false otherwise ## returns false otherwise
@ -779,7 +780,7 @@ proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage,
msg.proof = proof.value msg.proof = proof.value
return true return true
proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResult[void] = proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResult[void] =
# add members to the Merkle tree of the `rlnInstance` # add members to the Merkle tree of the `rlnInstance`
## Returns an error if it cannot add any member to the Merkle tree ## Returns an error if it cannot add any member to the Merkle tree
let membersAdded = wakuRlnRelay.insertMembers(0, list) let membersAdded = wakuRlnRelay.insertMembers(0, list)
@ -787,7 +788,7 @@ proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResul
return err("failed to add members to the Merkle tree") return err("failed to add members to the Merkle tree")
return ok() return ok()
proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler = proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler =
## assuming all the members arrive in order ## assuming all the members arrive in order
## TODO: check the index and the pubkey depending on ## TODO: check the index and the pubkey depending on
## the group update operation ## the group update operation
@ -813,7 +814,7 @@ proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler =
return ok() return ok()
return handler return handler
proc parse*(event: type MemberRegistered, proc parse*(event: type MemberRegistered,
log: JsonNode): RlnRelayResult[MembershipTuple] = log: JsonNode): RlnRelayResult[MembershipTuple] =
## parses the `data` parameter of the `MemberRegistered` event `log` ## parses the `data` parameter of the `MemberRegistered` event `log`
## returns an error if it cannot parse the `data` parameter ## returns an error if it cannot parse the `data` parameter
@ -836,8 +837,8 @@ proc parse*(event: type MemberRegistered,
except: except:
return err("failed to parse the data field of the MemberRegistered event") return err("failed to parse the data field of the MemberRegistered event")
type BlockTable = OrderedTable[BlockNumber, seq[MembershipTuple]] type BlockTable = OrderedTable[BlockNumber, seq[MembershipTuple]]
proc getHistoricalEvents*(ethClientUri: string, proc getHistoricalEvents*(ethClientUri: string,
contractAddress: Address, contractAddress: Address,
fromBlock: string = "0x0", fromBlock: string = "0x0",
toBlock: string = "latest"): Future[RlnRelayResult[BlockTable]] {.async, gcsafe.} = toBlock: string = "latest"): Future[RlnRelayResult[BlockTable]] {.async, gcsafe.} =
@ -871,7 +872,7 @@ proc getHistoricalEvents*(ethClientUri: string,
blockTable[blockNumber] = @[parsedEvent] blockTable[blockNumber] = @[parsedEvent]
return ok(blockTable) return ok(blockTable)
proc subscribeToGroupEvents*(ethClientUri: string, proc subscribeToGroupEvents*(ethClientUri: string,
ethAccountAddress: Option[Address] = none(Address), ethAccountAddress: Option[Address] = none(Address),
contractAddress: Address, contractAddress: Address,
blockNumber: string = "0x0", blockNumber: string = "0x0",
@ -937,7 +938,7 @@ proc subscribeToGroupEvents*(ethClientUri: string,
web3.onDisconnect = proc() = web3.onDisconnect = proc() =
debug "connection to ethereum node dropped", lastBlock = latestBlock debug "connection to ethereum node dropped", lastBlock = latestBlock
proc handleGroupUpdates*(rlnPeer: WakuRLNRelay) {.async, gcsafe.} = proc handleGroupUpdates*(rlnPeer: WakuRLNRelay) {.async, gcsafe.} =
## generates the groupUpdateHandler which is called when a new member is registered, ## generates the groupUpdateHandler which is called when a new member is registered,
## and has the WakuRLNRelay instance as a closure ## and has the WakuRLNRelay instance as a closure
let handler = generateGroupUpdateHandler(rlnPeer) let handler = generateGroupUpdateHandler(rlnPeer)
@ -946,7 +947,7 @@ proc handleGroupUpdates*(rlnPeer: WakuRLNRelay) {.async, gcsafe.} =
contractAddress = rlnPeer.membershipContractAddress, contractAddress = rlnPeer.membershipContractAddress,
handler = handler) handler = handler)
proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: PubsubTopic, contentTopic: ContentTopic, spamHandler: Option[SpamHandler] = none(SpamHandler)) = proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: PubsubTopic, contentTopic: ContentTopic, spamHandler: Option[SpamHandler] = none(SpamHandler)) =
## this procedure is a thin wrapper for the pubsub addValidator method ## this procedure is a thin wrapper for the pubsub addValidator method
## it sets a validator for the waku messages published on the supplied pubsubTopic and contentTopic ## it sets a validator for the waku messages published on the supplied pubsubTopic and contentTopic
## if contentTopic is empty, then validation takes place for All the messages published on the given pubsubTopic ## if contentTopic is empty, then validation takes place for All the messages published on the given pubsubTopic
@ -993,7 +994,7 @@ proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: PubsubTopic, contentTopi
let pb = PubSub(node.wakuRelay) let pb = PubSub(node.wakuRelay)
pb.addValidator(pubsubTopic, validator) pb.addValidator(pubsubTopic, validator)
proc mountRlnRelayStatic*(node: WakuNode, proc mountRlnRelayStatic*(node: WakuNode,
group: seq[IDCommitment], group: seq[IDCommitment],
memKeyPair: MembershipKeyPair, memKeyPair: MembershipKeyPair,
memIndex: MembershipIndex, memIndex: MembershipIndex,
@ -1044,7 +1045,7 @@ proc mountRlnRelayStatic*(node: WakuNode,
node.wakuRlnRelay = rlnPeer node.wakuRlnRelay = rlnPeer
return ok() return ok()
proc mountRlnRelayDynamic*(node: WakuNode, proc mountRlnRelayDynamic*(node: WakuNode,
ethClientAddr: string = "", ethClientAddr: string = "",
ethAccountAddress: Option[web3.Address] = none(web3.Address), ethAccountAddress: Option[web3.Address] = none(web3.Address),
ethAccountPrivKeyOpt: Option[keys.PrivateKey], ethAccountPrivKeyOpt: Option[keys.PrivateKey],
@ -1127,7 +1128,7 @@ proc mountRlnRelayDynamic*(node: WakuNode,
node.wakuRlnRelay = rlnPeer node.wakuRlnRelay = rlnPeer
return ok() return ok()
proc writeRlnCredentials*(path: string, proc writeRlnCredentials*(path: string,
credentials: RlnMembershipCredentials, credentials: RlnMembershipCredentials,
password: string): RlnRelayResult[void] = password: string): RlnRelayResult[void] =
# Returns RlnRelayResult[void], which indicates the success of the call # Returns RlnRelayResult[void], which indicates the success of the call
@ -1141,9 +1142,9 @@ proc writeRlnCredentials*(path: string,
return err("Error while saving keyfile for RLN credentials") return err("Error while saving keyfile for RLN credentials")
return ok() return ok()
# Attempts decryptions of all keyfiles with the provided password. # Attempts decryptions of all keyfiles with the provided password.
# If one or more credentials are successfully decrypted, the max(min(index,number_decrypted),0)-th is returned. # If one or more credentials are successfully decrypted, the max(min(index,number_decrypted),0)-th is returned.
proc readRlnCredentials*(path: string, proc readRlnCredentials*(path: string,
password: string, password: string,
index: int = 0): RlnRelayResult[Option[RlnMembershipCredentials]] = index: int = 0): RlnRelayResult[Option[RlnMembershipCredentials]] =
# Returns RlnRelayResult[Option[RlnMembershipCredentials]], which indicates the success of the call # Returns RlnRelayResult[Option[RlnMembershipCredentials]], which indicates the success of the call
@ -1172,7 +1173,7 @@ proc readRlnCredentials*(path: string,
except: except:
return err("Error while loading keyfile for RLN credentials at " & path) return err("Error while loading keyfile for RLN credentials at " & path)
proc mount(node: WakuNode, proc mount(node: WakuNode,
conf: WakuRlnConfig, conf: WakuRlnConfig,
spamHandler: Option[SpamHandler] = none(SpamHandler), spamHandler: Option[SpamHandler] = none(SpamHandler),
registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler) registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)
@ -1317,7 +1318,7 @@ proc mount(node: WakuNode,
return err("dynamic rln-relay could not be mounted: " & res.error()) return err("dynamic rln-relay could not be mounted: " & res.error())
return ok() return ok()
proc mountRlnRelay*(node: WakuNode, proc mountRlnRelay*(node: WakuNode,
conf: WakuRlnConfig, conf: WakuRlnConfig,
spamHandler: Option[SpamHandler] = none(SpamHandler), spamHandler: Option[SpamHandler] = none(SpamHandler),
registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler) registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)