specs/standards/application/rln-keystore.md
2025-07-30 21:23:33 -04:00

325 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: WAKU-RLN-KEYSTORE
name: Waku RLN Keystore
category: Standards Track
editor: Jimmy Debe <jimmy@status.im>
contributors:
- Aaryamann Challani <aaryamann@status.im>
---
## Abstract
This specification describes how the RLN, Rate Limit Nullifier,
credentials are securely stored in a JSON schema.
## Background
A keystore is a construct to store a users 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.
The secure storage of keys is important in peer-to-peer messaging applications.
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).
### Waku RLN Keystore Format:
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).
```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",
}
}
}
}
```
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.
### Metadata:
Information about the keystore SHOULD be stored in the metadata.
The declaration of `application`, `version`, and `appIdentifier` MAY occur in the metadata.
- `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:
After the RLN credentials are generated, it MUST be stored in a JSON schema.
The credentials MUST consist of a `membershipHash` and `WakuCredential`.
The `membershipHash` will be an identity hash of the user.
The `WakuCredential` will store the encryption portion of the keystore.
There MAY be multiple credentials stored in a keystore,
categorized by the `membershipHash`.
Each contruct MUST include the keypair:
> key: [`membershipHash`]: pair: [`WakuCredential`]
#### membershipHash
The `membershipHash` SHOULD be generated by nodes participating in a membership group,
as decribed in [32/RLN-V1](https://github.com/vacp2p/rfc-index/blob/main/vac/32/rln-v1.md).
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),
other hash functions MAY be used.
The hash function SHOULD be defined in the `verison` attribute.
A `membershipHash` MUST NOT already exist in the keystore.
To generate the `membershipHash` the following attributes SHOULD be used to create a hexadecimal string:
- `treeIndex` :
- `membershipContract`
- `chainId`,
- `identityCredential`
- `rateLimit`
##### `treeIndex`
After a node registers to a group,
a `treeIndex` value of the position in the Merkle tree SHOULD be returned.
- it MUST be a Merkle tree data structure filled with the `identity_commitment` from node registrations.
- it SHOULD be a hexadecimal string
##### `membershipContract`
For decentralized membership registrations,
the `membershipContract` value SHOULD be a `contractAddress` of a smart contract deployed on a blockchain.
- it SHOULD be a string.
##### `chainId`
It uniquely defines the chain upon which the registration has occurred.
The `chainId` value SHOULD be the blockchain identifier used for `membershipContract`,
as described in [EIP155](https://eips.ethereum.org/EIPS/eip-155).
- 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.
- 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.
- `identity_nullifier` : Random 32 byte value
- `identity_trapdoor` : Random 32 byte value
###### `identity_secret_hash`
Used to derive the `identity_commitment` of the node, and
as a private input for zero-knowledge proof generation.
- it MUST be created with `identity_secret` as a parameter for the hash function.
- This secret hash SHOULD be kept private by the node.
###### `identity_commitment`
- 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).
- it MUST be used by a node for group registering.
##### `rateLimit`
- it SHOULD be the node's membership rate limit
#### WakuCredential
The `WakuCredential` will store values used for encrypting and decrypting a node's keystore.
- 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.
The keystore MAY use PBKDF2 password-based encryption,
as described in [RFC 2898](https://www.ietf.org/rfc/rfc2898.txt).
A `WakuCredential` object MUST include:
| 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
The keystore SHOULD decrypt a node's credentials using a password and the `membershipHash`,
using PBKDF2 that returns the `decryptionKey` key.
The `decryptionKey` is used to verify that the keystore has the correct credentials.
- 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
### 1.) Add a Password
An attacker can identify which credential belongs to a node with a combination of `chainId` and
`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:
- The `membershipHash` RECOMMENDED to be constructed with `treeIndex`, `membershipContract`,
`identityCredential`, `rateLimit`, and `membershipPassword`
- `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
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)
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)