From c48f792dba0989fe17b6352cc45067c61e7f78a5 Mon Sep 17 00:00:00 2001 From: curryrasul Date: Sun, 2 Oct 2022 21:01:43 +0000 Subject: [PATCH] deploy: c84054b900c5601f2c709016294c3959ce17f0ce --- index.html | 1 - print.html | 28 +++++++++++++++++++++------- protocol_spec.html | 27 +++++++++++++++++++++------ rln.html | 1 - searchindex.js | 2 +- searchindex.json | 2 +- 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/index.html b/index.html index fe07d7d..c996eb6 100644 --- a/index.html +++ b/index.html @@ -138,7 +138,6 @@

RLN (Rate-Limiting Nullifier) is a zk-gadget/protocol that enables spam prevention mechanism for anonymous environments.

RLN is part of (PSE) Privacy & Scaling Explorations, a multidisciplinary team supported by the Ethereum Foundation. PSE explores new use cases for zero-knowledge proofs and other cryptographic primitives.

alt text

-

RLN team is working on the protocol (having the same name), implementations and different applications of it.

diff --git a/print.html b/print.html index 2ed1542..30ceb28 100644 --- a/print.html +++ b/print.html @@ -139,7 +139,6 @@

RLN (Rate-Limiting Nullifier) is a zk-gadget/protocol that enables spam prevention mechanism for anonymous environments.

RLN is part of (PSE) Privacy & Scaling Explorations, a multidisciplinary team supported by the Ethereum Foundation. PSE explores new use cases for zero-knowledge proofs and other cryptographic primitives.

alt text

-

RLN team is working on the protocol (having the same name), implementations and different applications of it.

Overview

This section is a starting point for understanding the concepts of RLN.

Here we'll discuss:

@@ -184,7 +183,7 @@
  • How circuits are implemented
  • Technical side of RLN

    -

    This topic is a less strict version of specifications. If you want more formal description, you can find specs in the references

    +

    This topic is a less strict version of specifications. If you want more formal description, you can find specs in the references. Also, if you're not familiar with Shamir's Secret Sharing scheme, you can read it here.


    As it's been said RLN consists of three parts:

    Well, let's discuss them.

    User registration

    -

    First part of RLN is registration. There is nothing special in RLN registration; it's almost the same process as in other protocols/apps with anonymous environments: we need to create Merkle Tree and every participant must submit the commitment and place it in the Merkle Tree, and after that to interact with the app every participant will create zkProof's, that she is a member of the tree.

    -

    We'll use Incremental Merkle Tree, as it more GAS-effective.

    -

    The slight difference is that we must enable secret sharing scheme (to split the commitment into parts). Thus, generation of the commitment is different.

    -

    Each member randomly generate secret key, that is denoted by a_0. Identity commitment q is the hash (Poseidon) of the secret key: q = Poseidon(a_0).

    -

    RLN would have no sense if there was no punishment for spam, that's why to become a member a user have to provide a certain form of stake.

    +

    First part of RLN is registration. There is nothing special in RLN registration; it's almost the same process as in other protocols/apps with anonymous environments: we need to create Merkle Tree and every participant must submit the commitment and place it in the Merkle Tree, and after that to interact with the app every participant will create zkProof's, that he is a member of the tree (we use Incremental Merkle Tree, as it more GAS-effective).

    +

    So, each member randomly generate secret key, that is denoted by a_0. Identity commitment q is the hash (Poseidon) of the secret key: q = Poseidon(a_0).

    +

    RLN would have no sense if there was no punishment for spam, that's why to become a member a user have to provide a certain form of stake. So, whoever has our a_0 can "slash" us.

    +

    The slight difference is that we must enable secret sharing scheme (to split the commitment into parts). We need to come up with polynomial. For simplicity we use linear polynomial (e.g. f(x) = kx + b). Therefore, having two points we can recover the polynomial.

    +

    Our polynomial will be: A(x) = (a_0, a_1), where a_1 = Poseidon(a_0, epoch).

    +

    Less strict: A(x) = a_1 * x + a_0.

    +

    epoch is just a simple identificator (also called external nullifier). And each epoch there is a polynomial with new a_1 and same a_0.

    +

    Signalling

    +

    Now, that the user is registered, he wants to interact with the system. Imagine, that the system is an anonymous chat and the interaction is the sending of messages. +So, to send a message user have to come up with share - the point (x, y) on her polynomial. +We denote: x = Poseidon(message), and y = A(x).

    +

    Thus, if in the same epoch user sends more than one message, his polynomial, and therefore his secret (a_0) can be recovered.

    +

    Of course, we somehow must prove that our share = (x, y) is valid (that this is really a point on our polynomial = A(x)), as well as we must prove other things are valid too, that's why we use zkSNARK. An explanation of the zk-circuits can be found in the next topic.

    +

    Slashing

    +

    As it's been said, if a user sends more than one message, everyone else will be able to recover his secret, slash him and take his stake.

    +

    Some important notes

    +

    There are also nullifier and rln_identifier which can be found in the RLN protocol/circuits.

    +

    So, rln_identifier is just a random value, that's unique per RLN app. It's used for additional cross-application security - to protect the user secrets being compromised if they use the same credentials accross different RLN apps. If rln_identifier is not present, the user uses the same credentials and sends a different message for two different RLN apps using the same epoch, then their secret key can be revealed. With adding the rln_identifier field we obscure the nullifier, so this kind of attack cannot happen. The only kind of attack that is possible is if we have an entity with a global view of all messages, and they try to brute force different combinations of x and y shares for different nullifiers.

    +

    Now, imagine, there are a lot of users sending messages and after each received message we need to check if any member can be slashed. For that we use all combinations of received shares and try to recover the polynomial. This is naive and non-optimal way. What if we have some mechanism, which will tell us about the connection between a person and his messages, while not revealing him. +For that we can use nullifier. nullifier = Poseidon(a_1, rln_identifier) and it's public, thus, if user sends more than one message, it will be immediately visible to everyone.

    Diagram

    flowchart TB
     
    diff --git a/protocol_spec.html b/protocol_spec.html
    index 157357b..f8daf48 100644
    --- a/protocol_spec.html
    +++ b/protocol_spec.html
    @@ -135,7 +135,7 @@
                     

    Technical side of RLN

    -

    This topic is a less strict version of specifications. If you want more formal description, you can find specs in the references

    +

    This topic is a less strict version of specifications. If you want more formal description, you can find specs in the references. Also, if you're not familiar with Shamir's Secret Sharing scheme, you can read it here.


    As it's been said RLN consists of three parts:

      @@ -145,11 +145,26 @@

    Well, let's discuss them.

    User registration

    -

    First part of RLN is registration. There is nothing special in RLN registration; it's almost the same process as in other protocols/apps with anonymous environments: we need to create Merkle Tree and every participant must submit the commitment and place it in the Merkle Tree, and after that to interact with the app every participant will create zkProof's, that she is a member of the tree.

    -

    We'll use Incremental Merkle Tree, as it more GAS-effective.

    -

    The slight difference is that we must enable secret sharing scheme (to split the commitment into parts). Thus, generation of the commitment is different.

    -

    Each member randomly generate secret key, that is denoted by a_0. Identity commitment q is the hash (Poseidon) of the secret key: q = Poseidon(a_0).

    -

    RLN would have no sense if there was no punishment for spam, that's why to become a member a user have to provide a certain form of stake.

    +

    First part of RLN is registration. There is nothing special in RLN registration; it's almost the same process as in other protocols/apps with anonymous environments: we need to create Merkle Tree and every participant must submit the commitment and place it in the Merkle Tree, and after that to interact with the app every participant will create zkProof's, that he is a member of the tree (we use Incremental Merkle Tree, as it more GAS-effective).

    +

    So, each member randomly generate secret key, that is denoted by a_0. Identity commitment q is the hash (Poseidon) of the secret key: q = Poseidon(a_0).

    +

    RLN would have no sense if there was no punishment for spam, that's why to become a member a user have to provide a certain form of stake. So, whoever has our a_0 can "slash" us.

    +

    The slight difference is that we must enable secret sharing scheme (to split the commitment into parts). We need to come up with polynomial. For simplicity we use linear polynomial (e.g. f(x) = kx + b). Therefore, having two points we can recover the polynomial.

    +

    Our polynomial will be: A(x) = (a_0, a_1), where a_1 = Poseidon(a_0, epoch).

    +

    Less strict: A(x) = a_1 * x + a_0.

    +

    epoch is just a simple identificator (also called external nullifier). And each epoch there is a polynomial with new a_1 and same a_0.

    +

    Signalling

    +

    Now, that the user is registered, he wants to interact with the system. Imagine, that the system is an anonymous chat and the interaction is the sending of messages. +So, to send a message user have to come up with share - the point (x, y) on her polynomial. +We denote: x = Poseidon(message), and y = A(x).

    +

    Thus, if in the same epoch user sends more than one message, his polynomial, and therefore his secret (a_0) can be recovered.

    +

    Of course, we somehow must prove that our share = (x, y) is valid (that this is really a point on our polynomial = A(x)), as well as we must prove other things are valid too, that's why we use zkSNARK. An explanation of the zk-circuits can be found in the next topic.

    +

    Slashing

    +

    As it's been said, if a user sends more than one message, everyone else will be able to recover his secret, slash him and take his stake.

    +

    Some important notes

    +

    There are also nullifier and rln_identifier which can be found in the RLN protocol/circuits.

    +

    So, rln_identifier is just a random value, that's unique per RLN app. It's used for additional cross-application security - to protect the user secrets being compromised if they use the same credentials accross different RLN apps. If rln_identifier is not present, the user uses the same credentials and sends a different message for two different RLN apps using the same epoch, then their secret key can be revealed. With adding the rln_identifier field we obscure the nullifier, so this kind of attack cannot happen. The only kind of attack that is possible is if we have an entity with a global view of all messages, and they try to brute force different combinations of x and y shares for different nullifiers.

    +

    Now, imagine, there are a lot of users sending messages and after each received message we need to check if any member can be slashed. For that we use all combinations of received shares and try to recover the polynomial. This is naive and non-optimal way. What if we have some mechanism, which will tell us about the connection between a person and his messages, while not revealing him. +For that we can use nullifier. nullifier = Poseidon(a_1, rln_identifier) and it's public, thus, if user sends more than one message, it will be immediately visible to everyone.

    Diagram

    flowchart TB
     
    diff --git a/rln.html b/rln.html
    index fe07d7d..c996eb6 100644
    --- a/rln.html
    +++ b/rln.html
    @@ -138,7 +138,6 @@
     

    RLN (Rate-Limiting Nullifier) is a zk-gadget/protocol that enables spam prevention mechanism for anonymous environments.

    RLN is part of (PSE) Privacy & Scaling Explorations, a multidisciplinary team supported by the Ethereum Foundation. PSE explores new use cases for zero-knowledge proofs and other cryptographic primitives.

    alt text

    -

    RLN team is working on the protocol (having the same name), implementations and different applications of it.

    diff --git a/searchindex.js b/searchindex.js index a842b53..744dd9b 100644 --- a/searchindex.js +++ b/searchindex.js @@ -1 +1 @@ -Object.assign(window.search, {"doc_urls":["rln.html#rln","overview.html#overview","what_is_rln.html#what-is-rate-limiting-nullifier","what_is_rln.html#how-it-works","what_is_rln.html#user-registration","what_is_rln.html#user-interaction","what_is_rln.html#user-removal-slashing","under_the_hood.html#under-the-hood","protocol_spec.html#technical-side-of-rln","protocol_spec.html#user-registration","protocol_spec.html#diagram","circuits.html#circuits","uses.html#uses","uses.html#zk-chat","how_to_use.html#how-to-use","theory.html#theory","sss.html#shamirs-secret-sharing-scheme","appendix.html#appendix","terminology.html#terminology","references.html#references"],"index":{"documentStore":{"docInfo":{"0":{"body":45,"breadcrumbs":2,"title":1},"1":{"body":19,"breadcrumbs":2,"title":1},"10":{"body":107,"breadcrumbs":6,"title":1},"11":{"body":19,"breadcrumbs":5,"title":1},"12":{"body":0,"breadcrumbs":3,"title":1},"13":{"body":2,"breadcrumbs":4,"title":2},"14":{"body":14,"breadcrumbs":2,"title":1},"15":{"body":12,"breadcrumbs":2,"title":1},"16":{"body":239,"breadcrumbs":8,"title":4},"17":{"body":9,"breadcrumbs":2,"title":1},"18":{"body":201,"breadcrumbs":3,"title":1},"19":{"body":26,"breadcrumbs":4,"title":1},"2":{"body":83,"breadcrumbs":5,"title":3},"3":{"body":43,"breadcrumbs":3,"title":1},"4":{"body":65,"breadcrumbs":4,"title":2},"5":{"body":134,"breadcrumbs":4,"title":2},"6":{"body":63,"breadcrumbs":5,"title":3},"7":{"body":15,"breadcrumbs":5,"title":2},"8":{"body":30,"breadcrumbs":8,"title":3},"9":{"body":81,"breadcrumbs":7,"title":2}},"docs":{"0":{"body":"RLN (Rate-Limiting Nullifier) is a zk-gadget/protocol that enables spam prevention mechanism for anonymous environments. RLN is part of ( PSE ) Privacy & Scaling Explorations , a multidisciplinary team supported by the Ethereum Foundation. PSE explores new use cases for zero-knowledge proofs and other cryptographic primitives. alt text RLN team is working on the protocol (having the same name), implementations and different applications of it.","breadcrumbs":"RLN » RLN","id":"0","title":"RLN"},"1":{"body":"This section is a starting point for understanding the concepts of RLN . Here we'll discuss: Basic explanation of the RLN protocol RLN protocol under the hood RLN uses","breadcrumbs":"Overview » Overview","id":"1","title":"Overview"},"10":{"body":"flowchart TB subgraph Generate Secret Key random0(Random 32 bytes) --> a_0(Secret Key) random1(Random 32 bytes) --> a_0 end subgraph RLN subgraph Identity Commitment a_0 --> h0(Poseidon Hash) h0 --> q(Identity Commitment) end subgraph Calculate Internal Nullifier a_0 --> h1(Poseidon Hash) epoch(Epoch) --> h1 h1 --> a_1 rln_identifier(RLN Identifier) --> h2(Poseidon Hash) a_1 --> h2 h2 --> nullifier(RLN Internal Nullifier) end subgraph Merkle Tree q --> merkle_tree_inclusion_proof(Merkle Tree Inclusion Proof) merkle_tree_inclusion_proof --> root(ZKP of Merkle Tree Root) end subgraph Shamirs Secret Scheme a_0 --> plus(+) a_1 --> multiply(*) x(Hashed Messaage) --> multiply multiply --> plus plus --> share_y end nullifier --> proof(ZKP) root --> proof share_y --> proof end","breadcrumbs":"Overview » Under the hood » Protocol spec » Diagram","id":"10","title":"Diagram"},"11":{"body":"zkSNARK is used in the RLN core. Therefore, we need to represent the protocol in R1CS (as we use Groth16). Circom DSL was chosen for this. This section provides an explanation of RLN circuits.","breadcrumbs":"Overview » Under the hood » Circuits » Circuits","id":"11","title":"Circuits"},"12":{"body":"","breadcrumbs":"Overview » Uses » Uses","id":"12","title":"Uses"},"13":{"body":"https://github.com/njofce/zk-chat","breadcrumbs":"Overview » Uses » zk-chat","id":"13","title":"zk-chat"},"14":{"body":"This section provides information on how to use RLN in your project: JavaScript RLN (for rln-js ) Rust RLN (for zerokit-rln )","breadcrumbs":"How to use » How to use","id":"14","title":"How to use"},"15":{"body":"This section provides theoretical information that underpins RLN . Here we'll discuss: Shamir's Secret Sharing","breadcrumbs":"Theory » Theory","id":"15","title":"Theory"},"16":{"body":"Shamirs Secret Sharing allows to split the secret to n parts and restore it upon presentation any m parts (m <= n) Sharmir's Secret Sharing wikipedia is a good reference to understand the concept. Reconstruction 1: https://github.com/akinovak/semaphore-lib/blob/5b9bb3210192c8e508eced7ef6579fd56e635ed0/src/rln.ts#L31 retrievePrivateKey(x1: bigint, x2:bigint, y1:bigint, y2:bigint): Buffer | ArrayBuffer { const slope = Fq.div(Fq.sub(y2, y1), Fq.sub(x2, x1)) const privateKey = Fq.sub(y1, Fq.mul(slope, x1)); return bigintConversion.bigintToBuf(Fq.normalize(privateKey)); } Reconstruction 2: https://github.com/akinovak/semaphore-lib/blob/rln_signature_changes/test/index.ts#L250 async function testRlnSlashingSimulation() { RLN.setHasher('poseidon'); const identity = RLN.genIdentity(); const privateKey = identity.keypair.privKey; const leafIndex = 3; const idCommitments: Array = []; for (let i=0; i = []; for (let i=0; i = []; for (let i=0; i = []; for (let i=0; i