mirror of
https://github.com/logos-storage/circom-goldilocks.git
synced 2026-01-02 13:03:10 +00:00
implement the Goldilocks-Poseidon permutation as an example application
This commit is contained in:
parent
409f1fda15
commit
d52cb86c7d
@ -26,10 +26,10 @@ To start with, we can do a simple bit-decomposition based range check for the ra
|
||||
Then for example we could do another such range check for `x + 2^32 - 1` instead of `x`,
|
||||
and that would be sufficient; however, this doubles the number of range checks.
|
||||
|
||||
Instead, we can exploit the special form the prime `P`: Observe, that in binary
|
||||
Instead, we can exploit the special form of the prime `P`: Observe, that in binary
|
||||
decomposition, `P - 1` looks like this:
|
||||
|
||||
P-1 = 2^64 - 2^32 = 0x FFFF FFFF FFFF FFFF 0000 0000 0000 0000
|
||||
P-1 = 2^64 - 2^32 = 0x FFFF FFFF 0000 0000
|
||||
|
||||
This means, that if we already know that `x` fits into 64 bits, then it's enough
|
||||
to check that IF the top 32 bits are all 1, THEN the bottom 32 bits are all 0
|
||||
|
||||
133
circuit/constants.circom
Normal file
133
circuit/constants.circom
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
// constants for Plonky2's Poseidon instance for the Goldilocks field
|
||||
|
||||
pragma circom 2.2.0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// known answer test (KAT):
|
||||
// the permutation of [0..11]
|
||||
function poseidon_kat() {
|
||||
|
||||
var kat[12] =
|
||||
[ 0xd64e1e3efc5b8e9e , 0x53666633020aaa47 , 0xd40285597c6a8825 , 0x613a4f81e81231d2
|
||||
, 0x414754bfebd051f0 , 0xcb1f8980294a023f , 0x6eb2a9e4d54a9d0f , 0x1902bc3af467e056
|
||||
, 0xf045d5eafdc6021f , 0xe4150f77caaa3be5 , 0xc9bfd01d39b50cce , 0x5c0a27fcb0e1459b
|
||||
];
|
||||
|
||||
return kat;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
function circular_matrix_coeffs() {
|
||||
|
||||
var cs[12] = [17, 15, 41, 16, 2, 28, 13, 13, 39, 18, 34, 20];
|
||||
|
||||
return cs;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
function poseidon_round_constants(round) {
|
||||
|
||||
var rcs[360] =
|
||||
[ 0xb585f766f2144405 , 0x7746a55f43921ad7 , 0xb2fb0d31cee799b4 , 0x0f6760a4803427d7
|
||||
, 0xe10d666650f4e012 , 0x8cae14cb07d09bf1 , 0xd438539c95f63e9f , 0xef781c7ce35b4c3d
|
||||
, 0xcdc4a239b0c44426 , 0x277fa208bf337bff , 0xe17653a29da578a1 , 0xc54302f225db2c76
|
||||
, 0x86287821f722c881 , 0x59cd1a8a41c18e55 , 0xc3b919ad495dc574 , 0xa484c4c5ef6a0781
|
||||
, 0x308bbd23dc5416cc , 0x6e4a40c18f30c09c , 0x9a2eedb70d8f8cfa , 0xe360c6e0ae486f38
|
||||
, 0xd5c7718fbfc647fb , 0xc35eae071903ff0b , 0x849c2656969c4be7 , 0xc0572c8c08cbbbad
|
||||
, 0xe9fa634a21de0082 , 0xf56f6d48959a600d , 0xf7d713e806391165 , 0x8297132b32825daf
|
||||
, 0xad6805e0e30b2c8a , 0xac51d9f5fcf8535e , 0x502ad7dc18c2ad87 , 0x57a1550c110b3041
|
||||
, 0x66bbd30e6ce0e583 , 0x0da2abef589d644e , 0xf061274fdb150d61 , 0x28b8ec3ae9c29633
|
||||
, 0x92a756e67e2b9413 , 0x70e741ebfee96586 , 0x019d5ee2af82ec1c , 0x6f6f2ed772466352
|
||||
, 0x7cf416cfe7e14ca1 , 0x61df517b86a46439 , 0x85dc499b11d77b75 , 0x4b959b48b9c10733
|
||||
, 0xe8be3e5da8043e57 , 0xf5c0bc1de6da8699 , 0x40b12cbf09ef74bf , 0xa637093ecb2ad631
|
||||
, 0x3cc3f892184df408 , 0x2e479dc157bf31bb , 0x6f49de07a6234346 , 0x213ce7bede378d7b
|
||||
, 0x5b0431345d4dea83 , 0xa2de45780344d6a1 , 0x7103aaf94a7bf308 , 0x5326fc0d97279301
|
||||
, 0xa9ceb74fec024747 , 0x27f8ec88bb21b1a3 , 0xfceb4fda1ded0893 , 0xfac6ff1346a41675
|
||||
, 0x7131aa45268d7d8c , 0x9351036095630f9f , 0xad535b24afc26bfb , 0x4627f5c6993e44be
|
||||
, 0x645cf794b8f1cc58 , 0x241c70ed0af61617 , 0xacb8e076647905f1 , 0x3737e9db4c4f474d
|
||||
, 0xe7ea5e33e75fffb6 , 0x90dee49fc9bfc23a , 0xd1b1edf76bc09c92 , 0x0b65481ba645c602
|
||||
, 0x99ad1aab0814283b , 0x438a7c91d416ca4d , 0xb60de3bcc5ea751c , 0xc99cab6aef6f58bc
|
||||
, 0x69a5ed92a72ee4ff , 0x5e7b329c1ed4ad71 , 0x5fc0ac0800144885 , 0x32db829239774eca
|
||||
, 0x0ade699c5830f310 , 0x7cc5583b10415f21 , 0x85df9ed2e166d64f , 0x6604df4fee32bcb1
|
||||
, 0xeb84f608da56ef48 , 0xda608834c40e603d , 0x8f97fe408061f183 , 0xa93f485c96f37b89
|
||||
, 0x6704e8ee8f18d563 , 0xcee3e9ac1e072119 , 0x510d0e65e2b470c1 , 0xf6323f486b9038f0
|
||||
, 0x0b508cdeffa5ceef , 0xf2417089e4fb3cbd , 0x60e75c2890d15730 , 0xa6217d8bf660f29c
|
||||
, 0x7159cd30c3ac118e , 0x839b4e8fafead540 , 0x0d3f3e5e82920adc , 0x8f7d83bddee7bba8
|
||||
, 0x780f2243ea071d06 , 0xeb915845f3de1634 , 0xd19e120d26b6f386 , 0x016ee53a7e5fecc6
|
||||
, 0xcb5fd54e7933e477 , 0xacb8417879fd449f , 0x9c22190be7f74732 , 0x5d693c1ba3ba3621
|
||||
, 0xdcef0797c2b69ec7 , 0x3d639263da827b13 , 0xe273fd971bc8d0e7 , 0x418f02702d227ed5
|
||||
, 0x8c25fda3b503038c , 0x2cbaed4daec8c07c , 0x5f58e6afcdd6ddc2 , 0x284650ac5e1b0eba
|
||||
, 0x635b337ee819dab5 , 0x9f9a036ed4f2d49f , 0xb93e260cae5c170e , 0xb0a7eae879ddb76d
|
||||
, 0xd0762cbc8ca6570c , 0x34c6efb812b04bf5 , 0x40bf0ab5fa14c112 , 0xb6b570fc7c5740d3
|
||||
, 0x5a27b9002de33454 , 0xb1a5b165b6d2b2d2 , 0x8722e0ace9d1be22 , 0x788ee3b37e5680fb
|
||||
, 0x14a726661551e284 , 0x98b7672f9ef3b419 , 0xbb93ae776bb30e3a , 0x28fd3b046380f850
|
||||
, 0x30a4680593258387 , 0x337dc00c61bd9ce1 , 0xd5eca244c7a4ff1d , 0x7762638264d279bd
|
||||
, 0xc1e434bedeefd767 , 0x0299351a53b8ec22 , 0xb2d456e4ad251b80 , 0x3e9ed1fda49cea0b
|
||||
, 0x2972a92ba450bed8 , 0x20216dd77be493de , 0xadffe8cf28449ec6 , 0x1c4dbb1c4c27d243
|
||||
, 0x15a16a8a8322d458 , 0x388a128b7fd9a609 , 0x2300e5d6baedf0fb , 0x2f63aa8647e15104
|
||||
, 0xf1c36ce86ecec269 , 0x27181125183970c9 , 0xe584029370dca96d , 0x4d9bbc3e02f1cfb2
|
||||
, 0xea35bc29692af6f8 , 0x18e21b4beabb4137 , 0x1e3b9fc625b554f4 , 0x25d64362697828fd
|
||||
, 0x5a3f1bb1c53a9645 , 0xdb7f023869fb8d38 , 0xb462065911d4e1fc , 0x49c24ae4437d8030
|
||||
, 0xd793862c112b0566 , 0xaadd1106730d8feb , 0xc43b6e0e97b0d568 , 0xe29024c18ee6fca2
|
||||
, 0x5e50c27535b88c66 , 0x10383f20a4ff9a87 , 0x38e8ee9d71a45af8 , 0xdd5118375bf1a9b9
|
||||
, 0x775005982d74d7f7 , 0x86ab99b4dde6c8b0 , 0xb1204f603f51c080 , 0xef61ac8470250ecf
|
||||
, 0x1bbcd90f132c603f , 0x0cd1dabd964db557 , 0x11a3ae5beb9d1ec9 , 0xf755bfeea585d11d
|
||||
, 0xa3b83250268ea4d7 , 0x516306f4927c93af , 0xddb4ac49c9efa1da , 0x64bb6dec369d4418
|
||||
, 0xf9cc95c22b4c1fcc , 0x08d37f755f4ae9f6 , 0xeec49b613478675b , 0xf143933aed25e0b0
|
||||
, 0xe4c5dd8255dfc622 , 0xe7ad7756f193198e , 0x92c2318b87fff9cb , 0x739c25f8fd73596d
|
||||
, 0x5636cac9f16dfed0 , 0xdd8f909a938e0172 , 0xc6401fe115063f5b , 0x8ad97b33f1ac1455
|
||||
, 0x0c49366bb25e8513 , 0x0784d3d2f1698309 , 0x530fb67ea1809a81 , 0x410492299bb01f49
|
||||
, 0x139542347424b9ac , 0x9cb0bd5ea1a1115e , 0x02e3f615c38f49a1 , 0x985d4f4a9c5291ef
|
||||
, 0x775b9feafdcd26e7 , 0x304265a6384f0f2d , 0x593664c39773012c , 0x4f0a2e5fb028f2ce
|
||||
, 0xdd611f1000c17442 , 0xd8185f9adfea4fd0 , 0xef87139ca9a3ab1e , 0x3ba71336c34ee133
|
||||
, 0x7d3a455d56b70238 , 0x660d32e130182684 , 0x297a863f48cd1f43 , 0x90e0a736a751ebb7
|
||||
, 0x549f80ce550c4fd3 , 0x0f73b2922f38bd64 , 0x16bf1f73fb7a9c3f , 0x6d1f5a59005bec17
|
||||
, 0x02ff876fa5ef97c4 , 0xc5cb72a2a51159b0 , 0x8470f39d2d5c900e , 0x25abb3f1d39fcb76
|
||||
, 0x23eb8cc9b372442f , 0xd687ba55c64f6364 , 0xda8d9e90fd8ff158 , 0xe3cbdc7d2fe45ea7
|
||||
, 0xb9a8c9b3aee52297 , 0xc0d28a5c10960bd3 , 0x45d7ac9b68f71a34 , 0xeeb76e397069e804
|
||||
, 0x3d06c8bd1514e2d9 , 0x9c9c98207cb10767 , 0x65700b51aedfb5ef , 0x911f451539869408
|
||||
, 0x7ae6849fbc3a0ec6 , 0x3bb340eba06afe7e , 0xb46e9d8b682ea65e , 0x8dcf22f9a3b34356
|
||||
, 0x77bdaeda586257a7 , 0xf19e400a5104d20d , 0xc368a348e46d950f , 0x9ef1cd60e679f284
|
||||
, 0xe89cd854d5d01d33 , 0x5cd377dc8bb882a2 , 0xa7b0fb7883eee860 , 0x7684403ec392950d
|
||||
, 0x5fa3f06f4fed3b52 , 0x8df57ac11bc04831 , 0x2db01efa1e1e1897 , 0x54846de4aadb9ca2
|
||||
, 0xba6745385893c784 , 0x541d496344d2c75b , 0xe909678474e687fe , 0xdfe89923f6c9c2ff
|
||||
, 0xece5a71e0cfedc75 , 0x5ff98fd5d51fe610 , 0x83e8941918964615 , 0x5922040b47f150c1
|
||||
, 0xf97d750e3dd94521 , 0x5080d4c2b86f56d7 , 0xa7de115b56c78d70 , 0x6a9242ac87538194
|
||||
, 0xf7856ef7f9173e44 , 0x2265fc92feb0dc09 , 0x17dfc8e4f7ba8a57 , 0x9001a64209f21db8
|
||||
, 0x90004c1371b893c5 , 0xb932b7cf752e5545 , 0xa0b1df81b6fe59fc , 0x8ef1dd26770af2c2
|
||||
, 0x0541a4f9cfbeed35 , 0x9e61106178bfc530 , 0xb3767e80935d8af2 , 0x0098d5782065af06
|
||||
, 0x31d191cd5c1466c7 , 0x410fefafa319ac9d , 0xbdf8f242e316c4ab , 0x9e8cd55b57637ed0
|
||||
, 0xde122bebe9a39368 , 0x4d001fd58f002526 , 0xca6637000eb4a9f8 , 0x2f2339d624f91f78
|
||||
, 0x6d1a7918c80df518 , 0xdf9a4939342308e9 , 0xebc2151ee6c8398c , 0x03cc2ba8a1116515
|
||||
, 0xd341d037e840cf83 , 0x387cb5d25af4afcc , 0xbba2515f22909e87 , 0x7248fe7705f38e47
|
||||
, 0x4d61e56a525d225a , 0x262e963c8da05d3d , 0x59e89b094d220ec2 , 0x055d5b52b78b9c5e
|
||||
, 0x82b27eb33514ef99 , 0xd30094ca96b7ce7b , 0xcf5cb381cd0a1535 , 0xfeed4db6919e5a7c
|
||||
, 0x41703f53753be59f , 0x5eeea940fcde8b6f , 0x4cd1f1b175100206 , 0x4a20358574454ec0
|
||||
, 0x1478d361dbbf9fac , 0x6f02dc07d141875c , 0x296a202ed8e556a2 , 0x2afd67999bf32ee5
|
||||
, 0x7acfd96efa95491d , 0x6798ba0c0abb2c6d , 0x34c6f57b26c92122 , 0x5736e1bad206b5de
|
||||
, 0x20057d2a0056521b , 0x3dea5bd5d0578bd7 , 0x16e50d897d4634ac , 0x29bff3ecb9b7a6e3
|
||||
, 0x475cd3205a3bdcde , 0x18a42105c31b7e88 , 0x023e7414af663068 , 0x15147108121967d7
|
||||
, 0xe4a3dff1d7d6fef9 , 0x01a8d1a588085737 , 0x11b4c74eda62beef , 0xe587cc0d69a73346
|
||||
, 0x1ff7327017aa2a6e , 0x594e29c42473d06b , 0xf6f31db1899b12d5 , 0xc02ac5e47312d3ca
|
||||
, 0xe70201e960cb78b8 , 0x6f90ff3b6a65f108 , 0x42747a7245e7fa84 , 0xd1f507e43ab749b2
|
||||
, 0x1c86d265f15750cd , 0x3996ce73dd832c1c , 0x8e7fba02983224bd , 0xba0dec7103255dd4
|
||||
, 0x9e9cbd781628fc5b , 0xdae8645996edd6a5 , 0xdebe0853b1a1d378 , 0xa49229d24d014343
|
||||
, 0x7be5b9ffda905e1c , 0xa3c95eaec244aa30 , 0x0230bca8f4df0544 , 0x4135c2bebfe148c6
|
||||
, 0x166fc0cc438a3c72 , 0x3762b59a8ae83efa , 0xe8928a4c89114750 , 0x2a440b51a4945ee5
|
||||
, 0x80cefd2b7d99ff83 , 0xbb9879c6e61fd62a , 0x6e7c8f1a84265034 , 0x164bb2de1bbeddc8
|
||||
, 0xf3c12fe54d5c653b , 0x40b9e922ed9771e2 , 0x551f5b0fbe7b1840 , 0x25032aa7c4cb1811
|
||||
, 0xaaed34074b164346 , 0x8ffd96bbf9c9c81d , 0x70fc91eb5937085c , 0x7f795e2a5f915440
|
||||
, 0x4543d9df5476d3cb , 0xf172d73e004fc90d , 0xdfd1c4febcc81238 , 0xbc8dfb627fe558fc
|
||||
];
|
||||
|
||||
var out[12];
|
||||
for(var i=0; i<12; i++) { out[i] = rcs[ 12*round + i ]; }
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -18,12 +18,14 @@ pragma circom 2.2.0;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// function SolinasExpoBig() { return 64; }
|
||||
// function SolinasExpoSmall() { return 32; }
|
||||
function SolinasExpoBig() { return 64; }
|
||||
function SolinasExpoSmall() { return 32; }
|
||||
|
||||
function SolinasExpoBig() { return 8; }
|
||||
function SolinasExpoSmall() { return 4; }
|
||||
// function SolinasExpoBig() { return 8; }
|
||||
// function SolinasExpoSmall() { return 4; }
|
||||
|
||||
function FieldPrime() { return (2**SolinasExpoBig() - 2**SolinasExpoSmall() + 1); }
|
||||
function FieldPrime() {
|
||||
return (2**SolinasExpoBig() - 2**SolinasExpoSmall() + 1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -75,6 +75,25 @@ template ToGoldilocks() {
|
||||
out.val <== bin.val;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// reduce numbers in the range `0 <= x < 2^k * P` modulo P
|
||||
template ReduceModP(k) {
|
||||
signal input inp;
|
||||
output Goldilocks() out;
|
||||
|
||||
var P = FieldPrime();
|
||||
|
||||
signal quot <-- inp \ P;
|
||||
signal rem <-- inp % P;
|
||||
|
||||
// check that `quot` is in a `k` bit range!
|
||||
component bits = ToBits( k );
|
||||
bits.inp <== quot;
|
||||
|
||||
inp === rem + P * quot; // check the multiplication equation
|
||||
out <== ToGoldilocks()(rem); // range check on the output
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@ -147,23 +166,14 @@ template Sum(k) {
|
||||
input Goldilocks() A[k];
|
||||
output Goldilocks() C;
|
||||
|
||||
var P = FieldPrime();
|
||||
|
||||
// sum A[i] = C + P * Q
|
||||
// since all A[i] < 2^64, Q will have at most as many bits as `k` have
|
||||
// so we can do a simple binary range-check on Q
|
||||
|
||||
var sum = 0;
|
||||
for(var i=0; i<k; i++) { sum += A[k].val; }
|
||||
signal quot <-- sum \ k; // integer division, not field division!
|
||||
signal rem <-- sum - quot*P;
|
||||
|
||||
// check that quot is in the expected range
|
||||
component bits = ToBits( CeilLog2(k) );
|
||||
bits.inp <== quot;
|
||||
|
||||
sum === rem + P * quot; // check the sum equation
|
||||
C <== ToGoldilocks()(rem); // range check on C
|
||||
C <== ReduceModP( CeilLog2(k) )( sum );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -176,45 +186,27 @@ template Mul() {
|
||||
input Goldilocks() A,B;
|
||||
output Goldilocks() C;
|
||||
|
||||
var P = FieldPrime();
|
||||
|
||||
// A * B = C + P * Q
|
||||
|
||||
var product = A.val * B.val;
|
||||
signal quot <-- product \ P;
|
||||
signal rem <-- product % P;
|
||||
|
||||
// check that `quot` is in a 64 bit range!
|
||||
component bits = ToBits( SolinasExpoBig() );
|
||||
bits.inp <== quot;
|
||||
|
||||
A.val * B.val === rem + P * quot; // check the multiplication equation
|
||||
C <== ToGoldilocks()(rem); // range check on C
|
||||
C <== ReduceModP( SolinasExpoBig() )( A.val * B.val );
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// multiplication of 3 Goldilocks field elements
|
||||
// as this still fits into 192 < 254 bits, we can do it a bit more efficiently
|
||||
// than two multiplications.
|
||||
//
|
||||
|
||||
template Mul3() {
|
||||
input Goldilocks() A,B,C;
|
||||
output Goldilocks() D;
|
||||
|
||||
var P = FieldPrime();
|
||||
|
||||
// A * B * C = D + P * Q
|
||||
|
||||
var product = A.val * B.val * C.val;
|
||||
signal quot <-- product \ P;
|
||||
signal rem <-- product % P;
|
||||
signal AB <== A.val * B.val;
|
||||
|
||||
// check that `quot` is in a 128 bit range!
|
||||
component bits = ToBits( 2 * SolinasExpoBig() );
|
||||
bits.inp <== quot;
|
||||
|
||||
A.val * B.val * C.val === rem + P * quot; // check the multiplication equation
|
||||
D <== ToGoldilocks()(rem); // range check on D
|
||||
D <== ReduceModP( 2 * SolinasExpoBig() )( AB * C.val );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
176
circuit/poseidon.circom
Normal file
176
circuit/poseidon.circom
Normal file
@ -0,0 +1,176 @@
|
||||
|
||||
//
|
||||
// Plonky2's Poseidon hash instance over the Goldilocks field
|
||||
//
|
||||
|
||||
pragma circom 2.2.0;
|
||||
|
||||
include "goldilocks.circom";
|
||||
include "constants.circom";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template SBOX() {
|
||||
input Goldilocks() inp;
|
||||
output Goldilocks() out;
|
||||
|
||||
Goldilocks() x3;
|
||||
|
||||
x3 <== Mul3()( inp , inp , inp );
|
||||
out <== Mul3()( x3 , x3 , inp );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// numbers in the range `0 <= x < 2*P`
|
||||
bus AtMostTwoP() {
|
||||
signal val;
|
||||
}
|
||||
|
||||
// If `x < P` then of course `x < 2*P` too
|
||||
template Embed() {
|
||||
input Goldilocks() inp;
|
||||
output AtMostTwoP() out;
|
||||
out.val <== inp.val;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template ExternalNonlinearLayer(round) {
|
||||
input Goldilocks() inp[12];
|
||||
output Goldilocks() out[12];
|
||||
|
||||
var rc[12] = poseidon_round_constants(round);
|
||||
Goldilocks RC [12];
|
||||
Goldilocks tmp[12];
|
||||
|
||||
for(var i=0; i<12; i++) {
|
||||
RC[i].val <== rc[i]; // we know that the constants are in the corrrect range
|
||||
tmp[i] <== Add()( inp[i] , RC[i] ); // this range check could be probably optimized away with a more general Mul3
|
||||
out[i] <== SBOX()( tmp[i] );
|
||||
}
|
||||
|
||||
// log("\nAFTER external nonlinear layer | round=",round);
|
||||
// for(var i=0; i<12; i++) {
|
||||
// log("out[",i,"] = ",out[i].val);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// NOTE: we don't reduce the output, as it will be multiplied by the MDS matrix next,
|
||||
// and it's enough to reduce after that
|
||||
//
|
||||
template InternalNonlinearLayer(round) {
|
||||
input Goldilocks() inp[12];
|
||||
output AtMostTwoP() out[12];
|
||||
|
||||
var rc[12] = poseidon_round_constants(round);
|
||||
|
||||
Goldilocks RC0;
|
||||
RC0.val <== rc[0]; // we know that the constants are in the corrrect range
|
||||
|
||||
Goldilocks tmp <== Add()( inp[0] , RC0 );
|
||||
Goldilocks sbox <== SBOX()( tmp );
|
||||
out[0] <== Embed()( sbox );
|
||||
|
||||
for(var i=1; i<12; i++) {
|
||||
out[i].val <== inp[i].val + rc[i];
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// NOTE: the sum of the coefficients of a row of the circulant matrix is
|
||||
//
|
||||
// > sum [17, 15, 41, 16, 2, 28, 13, 13, 39, 18, 34, 20] = 256
|
||||
//
|
||||
// So if each input is less than `B`, then the (unreduced) linear combination is less than `256*B`
|
||||
//
|
||||
// The only exception is the first row, becuase the diagonal
|
||||
// matrix `[8,0,0,...,0]` is added to the circulant matrix
|
||||
//
|
||||
template LinearDiffusionLayer(extra) {
|
||||
input AtMostTwoP inp[12];
|
||||
output Goldilocks() out[12];
|
||||
|
||||
var coeffs[12] = circular_matrix_coeffs();
|
||||
|
||||
var ys[12];
|
||||
for(var k=0; k<12; k++) {
|
||||
var y = 0;
|
||||
for(var j=0; j<12; j++) {
|
||||
var diag = ((k==0)&&(j==0)) ? 8 : 0;
|
||||
y += inp[j].val * ( diag + coeffs[ (j-k+12) % 12 ] );
|
||||
}
|
||||
ys[k] = y;
|
||||
}
|
||||
|
||||
out[0] <== ReduceModP( 9+extra )( ys[0] );
|
||||
for(var k=1; k<12; k++) { out[k] <== ReduceModP( 8+extra )( ys[k] ); }
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template ExternalRound(round) {
|
||||
input Goldilocks() inp[12];
|
||||
output Goldilocks() out[12];
|
||||
AtMostTwoP() tmp[12];
|
||||
Goldilocks() gls[12];
|
||||
|
||||
gls <== ExternalNonlinearLayer(round)( inp );
|
||||
for(var k=0; k<12; k++) { tmp[k] <== Embed()( gls[k] ); }
|
||||
out <== LinearDiffusionLayer(0)( tmp );
|
||||
|
||||
}
|
||||
|
||||
template InternalRound(round) {
|
||||
input Goldilocks() inp[12];
|
||||
output Goldilocks() out[12];
|
||||
AtMostTwoP() tmp[12];
|
||||
|
||||
tmp <== InternalNonlinearLayer(round)( inp );
|
||||
out <== LinearDiffusionLayer(1)( tmp );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template Permutation() {
|
||||
input Goldilocks() inp[12];
|
||||
output Goldilocks() out[12];
|
||||
Goldilocks() aux[31][12];
|
||||
|
||||
aux[0] <== inp;
|
||||
|
||||
for(var i=0 ; i<4 ; i++) { aux[i+1] <== ExternalRound(i)( aux[i] ); }
|
||||
for(var i=4 ; i<26; i++) { aux[i+1] <== InternalRound(i)( aux[i] ); }
|
||||
for(var i=26; i<30; i++) { aux[i+1] <== ExternalRound(i)( aux[i] ); }
|
||||
|
||||
aux[30] ==> out;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template CheckPermutationKAT() {
|
||||
signal input dummy; // hack around circom
|
||||
Goldilocks() inp[12];
|
||||
Goldilocks() out[12];
|
||||
|
||||
for(var i=0; i<12; i++) { inp[i].val <== i; }
|
||||
out <== Permutation()( inp );
|
||||
|
||||
var kat[12] = poseidon_kat();
|
||||
|
||||
log("\nfinal permutation output:");
|
||||
for(var i=0; i<12; i++) {
|
||||
log("out[",i,"] = ",out[i].val, " vs. expected = ",kat[i]);
|
||||
}
|
||||
|
||||
for(var i=0; i<12; i++) {
|
||||
out[i].val === kat[i];
|
||||
}
|
||||
}
|
||||
|
||||
17
circuit/run.sh
Executable file
17
circuit/run.sh
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
ORIG=`pwd`
|
||||
MAIN="testmain"
|
||||
INPUT="dummy.json"
|
||||
|
||||
cd build
|
||||
|
||||
circom ../${MAIN}.circom --r1cs --wasm
|
||||
|
||||
echo '{ "dummy": 666 }' >${INPUT}
|
||||
|
||||
cd ${MAIN}_js
|
||||
|
||||
node generate_witness.js ${MAIN}.wasm ../${INPUT} witness.wtns
|
||||
|
||||
cd ${ORIG}
|
||||
@ -16,6 +16,14 @@ template ToGoldilocksWrapper() {
|
||||
goldi.val ==> out;
|
||||
}
|
||||
|
||||
template ReduceWrapper(k) {
|
||||
signal input inp;
|
||||
signal output out;
|
||||
|
||||
Goldilocks() goldi <== ReduceModP(k);
|
||||
goldi.val ==> out;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template NegWrapper() {
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
pragma circom 2.2.0;
|
||||
|
||||
include "test_wrapper.circom";
|
||||
include "poseidon.circom";
|
||||
|
||||
//component main { public [A,B] } = AddWrapper();
|
||||
// component main { public [A,B] } = AddWrapper();
|
||||
// component main { public [A] } = InvWrapper();
|
||||
|
||||
component main { public [A] } = InvWrapper();
|
||||
component main { public [dummy] } = CheckPermutationKAT();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user