mirror of https://github.com/waku-org/nwaku.git
feat(waku-stealth-commitments): waku stealth commitment protocol (#2490)
* feat(waku-stealth-commitments): initialize app * feat: works! * fix: readme * feat: send and receive, handle received stealth commitment * fix: remove empty lines * chore: move to examples
This commit is contained in:
parent
e692edf6c1
commit
0def4904f2
|
@ -0,0 +1,38 @@
|
|||
# wakustealthcommitments
|
||||
|
||||
This application/tool/protocol is used to securely communicate requests and responses for the [Stealth Address Scheme](https://eips.ethereum.org/EIPS/eip-5564)
|
||||
|
||||
Uses TWN config as default, and content topic: `/wakustealthcommitments/1/app/proto`
|
||||
|
||||
## Usage
|
||||
|
||||
1. Clone the erc-5564-bn254 repo and build the static lib
|
||||
```sh
|
||||
gh repo clone rymnc/erc-5564-bn254
|
||||
cd erc-5564-bn254
|
||||
cargo build --release --all-features
|
||||
cp ./target/release/liberc_5564_bn254.a <path-to-nwaku>
|
||||
```
|
||||
|
||||
> ![NOTE]
|
||||
> This static library also includes the rln ffi library, so you don't need to build it separately.
|
||||
> This is because using both of them separately brings in a lot of duplicate symbols.
|
||||
|
||||
2. Build the wakustealthcommitments app
|
||||
```sh
|
||||
cd <path-to-nwaku>
|
||||
source env.sh
|
||||
nim c --out:build/wakustealthcommitments --verbosity:0 --hints:off -d:chronicles_log_level=INFO -d:git_version="v0.24.0-rc.0-62-g7da25c" -d:release --passL:-lm --passL:liberc_5564_bn254.a --debugger:native examples/wakustealthcommitments/wakustealthcommitments.nim
|
||||
```
|
||||
|
||||
3.
|
||||
```sh
|
||||
./build/wakustealthcommitments \
|
||||
--rln-relay-eth-client-address:<insert http rpc url> \
|
||||
--rln-relay-cred-path:<path-to-credentials-file> \
|
||||
--rln-relay-cred-password:<password-of-credentials-file>
|
||||
```
|
||||
|
||||
This service listens for requests for stealth commitment/address generation,
|
||||
partakes in the generation of said stealth commitment and then distributes the response to the mesh.
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
## Nim wrappers for the functions defined in librln
|
||||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import stew/results
|
||||
|
||||
######################################################################
|
||||
## ERC-5564-BN254 module APIs
|
||||
######################################################################
|
||||
|
||||
type CErrorCode* = uint8
|
||||
|
||||
type CG1Projective* = object
|
||||
x0: array[32, uint8]
|
||||
|
||||
type CReturn*[T] = object
|
||||
value: T
|
||||
err_code: CErrorCode
|
||||
|
||||
type CFr* = object
|
||||
x0: array[32, uint8]
|
||||
|
||||
type CStealthCommitment* = object
|
||||
stealth_commitment: CG1Projective
|
||||
view_tag: uint64
|
||||
|
||||
type CKeyPair* = object
|
||||
private_key: CFr
|
||||
public_key: CG1Projective
|
||||
|
||||
proc drop_ffi_derive_public_key*(ptrx: ptr CReturn[CG1Projective]) {.importc: "drop_ffi_derive_public_key".}
|
||||
|
||||
proc drop_ffi_generate_random_fr*(ptrx: ptr CReturn[CFr]) {.importc: "drop_ffi_generate_random_fr".}
|
||||
|
||||
proc drop_ffi_generate_stealth_commitment*(ptrx: ptr CReturn[CStealthCommitment]) {.importc: "drop_ffi_generate_stealth_commitment".}
|
||||
|
||||
proc drop_ffi_generate_stealth_private_key*(ptrx: ptr CReturn[CFr]) {.importc: "drop_ffi_generate_stealth_private_key".}
|
||||
|
||||
proc drop_ffi_random_keypair*(ptrx: ptr CReturn[CKeyPair]) {.importc: "drop_ffi_random_keypair".}
|
||||
|
||||
proc ffi_derive_public_key*(private_key: ptr CFr): (ptr CReturn[CG1Projective]) {.importc: "ffi_derive_public_key".}
|
||||
|
||||
proc ffi_generate_random_fr*(): (ptr CReturn[CFr]) {.importc: "ffi_generate_random_fr".}
|
||||
|
||||
proc ffi_generate_stealth_commitment*(viewing_public_key: ptr CG1Projective,
|
||||
spending_public_key: ptr CG1Projective,
|
||||
ephemeral_private_key: ptr CFr): (ptr CReturn[CStealthCommitment]) {.importc: "ffi_generate_stealth_commitment".}
|
||||
|
||||
proc ffi_generate_stealth_private_key*(ephemeral_public_key: ptr CG1Projective,
|
||||
spending_key: ptr CFr,
|
||||
viewing_key: ptr CFr,
|
||||
view_tag: ptr uint64): (ptr CReturn[CFr]) {.importc: "ffi_generate_stealth_private_key".}
|
||||
|
||||
proc ffi_random_keypair*(): (ptr CReturn[CKeyPair]) {.importc: "ffi_random_keypair".}
|
||||
|
||||
|
||||
## Nim wrappers and types for the ERC-5564-BN254 module
|
||||
|
||||
type FFIResult[T] = Result[T, string]
|
||||
type Fr = array[32, uint8]
|
||||
type G1Projective = array[32, uint8]
|
||||
type KeyPair* = object
|
||||
private_key*: Fr
|
||||
public_key*: G1Projective
|
||||
type StealthCommitment* = object
|
||||
stealth_commitment*: G1Projective
|
||||
view_tag*: uint64
|
||||
type PrivateKey* = Fr
|
||||
type PublicKey* = G1Projective
|
||||
|
||||
proc generateRandomFr*(): FFIResult[Fr] =
|
||||
let res_ptr = (ffi_generate_random_fr())
|
||||
let res_value = res_ptr[]
|
||||
if res_value.err_code != 0:
|
||||
drop_ffi_generate_random_fr(res_ptr)
|
||||
return err("Error generating random field element: " & $res_value.err_code)
|
||||
|
||||
let ret = res_value.value.x0
|
||||
drop_ffi_generate_random_fr(res_ptr)
|
||||
return ok(ret)
|
||||
|
||||
proc generateKeypair*(): FFIResult[KeyPair] =
|
||||
let res_ptr = (ffi_random_keypair())
|
||||
let res_value = res_ptr[]
|
||||
if res_value.err_code != 0:
|
||||
drop_ffi_random_keypair(res_ptr)
|
||||
return err("Error generating random keypair: " & $res_value.err_code)
|
||||
|
||||
let ret = KeyPair(private_key: res_value.value.private_key.x0, public_key: res_value.value.public_key.x0)
|
||||
drop_ffi_random_keypair(res_ptr)
|
||||
return ok(ret)
|
||||
|
||||
proc generateStealthCommitment*(viewing_public_key: G1Projective,
|
||||
spending_public_key: G1Projective,
|
||||
ephemeral_private_key: Fr): FFIResult[StealthCommitment] =
|
||||
let viewing_public_key = CG1Projective(x0: viewing_public_key)
|
||||
let viewing_public_key_ptr = unsafeAddr(viewing_public_key)
|
||||
let spending_public_key = CG1Projective(x0: spending_public_key)
|
||||
let spending_public_key_ptr = unsafeAddr(spending_public_key)
|
||||
let ephemeral_private_key = CFr(x0: ephemeral_private_key)
|
||||
let ephemeral_private_key_ptr = unsafeAddr(ephemeral_private_key)
|
||||
|
||||
let res_ptr = (ffi_generate_stealth_commitment(viewing_public_key_ptr, spending_public_key_ptr, ephemeral_private_key_ptr))
|
||||
let res_value = res_ptr[]
|
||||
if res_value.err_code != 0:
|
||||
drop_ffi_generate_stealth_commitment(res_ptr)
|
||||
return err("Error generating stealth commitment: " & $res_value.err_code)
|
||||
|
||||
let ret = StealthCommitment(stealth_commitment: res_value.value.stealth_commitment.x0, view_tag: res_value.value.view_tag)
|
||||
drop_ffi_generate_stealth_commitment(res_ptr)
|
||||
return ok(ret)
|
||||
|
||||
proc generateStealthPrivateKey*(ephemeral_public_key: G1Projective,
|
||||
spending_key: Fr,
|
||||
viewing_key: Fr,
|
||||
view_tag: uint64): FFIResult[Fr] =
|
||||
let ephemeral_public_key = CG1Projective(x0: ephemeral_public_key)
|
||||
let ephemeral_public_key_ptr = unsafeAddr(ephemeral_public_key)
|
||||
let spending_key = CFr(x0: spending_key)
|
||||
let spending_key_ptr = unsafeAddr(spending_key)
|
||||
let viewing_key = CFr(x0: viewing_key)
|
||||
let viewing_key_ptr = unsafeAddr(viewing_key)
|
||||
let view_tag_ptr = unsafeAddr(view_tag)
|
||||
|
||||
let res_ptr = (ffi_generate_stealth_private_key(ephemeral_public_key_ptr, spending_key_ptr, viewing_key_ptr, view_tag_ptr))
|
||||
let res_value = res_ptr[]
|
||||
if res_value.err_code != 0:
|
||||
drop_ffi_generate_stealth_private_key(res_ptr)
|
||||
return err("Error generating stealth private key: " & $res_value.err_code)
|
||||
|
||||
let ret = res_value.value.x0
|
||||
drop_ffi_generate_stealth_private_key(res_ptr)
|
||||
return ok(ret)
|
|
@ -0,0 +1,10 @@
|
|||
-d:chronicles_line_numbers
|
||||
-d:discv5_protocol_id="d5waku"
|
||||
-d:chronicles_runtime_filtering=on
|
||||
-d:chronicles_sinks="textlines,json"
|
||||
-d:chronicles_default_output_device=dynamic
|
||||
# Disabling the following topics from nim-eth and nim-dnsdisc since some types cannot be serialized
|
||||
-d:chronicles_disabled_topics="eth,dnsdisc.client"
|
||||
-d:chronicles_log_level=INFO
|
||||
# Results in empty output for some reason
|
||||
#-d:"chronicles_enabled_topics=GossipSub:TRACE,WakuRelay:TRACE"
|
|
@ -0,0 +1,106 @@
|
|||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import ../../apps/wakunode2/[networks_config, app, external_config]
|
||||
import ../../waku/common/logging
|
||||
import
|
||||
std/[options, strutils, os, sequtils],
|
||||
stew/shims/net as stewNet,
|
||||
chronicles,
|
||||
chronos,
|
||||
metrics,
|
||||
libbacktrace,
|
||||
libp2p/crypto/crypto
|
||||
|
||||
export
|
||||
networks_config,
|
||||
app,
|
||||
logging,
|
||||
options,
|
||||
strutils,
|
||||
os,
|
||||
sequtils,
|
||||
stewNet,
|
||||
chronicles,
|
||||
chronos,
|
||||
metrics,
|
||||
libbacktrace,
|
||||
crypto
|
||||
|
||||
proc setup*(): App =
|
||||
const versionString = "version / git commit hash: " & app.git_version
|
||||
let rng = crypto.newRng()
|
||||
|
||||
let confRes = WakuNodeConf.load(version = versionString)
|
||||
if confRes.isErr():
|
||||
error "failure while loading the configuration", error = $confRes.error
|
||||
quit(QuitFailure)
|
||||
|
||||
var conf = confRes.get()
|
||||
|
||||
let twnClusterConf = ClusterConf.TheWakuNetworkConf()
|
||||
if len(conf.shards) != 0:
|
||||
conf.pubsubTopics = conf.shards.mapIt(twnClusterConf.pubsubTopics[it.uint16])
|
||||
else:
|
||||
conf.pubsubTopics = twnClusterConf.pubsubTopics
|
||||
|
||||
# Override configuration
|
||||
conf.maxMessageSize = twnClusterConf.maxMessageSize
|
||||
conf.clusterId = twnClusterConf.clusterId
|
||||
conf.rlnRelay = twnClusterConf.rlnRelay
|
||||
conf.rlnRelayEthContractAddress = twnClusterConf.rlnRelayEthContractAddress
|
||||
conf.rlnRelayDynamic = twnClusterConf.rlnRelayDynamic
|
||||
conf.rlnRelayBandwidthThreshold = twnClusterConf.rlnRelayBandwidthThreshold
|
||||
conf.discv5Discovery = twnClusterConf.discv5Discovery
|
||||
conf.discv5BootstrapNodes =
|
||||
conf.discv5BootstrapNodes & twnClusterConf.discv5BootstrapNodes
|
||||
conf.rlnEpochSizeSec = twnClusterConf.rlnEpochSizeSec
|
||||
conf.rlnRelayUserMessageLimit = twnClusterConf.rlnRelayUserMessageLimit
|
||||
|
||||
var wakunode2 = App.init(rng, conf)
|
||||
## Peer persistence
|
||||
let res1 = wakunode2.setupPeerPersistence()
|
||||
if res1.isErr():
|
||||
error "1/5 Setting up storage failed", error = $res1.error
|
||||
quit(QuitFailure)
|
||||
|
||||
debug "2/5 Retrieve dynamic bootstrap nodes"
|
||||
|
||||
let res3 = wakunode2.setupDyamicBootstrapNodes()
|
||||
if res3.isErr():
|
||||
error "2/5 Retrieving dynamic bootstrap nodes failed", error = $res3.error
|
||||
quit(QuitFailure)
|
||||
|
||||
debug "3/5 Initializing node"
|
||||
|
||||
let res4 = wakunode2.setupWakuApp()
|
||||
if res4.isErr():
|
||||
error "3/5 Initializing node failed", error = $res4.error
|
||||
quit(QuitFailure)
|
||||
|
||||
debug "4/5 Mounting protocols"
|
||||
|
||||
var res5: Result[void, string]
|
||||
try:
|
||||
res5 = waitFor wakunode2.setupAndMountProtocols()
|
||||
if res5.isErr():
|
||||
error "4/5 Mounting protocols failed", error = $res5.error
|
||||
quit(QuitFailure)
|
||||
except Exception:
|
||||
error "4/5 Mounting protocols failed", error = getCurrentExceptionMsg()
|
||||
quit(QuitFailure)
|
||||
|
||||
debug "5/5 Starting node and mounted protocols"
|
||||
|
||||
# set triggerSelf to false, we don't want to process our own stealthCommitments
|
||||
wakunode2.node.wakuRelay.triggerSelf = false
|
||||
|
||||
let res6 = wakunode2.startApp()
|
||||
if res6.isErr():
|
||||
error "5/5 Starting node and protocols failed", error = $res6.error
|
||||
quit(QuitFailure)
|
||||
|
||||
info "Node setup complete"
|
||||
return wakunode2
|
|
@ -0,0 +1,154 @@
|
|||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
stew/results,
|
||||
../../waku/common/logging,
|
||||
../../waku/waku_node,
|
||||
../../waku/waku_rln_relay,
|
||||
./erc_5564_interface as StealthCommitmentFFI,
|
||||
./node_spec,
|
||||
./wire_spec
|
||||
|
||||
export
|
||||
wire_spec,
|
||||
logging
|
||||
|
||||
type StealthCommitmentProtocol* = object
|
||||
wakuApp: App
|
||||
contentTopic: string
|
||||
spendingKeyPair: StealthCommitmentFFI.KeyPair
|
||||
viewingKeyPair: StealthCommitmentFFI.KeyPair
|
||||
|
||||
proc deserialize(T: type StealthCommitmentFFI.PublicKey, v: SerializedKey): Result[T, string] =
|
||||
# deserialize seq[byte] into array[32, uint8]
|
||||
if v.len != 32:
|
||||
return err("invalid key length")
|
||||
var buf: array[32, uint8]
|
||||
for i in 0..<v.len:
|
||||
buf[i] = v[i]
|
||||
return ok(buf)
|
||||
|
||||
proc serialize(v: StealthCommitmentFFI.PublicKey | StealthCommitmentFFI.PrivateKey): SerializedKey =
|
||||
# serialize array[32, uint8] into seq[byte]
|
||||
var buf = newSeq[byte](v.len)
|
||||
for i in 0..<v.len:
|
||||
buf[i] = v[i]
|
||||
return buf
|
||||
|
||||
proc sendThruWaku*(self: StealthCommitmentProtocol, msg: seq[byte]): Future[Result[void, string]] {.async.} =
|
||||
let time = getTime().toUnix()
|
||||
var message = WakuMessage(payload: msg,
|
||||
contentTopic: self.contentTopic,
|
||||
version: 0,
|
||||
timestamp: getNanosecondTime(time))
|
||||
|
||||
(self.wakuApp.node.wakuRlnRelay.appendRLNProof(message, float64(time))).isOkOr:
|
||||
return err("could not append rate limit proof to the message: " & $error)
|
||||
|
||||
(await self.wakuApp.node.publish(some(DefaultPubsubTopic), message)).isOkOr:
|
||||
return err("failed to publish message: " & $error)
|
||||
|
||||
debug "rate limit proof is appended to the message"
|
||||
|
||||
return ok()
|
||||
|
||||
proc sendRequest*(self: StealthCommitmentProtocol): Future[Result[void, string]] {.async.} =
|
||||
let request = constructRequest(serialize(self.spendingKeyPair.publicKey), serialize(self.viewingKeyPair.publicKey)).encode()
|
||||
try:
|
||||
(await self.sendThruWaku(request.buffer)).isOkOr:
|
||||
return err("Could not send stealth commitment payload thru waku: " & $error)
|
||||
except CatchableError:
|
||||
return err("Could not send stealth commitment payload thru waku: " & getCurrentExceptionMsg())
|
||||
return ok()
|
||||
|
||||
|
||||
proc sendResponse*(self: StealthCommitmentProtocol, stealthCommitment: StealthCommitmentFFI.PublicKey, ephemeralPubKey: StealthCommitmentFFI.PublicKey, viewTag: uint64): Future[Result[void, string]] {.async.} =
|
||||
let response = constructResponse(serialize(stealthCommitment), serialize(ephemeralPubKey), viewTag).encode()
|
||||
try:
|
||||
(await self.sendThruWaku(response.buffer)).isOkOr:
|
||||
return err("Could not send stealth commitment payload thru waku: " & $error)
|
||||
except CatchableError:
|
||||
return err("Could not send stealth commitment payload thru waku: " & getCurrentExceptionMsg())
|
||||
return ok()
|
||||
|
||||
type SCPHandler* = proc (msg: WakuMessage): Future[void] {.async.}
|
||||
proc getSCPHandler(self: StealthCommitmentProtocol): SCPHandler =
|
||||
|
||||
let handler = proc(msg: WakuMessage): Future[void] {.async.} =
|
||||
let decodedRes = WakuStealthCommitmentMsg.decode(msg.payload)
|
||||
if decodedRes.isErr():
|
||||
error "could not decode scp message"
|
||||
let decoded = decodedRes.get()
|
||||
if decoded.request == false:
|
||||
# check if the generated stealth commitment belongs to the receiver
|
||||
# if not, continue
|
||||
let ephemeralPubKeyRes = deserialize(StealthCommitmentFFI.PublicKey, decoded.ephemeralPubKey.get())
|
||||
if ephemeralPubKeyRes.isErr():
|
||||
error "could not deserialize ephemeral public key: ", err = ephemeralPubKeyRes.error()
|
||||
let ephemeralPubKey = ephemeralPubKeyRes.get()
|
||||
let stealthCommitmentPrivateKeyRes = StealthCommitmentFFI.generateStealthPrivateKey(ephemeralPubKey,
|
||||
self.spendingKeyPair.privateKey,
|
||||
self.viewingKeyPair.privateKey,
|
||||
decoded.viewTag.get())
|
||||
if stealthCommitmentPrivateKeyRes.isErr():
|
||||
info "received stealth commitment does not belong to the receiver: ", err = stealthCommitmentPrivateKeyRes.error()
|
||||
|
||||
let stealthCommitmentPrivateKey = stealthCommitmentPrivateKeyRes.get()
|
||||
info "received stealth commitment belongs to the receiver: ", stealthCommitmentPrivateKey, stealthCommitmentPubKey = decoded.stealthCommitment.get()
|
||||
return
|
||||
# send response
|
||||
# deseralize the keys
|
||||
let spendingKeyRes = deserialize(StealthCommitmentFFI.PublicKey, decoded.spendingPubKey.get())
|
||||
if spendingKeyRes.isErr():
|
||||
error "could not deserialize spending key: ", err = spendingKeyRes.error()
|
||||
let spendingKey = spendingKeyRes.get()
|
||||
let viewingKeyRes = (deserialize(StealthCommitmentFFI.PublicKey, decoded.viewingPubKey.get()))
|
||||
if viewingKeyRes.isErr():
|
||||
error "could not deserialize viewing key: ", err = viewingKeyRes.error()
|
||||
let viewingKey = viewingKeyRes.get()
|
||||
|
||||
info "received spending key", spendingKey
|
||||
info "received viewing key", viewingKey
|
||||
let ephemeralKeyPairRes = StealthCommitmentFFI.generateKeyPair()
|
||||
if ephemeralKeyPairRes.isErr():
|
||||
error "could not generate ephemeral key pair: ", err = ephemeralKeyPairRes.error()
|
||||
let ephemeralKeyPair = ephemeralKeyPairRes.get()
|
||||
|
||||
let stealthCommitmentRes = StealthCommitmentFFI.generateStealthCommitment(spendingKey, viewingKey, ephemeralKeyPair.privateKey)
|
||||
if stealthCommitmentRes.isErr():
|
||||
error "could not generate stealth commitment: ", err = stealthCommitmentRes.error()
|
||||
let stealthCommitment = stealthCommitmentRes.get()
|
||||
|
||||
(await self.sendResponse(stealthCommitment.stealthCommitment, ephemeralKeyPair.publicKey, stealthCommitment.viewTag)).isOkOr:
|
||||
error "could not send response: ", err = $error
|
||||
|
||||
return handler
|
||||
|
||||
proc new*(wakuApp: App, contentTopic = ContentTopic("/wakustealthcommitments/1/app/proto")): Result[StealthCommitmentProtocol, string] =
|
||||
let spendingKeyPair = StealthCommitmentFFI.generateKeyPair().valueOr:
|
||||
return err("could not generate spending key pair: " & $error)
|
||||
let viewingKeyPair = StealthCommitmentFFI.generateKeyPair().valueOr:
|
||||
return err("could not generate viewing key pair: " & $error)
|
||||
|
||||
info "spending public key", publicKey = spendingKeyPair.publicKey
|
||||
info "viewing public key", publicKey = viewingKeyPair.publicKey
|
||||
|
||||
let SCP = StealthCommitmentProtocol(wakuApp: wakuApp,
|
||||
contentTopic: contentTopic,
|
||||
spendingKeyPair: spendingKeyPair,
|
||||
viewingKeyPair: viewingKeyPair)
|
||||
|
||||
|
||||
proc handler(topic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} =
|
||||
let scpHandler = getSCPHandler(SCP)
|
||||
if msg.contentTopic == contentTopic:
|
||||
try:
|
||||
await scpHandler(msg)
|
||||
except CatchableError:
|
||||
error "could not handle SCP message: ", err = getCurrentExceptionMsg()
|
||||
|
||||
wakuApp.node.subscribe((kind: PubsubSub, topic: DefaultPubsubTopic), some(handler))
|
||||
return ok(SCP)
|
|
@ -0,0 +1,43 @@
|
|||
when (NimMajor, NimMinor) < (1, 4):
|
||||
{.push raises: [Defect].}
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
stew/results,
|
||||
chronicles,
|
||||
./node_spec as Waku,
|
||||
./stealth_commitment_protocol as SCP
|
||||
|
||||
logScope:
|
||||
topics = "waku stealthcommitments"
|
||||
|
||||
when isMainModule:
|
||||
## Logging setup
|
||||
|
||||
# Adhere to NO_COLOR initiative: https://no-color.org/
|
||||
let color =
|
||||
try:
|
||||
not parseBool(os.getEnv("NO_COLOR", "false"))
|
||||
except CatchableError:
|
||||
true
|
||||
|
||||
logging.setupLogLevel(logging.LogLevel.INFO)
|
||||
logging.setupLogFormat(logging.LogFormat.TEXT, color)
|
||||
|
||||
info "Starting Waku Stealth Commitment Protocol"
|
||||
info "Starting Waku Node"
|
||||
let node = Waku.setup()
|
||||
info "Waku Node started, listening for StealthCommitmentMessages"
|
||||
let scp = SCP.new(node).valueOr:
|
||||
error "Could not start Stealth Commitment Protocol", error = $error
|
||||
quit(1)
|
||||
|
||||
try:
|
||||
info "Sending stealth commitment request"
|
||||
(waitFor scp.sendRequest()).isOkOr:
|
||||
error "Could not send stealth commitment request", error = $error
|
||||
except:
|
||||
error "Could not send stealth commitment request", error = getCurrentExceptionMsg()
|
||||
|
||||
runForever()
|
|
@ -0,0 +1,115 @@
|
|||
|
||||
import std/[times, options]
|
||||
import
|
||||
confutils,
|
||||
chronicles,
|
||||
chronos,
|
||||
stew/results
|
||||
|
||||
import
|
||||
../../waku/waku_core,
|
||||
../../waku/common/protobuf
|
||||
import libp2p/protobuf/minprotobuf
|
||||
|
||||
export
|
||||
times,
|
||||
options,
|
||||
confutils,
|
||||
chronicles,
|
||||
chronos,
|
||||
results,
|
||||
waku_core,
|
||||
protobuf,
|
||||
minprotobuf
|
||||
|
||||
type SerializedKey* = seq[byte]
|
||||
|
||||
type
|
||||
WakuStealthCommitmentMsg* = object
|
||||
request*: bool
|
||||
spendingPubKey*: Option[SerializedKey]
|
||||
viewingPubKey*: Option[SerializedKey]
|
||||
ephemeralPubKey*: Option[SerializedKey]
|
||||
stealthCommitment*: Option[SerializedKey]
|
||||
viewTag*: Option[uint64]
|
||||
|
||||
proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T] =
|
||||
var msg = WakuStealthCommitmentMsg()
|
||||
let pb = initProtoBuffer(buffer)
|
||||
|
||||
var request: uint64
|
||||
discard ? pb.getField(1, request)
|
||||
msg.request = request == 1
|
||||
var spendingPubKey = newSeq[byte]()
|
||||
discard ? pb.getField(2, spendingPubKey)
|
||||
msg.spendingPubKey = if spendingPubKey.len > 0: some(spendingPubKey) else: none(SerializedKey)
|
||||
var viewingPubKey = newSeq[byte]()
|
||||
discard ? pb.getField(3, viewingPubKey)
|
||||
msg.viewingPubKey = if viewingPubKey.len > 0: some(viewingPubKey) else: none(SerializedKey)
|
||||
|
||||
if msg.spendingPubKey.isSome() and msg.viewingPubKey.isSome():
|
||||
msg.stealthCommitment = none(SerializedKey)
|
||||
msg.viewTag = none(uint64)
|
||||
return ok(msg)
|
||||
if msg.spendingPubKey.isSome() and msg.viewingPubKey.isNone():
|
||||
return err(ProtoError.RequiredFieldMissing)
|
||||
if msg.spendingPubKey.isNone() and msg.viewingPubKey.isSome():
|
||||
return err(ProtoError.RequiredFieldMissing)
|
||||
if msg.request == true and msg.spendingPubKey.isNone() and msg.viewingPubKey.isNone():
|
||||
return err(ProtoError.RequiredFieldMissing)
|
||||
|
||||
|
||||
var stealthCommitment = newSeq[byte]()
|
||||
discard ? pb.getField(4, stealthCommitment)
|
||||
msg.stealthCommitment = if stealthCommitment.len > 0: some(stealthCommitment) else: none(SerializedKey)
|
||||
|
||||
var ephemeralPubKey = newSeq[byte]()
|
||||
discard ? pb.getField(5, ephemeralPubKey)
|
||||
msg.ephemeralPubKey = if ephemeralPubKey.len > 0: some(ephemeralPubKey) else: none(SerializedKey)
|
||||
|
||||
var viewTag: uint64
|
||||
discard ? pb.getField(6, viewTag)
|
||||
msg.viewTag = if viewTag != 0: some(viewTag) else: none(uint64)
|
||||
|
||||
if msg.stealthCommitment.isNone() and msg.viewTag.isNone() and msg.ephemeralPubKey.isNone():
|
||||
return err(ProtoError.RequiredFieldMissing)
|
||||
|
||||
if msg.stealthCommitment.isSome() and msg.viewTag.isNone():
|
||||
return err(ProtoError.RequiredFieldMissing)
|
||||
|
||||
if msg.stealthCommitment.isNone() and msg.viewTag.isSome():
|
||||
return err(ProtoError.RequiredFieldMissing)
|
||||
|
||||
if msg.stealthCommitment.isSome() and msg.viewTag.isSome():
|
||||
msg.spendingPubKey = none(SerializedKey)
|
||||
msg.viewingPubKey = none(SerializedKey)
|
||||
|
||||
ok(msg)
|
||||
|
||||
proc encode*(msg: WakuStealthCommitmentMsg): ProtoBuffer =
|
||||
var serialised = initProtoBuffer()
|
||||
|
||||
serialised.write(1, uint64(msg.request))
|
||||
|
||||
if msg.spendingPubKey.isSome():
|
||||
serialised.write(2, msg.spendingPubKey.get())
|
||||
if msg.viewingPubKey.isSome():
|
||||
serialised.write(3, msg.viewingPubKey.get())
|
||||
if msg.stealthCommitment.isSome():
|
||||
serialised.write(4, msg.stealthCommitment.get())
|
||||
if msg.ephemeralPubKey.isSome():
|
||||
serialised.write(5, msg.ephemeralPubKey.get())
|
||||
if msg.viewTag.isSome():
|
||||
serialised.write(6, msg.viewTag.get())
|
||||
|
||||
return serialised
|
||||
|
||||
func toByteSeq*(str: string): seq[byte] {.inline.} =
|
||||
## Converts a string to the corresponding byte sequence.
|
||||
@(str.toOpenArrayByte(0, str.high))
|
||||
|
||||
proc constructRequest*(spendingPubKey: SerializedKey, viewingPubKey: SerializedKey): WakuStealthCommitmentMsg =
|
||||
WakuStealthCommitmentMsg(request: true, spendingPubKey: some(spendingPubKey), viewingPubKey: some(viewingPubKey))
|
||||
|
||||
proc constructResponse*(stealthCommitment: SerializedKey, ephemeralPubKey: SerializedKey, viewTag: uint64): WakuStealthCommitmentMsg =
|
||||
WakuStealthCommitmentMsg(request: false, stealthCommitment: some(stealthCommitment), ephemeralPubKey: some(ephemeralPubKey), viewTag: some(viewTag))
|
Loading…
Reference in New Issue