From fb6504385a026e6709114741b67bbb77f3b78b90 Mon Sep 17 00:00:00 2001 From: Brechy Date: Thu, 2 Nov 2023 11:16:11 -0300 Subject: [PATCH] chore: deprecation notice --- README.md | 50 +++--- docs/0_attestation_station.md | 28 +++ docs/1_attestations.md | 68 ++++++++ docs/2_data_processing.md | 51 ++++++ docs/3_dynamic_sets.md | 110 ++++++++++++ docs/4_algorithm.md | 170 +++++++++++++++++++ docs/5_beyond.md | 42 +++++ docs/README.md | 20 +++ docs/SUMMARY.md | 9 + eigentrust-cli/LICENSE | 1 - eigentrust-zk/src/ecc/same_curve/mod.rs | 1 + eigentrust-zk/src/gadgets/lt_eq_lookup.rs | 2 + eigentrust-zk/src/integer/native.rs | 2 + eigentrust-zk/src/lib.rs | 1 + eigentrust-zk/src/merkle_tree/native.rs | 1 + eigentrust-zk/src/verifier/aggregator/mod.rs | 1 + eigentrust-zk/src/verifier/transcript/mod.rs | 4 +- eigentrust/LICENSE | 1 - eigentrust/src/lib.rs | 24 +-- scripts/build-docs.sh | 2 +- 20 files changed, 533 insertions(+), 55 deletions(-) create mode 100644 docs/0_attestation_station.md create mode 100644 docs/1_attestations.md create mode 100644 docs/2_data_processing.md create mode 100644 docs/3_dynamic_sets.md create mode 100644 docs/4_algorithm.md create mode 100644 docs/5_beyond.md create mode 100644 docs/README.md create mode 100644 docs/SUMMARY.md delete mode 100644 eigentrust-cli/LICENSE delete mode 100644 eigentrust/LICENSE diff --git a/README.md b/README.md index 22249ed1..d5f1f96b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# ZK Eigen Trust +# ZK EigenTrust - Deprecated + +**Notice: This project is no longer being maintained as of November 2023.** [![MIT licensed][mit-badge]][mit-url] [![Build Status][actions-badge]][actions-url] @@ -8,47 +10,39 @@ [actions-badge]: https://github.com/eigen-trust/protocol/actions/workflows/test.yml/badge.svg [actions-url]: https://github.com/eigen-trust/protocol/actions?query=branch%3Amaster -A library for managing trust in a distributed network with zero-knowledge features. - -## Main characteristics: - -**Self-policing** - the shared ethics of the user population is defined and enforced by the peers themselves and not by some central authority. +A Rust and Halo2-based library designed to manage trust in distributed networks with zero-knowledge proofs, guided by the framework established in the original [EigenTrust paper](https://nlp.stanford.edu/pubs/eigentrust.pdf). Its primary characteristics are: -**Minimal** - computation, infrastructure, storage, and message complexity are reduced to a minimum. +- **Self-policing**: The shared ethics of the user population is defined and enforced by the peers themselves and not by some central authority. -**Incorruptible** - Reputation should be obtained by consistent good behavior through several transactions. This is enforced for all users, so no one can cheat the system and obtain a higher reputation. It is also resistant to malicious collectives. +- **Minimal**: computation, infrastructure, storage, and message complexity are reduced to a minimum. -## Development Guidelines +- **Incorruptible**: Reputation should be obtained by consistent good behavior through several transactions. This is enforced for all users, so no one can cheat the system and obtain a higher reputation. It is also resistant to malicious collectives. -The following document explains the development process and our values: +## Deprecation Notice -[Development Process](https://hackmd.io/MzCV5EGyTo-aNIRUV0PnUQ) +Effective November 2023, this project has been deprecated and is no longer under active development. -## Usage +We invite the community to fork and maintain their own versions of this codebase. Should you choose to do so, we remind you to comply with the terms outlined in the [license](LICENSE). -To build the project: +## Structure -```bash -./scripts/build.sh -``` +The project is organized in three crates: -To build the documentation: +- [eigentrust](eigentrust): This is the core library crate. It provides the `Client` struct for interfacing with the EigenTrust algorithm's circuits and includes additional modules to extend its functionality and facilitate integration. -```bash -./scripts/build-docs.sh +- [eigentrust-cli](eigentrust-cli): This crate offers a command-line interface application that serves as a practical example of using the library. It supports operations such as deploying smart contracts, submitting attestations, calculating global trust scores, and generating and verifying zero-knowledge proofs. -# Open the documentation in the browser -cargo doc --no-deps --open -``` +- [eigentrust-zk](eigentrust-zk): Dedicated to the zero-knowledge components of the protocol, this crate encompasses the necessary Chips, Chipsets, and Circuits that pertain to the EigenTrust protocol implementation. -## License +For a more in-depth understanding of the project's architecture and functionality, please refer to the documentation in the [docs](docs) directory. -This library is licensed under the following license: +There's also a [scripts](scripts) directory containing scripts for building documentation, running tests across the workspace, and compiling the entire project. -- MIT license ([LICENSE](LICENSE) or [opensource.org license link](http://opensource.org/licenses/MIT)) +### License -## Acknowledgements +Licensed under the MIT License - see the [LICENSE](LICENSE) file for details or visit [opensource.org](http://opensource.org/licenses/MIT). -This project is developed under the Ethereum Foundation grant. +### Acknowledgements -The library is implemented according to the original [Eigen Trust paper](https://web.archive.org/web/20230219174826/http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf). +- Ethereum Foundation and Privacy & Scaling Explorations team. +- All contributors to this repository. diff --git a/docs/0_attestation_station.md b/docs/0_attestation_station.md new file mode 100644 index 00000000..509e0897 --- /dev/null +++ b/docs/0_attestation_station.md @@ -0,0 +1,28 @@ +--- +This page describes the AttestationStation smart contract and how its used within the EigenTrust protocol context. +--- + +# AttestationStation + +The AttestationStation smart contract is a key component of the EigenTrust protocol, which is designed to enable trust among peers in decentralized networks. Attestations, also known as opinions or ratings, are an important part of the protocol as they allow peers to express their trust or distrust of other peers. The AttestationStation contract serves as a repository for attestations submitted by peers in the network. + +Examples (Let's assume we are doing ratings from 0-5): +- Alice attests Bob with a rating of 5 +- Alice attests to Carol with a rating of 2 +- Bob attests to Alice with a rating of 3 +- Carol says Bob with a rating of 4 +- Alice attests Bob with a rating of 1 + +The mapping attestations is a 3-dimensional mapping that stores attestations submitted by peers. The first key is the address of the peer submitting the attestation. The second key is the address of the peer being attested to. The third key is a bytes32 hash representing the transaction or interaction between the peers. The value stored in the mapping is a bytes array representing the attestation data. +```solidity +mapping(address => mapping(address => mapping(bytes32 => bytes))) public attestations; +``` + +The AttestationData struct represents an attestation submitted by a peer. The `about` field is the address of the peer being attested to. The `key` field is a bytes32 hash representing the transaction or interaction between the peers. The `val` field is a bytes array representing the attestation data. The structure of the `val` field is described in more detail in the [Attestations](../1_attestations.md) documentation. +```solidity +struct AttestationData { + address about; + bytes32 key; + bytes val; +} +``` diff --git a/docs/1_attestations.md b/docs/1_attestations.md new file mode 100644 index 00000000..55ecbb4a --- /dev/null +++ b/docs/1_attestations.md @@ -0,0 +1,68 @@ +--- +This page describes the smart contract used for attestations +--- + +# Attestations + +Attestations are the ratings or opinions given by one peer about another peer in the EigenTrust protocol. Each attestation is given for a single transaction or interaction between peers. + +The structure of an attestation is defined as follows: +```rust +struct Attestation { + about: F, + key: F, + value: F, + message: F +} +``` + +Here's a breakdown of each field in the attestation: + +- `about`: the Ethereum address of the peer being rated. This could be an EOA, a smart contract, a DAO, etc. +- `key`: a unique identifier for the transaction or interaction being rated. This could be a hash of the transaction data or a random number generated by the rater. +- `value`: the score given by the rater for the transaction or interaction. The score can range from 0 to a maximum score defined as a constant in the protocol. +- `message`: an optional field for attaching additional information to the attestation. This could be a message from the rater, a domain in which the transaction took place, or a content hash related to the transaction. + +To ensure the integrity and authenticity of an attestation, it is hashed using the Poseidon hash function and then signed using the ECDSA signing algorithm: +```rust +let att_hash = Poseidon::hash(attestation); +let sig = ECDSA::sign(att_hash, keys); +``` +The resulting signature, value and message bytes are stored in the AttestationStation smart contract. The bytes layout would be: +```rust +r = [u8; 32] +s = [u8; 32] +value = u8 +message = [u8; 32] +``` +This adds up to 97 bytes or 65 if we exclude message bytes. + +In case of fetching the attestation from AS and verifying it - first, we read the event: +```solidity +event AttestationCreated( + address indexed creator, + address indexed about, + bytes32 indexed key, + bytes val +); +``` + +Using this data, we extract the `r` and `s`, we verify the signature: +```rust +let (r, s, value, message) = extract_r_s_value_message(val); +let att = Attestation::new(about, key, value, message); +let hash = Poseidon::hash(att); +let is_valid = ECDSA::verify(pub_key, r, s, hash); +assert!(is_valid); +``` + +Then check if the used `pub_key` is actually the pre-image of the `creator`: +```rust +let pk_hash = keccak256(pub_key); +let creator_address = to_address(pk_hash); +assert!(creator_address == creator); +``` + +See [AttestationStation](../0_attestation_station.md) for more details on how attestations are stored and managed in the EigenTrust protocol. + +By signing the attestation, the rater can prove that they made the rating and that the rating has not been tampered with. This is important for verifying the validity of the attestation in an off-chain environment, such as when calculating the EigenTrust scores for each peer. diff --git a/docs/2_data_processing.md b/docs/2_data_processing.md new file mode 100644 index 00000000..71306743 --- /dev/null +++ b/docs/2_data_processing.md @@ -0,0 +1,51 @@ +--- +This page provides an overview of how data is processed after being pulled from AttestationStation. The data stored in AttestationStation is submitted from one user to another, but the EigenTrust algorithm processes opinions from one user to the whole group. +--- + +To start, a group needs to be defined. This is typically done by assigning a group ID and creating a list of peers, as shown below: +``` +group_id = 1377 +group = [peer1, peer2, peer3, peer4, peer5] +``` + + +And lets assume we have some attestations in AS already: +``` +peer1 => peer2 => 1377 => 5 +peer2 => peer3 => 1377 => 7 +peer4 => peer2 => 1377 => 3 +``` + +Once the group is defined, the next step is to search AttestationStation to construct an opinion map. This is done by iterating through each peer in the group and searching for relevant attestations. The pseudo code snippet below demonstrates this process: +```rust +for i in 0..group.len() { + let peer_i = group[i]; + if peer_i == null { + continue; + } + for j in 0..group.len() { + let peer_j = group[j]; + + let is_null = peer_j == null; + let is_self = peer_i == peer_j; + if is_null || is_self { + continue; + } + + let att = AS.attestations(peer_i, peer_j, group_id); + op_map[peer_i][j] = (peer_j, att); + } +} +``` + +In this code, `peer_i` and `peer_j` represent two peers in the group, and `AS.attestations(peer_i, peer_j, group_id)` retrieves the attestation between the two peers for the given group ID. The resulting opinion map, stored in the op_map variable, is a two-dimensional array that maps each peer to a list of their attestations with other peers in the group. + +Here's an example of what the opinion map might look like, based on the attestations shown earlier: +``` +peer1_op => [(peer1, 0), (peer2, 5), (peer3, 0), (peer4, 0), (peer5, 0)] +peer2_op => [(peer1, 0), (peer2, 0), (peer3, 7), (peer4, 0), (peer5, 0)] +peer4_op => [(peer1, 0), (peer2, 3), (peer3, 0), (peer4, 0), (peer5, 0)] +``` + +This opinion map is then passed to a filtering algorithm before being passed to the EigenTrust algorithm.\ +The details of the filtering algorithm are discussed in more detail in the [Dynamic Sets](../3_dynamic_sets.md) page. diff --git a/docs/3_dynamic_sets.md b/docs/3_dynamic_sets.md new file mode 100644 index 00000000..f424f131 --- /dev/null +++ b/docs/3_dynamic_sets.md @@ -0,0 +1,110 @@ +--- +This page describes our dynamic sets filtering algorithm. +--- + +Suppose we create a fixed set of peers with a limit of 5.\ +Instead of using Ethereum addresses we will use simplified identifiers +like peer1, peer2, peer3, etc. and we will use `null` for empty slots. + +This set will change over time as we will be able to add and remove members. + +For example, let's say we have the following set of peers: +``` +set = [peer1, peer2, peer3, null, null] +``` + +Now, imagine we have a map that represent opinions from one peer to the whole group. Every opinion should match the set to be valid, in the following way: +``` +peer1 => [(peer1, 0), (peer2, 4), (peer3, 6), (null, 0), (null, 0)] +``` +The opinion array should equal the original set in length.\ +The items in the array are touples of the id of the peer that we want to give the score to and the actual score. The id at each index should match the id in the set in order to be considered valid. + +The whole map should look like this: +``` +scores => { + peer1 => [(peer1, 0), (peer2, 4), (peer3, 6), (null, 0), (null, 0)] + peer2 => [(peer1, 4), (peer2, 0), (peer3, 6), (null, 0), (null, 0)] + peer3 => [(peer1, 4), (peer2, 6), (peer3, 0), (null, 0), (null, 0)] +} +``` + +Now, let's take a look at how we filter out invalid cases from the opinion array. + +**Filtering of invalid cases:** + +1) Id at the specific index does not match the one in the set:\ +Suppose we want to give a score of 5 to peer13 at the index 3: +``` +peer1 => [(peer1, 0), (peer2, 4), (peer3, 6), (peer13, 5), (null, 0)] +``` +Since the id at index 3 is null, the id and the score will be nullified, and the new opinion will look like: +``` +peer1 => [(peer1, 0), (peer2, 4), (peer3, 6), (null, 0), (null, 0)] +``` + +2) Non 0 score was given to itself:\ +Giving score to itself is forbiden since peers would be able to give the score only to themselves, thus introducing reputation leaking during the convergence. +So, this type of opinion: +``` +peer1 => [(peer1, 4), (peer2, 0), (peer3, 6), (null, 0), (null, 0)] +``` +will turn into: +``` +peer1 => [(peer1, 0), (peer2, 0), (peer3, 6), (null, 0), (null, 0)] +``` + +3) Total sum of scores is 0:\ +If the initial opinion, or the filtered opinion has a sum of scores of 0, +the equal score (score of 1) is given to each peer, so this: +``` +peer1 => [(peer1, 0), (peer2, 0), (peer3, 0), (null, 0), (null, 0)] +``` +will turn into this: +``` +peer1 => [(peer1, 0), (peer2, 1), (peer3, 1), (null, 0), (null, 0)] +``` + +4) Opinion array does not exist/not signed:\ +Will be treated the same way as 3). The equal score will be distributed to all peers + +The pseudo code algorithm: +```rust +for i in set.len() { + let pk_i = set[i]; + if pk_i == null { + continue; + } + + for j in set.len() { + let pk_j = set[j]; + let op_pk_j = scores[pk_i][j].0; + + let is_diff_pk_j = pk_j != op_pk_j; + let is_pk_j_zero = pk_j == null; + let is_pk_i = pk_j == pk_i; + + if is_diff_pk_j || is_pk_j_zero || is_pk_i { + scores[pk_i][j].1 = 0; + } + + if is_diff_pk_j { + scores[pk_i][j].0 = pk_j; + } + } + + let op_score_sum = sum(scores[pk_i]); + if op_score_sum == 0 { + for j in 0..group.len() { + let pk_j = scores[pk_i][j].0; + + let is_diff_pk = pk_j != pk_i; + let is_not_null = pk_j != null; + + if is_diff_pk && is_not_null { + scores[pk_i][j] = (pk_j, Fr::from(1)); + } + } + } +} +``` diff --git a/docs/4_algorithm.md b/docs/4_algorithm.md new file mode 100644 index 00000000..3493e321 --- /dev/null +++ b/docs/4_algorithm.md @@ -0,0 +1,170 @@ +--- +description: A higher level description of Eigen Trust protocol. +--- + +# Algorithm + +The name Eigen Trust originates from the [original paper](https://nlp.stanford.edu/pubs/eigentrust.pdf). + +It relates to the way the reputation score is calculated, which is done the following way: + +Suppose we have a vector `s` that contains the initial scores for 5 peers: +``` +s = [1000, 2000, 500, 300, 200] +``` + +We will refer to peers by their index in this set. e.g. Peer 0 is a peer on index `0` (which has reputation of `1000`) + +Now let's suppose we have an opinion matrix: +``` +op0 = [0.0, 0.2, 0.3, 0.5, 0.0] - Peer 0 opinions +op1 = [0.1, 0.0, 0.1, 0.1, 0.7] - Peer 1 opinions +op2 = [0.4, 0.1, 0.0, 0.2, 0.3] - Peer 2 opinions +op3 = [0.1, 0.1, 0.7, 0.0, 0.1] - Peer 3 opinions +op4 = [0.3, 0.1, 0.4, 0.2, 0.0] - Peer 4 opinions +``` + +The matrix define above describes the distribution of the reputation owned by the peers. Notice that the sum of the distribution of one peer is equal to `1.0`, and we are also not giving ourselves any amount. + +Now, let's turn that that distribution into scores: + +We take the score of Peer N and multiply it with each element in `op[n]`: +``` +sop0 = s[0] * op0 = [ 0, 200, 300, 500, 0] +sop1 = s[1] * op1 = [200, 0, 200, 200, 1400] +sop2 = s[2] * op2 = [200, 50, 0, 100, 150] +sop3 = s[3] * op3 = [ 30, 30, 210, 0, 30] +sop4 = s[4] * op4 = [ 60, 20, 80, 40, 0] +``` + +Now, from this new matrix we can get the new scores for Peer 0: +``` +s0 = sop0[0] + sop1[0] + sop2[0] + sop3[0] + sop4[0] = 0 + 200 + 200 + 30 + 60 = 490 +``` + +If we apply the same for formula we can get the new scores for all peers: +``` +s = [490, 300, 790, 840, 1580] +``` + +Notice that amount of reputation in the system is always the same (compare with initial `s`). The reputation cannot be created or destroyed, it can only be allocated. + +Everything we did was just one iteration of Eigen Trust algorithm. If we apply the same process throughout several iterations, the reputation score of each peer will not change much further after a certain point. When that happens we say that the reputation scores has **converged.** + +Here is an algorithm example written in Rust: +```rust +let mut s: [f32; 5] = [1000., 2000., 500., 300., 200.]; + +const NUM_ITER: usize = 10; + +let op0 = [0.0, 0.2, 0.3, 0.5, 0.0]; // - Peer 0 opinions +let op1 = [0.1, 0.0, 0.1, 0.1, 0.7]; // - Peer 1 opinions +let op2 = [0.4, 0.1, 0.0, 0.2, 0.3]; // - Peer 2 opinions +let op3 = [0.1, 0.1, 0.7, 0.0, 0.1]; // - Peer 3 opinions +let op4 = [0.3, 0.1, 0.4, 0.2, 0.0]; // = Peer 4 opinions + +for _ in 0..NUM_ITER { + // sop0 = s[0] * op0 + let sop0 = op0.map(|v| v * s[0]); + // sop1 = s[1] * op1 + let sop1 = op1.map(|v| v * s[1]); + // sop2 = s[2] * op2 + let sop2 = op2.map(|v| v * s[2]); + // sop3 = s[3] * op3 + let sop3 = op3.map(|v| v * s[3]); + // sop4 = s[4] * op4 + let sop4 = op4.map(|v| v * s[4]); + + let s0 = sop0[0] + sop1[0] + sop2[0] + sop3[0] + sop4[0]; + let s1 = sop0[1] + sop1[1] + sop2[1] + sop3[1] + sop4[1]; + let s2 = sop0[2] + sop1[2] + sop2[2] + sop3[2] + sop4[2]; + let s3 = sop0[3] + sop1[3] + sop2[3] + sop3[3] + sop4[3]; + let s4 = sop0[4] + sop1[4] + sop2[4] + sop3[4] + sop4[4]; + + s = [s0, s1, s2, s3, s4]; + + println!("[{}]", s.map(|v| format!("{:>9.4}", v)).join(", ")); +} +``` + +The logs: +``` +[490.0000, 300.0000, 790.0000, 840.0000, 1580.0000] - iter 0 +[904.0000, 419.0000, 1397.0000, 749.0000, 531.0000] - iter 1 +[834.9000, 448.5000, 1049.8000, 879.5000, 787.3000] - iter 2 +[788.9100, 438.6400, 1225.8900, 829.7200, 716.8400] - iter 3 +[832.2440, 435.0270, 1148.0771, 826.8651, 757.7870] - iter 4 +[812.7562, 439.7218, 1175.0963, 840.7976, 731.6286] - iter 5 +[817.5791, 437.3035, 1169.0088, 831.6953, 744.4139] - iter 6 +[817.8276, 438.0276, 1168.9563, 835.2045, 739.9846] - iter 7 +[816.9011, 437.9801, 1169.7881, 834.5048, 740.8266] - iter 8 +[817.4117, 437.8922, 1169.3523, 834.3715, 740.9730] - iter 9 +``` + +We can see that only after a few iterations, the scores will converge, depending on how much accuracy is needed. + +In the real world, we are working with finite field, so our data structures and algorithm has to be modified a bit. + +First we define a constant for a number of iterations: +```rust +const NUM_ITER = 10; +``` + +Then, the EigenTrust set which includes the inital score for each peer: +```rust +s = [(peer1, 1000), (peer2, 2000), (peer3, 500), (peer4, 300), (peer5, 200)] +``` + +Now, the scores map: +```rust +scores => { + peer1 => [(peer1, 0), (peer2, 2), (peer3, 3), (peer4, 5), (peer5, 0)] + peer2 => [(peer1, 1), (peer2, 0), (peer3, 1), (peer4, 1), (peer5, 7)] + peer3 => [(peer1, 4), (peer2, 1), (peer3, 0), (peer4, 2), (peer5, 3)] + peer4 => [(peer1, 1), (peer2, 1), (peer3, 7), (peer4, 0), (peer5, 1)] + peer5 => [(peer1, 3), (peer2, 1), (peer3, 4), (peer4, 2), (peer5, 0)] +} +``` + +Minimum number of participants should be 2, if it is less, the matrix would not be able to converge: +```rust +let valid_peers_count = count(filter(s, |s| s.0 != null)) +assert!(valid_peers_count >= 2) +``` + +Before we run the algorithm, we have to normalise the scores: +```rust +// Normalise the scores +for i in 0..s.len() { + let (pk_i, creadits) = s[i]; + if pk == null { + continue; + } + let sum = sum(scores[pk_i]); + for j in 0..s.len() { + scores[pk_i][j] = scores[pk_i][j] / sum; + } +} +``` + +Now, we have conditions to run the EigenTrust algorithm: +```rust +for _ in 0..NUM_ITER { + for i in 0..s.len() { + let (pk_i, _) = s[i]; + let new_score = 0; + if pk_i == null { + continue; + } + for j in 0..s.len() { + let (pk_j, neighbour_score) = s[j]; + if pk_j == null { + continue; + } + let score = scores[pk_j][i]; + new_score += score * neighbour_score; + } + s[i].1 = new_score + } +} +``` diff --git a/docs/5_beyond.md b/docs/5_beyond.md new file mode 100644 index 00000000..6367dba5 --- /dev/null +++ b/docs/5_beyond.md @@ -0,0 +1,42 @@ +--- +description: This pages explores future directions for EigenTrust. +--- + +Several problems to be solved: +1) Non-unique peer identifiers:\ +If there are two or more peers with the same identifier in the set, the filtering algorithm will not work as intended. To avoid this, it is important to use unique identifiers for each peer. +We can achieve this by requiring the set to have unique id associated with it. This can be achieved by compressing all the peers ids into a MerkleTree root/Sponge hash outside the circuit and make constraints inside the circuit. +For example, consider a set: +```rust +s = [(peer1, 1000), (peer2, 2000), (peer3, 500), (peer4, 300), (peer5, 200)] +``` + +We can extract the peer ids from this set, and construct the unique id for the whole set +```rust +s_ids = s.map(|x| x.0) +root_hash = construct_merkle_tree(s_ids) +// OR +final_hash = poseidon_sponge_hash(s_ids) +``` +Then we can pass `root_hash` or `final_hash` into the circuit as a public input. We would re-construct the same tree/sponge hash inside the circuit and compare with the public input. + +2) Performance considerations:\ +As the size of the set and the opinion map grows, the filtering algorithm can become computationally expensive. To optimize performance, it may be necessary to use more efficient data structures and algorithms. +One way we could fix this is to split the network into smaller ones. So, have predefined groups of maximum 256 peers for which we can make EigenTrust convergence proofs. We can then aggregate 2 or more of these proofs to form larger groups. + +If we have sets with `N` participants, aggregating `M` number of proofs, would result in `N * M` number of participants. +```rust +s1 = ([peer1_score, peer2_score, peer3_score], proof_1) +s2 = ([peer4_score, peer5_score, peer6_score], proof_2) +s3 = ([peer7_score, peer8_score, peer9_score], proof_3) + +accumulator_limbs = aggregate(s1, s2, s3) + +verify(accumulator_limbs) +``` + +We can also do multiple levels of aggregation in form of a Merkle Tree until we reach the root, where we have aggregated the whole network. + +Future directions - Integration with smart contract platforms: +1) Peers can use these proofs to prove their reputation and use them to join communities such as Semaphore groups or similar working groups. We can generalise this to make gate-keeping for any form of action on any protocol. +2) We can also integrate EigenTrust sets inside the smart contract itself. The converged scores of each participants can be used for reputation-weighted voting inside this smart contract. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..1abc519b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,20 @@ +--- +description: EigenTrust protocol +--- + +# EigenTrust + +EigenTrust is a reputation-based trust management algorithm that evaluates the trustworthiness of peers in peer-to-peer networks. The algorithm calculates a reputation score for each peer based on feedback from other peers in the network. + +The algorithm is based on an opinion matrix that describes the distribution of the reputation owned by the peers in the network. The opinion matrix is used to calculate new scores for each peer, and the process is repeated until the scores converge. + +EigenTrust uses a recursive algorithm that involves updating the scores for each peer based on the scores of the other peers in the network. The algorithm is designed to be resilient against collusion and free-riding, two common problems in peer-to-peer networks. + +The EigenTrust algorithm can be used in a variety of decentralized decision-making applications, such as decentralized autonomous organizations (DAOs), prediction markets, and reputation systems. It can also be used in peer-to-peer networks to facilitate content discovery and recommendation. + +**Main characteristics:** +- Self-policing - the shared ethics of the user groups is defined and enforced by the peers themselves and not by some central authority. + +- Incorruptible - Reputation should be obtained by consistent good behavior through several transactions. It is resistant to sybil attack through mechanisms of bootstrapping or sybil rank filtering algorithm. + +- Permissonless - New peers can join the system without the permisson of central autorithy, given that they satisfy certain critirea. diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md new file mode 100644 index 00000000..91ec581e --- /dev/null +++ b/docs/SUMMARY.md @@ -0,0 +1,9 @@ +# Table of contents + +* [EigenTrust](README.md) +* [Attestation Station](0_attestation_station.md) +* [Attestation](1_attestations.md) +* [Data Processing](2_data_processing.md) +* [Dynamic Sets](3_dynamic_sets.md) +* [The Algorithm](4_algorithm.md) +* [Future Ideas](5_beyond.md) diff --git a/eigentrust-cli/LICENSE b/eigentrust-cli/LICENSE deleted file mode 100644 index ea5b6064..00000000 --- a/eigentrust-cli/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/eigentrust-zk/src/ecc/same_curve/mod.rs b/eigentrust-zk/src/ecc/same_curve/mod.rs index 1f1f9b85..9e435a49 100644 --- a/eigentrust-zk/src/ecc/same_curve/mod.rs +++ b/eigentrust-zk/src/ecc/same_curve/mod.rs @@ -450,6 +450,7 @@ where C::Scalar: FieldExt, { /// Creates a new ecc equal chipset. + #[allow(dead_code)] pub fn new( p: AssignedEcPoint, q: AssignedEcPoint, diff --git a/eigentrust-zk/src/gadgets/lt_eq_lookup.rs b/eigentrust-zk/src/gadgets/lt_eq_lookup.rs index b8cec9fb..1e953624 100644 --- a/eigentrust-zk/src/gadgets/lt_eq_lookup.rs +++ b/eigentrust-zk/src/gadgets/lt_eq_lookup.rs @@ -79,6 +79,7 @@ struct LessEqualConfig { impl LessEqualConfig { /// Constructs new config + #[allow(dead_code)] fn new( main: MainConfig, lookup_range_check: RangeChipsetConfig, bits_2_num_selector: Selector, n_shifted_selector: Selector, @@ -95,6 +96,7 @@ struct LessEqualChipset { impl LessEqualChipset { /// Constructs a new chipset + #[allow(dead_code)] fn new(x: AssignedCell, y: AssignedCell) -> Self { Self { x, y } } diff --git a/eigentrust-zk/src/integer/native.rs b/eigentrust-zk/src/integer/native.rs index d90d7483..16ba9907 100644 --- a/eigentrust-zk/src/integer/native.rs +++ b/eigentrust-zk/src/integer/native.rs @@ -57,8 +57,10 @@ pub struct ReductionWitness< /// Quotient from the operation. pub(crate) quotient: Quotient, /// Intermediate values from the operation. + #[allow(dead_code)] pub(crate) intermediate: [N; NUM_LIMBS], /// Residue values from the operation. + #[allow(dead_code)] pub(crate) residues: Vec, } diff --git a/eigentrust-zk/src/lib.rs b/eigentrust-zk/src/lib.rs index 110e6e24..cfe78f14 100644 --- a/eigentrust-zk/src/lib.rs +++ b/eigentrust-zk/src/lib.rs @@ -258,6 +258,7 @@ pub struct CommonConfig { /// Fixed columns fixed: [Column; FIXED], /// Table column + #[allow(dead_code)] table: TableColumn, /// Instance column instance: Column, diff --git a/eigentrust-zk/src/merkle_tree/native.rs b/eigentrust-zk/src/merkle_tree/native.rs index d578a1c5..017912a1 100644 --- a/eigentrust-zk/src/merkle_tree/native.rs +++ b/eigentrust-zk/src/merkle_tree/native.rs @@ -63,6 +63,7 @@ where H: Hasher, { /// Value that is based on for construction of the path + #[allow(dead_code)] pub(crate) value: F, /// Array that keeps the path pub(crate) path_arr: [[F; ARITY]; LENGTH], diff --git a/eigentrust-zk/src/verifier/aggregator/mod.rs b/eigentrust-zk/src/verifier/aggregator/mod.rs index cdf12d70..3679f815 100644 --- a/eigentrust-zk/src/verifier/aggregator/mod.rs +++ b/eigentrust-zk/src/verifier/aggregator/mod.rs @@ -44,6 +44,7 @@ where E::Scalar: FieldExt, { protocol: PlonkProtocol, + #[allow(clippy::type_complexity)] instances: (Vec>, Vec>>), proof: Option>, } diff --git a/eigentrust-zk/src/verifier/transcript/mod.rs b/eigentrust-zk/src/verifier/transcript/mod.rs index 647827eb..2e4f7f73 100644 --- a/eigentrust-zk/src/verifier/transcript/mod.rs +++ b/eigentrust-zk/src/verifier/transcript/mod.rs @@ -333,9 +333,7 @@ where mod test { use super::{native::NativeTranscriptRead, LoaderConfig, TranscriptReadChipset}; use crate::{ - circuits::{ - FullRoundHasher, PartialRoundHasher, PoseidonNativeHasher, PoseidonNativeSponge, - }, + circuits::{FullRoundHasher, PartialRoundHasher, PoseidonNativeSponge}, ecc::{ same_curve::{native::EcPoint, AssignedEcPoint, UnassignedEcPoint}, AuxConfig, EccAddConfig, EccDoubleConfig, EccMulConfig, EccTableSelectConfig, diff --git a/eigentrust/LICENSE b/eigentrust/LICENSE deleted file mode 100644 index ea5b6064..00000000 --- a/eigentrust/LICENSE +++ /dev/null @@ -1 +0,0 @@ -../LICENSE \ No newline at end of file diff --git a/eigentrust/src/lib.rs b/eigentrust/src/lib.rs index 3f0a9435..93218c0b 100644 --- a/eigentrust/src/lib.rs +++ b/eigentrust/src/lib.rs @@ -1,25 +1,7 @@ -//! # Eigen Trust +//! # EigenTrust Library //! -//! A library for managing trust in a distributed network with zero-knowledge -//! features. -//! -//! ## Main characteristics: -//! -//! **Self-policing** - the shared ethics of the user population is defined and -//! enforced by the peers themselves and not by some central authority. -//! -//! **Minimal** - computation, infrastructure, storage, and message complexity -//! are reduced to a minimum. -//! -//! **Incorruptible** - Reputation should be obtained by consistent good -//! behavior through several transactions. This is enforced for all users, so no -//! one can cheat the system and obtain a higher reputation. It is also -//! resistant to malicious collectives. -//! -//! ## Implementation -//! -//! The library is implemented according to the original [Eigen Trust paper](http://ilpubs.stanford.edu:8090/562/1/2002-56.pdf). -//! It is developed under an Ethereum Foundation grant. +//! Provides the `Client` struct to interface with the EigenTrust algorithm's circuits. +//! Additional modules are included to enhance functionality and support integration. // Rustc #![warn(trivial_casts)] diff --git a/scripts/build-docs.sh b/scripts/build-docs.sh index 10801e35..d6197dfc 100755 --- a/scripts/build-docs.sh +++ b/scripts/build-docs.sh @@ -1 +1 @@ -cargo doc -p eigen-trust-server --no-deps +cargo doc -p eigentrust --no-deps