���� JFIF  XX �� �� �     $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222�� ��" �� 4     ��   �� �,�PG"Z_�4�˷����kjز�Z�,F+��_z�,�© �����zh6�٨�ic�fu��� #ډb���_�N� ?� �wQ���5-�~�I���8��� �TK<5o�Iv-� ����k�_U_����� ~b�M��d��� �Ӝ�U�Hh��?]��E�w��Q���k�{��_}qFW7HTՑ��Y��F� ?_�'ϔ��_�Ջt� �=||I �� 6�έ"�����D���/[�k�9�� �Y�8 ds|\���Ҿp6�Ҵ���]��.����6� z<�v��@]�i% �� $j��~ �g��J>��no����pM[me�i$[�� �� s�o�ᘨ�˸ nɜG-�ĨU�ycP� 3.DB�li�;� �hj���x 7Z^�N�h��� ���N3u{�:j �x�힞��#M &��jL P@ _���� P�� &��o8 ������9 �����@Sz 6�t7#O�ߋ � s}Yf�T� ��lmr����Z)'N��k�۞p ����w\�T ȯ?�8` �O��i{wﭹW�[�r�� ��Q4F�׊�� �3m&L�=��h3� ���z~��#� \�l :�F,j@�� ʱ�wQT����8�"kJO��� 6�֚l���� }��� R�>ډK���]��y����&����p�}b�� ;N�1�m�r$� |��7�>e�@ B�TM*-i H��g�D�)� E�m�|�ؘbҗ�a ��Ҿ���� t4��� o���G��*oCN�rP���Q��@z,|?W[0 �����:�n,j WiE��W� �$~/�hp\��?��{(�0���+�Y8rΟ�+����>S-S�� ��VN;� }�s?.����� w �9��˟<���Mq4�Wv' ��{)0�1mB ��V����W[� ����8�/<� �%���wT^�5���b��)iM� p g�N�&ݝ� �VO~� q���u���9� ����!��J27��� �$ O-���! �: �%H��� ـ ����y�ΠM=t{!S�� oK8������ t<����è :a�� ����[���� �ա�H���~��w��Qz`�p o�^ �� ��Q��n�  �,uu�C� $ ^���,� �����8�#��:�6��e�|~� ��!�3� 3.�\0�� q��o�4`.|� ����y�Q�`~;�d�ׯ,��O�Zw�������`73�v�܋�< ���Ȏ�� ـ4k��5�K�a�u�=9Yd��$>x�A�&�� j0� ���vF��� Y� |�y��� ~�6�@c��1vOp �Ig�� ��4��l�OD� ��L����� R���c���j�_�uX 6��3?nk��Wy�f;^*B� ��@ �~a�`��Eu������ +� �� 6�L��.ü>��}y���}_�O�6�͐�:�Yr G�X��kG�� ���l^w�� �~㒶sy� �Iu�!� W ��X��N�7BV��O��!X�2����wvG�R�f�T#�����t�/?���%8�^�W�aT ��G�cL�M���I��(J����1~�8�?aT ���]����AS�E��(��*E}� 2�� #I/�׍qz��^t�̔��� b�Yz4x ���t�){ OH� �+(E��A&�N�������XT��o��"�XC�� '���)}�J�z�p� ��~5�}�^����+�6����w��c��Q�| Lp�d�H��}�(�.|����k��c4^� "�����Z?ȕ ��a< �L�!0 39C� �Eu� C�F�Ew�ç ;�n?�*o���B�8�bʝ���'#Rqf�� �M}7����]��� �s2tcS{�\icTx;�\��7K���P ���ʇ Z O-��~�� c>"��?�� �����P ��E��O�8��@�8��G��Q�g�a�Վ���󁶠 �䧘��_%#r�>� 1�z�a�� eb��qcP ѵ��n���#L��� =��׀t� L�7�` ��V��� A{�C:�g���e@ �w1 Xp 3�c3�ġ���� p��M"'-�@n4���fG� �B3�DJ�8[Jo�ߐ���gK)ƛ��$���� � ��8�3�����+���� �����6�ʻ���� ���S�kI�*KZlT _`�� �?��K� ���QK�d ����B`�s}�>���` ��*�>��,*@J�d�oF*� ���弝��O}�k��s��]��y�ߘ ��c1G�V���<=�7��7����6 �q�PT��tXԀ�!9*4�4Tހ 3XΛex�46�� �Y��D ����� �BdemDa����\�_l,� �G�/���֌7���Y�](�xTt^%�GE�����4�}bT ���ڹ�����; Y)���B�Q��u��>J/J � ⮶.�XԄ��j�ݳ� +E��d ��r�5�_D �1 �� o�� �B�x�΢�#� ��<��W�����8���R6�@ g�M�.��� dr�D��>(otU��@ x=��~v���2� ӣ�d�oBd ��3�eO�6�㣷�� ���ݜ 6��6Y��Qz`�� S��{���\P �~z m5{J/L��1������<�e�ͅPu� b�]�ϔ ���'�� ����f�b� Zpw��c`"��i���BD@:)ִ�:�]��h v�E� w���T�l ��P� ��"Ju�}��وV J��G6��. J/�Qgl߭�e�����@�z�Zev2u� )]կ��� ��7x�� �s�M�-<ɯ�c��r� v�����@��$�ޮ}lk���a�� �'����>x��O\�Z Fu>��� ��ck#��&:��`�$ �ai�>2Δ����l���oF[h� �lE�ܺ�Π k:)���` �� $[6�����9�����kOw�\|��� 8}������ބ:��񶐕� �I�A1/� =�2[�,�!��.}gN#�u����b ��� ~� �݊��}34q��� �d�E��L c��$ ��"�[q�U�硬g^��%B � z���r�p J�ru%v\h 1Y�ne` ǥ:g�� �pQM~�^� Xi� ��`S�:V2 9.�P���V� ?B�k�� AEvw%�_�9C�Q����wKekP ؠ�\� ;Io d�{ ߞo�c1eP��� �\� `����E=���@K<�Y�� �eڼ�J ���w����{av�F�'�M�@ /J��+9p ���|]���� �Iw &` ��8���& M�hg ��[�{ ��Xj�� %��Ӓ� $��(��� �ʹN��� <>�I���RY� ��K2�NPlL�ɀ )��&e� ���B+ь����( � �JTx ���_?EZ� }@ 6�U���뙢ط�z��dWI� n` D����噥�[��uV��"�G& Ú����2 g�}&m� �?ċ �"����Om#� ������� � ��{� ON��"S�X ��Ne��ysQ���@ Fn��Vg��� dX�~nj� ]J�<�K]: ��FW�� b�������62 �=��5f����JKw� �bf�X� 55��~J �%^� ���:�-�QIE��P��v�nZum� z � ~ə ���� ���ة����;�f��\v��� g�8�1��f2 4;�V���ǔ�)��� �9���1\�� c��v�/'Ƞ�w����� ��$�4�R-��t�� �� e�6�/�ġ �̕Ecy�J���u�B���<�W�ַ~�w[B1L۲�-JS΂�{���΃���� ��A��20�c# �� @    0!1@AP"#2Q`$3V�%45a6�FRUq���   � ���^7ׅ,$n� ������+��F�`��2X'��0vM��p�L=������ 5��8������u�p~���.�`r�����\��� O��,ư�0oS ��_�M�����l���4�kv\JSd���x���SW�<��Ae�IX����������$I���w�:S���y���›R��9�Q[���,�5�;�@]�%���u�@ *ro�lbI �� ��+���%m:�͇ZV�����u�̉����θau<�fc�.����{�4Ա� �Q����*�Sm��8\ujqs]{kN���)qO�y�_*dJ�b�7���yQqI&9�ԌK!�M}�R�;�� ����S�T���1���i[U�ɵz�]��U)V�S6���3$K{� ߊ<�(� E]Զ[ǼENg�����'�\?#)Dkf��J���o��v���'�%ƞ�&K�u� !��b�35LX�Ϸ��63$K�a�;�9>,R��W��3�3� d�JeTYE.Mϧ��-�o�j3+y��y^�c�������VO�9NV\nd�1 ��!͕_)a�v;����թ�M�lWR1��)El��P;��yوÏ�u 3�k�5Pr6<�⒲l�!˞*��u־�n�!�l:����UNW ��%��Chx8vL'��X�@��*��)���̮��ˍ��� � ��D-M�+J�U�kvK����+�x8��cY������?�Ԡ��~3mo��|�u@[XeY�C�\Kp�x8�oC�C�&����N�~3-H���� ��MX�s�u<`���~"WL��$8ξ��3���a�)|:@�m�\���^�`�@ҷ)�5p+��6���p�%i)P M���ngc�����#0Aruz���RL+xSS?���ʮ}()#�t��mˇ!��0}}y����<�e� �-ή�Ԩ��X������ MF���ԙ~l L.3���}�V뽺�v��� ��멬��Nl�)�2����^�Iq��a��M��qG��T�����c3#������3U�Ǎ���}��לS�|qa��ڃ�+���-��2�f����/��bz��ڐ�� �ݼ[2�ç����k�X�2�* �Z�d���J�G����M*9W���s{��w���T��x��y,�in�O�v��]���n����P�$� JB@=4�OTI�n��e�22a\����q�d���%�$��(���:���: /*�K[PR�fr\nڙdN���F�n�$�4� [�� U�zƶ����� �mʋ���,�ao�u 3�z� �x��Kn����\[��VFmbE;�_U��&V�Gg�]L�۪&#n%�$ɯ� dG���D�TI=�%+AB�Ru#��b4�1�»x�cs�YzڙJG��f��Il� �d�eF'T� iA��T���uC�$����Y��H?����[!G`}���ͪ� �纤Hv\������j�Ex�K���!���OiƸ�Yj�+u-<���'q����uN�*�r\��+�]���<�wOZ.fp�ێ��,-*)V?j-kÊ#�`�r��dV����(�ݽBk�����G�ƛk�QmUڗe��Z���f}|����8�8��a���i��3'J�����~G_�^���d�8w������ R�`(�~�.��u���l�s+g�bv���W���lGc}��u���afE~1�Ue������Z�0�8�=e�� f@/�jqEKQQ�J� �oN��J���W5~M>$6�Lt�;$ʳ{���^��6�{����v6���ķܰg�V�cnn �~z�x�«�,2�u�?cE+Ș�H؎�%�Za�)���X>uW�Tz�Nyo����s���FQƤ��$��*�&�LLXL)�1�" L��eO��ɟ�9=���:t��Z���c��Ž���Y?�ӭV�wv�~,Y��r�ۗ�|�y��GaF�����C�����.�+� ���v1���fήJ�����]�S��T��B��n5sW}y�$��~z�'�c ��8 ��� ,! �p��VN�S��N�N�q��y8z˱�A��4��*��'������2n<�s���^ǧ˭P�Jޮɏ�U�G�L�J�*#��<�V��t7�8����TĜ>��i}K%,���)[��z�21z ?�N�i�n1?T�I�R#��m-�����������������1����lA�`��fT5+��ܐ�c�q՝��ʐ��,���3�f2U�եmab��#ŠdQ�y>\��)�SLY����w#��.���ʑ�f��� ,"+�w�~�N�'�c�O�3F�������N<���)j��&��,-� �љ���֊�_�zS���TǦ����w�>��?�������n��U仆�V���e�����0���$�C�d���rP �m�׈e�Xm�Vu� �L��.�bֹ��� �[Դaզ���*��\y�8�Է:�Ez\�0�Kq�C b��̘��cө���Q��=0Y��s�N��S.��� 3.���O�o:���#���v7�[#߫ ��5�܎�L���Er4���9n��COWlG�^��0k�%<���ZB���aB_���������'=��{i�v�l�$�uC���mƎҝ{�c㱼�y]���W�i ��ߧc��m�H� m�"�"�����;Y�ߝ�Z�Ǔ�����:S#��|}�y�,/k�Ld� TA�(�AI$+I3��;Y*���Z��}|��ӧO��d�v��..#:n��f>�>���ȶI�TX��� 8��y����"d�R�|�)0���=���n4��6ⲑ�+��r<�O�܂~zh�z����7ܓ�HH�Ga롏���nCo�>������a ���~]���R���̲c?�6(�q�;5%� |�uj�~z8R =X��I�V=�|{v�Gj\gc��q����z�؋%M�ߍ����1y��#��@f^���^�>N��� ��#x#۹��6�Y~�?�dfPO��{��P�4��V��u1E1J �*|���%�� �JN��`eWu�zk M6���q t[�� ��g�G���v��WIG��u_ft����5�j�"�Y�:T��ɐ���*�;� e5���4����q$C��2d�}���� _S�L#m�Yp��O�.�C�;��c����Hi#֩%+) �Ӎ��ƲV���SYź��g |���tj��3�8���r|���V��1#;.SQ�A[���S������#���`n�+���$��$ I �P\[�@�s��(�ED�z���P��])8�G#��0B��[ى��X�II�q<��9�~[Z멜�Z�⊔IWU&A>�P~�#��dp<�?����7���c��'~���5 ��+$���lx@�M�dm��n<=e�dyX��?{�|Aef ,|n3�<~z�ƃ�uۧ�����P��Y,�ӥQ�*g�#먙R�\���;T��i,��[9Qi歉����c>]9�� ��"�c��P�� �Md?٥��If�ت�u��k��/����F��9�c*9��Ǎ:�ØF���z�n*�@|I�ށ9����N3{'��[�'ͬ�Ҳ4��#}��!�V� Fu��,�,mTIk���v C�7v���B�6k�T9��1�*l� '~��ƞF��lU��'�M ����][ΩũJ_�{�i�I�n��$�� �L�� j��O�dx�����kza۪��#�E��Cl����x˘�o�����V���ɞ�ljr��)�/,�߬h�L��#��^��L�ф�,íMƁe�̩�NB�L�����iL����q�}��(��q��6IçJ$�W�E$��:������=#����(�K�B����zђ <��K(�N�۫K�w��^O{!����) �H���>x�������lx�?>Պ�+�>�W���,Ly!_�D���Ō�l���Q�!�[ �S����J��1��Ɛ�Y}��b,+�Lo�x�ɓ)����=�y�oh�@�꥟/��I��ѭ=��P�y9��� �ۍYӘ�e+�p�Jnϱ?V\SO%�(�t� ���=?MR�[Ș�����d�/ ��n�l��B�7j� ��!�;ӥ�/�[-���A�>� dN�sLj ��,ɪv��=1c�.SQ�O3�U���ƀ�ܽ�E����������̻��9G�ϷD�7(�}��Ävӌ\� y�_0[w ���<΍>����a_��[0+�L��F.�޺��f�>oN�T����q;���y\��bՃ��y�jH�<|q-eɏ�_?_9+P���Hp$�����[ux�K w�Mw��N�ی'$Y2�=��q���KB��P��~�� ����Yul:�[<����F1�2�O���5=d����]Y�sw:���Ϯ���E��j,_Q��X��z`H1,#II ��d�wr��P˂@�ZJV����y$�\y�{}��^~���[:N����ߌ�U�������O��d�����ؾe��${p>G��3c���Ė�lʌ�� ת��[��`ϱ�-W����dg�I��ig2��� ��}s ��ؤ(%#sS@���~���3�X�nRG�~\jc3�v��ӍL��M[JB�T��s3}��j�Nʖ��W����;7� �ç?=X�F=-�=����q�ߚ���#���='�c��7���ڑW�I(O+=:uxq�������������e2�zi+�kuG�R��������0�&e�n���iT^J����~\jy���p'dtG��s����O��3����9* �b#Ɋ�� p������[Bws�T�>d4�ۧs���nv�n���U���_�~,�v����ƜJ1��s�� �QIz�� )�(lv8M���U=�;����56��G���s#�K���MP�=��LvyGd��}�VwWBF�'�à �?MH�U�g2�� ����!�p�7Q��j��ڴ����=��j�u��� Jn�A s���uM������e��Ɔ�Ҕ�!) '��8Ϣ�ٔ� �ޝ(��Vp���צ֖d=�IC�J�Ǡ{q������kԭ�߸���i��@K����u�|�p=..�*+����x�����z[Aqġ#s2a�Ɗ���RR�)*HRsi�~�a &f��M��P����-K�L@��Z��Xy�'x�{}��Zm+���:�)�) IJ�-i�u���� ���ܒH��'� L(7�y�GӜq���� j��� 6ߌg1�g�o���,kر���tY�?W,���p���e���f�OQS��!K�۟cҒA�|ս�j�>��=⬒��˧L[�� �߿2JaB~R��u�:��Q�] �0H~���]�7��Ƽ�I���( }��cq '�ήET���q�?f�ab���ӥvr� �)o��-Q��_'����ᴎo��K������;��V���o��%���~OK ����*��b�f:���-ťIR��`B�5!RB@���ï�� �u �̯e\�_U�_������� g�ES��3������� QT��a�� ��x����U<~�c?�*�#]�MW,[8O�a�x��]�1bC|踤�P��lw5V%�)�{t�<��d��5���0i�XSU��m:��Z�┵�i�"��1�^B�-��P�hJ��&)O��*�D��c�W��vM��)����}���P��ܗ-q����\mmζZ-l@�}��a��E�6��F�@��&Sg@���ݚ�M����� ȹ 4����#p�\H����dYDo�H���"��\��..R�B�H�z_�/5˘����6��KhJR��P�mƶi�m���3� ,#c�co��q�a)*P t����R�m�k�7x�D�E�\Y�閣_X�<���~�)���c[[�BP����6�Yq���S��0����%_����;��Àv�~�| VS؇ ��'O0��F0��\���U�-�d@�����7�SJ*z��3n��y��P����O��������� m�~�P�3|Y��ʉr#�C�<�G~�.,! ���bqx���h~0=��!ǫ�jy����l� O,�[B��~��|9��ٱ����Xly�#�i�B��g%�S��������tˋ���e���ې��\[d�t)��.+u�|1 ������#�~Oj����hS�%��i.�~X���I�H�m��0n���c�1uE�q��cF�RF�o���7� �O�ꮧ� ���ۛ{��ʛi5�rw?׌#Qn�TW��~?y$��m\�\o����%W� ?=>S�N@�� �Ʈ���R����N�)�r"C�:��:����� �����#��qb��Y�. �6[��2K����2u�Ǧ�HYR��Q�MV��� �G�$��Q+.>�����nNH��q�^��� ����q��mM��V��D�+�-�#*�U�̒ ���p욳��u:�������IB���m� ��PV@O���r[b= �� ��1U�E��_Nm�yKbN�O���U�}�the�`�|6֮P>�\2�P�V���I�D�i�P�O;�9�r�mAHG�W�S]��J*�_�G��+kP�2����Ka�Z���H�'K�x�W�MZ%�O�YD�Rc+o��?�q��Ghm��d�S�oh�\�D�|:W������UA�Qc yT�q� �����~^�H��/��#p�CZ���T�I�1�ӏT����4��"�ČZ�����}��`w�#�*,ʹ�� ��0�i��課�Om�*�da��^gJ݅{���l�e9uF#T�ֲ��̲�ٞC"�q���ߍ ոޑ�o#�XZTp����@ o�8��(jd��xw�]�,f���`~� |,s��^����f�1���t��|��m�򸄭/ctr��5s��7�9Q�4�H1꠲BB@ l9@���C�����+�wp�xu�£Yc�9��?`@#�o�mH�s2��)�=��2�.�l����jg�9$�Y�S�%*L������R�Y������7Z���,*=�䷘$�������arm�o�ϰ���UW.|�r�uf����IGw�t����Zwo��~5 ��YյhO+=8fF�)�W�7�L9lM�̘·Y���֘YLf�큹�pRF���99.A �"wz��=E\Z���'a� 2��Ǚ�#;�'}�G���*��l��^"q��+2FQ� hj��kŦ��${���ޮ-�T�٭cf�|�3#~�RJ����t��$b�(R��(����r���dx� >U b�&9,>���%E\� Ά�e�$��'�q't��*�א���ެ�b��-|d���SB�O�O��$�R+�H�)�܎�K��1m`;�J�2�Y~9��O�g8=vqD`K[�F)k�[���1m޼c��n���]s�k�z$@��)!I �x՝"v��9=�ZA=`Ɠi �:�E��)` 7��vI��}d�YI�_ �o�:ob���o ���3Q��&D&�2=�� �Ά��;>�h����y.*ⅥS������Ӭ�+q&����j|UƧ��� �}���J0��WW< ۋS�)jQR�j���Ư��rN)�Gű�4Ѷ(�S)Ǣ�8��i��W52���No˓� ۍ%�5brOn�L�;�n��\G����=�^U�dI���8$�&���h��'���+�(������cȁ߫k�l��S^���cƗjԌE�ꭔ��gF���Ȓ��@���}O���*;e�v�WV���YJ\�]X'5��ղ�k�F��b 6R�o՜m��i N�i���� >J����?��lPm�U��}>_Z&�KK��q�r��I�D�Չ~�q�3fL�:S�e>���E���-G���{L�6p�e,8��������QI��h��a�Xa��U�A'���ʂ���s�+טIjP�-��y�8ۈZ?J$��W�P� ��R�s�]��|�l(�ԓ��sƊi��o(��S0 ��Y� 8�T97.�����WiL��c�~�dxc�E|�2!�X�K�Ƙਫ਼�$((�6�~|d9u+�qd�^3�89��Y�6L�.I�����?���iI�q���9�)O/뚅����O���X��X�V��ZF[�یgQ�L��K1���RҖr@v�#��X�l��F���Нy�S�8�7�kF!A��sM���^rkp�jP�DyS$N���q�� nxҍ!U�f�!eh�i�2�m ���`�Y�I�9r�6� �TF���C}/�y�^���Η���5d�'��9A-��J��>{�_l+�`��A���[�'��յ�ϛ#w:݅�%��X�}�&�PSt�Q�"�-��\縵�/����$Ɨh�Xb�*�y��BS����;W�ջ_mc�����vt?2}1�;qS�d�d~u:2k5�2�R�~�z+|HE!)�Ǟl��7`��0�<�,�2*���Hl-��x�^����'_TV�gZA�'j� ^�2Ϊ��N7t�����?w�� �x1��f��Iz�C-Ȗ��K�^q�;���-W�DvT�7��8�Z�������� hK�(P:��Q- �8�n�Z���܃e貾�<�1�YT<�,�����"�6{ / �?�͟��|1�:�#g��W�>$����d��J��d�B�� =��jf[��%rE^��il:��B���x���Sּ�1հ��,�=��*�7 fcG��#q� �eh?��2�7�����,�!7x��6�n�LC�4x��},Geǝ�tC.��vS �F�43��zz\��;QYC,6����~;RYS/6���|2���5���v��T��i����������mlv��������&� �nRh^ejR�LG�f���? �ۉҬܦƩ��|��Ȱ����>3����!v��i�ʯ�>�v��オ�X3e���_1z�Kȗ\<������!�8���V��]��?b�k41�Re��T�q��mz��TiOʦ�Z��Xq���L������q"+���2ۨ��8}�&N7XU7Ap�d�X��~�׿��&4e�o�F��� �H�� ��O���č�c�� 懴�6���͉��+)��v;j��ݷ�� �UV�� i��� j���Y9GdÒJ1��詞�����V?h��l�� ��l�cGs�ځ�������y�Ac���� �\V3�? �� ܙg�>qH�S,�E�W�[�㺨�uch�⍸�O�}���a��>�q�6�n6� ���N6�q�� ���� N    ! 1AQaq�0@����"2BRb�#Pr���3C`��Scst���$4D���%Td��  ? � ��N����a��3��m���C���w��������xA�m�q�m��� m������$����4n淿t'��C"w��zU=D�\R+w�p+Y�T�&�պ@��ƃ��3ޯ?�Aﶂ��aŘ���@-�����Q�=���9D��ռ�ѻ@��M�V��P��܅�G5�f�Y<�u=,EC)�<�Fy'�"�&�չ�X~f��l�KԆV��?�� �W�N����=(� �;���{�r����ٌ�Y���h{�١������jW����P���Tc�����X�K�r��}���w�R��%��?���E��m�� �Y�q|����\lEE4� ��r���}�lsI�Y������f�$�=�d�yO����p�����yBj8jU�o�/�S��?�U��*������ˍ�0����� �u�q�m [�?f����a�� )Q�>����6#������� ?����0UQ����,IX���(6ڵ[�DI�MNލ�c&���υ�j\��X�R|,4��� j������T�hA�e��^���d���b<����n�� �즇�=!���3�^�`j�h�ȓr��jẕ�c�,ٞX����-����a�ﶔ���#�$��]w�O��Ӫ�1y%��L�Y<�wg#�ǝ�̗`�x�xa�t�w��»1���o7o5��>�m뭛C���Uƃߜ}�C���y1Xνm�F8�jI���]����H���ۺиE@I�i;r�8ӭ���� V�F�Շ| ��&?�3|x�B�MuS�Ge�=Ӕ�#BE5G�� ���Y!z��_e��q�р/W>|-�Ci߇�t�1ޯќd�R3�u��g�=0 5��[?�#͏��q�cf���H��{ ?u�=?�?ǯ���}Z��z���hmΔ�BFTW�����<�q� (v� ��!��z���iW]*�J�V�z��gX֧A�q�&��/w���u�gYӘa���; �i=����g:��?2�dž6�ى�k�4�>�Pxs����}������G�9� �3 ���)gG�R<>r h�$��'nc�h�P��Bj��J�ҧH� -��N1���N��?��~��}-q!=��_2hc�M��l�vY%UE�@|�v����M2�.Y[|y�"Eï��K�ZF,�ɯ?,q�?v�M 80jx�"�;�9vk�����+ ֧�� �ȺU��?�%�vcV��mA�6��Qg^M��� �A}�3�nl� QRN�l8�kkn�'�����(��M�7m9و�q���%ޟ���*h$Zk"��$�9��: �?U8�Sl��,,|ɒ��xH(ѷ����Gn�/Q�4�P��G�%��Ա8�N��!� �&�7�;���eKM7�4��9R/%����l�c>�x;������>��C�:�����t��h?aKX�bhe�ᜋ^�$�Iհ �hr7%F$�E��Fd���t��5���+�(M6�t����Ü�UU|zW�=a�Ts�Tg������dqP�Q����b'�m���1{|Y����X�N��b �P~��F^F:����k6�"�j!�� �I�r�`��1&�-$�Bevk:y���#y w��I0��x��=D�4��tU���P�ZH��ڠ底taP��6����b>�xa� ���Q�#� WeF��ŮNj�p�J* mQ�N��� �*I�-*�ȩ�F�g�3 �5��V�ʊ�ɮ�a��5F���O@{���NX��?����H�]3��1�Ri_u��������ѕ�� ����0��� F��~��:60�p�͈�S��qX#a�5>���`�o&+�<2�D����: �������ڝ�$�nP���*)�N�|y�Ej�F�5ټ�e���ihy�Z �>���k�bH�a�v��h�-#���!�Po=@k̆IEN��@��}Ll?j�O������߭�ʞ���Q|A07x���wt!xf���I2?Z��<ץ�T���cU�j��]�� 陎Ltl �}5�ϓ��$�,��O�mˊ�;�@O��jE��j(�ا,��LX���LO���Ц�90�O �.����a��nA���7������j4 ��W��_ٓ���zW�jcB������y՗+EM�)d���N�g6�y1_x��p�$Lv :��9�"z��p���ʙ$��^��JԼ*�ϭ����o���=x�Lj�6�J��u82�A�H�3$�ٕ@�=Vv�]�'�qEz�;I˼��)��=��ɯ���x �/�W(V���p�����$ �m�������u�����񶤑Oqˎ�T����r��㠚x�sr�GC��byp�G��1ߠ�w e�8�$⿄����/�M{*}��W�]˷.�CK\�ުx���/$�WP w���r� |i���&�}�{�X� �>��$-��l���?-z���g����lΆ���(F���h�vS*���b���߲ڡn,|)mrH[���a�3�ר�[1��3o_�U�3�TC�$��(�=�)0�kgP���� ��u�^=��4 �WYCҸ:��vQ�ר�X�à��tk�m,�t*��^�,�}D*� �"(�I��9R����>`�`��[~Q]�#af��i6l��8���6�:,s�s�N6�j"�A4���IuQ��6E,�GnH��zS�HO�uk�5$�I�4��ؤ�Q9�@��C����wp �BGv[]�u�Ov��� 0I4���\��y�����Q�Ѹ��~>Z��8�T��a��q�ޣ;z��a���/��S��I:�ܫ_�|������>=Z����8:�S��U�I�J��"IY���8%b8���H��:�QO�6�;7�I�S��J��ҌAά3��>c���E+&jf$eC+�z�;��V����� �r���ʺ������my�e���aQ�f&��6�ND ��.:��NT�vm�<- u���ǝ\MvZY�N�NT��-A�>jr!S��n�O 1�3�Ns�%�3D@���`������ܟ 1�^c<���� �a�ɽ�̲�Xë#�w�|y�cW�=�9I*H8�p�^(4���՗�k��arOcW�tO�\�ƍR��8����'�K���I�Q�����?5�>[�}��yU�ײ -h��=��% q�ThG�2�)���"ו3]�!kB��*p�FDl�A���,�eEi�H�f�Ps�����5�H:�Փ~�H�0Dت�D�I����h�F3�������c��2���E��9�H��5�zԑ�ʚ�i�X�=:m�xg�hd(�v����׊�9iS��O��d@0ڽ���:�p�5�h-��t�&���X�q�ӕ,��ie�|���7A�2���O%P��E��htj��Y1��w�Ѓ!����  ���� ࢽ��My�7�\�a�@�ţ�J �4�Ȼ�F�@o�̒?4�wx��)��]�P��~�����u�����5�����7X ��9��^ܩ�U;Iꭆ 5 �������eK2�7(�{|��Y׎ �V��\"���Z�1� Z�����}��(�Ǝ"�1S���_�vE30>���p;� ΝD��%x�W�?W?v����o�^V�i�d��r[��/&>�~`�9Wh��y�;���R�� � ;;ɮT��?����r$�g1�K����A��C��c��K��l:�'��3 c�ﳯ*"t8�~l��)���m��+U,z��`( �>yJ�?����h>��]��v��ЍG*�{`��;y]��I�T� ;c��NU�fo¾h���/$���|NS���1�S�"�H��V���T���4��uhǜ�]�v;���5�͠x��'C\�SBpl���h}�N����� A�Bx���%��ޭ�l��/����T��w�ʽ]D�=����K���ž�r㻠l4�S�O?=�k �M:� ��c�C�a�#ha���)�ѐxc�s���gP�iG�� {+���x���Q���I= �� z��ԫ+ �8"�k�ñ�j=|����c ��y��CF��/ ��*9ж�h{ �?4�o� ��k�m�Q�N�x��;�Y��4膚�a�w?�6�> e]�����Q�r�:����g�,i"�����ԩA� *M�<�G��b�if��l^M��5� �Ҩ�{����6J��ZJ�����P�*�����Y���ݛu�_4�9�I8�7���������,^ToR���m4�H��?�N�S�ѕw��/S��甍�@�9H�S�T��t�ƻ���ʒU��*{Xs�@����f��� ��֒Li�K{H�w^���������Ϥm�tq���s� ���ք��f:��o~s��g�r��ט� �S�ѱC�e]�x���a��) ���(b-$(�j>�7q�B?ӕ�F��hV25r[7 Y� }L�R��}����*sg+��x�r�2�U=�*'WS��ZDW]�WǞ�<��叓���{�$�9Ou4��y�90-�1�'*D`�c�^o?(�9��u���ݐ��'PI&� f�Jݮ�������:wS����jfP1F:X �H�9dԯ�� �˝[�_54 �}*;@�ܨ�� ð�yn�T���?�ןd�#���4rG�ͨ��H�1�|-#���Mr�S3��G�3�����)�.᧏3v�z֑��r����$G"�`j �1t��x0<Ɔ�Wh6�y�6��,œ�Ga��gA����y��b��)� �h�D��ß�_�m��ü �gG;��e�v��ݝ�nQ� ��C����-�*��o���y�a��M��I�>�<���]obD��"�:���G�A��-\%LT�8���c�)��+y76���o�Q�#*{�(F�⽕�y����=���rW�\p���۩�c���A���^e6��K������ʐ�cVf5$�'->���ՉN"���F�"�UQ@�f��Gb~��#�&�M=��8�ט�JNu9��D��[̤�s�o�~��� ��� G��9T�tW^g5y$b��Y'��س�Ǵ�=��U-2 #�MC�t(�i� �lj�@Q 5�̣i�*�O����s�x�K�f��}\��M{E�V�{�υ��Ƈ�����);�H����I��fe�Lȣr�2��>��W� I�Ȃ6������i��k�� �5�YOxȺ����>��Y�f5'��|��H+��98pj�n�.O�y�������jY��~��i�w'������l�;�s�2��Y��:'lg�ꥴ)o#'Sa�a�K��Z� �m��}�`169�n���"���x��I ��*+� }F<��cГ���F�P�������ֹ*�PqX�x۩��,� ��N�� �4<-����%����:��7����W���u�`����� $�?�I��&����o��o��`v�>��P��"��l���4��5'�Z�gE���8���?��[�X�7(��.Q�-��*���ތL@̲����v��.5���[��=�t\+�CNܛ��,g�SQnH����}*F�G16���&:�t��4ُ"A��̣��$�b �|����#rs��a�����T�� ]�<�j��B S�('$�ɻ� �wP;�/�n��?�ݜ��x�F��yUn�~mL*-�������Xf�wd^�a�}��f�,=t�׵i�.2/wpN�Ep8�OР���•��R�FJ� 55TZ��T �ɭ�<��]��/�0�r�@�f��V��V����Nz�G��^���7hZi����k��3�,kN�e|�vg�1{9]_i��X5y7� 8e]�U����'�-2,���e"����]ot�I��Y_��n�(JҼ��1�O ]bXc���Nu�No��pS���Q_���_�?i�~�x h5d'�(qw52] ��'ޤ�q��o1�R!���`ywy�A4u���h<קy���\[~�4�\ X�Wt/� 6�����n�F�a8��f���z �3$�t(���q��q�x��^�XWeN'p<-v�!�{�(>ӽDP7��ո0�y)�e$ٕv�Ih'Q�EA�m*�H��RI��=:��� ���4牢) �%_iN�ݧ�l]� �Nt���G��H�L��� ɱ�g<���1V�,�J~�ٹ�"K��Q�� 9�HS�9�?@��k����r�;we݁�]I�!{ �@�G�[�"��`���J:�n]�{�cA�E����V��ʆ���#��U9�6����j�#Y�m\��q�e4h�B�7��C�������d<�?J����1g:ٳ���=Y���D�p�ц� ׈ǔ��1�]26؜oS�'��9�V�FVu�P�h�9�xc�oq�X��p�o�5��Ա5$�9W�V(�[Ak�aY錎qf;�'�[�|���b�6�Ck��)��#a#a˙��8���=äh�4��2��C��4tm^ �n'c� ��]GQ$[Wҿ��i���vN�{Fu ��1�gx��1┷���N�m��{j-,��x�� Ūm�ЧS�[�s���Gna���䑴�� x�p 8<������97�Q���ϴ�v�aϚG��Rt�Һ׈�f^\r��WH�JU�7Z���y)�vg=����n��4�_)y��D'y�6�]�c�5̪ �\� �PF�k����&�c;��cq�$~T�7j ���nç]�<�g ":�to�t}�159�<�/�8������m�b�K#g'I'.W����� 6��I/��>v��\�MN��g���m�A�yQL�4u�Lj�j9��#44�t��l^�}L����n��R��!��t��±]��r��h6ٍ>�yҏ�N��fU�� ���� Fm@�8}�/u��jb9������he:A�y�ծw��GpΧh�5����l}�3p468��)U��d��c����;Us/�֔�YX�1�O2��uq�s��`hwg�r~�{ R��mhN��؎*q 42�*th��>�#���E����#��Hv�O����q�}����� 6�e��\�,Wk�#���X��b>��p}�դ��3���T5��†��6��[��@ �P�y*n��|'f�֧>�lư΂�̺����SU�'*�q�p�_S�����M�� '��c�6��� ��m�� ySʨ;M��r���Ƌ�m�Kxo,���Gm�P��A�G�:��i��w�9�}M(�^�V��$ǒ�ѽ�9���|���� �a����J�SQ�a���r�B;����}���ٻ֢�2�%U���c�#�g���N�a�ݕ�'�v�[�OY'��3L�3�;,p�]@�S��{ls��X�'���c�jw� k'a�.��}�}&�� �dP�*�bK=ɍ!����;3n�gΊU�ߴmt�'*{,=SzfD� A��ko~�G�aoq�_mi}#�m�������P�Xhύ��� �mxǍ�΂���巿zf��Q���c���|kc�����?���W��Y�$���_Lv����l߶��c���`?����l�j�ݲˏ!V��6����U�Ђ(A���4y)H���p�Z_�x��>���e�� R��$�/�`^'3qˏ�-&Q�=?��CFVR �D�fV�9��{�8g�������n�h�(P"��6�[�D���< E�����~0<@�`�G�6����Hг�cc�� �c�K.5��D��d�B���`?�XQ��2��ٿyqo&+�1^� DW�0�ꊩ���G�#��Q�nL3��c���������/��x ��1�1 [y�x�პCW��C�c�UĨ80�m�e�4.{�m��u���I=��f�����0QRls9���f���������9���~f�����Ǩ��a�"@�8���ȁ�Q����#c�ic������G��$���G���r/$W�(��W���V�"��m�7�[m�A�m����bo��D� j����۳� l���^�k�h׽����� ��#� iXn�v��eT�k�a�^Y�4�BN�� ĕ�� 0    !01@Q"2AaPq3BR������ ? � ��@4�Q�����T3,���㺠�W�[=JK�Ϟ���2�r^7��vc�:�9 �E�ߴ�w�S#d���Ix��u��:��Hp��9E!�� V 2;73|F��9Y���*ʬ�F��D����u&���y؟��^EA��A��(ɩ���^��GV:ݜDy�`��Jr29ܾ�㝉��[���E;Fzx��YG��U�e�Y�C���� ����v-tx����I�sם�Ę�q��Eb�+P\ :>�i�C'�;�����k|z�رn�y]�#ǿb��Q��������w�����(�r|ӹs��[�D��2v-%��@;�8<a���[\o[ϧw��I!��*0�krs)�[�J9^��ʜ��p1)� "��/_>��o��<1����A�E�y^�C��`�x1'ܣn�p��s`l���fQ��):�l����b>�Me�jH^?�kl3(�z:���1ŠK&?Q�~�{�ٺ�h�y���/�[��V�|6��}�KbX����mn[-��7�5q�94�������dm���c^���h� X��5��<�eޘ>G���-�}�دB�ޟ� ��|�rt�M��V+�]�c?�-#ڛ��^ǂ}���Lkr���O��u�>�-D�ry� D?:ޞ�U��ǜ�7�V��?瓮�"�#���r��չģVR;�n���/_� ؉v�ݶe5d�b9��/O��009�G���5n�W����JpA�*�r9�>�1��.[t���s�F���nQ� V 77R�]�ɫ8����_0<՜�IF�u(v��4��F�k�3��E)��N:��yڮe��P�`�1}�$WS��J�SQ�N�j �ٺ��޵�#l���ј(�5=��5�lǏmoW�v-�1����v,W�mn��߀$x�<����v�j(����c]��@#��1������Ǔ���o'��u+����;G�#�޸��v-lη��/(`i⣍Pm^� ��ԯ̾9Z��F��������n��1��� ��]�[��)�'������ :�֪�W��FC����� �B9،!?���]��V��A�Վ�M��b�w��G F>_DȬ0¤�#�QR�[V��kz���m�w�"��9ZG�7'[��=�Q����j8R?�zf�\a�=��O�U����*oB�A�|G���2�54 �p��.w7� �� ��&������ξxGHp� B%��$g�����t�Џ򤵍z���HN�u�Я�-�'4��0�� ;_�� 3     !01"@AQa2Pq#3BR������ ? � �ʩca��en��^��8���<�u#��m*08r��y�N"�<�Ѳ0��@\�p��� �����Kv�D��J8�Fҽ� �f�Y��-m�ybX�NP����}�!*8t(�OqѢ��Q�wW�K��ZD��Δ^e��!� ��B�K��p~�����e*l}z#9ң�k���q#�Ft�o��S�R����-�w�!�S���Ӥß|M�l޶V��!eˈ�8Y���c�ЮM2��tk���� ������J�fS����Ö*i/2�����n]�k�\���|4yX�8��U�P.���Ы[���l��@"�t�<������5�lF���vU�����W��W��;�b�cД^6[#7@vU�xgZv��F�6��Q,K�v��� �+Ъ��n��Ǣ��Ft���8��0��c�@�!�Zq s�v�t�;#](B��-�nῃ~���3g������5�J�%���O������n�kB�ĺ�.r��+���#�N$?�q�/�s�6��p��a����a��J/��M�8��6�ܰ"�*������ɗud"\w���aT(����[��F��U՛����RT�b���n�*��6���O��SJ�.�ij<�v�MT��R\c��5l�sZB>F��<7�;EA��{��E���Ö��1U/�#��d1�a�n.1ě����0�ʾR�h��|�R��Ao�3�m3 ��%�� ���28Q� ��y��φ���H�To�7�lW>����#i`�q���c����a��� �m,B�-j����݋�'mR1Ήt�>��V��p���s�0IbI�C.���1R�ea�����]H�6�������� ��4B>��o��](��$B���m�����a�!=� �?�B� K�Ǿ+�Ծ"�n���K��*��+��[T#�{ E�J�S����Q�����s�5�:�U�\wĐ�f�3����܆&�)��� �I���Ԇw��E T�lrTf6Q|R�h:��[K�� �z��c֧�G�C��%\��_�a �84��HcO�bi��ؖV��7H �)*ģK~Xhչ0��4?�0��� �E<���}3���#���u�?�� ��|g�S�6ꊤ�|�I#Hڛ� �ա��w�X��9��7���Ŀ%�SL��y6č��|�F�a 8���b� �$�sק�h���b9RAu7�˨p�Č�_\*w��묦��F ����4D~�f����|(�"m���NK��i�S�>�$d7SlA��/�²����SL��|6N�}���S�˯���g��]6��; �#�.��<���q'Q�1|KQ$�����񛩶"�$r�b:���N8�w@��8$�� �AjfG|~�9F ���Y��ʺ��Bwؒ������M:I岎�G��`s�YV5����6��A �b:�W���G�q%l�����F��H���7�������Fsv7� �k�� 403WebShell
403Webshell
Server IP : 127.0.0.1  /  Your IP : 10.100.1.254
Web Server : Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.0.30
System : Windows NT WIZC-EXTRANET 10.0 build 19045 (Windows 10) AMD64
User : SYSTEM ( 0)
PHP Version : 8.0.30
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  C:/xampp/phpMyAdmin/vendor/paragonie/sodium_compat/src/Core/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : C:/xampp/phpMyAdmin/vendor/paragonie/sodium_compat/src/Core/Curve25519.php
<?php

if (class_exists('ParagonIE_Sodium_Core_Curve25519', false)) {
    return;
}

/**
 * Class ParagonIE_Sodium_Core_Curve25519
 *
 * Implements Curve25519 core functions
 *
 * Based on the ref10 curve25519 code provided by libsodium
 *
 * @ref https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c
 */
abstract class ParagonIE_Sodium_Core_Curve25519 extends ParagonIE_Sodium_Core_Curve25519_H
{
    /**
     * Get a field element of size 10 with a value of 0
     *
     * @internal You should not use this directly from another application
     *
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_0()
    {
        return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
            array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
        );
    }

    /**
     * Get a field element of size 10 with a value of 1
     *
     * @internal You should not use this directly from another application
     *
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_1()
    {
        return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
            array(1, 0, 0, 0, 0, 0, 0, 0, 0, 0)
        );
    }

    /**
     * Add two field elements.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     * @psalm-suppress MixedAssignment
     * @psalm-suppress MixedOperand
     */
    public static function fe_add(
        ParagonIE_Sodium_Core_Curve25519_Fe $f,
        ParagonIE_Sodium_Core_Curve25519_Fe $g
    ) {
        /** @var array<int, int> $arr */
        $arr = array();
        for ($i = 0; $i < 10; ++$i) {
            $arr[$i] = (int) ($f[$i] + $g[$i]);
        }
        return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($arr);
    }

    /**
     * Constant-time conditional move.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
     * @param int $b
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     * @psalm-suppress MixedAssignment
     */
    public static function fe_cmov(
        ParagonIE_Sodium_Core_Curve25519_Fe $f,
        ParagonIE_Sodium_Core_Curve25519_Fe $g,
        $b = 0
    ) {
        /** @var array<int, int> $h */
        $h = array();
        $b *= -1;
        for ($i = 0; $i < 10; ++$i) {
            $x = (($f[$i] ^ $g[$i]) & $b);
            $h[$i] = ($f[$i]) ^ $x;
        }
        return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h);
    }

    /**
     * Create a copy of a field element.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_copy(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        $h = clone $f;
        return $h;
    }

    /**
     * Give: 32-byte string.
     * Receive: A field element object to use for internal calculations.
     *
     * @internal You should not use this directly from another application
     *
     * @param string $s
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     * @throws RangeException
     * @throws TypeError
     */
    public static function fe_frombytes($s)
    {
        if (self::strlen($s) !== 32) {
            throw new RangeException('Expected a 32-byte string.');
        }
        $h0 = self::load_4($s);
        $h1 = self::load_3(self::substr($s, 4, 3)) << 6;
        $h2 = self::load_3(self::substr($s, 7, 3)) << 5;
        $h3 = self::load_3(self::substr($s, 10, 3)) << 3;
        $h4 = self::load_3(self::substr($s, 13, 3)) << 2;
        $h5 = self::load_4(self::substr($s, 16, 4));
        $h6 = self::load_3(self::substr($s, 20, 3)) << 7;
        $h7 = self::load_3(self::substr($s, 23, 3)) << 5;
        $h8 = self::load_3(self::substr($s, 26, 3)) << 4;
        $h9 = (self::load_3(self::substr($s, 29, 3)) & 8388607) << 2;

        $carry9 = ($h9 + (1 << 24)) >> 25;
        $h0 += self::mul($carry9, 19, 5);
        $h9 -= $carry9 << 25;
        $carry1 = ($h1 + (1 << 24)) >> 25;
        $h2 += $carry1;
        $h1 -= $carry1 << 25;
        $carry3 = ($h3 + (1 << 24)) >> 25;
        $h4 += $carry3;
        $h3 -= $carry3 << 25;
        $carry5 = ($h5 + (1 << 24)) >> 25;
        $h6 += $carry5;
        $h5 -= $carry5 << 25;
        $carry7 = ($h7 + (1 << 24)) >> 25;
        $h8 += $carry7;
        $h7 -= $carry7 << 25;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;
        $carry2 = ($h2 + (1 << 25)) >> 26;
        $h3 += $carry2;
        $h2 -= $carry2 << 26;
        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;
        $carry6 = ($h6 + (1 << 25)) >> 26;
        $h7 += $carry6;
        $h6 -= $carry6 << 26;
        $carry8 = ($h8 + (1 << 25)) >> 26;
        $h9 += $carry8;
        $h8 -= $carry8 << 26;

        return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
            array(
                (int) $h0,
                (int) $h1,
                (int) $h2,
                (int) $h3,
                (int) $h4,
                (int) $h5,
                (int) $h6,
                (int) $h7,
                (int) $h8,
                (int) $h9
            )
        );
    }

    /**
     * Convert a field element to a byte string.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $h
     * @return string
     */
    public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h)
    {
        $h0 = (int) $h[0];
        $h1 = (int) $h[1];
        $h2 = (int) $h[2];
        $h3 = (int) $h[3];
        $h4 = (int) $h[4];
        $h5 = (int) $h[5];
        $h6 = (int) $h[6];
        $h7 = (int) $h[7];
        $h8 = (int) $h[8];
        $h9 = (int) $h[9];

        $q = (self::mul($h9, 19, 5) + (1 << 24)) >> 25;
        $q = ($h0 + $q) >> 26;
        $q = ($h1 + $q) >> 25;
        $q = ($h2 + $q) >> 26;
        $q = ($h3 + $q) >> 25;
        $q = ($h4 + $q) >> 26;
        $q = ($h5 + $q) >> 25;
        $q = ($h6 + $q) >> 26;
        $q = ($h7 + $q) >> 25;
        $q = ($h8 + $q) >> 26;
        $q = ($h9 + $q) >> 25;

        $h0 += self::mul($q, 19, 5);

        $carry0 = $h0 >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;
        $carry1 = $h1 >> 25;
        $h2 += $carry1;
        $h1 -= $carry1 << 25;
        $carry2 = $h2 >> 26;
        $h3 += $carry2;
        $h2 -= $carry2 << 26;
        $carry3 = $h3 >> 25;
        $h4 += $carry3;
        $h3 -= $carry3 << 25;
        $carry4 = $h4 >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;
        $carry5 = $h5 >> 25;
        $h6 += $carry5;
        $h5 -= $carry5 << 25;
        $carry6 = $h6 >> 26;
        $h7 += $carry6;
        $h6 -= $carry6 << 26;
        $carry7 = $h7 >> 25;
        $h8 += $carry7;
        $h7 -= $carry7 << 25;
        $carry8 = $h8 >> 26;
        $h9 += $carry8;
        $h8 -= $carry8 << 26;
        $carry9 = $h9 >> 25;
        $h9 -= $carry9 << 25;

        /**
         * @var array<int, int>
         */
        $s = array(
            (int) (($h0 >> 0) & 0xff),
            (int) (($h0 >> 8) & 0xff),
            (int) (($h0 >> 16) & 0xff),
            (int) ((($h0 >> 24) | ($h1 << 2)) & 0xff),
            (int) (($h1 >> 6) & 0xff),
            (int) (($h1 >> 14) & 0xff),
            (int) ((($h1 >> 22) | ($h2 << 3)) & 0xff),
            (int) (($h2 >> 5) & 0xff),
            (int) (($h2 >> 13) & 0xff),
            (int) ((($h2 >> 21) | ($h3 << 5)) & 0xff),
            (int) (($h3 >> 3) & 0xff),
            (int) (($h3 >> 11) & 0xff),
            (int) ((($h3 >> 19) | ($h4 << 6)) & 0xff),
            (int) (($h4 >> 2) & 0xff),
            (int) (($h4 >> 10) & 0xff),
            (int) (($h4 >> 18) & 0xff),
            (int) (($h5 >> 0) & 0xff),
            (int) (($h5 >> 8) & 0xff),
            (int) (($h5 >> 16) & 0xff),
            (int) ((($h5 >> 24) | ($h6 << 1)) & 0xff),
            (int) (($h6 >> 7) & 0xff),
            (int) (($h6 >> 15) & 0xff),
            (int) ((($h6 >> 23) | ($h7 << 3)) & 0xff),
            (int) (($h7 >> 5) & 0xff),
            (int) (($h7 >> 13) & 0xff),
            (int) ((($h7 >> 21) | ($h8 << 4)) & 0xff),
            (int) (($h8 >> 4) & 0xff),
            (int) (($h8 >> 12) & 0xff),
            (int) ((($h8 >> 20) | ($h9 << 6)) & 0xff),
            (int) (($h9 >> 2) & 0xff),
            (int) (($h9 >> 10) & 0xff),
            (int) (($h9 >> 18) & 0xff)
        );
        return self::intArrayToString($s);
    }

    /**
     * Is a field element negative? (1 = yes, 0 = no. Used in calculations.)
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return int
     * @throws SodiumException
     * @throws TypeError
     */
    public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        $str = self::fe_tobytes($f);
        return (int) (self::chrToInt($str[0]) & 1);
    }

    /**
     * Returns 0 if this field element results in all NUL bytes.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return bool
     * @throws SodiumException
     * @throws TypeError
     */
    public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        static $zero;
        if ($zero === null) {
            $zero = str_repeat("\x00", 32);
        }
        /** @var string $zero */
        /** @var string $str */
        $str = self::fe_tobytes($f);
        return !self::verify_32($str, (string) $zero);
    }

    /**
     * Multiply two field elements
     *
     * h = f * g
     *
     * @internal You should not use this directly from another application
     *
     * @security Is multiplication a source of timing leaks? If so, can we do
     *           anything to prevent that from happening?
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_mul(
        ParagonIE_Sodium_Core_Curve25519_Fe $f,
        ParagonIE_Sodium_Core_Curve25519_Fe $g
    ) {
        // Ensure limbs aren't oversized.
        $f = self::fe_normalize($f);
        $g = self::fe_normalize($g);
        $f0 = $f[0];
        $f1 = $f[1];
        $f2 = $f[2];
        $f3 = $f[3];
        $f4 = $f[4];
        $f5 = $f[5];
        $f6 = $f[6];
        $f7 = $f[7];
        $f8 = $f[8];
        $f9 = $f[9];
        $g0 = $g[0];
        $g1 = $g[1];
        $g2 = $g[2];
        $g3 = $g[3];
        $g4 = $g[4];
        $g5 = $g[5];
        $g6 = $g[6];
        $g7 = $g[7];
        $g8 = $g[8];
        $g9 = $g[9];
        $g1_19 = self::mul($g1, 19, 5);
        $g2_19 = self::mul($g2, 19, 5);
        $g3_19 = self::mul($g3, 19, 5);
        $g4_19 = self::mul($g4, 19, 5);
        $g5_19 = self::mul($g5, 19, 5);
        $g6_19 = self::mul($g6, 19, 5);
        $g7_19 = self::mul($g7, 19, 5);
        $g8_19 = self::mul($g8, 19, 5);
        $g9_19 = self::mul($g9, 19, 5);
        $f1_2 = $f1 << 1;
        $f3_2 = $f3 << 1;
        $f5_2 = $f5 << 1;
        $f7_2 = $f7 << 1;
        $f9_2 = $f9 << 1;
        $f0g0    = self::mul($f0,    $g0, 26);
        $f0g1    = self::mul($f0,    $g1, 25);
        $f0g2    = self::mul($f0,    $g2, 26);
        $f0g3    = self::mul($f0,    $g3, 25);
        $f0g4    = self::mul($f0,    $g4, 26);
        $f0g5    = self::mul($f0,    $g5, 25);
        $f0g6    = self::mul($f0,    $g6, 26);
        $f0g7    = self::mul($f0,    $g7, 25);
        $f0g8    = self::mul($f0,    $g8, 26);
        $f0g9    = self::mul($f0,    $g9, 26);
        $f1g0    = self::mul($f1,    $g0, 26);
        $f1g1_2  = self::mul($f1_2,  $g1, 25);
        $f1g2    = self::mul($f1,    $g2, 26);
        $f1g3_2  = self::mul($f1_2,  $g3, 25);
        $f1g4    = self::mul($f1,    $g4, 26);
        $f1g5_2  = self::mul($f1_2,  $g5, 25);
        $f1g6    = self::mul($f1,    $g6, 26);
        $f1g7_2  = self::mul($f1_2,  $g7, 25);
        $f1g8    = self::mul($f1,    $g8, 26);
        $f1g9_38 = self::mul($g9_19, $f1_2, 26);
        $f2g0    = self::mul($f2,    $g0, 26);
        $f2g1    = self::mul($f2,    $g1, 25);
        $f2g2    = self::mul($f2,    $g2, 26);
        $f2g3    = self::mul($f2,    $g3, 25);
        $f2g4    = self::mul($f2,    $g4, 26);
        $f2g5    = self::mul($f2,    $g5, 25);
        $f2g6    = self::mul($f2,    $g6, 26);
        $f2g7    = self::mul($f2,    $g7, 25);
        $f2g8_19 = self::mul($g8_19, $f2, 26);
        $f2g9_19 = self::mul($g9_19, $f2, 26);
        $f3g0    = self::mul($f3,    $g0, 26);
        $f3g1_2  = self::mul($f3_2,  $g1, 25);
        $f3g2    = self::mul($f3,    $g2, 26);
        $f3g3_2  = self::mul($f3_2,  $g3, 25);
        $f3g4    = self::mul($f3,    $g4, 26);
        $f3g5_2  = self::mul($f3_2,  $g5, 25);
        $f3g6    = self::mul($f3,    $g6, 26);
        $f3g7_38 = self::mul($g7_19, $f3_2, 26);
        $f3g8_19 = self::mul($g8_19, $f3, 25);
        $f3g9_38 = self::mul($g9_19, $f3_2, 26);
        $f4g0    = self::mul($f4,    $g0, 26);
        $f4g1    = self::mul($f4,    $g1, 25);
        $f4g2    = self::mul($f4,    $g2, 26);
        $f4g3    = self::mul($f4,    $g3, 25);
        $f4g4    = self::mul($f4,    $g4, 26);
        $f4g5    = self::mul($f4,    $g5, 25);
        $f4g6_19 = self::mul($g6_19, $f4, 26);
        $f4g7_19 = self::mul($g7_19, $f4, 26);
        $f4g8_19 = self::mul($g8_19, $f4, 26);
        $f4g9_19 = self::mul($g9_19, $f4, 26);
        $f5g0    = self::mul($f5,    $g0, 26);
        $f5g1_2  = self::mul($f5_2,  $g1, 25);
        $f5g2    = self::mul($f5,    $g2, 26);
        $f5g3_2  = self::mul($f5_2,  $g3, 25);
        $f5g4    = self::mul($f5,    $g4, 26);
        $f5g5_38 = self::mul($g5_19, $f5_2, 26);
        $f5g6_19 = self::mul($g6_19, $f5, 25);
        $f5g7_38 = self::mul($g7_19, $f5_2, 26);
        $f5g8_19 = self::mul($g8_19, $f5, 25);
        $f5g9_38 = self::mul($g9_19, $f5_2, 26);
        $f6g0    = self::mul($f6,    $g0, 26);
        $f6g1    = self::mul($f6,    $g1, 25);
        $f6g2    = self::mul($f6,    $g2, 26);
        $f6g3    = self::mul($f6,    $g3, 25);
        $f6g4_19 = self::mul($g4_19, $f6, 26);
        $f6g5_19 = self::mul($g5_19, $f6, 26);
        $f6g6_19 = self::mul($g6_19, $f6, 26);
        $f6g7_19 = self::mul($g7_19, $f6, 26);
        $f6g8_19 = self::mul($g8_19, $f6, 26);
        $f6g9_19 = self::mul($g9_19, $f6, 26);
        $f7g0    = self::mul($f7,    $g0, 26);
        $f7g1_2  = self::mul($f7_2,  $g1, 25);
        $f7g2    = self::mul($f7,    $g2, 26);
        $f7g3_38 = self::mul($g3_19, $f7_2, 26);
        $f7g4_19 = self::mul($g4_19, $f7, 26);
        $f7g5_38 = self::mul($g5_19, $f7_2, 26);
        $f7g6_19 = self::mul($g6_19, $f7, 25);
        $f7g7_38 = self::mul($g7_19, $f7_2, 26);
        $f7g8_19 = self::mul($g8_19, $f7, 25);
        $f7g9_38 = self::mul($g9_19,$f7_2, 26);
        $f8g0    = self::mul($f8,    $g0, 26);
        $f8g1    = self::mul($f8,    $g1, 25);
        $f8g2_19 = self::mul($g2_19, $f8, 26);
        $f8g3_19 = self::mul($g3_19, $f8, 26);
        $f8g4_19 = self::mul($g4_19, $f8, 26);
        $f8g5_19 = self::mul($g5_19, $f8, 26);
        $f8g6_19 = self::mul($g6_19, $f8, 26);
        $f8g7_19 = self::mul($g7_19, $f8, 26);
        $f8g8_19 = self::mul($g8_19, $f8, 26);
        $f8g9_19 = self::mul($g9_19, $f8, 26);
        $f9g0    = self::mul($f9,    $g0, 26);
        $f9g1_38 = self::mul($g1_19, $f9_2, 26);
        $f9g2_19 = self::mul($g2_19, $f9, 25);
        $f9g3_38 = self::mul($g3_19, $f9_2, 26);
        $f9g4_19 = self::mul($g4_19, $f9, 25);
        $f9g5_38 = self::mul($g5_19, $f9_2, 26);
        $f9g6_19 = self::mul($g6_19, $f9, 25);
        $f9g7_38 = self::mul($g7_19, $f9_2, 26);
        $f9g8_19 = self::mul($g8_19, $f9, 25);
        $f9g9_38 = self::mul($g9_19, $f9_2, 26);

        $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38;
        $h1 = $f0g1 + $f1g0    + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19;
        $h2 = $f0g2 + $f1g1_2  + $f2g0    + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38;
        $h3 = $f0g3 + $f1g2    + $f2g1    + $f3g0    + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19;
        $h4 = $f0g4 + $f1g3_2  + $f2g2    + $f3g1_2  + $f4g0    + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38;
        $h5 = $f0g5 + $f1g4    + $f2g3    + $f3g2    + $f4g1    + $f5g0    + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19;
        $h6 = $f0g6 + $f1g5_2  + $f2g4    + $f3g3_2  + $f4g2    + $f5g1_2  + $f6g0    + $f7g9_38 + $f8g8_19 + $f9g7_38;
        $h7 = $f0g7 + $f1g6    + $f2g5    + $f3g4    + $f4g3    + $f5g2    + $f6g1    + $f7g0    + $f8g9_19 + $f9g8_19;
        $h8 = $f0g8 + $f1g7_2  + $f2g6    + $f3g5_2  + $f4g4    + $f5g3_2  + $f6g2    + $f7g1_2  + $f8g0    + $f9g9_38;
        $h9 = $f0g9 + $f1g8    + $f2g7    + $f3g6    + $f4g5    + $f5g4    + $f6g3    + $f7g2    + $f8g1    + $f9g0   ;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;
        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;

        $carry1 = ($h1 + (1 << 24)) >> 25;
        $h2 += $carry1;
        $h1 -= $carry1 << 25;
        $carry5 = ($h5 + (1 << 24)) >> 25;
        $h6 += $carry5;
        $h5 -= $carry5 << 25;

        $carry2 = ($h2 + (1 << 25)) >> 26;
        $h3 += $carry2;
        $h2 -= $carry2 << 26;
        $carry6 = ($h6 + (1 << 25)) >> 26;
        $h7 += $carry6;
        $h6 -= $carry6 << 26;

        $carry3 = ($h3 + (1 << 24)) >> 25;
        $h4 += $carry3;
        $h3 -= $carry3 << 25;
        $carry7 = ($h7 + (1 << 24)) >> 25;
        $h8 += $carry7;
        $h7 -= $carry7 << 25;

        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;
        $carry8 = ($h8 + (1 << 25)) >> 26;
        $h9 += $carry8;
        $h8 -= $carry8 << 26;

        $carry9 = ($h9 + (1 << 24)) >> 25;
        $h0 += self::mul($carry9, 19, 5);
        $h9 -= $carry9 << 25;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;

        return self::fe_normalize(
            ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
                array(
                    (int) $h0,
                    (int) $h1,
                    (int) $h2,
                    (int) $h3,
                    (int) $h4,
                    (int) $h5,
                    (int) $h6,
                    (int) $h7,
                    (int) $h8,
                    (int) $h9
                )
            )
        );
    }

    /**
     * Get the negative values for each piece of the field element.
     *
     * h = -f
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     * @psalm-suppress MixedAssignment
     */
    public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        $h = new ParagonIE_Sodium_Core_Curve25519_Fe();
        for ($i = 0; $i < 10; ++$i) {
            $h[$i] = -$f[$i];
        }
        return self::fe_normalize($h);
    }

    /**
     * Square a field element
     *
     * h = f * f
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        $f = self::fe_normalize($f);
        $f0 = (int) $f[0];
        $f1 = (int) $f[1];
        $f2 = (int) $f[2];
        $f3 = (int) $f[3];
        $f4 = (int) $f[4];
        $f5 = (int) $f[5];
        $f6 = (int) $f[6];
        $f7 = (int) $f[7];
        $f8 = (int) $f[8];
        $f9 = (int) $f[9];

        $f0_2 = $f0 << 1;
        $f1_2 = $f1 << 1;
        $f2_2 = $f2 << 1;
        $f3_2 = $f3 << 1;
        $f4_2 = $f4 << 1;
        $f5_2 = $f5 << 1;
        $f6_2 = $f6 << 1;
        $f7_2 = $f7 << 1;
        $f5_38 = self::mul($f5, 38, 6);
        $f6_19 = self::mul($f6, 19, 5);
        $f7_38 = self::mul($f7, 38, 6);
        $f8_19 = self::mul($f8, 19, 5);
        $f9_38 = self::mul($f9, 38, 6);
        $f0f0    = self::mul($f0,    $f0,    26);
        $f0f1_2  = self::mul($f0_2,  $f1,    26);
        $f0f2_2  = self::mul($f0_2,  $f2,    26);
        $f0f3_2  = self::mul($f0_2,  $f3,    26);
        $f0f4_2  = self::mul($f0_2,  $f4,    26);
        $f0f5_2  = self::mul($f0_2,  $f5,    26);
        $f0f6_2  = self::mul($f0_2,  $f6,    26);
        $f0f7_2  = self::mul($f0_2,  $f7,    26);
        $f0f8_2  = self::mul($f0_2,  $f8,    26);
        $f0f9_2  = self::mul($f0_2,  $f9,    26);
        $f1f1_2  = self::mul($f1_2,  $f1,    26);
        $f1f2_2  = self::mul($f1_2,  $f2,    26);
        $f1f3_4  = self::mul($f1_2,  $f3_2,  26);
        $f1f4_2  = self::mul($f1_2,  $f4,    26);
        $f1f5_4  = self::mul($f1_2,  $f5_2,  26);
        $f1f6_2  = self::mul($f1_2,  $f6,    26);
        $f1f7_4  = self::mul($f1_2,  $f7_2,  26);
        $f1f8_2  = self::mul($f1_2,  $f8,    26);
        $f1f9_76 = self::mul($f9_38, $f1_2,  27);
        $f2f2    = self::mul($f2,    $f2,    27);
        $f2f3_2  = self::mul($f2_2,  $f3,    27);
        $f2f4_2  = self::mul($f2_2,  $f4,    27);
        $f2f5_2  = self::mul($f2_2,  $f5,    27);
        $f2f6_2  = self::mul($f2_2,  $f6,    27);
        $f2f7_2  = self::mul($f2_2,  $f7,    27);
        $f2f8_38 = self::mul($f8_19, $f2_2,  27);
        $f2f9_38 = self::mul($f9_38, $f2,    26);
        $f3f3_2  = self::mul($f3_2,  $f3,    26);
        $f3f4_2  = self::mul($f3_2,  $f4,    26);
        $f3f5_4  = self::mul($f3_2,  $f5_2,  26);
        $f3f6_2  = self::mul($f3_2,  $f6,    26);
        $f3f7_76 = self::mul($f7_38, $f3_2,  26);
        $f3f8_38 = self::mul($f8_19, $f3_2,  26);
        $f3f9_76 = self::mul($f9_38, $f3_2,  26);
        $f4f4    = self::mul($f4,    $f4,    26);
        $f4f5_2  = self::mul($f4_2,  $f5,    26);
        $f4f6_38 = self::mul($f6_19, $f4_2,  27);
        $f4f7_38 = self::mul($f7_38, $f4,    26);
        $f4f8_38 = self::mul($f8_19, $f4_2,  27);
        $f4f9_38 = self::mul($f9_38, $f4,    26);
        $f5f5_38 = self::mul($f5_38, $f5,    26);
        $f5f6_38 = self::mul($f6_19, $f5_2,  26);
        $f5f7_76 = self::mul($f7_38, $f5_2,  26);
        $f5f8_38 = self::mul($f8_19, $f5_2,  26);
        $f5f9_76 = self::mul($f9_38, $f5_2,  26);
        $f6f6_19 = self::mul($f6_19, $f6,    26);
        $f6f7_38 = self::mul($f7_38, $f6,    26);
        $f6f8_38 = self::mul($f8_19, $f6_2,  27);
        $f6f9_38 = self::mul($f9_38, $f6,    26);
        $f7f7_38 = self::mul($f7_38, $f7,    26);
        $f7f8_38 = self::mul($f8_19, $f7_2,  26);
        $f7f9_76 = self::mul($f9_38, $f7_2,  26);
        $f8f8_19 = self::mul($f8_19, $f8,    26);
        $f8f9_38 = self::mul($f9_38, $f8,    26);
        $f9f9_38 = self::mul($f9_38, $f9,    26);
        $h0 = $f0f0   + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38;
        $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38;
        $h2 = $f0f2_2 + $f1f1_2  + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19;
        $h3 = $f0f3_2 + $f1f2_2  + $f4f9_38 + $f5f8_38 + $f6f7_38;
        $h4 = $f0f4_2 + $f1f3_4  + $f2f2    + $f5f9_76 + $f6f8_38 + $f7f7_38;
        $h5 = $f0f5_2 + $f1f4_2  + $f2f3_2  + $f6f9_38 + $f7f8_38;
        $h6 = $f0f6_2 + $f1f5_4  + $f2f4_2  + $f3f3_2  + $f7f9_76 + $f8f8_19;
        $h7 = $f0f7_2 + $f1f6_2  + $f2f5_2  + $f3f4_2  + $f8f9_38;
        $h8 = $f0f8_2 + $f1f7_4  + $f2f6_2  + $f3f5_4  + $f4f4    + $f9f9_38;
        $h9 = $f0f9_2 + $f1f8_2  + $f2f7_2  + $f3f6_2  + $f4f5_2;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;
        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;

        $carry1 = ($h1 + (1 << 24)) >> 25;
        $h2 += $carry1;
        $h1 -= $carry1 << 25;
        $carry5 = ($h5 + (1 << 24)) >> 25;
        $h6 += $carry5;
        $h5 -= $carry5 << 25;

        $carry2 = ($h2 + (1 << 25)) >> 26;
        $h3 += $carry2;
        $h2 -= $carry2 << 26;
        $carry6 = ($h6 + (1 << 25)) >> 26;
        $h7 += $carry6;
        $h6 -= $carry6 << 26;

        $carry3 = ($h3 + (1 << 24)) >> 25;
        $h4 += $carry3;
        $h3 -= $carry3 << 25;
        $carry7 = ($h7 + (1 << 24)) >> 25;
        $h8 += $carry7;
        $h7 -= $carry7 << 25;

        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;
        $carry8 = ($h8 + (1 << 25)) >> 26;
        $h9 += $carry8;
        $h8 -= $carry8 << 26;

        $carry9 = ($h9 + (1 << 24)) >> 25;
        $h0 += self::mul($carry9, 19, 5);
        $h9 -= $carry9 << 25;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;

        return self::fe_normalize(
            ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
                array(
                    (int) $h0,
                    (int) $h1,
                    (int) $h2,
                    (int) $h3,
                    (int) $h4,
                    (int) $h5,
                    (int) $h6,
                    (int) $h7,
                    (int) $h8,
                    (int) $h9
                )
            )
        );
    }


    /**
     * Square and double a field element
     *
     * h = 2 * f * f
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        $f = self::fe_normalize($f);
        $f0 = (int) $f[0];
        $f1 = (int) $f[1];
        $f2 = (int) $f[2];
        $f3 = (int) $f[3];
        $f4 = (int) $f[4];
        $f5 = (int) $f[5];
        $f6 = (int) $f[6];
        $f7 = (int) $f[7];
        $f8 = (int) $f[8];
        $f9 = (int) $f[9];

        $f0_2 = $f0 << 1;
        $f1_2 = $f1 << 1;
        $f2_2 = $f2 << 1;
        $f3_2 = $f3 << 1;
        $f4_2 = $f4 << 1;
        $f5_2 = $f5 << 1;
        $f6_2 = $f6 << 1;
        $f7_2 = $f7 << 1;
        $f5_38 = self::mul($f5, 38, 6); /* 1.959375*2^30 */
        $f6_19 = self::mul($f6, 19, 5); /* 1.959375*2^30 */
        $f7_38 = self::mul($f7, 38, 6); /* 1.959375*2^30 */
        $f8_19 = self::mul($f8, 19, 5); /* 1.959375*2^30 */
        $f9_38 = self::mul($f9, 38, 6); /* 1.959375*2^30 */
        $f0f0 = self::mul($f0, $f0, 24);
        $f0f1_2 = self::mul($f0_2, $f1, 24);
        $f0f2_2 = self::mul($f0_2, $f2, 24);
        $f0f3_2 = self::mul($f0_2, $f3, 24);
        $f0f4_2 = self::mul($f0_2, $f4, 24);
        $f0f5_2 = self::mul($f0_2, $f5, 24);
        $f0f6_2 = self::mul($f0_2, $f6, 24);
        $f0f7_2 = self::mul($f0_2, $f7, 24);
        $f0f8_2 = self::mul($f0_2, $f8, 24);
        $f0f9_2 = self::mul($f0_2, $f9, 24);
        $f1f1_2 = self::mul($f1_2,  $f1, 24);
        $f1f2_2 = self::mul($f1_2,  $f2, 24);
        $f1f3_4 = self::mul($f1_2,  $f3_2, 24);
        $f1f4_2 = self::mul($f1_2,  $f4, 24);
        $f1f5_4 = self::mul($f1_2,  $f5_2, 24);
        $f1f6_2 = self::mul($f1_2,  $f6, 24);
        $f1f7_4 = self::mul($f1_2,  $f7_2, 24);
        $f1f8_2 = self::mul($f1_2,  $f8, 24);
        $f1f9_76 = self::mul($f9_38, $f1_2, 24);
        $f2f2 = self::mul($f2,  $f2, 24);
        $f2f3_2 = self::mul($f2_2,  $f3, 24);
        $f2f4_2 = self::mul($f2_2,  $f4, 24);
        $f2f5_2 = self::mul($f2_2,  $f5, 24);
        $f2f6_2 = self::mul($f2_2,  $f6, 24);
        $f2f7_2 = self::mul($f2_2,  $f7, 24);
        $f2f8_38 = self::mul($f8_19, $f2_2, 25);
        $f2f9_38 = self::mul($f9_38, $f2, 24);
        $f3f3_2 = self::mul($f3_2,  $f3, 24);
        $f3f4_2 = self::mul($f3_2,  $f4, 24);
        $f3f5_4 = self::mul($f3_2,  $f5_2, 24);
        $f3f6_2 = self::mul($f3_2,  $f6, 24);
        $f3f7_76 = self::mul($f7_38, $f3_2, 24);
        $f3f8_38 = self::mul($f8_19, $f3_2, 24);
        $f3f9_76 = self::mul($f9_38, $f3_2, 24);
        $f4f4 = self::mul($f4,  $f4, 24);
        $f4f5_2 = self::mul($f4_2,  $f5, 24);
        $f4f6_38 = self::mul($f6_19, $f4_2, 25);
        $f4f7_38 = self::mul($f7_38, $f4, 24);
        $f4f8_38 = self::mul($f8_19, $f4_2, 25);
        $f4f9_38 = self::mul($f9_38, $f4, 24);
        $f5f5_38 = self::mul($f5_38, $f5, 24);
        $f5f6_38 = self::mul($f6_19, $f5_2, 24);
        $f5f7_76 = self::mul($f7_38, $f5_2, 24);
        $f5f8_38 = self::mul($f8_19, $f5_2, 24);
        $f5f9_76 = self::mul($f9_38, $f5_2, 24);
        $f6f6_19 = self::mul($f6_19, $f6, 24);
        $f6f7_38 = self::mul($f7_38, $f6, 24);
        $f6f8_38 = self::mul($f8_19, $f6_2, 25);
        $f6f9_38 = self::mul($f9_38, $f6, 24);
        $f7f7_38 = self::mul($f7_38, $f7, 24);
        $f7f8_38 = self::mul($f8_19, $f7_2, 24);
        $f7f9_76 = self::mul($f9_38, $f7_2, 24);
        $f8f8_19 = self::mul($f8_19, $f8, 24);
        $f8f9_38 = self::mul($f9_38, $f8, 24);
        $f9f9_38 = self::mul($f9_38, $f9, 24);

        $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38) << 1;
        $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38) << 1;
        $h2 = (int) ($f0f2_2 + $f1f1_2  + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19) << 1;
        $h3 = (int) ($f0f3_2 + $f1f2_2  + $f4f9_38 + $f5f8_38 + $f6f7_38) << 1;
        $h4 = (int) ($f0f4_2 + $f1f3_4  + $f2f2    + $f5f9_76 + $f6f8_38 + $f7f7_38) << 1;
        $h5 = (int) ($f0f5_2 + $f1f4_2  + $f2f3_2  + $f6f9_38 + $f7f8_38) << 1;
        $h6 = (int) ($f0f6_2 + $f1f5_4  + $f2f4_2  + $f3f3_2  + $f7f9_76 + $f8f8_19) << 1;
        $h7 = (int) ($f0f7_2 + $f1f6_2  + $f2f5_2  + $f3f4_2  + $f8f9_38) << 1;
        $h8 = (int) ($f0f8_2 + $f1f7_4  + $f2f6_2  + $f3f5_4  + $f4f4    + $f9f9_38) << 1;
        $h9 = (int) ($f0f9_2 + $f1f8_2  + $f2f7_2  + $f3f6_2  + $f4f5_2) << 1;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;
        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;

        $carry1 = ($h1 + (1 << 24)) >> 25;
        $h2 += $carry1;
        $h1 -= $carry1 << 25;
        $carry5 = ($h5 + (1 << 24)) >> 25;
        $h6 += $carry5;
        $h5 -= $carry5 << 25;

        $carry2 = ($h2 + (1 << 25)) >> 26;
        $h3 += $carry2;
        $h2 -= $carry2 << 26;
        $carry6 = ($h6 + (1 << 25)) >> 26;
        $h7 += $carry6;
        $h6 -= $carry6 << 26;

        $carry3 = ($h3 + (1 << 24)) >> 25;
        $h4 += $carry3;
        $h3 -= $carry3 << 25;
        $carry7 = ($h7 + (1 << 24)) >> 25;
        $h8 += $carry7;
        $h7 -= $carry7 << 25;

        $carry4 = ($h4 + (1 << 25)) >> 26;
        $h5 += $carry4;
        $h4 -= $carry4 << 26;
        $carry8 = ($h8 + (1 << 25)) >> 26;
        $h9 += $carry8;
        $h8 -= $carry8 << 26;

        $carry9 = ($h9 + (1 << 24)) >> 25;
        $h0 += self::mul($carry9, 19, 5);
        $h9 -= $carry9 << 25;

        $carry0 = ($h0 + (1 << 25)) >> 26;
        $h1 += $carry0;
        $h0 -= $carry0 << 26;

        return self::fe_normalize(
            ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
                array(
                    (int) $h0,
                    (int) $h1,
                    (int) $h2,
                    (int) $h3,
                    (int) $h4,
                    (int) $h5,
                    (int) $h6,
                    (int) $h7,
                    (int) $h8,
                    (int) $h9
                )
            )
        );
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z)
    {
        $z = clone $Z;
        $t0 = self::fe_sq($z);
        $t1 = self::fe_sq($t0);
        $t1 = self::fe_sq($t1);
        $t1 = self::fe_mul($z, $t1);
        $t0 = self::fe_mul($t0, $t1);
        $t2 = self::fe_sq($t0);
        $t1 = self::fe_mul($t1, $t2);
        $t2 = self::fe_sq($t1);
        for ($i = 1; $i < 5; ++$i) {
            $t2 = self::fe_sq($t2);
        }
        $t1 = self::fe_mul($t2, $t1);
        $t2 = self::fe_sq($t1);
        for ($i = 1; $i < 10; ++$i) {
            $t2 = self::fe_sq($t2);
        }
        $t2 = self::fe_mul($t2, $t1);
        $t3 = self::fe_sq($t2);
        for ($i = 1; $i < 20; ++$i) {
            $t3 = self::fe_sq($t3);
        }
        $t2 = self::fe_mul($t3, $t2);
        $t2 = self::fe_sq($t2);
        for ($i = 1; $i < 10; ++$i) {
            $t2 = self::fe_sq($t2);
        }
        $t1 = self::fe_mul($t2, $t1);
        $t2 = self::fe_sq($t1);
        for ($i = 1; $i < 50; ++$i) {
            $t2 = self::fe_sq($t2);
        }
        $t2 = self::fe_mul($t2, $t1);
        $t3 = self::fe_sq($t2);
        for ($i = 1; $i < 100; ++$i) {
            $t3 = self::fe_sq($t3);
        }
        $t2 = self::fe_mul($t3, $t2);
        $t2 = self::fe_sq($t2);
        for ($i = 1; $i < 50; ++$i) {
            $t2 = self::fe_sq($t2);
        }
        $t1 = self::fe_mul($t2, $t1);
        $t1 = self::fe_sq($t1);
        for ($i = 1; $i < 5; ++$i) {
            $t1 = self::fe_sq($t1);
        }
        return self::fe_mul($t1, $t0);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $z
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z)
    {
        $z = self::fe_normalize($z);
        # fe_sq(t0, z);
        # fe_sq(t1, t0);
        # fe_sq(t1, t1);
        # fe_mul(t1, z, t1);
        # fe_mul(t0, t0, t1);
        # fe_sq(t0, t0);
        # fe_mul(t0, t1, t0);
        # fe_sq(t1, t0);
        $t0 = self::fe_sq($z);
        $t1 = self::fe_sq($t0);
        $t1 = self::fe_sq($t1);
        $t1 = self::fe_mul($z, $t1);
        $t0 = self::fe_mul($t0, $t1);
        $t0 = self::fe_sq($t0);
        $t0 = self::fe_mul($t1, $t0);
        $t1 = self::fe_sq($t0);

        # for (i = 1; i < 5; ++i) {
        #     fe_sq(t1, t1);
        # }
        for ($i = 1; $i < 5; ++$i) {
            $t1 = self::fe_sq($t1);
        }

        # fe_mul(t0, t1, t0);
        # fe_sq(t1, t0);
        $t0 = self::fe_mul($t1, $t0);
        $t1 = self::fe_sq($t0);

        # for (i = 1; i < 10; ++i) {
        #     fe_sq(t1, t1);
        # }
        for ($i = 1; $i < 10; ++$i) {
            $t1 = self::fe_sq($t1);
        }

        # fe_mul(t1, t1, t0);
        # fe_sq(t2, t1);
        $t1 = self::fe_mul($t1, $t0);
        $t2 = self::fe_sq($t1);

        # for (i = 1; i < 20; ++i) {
        #     fe_sq(t2, t2);
        # }
        for ($i = 1; $i < 20; ++$i) {
            $t2 = self::fe_sq($t2);
        }

        # fe_mul(t1, t2, t1);
        # fe_sq(t1, t1);
        $t1 = self::fe_mul($t2, $t1);
        $t1 = self::fe_sq($t1);

        # for (i = 1; i < 10; ++i) {
        #     fe_sq(t1, t1);
        # }
        for ($i = 1; $i < 10; ++$i) {
            $t1 = self::fe_sq($t1);
        }

        # fe_mul(t0, t1, t0);
        # fe_sq(t1, t0);
        $t0 = self::fe_mul($t1, $t0);
        $t1 = self::fe_sq($t0);

        # for (i = 1; i < 50; ++i) {
        #     fe_sq(t1, t1);
        # }
        for ($i = 1; $i < 50; ++$i) {
            $t1 = self::fe_sq($t1);
        }

        # fe_mul(t1, t1, t0);
        # fe_sq(t2, t1);
        $t1 = self::fe_mul($t1, $t0);
        $t2 = self::fe_sq($t1);

        # for (i = 1; i < 100; ++i) {
        #     fe_sq(t2, t2);
        # }
        for ($i = 1; $i < 100; ++$i) {
            $t2 = self::fe_sq($t2);
        }

        # fe_mul(t1, t2, t1);
        # fe_sq(t1, t1);
        $t1 = self::fe_mul($t2, $t1);
        $t1 = self::fe_sq($t1);

        # for (i = 1; i < 50; ++i) {
        #     fe_sq(t1, t1);
        # }
        for ($i = 1; $i < 50; ++$i) {
            $t1 = self::fe_sq($t1);
        }

        # fe_mul(t0, t1, t0);
        # fe_sq(t0, t0);
        # fe_sq(t0, t0);
        # fe_mul(out, t0, z);
        $t0 = self::fe_mul($t1, $t0);
        $t0 = self::fe_sq($t0);
        $t0 = self::fe_sq($t0);
        return self::fe_mul($t0, $z);
    }

    /**
     * Subtract two field elements.
     *
     * h = f - g
     *
     * Preconditions:
     * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
     * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
     *
     * Postconditions:
     * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $g
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     * @psalm-suppress MixedOperand
     */
    public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g)
    {
        return self::fe_normalize(
            ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(
                array(
                    (int) ($f[0] - $g[0]),
                    (int) ($f[1] - $g[1]),
                    (int) ($f[2] - $g[2]),
                    (int) ($f[3] - $g[3]),
                    (int) ($f[4] - $g[4]),
                    (int) ($f[5] - $g[5]),
                    (int) ($f[6] - $g[6]),
                    (int) ($f[7] - $g[7]),
                    (int) ($f[8] - $g[8]),
                    (int) ($f[9] - $g[9])
                )
            )
        );
    }

    /**
     * Add two group elements.
     *
     * r = p + q
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
     */
    public static function ge_add(
        ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
        ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
    ) {
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();
        $r->X = self::fe_add($p->Y, $p->X);
        $r->Y = self::fe_sub($p->Y, $p->X);
        $r->Z = self::fe_mul($r->X, $q->YplusX);
        $r->Y = self::fe_mul($r->Y, $q->YminusX);
        $r->T = self::fe_mul($q->T2d, $p->T);
        $r->X = self::fe_mul($p->Z, $q->Z);
        $t0   = self::fe_add($r->X, $r->X);
        $r->X = self::fe_sub($r->Z, $r->Y);
        $r->Y = self::fe_add($r->Z, $r->Y);
        $r->Z = self::fe_add($t0, $r->T);
        $r->T = self::fe_sub($t0, $r->T);
        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215
     * @param string $a
     * @return array<int, mixed>
     * @throws SodiumException
     * @throws TypeError
     */
    public static function slide($a)
    {
        if (self::strlen($a) < 256) {
            if (self::strlen($a) < 16) {
                $a = str_pad($a, 256, '0', STR_PAD_RIGHT);
            }
        }
        /** @var array<int, int> $r */
        $r = array();

        /** @var int $i */
        for ($i = 0; $i < 256; ++$i) {
            $r[$i] = (int) (
                1 & (
                    self::chrToInt($a[(int) ($i >> 3)])
                        >>
                    ($i & 7)
                )
            );
        }

        for ($i = 0;$i < 256;++$i) {
            if ($r[$i]) {
                for ($b = 1;$b <= 6 && $i + $b < 256;++$b) {
                    if ($r[$i + $b]) {
                        if ($r[$i] + ($r[$i + $b] << $b) <= 15) {
                            $r[$i] += $r[$i + $b] << $b;
                            $r[$i + $b] = 0;
                        } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) {
                            $r[$i] -= $r[$i + $b] << $b;
                            for ($k = $i + $b; $k < 256; ++$k) {
                                if (!$r[$k]) {
                                    $r[$k] = 1;
                                    break;
                                }
                                $r[$k] = 0;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
        }
        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param string $s
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     * @throws SodiumException
     * @throws TypeError
     */
    public static function ge_frombytes_negate_vartime($s)
    {
        static $d = null;
        if (!$d) {
            $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
        }

        # fe_frombytes(h->Y,s);
        # fe_1(h->Z);
        $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
            self::fe_0(),
            self::fe_frombytes($s),
            self::fe_1()
        );

        # fe_sq(u,h->Y);
        # fe_mul(v,u,d);
        # fe_sub(u,u,h->Z);       /* u = y^2-1 */
        # fe_add(v,v,h->Z);       /* v = dy^2+1 */
        $u = self::fe_sq($h->Y);
        /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d */
        $v = self::fe_mul($u, $d);
        $u = self::fe_sub($u, $h->Z); /* u =  y^2 - 1 */
        $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */

        # fe_sq(v3,v);
        # fe_mul(v3,v3,v);        /* v3 = v^3 */
        # fe_sq(h->X,v3);
        # fe_mul(h->X,h->X,v);
        # fe_mul(h->X,h->X,u);    /* x = uv^7 */
        $v3 = self::fe_sq($v);
        $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */
        $h->X = self::fe_sq($v3);
        $h->X = self::fe_mul($h->X, $v);
        $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */

        # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */
        # fe_mul(h->X,h->X,v3);
        # fe_mul(h->X,h->X,u);    /* x = uv^3(uv^7)^((q-5)/8) */
        $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */
        $h->X = self::fe_mul($h->X, $v3);
        $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */

        # fe_sq(vxx,h->X);
        # fe_mul(vxx,vxx,v);
        # fe_sub(check,vxx,u);    /* vx^2-u */
        $vxx = self::fe_sq($h->X);
        $vxx = self::fe_mul($vxx, $v);
        $check = self::fe_sub($vxx, $u); /* vx^2 - u */

        # if (fe_isnonzero(check)) {
        #     fe_add(check,vxx,u);  /* vx^2+u */
        #     if (fe_isnonzero(check)) {
        #         return -1;
        #     }
        #     fe_mul(h->X,h->X,sqrtm1);
        # }
        if (self::fe_isnonzero($check)) {
            $check = self::fe_add($vxx, $u); /* vx^2 + u */
            if (self::fe_isnonzero($check)) {
                throw new RangeException('Internal check failed.');
            }
            $h->X = self::fe_mul(
                $h->X,
                ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1)
            );
        }

        # if (fe_isnegative(h->X) == (s[31] >> 7)) {
        #     fe_neg(h->X,h->X);
        # }
        $i = self::chrToInt($s[31]);
        if (self::fe_isnegative($h->X) === ($i >> 7)) {
            $h->X = self::fe_neg($h->X);
        }

        # fe_mul(h->T,h->X,h->Y);
        $h->T = self::fe_mul($h->X, $h->Y);
        return $h;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
     */
    public static function ge_madd(
        ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
        ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
        ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
    ) {
        $r = clone $R;
        $r->X = self::fe_add($p->Y, $p->X);
        $r->Y = self::fe_sub($p->Y, $p->X);
        $r->Z = self::fe_mul($r->X, $q->yplusx);
        $r->Y = self::fe_mul($r->Y, $q->yminusx);
        $r->T = self::fe_mul($q->xy2d, $p->T);
        $t0 = self::fe_add(clone $p->Z, clone $p->Z);
        $r->X = self::fe_sub($r->Z, $r->Y);
        $r->Y = self::fe_add($r->Z, $r->Y);
        $r->Z = self::fe_add($t0, $r->T);
        $r->T = self::fe_sub($t0, $r->T);

        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
     */
    public static function ge_msub(
        ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R,
        ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
        ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q
    ) {
        $r = clone $R;

        $r->X = self::fe_add($p->Y, $p->X);
        $r->Y = self::fe_sub($p->Y, $p->X);
        $r->Z = self::fe_mul($r->X, $q->yminusx);
        $r->Y = self::fe_mul($r->Y, $q->yplusx);
        $r->T = self::fe_mul($q->xy2d, $p->T);
        $t0 = self::fe_add($p->Z, $p->Z);
        $r->X = self::fe_sub($r->Z, $r->Y);
        $r->Y = self::fe_add($r->Z, $r->Y);
        $r->Z = self::fe_sub($t0, $r->T);
        $r->T = self::fe_add($t0, $r->T);

        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
     */
    public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
    {
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2();
        $r->X = self::fe_mul($p->X, $p->T);
        $r->Y = self::fe_mul($p->Y, $p->Z);
        $r->Z = self::fe_mul($p->Z, $p->T);
        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     */
    public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p)
    {
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
        $r->X = self::fe_mul($p->X, $p->T);
        $r->Y = self::fe_mul($p->Y, $p->Z);
        $r->Z = self::fe_mul($p->Z, $p->T);
        $r->T = self::fe_mul($p->X, $p->Y);
        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
     */
    public static function ge_p2_0()
    {
        return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
            self::fe_0(),
            self::fe_1(),
            self::fe_1()
        );
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
     */
    public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p)
    {
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();

        $r->X = self::fe_sq($p->X);
        $r->Z = self::fe_sq($p->Y);
        $r->T = self::fe_sq2($p->Z);
        $r->Y = self::fe_add($p->X, $p->Y);
        $t0   = self::fe_sq($r->Y);
        $r->Y = self::fe_add($r->Z, $r->X);
        $r->Z = self::fe_sub($r->Z, $r->X);
        $r->X = self::fe_sub($t0, $r->Y);
        $r->T = self::fe_sub($r->T, $r->Z);

        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     */
    public static function ge_p3_0()
    {
        return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
            self::fe_0(),
            self::fe_1(),
            self::fe_1(),
            self::fe_0()
        );
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
     */
    public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
    {
        static $d2 = null;
        if ($d2 === null) {
            $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2);
        }
        /** @var ParagonIE_Sodium_Core_Curve25519_Fe $d2 */
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
        $r->YplusX = self::fe_add($p->Y, $p->X);
        $r->YminusX = self::fe_sub($p->Y, $p->X);
        $r->Z = self::fe_copy($p->Z);
        $r->T2d = self::fe_mul($p->T, $d2);
        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
     */
    public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
    {
        return new ParagonIE_Sodium_Core_Curve25519_Ge_P2(
            self::fe_copy($p->X),
            self::fe_copy($p->Y),
            self::fe_copy($p->Z)
        );
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
     * @return string
     * @throws SodiumException
     * @throws TypeError
     */
    public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
    {
        $recip = self::fe_invert($h->Z);
        $x = self::fe_mul($h->X, $recip);
        $y = self::fe_mul($h->Y, $recip);
        $s = self::fe_tobytes($y);
        $s[31] = self::intToChr(
            self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
        );
        return $s;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
     */
    public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p)
    {
        $q = self::ge_p3_to_p2($p);
        return self::ge_p2_dbl($q);
    }

    /**
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
     */
    public static function ge_precomp_0()
    {
        return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
            self::fe_1(),
            self::fe_1(),
            self::fe_0()
        );
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param int $b
     * @param int $c
     * @return int
     */
    public static function equal($b, $c)
    {
        return (int) ((($b ^ $c) - 1) >> 31) & 1;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param int|string $char
     * @return int (1 = yes, 0 = no)
     * @throws SodiumException
     * @throws TypeError
     */
    public static function negative($char)
    {
        if (is_int($char)) {
            return ($char >> 63) & 1;
        }
        $x = self::chrToInt(self::substr($char, 0, 1));
        return (int) ($x >> 63);
    }

    /**
     * Conditional move
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u
     * @param int $b
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
     */
    public static function cmov(
        ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t,
        ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u,
        $b
    ) {
        if (!is_int($b)) {
            throw new InvalidArgumentException('Expected an integer.');
        }
        return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
            self::fe_cmov($t->yplusx,  $u->yplusx,  $b),
            self::fe_cmov($t->yminusx, $u->yminusx, $b),
            self::fe_cmov($t->xy2d,    $u->xy2d,    $b)
        );
    }

    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u
     * @param int $b
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
     */
    public static function ge_cmov_cached(
        ParagonIE_Sodium_Core_Curve25519_Ge_Cached $t,
        ParagonIE_Sodium_Core_Curve25519_Ge_Cached $u,
        $b
    ) {
        $b &= 1;
        $ret = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached();
        $ret->YplusX  = self::fe_cmov($t->YplusX,  $u->YplusX,  $b);
        $ret->YminusX = self::fe_cmov($t->YminusX, $u->YminusX, $b);
        $ret->Z       = self::fe_cmov($t->Z,       $u->Z,       $b);
        $ret->T2d     = self::fe_cmov($t->T2d,     $u->T2d,     $b);
        return $ret;
    }

    /**
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $cached
     * @param int $b
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached
     * @throws SodiumException
     */
    public static function ge_cmov8_cached(array $cached, $b)
    {
        // const unsigned char bnegative = negative(b);
        // const unsigned char babs      = b - (((-bnegative) & b) * ((signed char) 1 << 1));
        $bnegative = self::negative($b);
        $babs = $b - (((-$bnegative) & $b) << 1);

        // ge25519_cached_0(t);
        $t = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
            self::fe_1(),
            self::fe_1(),
            self::fe_1(),
            self::fe_0()
        );

        // ge25519_cmov_cached(t, &cached[0], equal(babs, 1));
        // ge25519_cmov_cached(t, &cached[1], equal(babs, 2));
        // ge25519_cmov_cached(t, &cached[2], equal(babs, 3));
        // ge25519_cmov_cached(t, &cached[3], equal(babs, 4));
        // ge25519_cmov_cached(t, &cached[4], equal(babs, 5));
        // ge25519_cmov_cached(t, &cached[5], equal(babs, 6));
        // ge25519_cmov_cached(t, &cached[6], equal(babs, 7));
        // ge25519_cmov_cached(t, &cached[7], equal(babs, 8));
        for ($x = 0; $x < 8; ++$x) {
            $t = self::ge_cmov_cached($t, $cached[$x], self::equal($babs, $x + 1));
        }

        // fe25519_copy(minust.YplusX, t->YminusX);
        // fe25519_copy(minust.YminusX, t->YplusX);
        // fe25519_copy(minust.Z, t->Z);
        // fe25519_neg(minust.T2d, t->T2d);
        $minust = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
            self::fe_copy($t->YminusX),
            self::fe_copy($t->YplusX),
            self::fe_copy($t->Z),
            self::fe_neg($t->T2d)
        );
        return self::ge_cmov_cached($t, $minust, $bnegative);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param int $pos
     * @param int $b
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp
     * @throws SodiumException
     * @throws TypeError
     * @psalm-suppress MixedArgument
     * @psalm-suppress MixedArrayAccess
     * @psalm-suppress MixedArrayOffset
     */
    public static function ge_select($pos = 0, $b = 0)
    {
        static $base = null;
        if ($base === null) {
            $base = array();
            /** @var int $i */
            foreach (self::$base as $i => $bas) {
                for ($j = 0; $j < 8; ++$j) {
                    $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
                        ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]),
                        ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]),
                        ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2])
                    );
                }
            }
        }
        /** @var array<int, array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp>> $base */
        if (!is_int($pos)) {
            throw new InvalidArgumentException('Position must be an integer');
        }
        if ($pos < 0 || $pos > 31) {
            throw new RangeException('Position is out of range [0, 31]');
        }

        $bnegative = self::negative($b);
        $babs = $b - (((-$bnegative) & $b) << 1);

        $t = self::ge_precomp_0();
        for ($i = 0; $i < 8; ++$i) {
            $t = self::cmov(
                $t,
                $base[$pos][$i],
                self::equal($babs, $i + 1)
            );
        }
        $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
            self::fe_copy($t->yminusx),
            self::fe_copy($t->yplusx),
            self::fe_neg($t->xy2d)
        );
        return self::cmov($t, $minusT, $bnegative);
    }

    /**
     * Subtract two group elements.
     *
     * r = p - q
     *
     * @internal You should not use this directly from another application
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1
     */
    public static function ge_sub(
        ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p,
        ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q
    ) {
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();

        $r->X = self::fe_add($p->Y, $p->X);
        $r->Y = self::fe_sub($p->Y, $p->X);
        $r->Z = self::fe_mul($r->X, $q->YminusX);
        $r->Y = self::fe_mul($r->Y, $q->YplusX);
        $r->T = self::fe_mul($q->T2d, $p->T);
        $r->X = self::fe_mul($p->Z, $q->Z);
        $t0 = self::fe_add($r->X, $r->X);
        $r->X = self::fe_sub($r->Z, $r->Y);
        $r->Y = self::fe_add($r->Z, $r->Y);
        $r->Z = self::fe_sub($t0, $r->T);
        $r->T = self::fe_add($t0, $r->T);

        return $r;
    }

    /**
     * Convert a group element to a byte string.
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h
     * @return string
     * @throws SodiumException
     * @throws TypeError
     */
    public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h)
    {
        $recip = self::fe_invert($h->Z);
        $x = self::fe_mul($h->X, $recip);
        $y = self::fe_mul($h->Y, $recip);
        $s = self::fe_tobytes($y);
        $s[31] = self::intToChr(
            self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7)
        );
        return $s;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param string $a
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
     * @param string $b
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2
     * @throws SodiumException
     * @throws TypeError
     * @psalm-suppress MixedArgument
     * @psalm-suppress MixedArrayAccess
     */
    public static function ge_double_scalarmult_vartime(
        $a,
        ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A,
        $b
    ) {
        /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai */
        $Ai = array();

        /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Precomp> $Bi */
        static $Bi = array();
        if (!$Bi) {
            for ($i = 0; $i < 8; ++$i) {
                $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp(
                    ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]),
                    ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]),
                    ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2])
                );
            }
        }
        for ($i = 0; $i < 8; ++$i) {
            $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(
                self::fe_0(),
                self::fe_0(),
                self::fe_0(),
                self::fe_0()
            );
        }

        # slide(aslide,a);
        # slide(bslide,b);
        /** @var array<int, int> $aslide */
        $aslide = self::slide($a);
        /** @var array<int, int> $bslide */
        $bslide = self::slide($b);

        # ge_p3_to_cached(&Ai[0],A);
        # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t);
        $Ai[0] = self::ge_p3_to_cached($A);
        $t = self::ge_p3_dbl($A);
        $A2 = self::ge_p1p1_to_p3($t);

        # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u);
        # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u);
        # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u);
        # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u);
        # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u);
        # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u);
        # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u);
        for ($i = 0; $i < 7; ++$i) {
            $t = self::ge_add($A2, $Ai[$i]);
            $u = self::ge_p1p1_to_p3($t);
            $Ai[$i + 1] = self::ge_p3_to_cached($u);
        }

        # ge_p2_0(r);
        $r = self::ge_p2_0();

        # for (i = 255;i >= 0;--i) {
        #     if (aslide[i] || bslide[i]) break;
        # }
        $i = 255;
        for (; $i >= 0; --$i) {
            if ($aslide[$i] || $bslide[$i]) {
                break;
            }
        }

        # for (;i >= 0;--i) {
        for (; $i >= 0; --$i) {
            # ge_p2_dbl(&t,r);
            $t = self::ge_p2_dbl($r);

            # if (aslide[i] > 0) {
            if ($aslide[$i] > 0) {
                # ge_p1p1_to_p3(&u,&t);
                # ge_add(&t,&u,&Ai[aslide[i]/2]);
                $u = self::ge_p1p1_to_p3($t);
                $t = self::ge_add(
                    $u,
                    $Ai[(int) floor($aslide[$i] / 2)]
                );
            # } else if (aslide[i] < 0) {
            } elseif ($aslide[$i] < 0) {
                # ge_p1p1_to_p3(&u,&t);
                # ge_sub(&t,&u,&Ai[(-aslide[i])/2]);
                $u = self::ge_p1p1_to_p3($t);
                $t = self::ge_sub(
                    $u,
                    $Ai[(int) floor(-$aslide[$i] / 2)]
                );
            }

            # if (bslide[i] > 0) {
            if ($bslide[$i] > 0) {
                /** @var int $index */
                $index = (int) floor($bslide[$i] / 2);
                # ge_p1p1_to_p3(&u,&t);
                # ge_madd(&t,&u,&Bi[bslide[i]/2]);
                $u = self::ge_p1p1_to_p3($t);
                $t = self::ge_madd($t, $u, $Bi[$index]);
            # } else if (bslide[i] < 0) {
            } elseif ($bslide[$i] < 0) {
                /** @var int $index */
                $index = (int) floor(-$bslide[$i] / 2);
                # ge_p1p1_to_p3(&u,&t);
                # ge_msub(&t,&u,&Bi[(-bslide[i])/2]);
                $u = self::ge_p1p1_to_p3($t);
                $t = self::ge_msub($t, $u, $Bi[$index]);
            }
            # ge_p1p1_to_p2(r,&t);
            $r = self::ge_p1p1_to_p2($t);
        }
        return $r;
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param string $a
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     * @throws SodiumException
     * @throws TypeError
     * @psalm-suppress MixedAssignment
     * @psalm-suppress MixedOperand
     */
    public static function ge_scalarmult($a, $p)
    {
        $e = array_fill(0, 64, 0);

        /** @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] $pi */
        $pi = array();

        //        ge25519_p3_to_cached(&pi[1 - 1], p);   /* p */
        $pi[0] = self::ge_p3_to_cached($p);

        //        ge25519_p3_dbl(&t2, p);
        //        ge25519_p1p1_to_p3(&p2, &t2);
        //        ge25519_p3_to_cached(&pi[2 - 1], &p2); /* 2p = 2*p */
        $t2 = self::ge_p3_dbl($p);
        $p2 = self::ge_p1p1_to_p3($t2);
        $pi[1] = self::ge_p3_to_cached($p2);

        //        ge25519_add_cached(&t3, p, &pi[2 - 1]);
        //        ge25519_p1p1_to_p3(&p3, &t3);
        //        ge25519_p3_to_cached(&pi[3 - 1], &p3); /* 3p = 2p+p */
        $t3 = self::ge_add($p, $pi[1]);
        $p3 = self::ge_p1p1_to_p3($t3);
        $pi[2] = self::ge_p3_to_cached($p3);

        //        ge25519_p3_dbl(&t4, &p2);
        //        ge25519_p1p1_to_p3(&p4, &t4);
        //        ge25519_p3_to_cached(&pi[4 - 1], &p4); /* 4p = 2*2p */
        $t4 = self::ge_p3_dbl($p2);
        $p4 = self::ge_p1p1_to_p3($t4);
        $pi[3] = self::ge_p3_to_cached($p4);

        //        ge25519_add_cached(&t5, p, &pi[4 - 1]);
        //        ge25519_p1p1_to_p3(&p5, &t5);
        //        ge25519_p3_to_cached(&pi[5 - 1], &p5); /* 5p = 4p+p */
        $t5 = self::ge_add($p, $pi[3]);
        $p5 = self::ge_p1p1_to_p3($t5);
        $pi[4] = self::ge_p3_to_cached($p5);

        //        ge25519_p3_dbl(&t6, &p3);
        //        ge25519_p1p1_to_p3(&p6, &t6);
        //        ge25519_p3_to_cached(&pi[6 - 1], &p6); /* 6p = 2*3p */
        $t6 = self::ge_p3_dbl($p3);
        $p6 = self::ge_p1p1_to_p3($t6);
        $pi[5] = self::ge_p3_to_cached($p6);

        //        ge25519_add_cached(&t7, p, &pi[6 - 1]);
        //        ge25519_p1p1_to_p3(&p7, &t7);
        //        ge25519_p3_to_cached(&pi[7 - 1], &p7); /* 7p = 6p+p */
        $t7 = self::ge_add($p, $pi[5]);
        $p7 = self::ge_p1p1_to_p3($t7);
        $pi[6] = self::ge_p3_to_cached($p7);

        //        ge25519_p3_dbl(&t8, &p4);
        //        ge25519_p1p1_to_p3(&p8, &t8);
        //        ge25519_p3_to_cached(&pi[8 - 1], &p8); /* 8p = 2*4p */
        $t8 = self::ge_p3_dbl($p4);
        $p8 = self::ge_p1p1_to_p3($t8);
        $pi[7] = self::ge_p3_to_cached($p8);


        //        for (i = 0; i < 32; ++i) {
        //            e[2 * i + 0] = (a[i] >> 0) & 15;
        //            e[2 * i + 1] = (a[i] >> 4) & 15;
        //        }
        for ($i = 0; $i < 32; ++$i) {
            $e[($i << 1)    ] =  self::chrToInt($a[$i]) & 15;
            $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15;
        }
        //        /* each e[i] is between 0 and 15 */
        //        /* e[63] is between 0 and 7 */

        //        carry = 0;
        //        for (i = 0; i < 63; ++i) {
        //            e[i] += carry;
        //            carry = e[i] + 8;
        //            carry >>= 4;
        //            e[i] -= carry * ((signed char) 1 << 4);
        //        }
        $carry = 0;
        for ($i = 0; $i < 63; ++$i) {
            $e[$i] += $carry;
            $carry = $e[$i] + 8;
            $carry >>= 4;
            $e[$i] -= $carry << 4;
        }
        //        e[63] += carry;
        //        /* each e[i] is between -8 and 8 */
        $e[63] += $carry;

        //        ge25519_p3_0(h);
        $h = self::ge_p3_0();

        //        for (i = 63; i != 0; i--) {
        for ($i = 63; $i != 0; --$i) {
            // ge25519_cmov8_cached(&t, pi, e[i]);
            $t = self::ge_cmov8_cached($pi, $e[$i]);
            // ge25519_add_cached(&r, h, &t);
            $r = self::ge_add($h, $t);

            // ge25519_p1p1_to_p2(&s, &r);
            // ge25519_p2_dbl(&r, &s);
            // ge25519_p1p1_to_p2(&s, &r);
            // ge25519_p2_dbl(&r, &s);
            // ge25519_p1p1_to_p2(&s, &r);
            // ge25519_p2_dbl(&r, &s);
            // ge25519_p1p1_to_p2(&s, &r);
            // ge25519_p2_dbl(&r, &s);
            $s = self::ge_p1p1_to_p2($r);
            $r = self::ge_p2_dbl($s);
            $s = self::ge_p1p1_to_p2($r);
            $r = self::ge_p2_dbl($s);
            $s = self::ge_p1p1_to_p2($r);
            $r = self::ge_p2_dbl($s);
            $s = self::ge_p1p1_to_p2($r);
            $r = self::ge_p2_dbl($s);

            // ge25519_p1p1_to_p3(h, &r);  /* *16 */
            $h = self::ge_p1p1_to_p3($r); /* *16 */
        }

        //        ge25519_cmov8_cached(&t, pi, e[i]);
        //        ge25519_add_cached(&r, h, &t);
        //        ge25519_p1p1_to_p3(h, &r);
        $t = self::ge_cmov8_cached($pi, $e[0]);
        $r = self::ge_add($h, $t);
        return self::ge_p1p1_to_p3($r);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param string $a
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     * @throws SodiumException
     * @throws TypeError
     * @psalm-suppress MixedAssignment
     * @psalm-suppress MixedOperand
     */
    public static function ge_scalarmult_base($a)
    {
        /** @var array<int, int> $e */
        $e = array();
        $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1();

        for ($i = 0; $i < 32; ++$i) {
            $dbl = (int) $i << 1;
            $e[$dbl] = (int) self::chrToInt($a[$i]) & 15;
            $e[$dbl + 1] = (int) (self::chrToInt($a[$i]) >> 4) & 15;
        }

        $carry = 0;
        for ($i = 0; $i < 63; ++$i) {
            $e[$i] += $carry;
            $carry = $e[$i] + 8;
            $carry >>= 4;
            $e[$i] -= $carry << 4;
        }
        $e[63] += (int) $carry;

        $h = self::ge_p3_0();

        for ($i = 1; $i < 64; $i += 2) {
            $t = self::ge_select((int) floor($i / 2), (int) $e[$i]);
            $r = self::ge_madd($r, $h, $t);
            $h = self::ge_p1p1_to_p3($r);
        }

        $r = self::ge_p3_dbl($h);

        $s = self::ge_p1p1_to_p2($r);
        $r = self::ge_p2_dbl($s);
        $s = self::ge_p1p1_to_p2($r);
        $r = self::ge_p2_dbl($s);
        $s = self::ge_p1p1_to_p2($r);
        $r = self::ge_p2_dbl($s);

        $h = self::ge_p1p1_to_p3($r);

        for ($i = 0; $i < 64; $i += 2) {
            $t = self::ge_select($i >> 1, (int) $e[$i]);
            $r = self::ge_madd($r, $h, $t);
            $h = self::ge_p1p1_to_p3($r);
        }
        return $h;
    }

    /**
     * Calculates (ab + c) mod l
     * where l = 2^252 + 27742317777372353535851937790883648493
     *
     * @internal You should not use this directly from another application
     *
     * @param string $a
     * @param string $b
     * @param string $c
     * @return string
     * @throws TypeError
     */
    public static function sc_muladd($a, $b, $c)
    {
        $a0 = 2097151 & self::load_3(self::substr($a, 0, 3));
        $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
        $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
        $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
        $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
        $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
        $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
        $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
        $a8 = 2097151 & self::load_3(self::substr($a, 21, 3));
        $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
        $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
        $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);

        $b0 = 2097151 & self::load_3(self::substr($b, 0, 3));
        $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
        $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
        $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
        $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
        $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
        $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
        $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
        $b8 = 2097151 & self::load_3(self::substr($b, 21, 3));
        $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
        $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
        $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);

        $c0 = 2097151 & self::load_3(self::substr($c, 0, 3));
        $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5);
        $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2);
        $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7);
        $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4);
        $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1);
        $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6);
        $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3);
        $c8 = 2097151 & self::load_3(self::substr($c, 21, 3));
        $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5);
        $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2);
        $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7);

        /* Can't really avoid the pyramid here: */
        $s0 = $c0 + self::mul($a0, $b0, 24);
        $s1 = $c1 + self::mul($a0, $b1, 24) + self::mul($a1, $b0, 24);
        $s2 = $c2 + self::mul($a0, $b2, 24) + self::mul($a1, $b1, 24) + self::mul($a2, $b0, 24);
        $s3 = $c3 + self::mul($a0, $b3, 24) + self::mul($a1, $b2, 24) + self::mul($a2, $b1, 24) + self::mul($a3, $b0, 24);
        $s4 = $c4 + self::mul($a0, $b4, 24) + self::mul($a1, $b3, 24) + self::mul($a2, $b2, 24) + self::mul($a3, $b1, 24) +
               self::mul($a4, $b0, 24);
        $s5 = $c5 + self::mul($a0, $b5, 24) + self::mul($a1, $b4, 24) + self::mul($a2, $b3, 24) + self::mul($a3, $b2, 24) +
               self::mul($a4, $b1, 24) + self::mul($a5, $b0, 24);
        $s6 = $c6 + self::mul($a0, $b6, 24) + self::mul($a1, $b5, 24) + self::mul($a2, $b4, 24) + self::mul($a3, $b3, 24) +
               self::mul($a4, $b2, 24) + self::mul($a5, $b1, 24) + self::mul($a6, $b0, 24);
        $s7 = $c7 + self::mul($a0, $b7, 24) + self::mul($a1, $b6, 24) + self::mul($a2, $b5, 24) + self::mul($a3, $b4, 24) +
               self::mul($a4, $b3, 24) + self::mul($a5, $b2, 24) + self::mul($a6, $b1, 24) + self::mul($a7, $b0, 24);
        $s8 = $c8 + self::mul($a0, $b8, 24) + self::mul($a1, $b7, 24) + self::mul($a2, $b6, 24) + self::mul($a3, $b5, 24) +
               self::mul($a4, $b4, 24) + self::mul($a5, $b3, 24) + self::mul($a6, $b2, 24) + self::mul($a7, $b1, 24) +
               self::mul($a8, $b0, 24);
        $s9 = $c9 + self::mul($a0, $b9, 24) + self::mul($a1, $b8, 24) + self::mul($a2, $b7, 24) + self::mul($a3, $b6, 24) +
               self::mul($a4, $b5, 24) + self::mul($a5, $b4, 24) + self::mul($a6, $b3, 24) + self::mul($a7, $b2, 24) +
               self::mul($a8, $b1, 24) + self::mul($a9, $b0, 24);
        $s10 = $c10 + self::mul($a0, $b10, 24) + self::mul($a1, $b9, 24) + self::mul($a2, $b8, 24) + self::mul($a3, $b7, 24) +
               self::mul($a4, $b6, 24) + self::mul($a5, $b5, 24) + self::mul($a6, $b4, 24) + self::mul($a7, $b3, 24) +
               self::mul($a8, $b2, 24) + self::mul($a9, $b1, 24) + self::mul($a10, $b0, 24);
        $s11 = $c11 + self::mul($a0, $b11, 24) + self::mul($a1, $b10, 24) + self::mul($a2, $b9, 24) + self::mul($a3, $b8, 24) +
               self::mul($a4, $b7, 24) + self::mul($a5, $b6, 24) + self::mul($a6, $b5, 24) + self::mul($a7, $b4, 24) +
               self::mul($a8, $b3, 24) + self::mul($a9, $b2, 24) + self::mul($a10, $b1, 24) + self::mul($a11, $b0, 24);
        $s12 = self::mul($a1, $b11, 24) + self::mul($a2, $b10, 24) + self::mul($a3, $b9, 24) + self::mul($a4, $b8, 24) +
               self::mul($a5, $b7, 24) + self::mul($a6, $b6, 24) + self::mul($a7, $b5, 24) + self::mul($a8, $b4, 24) +
               self::mul($a9, $b3, 24) + self::mul($a10, $b2, 24) + self::mul($a11, $b1, 24);
        $s13 = self::mul($a2, $b11, 24) + self::mul($a3, $b10, 24) + self::mul($a4, $b9, 24) + self::mul($a5, $b8, 24) +
               self::mul($a6, $b7, 24) + self::mul($a7, $b6, 24) + self::mul($a8, $b5, 24) + self::mul($a9, $b4, 24) +
               self::mul($a10, $b3, 24) + self::mul($a11, $b2, 24);
        $s14 = self::mul($a3, $b11, 24) + self::mul($a4, $b10, 24) + self::mul($a5, $b9, 24) + self::mul($a6, $b8, 24) +
               self::mul($a7, $b7, 24) + self::mul($a8, $b6, 24) + self::mul($a9, $b5, 24) + self::mul($a10, $b4, 24) +
               self::mul($a11, $b3, 24);
        $s15 = self::mul($a4, $b11, 24) + self::mul($a5, $b10, 24) + self::mul($a6, $b9, 24) + self::mul($a7, $b8, 24) +
               self::mul($a8, $b7, 24) + self::mul($a9, $b6, 24) + self::mul($a10, $b5, 24) + self::mul($a11, $b4, 24);
        $s16 = self::mul($a5, $b11, 24) + self::mul($a6, $b10, 24) + self::mul($a7, $b9, 24) + self::mul($a8, $b8, 24) +
               self::mul($a9, $b7, 24) + self::mul($a10, $b6, 24) + self::mul($a11, $b5, 24);
        $s17 = self::mul($a6, $b11, 24) + self::mul($a7, $b10, 24) + self::mul($a8, $b9, 24) + self::mul($a9, $b8, 24) +
               self::mul($a10, $b7, 24) + self::mul($a11, $b6, 24);
        $s18 = self::mul($a7, $b11, 24) + self::mul($a8, $b10, 24) + self::mul($a9, $b9, 24) + self::mul($a10, $b8, 24) +
               self::mul($a11, $b7, 24);
        $s19 = self::mul($a8, $b11, 24) + self::mul($a9, $b10, 24) + self::mul($a10, $b9, 24) + self::mul($a11, $b8, 24);
        $s20 = self::mul($a9, $b11, 24) + self::mul($a10, $b10, 24) + self::mul($a11, $b9, 24);
        $s21 = self::mul($a10, $b11, 24) + self::mul($a11, $b10, 24);
        $s22 = self::mul($a11, $b11, 24);
        $s23 = 0;

        $carry0 = ($s0 + (1 << 20)) >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry2 = ($s2 + (1 << 20)) >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry4 = ($s4 + (1 << 20)) >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        $carry12 = ($s12 + (1 << 20)) >> 21;
        $s13 += $carry12;
        $s12 -= $carry12 << 21;
        $carry14 = ($s14 + (1 << 20)) >> 21;
        $s15 += $carry14;
        $s14 -= $carry14 << 21;
        $carry16 = ($s16 + (1 << 20)) >> 21;
        $s17 += $carry16;
        $s16 -= $carry16 << 21;
        $carry18 = ($s18 + (1 << 20)) >> 21;
        $s19 += $carry18;
        $s18 -= $carry18 << 21;
        $carry20 = ($s20 + (1 << 20)) >> 21;
        $s21 += $carry20;
        $s20 -= $carry20 << 21;
        $carry22 = ($s22 + (1 << 20)) >> 21;
        $s23 += $carry22;
        $s22 -= $carry22 << 21;

        $carry1 = ($s1 + (1 << 20)) >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry3 = ($s3 + (1 << 20)) >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry5 = ($s5 + (1 << 20)) >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;
        $carry13 = ($s13 + (1 << 20)) >> 21;
        $s14 += $carry13;
        $s13 -= $carry13 << 21;
        $carry15 = ($s15 + (1 << 20)) >> 21;
        $s16 += $carry15;
        $s15 -= $carry15 << 21;
        $carry17 = ($s17 + (1 << 20)) >> 21;
        $s18 += $carry17;
        $s17 -= $carry17 << 21;
        $carry19 = ($s19 + (1 << 20)) >> 21;
        $s20 += $carry19;
        $s19 -= $carry19 << 21;
        $carry21 = ($s21 + (1 << 20)) >> 21;
        $s22 += $carry21;
        $s21 -= $carry21 << 21;

        $s11 += self::mul($s23, 666643, 20);
        $s12 += self::mul($s23, 470296, 19);
        $s13 += self::mul($s23, 654183, 20);
        $s14 -= self::mul($s23, 997805, 20);
        $s15 += self::mul($s23, 136657, 18);
        $s16 -= self::mul($s23, 683901, 20);

        $s10 += self::mul($s22, 666643, 20);
        $s11 += self::mul($s22, 470296, 19);
        $s12 += self::mul($s22, 654183, 20);
        $s13 -= self::mul($s22, 997805, 20);
        $s14 += self::mul($s22, 136657, 18);
        $s15 -= self::mul($s22, 683901, 20);

        $s9  += self::mul($s21,  666643, 20);
        $s10 += self::mul($s21,  470296, 19);
        $s11 += self::mul($s21,  654183, 20);
        $s12 -= self::mul($s21,  997805, 20);
        $s13 += self::mul($s21,  136657, 18);
        $s14 -= self::mul($s21,  683901, 20);

        $s8  += self::mul($s20,  666643, 20);
        $s9  += self::mul($s20,  470296, 19);
        $s10 += self::mul($s20,  654183, 20);
        $s11 -= self::mul($s20,  997805, 20);
        $s12 += self::mul($s20,  136657, 18);
        $s13 -= self::mul($s20,  683901, 20);

        $s7  += self::mul($s19,  666643, 20);
        $s8  += self::mul($s19,  470296, 19);
        $s9  += self::mul($s19,  654183, 20);
        $s10 -= self::mul($s19,  997805, 20);
        $s11 += self::mul($s19,  136657, 18);
        $s12 -= self::mul($s19,  683901, 20);

        $s6  += self::mul($s18,  666643, 20);
        $s7  += self::mul($s18,  470296, 19);
        $s8  += self::mul($s18,  654183, 20);
        $s9  -= self::mul($s18,  997805, 20);
        $s10 += self::mul($s18,  136657, 18);
        $s11 -= self::mul($s18,  683901, 20);

        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        $carry12 = ($s12 + (1 << 20)) >> 21;
        $s13 += $carry12;
        $s12 -= $carry12 << 21;
        $carry14 = ($s14 + (1 << 20)) >> 21;
        $s15 += $carry14;
        $s14 -= $carry14 << 21;
        $carry16 = ($s16 + (1 << 20)) >> 21;
        $s17 += $carry16;
        $s16 -= $carry16 << 21;

        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;
        $carry13 = ($s13 + (1 << 20)) >> 21;
        $s14 += $carry13;
        $s13 -= $carry13 << 21;
        $carry15 = ($s15 + (1 << 20)) >> 21;
        $s16 += $carry15;
        $s15 -= $carry15 << 21;

        $s5  += self::mul($s17,  666643, 20);
        $s6  += self::mul($s17,  470296, 19);
        $s7  += self::mul($s17,  654183, 20);
        $s8  -= self::mul($s17,  997805, 20);
        $s9  += self::mul($s17,  136657, 18);
        $s10 -= self::mul($s17,  683901, 20);

        $s4 += self::mul($s16,  666643, 20);
        $s5 += self::mul($s16,  470296, 19);
        $s6 += self::mul($s16,  654183, 20);
        $s7 -= self::mul($s16,  997805, 20);
        $s8 += self::mul($s16,  136657, 18);
        $s9 -= self::mul($s16,  683901, 20);

        $s3 += self::mul($s15,  666643, 20);
        $s4 += self::mul($s15,  470296, 19);
        $s5 += self::mul($s15,  654183, 20);
        $s6 -= self::mul($s15,  997805, 20);
        $s7 += self::mul($s15,  136657, 18);
        $s8 -= self::mul($s15,  683901, 20);

        $s2 += self::mul($s14,  666643, 20);
        $s3 += self::mul($s14,  470296, 19);
        $s4 += self::mul($s14,  654183, 20);
        $s5 -= self::mul($s14,  997805, 20);
        $s6 += self::mul($s14,  136657, 18);
        $s7 -= self::mul($s14,  683901, 20);

        $s1 += self::mul($s13,  666643, 20);
        $s2 += self::mul($s13,  470296, 19);
        $s3 += self::mul($s13,  654183, 20);
        $s4 -= self::mul($s13,  997805, 20);
        $s5 += self::mul($s13,  136657, 18);
        $s6 -= self::mul($s13,  683901, 20);

        $s0 += self::mul($s12,  666643, 20);
        $s1 += self::mul($s12,  470296, 19);
        $s2 += self::mul($s12,  654183, 20);
        $s3 -= self::mul($s12,  997805, 20);
        $s4 += self::mul($s12,  136657, 18);
        $s5 -= self::mul($s12,  683901, 20);
        $s12 = 0;

        $carry0 = ($s0 + (1 << 20)) >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry2 = ($s2 + (1 << 20)) >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry4 = ($s4 + (1 << 20)) >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;

        $carry1 = ($s1 + (1 << 20)) >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry3 = ($s3 + (1 << 20)) >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry5 = ($s5 + (1 << 20)) >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;

        $s0 += self::mul($s12,  666643, 20);
        $s1 += self::mul($s12,  470296, 19);
        $s2 += self::mul($s12,  654183, 20);
        $s3 -= self::mul($s12,  997805, 20);
        $s4 += self::mul($s12,  136657, 18);
        $s5 -= self::mul($s12,  683901, 20);
        $s12 = 0;

        $carry0 = $s0 >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry1 = $s1 >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry2 = $s2 >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry3 = $s3 >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry4 = $s4 >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry5 = $s5 >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry6 = $s6 >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry7 = $s7 >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry8 = $s8 >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry9 = $s9 >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry10 = $s10 >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        $carry11 = $s11 >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;

        $s0 += self::mul($s12,  666643, 20);
        $s1 += self::mul($s12,  470296, 19);
        $s2 += self::mul($s12,  654183, 20);
        $s3 -= self::mul($s12,  997805, 20);
        $s4 += self::mul($s12,  136657, 18);
        $s5 -= self::mul($s12,  683901, 20);

        $carry0 = $s0 >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry1 = $s1 >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry2 = $s2 >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry3 = $s3 >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry4 = $s4 >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry5 = $s5 >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry6 = $s6 >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry7 = $s7 >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry8 = $s8 >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry9 = $s9 >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry10 = $s10 >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;

        /**
         * @var array<int, int>
         */
        $arr = array(
            (int) (0xff & ($s0 >> 0)),
            (int) (0xff & ($s0 >> 8)),
            (int) (0xff & (($s0 >> 16) | $s1 << 5)),
            (int) (0xff & ($s1 >> 3)),
            (int) (0xff & ($s1 >> 11)),
            (int) (0xff & (($s1 >> 19) | $s2 << 2)),
            (int) (0xff & ($s2 >> 6)),
            (int) (0xff & (($s2 >> 14) | $s3 << 7)),
            (int) (0xff & ($s3 >> 1)),
            (int) (0xff & ($s3 >> 9)),
            (int) (0xff & (($s3 >> 17) | $s4 << 4)),
            (int) (0xff & ($s4 >> 4)),
            (int) (0xff & ($s4 >> 12)),
            (int) (0xff & (($s4 >> 20) | $s5 << 1)),
            (int) (0xff & ($s5 >> 7)),
            (int) (0xff & (($s5 >> 15) | $s6 << 6)),
            (int) (0xff & ($s6 >> 2)),
            (int) (0xff & ($s6 >> 10)),
            (int) (0xff & (($s6 >> 18) | $s7 << 3)),
            (int) (0xff & ($s7 >> 5)),
            (int) (0xff & ($s7 >> 13)),
            (int) (0xff & ($s8 >> 0)),
            (int) (0xff & ($s8 >> 8)),
            (int) (0xff & (($s8 >> 16) | $s9 << 5)),
            (int) (0xff & ($s9 >> 3)),
            (int) (0xff & ($s9 >> 11)),
            (int) (0xff & (($s9 >> 19) | $s10 << 2)),
            (int) (0xff & ($s10 >> 6)),
            (int) (0xff & (($s10 >> 14) | $s11 << 7)),
            (int) (0xff & ($s11 >> 1)),
            (int) (0xff & ($s11 >> 9)),
            0xff & ($s11 >> 17)
        );
        return self::intArrayToString($arr);
    }

    /**
     * @internal You should not use this directly from another application
     *
     * @param string $s
     * @return string
     * @throws TypeError
     */
    public static function sc_reduce($s)
    {
        $s0 = 2097151 & self::load_3(self::substr($s, 0, 3));
        $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5);
        $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2);
        $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7);
        $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4);
        $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1);
        $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6);
        $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3);
        $s8 = 2097151 & self::load_3(self::substr($s, 21, 3));
        $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5);
        $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2);
        $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7);
        $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4);
        $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1);
        $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6);
        $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3);
        $s16 = 2097151 & self::load_3(self::substr($s, 42, 3));
        $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5);
        $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2);
        $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7);
        $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4);
        $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1);
        $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6);
        $s23 = 0x1fffffff & (self::load_4(self::substr($s, 60, 4)) >> 3);

        $s11 += self::mul($s23,  666643, 20);
        $s12 += self::mul($s23,  470296, 19);
        $s13 += self::mul($s23,  654183, 20);
        $s14 -= self::mul($s23,  997805, 20);
        $s15 += self::mul($s23,  136657, 18);
        $s16 -= self::mul($s23,  683901, 20);

        $s10 += self::mul($s22,  666643, 20);
        $s11 += self::mul($s22,  470296, 19);
        $s12 += self::mul($s22,  654183, 20);
        $s13 -= self::mul($s22,  997805, 20);
        $s14 += self::mul($s22,  136657, 18);
        $s15 -= self::mul($s22,  683901, 20);

        $s9  += self::mul($s21,  666643, 20);
        $s10 += self::mul($s21,  470296, 19);
        $s11 += self::mul($s21,  654183, 20);
        $s12 -= self::mul($s21,  997805, 20);
        $s13 += self::mul($s21,  136657, 18);
        $s14 -= self::mul($s21,  683901, 20);

        $s8  += self::mul($s20,  666643, 20);
        $s9  += self::mul($s20,  470296, 19);
        $s10 += self::mul($s20,  654183, 20);
        $s11 -= self::mul($s20,  997805, 20);
        $s12 += self::mul($s20,  136657, 18);
        $s13 -= self::mul($s20,  683901, 20);

        $s7  += self::mul($s19,  666643, 20);
        $s8  += self::mul($s19,  470296, 19);
        $s9  += self::mul($s19,  654183, 20);
        $s10 -= self::mul($s19,  997805, 20);
        $s11 += self::mul($s19,  136657, 18);
        $s12 -= self::mul($s19,  683901, 20);

        $s6  += self::mul($s18,  666643, 20);
        $s7  += self::mul($s18,  470296, 19);
        $s8  += self::mul($s18,  654183, 20);
        $s9  -= self::mul($s18,  997805, 20);
        $s10 += self::mul($s18,  136657, 18);
        $s11 -= self::mul($s18,  683901, 20);

        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        $carry12 = ($s12 + (1 << 20)) >> 21;
        $s13 += $carry12;
        $s12 -= $carry12 << 21;
        $carry14 = ($s14 + (1 << 20)) >> 21;
        $s15 += $carry14;
        $s14 -= $carry14 << 21;
        $carry16 = ($s16 + (1 << 20)) >> 21;
        $s17 += $carry16;
        $s16 -= $carry16 << 21;

        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;
        $carry13 = ($s13 + (1 << 20)) >> 21;
        $s14 += $carry13;
        $s13 -= $carry13 << 21;
        $carry15 = ($s15 + (1 << 20)) >> 21;
        $s16 += $carry15;
        $s15 -= $carry15 << 21;

        $s5  += self::mul($s17,  666643, 20);
        $s6  += self::mul($s17,  470296, 19);
        $s7  += self::mul($s17,  654183, 20);
        $s8  -= self::mul($s17,  997805, 20);
        $s9  += self::mul($s17,  136657, 18);
        $s10 -= self::mul($s17,  683901, 20);

        $s4 += self::mul($s16,  666643, 20);
        $s5 += self::mul($s16,  470296, 19);
        $s6 += self::mul($s16,  654183, 20);
        $s7 -= self::mul($s16,  997805, 20);
        $s8 += self::mul($s16,  136657, 18);
        $s9 -= self::mul($s16,  683901, 20);

        $s3 += self::mul($s15,  666643, 20);
        $s4 += self::mul($s15,  470296, 19);
        $s5 += self::mul($s15,  654183, 20);
        $s6 -= self::mul($s15,  997805, 20);
        $s7 += self::mul($s15,  136657, 18);
        $s8 -= self::mul($s15,  683901, 20);

        $s2 += self::mul($s14,  666643, 20);
        $s3 += self::mul($s14,  470296, 19);
        $s4 += self::mul($s14,  654183, 20);
        $s5 -= self::mul($s14,  997805, 20);
        $s6 += self::mul($s14,  136657, 18);
        $s7 -= self::mul($s14,  683901, 20);

        $s1 += self::mul($s13,  666643, 20);
        $s2 += self::mul($s13,  470296, 19);
        $s3 += self::mul($s13,  654183, 20);
        $s4 -= self::mul($s13,  997805, 20);
        $s5 += self::mul($s13,  136657, 18);
        $s6 -= self::mul($s13,  683901, 20);

        $s0 += self::mul($s12,  666643, 20);
        $s1 += self::mul($s12,  470296, 19);
        $s2 += self::mul($s12,  654183, 20);
        $s3 -= self::mul($s12,  997805, 20);
        $s4 += self::mul($s12,  136657, 18);
        $s5 -= self::mul($s12,  683901, 20);
        $s12 = 0;

        $carry0 = ($s0 + (1 << 20)) >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry2 = ($s2 + (1 << 20)) >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry4 = ($s4 + (1 << 20)) >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;

        $carry1 = ($s1 + (1 << 20)) >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry3 = ($s3 + (1 << 20)) >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry5 = ($s5 + (1 << 20)) >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;

        $s0 += self::mul($s12,  666643, 20);
        $s1 += self::mul($s12,  470296, 19);
        $s2 += self::mul($s12,  654183, 20);
        $s3 -= self::mul($s12,  997805, 20);
        $s4 += self::mul($s12,  136657, 18);
        $s5 -= self::mul($s12,  683901, 20);
        $s12 = 0;

        $carry0 = $s0 >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry1 = $s1 >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry2 = $s2 >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry3 = $s3 >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry4 = $s4 >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry5 = $s5 >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry6 = $s6 >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry7 = $s7 >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry8 = $s8 >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry9 = $s9 >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry10 = $s10 >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        $carry11 = $s11 >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;

        $s0 += self::mul($s12,  666643, 20);
        $s1 += self::mul($s12,  470296, 19);
        $s2 += self::mul($s12,  654183, 20);
        $s3 -= self::mul($s12,  997805, 20);
        $s4 += self::mul($s12,  136657, 18);
        $s5 -= self::mul($s12,  683901, 20);

        $carry0 = $s0 >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        $carry1 = $s1 >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        $carry2 = $s2 >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        $carry3 = $s3 >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        $carry4 = $s4 >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        $carry5 = $s5 >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        $carry6 = $s6 >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        $carry7 = $s7 >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        $carry8 = $s8 >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        $carry9 = $s9 >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        $carry10 = $s10 >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;

        /**
         * @var array<int, int>
         */
        $arr = array(
            (int) ($s0 >> 0),
            (int) ($s0 >> 8),
            (int) (($s0 >> 16) | $s1 << 5),
            (int) ($s1 >> 3),
            (int) ($s1 >> 11),
            (int) (($s1 >> 19) | $s2 << 2),
            (int) ($s2 >> 6),
            (int) (($s2 >> 14) | $s3 << 7),
            (int) ($s3 >> 1),
            (int) ($s3 >> 9),
            (int) (($s3 >> 17) | $s4 << 4),
            (int) ($s4 >> 4),
            (int) ($s4 >> 12),
            (int) (($s4 >> 20) | $s5 << 1),
            (int) ($s5 >> 7),
            (int) (($s5 >> 15) | $s6 << 6),
            (int) ($s6 >> 2),
            (int) ($s6 >> 10),
            (int) (($s6 >> 18) | $s7 << 3),
            (int) ($s7 >> 5),
            (int) ($s7 >> 13),
            (int) ($s8 >> 0),
            (int) ($s8 >> 8),
            (int) (($s8 >> 16) | $s9 << 5),
            (int) ($s9 >> 3),
            (int) ($s9 >> 11),
            (int) (($s9 >> 19) | $s10 << 2),
            (int) ($s10 >> 6),
            (int) (($s10 >> 14) | $s11 << 7),
            (int) ($s11 >> 1),
            (int) ($s11 >> 9),
            (int) $s11 >> 17
        );
        return self::intArrayToString($arr);
    }

    /**
     * multiply by the order of the main subgroup l = 2^252+27742317777372353535851937790883648493
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
     * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
     */
    public static function ge_mul_l(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A)
    {
        $aslide = array(
            13, 0, 0, 0, 0, -1, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, -5, 0, 0, 0,
            0, 0, 0, -3, 0, 0, 0, 0, -13, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 3, 0,
            0, 0, 0, -13, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0,
            0, 0, 11, 0, 0, 0, 0, -13, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 0, -1,
            0, 0, 0, 0, 3, 0, 0, 0, 0, -11, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0,
            0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 5, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
        );

        /** @var array<int, ParagonIE_Sodium_Core_Curve25519_Ge_Cached> $Ai size 8 */
        $Ai = array();

        # ge_p3_to_cached(&Ai[0], A);
        $Ai[0] = self::ge_p3_to_cached($A);
        # ge_p3_dbl(&t, A);
        $t = self::ge_p3_dbl($A);
        # ge_p1p1_to_p3(&A2, &t);
        $A2 = self::ge_p1p1_to_p3($t);

        for ($i = 1; $i < 8; ++$i) {
            # ge_add(&t, &A2, &Ai[0]);
            $t = self::ge_add($A2, $Ai[$i - 1]);
            # ge_p1p1_to_p3(&u, &t);
            $u = self::ge_p1p1_to_p3($t);
            # ge_p3_to_cached(&Ai[i], &u);
            $Ai[$i] = self::ge_p3_to_cached($u);
        }

        $r = self::ge_p3_0();
        for ($i = 252; $i >= 0; --$i) {
            $t = self::ge_p3_dbl($r);
            if ($aslide[$i] > 0) {
                # ge_p1p1_to_p3(&u, &t);
                $u = self::ge_p1p1_to_p3($t);
                # ge_add(&t, &u, &Ai[aslide[i] / 2]);
                $t = self::ge_add($u, $Ai[(int)($aslide[$i] / 2)]);
            } elseif ($aslide[$i] < 0) {
                # ge_p1p1_to_p3(&u, &t);
                $u = self::ge_p1p1_to_p3($t);
                # ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
                $t = self::ge_sub($u, $Ai[(int)(-$aslide[$i] / 2)]);
            }
        }

        # ge_p1p1_to_p3(r, &t);
        return self::ge_p1p1_to_p3($t);
    }

    /**
     * @param string $a
     * @param string $b
     * @return string
     */
    public static function sc25519_mul($a, $b)
    {
        //    int64_t a0  = 2097151 & load_3(a);
        //    int64_t a1  = 2097151 & (load_4(a + 2) >> 5);
        //    int64_t a2  = 2097151 & (load_3(a + 5) >> 2);
        //    int64_t a3  = 2097151 & (load_4(a + 7) >> 7);
        //    int64_t a4  = 2097151 & (load_4(a + 10) >> 4);
        //    int64_t a5  = 2097151 & (load_3(a + 13) >> 1);
        //    int64_t a6  = 2097151 & (load_4(a + 15) >> 6);
        //    int64_t a7  = 2097151 & (load_3(a + 18) >> 3);
        //    int64_t a8  = 2097151 & load_3(a + 21);
        //    int64_t a9  = 2097151 & (load_4(a + 23) >> 5);
        //    int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
        //    int64_t a11 = (load_4(a + 28) >> 7);
        $a0  = 2097151 &  self::load_3(self::substr($a, 0, 3));
        $a1  = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5);
        $a2  = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2);
        $a3  = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7);
        $a4  = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4);
        $a5  = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1);
        $a6  = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6);
        $a7  = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3);
        $a8  = 2097151 &  self::load_3(self::substr($a, 21, 3));
        $a9  = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5);
        $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2);
        $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7);

        //    int64_t b0  = 2097151 & load_3(b);
        //    int64_t b1  = 2097151 & (load_4(b + 2) >> 5);
        //    int64_t b2  = 2097151 & (load_3(b + 5) >> 2);
        //    int64_t b3  = 2097151 & (load_4(b + 7) >> 7);
        //    int64_t b4  = 2097151 & (load_4(b + 10) >> 4);
        //    int64_t b5  = 2097151 & (load_3(b + 13) >> 1);
        //    int64_t b6  = 2097151 & (load_4(b + 15) >> 6);
        //    int64_t b7  = 2097151 & (load_3(b + 18) >> 3);
        //    int64_t b8  = 2097151 & load_3(b + 21);
        //    int64_t b9  = 2097151 & (load_4(b + 23) >> 5);
        //    int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
        //    int64_t b11 = (load_4(b + 28) >> 7);
        $b0  = 2097151 &  self::load_3(self::substr($b, 0, 3));
        $b1  = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5);
        $b2  = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2);
        $b3  = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7);
        $b4  = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4);
        $b5  = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1);
        $b6  = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6);
        $b7  = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3);
        $b8  = 2097151 &  self::load_3(self::substr($b, 21, 3));
        $b9  = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5);
        $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2);
        $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7);

        //    s0 = a0 * b0;
        //    s1 = a0 * b1 + a1 * b0;
        //    s2 = a0 * b2 + a1 * b1 + a2 * b0;
        //    s3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
        //    s4 = a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
        //    s5 = a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
        //    s6 = a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
        //    s7 = a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 +
        //        a6 * b1 + a7 * b0;
        //    s8 = a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 +
        //        a6 * b2 + a7 * b1 + a8 * b0;
        //    s9 = a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 +
        //        a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
        //    s10 = a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 +
        //        a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
        //    s11 = a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 +
        //        a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
        //    s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 +
        //        a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
        //    s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 +
        //        a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
        //    s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 +
        //        a9 * b5 + a10 * b4 + a11 * b3;
        //    s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 +
        //        a10 * b5 + a11 * b4;
        //    s16 =
        //        a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
        //    s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
        //    s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
        //    s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
        //    s20 = a9 * b11 + a10 * b10 + a11 * b9;
        //    s21 = a10 * b11 + a11 * b10;
        //    s22 = a11 * b11;
        //    s23 = 0;
        $s0 = self::mul($a0, $b0, 22);
        $s1 = self::mul($a0, $b1, 22) + self::mul($a1, $b0, 22);
        $s2 = self::mul($a0, $b2, 22) + self::mul($a1, $b1, 22) + self::mul($a2, $b0, 22);
        $s3 = self::mul($a0, $b3, 22) + self::mul($a1, $b2, 22) + self::mul($a2, $b1, 22) + self::mul($a3, $b0, 22);
        $s4 = self::mul($a0, $b4, 22) + self::mul($a1, $b3, 22) + self::mul($a2, $b2, 22) + self::mul($a3, $b1, 22) +
            self::mul($a4, $b0, 22);
        $s5 = self::mul($a0, $b5, 22) + self::mul($a1, $b4, 22) + self::mul($a2, $b3, 22) + self::mul($a3, $b2, 22) +
            self::mul($a4, $b1, 22) + self::mul($a5, $b0, 22);
        $s6 = self::mul($a0, $b6, 22) + self::mul($a1, $b5, 22) + self::mul($a2, $b4, 22) + self::mul($a3, $b3, 22) +
            self::mul($a4, $b2, 22) + self::mul($a5, $b1, 22) + self::mul($a6, $b0, 22);
        $s7 = self::mul($a0, $b7, 22) + self::mul($a1, $b6, 22) + self::mul($a2, $b5, 22) + self::mul($a3, $b4, 22) +
            self::mul($a4, $b3, 22) + self::mul($a5, $b2, 22) + self::mul($a6, $b1, 22) + self::mul($a7, $b0, 22);
        $s8 = self::mul($a0, $b8, 22) + self::mul($a1, $b7, 22) + self::mul($a2, $b6, 22) + self::mul($a3, $b5, 22) +
            self::mul($a4, $b4, 22) + self::mul($a5, $b3, 22) + self::mul($a6, $b2, 22) + self::mul($a7, $b1, 22) +
            self::mul($a8, $b0, 22);
        $s9 = self::mul($a0, $b9, 22) + self::mul($a1, $b8, 22) + self::mul($a2, $b7, 22) + self::mul($a3, $b6, 22) +
            self::mul($a4, $b5, 22) + self::mul($a5, $b4, 22) + self::mul($a6, $b3, 22) + self::mul($a7, $b2, 22) +
            self::mul($a8, $b1, 22) + self::mul($a9, $b0, 22);
        $s10 = self::mul($a0, $b10, 22) + self::mul($a1, $b9, 22) + self::mul($a2, $b8, 22) + self::mul($a3, $b7, 22) +
            self::mul($a4, $b6, 22) + self::mul($a5, $b5, 22) + self::mul($a6, $b4, 22) + self::mul($a7, $b3, 22) +
            self::mul($a8, $b2, 22) + self::mul($a9, $b1, 22) + self::mul($a10, $b0, 22);
        $s11 = self::mul($a0, $b11, 22) + self::mul($a1, $b10, 22) + self::mul($a2, $b9, 22) + self::mul($a3, $b8, 22) +
            self::mul($a4, $b7, 22) + self::mul($a5, $b6, 22) + self::mul($a6, $b5, 22) + self::mul($a7, $b4, 22) +
            self::mul($a8, $b3, 22) + self::mul($a9, $b2, 22) + self::mul($a10, $b1, 22) + self::mul($a11, $b0, 22);
        $s12 = self::mul($a1, $b11, 22) + self::mul($a2, $b10, 22) + self::mul($a3, $b9, 22) + self::mul($a4, $b8, 22) +
            self::mul($a5, $b7, 22) + self::mul($a6, $b6, 22) + self::mul($a7, $b5, 22) + self::mul($a8, $b4, 22) +
            self::mul($a9, $b3, 22) + self::mul($a10, $b2, 22) + self::mul($a11, $b1, 22);
        $s13 = self::mul($a2, $b11, 22) + self::mul($a3, $b10, 22) + self::mul($a4, $b9, 22) + self::mul($a5, $b8, 22) +
            self::mul($a6, $b7, 22) + self::mul($a7, $b6, 22) + self::mul($a8, $b5, 22) + self::mul($a9, $b4, 22) +
            self::mul($a10, $b3, 22) + self::mul($a11, $b2, 22);
        $s14 = self::mul($a3, $b11, 22) + self::mul($a4, $b10, 22) + self::mul($a5, $b9, 22) + self::mul($a6, $b8, 22) +
            self::mul($a7, $b7, 22) + self::mul($a8, $b6, 22) + self::mul($a9, $b5, 22) + self::mul($a10, $b4, 22) +
            self::mul($a11, $b3, 22);
        $s15 = self::mul($a4, $b11, 22) + self::mul($a5, $b10, 22) + self::mul($a6, $b9, 22) + self::mul($a7, $b8, 22) +
            self::mul($a8, $b7, 22) + self::mul($a9, $b6, 22) + self::mul($a10, $b5, 22) + self::mul($a11, $b4, 22);
        $s16 =
            self::mul($a5, $b11, 22) + self::mul($a6, $b10, 22) + self::mul($a7, $b9, 22) + self::mul($a8, $b8, 22) +
            self::mul($a9, $b7, 22) + self::mul($a10, $b6, 22) + self::mul($a11, $b5, 22);
        $s17 = self::mul($a6, $b11, 22) + self::mul($a7, $b10, 22) + self::mul($a8, $b9, 22) + self::mul($a9, $b8, 22) +
            self::mul($a10, $b7, 22) + self::mul($a11, $b6, 22);
        $s18 = self::mul($a7, $b11, 22) + self::mul($a8, $b10, 22) + self::mul($a9, $b9, 22) + self::mul($a10, $b8, 22)
            + self::mul($a11, $b7, 22);
        $s19 = self::mul($a8, $b11, 22) + self::mul($a9, $b10, 22) + self::mul($a10, $b9, 22) +
            self::mul($a11, $b8, 22);
        $s20 = self::mul($a9, $b11, 22) + self::mul($a10, $b10, 22) + self::mul($a11, $b9, 22);
        $s21 = self::mul($a10, $b11, 22) + self::mul($a11, $b10, 22);
        $s22 = self::mul($a11, $b11, 22);
        $s23 = 0;

        //    carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
        //    s1 += carry0;
        //    s0 -= carry0 * ((uint64_t) 1L << 21);
        $carry0 = ($s0 + (1 << 20)) >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        //    carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
        //    s3 += carry2;
        //    s2 -= carry2 * ((uint64_t) 1L << 21);
        $carry2 = ($s2 + (1 << 20)) >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        //    carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
        //    s5 += carry4;
        //    s4 -= carry4 * ((uint64_t) 1L << 21);
        $carry4 = ($s4 + (1 << 20)) >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
        //    s7 += carry6;
        //    s6 -= carry6 * ((uint64_t) 1L << 21);
        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
        //    s9 += carry8;
        //    s8 -= carry8 * ((uint64_t) 1L << 21);
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
        //    s11 += carry10;
        //    s10 -= carry10 * ((uint64_t) 1L << 21);
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        //    carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
        //    s13 += carry12;
        //    s12 -= carry12 * ((uint64_t) 1L << 21);
        $carry12 = ($s12 + (1 << 20)) >> 21;
        $s13 += $carry12;
        $s12 -= $carry12 << 21;
        //    carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
        //    s15 += carry14;
        //    s14 -= carry14 * ((uint64_t) 1L << 21);
        $carry14 = ($s14 + (1 << 20)) >> 21;
        $s15 += $carry14;
        $s14 -= $carry14 << 21;
        //    carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
        //    s17 += carry16;
        //    s16 -= carry16 * ((uint64_t) 1L << 21);
        $carry16 = ($s16 + (1 << 20)) >> 21;
        $s17 += $carry16;
        $s16 -= $carry16 << 21;
        //    carry18 = (s18 + (int64_t) (1L << 20)) >> 21;
        //    s19 += carry18;
        //    s18 -= carry18 * ((uint64_t) 1L << 21);
        $carry18 = ($s18 + (1 << 20)) >> 21;
        $s19 += $carry18;
        $s18 -= $carry18 << 21;
        //    carry20 = (s20 + (int64_t) (1L << 20)) >> 21;
        //    s21 += carry20;
        //    s20 -= carry20 * ((uint64_t) 1L << 21);
        $carry20 = ($s20 + (1 << 20)) >> 21;
        $s21 += $carry20;
        $s20 -= $carry20 << 21;
        //    carry22 = (s22 + (int64_t) (1L << 20)) >> 21;
        //    s23 += carry22;
        //    s22 -= carry22 * ((uint64_t) 1L << 21);
        $carry22 = ($s22 + (1 << 20)) >> 21;
        $s23 += $carry22;
        $s22 -= $carry22 << 21;

        //    carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
        //    s2 += carry1;
        //    s1 -= carry1 * ((uint64_t) 1L << 21);
        $carry1 = ($s1 + (1 << 20)) >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        //    carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
        //    s4 += carry3;
        //    s3 -= carry3 * ((uint64_t) 1L << 21);
        $carry3 = ($s3 + (1 << 20)) >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        //    carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
        //    s6 += carry5;
        //    s5 -= carry5 * ((uint64_t) 1L << 21);
        $carry5 = ($s5 + (1 << 20)) >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
        //    s8 += carry7;
        //    s7 -= carry7 * ((uint64_t) 1L << 21);
        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
        //    s10 += carry9;
        //    s9 -= carry9 * ((uint64_t) 1L << 21);
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
        //    s12 += carry11;
        //    s11 -= carry11 * ((uint64_t) 1L << 21);
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;
        //    carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
        //    s14 += carry13;
        //    s13 -= carry13 * ((uint64_t) 1L << 21);
        $carry13 = ($s13 + (1 << 20)) >> 21;
        $s14 += $carry13;
        $s13 -= $carry13 << 21;
        //    carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
        //    s16 += carry15;
        //    s15 -= carry15 * ((uint64_t) 1L << 21);
        $carry15 = ($s15 + (1 << 20)) >> 21;
        $s16 += $carry15;
        $s15 -= $carry15 << 21;
        //    carry17 = (s17 + (int64_t) (1L << 20)) >> 21;
        //    s18 += carry17;
        //    s17 -= carry17 * ((uint64_t) 1L << 21);
        $carry17 = ($s17 + (1 << 20)) >> 21;
        $s18 += $carry17;
        $s17 -= $carry17 << 21;
        //    carry19 = (s19 + (int64_t) (1L << 20)) >> 21;
        //    s20 += carry19;
        //    s19 -= carry19 * ((uint64_t) 1L << 21);
        $carry19 = ($s19 + (1 << 20)) >> 21;
        $s20 += $carry19;
        $s19 -= $carry19 << 21;
        //    carry21 = (s21 + (int64_t) (1L << 20)) >> 21;
        //    s22 += carry21;
        //    s21 -= carry21 * ((uint64_t) 1L << 21);
        $carry21 = ($s21 + (1 << 20)) >> 21;
        $s22 += $carry21;
        $s21 -= $carry21 << 21;

        //    s11 += s23 * 666643;
        //    s12 += s23 * 470296;
        //    s13 += s23 * 654183;
        //    s14 -= s23 * 997805;
        //    s15 += s23 * 136657;
        //    s16 -= s23 * 683901;
        $s11 += self::mul($s23, 666643, 20);
        $s12 += self::mul($s23, 470296, 19);
        $s13 += self::mul($s23, 654183, 20);
        $s14 -= self::mul($s23, 997805, 20);
        $s15 += self::mul($s23, 136657, 18);
        $s16 -= self::mul($s23, 683901, 20);

        //    s10 += s22 * 666643;
        //    s11 += s22 * 470296;
        //    s12 += s22 * 654183;
        //    s13 -= s22 * 997805;
        //    s14 += s22 * 136657;
        //    s15 -= s22 * 683901;
        $s10 += self::mul($s22, 666643, 20);
        $s11 += self::mul($s22, 470296, 19);
        $s12 += self::mul($s22, 654183, 20);
        $s13 -= self::mul($s22, 997805, 20);
        $s14 += self::mul($s22, 136657, 18);
        $s15 -= self::mul($s22, 683901, 20);

        //    s9 += s21 * 666643;
        //    s10 += s21 * 470296;
        //    s11 += s21 * 654183;
        //    s12 -= s21 * 997805;
        //    s13 += s21 * 136657;
        //    s14 -= s21 * 683901;
        $s9 += self::mul($s21, 666643, 20);
        $s10 += self::mul($s21, 470296, 19);
        $s11 += self::mul($s21, 654183, 20);
        $s12 -= self::mul($s21, 997805, 20);
        $s13 += self::mul($s21, 136657, 18);
        $s14 -= self::mul($s21, 683901, 20);

        //    s8 += s20 * 666643;
        //    s9 += s20 * 470296;
        //    s10 += s20 * 654183;
        //    s11 -= s20 * 997805;
        //    s12 += s20 * 136657;
        //    s13 -= s20 * 683901;
        $s8 += self::mul($s20, 666643, 20);
        $s9 += self::mul($s20, 470296, 19);
        $s10 += self::mul($s20, 654183, 20);
        $s11 -= self::mul($s20, 997805, 20);
        $s12 += self::mul($s20, 136657, 18);
        $s13 -= self::mul($s20, 683901, 20);

        //    s7 += s19 * 666643;
        //    s8 += s19 * 470296;
        //    s9 += s19 * 654183;
        //    s10 -= s19 * 997805;
        //    s11 += s19 * 136657;
        //    s12 -= s19 * 683901;
        $s7 += self::mul($s19, 666643, 20);
        $s8 += self::mul($s19, 470296, 19);
        $s9 += self::mul($s19, 654183, 20);
        $s10 -= self::mul($s19, 997805, 20);
        $s11 += self::mul($s19, 136657, 18);
        $s12 -= self::mul($s19, 683901, 20);

        //    s6 += s18 * 666643;
        //    s7 += s18 * 470296;
        //    s8 += s18 * 654183;
        //    s9 -= s18 * 997805;
        //    s10 += s18 * 136657;
        //    s11 -= s18 * 683901;
        $s6 += self::mul($s18, 666643, 20);
        $s7 += self::mul($s18, 470296, 19);
        $s8 += self::mul($s18, 654183, 20);
        $s9 -= self::mul($s18, 997805, 20);
        $s10 += self::mul($s18, 136657, 18);
        $s11 -= self::mul($s18, 683901, 20);

        //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
        //    s7 += carry6;
        //    s6 -= carry6 * ((uint64_t) 1L << 21);
        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
        //    s9 += carry8;
        //    s8 -= carry8 * ((uint64_t) 1L << 21);
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
        //    s11 += carry10;
        //    s10 -= carry10 * ((uint64_t) 1L << 21);
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        //    carry12 = (s12 + (int64_t) (1L << 20)) >> 21;
        //    s13 += carry12;
        //    s12 -= carry12 * ((uint64_t) 1L << 21);
        $carry12 = ($s12 + (1 << 20)) >> 21;
        $s13 += $carry12;
        $s12 -= $carry12 << 21;
        //    carry14 = (s14 + (int64_t) (1L << 20)) >> 21;
        //    s15 += carry14;
        //    s14 -= carry14 * ((uint64_t) 1L << 21);
        $carry14 = ($s14 + (1 << 20)) >> 21;
        $s15 += $carry14;
        $s14 -= $carry14 << 21;
        //    carry16 = (s16 + (int64_t) (1L << 20)) >> 21;
        //    s17 += carry16;
        //    s16 -= carry16 * ((uint64_t) 1L << 21);
        $carry16 = ($s16 + (1 << 20)) >> 21;
        $s17 += $carry16;
        $s16 -= $carry16 << 21;

        //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
        //    s8 += carry7;
        //    s7 -= carry7 * ((uint64_t) 1L << 21);
        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
        //    s10 += carry9;
        //    s9 -= carry9 * ((uint64_t) 1L << 21);
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
        //    s12 += carry11;
        //    s11 -= carry11 * ((uint64_t) 1L << 21);
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;
        //    carry13 = (s13 + (int64_t) (1L << 20)) >> 21;
        //    s14 += carry13;
        //    s13 -= carry13 * ((uint64_t) 1L << 21);
        $carry13 = ($s13 + (1 << 20)) >> 21;
        $s14 += $carry13;
        $s13 -= $carry13 << 21;
        //    carry15 = (s15 + (int64_t) (1L << 20)) >> 21;
        //    s16 += carry15;
        //    s15 -= carry15 * ((uint64_t) 1L << 21);
        $carry15 = ($s15 + (1 << 20)) >> 21;
        $s16 += $carry15;
        $s15 -= $carry15 << 21;

        //    s5 += s17 * 666643;
        //    s6 += s17 * 470296;
        //    s7 += s17 * 654183;
        //    s8 -= s17 * 997805;
        //    s9 += s17 * 136657;
        //    s10 -= s17 * 683901;
        $s5 += self::mul($s17, 666643, 20);
        $s6 += self::mul($s17, 470296, 19);
        $s7 += self::mul($s17, 654183, 20);
        $s8 -= self::mul($s17, 997805, 20);
        $s9 += self::mul($s17, 136657, 18);
        $s10 -= self::mul($s17, 683901, 20);

        //    s4 += s16 * 666643;
        //    s5 += s16 * 470296;
        //    s6 += s16 * 654183;
        //    s7 -= s16 * 997805;
        //    s8 += s16 * 136657;
        //    s9 -= s16 * 683901;
        $s4 += self::mul($s16, 666643, 20);
        $s5 += self::mul($s16, 470296, 19);
        $s6 += self::mul($s16, 654183, 20);
        $s7 -= self::mul($s16, 997805, 20);
        $s8 += self::mul($s16, 136657, 18);
        $s9 -= self::mul($s16, 683901, 20);

        //    s3 += s15 * 666643;
        //    s4 += s15 * 470296;
        //    s5 += s15 * 654183;
        //    s6 -= s15 * 997805;
        //    s7 += s15 * 136657;
        //    s8 -= s15 * 683901;
        $s3 += self::mul($s15, 666643, 20);
        $s4 += self::mul($s15, 470296, 19);
        $s5 += self::mul($s15, 654183, 20);
        $s6 -= self::mul($s15, 997805, 20);
        $s7 += self::mul($s15, 136657, 18);
        $s8 -= self::mul($s15, 683901, 20);

        //    s2 += s14 * 666643;
        //    s3 += s14 * 470296;
        //    s4 += s14 * 654183;
        //    s5 -= s14 * 997805;
        //    s6 += s14 * 136657;
        //    s7 -= s14 * 683901;
        $s2 += self::mul($s14, 666643, 20);
        $s3 += self::mul($s14, 470296, 19);
        $s4 += self::mul($s14, 654183, 20);
        $s5 -= self::mul($s14, 997805, 20);
        $s6 += self::mul($s14, 136657, 18);
        $s7 -= self::mul($s14, 683901, 20);

        //    s1 += s13 * 666643;
        //    s2 += s13 * 470296;
        //    s3 += s13 * 654183;
        //    s4 -= s13 * 997805;
        //    s5 += s13 * 136657;
        //    s6 -= s13 * 683901;
        $s1 += self::mul($s13, 666643, 20);
        $s2 += self::mul($s13, 470296, 19);
        $s3 += self::mul($s13, 654183, 20);
        $s4 -= self::mul($s13, 997805, 20);
        $s5 += self::mul($s13, 136657, 18);
        $s6 -= self::mul($s13, 683901, 20);

        //    s0 += s12 * 666643;
        //    s1 += s12 * 470296;
        //    s2 += s12 * 654183;
        //    s3 -= s12 * 997805;
        //    s4 += s12 * 136657;
        //    s5 -= s12 * 683901;
        //    s12 = 0;
        $s0 += self::mul($s12, 666643, 20);
        $s1 += self::mul($s12, 470296, 19);
        $s2 += self::mul($s12, 654183, 20);
        $s3 -= self::mul($s12, 997805, 20);
        $s4 += self::mul($s12, 136657, 18);
        $s5 -= self::mul($s12, 683901, 20);
        $s12 = 0;

        //    carry0 = (s0 + (int64_t) (1L << 20)) >> 21;
        //    s1 += carry0;
        //    s0 -= carry0 * ((uint64_t) 1L << 21);
        $carry0 = ($s0 + (1 << 20)) >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        //    carry2 = (s2 + (int64_t) (1L << 20)) >> 21;
        //    s3 += carry2;
        //    s2 -= carry2 * ((uint64_t) 1L << 21);
        $carry2 = ($s2 + (1 << 20)) >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        //    carry4 = (s4 + (int64_t) (1L << 20)) >> 21;
        //    s5 += carry4;
        //    s4 -= carry4 * ((uint64_t) 1L << 21);
        $carry4 = ($s4 + (1 << 20)) >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        //    carry6 = (s6 + (int64_t) (1L << 20)) >> 21;
        //    s7 += carry6;
        //    s6 -= carry6 * ((uint64_t) 1L << 21);
        $carry6 = ($s6 + (1 << 20)) >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        //    carry8 = (s8 + (int64_t) (1L << 20)) >> 21;
        //    s9 += carry8;
        //    s8 -= carry8 * ((uint64_t) 1L << 21);
        $carry8 = ($s8 + (1 << 20)) >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        //    carry10 = (s10 + (int64_t) (1L << 20)) >> 21;
        //    s11 += carry10;
        //    s10 -= carry10 * ((uint64_t) 1L << 21);
        $carry10 = ($s10 + (1 << 20)) >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;

        //    carry1 = (s1 + (int64_t) (1L << 20)) >> 21;
        //    s2 += carry1;
        //    s1 -= carry1 * ((uint64_t) 1L << 21);
        $carry1 = ($s1 + (1 << 20)) >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        //    carry3 = (s3 + (int64_t) (1L << 20)) >> 21;
        //    s4 += carry3;
        //    s3 -= carry3 * ((uint64_t) 1L << 21);
        $carry3 = ($s3 + (1 << 20)) >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        //    carry5 = (s5 + (int64_t) (1L << 20)) >> 21;
        //    s6 += carry5;
        //    s5 -= carry5 * ((uint64_t) 1L << 21);
        $carry5 = ($s5 + (1 << 20)) >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        //    carry7 = (s7 + (int64_t) (1L << 20)) >> 21;
        //    s8 += carry7;
        //    s7 -= carry7 * ((uint64_t) 1L << 21);
        $carry7 = ($s7 + (1 << 20)) >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        //    carry9 = (s9 + (int64_t) (1L << 20)) >> 21;
        //    s10 += carry9;
        //    s9 -= carry9 * ((uint64_t) 1L << 21);
        $carry9 = ($s9 + (1 << 20)) >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        //    carry11 = (s11 + (int64_t) (1L << 20)) >> 21;
        //    s12 += carry11;
        //    s11 -= carry11 * ((uint64_t) 1L << 21);
        $carry11 = ($s11 + (1 << 20)) >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;

        //    s0 += s12 * 666643;
        //    s1 += s12 * 470296;
        //    s2 += s12 * 654183;
        //    s3 -= s12 * 997805;
        //    s4 += s12 * 136657;
        //    s5 -= s12 * 683901;
        //    s12 = 0;
        $s0 += self::mul($s12, 666643, 20);
        $s1 += self::mul($s12, 470296, 19);
        $s2 += self::mul($s12, 654183, 20);
        $s3 -= self::mul($s12, 997805, 20);
        $s4 += self::mul($s12, 136657, 18);
        $s5 -= self::mul($s12, 683901, 20);
        $s12 = 0;

        //    carry0 = s0 >> 21;
        //    s1 += carry0;
        //    s0 -= carry0 * ((uint64_t) 1L << 21);
        $carry0 = $s0 >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        //    carry1 = s1 >> 21;
        //    s2 += carry1;
        //    s1 -= carry1 * ((uint64_t) 1L << 21);
        $carry1 = $s1 >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        //    carry2 = s2 >> 21;
        //    s3 += carry2;
        //    s2 -= carry2 * ((uint64_t) 1L << 21);
        $carry2 = $s2 >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        //    carry3 = s3 >> 21;
        //    s4 += carry3;
        //    s3 -= carry3 * ((uint64_t) 1L << 21);
        $carry3 = $s3 >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        //    carry4 = s4 >> 21;
        //    s5 += carry4;
        //    s4 -= carry4 * ((uint64_t) 1L << 21);
        $carry4 = $s4 >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        //    carry5 = s5 >> 21;
        //    s6 += carry5;
        //    s5 -= carry5 * ((uint64_t) 1L << 21);
        $carry5 = $s5 >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        //    carry6 = s6 >> 21;
        //    s7 += carry6;
        //    s6 -= carry6 * ((uint64_t) 1L << 21);
        $carry6 = $s6 >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        //    carry7 = s7 >> 21;
        //    s8 += carry7;
        //    s7 -= carry7 * ((uint64_t) 1L << 21);
        $carry7 = $s7 >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        //    carry8 = s8 >> 21;
        //    s9 += carry8;
        //    s8 -= carry8 * ((uint64_t) 1L << 21);
        $carry8 = $s8 >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        //    carry9 = s9 >> 21;
        //    s10 += carry9;
        //    s9 -= carry9 * ((uint64_t) 1L << 21);
        $carry9 = $s9 >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        //    carry10 = s10 >> 21;
        //    s11 += carry10;
        //    s10 -= carry10 * ((uint64_t) 1L << 21);
        $carry10 = $s10 >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;
        //    carry11 = s11 >> 21;
        //    s12 += carry11;
        //    s11 -= carry11 * ((uint64_t) 1L << 21);
        $carry11 = $s11 >> 21;
        $s12 += $carry11;
        $s11 -= $carry11 << 21;

        //    s0 += s12 * 666643;
        //    s1 += s12 * 470296;
        //    s2 += s12 * 654183;
        //    s3 -= s12 * 997805;
        //    s4 += s12 * 136657;
        //    s5 -= s12 * 683901;
        $s0 += self::mul($s12, 666643, 20);
        $s1 += self::mul($s12, 470296, 19);
        $s2 += self::mul($s12, 654183, 20);
        $s3 -= self::mul($s12, 997805, 20);
        $s4 += self::mul($s12, 136657, 18);
        $s5 -= self::mul($s12, 683901, 20);

        //    carry0 = s0 >> 21;
        //    s1 += carry0;
        //    s0 -= carry0 * ((uint64_t) 1L << 21);
        $carry0 = $s0 >> 21;
        $s1 += $carry0;
        $s0 -= $carry0 << 21;
        //    carry1 = s1 >> 21;
        //    s2 += carry1;
        //    s1 -= carry1 * ((uint64_t) 1L << 21);
        $carry1 = $s1 >> 21;
        $s2 += $carry1;
        $s1 -= $carry1 << 21;
        //    carry2 = s2 >> 21;
        //    s3 += carry2;
        //    s2 -= carry2 * ((uint64_t) 1L << 21);
        $carry2 = $s2 >> 21;
        $s3 += $carry2;
        $s2 -= $carry2 << 21;
        //    carry3 = s3 >> 21;
        //    s4 += carry3;
        //    s3 -= carry3 * ((uint64_t) 1L << 21);
        $carry3 = $s3 >> 21;
        $s4 += $carry3;
        $s3 -= $carry3 << 21;
        //    carry4 = s4 >> 21;
        //    s5 += carry4;
        //    s4 -= carry4 * ((uint64_t) 1L << 21);
        $carry4 = $s4 >> 21;
        $s5 += $carry4;
        $s4 -= $carry4 << 21;
        //    carry5 = s5 >> 21;
        //    s6 += carry5;
        //    s5 -= carry5 * ((uint64_t) 1L << 21);
        $carry5 = $s5 >> 21;
        $s6 += $carry5;
        $s5 -= $carry5 << 21;
        //    carry6 = s6 >> 21;
        //    s7 += carry6;
        //    s6 -= carry6 * ((uint64_t) 1L << 21);
        $carry6 = $s6 >> 21;
        $s7 += $carry6;
        $s6 -= $carry6 << 21;
        //    carry7 = s7 >> 21;
        //    s8 += carry7;
        //    s7 -= carry7 * ((uint64_t) 1L << 21);
        $carry7 = $s7 >> 21;
        $s8 += $carry7;
        $s7 -= $carry7 << 21;
        //    carry8 = s8 >> 21;
        //    s9 += carry8;
        //    s8 -= carry8 * ((uint64_t) 1L << 21);
        $carry8 = $s8 >> 21;
        $s9 += $carry8;
        $s8 -= $carry8 << 21;
        //    carry9 = s9 >> 21;
        //    s10 += carry9;
        //    s9 -= carry9 * ((uint64_t) 1L << 21);
        $carry9 = $s9 >> 21;
        $s10 += $carry9;
        $s9 -= $carry9 << 21;
        //    carry10 = s10 >> 21;
        //    s11 += carry10;
        //    s10 -= carry10 * ((uint64_t) 1L << 21);
        $carry10 = $s10 >> 21;
        $s11 += $carry10;
        $s10 -= $carry10 << 21;

        $s = array_fill(0, 32, 0);
        // s[0]  = s0 >> 0;
        $s[0]  = $s0 >> 0;
        // s[1]  = s0 >> 8;
        $s[1]  = $s0 >> 8;
        // s[2]  = (s0 >> 16) | (s1 * ((uint64_t) 1 << 5));
        $s[2]  = ($s0 >> 16) | ($s1 << 5);
        // s[3]  = s1 >> 3;
        $s[3]  = $s1 >> 3;
        // s[4]  = s1 >> 11;
        $s[4]  = $s1 >> 11;
        // s[5]  = (s1 >> 19) | (s2 * ((uint64_t) 1 << 2));
        $s[5]  = ($s1 >> 19) | ($s2 << 2);
        // s[6]  = s2 >> 6;
        $s[6]  = $s2 >> 6;
        // s[7]  = (s2 >> 14) | (s3 * ((uint64_t) 1 << 7));
        $s[7]  = ($s2 >> 14) | ($s3 << 7);
        // s[8]  = s3 >> 1;
        $s[8]  = $s3 >> 1;
        // s[9]  = s3 >> 9;
        $s[9]  = $s3 >> 9;
        // s[10] = (s3 >> 17) | (s4 * ((uint64_t) 1 << 4));
        $s[10] = ($s3 >> 17) | ($s4 << 4);
        // s[11] = s4 >> 4;
        $s[11] = $s4 >> 4;
        // s[12] = s4 >> 12;
        $s[12] = $s4 >> 12;
        // s[13] = (s4 >> 20) | (s5 * ((uint64_t) 1 << 1));
        $s[13] = ($s4 >> 20) | ($s5 << 1);
        // s[14] = s5 >> 7;
        $s[14] = $s5 >> 7;
        // s[15] = (s5 >> 15) | (s6 * ((uint64_t) 1 << 6));
        $s[15] = ($s5 >> 15) | ($s6 << 6);
        // s[16] = s6 >> 2;
        $s[16] = $s6 >> 2;
        // s[17] = s6 >> 10;
        $s[17] = $s6 >> 10;
        // s[18] = (s6 >> 18) | (s7 * ((uint64_t) 1 << 3));
        $s[18] = ($s6 >> 18) | ($s7 << 3);
        // s[19] = s7 >> 5;
        $s[19] = $s7 >> 5;
        // s[20] = s7 >> 13;
        $s[20] = $s7 >> 13;
        // s[21] = s8 >> 0;
        $s[21] = $s8 >> 0;
        // s[22] = s8 >> 8;
        $s[22] = $s8 >> 8;
        // s[23] = (s8 >> 16) | (s9 * ((uint64_t) 1 << 5));
        $s[23] = ($s8 >> 16) | ($s9 << 5);
        // s[24] = s9 >> 3;
        $s[24] = $s9 >> 3;
        // s[25] = s9 >> 11;
        $s[25] = $s9 >> 11;
        // s[26] = (s9 >> 19) | (s10 * ((uint64_t) 1 << 2));
        $s[26] = ($s9 >> 19) | ($s10 << 2);
        // s[27] = s10 >> 6;
        $s[27] = $s10 >> 6;
        // s[28] = (s10 >> 14) | (s11 * ((uint64_t) 1 << 7));
        $s[28] = ($s10 >> 14) | ($s11 << 7);
        // s[29] = s11 >> 1;
        $s[29] = $s11 >> 1;
        // s[30] = s11 >> 9;
        $s[30] = $s11 >> 9;
        // s[31] = s11 >> 17;
        $s[31] = $s11 >> 17;
        return self::intArrayToString($s);
    }

    /**
     * @param string $s
     * @return string
     */
    public static function sc25519_sq($s)
    {
        return self::sc25519_mul($s, $s);
    }

    /**
     * @param string $s
     * @param int $n
     * @param string $a
     * @return string
     */
    public static function sc25519_sqmul($s, $n, $a)
    {
        for ($i = 0; $i < $n; ++$i) {
            $s = self::sc25519_sq($s);
        }
        return self::sc25519_mul($s, $a);
    }

    /**
     * @param string $s
     * @return string
     */
    public static function sc25519_invert($s)
    {
        $_10 = self::sc25519_sq($s);
        $_11 = self::sc25519_mul($s, $_10);
        $_100 = self::sc25519_mul($s, $_11);
        $_1000 = self::sc25519_sq($_100);
        $_1010 = self::sc25519_mul($_10, $_1000);
        $_1011 = self::sc25519_mul($s, $_1010);
        $_10000 = self::sc25519_sq($_1000);
        $_10110 = self::sc25519_sq($_1011);
        $_100000 = self::sc25519_mul($_1010, $_10110);
        $_100110 = self::sc25519_mul($_10000, $_10110);
        $_1000000 = self::sc25519_sq($_100000);
        $_1010000 = self::sc25519_mul($_10000, $_1000000);
        $_1010011 = self::sc25519_mul($_11, $_1010000);
        $_1100011 = self::sc25519_mul($_10000, $_1010011);
        $_1100111 = self::sc25519_mul($_100, $_1100011);
        $_1101011 = self::sc25519_mul($_100, $_1100111);
        $_10010011 = self::sc25519_mul($_1000000, $_1010011);
        $_10010111 = self::sc25519_mul($_100, $_10010011);
        $_10111101 = self::sc25519_mul($_100110, $_10010111);
        $_11010011 = self::sc25519_mul($_10110, $_10111101);
        $_11100111 = self::sc25519_mul($_1010000, $_10010111);
        $_11101011 = self::sc25519_mul($_100, $_11100111);
        $_11110101 = self::sc25519_mul($_1010, $_11101011);

        $recip = self::sc25519_mul($_1011, $_11110101);
        $recip = self::sc25519_sqmul($recip, 126, $_1010011);
        $recip = self::sc25519_sqmul($recip, 9, $_10);
        $recip = self::sc25519_mul($recip, $_11110101);
        $recip = self::sc25519_sqmul($recip, 7, $_1100111);
        $recip = self::sc25519_sqmul($recip, 9, $_11110101);
        $recip = self::sc25519_sqmul($recip, 11, $_10111101);
        $recip = self::sc25519_sqmul($recip, 8, $_11100111);
        $recip = self::sc25519_sqmul($recip, 9, $_1101011);
        $recip = self::sc25519_sqmul($recip, 6, $_1011);
        $recip = self::sc25519_sqmul($recip, 14, $_10010011);
        $recip = self::sc25519_sqmul($recip, 10, $_1100011);
        $recip = self::sc25519_sqmul($recip, 9, $_10010111);
        $recip = self::sc25519_sqmul($recip, 10, $_11110101);
        $recip = self::sc25519_sqmul($recip, 8, $_11010011);
        return self::sc25519_sqmul($recip, 8, $_11101011);
    }

    /**
     * @param string $s
     * @return string
     */
    public static function clamp($s)
    {
        $s_ = self::stringToIntArray($s);
        $s_[0] &= 248;
        $s_[31] |= 64;
        $s_[31] &= 128;
        return self::intArrayToString($s_);
    }

    /**
     * Ensure limbs are less than 28 bits long to prevent float promotion.
     *
     * This uses a constant-time conditional swap under the hood.
     *
     * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
     * @return ParagonIE_Sodium_Core_Curve25519_Fe
     */
    public static function fe_normalize(ParagonIE_Sodium_Core_Curve25519_Fe $f)
    {
        $x = (PHP_INT_SIZE << 3) - 1; // 31 or 63

        $g = self::fe_copy($f);
        for ($i = 0; $i < 10; ++$i) {
            $mask = -(($g[$i] >> $x) & 1);

            /*
             * Get two candidate normalized values for $g[$i], depending on the sign of $g[$i]:
             */
            $a = $g[$i] & 0x7ffffff;
            $b = -((-$g[$i]) & 0x7ffffff);

            /*
             * Return the appropriate candidate value, based on the sign of the original input:
             *
             * The following is equivalent to this ternary:
             *
             * $g[$i] = (($g[$i] >> $x) & 1) ? $a : $b;
             *
             * Except what's written doesn't contain timing leaks.
             */
            $g[$i] = ($a ^ (($a ^ $b) & $mask));
        }
        return $g;
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit