2024-02-28 21:48:27 -05:00
---
title: WAKU-RLN-KEYSTORE
name: Waku RLN Keystore
category: Standards Track
editor: Jimmy Debe < jimmy @status .im >
contributors:
- Aaryamann Challani < aaryamann @status .im >
---
## Abstract
2025-07-30 20:49:21 -04:00
This specification describes how the RLN, Rate Limit Nullifier,
credentials are securely stored in a JSON schema.
2024-02-28 21:48:27 -05:00
## Background
2025-07-30 20:49:21 -04:00
A keystore is a construct to store a user’ s cryptographic keys.
The keys are encrypted and decrypted based on the methods specified in this specification.
A [17/WAKU2-RLN-RELAY ](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md )
keystore stores a node's credentials locally and
[32/RLN-V1 ](https://github.com/vacp2p/rfc-index/blob/main/vac/32/rln-v1.md ) is used as a spam-prevention mechanism with the help of zero-knowledge proofs.
2024-02-28 21:48:27 -05:00
The secure storage of keys is important in peer-to-peer messaging applications.
2025-07-30 20:49:21 -04:00
Zero-knowledge proofs are used to have anonymous rate-limiting for messaging frameworks.
Node's Credentials are encrypted and
stored in the keystore to be retrieved at any time over the Waku network.
With [32/RLN-V1 ](https://github.com/vacp2p/rfc-index/blob/main/vac/32/rln-v1.md ), sending and receiving
messages will ensure a message rate for the network is being followed while preserving the anonymity of the message owner.
## Specification
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”,
“NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC 2119 ](https://www.ietf.org/rfc/rfc2119.txt ).
2024-02-28 21:48:27 -05:00
### Waku RLN Keystore Format:
2025-07-30 20:49:21 -04:00
A format example of a keystore used by a [17/WAKU2-RLN-Relay ](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md ).
2024-02-28 21:48:27 -05:00
```js
const Keystore {
application: "waku-rln-relay" ,
appIdentifier: "string",
version: "string",
credentials: {
"membershipHash": {
crypto: {
cipher: "string",
cipherparams: {
iv: "string",
},
ciphertext: "string",
kdf: "string",
kdfparams: {
dklen: integer,
c: integer,
prf: "string",
salt: "string",
},
mac: "string",
}
}
}
}
```
2025-07-30 20:49:21 -04:00
The keystore MUST be generated using a cryptographic construction that supports password verification and decryption.
Keystore modules MUST include metadata, a key derivation function, a checksum, a cipher, and a membership hash.
2024-02-28 21:48:27 -05:00
### Metadata:
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
Information about the keystore SHOULD be stored in the metadata.
2025-07-30 20:49:21 -04:00
The declaration of `application` , `version` , and `appIdentifier` MAY occur in the metadata.
2024-02-28 21:48:27 -05:00
- `application` : current application, MUST be a string
- `version` : application version, MUST be a string, SHOULD follow semantic versioning
- `appIdentifier` : application identifier, MUST be a string
### Credentials:
2025-07-30 20:49:21 -04:00
After the RLN credentials are generated, it MUST be stored in a JSON schema.
The credentials MUST consist of a `membershipHash` and `WakuCredential` .
2024-02-28 21:48:27 -05:00
The `membershipHash` will be an identity hash of the user.
2025-07-30 20:49:21 -04:00
The `WakuCredential` will store the encryption portion of the keystore.
There MAY be multiple credentials stored in a keystore,
categorized by the `membershipHash` .
2024-02-28 21:48:27 -05:00
Each contruct MUST include the keypair:
> key: [`membershipHash`]: pair: [`WakuCredential`]
#### membershipHash
2025-07-30 21:23:33 -04:00
The `membershipHash` SHOULD be generated by nodes participating in a membership group,
2025-07-30 20:49:21 -04:00
as decribed in [32/RLN-V1 ](https://github.com/vacp2p/rfc-index/blob/main/vac/32/rln-v1.md ).
2025-07-30 21:23:33 -04:00
Each node SHOULD register to the group using an `identity_commitment` stored in a Merkle tree.
The RECOMMENDED cryptographic hash function used to generate the `membershipHash` is [SHA256 ](https://www.rfc-editor.org/rfc/rfc4634.txt ),
2024-02-28 21:48:27 -05:00
other hash functions MAY be used.
2025-07-30 21:23:33 -04:00
The hash function SHOULD be defined in the `verison` attribute.
A `membershipHash` MUST NOT already exist in the keystore.
2025-07-30 20:49:21 -04:00
To generate the `membershipHash` the following attributes SHOULD be used to create a hexadecimal string:
- `treeIndex` :
- `membershipContract`
- `chainId` ,
- `identityCredential`
- `rateLimit`
2024-02-28 21:48:27 -05:00
##### `treeIndex`
2025-07-30 21:23:33 -04:00
After a node registers to a group,
2024-02-28 21:48:27 -05:00
a `treeIndex` value of the position in the Merkle tree SHOULD be returned.
2025-07-30 20:49:21 -04:00
2025-07-30 21:23:33 -04:00
- it MUST be a Merkle tree data structure filled with the `identity_commitment` from node registrations.
2025-07-30 20:49:21 -04:00
- it SHOULD be a hexadecimal string
2024-02-28 21:48:27 -05:00
##### `membershipContract`
For decentralized membership registrations,
2025-07-30 21:23:33 -04:00
the `membershipContract` value SHOULD be a `contractAddress` of a smart contract deployed on a blockchain.
2025-07-30 20:49:21 -04:00
- it SHOULD be a string.
2024-02-28 21:48:27 -05:00
##### `chainId`
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
It uniquely defines the chain upon which the registration has occurred.
2025-07-30 21:23:33 -04:00
The `chainId` value SHOULD be the blockchain identifier used for `membershipContract` ,
2024-02-28 21:48:27 -05:00
as described in [EIP155 ](https://eips.ethereum.org/EIPS/eip-155 ).
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
- it MUST be a string
##### `identityCredential`
The `identityCredential` MUST be derived after a succussful decryption of the keystore.
The `identityCredential` MUST be constructed with the `identity_secret` , `identity_secret_hash` , `identity_commitment` values.
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
- it MUST be a hash of `identity_commitment` stored in a Merkle tree.
- it MUST be a string.
###### `identity_secret`
The `identity_secret` MUST be constructed with `identity_nullifier` + `identity_trapdoor` values.
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
- `identity_nullifier` : Random 32 byte value
- `identity_trapdoor` : Random 32 byte value
###### `identity_secret_hash`
2025-07-30 21:23:33 -04:00
Used to derive the `identity_commitment` of the node, and
2024-02-28 21:48:27 -05:00
as a private input for zero-knowledge proof generation.
2025-07-30 21:23:33 -04:00
2024-02-28 21:48:27 -05:00
- it MUST be created with `identity_secret` as a parameter for the hash function.
2025-07-30 21:23:33 -04:00
- This secret hash SHOULD be kept private by the node.
2024-02-28 21:48:27 -05:00
2025-07-30 20:49:21 -04:00
###### `identity_commitment`
2024-02-28 21:48:27 -05:00
- it SHOULD be created with `identity_secret_hash` by using the hash function Poseidon,
as described in [Poseidon Paper ](https://eprint.iacr.org/2019/458.pdf ).
2025-07-30 21:23:33 -04:00
- it MUST be used by a node for group registering.
2024-02-28 21:48:27 -05:00
2025-07-30 20:49:21 -04:00
##### `rateLimit`
2025-07-30 21:23:33 -04:00
- it SHOULD be the node's membership rate limit
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
#### WakuCredential
2025-07-30 21:23:33 -04:00
The `WakuCredential` will store values used for encrypting and decrypting a node's keystore.
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
- it MUST be used for password verification.
- it MUST follow [EIP-2335 ](https://eips.ethereum.org/EIPS/eip-2335 )
- it SHOULD use [SHA256 ](https://www.rfc-editor.org/rfc/rfc4634.txt ) as the hash function
#### KDF
The password-based encryption used SHOULD be KDF, key derivation function,
to produce a derived key from a password and other parameters.
2025-07-30 20:49:21 -04:00
The keystore MAY use PBKDF2 password-based encryption,
2024-02-28 21:48:27 -05:00
as described in [RFC 2898 ](https://www.ietf.org/rfc/rfc2898.txt ).
A `WakuCredential` object MUST include:
2025-07-30 21:23:33 -04:00
2024-02-28 21:48:27 -05:00
| Name | Description |
|----|-----|
| password | used to encrypt keystore and decryption key |
| secret | key to be encrypted |
| pubKey | public key |
| path | HD, hardened derivation, path used to generate the secret |
| checksum | hash function |
| cipher | cipher function |
```js
crypto: {
cipher: "string" // The cipher function
cipherparams: {
iv: "string" // The cipher parameters
},
ciphertext: "string" // The cipher message,
kdf: "string" // KDF Function,
kdfparams: {
param: integer // Salt value and iteration count,
dklen: integer // Length in octets of derived key, MUST be positive integer,
c: "string" // Iteration count, MUST be positive integer,
prf: "string" // Underlying pseudorandom function,
salt: "string" // Produces a large set of keys based on the password
},
mac: "string" // Checksum
}
```
#### Decryption
2025-07-30 20:49:21 -04:00
2025-07-30 21:23:33 -04:00
The keystore SHOULD decrypt a node's credentials using a password and the `membershipHash` ,
2024-02-28 21:48:27 -05:00
using PBKDF2 that returns the `decryptionKey` key.
2025-07-30 21:23:33 -04:00
The `decryptionKey` is used to verify that the keystore has the correct credentials.
2025-07-30 20:49:21 -04:00
2024-02-28 21:48:27 -05:00
- To generate the `decryptionKey` , it MUST be constructed from a password and KDF,
as desrcibed in [ERC-2335: BLS12-381 Keystore ](https://eips.ethereum.org/EIPS/eip-2335 ).
- The `decryptionKey` , is derived from the cipher function and
cipher parameters described in the KDF used in the keystore.
### Test Vectors
RLN uses Poseidon hash algorithm to generate the `identityCredential` ,
as described in [Poseidon Paper ](https://eprint.iacr.org/2019/458.pdf ).
The keystore hash algorithm used is [SHA256 ](https://www.rfc-editor.org/rfc/rfc4634.txt ).
#### Input:
- `application` : "waku-rln-relay"
- `appIdentifier` : "01234567890abcdef"
- `version` : "0.2"
- `hashFunction` : "poseidonHash"
- `password` : "sup3rsecure"
```js
identityCredential = {
IDTrapdoor: [
211, 23, 66, 42, 179, 130, 131, 111, 201, 205, 244, 34, 27, 238, 244,
216, 131, 240, 188, 45, 193, 172, 4, 168, 225, 225, 43, 197, 114, 176,
126, 9,
],
IDNullifier: [
238, 168, 239, 65, 73, 63, 105, 19, 132, 62, 213, 205, 191, 255, 209, 9,
178, 155, 239, 201, 131, 125, 233, 136, 246, 217, 9, 237, 55, 89, 81,
42,
],
IDSecretHash: [
150, 54, 194, 28, 18, 216, 138, 253, 95, 139, 120, 109, 98, 129, 146,
101, 41, 194, 36, 36, 96, 152, 152, 89, 151, 160, 118, 15, 222, 124,
187, 4,
],
IDCommitment: [
112, 216, 27, 89, 188, 135, 203, 19, 168, 211, 117, 13, 231, 135, 229,
58, 94, 20, 246, 8, 33, 65, 238, 37, 112, 97, 65, 241, 255, 93, 171, 15,
],
}
membership = {
chainId: "0xAA36A7",
treeIndex: 8,
address: "0x8e1F3742B987d8BA376c0CBbD7357fE1F003ED71",
}
```
#### Output:
```js
application: "waku-rln-relay",
appIdentifier: "01234567890abcdef",
version: "0.2",
credentials: {
"9DB2B4718A97485B9F70F68D1CC19F4E10F0B4CE943418838E94956CB8E57548": {
crypto: {
cipher: "aes-128-ctr",
cipherparams: {
iv: "fd6b39eb71d44c59f6bf5ff3d8945c80",
},
ciphertext: "9c72f47ce95de03ed34502d0288e7576b66b51b9e7d5ae882c27bd89f94e6a03c2c44c2ddf0c982e72003d67212105f1b64614f57cabb0ceadab7e07be165eee1121ad6b81951368a9f3be2dd99ea294515f6013d5f2bd4702a40e36cfde2ea298b23b31e5ce719d8040c3331f73d6bf44f88bca39bac0e917d8bf545500e4f40d321c235426a80f315ac70666acbd3bdf803fbc1e7e7103fed466525ed332b25d72b2dbedf6fa383b2305987c1fe276b029570519b3e79930edf08c1029868d05c2c08ab61d7c64f63c054b4f6a5a12d43cdc79751b6fe58d3ed26b69443eb7c9f7efce27912340129c91b6b813ac94efd5776a40b1dda896d61357de208c7c47a14af911cc231355c8093ee6626e89c07e1037f9e0b22c690e3e049014399ca0212c509cb04c71c7860d1b17a0c47711c490c27bad2825926148a1f15a507f36ba2cdaa04897fce2914e53caed0beaf1bebd2a83af76511cc15bff2165ff0860ad6eca1f30022d7739b2a6b6a72f2feeef0f5941183cda015b4631469e1f4cf27003cab9a90920301cb30d95e4554686922dc5a05c13dfb575cdf113c700d607896011970e6ee7d6edb61210ab28ac8f0c84c606c097e3e300f0a5f5341edfd15432bef6225a498726b62a98283829ad51023b2987f30686cfb4ea3951f3957654035ec291f9b0964a3a8665d81b16cec20fb40f944d5f9bf03ac1e444ad45bae3fa85e7465ce620c0966d8148d6e2856f676c4fbbe3ebe470453efb4bbda1866680037917e37765f680e3da96ef3991f3fe5cda80c523996c2234758bf5f7b6d052dc6942f5a92c8b8eec5d2d8940203bbb6b1cba7b7ebc1334334ca69cdb509a5ea58ec6b2ebaea52307589eaae9430eb15ad234c0c39c83accdf3b77e52a616e345209c5bc9b442f9f0fa96836d9342f983a7",
kdf: "pbkdf2",
kdfparams: {
dklen: 32,
c: 1000000,
prf: "hmac-sha256",
salt: "60f0aa92fbf63a8356dfdbed2ab18058",
},
mac: "51a227ac6db7f2797c63925880b3db664e034231a4c68daa919ab42d8df38bc6",
},
}
```
## Security Considerations
2025-07-30 21:23:33 -04:00
2024-02-28 21:48:27 -05:00
### 1.) Add a Password
2025-07-30 21:23:33 -04:00
An attacker can identify which credential belongs to a node with a combination of `chainId` and
2024-02-28 21:48:27 -05:00
`contractAddress` pair by brute forcing the `treeIndex` iteratively to find a hash match.
The RECOMMENDED solution is to add a password to the construction of `membershipHash` to prevent this attack.
The RECOMMENDED `membershipHash` Construction:
2025-07-30 21:23:33 -04:00
- The `membershipHash` RECOMMENDED to be constructed with `treeIndex` , `membershipContract` ,
`identityCredential` , `rateLimit` , and `membershipPassword`
2024-02-28 21:48:27 -05:00
- `membershipPassword` : a new password created to private attacks compromising keystore credentials.
- The user MUST store the `membershipPassword` privately.
## Copyright
Copyright and related rights waived via [CC0 ](https://creativecommons.org/publicdomain/zero/1.0/ ).
## References
2025-07-30 20:49:21 -04:00
1. [32/RLN-V1 ](https://github.com/vacp2p/rfc-index/blob/main/vac/32/rln-v1.md )
2. [17/WAKU2-RLN-RELAY ](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/17/rln-relay.md )
2024-02-28 21:48:27 -05:00
3. [SHA256 ](https://www.rfc-editor.org/rfc/rfc4634.txt )
4. [EIP155 ](https://eips.ethereum.org/EIPS/eip-155 )
5. [Poseidon Paper ](https://eprint.iacr.org/2019/458.pdf )
6. [EIP-2335 ](https://eips.ethereum.org/EIPS/eip-2335 )
7. [RFC 2898 ](https://www.ietf.org/rfc/rfc2898.txt )
8. [ERC-2335: BLS12-381 Keystore ](https://eips.ethereum.org/EIPS/eip-2335 )