mirror of https://github.com/waku-org/nwaku.git
Basic proof gen and vrfy (#421)
* adds the proof field to the WakuMessage * adds a basic zkProof api * adds proof gen to the publish proc * relocates the proofGen and proofVrfy to rln_relay_utils * wip: test of proof gen * adds a procedure to pass rln-relay message validator, adds the proof gen * tests the proof gen and verify * relocates zkp API * adds documentation and todos * adds todos and documentations * removes an unnecessary comment * adds todos
This commit is contained in:
parent
b3208b343f
commit
d64aadc8ad
|
@ -394,4 +394,58 @@ procSuite "WakuNode":
|
||||||
await node1.stop()
|
await node1.stop()
|
||||||
await node2.stop()
|
await node2.stop()
|
||||||
await node3.stop()
|
await node3.stop()
|
||||||
|
asyncTest "testing rln-relay with mocked zkp":
|
||||||
|
|
||||||
|
let
|
||||||
|
# publisher node
|
||||||
|
nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node1 = WakuNode.init(nodeKey1, ValidIpAddress.init("0.0.0.0"), Port(60000))
|
||||||
|
# Relay node
|
||||||
|
nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node2 = WakuNode.init(nodeKey2, ValidIpAddress.init("0.0.0.0"), Port(60002))
|
||||||
|
# Subscriber
|
||||||
|
nodeKey3 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node3 = WakuNode.init(nodeKey3, ValidIpAddress.init("0.0.0.0"), Port(60003))
|
||||||
|
|
||||||
|
pubSubTopic = "defaultTopic"
|
||||||
|
contentTopic1 = ContentTopic(1)
|
||||||
|
payload = "hello world".toBytes()
|
||||||
|
message1 = WakuMessage(payload: payload, contentTopic: contentTopic1)
|
||||||
|
|
||||||
|
# start all the nodes
|
||||||
|
await node1.start()
|
||||||
|
node1.mountRelay(@[pubSubTopic])
|
||||||
|
|
||||||
|
await node2.start()
|
||||||
|
node2.mountRelay(@[pubSubTopic])
|
||||||
|
node2.addRLNRelayValidator(pubSubTopic)
|
||||||
|
|
||||||
|
await node3.start()
|
||||||
|
node3.mountRelay(@[pubSubTopic])
|
||||||
|
|
||||||
|
await node1.connectToNodes(@[node2.peerInfo])
|
||||||
|
await node3.connectToNodes(@[node2.peerInfo])
|
||||||
|
|
||||||
|
var completionFut = newFuture[bool]()
|
||||||
|
proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} =
|
||||||
|
let msg = WakuMessage.init(data)
|
||||||
|
if msg.isOk():
|
||||||
|
let val = msg.value()
|
||||||
|
debug "The received topic:", topic
|
||||||
|
if topic == pubSubTopic:
|
||||||
|
completionFut.complete(true)
|
||||||
|
|
||||||
|
|
||||||
|
node3.subscribe(pubSubTopic, relayHandler)
|
||||||
|
await sleepAsync(2000.millis)
|
||||||
|
|
||||||
|
await node1.publish(pubSubTopic, message1, rlnRelayEnabled = true)
|
||||||
|
await sleepAsync(2000.millis)
|
||||||
|
|
||||||
|
|
||||||
|
check:
|
||||||
|
(await completionFut.withTimeout(10.seconds)) == true
|
||||||
|
|
||||||
|
await node1.stop()
|
||||||
|
await node2.stop()
|
||||||
|
await node3.stop()
|
||||||
|
|
|
@ -8,9 +8,10 @@ import
|
||||||
libp2p/crypto/crypto,
|
libp2p/crypto/crypto,
|
||||||
libp2p/protocols/protocol,
|
libp2p/protocols/protocol,
|
||||||
# NOTE For TopicHandler, solve with exports?
|
# NOTE For TopicHandler, solve with exports?
|
||||||
|
libp2p/protocols/pubsub/rpc/messages,
|
||||||
libp2p/protocols/pubsub/pubsub,
|
libp2p/protocols/pubsub/pubsub,
|
||||||
libp2p/standard_setup,
|
libp2p/standard_setup,
|
||||||
../protocol/[waku_relay, message_notifier],
|
../protocol/[waku_relay, waku_message, message_notifier],
|
||||||
../protocol/waku_store/waku_store,
|
../protocol/waku_store/waku_store,
|
||||||
../protocol/waku_swap/waku_swap,
|
../protocol/waku_swap/waku_swap,
|
||||||
../protocol/waku_filter/waku_filter,
|
../protocol/waku_filter/waku_filter,
|
||||||
|
@ -239,17 +240,26 @@ proc unsubscribe*(node: WakuNode, request: FilterRequest) {.async, gcsafe.} =
|
||||||
waku_node_filters.set(node.filters.len.int64)
|
waku_node_filters.set(node.filters.len.int64)
|
||||||
|
|
||||||
|
|
||||||
proc publish*(node: WakuNode, topic: Topic, message: WakuMessage) {.async, gcsafe.} =
|
proc publish*(node: WakuNode, topic: Topic, message: WakuMessage, rlnRelayEnabled: bool = false) {.async, gcsafe.} =
|
||||||
## Publish a `WakuMessage` to a PubSub topic. `WakuMessage` should contain a
|
## Publish a `WakuMessage` to a PubSub topic. `WakuMessage` should contain a
|
||||||
## `contentTopic` field for light node functionality. This field may be also
|
## `contentTopic` field for light node functionality. This field may be also
|
||||||
## be omitted.
|
## be omitted.
|
||||||
##
|
##
|
||||||
## Status: Implemented.
|
## Status: Implemented.
|
||||||
##
|
## When rlnRelayEnabled is true, a zkp will be generated and attached to the message (it is an experimental feature)
|
||||||
|
|
||||||
let wakuRelay = node.wakuRelay
|
let wakuRelay = node.wakuRelay
|
||||||
|
|
||||||
debug "publish", topic=topic, contentTopic=message.contentTopic
|
debug "publish", topic=topic, contentTopic=message.contentTopic
|
||||||
|
var publishingMessage = message
|
||||||
|
|
||||||
|
if rlnRelayEnabled:
|
||||||
|
# if rln relay is enabled then a proof must be generated and added to the waku message
|
||||||
|
let
|
||||||
|
proof = proofGen(message.payload)
|
||||||
|
## TODO here since the message is immutable we have to make a copy of it and then attach the proof to its duplicate
|
||||||
|
## TODO however, it might be better to change message type to mutable (i.e., var) so that we can add the proof field to the original message
|
||||||
|
publishingMessage = WakuMessage(payload: message.payload, contentTopic: message.contentTopic, version: message.version, proof: proof)
|
||||||
|
|
||||||
let data = message.encode().buffer
|
let data = message.encode().buffer
|
||||||
|
|
||||||
discard await wakuRelay.publish(topic, data)
|
discard await wakuRelay.publish(topic, data)
|
||||||
|
@ -343,6 +353,20 @@ proc mountRlnRelay*(node: WakuNode, ethClientAddress: Option[string] = none(stri
|
||||||
node.wakuRlnRelay = rlnPeer
|
node.wakuRlnRelay = rlnPeer
|
||||||
|
|
||||||
|
|
||||||
|
proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: string) =
|
||||||
|
## this procedure is a thin wrapper for the pubsub addValidator method
|
||||||
|
## it sets message validator on the given pubsubTopic, the validator will check that
|
||||||
|
## all the messages published in the pubsubTopic have a valid zero-knowledge proof
|
||||||
|
proc validator(topic: string, message: messages.Message): Future[ValidationResult] {.async.} =
|
||||||
|
let msg = WakuMessage.init(message.data)
|
||||||
|
if msg.isOk():
|
||||||
|
# check the proof
|
||||||
|
if proofVrfy(msg.value().payload, msg.value().proof):
|
||||||
|
result = ValidationResult.Accept
|
||||||
|
# set a validator for the pubsubTopic
|
||||||
|
let pb = PubSub(node.wakuRelay)
|
||||||
|
pb.addValidator(pubsubTopic, validator)
|
||||||
|
|
||||||
proc mountRelay*(node: WakuNode, topics: seq[string] = newSeq[string](), rlnRelayEnabled = false) {.gcsafe.} =
|
proc mountRelay*(node: WakuNode, topics: seq[string] = newSeq[string](), rlnRelayEnabled = false) {.gcsafe.} =
|
||||||
let wakuRelay = WakuRelay.init(
|
let wakuRelay = WakuRelay.init(
|
||||||
switch = node.switch,
|
switch = node.switch,
|
||||||
|
@ -376,8 +400,11 @@ proc mountRelay*(node: WakuNode, topics: seq[string] = newSeq[string](), rlnRela
|
||||||
# TODO pass rln relay inputs to this proc, right now it uses default values that are set in the mountRlnRelay proc
|
# TODO pass rln relay inputs to this proc, right now it uses default values that are set in the mountRlnRelay proc
|
||||||
info "WakuRLNRelay is enabled"
|
info "WakuRLNRelay is enabled"
|
||||||
waitFor mountRlnRelay(node)
|
waitFor mountRlnRelay(node)
|
||||||
|
# TODO currently the message validator is set for the defaultTopic, this can be configurable to accept other pubsub topics as well
|
||||||
|
addRLNRelayValidator(node, defaultTopic)
|
||||||
info "WakuRLNRelay is mounted successfully"
|
info "WakuRLNRelay is mounted successfully"
|
||||||
|
|
||||||
|
|
||||||
## Helpers
|
## Helpers
|
||||||
proc dialPeer*(n: WakuNode, address: string) {.async.} =
|
proc dialPeer*(n: WakuNode, address: string) {.async.} =
|
||||||
info "dialPeer", address = address
|
info "dialPeer", address = address
|
||||||
|
|
|
@ -16,6 +16,9 @@ type
|
||||||
payload*: seq[byte]
|
payload*: seq[byte]
|
||||||
contentTopic*: ContentTopic
|
contentTopic*: ContentTopic
|
||||||
version*: uint32
|
version*: uint32
|
||||||
|
# the proof field indicates that the message is not a spam
|
||||||
|
# this field will be used in the rln-relay protocol
|
||||||
|
proof*: seq[byte]
|
||||||
|
|
||||||
# Encoding and decoding -------------------------------------------------------
|
# Encoding and decoding -------------------------------------------------------
|
||||||
proc init*(T: type WakuMessage, buffer: seq[byte]): ProtoResult[T] =
|
proc init*(T: type WakuMessage, buffer: seq[byte]): ProtoResult[T] =
|
||||||
|
@ -25,6 +28,7 @@ proc init*(T: type WakuMessage, buffer: seq[byte]): ProtoResult[T] =
|
||||||
discard ? pb.getField(1, msg.payload)
|
discard ? pb.getField(1, msg.payload)
|
||||||
discard ? pb.getField(2, msg.contentTopic)
|
discard ? pb.getField(2, msg.contentTopic)
|
||||||
discard ? pb.getField(3, msg.version)
|
discard ? pb.getField(3, msg.version)
|
||||||
|
discard ? pb.getField(4, msg.proof)
|
||||||
|
|
||||||
ok(msg)
|
ok(msg)
|
||||||
|
|
||||||
|
@ -34,3 +38,4 @@ proc encode*(message: WakuMessage): ProtoBuffer =
|
||||||
result.write(1, message.payload)
|
result.write(1, message.payload)
|
||||||
result.write(2, message.contentTopic)
|
result.write(2, message.contentTopic)
|
||||||
result.write(3, message.version)
|
result.write(3, message.version)
|
||||||
|
result.write(4, message.proof)
|
||||||
|
|
|
@ -66,4 +66,6 @@ proc hash*(ctx: ptr RLNBn256, inputs_buffer:ptr Buffer, input_len: ptr csize_t,
|
||||||
# output_buffer: *mut Buffer,
|
# output_buffer: *mut Buffer,
|
||||||
# ) -> bool
|
# ) -> bool
|
||||||
|
|
||||||
{.pop.}
|
{.pop.}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import
|
import
|
||||||
chronicles, options, chronos, stint,
|
chronicles, options, chronos, stint, sequtils,
|
||||||
web3,
|
web3,
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
eth/keys,
|
eth/keys,
|
||||||
|
@ -98,4 +98,12 @@ proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} =
|
||||||
discard await sender.register(pk).send(MembershipFee)
|
discard await sender.register(pk).send(MembershipFee)
|
||||||
# TODO check the receipt and then return true/false
|
# TODO check the receipt and then return true/false
|
||||||
await web3.close()
|
await web3.close()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
proc proofGen*(data: seq[byte]): seq[byte] =
|
||||||
|
# TODO to implement the actual proof generation logic
|
||||||
|
return "proof".toBytes()
|
||||||
|
|
||||||
|
proc proofVrfy*(data, proof: seq[byte]): bool =
|
||||||
|
# TODO to implement the actual proof verification logic
|
||||||
|
return true
|
Loading…
Reference in New Issue