Skip to content

fatlabsxyz/privacy-pools-starknet

Repository files navigation

Notes:

We decided to change the way the scope, context, and label are computed. The main reason is that those values are coputed in solidity hashing with a keccak256. This hash is not implemented in cairo, the implementation of non-native hashes is really expensive. These hashes are not computed inside of the circuits so we can use another hash to compute them. We chose the poseidon hash implemented on starknet with the function core::poseidon::poseidon_hash_span.

SCOPE

The scope is computed in solidity as

SCOPE = uint256(keccak256(abi.encodePacked(address(this), block.chainid, _asset))) % Constants.SNARK_SCALAR_FIELD;

We now compute it as follows,

fn compute_scope(self: @ContractState, asset: ContractAddress) -> u256 {
    let CHAIN_ID = get_tx_info().unbox().chain_id;
    let span: Span<felt252> = array![get_contract_address().into(), CHAIN_ID, asset.into()].span();
    let scope: u256 = poseidon_hash_span(span).into();
    return scope;
}

In typescript this can be implemented with,

import { poseidonHashMany } from "@scure/starknet"
scope = poseidonHashMany([poolAddress, CHAIN_ID, ASSET])

To test the implementation we can use

poolAddress: 0x123456;
CHAIN_ID: 0x534e5f5345504f4c4941; //sepolia
ASSET:: 0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d; //STRK_ADDRESS
SCOPE: 694951935208482397787848015954714431929730211336803088452174886917016209636

LABEL

Label is computed in solidity like,

LABEL = uint256(keccak256(abi.encodePacked(SCOPE, ++nonce))) % Constants.SNARK_SCALAR_FIELD;
fn compute_label(ref self: ContractState) -> u256 {
    let scope = self.scope.read();
    let nonce = self.nonce.read();

    let span = array![nonce.into(),scope.low.into(), scope.high.into()].span();
    let label: u256 = poseidon_hash_span(span).into();
    return label;
}
import { poseidonHashMany } from "@scure/starknet"
label = poseidonHashMany([nonce, scope.low,scope.high])

CONTEXT

CONTEXT = uint256(keccak256(abi.encode(_withdrawal, SCOPE))) % Constants.SNARK_SCALAR_FIELD)

In cairo we compute the context with a method of the Withdrawal struct,

fn compute_context(self: @Withdrawal, scope: u256) -> u256 {
    let mut temp = array![];
    Serde::serialize(self, ref temp);
    temp.append(scope.low.into());
    temp.append(scope.high.into());
    let context = poseidon_hash_span(temp.span()).into()
    return context;
}

The Withdrawal struct is

pub struct Withdrawal {
    processor: ContractAddress,
    data: Span<felt252>,
}

At low level, the span to hash consists of the serialization of the struct with the scope

span = [processor, data.len, ...data...,scope.low,scope.high]
import { poseidonHashMany } from "@scure/starknet"
context = poseidonHashMany([
    processor,
    data.len,
    ...data...,
    scope.low,
    scope.high,
])

##CHAIN ID The chain_id of starknet

sepolia_id = 0x534e5f5345504f4c4941
mainet_id = 0x534e5f4d41494e

Audits

Feltroid Prime

About

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors