Skip to content

Commit

Permalink
feat(waku-stealth-commitments): waku stealth commitment protocol (#2490)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
rymnc committed Mar 6, 2024
1 parent e692edf commit 0def490
Show file tree
Hide file tree
Showing 7 changed files with 601 additions and 0 deletions.
38 changes: 38 additions & 0 deletions examples/wakustealthcommitments/README.md
@@ -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.

135 changes: 135 additions & 0 deletions examples/wakustealthcommitments/erc_5564_interface.nim
@@ -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)
10 changes: 10 additions & 0 deletions examples/wakustealthcommitments/nim.cfg
@@ -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"
106 changes: 106 additions & 0 deletions examples/wakustealthcommitments/node_spec.nim
@@ -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 comments on commit 0def490

Please sign in to comment.