// // Copyright (c) 2026 BEL ESPRIT D ACCORD TRUST HOLDINGS INC // All rights reserved. pragma circom 2.1.6; include "./node_modules/circomlib/circuits/bitify.circom"; template ShadowWalk(nBits) { // Private inputs: state and coin (each constrained to nBits bits) signal input state; signal input coin; // Public inputs: the expected outputs of the shadow walk step signal input next_state; signal input next_coin; // Constrain state and coin to be exactly nBits bits (i.e., in [0, 2^nBits - 1]) component num2bits_state = Num2Bits(nBits); num2bits_state.in <== state; component num2bits_coin = Num2Bits(nBits); num2bits_coin.in <== coin; // Calculate the shadow walk step: // next_coin = (state + coin) mod PrimeField // next_state = (state - next_coin) mod PrimeField // // Since state and coin are < 2^nBits, and we assume 2^(nBits+1) < PrimeField // (which holds for nBits <= 254 given PrimeField ~ 2^255), there is no // wrap-around in the addition. Thus: // next_coin = state + coin (as integers, which equals the field element) // next_state = state - next_coin (in the field) signal next_coin_calc; signal next_state_calc; next_coin_calc <== state + coin; next_state_calc <== state - next_coin_calc; // Constrain the calculated outputs to match the public inputs next_coin_calc === next_coin; next_state_calc === next_state; } // Default instantiation: 10-bit state space (1024 positions) // PrimeField = 21888242871839275222246405745257275088548364400416034343698204186575808495617 // For nBits <= 254, 2^(nBits+1) < PrimeField holds, so no wrap-around. component main {public [next_state, next_coin]} = ShadowWalk(10);