mirror of https://github.com/vacp2p/rfc.git
chore(32-RLN): update v1 RFC (#581)
fix(32-RLN): change to stable version & rename to RLN-V1 chore(32-RLN): add SSS attack description chore(32-RLN): PR fixes chore(32-RLN): minor PR changes
This commit is contained in:
parent
c70a47f645
commit
c9052d1826
|
@ -1,14 +1,15 @@
|
|||
---
|
||||
slug: 32
|
||||
title: 32/RLN
|
||||
title: 32/RLN-V1
|
||||
name: Rate Limit Nullifier
|
||||
status: raw
|
||||
editor: Blagoj Dimovski <blagoj.dimovski@yandex.com>
|
||||
editor: Rasul Ibragimov <curryrasul@gmail.com>
|
||||
contributors:
|
||||
- Barry Whitehat <barrywhitehat@protonmail.com>
|
||||
- Sanaz Taheri <sanaz@status.im>
|
||||
- Oskar Thorén <oskar@status.im>
|
||||
- Onur Kilic <onurkilic1004@gmail.com>
|
||||
- Blagoj Dimovski <blagoj.dimovski@yandex.com>
|
||||
---
|
||||
|
||||
# Abstract
|
||||
|
@ -133,14 +134,13 @@ For proof generation,
|
|||
the user need to submit the following fields to the circuit:
|
||||
|
||||
```
|
||||
{
|
||||
{
|
||||
identity_secret: identity_secret_hash,
|
||||
path_elements: Merkle_proof.path_elements,
|
||||
identity_path_index: Merkle_proof.indices,
|
||||
x: signal_hash,
|
||||
epoch: epoch,
|
||||
rln_identifier: rln_identifier
|
||||
}
|
||||
external_nullifier: external_nullifier
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
@ -155,8 +155,7 @@ The following fields are needed for proof output calculation:
|
|||
```
|
||||
{
|
||||
identity_secret_hash: bigint,
|
||||
epoch: bigint,
|
||||
rln_identifier: bigint,
|
||||
external_nullifier: bigint,
|
||||
x: bigint,
|
||||
}
|
||||
```
|
||||
|
@ -164,8 +163,6 @@ The following fields are needed for proof output calculation:
|
|||
The output `[y, internal_nullifier]` is calculated in the following way:
|
||||
|
||||
```
|
||||
external_nullifier = poseidonHash([epoch, rln_identifier])
|
||||
|
||||
a_0 = identity_secret_hash
|
||||
a_1 = poseidonHash([a0, external_nullifier])
|
||||
|
||||
|
@ -196,10 +193,10 @@ Additionally depending on the application,
|
|||
the following fields might be required:
|
||||
|
||||
```
|
||||
{
|
||||
{
|
||||
root: Merkle_proof.root,
|
||||
epoch: epoch
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
@ -265,8 +262,7 @@ The `zk_proof` should be verified by providing the `zk_proof` field to the circu
|
|||
Merkle_proof.root,
|
||||
internal_nullifier,
|
||||
x, # signal_hash
|
||||
epoch,
|
||||
rln_identifier
|
||||
external_nullifier
|
||||
]
|
||||
```
|
||||
|
||||
|
@ -345,15 +341,14 @@ using the [circomlib](https://docs.circom.io/) library.
|
|||
|
||||
### System parameters
|
||||
|
||||
- `n_levels` - Merkle tree depth
|
||||
- `DEPTH` - Merkle tree depth
|
||||
|
||||
|
||||
### Circuit parameters
|
||||
|
||||
**Public Inputs**
|
||||
- `x`
|
||||
- `epoch`
|
||||
- `rln_identifier`
|
||||
- `external_nullifier`
|
||||
|
||||
**Private Inputs**
|
||||
* `identity_secret_hash`
|
||||
|
@ -443,9 +438,9 @@ The identity credentials of a user are composed of:
|
|||
The `identity_secret` is generated in the following way:
|
||||
|
||||
```
|
||||
identity_nullifier = random_32_byte_buffer
|
||||
identity_trapdoor = random_32_byte_buffer
|
||||
identity_secret = [identity_nullifier, identity_trapdoor]
|
||||
identity_nullifier = random_32_byte_buffer
|
||||
identity_trapdoor = random_32_byte_buffer
|
||||
identity_secret = [identity_nullifier, identity_trapdoor]
|
||||
```
|
||||
|
||||
The same secret should not be used accross different protocols,
|
||||
|
@ -456,7 +451,7 @@ because revealing the secret at one protocol could break privacy for the user in
|
|||
The `identity_secret_hash` is generated by obtaining a Poseidon hash of the `identity_secret` array:
|
||||
|
||||
```
|
||||
identity_secret_hash = poseidonHash(identity_secret)
|
||||
identity_secret_hash = poseidonHash(identity_secret)
|
||||
```
|
||||
|
||||
### `identity_commitment`
|
||||
|
@ -477,6 +472,16 @@ The standard for this is to use trusted [Multi-Party Computation (MPC)](https://
|
|||
which requires two phases.
|
||||
Trusted MPC ceremony has not yet been performed for the RLN circuits.
|
||||
|
||||
## SSS security assumptions
|
||||
|
||||
Shamir-Secret Sharing requires polynomial coefficients to be independent of each other.
|
||||
However, `a_1` depends on `a_0` through the Poseidon hash algorithm.
|
||||
Due to the design of Poseidon, it is possible to [attack](https://github.com/Rate-Limiting-Nullifier/rln-circuits/pull/7#issuecomment-1416085627) the protocol.
|
||||
It was decided *not* to change the circuits design, since at the moment the attack is infeasible. Therefore, implementers must be aware that the current version provides approximately 160-bit security and not 254.
|
||||
Possible improvements:
|
||||
* [change the circuit](https://github.com/Rate-Limiting-Nullifier/rln-circuits/pull/7#issuecomment-1416085627) to make coefficients independent;
|
||||
* switch to other hash function (Keccak, SHA);
|
||||
|
||||
# Appendix B: Identity scheme choice
|
||||
|
||||
The hashing scheme used is based on the design decisions which also include the Semaphore circuits.
|
||||
|
@ -499,9 +504,9 @@ To achieve the above interoperability UX while preventing the shared app securit
|
|||
we had to do the follow in regard the identity secret and identity commitment:
|
||||
|
||||
```
|
||||
identity_secret = [identity_nullifier, identity_trapdoor]
|
||||
identity_secret_hash = poseidonHash(identity_secret)
|
||||
identity_commitment = poseidonHash([identity_secret_hash])
|
||||
identity_secret = [identity_nullifier, identity_trapdoor]
|
||||
identity_secret_hash = poseidonHash(identity_secret)
|
||||
identity_commitment = poseidonHash([identity_secret_hash])
|
||||
```
|
||||
|
||||
Secret components for generating Semaphore proof:
|
||||
|
@ -554,82 +559,73 @@ The examples are written in [rust](https://www.rust-lang.org/).
|
|||
## Creating a RLN object
|
||||
|
||||
```rust
|
||||
use rln::protocol::*;
|
||||
use rln::public::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
// We set the RLN parameters:
|
||||
// - the tree height;
|
||||
// - the circuit resource folder (requires a trailing "/").
|
||||
let tree_height = 20;
|
||||
let resources = Cursor::new("../zerokit/rln/resources/tree_height_20/");
|
||||
|
||||
// We create a new RLN instance
|
||||
let mut rln = RLN::new(tree_height, resources);
|
||||
use rln::protocol::*;
|
||||
use rln::public::*;
|
||||
use std::io::Cursor;
|
||||
// We set the RLN parameters:
|
||||
// - the tree height;
|
||||
// - the circuit resource folder (requires a trailing "/").
|
||||
let tree_height = 20;
|
||||
let resources = Cursor::new("../zerokit/rln/resources/tree_height_20/");
|
||||
// We create a new RLN instance
|
||||
let mut rln = RLN::new(tree_height, resources);
|
||||
```
|
||||
|
||||
## Generating identity credentials
|
||||
|
||||
```rust
|
||||
// We generate an identity tuple
|
||||
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.extended_key_gen(&mut buffer).unwrap();
|
||||
|
||||
// We deserialize the keygen output to obtain
|
||||
// the identiy_secret and id_commitment
|
||||
let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) = deserialize_identity_tuple(buffer.into_inner());
|
||||
// We generate an identity tuple
|
||||
let mut buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.extended_key_gen(&mut buffer).unwrap();
|
||||
// We deserialize the keygen output to obtain
|
||||
// the identiy_secret and id_commitment
|
||||
let (identity_trapdoor, identity_nullifier, identity_secret_hash, id_commitment) = deserialize_identity_tuple(buffer.into_inner());
|
||||
```
|
||||
|
||||
## Adding ID commitment to the RLN Merkle tree
|
||||
|
||||
```rust
|
||||
// We define the tree index where id_commitment will be added
|
||||
let id_index = 10;
|
||||
|
||||
// We serialize id_commitment and pass it to set_leaf
|
||||
let mut buffer = Cursor::new(serialize_field_element(id_commitment));
|
||||
rln.set_leaf(id_index, &mut buffer).unwrap();
|
||||
// We define the tree index where id_commitment will be added
|
||||
let id_index = 10;
|
||||
// We serialize id_commitment and pass it to set_leaf
|
||||
let mut buffer = Cursor::new(serialize_field_element(id_commitment));
|
||||
rln.set_leaf(id_index, &mut buffer).unwrap();
|
||||
```
|
||||
|
||||
## Setting epoch and signal
|
||||
|
||||
```rust
|
||||
// We generate epoch from a date seed and we ensure is
|
||||
// mapped to a field element by hashing-to-field its content
|
||||
let epoch = hash_to_field(b"Today at noon, this year");
|
||||
|
||||
// We set our signal
|
||||
let signal = b"RLN is awesome";
|
||||
// We generate epoch from a date seed and we ensure is
|
||||
// mapped to a field element by hashing-to-field its content
|
||||
let epoch = hash_to_field(b"Today at noon, this year");
|
||||
// We set our signal
|
||||
let signal = b"RLN is awesome";
|
||||
```
|
||||
|
||||
## Generating proof
|
||||
|
||||
```rust
|
||||
// We prepare input to the proof generation routine
|
||||
let proof_input = prepare_prove_input(identity_secret, id_index, epoch, signal);
|
||||
|
||||
// We generate a RLN proof for proof_input
|
||||
let mut in_buffer = Cursor::new(proof_input);
|
||||
let mut out_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut in_buffer, &mut out_buffer)
|
||||
// We prepare input to the proof generation routine
|
||||
let proof_input = prepare_prove_input(identity_secret, id_index, epoch, signal);
|
||||
// We generate a RLN proof for proof_input
|
||||
let mut in_buffer = Cursor::new(proof_input);
|
||||
let mut out_buffer = Cursor::new(Vec::<u8>::new());
|
||||
rln.generate_rln_proof(&mut in_buffer, &mut out_buffer)
|
||||
.unwrap();
|
||||
|
||||
// We get the public outputs returned by the circuit evaluation
|
||||
let proof_data = out_buffer.into_inner();
|
||||
// We get the public outputs returned by the circuit evaluation
|
||||
let proof_data = out_buffer.into_inner();
|
||||
```
|
||||
|
||||
## Verifiying proof
|
||||
|
||||
```rust
|
||||
// We prepare input to the proof verification routine
|
||||
let verify_data = prepare_verify_input(proof_data, signal);
|
||||
|
||||
// We verify the zk-proof against the provided proof values
|
||||
let mut in_buffer = Cursor::new(verify_data);
|
||||
let verified = rln.verify(&mut in_buffer).unwrap();
|
||||
|
||||
// We ensure the proof is valid
|
||||
assert!(verified);
|
||||
// We prepare input to the proof verification routine
|
||||
let verify_data = prepare_verify_input(proof_data, signal);
|
||||
// We verify the zk-proof against the provided proof values
|
||||
let mut in_buffer = Cursor::new(verify_data);
|
||||
let verified = rln.verify(&mut in_buffer).unwrap();
|
||||
// We ensure the proof is valid
|
||||
assert!(verified);
|
||||
```
|
||||
|
||||
For more details please visit the [`zerokit`](https://github.com/vacp2p/zerokit) library.
|
||||
|
@ -652,3 +648,5 @@ Copyright and related rights waived via [CC0](https://creativecommons.org/public
|
|||
- [10] https://ethresear.ch/t/gas-and-circuit-constraint-benchmarks-of-binary-and-quinary-incremental-merkle-trees-using-the-poseidon-hash-function/7446
|
||||
- [11] https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing
|
||||
- [12] https://research.nccgroup.com/2020/06/24/security-considerations-of-zk-snark-parameter-multi-party-computation/
|
||||
- [13] https://github.com/Rate-Limiting-Nullifier/rln-circuits/
|
||||
- [14] https://rate-limiting-nullifier.github.io/rln-docs/
|
|
@ -8,7 +8,7 @@ bookMenuLevels: 1
|
|||
- [24/STATUS-CURATION]({{< relref "/docs/rfcs/24/README.md" >}})
|
||||
- [28/STATUS-FEATURING]({{< relref "/docs/rfcs/28/README.md" >}})
|
||||
- [31/WAKU2-ENR]({{< relref "/docs/rfcs/31/README.md" >}})
|
||||
- [32/RLN-SPEC]({{< relref "/docs/rfcs/32/README.md" >}})
|
||||
- [32/RLN-V1-SPEC]({{< relref "/docs/rfcs/32/README.md" >}})
|
||||
- [34/WAKU2-PEER-EXCHANGE]({{< relref "/docs/rfcs/34/README.md" >}})
|
||||
- [35/WAKU2-NOISE]({{< relref "/docs/rfcs/35/README.md" >}})
|
||||
- [37/WAKU2-NOISE-SESSIONS]({{< relref "/docs/rfcs/37/README.md" >}})
|
||||
|
|
Loading…
Reference in New Issue