> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stoffelmpc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Input Manager

> Contract for handling client input submission with privacy-preserving masking and ECDSA authentication.

The `StoffelInputManager` contract handles client input submission for MPC computations, including mask reservation and ECDSA authentication.

## Overview

```solidity theme={null}
abstract contract StoffelInputManager {
    // Manages client inputs with privacy-preserving masking
}
```

## How Input Masking Works

Clients don't submit raw inputs on-chain (that would reveal them). Instead:

1. **MPC nodes generate input masks** during preprocessing
2. **Clients reserve mask indices** on-chain
3. **Clients submit masked inputs**: `masked = input + mask`
4. **MPC nodes unmask** during computation using their mask shares

```
Client Input: 42
Mask:         17
Masked Input: 59  ← This goes on-chain (reveals nothing about 42)
```

## Data Structures

### MaskedInput

```solidity theme={null}
struct MaskedInput {
    uint256 index;        // Reserved mask index
    uint256 maskedInput;  // Input XOR/+ mask
}
```

### Inputs

```solidity theme={null}
struct Inputs {
    bytes publicInputs;           // Optional public parameters
    MaskedInput[] maskedInputs;   // Array of masked secret inputs
}
```

### Outputs

```solidity theme={null}
struct Outputs {
    bytes publicOutputs;          // Computation results
    mapping(address => mapping(address => bool)) sharesReceived;
    // Tracks: client => party => received
}
```

## Storage

```solidity theme={null}
// Maps index to reserving client
mapping(uint256 => address) public reservedInputIndices;

// Total indices available
uint256 public nTotalIndices;

// Remaining unreserved indices
uint256 public nIndicesLeft;

// Client inputs storage
mapping(address => MaskedInput) public clientInputs;
```

## Functions

### initializeInputMaskBuffer

Sets up the input mask buffer. Called by designated party during preprocessing.

```solidity theme={null}
function initializeInputMaskBuffer(uint256 nIndicesToReserve)
    external
    onlyDesignatedParty
{
    nTotalIndices = nIndicesToReserve;
    nIndicesLeft = nIndicesToReserve;
}
```

### reserveInputMask

Clients call this to reserve an input mask index.

```solidity theme={null}
function reserveInputMask(uint256 indexToReserve) external {
    require(indexToReserve < nTotalIndices, "Index out of bounds");
    require(reservedInputIndices[indexToReserve] == address(0), "Index already reserved");
    require(nIndicesLeft > 0, "No indices left");

    reservedInputIndices[indexToReserve] = msg.sender;
    nIndicesLeft--;

    emit InputMaskReserved(msg.sender, indexToReserve);
}
```

### submitMaskedInput

Clients submit their masked input using a reserved index.

```solidity theme={null}
function submitMaskedInput(uint256 maskedInput, uint256 reservedIndex) external {
    require(reservedInputIndices[reservedIndex] == msg.sender, "Not your reserved index");

    clientInputs[msg.sender] = MaskedInput({
        index: reservedIndex,
        maskedInput: maskedInput
    });

    // Unreserve the index (one-time use)
    reservedInputIndices[reservedIndex] = address(0);

    emit MaskedInputSubmitted(msg.sender, reservedIndex);
}
```

### authenticateClient

MPC nodes use this for off-chain client authentication via ECDSA.

```solidity theme={null}
function authenticateClient(
    uint256 requestIndex,
    address clientAddr,
    bytes calldata signature
) external view returns (bool) {
    // Construct the message hash
    bytes32 messageHash = keccak256(abi.encode(requestIndex));
    bytes32 ethSignedHash = keccak256(
        abi.encodePacked("\x19Ethereum Signed Message:\n32", messageHash)
    );

    // Recover signer from signature
    address recovered = recoverSigner(ethSignedHash, signature);

    return recovered == clientAddr;
}
```

### getClientInput

Retrieve a client's submitted input.

```solidity theme={null}
function getClientInput(address client)
    external
    view
    returns (MaskedInput memory)
{
    return clientInputs[client];
}
```

### hasClientSubmitted

Check if a client has submitted their input.

```solidity theme={null}
function hasClientSubmitted(address client) external view returns (bool) {
    return clientInputs[client].maskedInput != 0 ||
           clientInputs[client].index != 0;
}
```

## Events

```solidity theme={null}
event InputMaskReserved(address indexed client, uint256 indexed index);
event MaskedInputSubmitted(address indexed client, uint256 indexed index);
event ClientAuthenticated(address indexed client, uint256 indexed requestIndex);
```

## Client Workflow

### 1. Reserve a Mask Index

```javascript theme={null}
// Client reserves index 5
await coordinator.reserveInputMask(5);
```

### 2. Get the Mask (Off-Chain)

```javascript theme={null}
// Client contacts MPC nodes to get their mask
// This happens off-chain via the Rust SDK
const mask = await mpcClient.getInputMask(5);
```

### 3. Compute Masked Input

```javascript theme={null}
// Client masks their secret input
const secretInput = 42n;
const maskedInput = secretInput + mask;  // or XOR depending on protocol
```

### 4. Submit Masked Input

```javascript theme={null}
// Client submits on-chain
await coordinator.submitMaskedInput(maskedInput, 5);
```

### 5. MPC Nodes Unmask

During computation, MPC nodes:

1. Read `maskedInput` from contract
2. Subtract their mask share
3. Proceed with MPC on the unmasked value

## Authentication Flow

For off-chain operations, clients prove their identity:

```javascript theme={null}
// Client signs a request
const requestIndex = 12345;
const messageHash = ethers.utils.keccak256(
    ethers.utils.defaultAbiCoder.encode(['uint256'], [requestIndex])
);
const signature = await wallet.signMessage(ethers.utils.arrayify(messageHash));

// MPC node verifies on-chain
const isValid = await coordinator.authenticateClient(
    requestIndex,
    clientAddress,
    signature
);
```

## Example: Complete Input Flow

```solidity theme={null}
contract SecureVoting is StoffelCoordinator {
    mapping(address => bool) public hasVoted;

    function vote(uint256 maskedVote, uint256 maskIndex) external {
        require(!hasVoted[msg.sender], "Already voted");
        require(currentRound == Round.CollectingClientInputRound, "Not collecting");

        // Verify client reserved this index
        require(reservedInputIndices[maskIndex] == msg.sender, "Wrong index");

        // Submit the masked vote
        clientInputs[msg.sender] = MaskedInput({
            index: maskIndex,
            maskedInput: maskedVote
        });

        hasVoted[msg.sender] = true;
        reservedInputIndices[maskIndex] = address(0);

        emit MaskedInputSubmitted(msg.sender, maskIndex);
    }
}
```

## Security Considerations

### Index Reservation

* Each index can only be reserved once
* Prevents double-spending of masks
* Clients should reserve early to ensure availability

### Mask Uniqueness

* Each mask is used exactly once
* After submission, the index is unreserved
* Prevents mask reuse attacks

### Authentication

* ECDSA signatures verify client identity
* Prevents impersonation in off-chain communications
* Message includes unique `requestIndex` to prevent replay

### Input Privacy

* Only masked values appear on-chain
* Raw inputs never touch the blockchain
* Privacy depends on MPC node security (threshold trust)

## Next Steps

* [StoffelCoordinator](./coordinator): State machine details
* [Access Control](./access-control): Role management
* [Overview](./overview): Architecture overview
