> For the complete documentation index, see [llms.txt](https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/tutorial-16-zero-knowledge-zk/bugs-in-the-wild/semaphore-missing-smart-contract-range-check.md).

# Semaphore: Missing Smart Contract Range Check

{% hint style="info" %}
[**Book an audit with Zokyo**](https://www.zokyo.io/)
{% endhint %}

**Summary**

Related Vulnerabilities: 3. [Arithmetic Over/Under Flows](/zokyo-tutorials/tutorial-16-zero-knowledge-zk/common-vulnerabilities-in-zk-code/arithmetic-over-under-flows.md)

Identified By: [PSE Security Team](https://twitter.com/PrivacyScaling)

The Semaphore smart contracts performed range checks in some places but not others. The range checks were to ensure that all public inputs were less than the [snark scalar field order](/zokyo-tutorials/tutorial-16-zero-knowledge-zk/definitions-and-essentials/scalar-field-order.md). However, these checks weren’t enforced in all the necessary places. This could cause new Semaphore group owners to unknowingly create a group that will always fail verification.

**Background**

Semaphore is a dapp built on Ethereum that allows users to prove their membership of a group and send signals such as votes or endorsements without revealing their original identity. Essentially, trusted coordinators create a group (with a group Id) and add members via the smart contracts. Members can then submit zero knowledge proofs to the coordinator that prove their membership of the group and optionally contain a signal with it.

**The** **Vulnerability**

Since the Solidity *uint256* type can hold numbers larger than the [snark scalar field order](/zokyo-tutorials/tutorial-16-zero-knowledge-zk/definitions-and-essentials/scalar-field-order.md), it is important to be weary of overflows. In order to prevent unwanted overflows, the Semaphore verifier smart contract automatically fails if a public input is greater than the snark scalar field order:

```
// From Semaphore/contracts/base/Verifier.sol (outdated)
require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field");
```

When a coordinator creates a new group, they can input any valid *uint256* value as the id. This is a problem since the id is a public input for the zk proof. If the id is greater than the snark scalar field order, the verifier will always revert and the group isn’t operable.

**The Fix**

To prevent an inoperable group from being created, a check on the group Id is needed. This check needs to ensure that the new group id will be less than the snark scalar field order:

```
// From Semaphore/contracts/base/SemaphoreGroups.sol
function _createGroup(
    uint256 groupId,
    uint8 depth,
    uint256 zeroValue
  ) internal virtual {
		// The Fix is the following require statement:
    require(groupId < SNARK_SCALAR_FIELD, "SemaphoreGroups: group id must be < SNARK_SCALAR_FIELD");
    require(getDepth(groupId) == 0, "SemaphoreGroups: group already exists");

    groups[groupId].init(depth, zeroValue);
    emit GroupCreated(groupId, depth, zeroValue);
  }
```

### **Conclusion:**

1. **Issue with uint256:** In Ethereum's Solidity language, the `uint256` type can store values up to 2^256 - 1. This range is greater than the snark scalar field order (a predefined value relevant to zk-SNARKs, which is essential for the zero-knowledge proofs used in Semaphore). Hence, there's a potential risk if any of the inputs exceed the snark scalar field order, causing unwanted overflows.
2. **Check in Verifier:** In the outdated version of the Semaphore verifier contract, there's a check that any public input used in a zk proof must be less than the snark scalar field order. If not, the verification process fails.
3. **Problem with Group IDs:** When a coordinator establishes a new group, they can set any value as the group ID, provided it's within the valid range of `uint256`. However, because this ID acts as a public input for the zk proof, there's a significant risk. If the coordinator unintentionally sets an ID greater than the snark scalar field order, all zk proofs involving that group will fail.

   In simpler terms, imagine a coordinator setting up a voting group but choosing an ID so high that every single vote (zk proof) from that group gets automatically rejected by the system. The entire group becomes useless.

### **The Fix:**

1. **GroupId Check:** The fix involves adding a check when creating a group to ensure the group's ID is smaller than the snark scalar field order. If it isn't, the creation of the group fails. This requirement prevents the accidental creation of inoperable groups and ensures all created groups can successfully interact with the zk proofs.

   So now, when a coordinator tries to set up a group, the system immediately warns them if they're about to choose an unusable ID. The process is halted, preventing potential issues down the line.

In essence, the vulnerability stemmed from the flexibility given to coordinators to select any group ID, without ensuring that this ID was compatible with the zk proof verification system. The fix introduces a necessary validation step, ensuring all group IDs are zk-proof friendly.

**References**

1. [Reported Github Issue](https://github.com/semaphore-protocol/semaphore/issues/90)
2. [Commit of the Fix](https://github.com/semaphore-protocol/semaphore/pull/91)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://zokyo-auditing-tutorials.gitbook.io/zokyo-tutorials/tutorial-16-zero-knowledge-zk/bugs-in-the-wild/semaphore-missing-smart-contract-range-check.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
