/************************************************************************************************************************************************************************/ /*ZZZZZZZZZZZZZZZZZZZKKKKKKKKK KKKKKKKNNNNNNNN NNNNNNNN OOOOOOOOO XXXXXXX XXXXXXX ..../&@&#. .###%@@@#, .. /*Z:::::::::::::::::ZK:::::::K K:::::KN:::::::N N::::::N OO:::::::::OO X:::::X X:::::X ...(@@* .... . &#//%@@&,. /*Z:::::::::::::::::ZK:::::::K K:::::KN::::::::N N::::::N OO:::::::::::::OO X:::::X X:::::X ..*@@......... .@#%%(%&@&.. /*Z:::ZZZZZZZZ:::::Z K:::::::K K::::::KN:::::::::N N::::::NO:::::::OOO:::::::OX::::::X X::::::X .*@( ........ . .&@@@@. .@%%%%%#&@@. /*ZZZZZ Z:::::Z KK::::::K K:::::KKKN::::::::::N N::::::NO::::::O O::::::OXXX:::::X X::::::XX ...&@ ......... . &. .@ /@%%%%%%&@@# /* Z:::::Z K:::::K K:::::K N:::::::::::N N::::::NO:::::O O:::::O X:::::X X:::::X ..@( .......... . &. ,& /@%%%%&&&&@@@. /* Z:::::Z K::::::K:::::K N:::::::N::::N N::::::NO:::::O O:::::O X:::::X:::::X ..&% ........... .@%(#@# ,@%%%%&&&&&@@@%. /* Z:::::Z K:::::::::::K N::::::N N::::N N::::::NO:::::O O:::::O X:::::::::X ..,@ ............ *@%%%&%&&&&&&@@@. /* Z:::::Z K:::::::::::K N::::::N N::::N:::::::NO:::::O O:::::O X:::::::::X ..(@ ............. ,#@&&&&&&&&&&&&@@@@* /* Z:::::Z K::::::K:::::K N::::::N N:::::::::::NO:::::O O:::::O X:::::X:::::X .*@.............. . ..,(%&@@&&&&&&&&&&&&&&&&@@@@, /* Z:::::Z K:::::K K:::::K N::::::N N::::::::::NO:::::O O:::::O X:::::X X:::::X ...&#............. *@@&&&&&&&&&&&&&&&&&&&&@@&@@@@& /*ZZZ:::::Z ZZZZZKK::::::K K:::::KKKN::::::N N:::::::::NO::::::O O::::::OXXX:::::X X::::::XX ...@/.......... *@@@@. ,@@. &@&&&&&&@@@@@@@@@@@. /*Z::::::ZZZZZZZZ:::ZK:::::::K K::::::KN::::::N N::::::::NO:::::::OOO:::::::OX::::::X X::::::X ....&#..........@@@, *@@&&&@% .@@@@@@@@@@@@@@@& /*Z:::::::::::::::::ZK:::::::K K:::::KN::::::N N:::::::N OO:::::::::::::OO X:::::X X:::::X ....*@.,......,@@@...@@@@@@&..%@@@@@@@@@@@@@/ /*Z:::::::::::::::::ZK:::::::K K:::::KN::::::N N::::::N OO:::::::::OO X:::::X X:::::X ...*@,,.....%@@@,.........%@@@@@@@@@@@@( /*ZZZZZZZZZZZZZZZZZZZKKKKKKKKK KKKKKKKNNNNNNNN NNNNNNN OOOOOOOOO XXXXXXX XXXXXXX ...&@,....*@@@@@ ..,@@@@@@@@@@@@@&. /* ....,(&@@&..,,,/@&#*. . /* ......(&.,.,,/&@,. /* .....,%*.,*@% /* .#@@@&(&@*,,*@@%,.. /* .##,,,**$.,,*@@@@@%. /* *(%%&&@(,,**@@@@@& /* . . .#@((@@(*,** /* . (*. . /* .*/ ///* Copyright (C) 2025 - Renaud Dubois, Simon Masson - This file is part of ZKNOX project ///* License: This software is licensed under MIT License ///* This Code may be reused including this header, license and copyright notice. ///* See LICENSE file at the root folder of the project. ///* FILE: ZKNOX_NTT.sol ///* Description: Compute Negative Wrap Convolution NTT as specified in EIP-NTT /************************************************************************************************************************************************************************/ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; contract ZKNOX_NTT{ /************************************************************************************************************************************************************************/ /* COMMON */ /************************************************************************************************************************************************************************/ //Vectorized modular multiplication //Multiply chunk wise vectors of n chunks modulo q function ZKNOX_VECMULMOD( uint[] memory a, uint[] memory b, uint q ) public pure returns (uint[] memory) { assert(a.length == b.length); uint[] memory res = new uint[](a.length); for (uint i = 0; i < a.length; i++) { res[i] = mulmod(a[i], b[i], q); } return res; } //Vectorized modular multiplication //Multiply chunk wise vectors of n chunks modulo q function ZKNOX_VECADDMOD( uint[] memory a, uint[] memory b, uint q ) public pure returns (uint[] memory) { assert(a.length == b.length); uint[] memory res = new uint[](a.length); for (uint i = 0; i < a.length; i++) { res[i] = addmod(a[i], b[i], q); } return res; } /************************************************************************************************************************************************************************/ /* STATEFULL VERSION */ /************************************************************************************************************************************************************************/ /* STORAGE FOR THE STATEFUL VERSION */ address public o_psirev; //external contract containing psi_rev address public o_psi_inv_rev;//external contract containing psi_inv_rev uint256 storage_q; uint256 storage_nm1modq;//n^-1 mod 12289 uint256 is_immutable;//"antifuse" variable constructor(address Apsi_rev, address Apsi_inrev, uint256 q, uint256 nm1modq) { storage_q = q;//prime field modulus storage_nm1modq=nm1modq;//n^-1 mod 12289, used in inverse NTT o_psirev = Apsi_rev; o_psi_inv_rev = Apsi_inrev; is_immutable = 1; } function update(address Apsi_rev, address Apsi_inrev, uint256 q, uint256 nm1modq) public{ if(is_immutable>0){ storage_q = q;//prime field modulus storage_nm1modq=nm1modq;//n^-1 mod 12289, used in inverse NTT o_psirev = Apsi_rev; o_psi_inv_rev = Apsi_inrev; } } //by calling this function, the contract storage variables cannot be modified (precomputed values) function make_immutable() public{ is_immutable=1; } // NTT_FW as specified by EIP, statefull version //address apsirev: address of the contract storing the powers of psi function ZKNOX_NTTFW(uint[] memory a, address apsirev) public view returns (uint[] memory){ uint n=a.length; uint t=n; uint m=1; uint q=storage_q; uint[1] memory S; assembly{ for {} gt(n,m) { } {//while(m 1) let j1:=0 let h:=shr(1,m)//uint h = m>>1; for {let i:=0} gt(h,i) { i := add(i, 1) } { //while(m>1; for(uint i=0;i 1){ uint j1 = 0; uint h = m>>1; for(uint i=0;i>1; }//end while t=storage_nm1modq;//sparing one variable for stack for(m=0;m