diff --git a/publications/research-bulletins/in-prog/MRL-0006 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/biblio.bib b/publications/research-bulletins/in-prog/MRL-9999 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/biblio.bib similarity index 100% rename from publications/research-bulletins/in-prog/MRL-0006 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/biblio.bib rename to publications/research-bulletins/in-prog/MRL-9999 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/biblio.bib diff --git a/publications/research-bulletins/in-prog/MRL-0006 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/main.tex b/publications/research-bulletins/in-prog/MRL-9999 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/main.tex similarity index 100% rename from publications/research-bulletins/in-prog/MRL-0006 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/main.tex rename to publications/research-bulletins/in-prog/MRL-9999 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/main.tex diff --git a/publications/research-bulletins/in-prog/MRL-0006 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/mrl.cls b/publications/research-bulletins/in-prog/MRL-9999 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/mrl.cls similarity index 100% rename from publications/research-bulletins/in-prog/MRL-0006 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/mrl.cls rename to publications/research-bulletins/in-prog/MRL-9999 - Difficulty Adjustment Algorithms in Cryptocurrency Protocols/mrl.cls diff --git a/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/MRL_9999a__Threshold_CryptoNote_Signatures.pdf b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/MRL_9999a__Threshold_CryptoNote_Signatures.pdf new file mode 100644 index 0000000..1c70b31 Binary files /dev/null and b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/MRL_9999a__Threshold_CryptoNote_Signatures.pdf differ diff --git a/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/biblio.bib b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/biblio.bib new file mode 100644 index 0000000..d51624f --- /dev/null +++ b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/biblio.bib @@ -0,0 +1,208 @@ +@article{nakamoto2008bitcoin, + title={{B}itcoin: {A} peer-to-peer electronic cash system}, + author={Nakamoto, Satoshi} +} + +@techreport{grenander1981abstract, + title={Abstract {I}nference}, + author={Grenander, Ulf and Ulf, Grenander}, + year={1981} +} + +@article{massey1996estimating, + title={{E}stimating the parameters of a nonhomogeneous {P}oisson process with linear rate}, + author={Massey, William A and Parker, Geraldine A and Whitt, Ward}, + journal={Telecommunication Systems}, + volume={5}, + number={2}, + pages={361--388}, + year={1996}, + publisher={Springer} +} + +@inproceedings{decker2013information, + title={{I}nformation propagation in the {B}itcoin network}, + author={Decker, Christian and Wattenhofer, Roger}, + booktitle={Peer-to-Peer Computing (P2P), 2013 IEEE Thirteenth International Conference on}, + pages={1--10}, + year={2013}, + organization={IEEE} +} + +@article{sompolinsky2013accelerating, + title={Accelerating {B}itcoin's Transaction Processing. Fast Money Grows on Trees, Not Chains.}, + author={Sompolinsky, Yonatan and Zohar, Aviv}, + journal={IACR Cryptology ePrint Archive}, + volume={2013}, + pages={881}, + year={2013} +} + +@article{macheta2014counterfeiting, + title={Counterfeiting via Merkle Tree Exploits within Virtual Currencies Employing the {C}ryptoNote Protocol}, + author={Macheta, Jan and Noether, Sarang and Noether, Surae and Smooth, Javier}, + year={2014} +} + +@incollection{eyal2014majority, + title={Majority is not enough: {B}itcoin mining is vulnerable}, + author={Eyal, Ittay and Sirer, Emin G{\"u}n}, + booktitle={Financial Cryptography and Data Security}, + pages={436--454}, + year={2014}, + publisher={Springer} +} + + +@article{kraft2015difficulty, + title={Difficulty Control for Blockchain-Based Consensus Systems}, + author={Kraft, Daniel}, + year={2015} +} + +@book{serfozo2009basics, + title={Basics of applied stochastic processes}, + author={Serfozo, Richard}, + year={2009}, + publisher={Springer Science \& Business Media} +} + +@article{miller2017empirical, + title={An Empirical Analysis of Linkability in the {M}onero Blockchain}, + author={Miller, Andrew and M{\"o}ser, Malte and Lee, Kevin and Narayanan, Arvind}, + journal={arXiv preprint arXiv:1704.04299}, + year={2017} +} + +@inproceedings{au2006constant, + title={Constant-size {ID}-based linkable and revocable-iff-linked ring signature}, + author={Au, Man Ho and Liu, Joseph K and Susilo, Willy and Yuen, Tsz Hon}, + booktitle={International Conference on Cryptology in India}, + pages={364--378}, + year={2006}, + organization={Springer} +} + +@inproceedings{au2006event, + title={Event-oriented k-times revocable-iff-linked group signatures}, + author={Au, Man Ho and Susilo, Willy and Yiu, Siu-Ming}, + booktitle={Australasian Conference on Information Security and Privacy}, + pages={223--234}, + year={2006}, + organization={Springer} +} + +@inproceedings{chandran2007ring, + title={Ring signatures of sub-linear size without random oracles}, + author={Chandran, Nishanth and Groth, Jens and Sahai, Amit}, + booktitle={International Colloquium on Automata, Languages, and Programming}, + pages={423--434}, + year={2007}, + organization={Springer} +} + +@article{kumar2017traceability, + title={A Traceability Analysis of {M}onero's Blockchain}, + author={Kumar, Amrit and Fischer, Cl{\'e}ment and Tople, Shruti and Saxena, Prateek}, + year={2017} +} + +@misc{knaccc2017, + author = {knaccc}, + title = {Potential Privacy Leaks in {M}onero and Churning}, + year = {2017}, + publisher = {GitHub}, + journal = {GitHub repository}, + howpublished = {\url{https://github.com/monero-project/monero/issues/1673#issuecomment-278509986}} +} + +@misc{kenshi2017, + author = {kenshi84}, + title = {Monero Subaddresses}, + year = {2017}, + publisher = {GitHub}, + journal = {GitHub repository}, + howpublished = {\url{https://github.com/monero-project/monero/pull/2056}} +} + +@misc{mcElrathBraid, + author = {Bob McElrath}, + title = {Braiding the Blockchain}, + year = {2017}, + howpublished = {\url{https://scalingbitcoin.org/hongkong2015/presentations/DAY2/2_breaking_the_chain_1_mcelrath.pdf}} +} + +@article{noether2016ring, + title={Ring Confidential Transactions}, + author={Noether, Shen and Mackenzie, Adam and others}, + journal={Ledger}, + volume={1}, + pages={1--18}, + year={2016} +} + +@article{T-1955, +doi = {10.2307/166755}, +title = {Applications of Game Theory in Fighter versus Bomber Combat}, +author = {T. E. Caywood and C. J. Thomas}, +journal = {Journal of the Operations Research Society of America}, +issnp = {0096-3984}, +issne = {2326-3229}, +year = {1955}, +month = {11}, +volume = {3}, +issue = {4}, +page = {402--411}, +url = {http://gen.lib.rus.ec/scimag/index.php?s=10.2307/166755}, +} + +@book{strogatz2014nonlinear, + title={Nonlinear dynamics and chaos: with applications to physics, biology, chemistry, and engineering}, + author={Strogatz, Steven H}, + year={2014}, + publisher={Westview press} +} + +@article{doob1942topics, + title={Topics in the theory of {M}arkoff chains}, + author={Doob, Joseph L}, + journal={Transactions of the American Mathematical Society}, + volume={52}, + number={1}, + pages={37--64}, + year={1942}, + publisher={JSTOR} +} + +@article{doob1945markoff, + title={{M}arkoff chains--denumerable case}, + author={Doob, Joseph L}, + journal={Transactions of the American Mathematical Society}, + volume={58}, + number={3}, + pages={455--473}, + year={1945}, + publisher={JSTOR} +} + +@article{gillespie1977exact, + title={Exact stochastic simulation of coupled chemical reactions}, + author={Gillespie, Daniel T}, + journal={The journal of physical chemistry}, + volume={81}, + number={25}, + pages={2340--2361}, + year={1977}, + publisher={ACS Publications} +} + +@article{gillespie1976general, + title={A general method for numerically simulating the stochastic time evolution of coupled chemical reactions}, + author={Gillespie, Daniel T}, + journal={Journal of computational physics}, + volume={22}, + number={4}, + pages={403--434}, + year={1976}, + publisher={Elsevier} +} diff --git a/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/main.tex b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/main.tex new file mode 100644 index 0000000..c53f7ec --- /dev/null +++ b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/main.tex @@ -0,0 +1,256 @@ +\documentclass[12pt,english]{mrl} +\usepackage{graphicx} +\usepackage{listings} +\usepackage{cite} +\usepackage{amsthm} + +\usepackage[toc,page]{appendix} + +\renewcommand{\familydefault}{\rmdefault} +\usepackage[T1]{fontenc} +\usepackage[latin9]{inputenc} +\usepackage{color} +\usepackage{babel} +\usepackage{verbatim} +\usepackage{float} +\usepackage{url} +\usepackage{amsthm} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage[unicode=true,pdfusetitle, bookmarks=true,bookmarksnumbered=false,bookmarksopen=false, breaklinks=false,pdfborder={0 0 1},backref=false,colorlinks=true]{hyperref} +\usepackage{breakurl} +\usepackage{todonotes} + + +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{amssymb,enumerate} +\usepackage{amsthm} +\usepackage{cite} +\usepackage{comment} +\usepackage[all]{xy} +%\usepackage[notref,notcite]{showkeys} +\usepackage{hyperref} +\usepackage{todonotes} + +% THEOREM ENVIRONMENTS +\newtheorem*{example}{Example} +\theoremstyle{definition} +\newtheorem{lem}{Lemma}[section] +\newtheorem{cor}[lem]{Corollary} +\newtheorem{prop}[lem]{Proposition} +\newtheorem{thm}[lem]{Theorem} +\newtheorem{soln}[]{Solution} +\newtheorem{conj}[lem]{Conjecture} +\newtheorem{Defn}[lem]{Definition} +\newtheorem{Ex}[lem]{Example} +\newtheorem{Question}[lem]{Question} +\newtheorem{Property}[lem]{Property} +\newtheorem{Properties}[lem]{Properties} +\newtheorem{Discussion}[lem]{Remark} +\newtheorem{Construction}[lem]{Construction} +\newtheorem{Notation}[lem]{Notation} +\newtheorem{Fact}[lem]{Fact} +\newtheorem{Notationdefinition}[lem]{Definition/Notation} +\newtheorem{Remarkdefinition}[lem]{Remark/Definition} +\newtheorem{rem}[lem]{Remark} +\newtheorem{Subprops}{}[lem] +\newtheorem{Para}[lem]{} +\newtheorem{Exer}[lem]{Exercise} +\newtheorem{Exerc}{Exercise} + +\newenvironment{defn}{\begin{Defn}\rm}{\end{Defn}} +\newenvironment{ex}{\begin{Ex}\rm}{\end{Ex}} +\newenvironment{question}{\begin{Question}\rm}{\end{Question}} +\newenvironment{property}{\begin{Property}\rm}{\end{Property}} +\newenvironment{properties}{\begin{Properties}\rm}{\end{Properties}} +\newenvironment{notation}{\begin{Notation}\rm}{\end{Notation}} +\newenvironment{fact}{\begin{Fact}\rm}{\end{Fact}} +\newenvironment{notationdefinition}{\begin{Notationdefinition}\rm}{\end{Notationdefinition}} +\newenvironment{remarkdefinition}{\begin{Remarkdefinition}\rm}{\end{Remarkdefinition}} +\newenvironment{subprops}{\begin{Subprops}\rm}{\end{Subprops}} +\newenvironment{para}{\begin{Para}\rm}{\end{Para}} +\newenvironment{disc}{\begin{Discussion}\rm}{\end{Discussion}} +\newenvironment{construction}{\begin{Construction}\rm}{\end{Construction}} +\newenvironment{exer}{\begin{Exer}\rm}{\end{Exer}} +\newenvironment{exerc}{\begin{Exerc}\rm}{\end{Exerc}} + +\newtheorem{intthm}{Theorem} +\renewcommand{\theintthm}{\Alph{intthm}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands. +\floatstyle{ruled} +\newfloat{algorithm}{tbp}{loa} +\providecommand{\algorithmname}{Algorithm} +\floatname{algorithm}{\protect\algorithmname} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. +\numberwithin{equation}{section} +\numberwithin{figure}{section} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. +\usepackage{algpseudocode} + +\usepackage{subcaption} + +\numberwithin{equation}{section} + + +\makeatletter + + +\makeatletter + +\newcommand{\h}{\mathcal{H}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands. +\floatstyle{ruled} +\newfloat{algorithm}{tbp}{loa} +\providecommand{\algorithmname}{Algorithm} +\floatname{algorithm}{\protect\algorithmname} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. +\numberwithin{equation}{section} +\numberwithin{figure}{section} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. +\usepackage{algpseudocode} + +\makeatother + +\begin{document} +\begin{frontmatter} + +\begin{fmbox} +{\huge\sffamily Quarterly update} \hfill\setlength{\fboxrule}{0px}\setlength{\fboxsep}{5px}\fbox{\includegraphics[width=2in]{moneroLogo.png}} +\dochead{} +\date{\today} +\author[ + addressref={mrl}, + email={bggoode@g.clemson.edu} +]{\fnm{Brandon} \snm{Goodell}} + + +\address[id=mrl]{ + \orgname{Monero Research Lab} +} +\end{fmbox} + +%\begin{abstractbox} +%This document describes +%\begin{abstract} +%We outline the various ideas currently under investigation by the Monero Research Lab, provide context for each task, and present some informative sources regarding each task. \end{abstract} +%\end{abstractbox} +\end{frontmatter} + +This document is intended to inform the community of the work done at MRL in the past quarter, sort of as a response to the first MRL Roadmap, MRL-R001, and sort of as a newsletter to inform everyone about Monero Research Lab. We try to address the partial MRL ``to-do'' list of research items from the first MRL Research Bulletin, MRL-R001, and document the work that has been done both directly and indirectly toward those ends. We document which items on those lists are being de-prioritized on the next MRL Roadmap, and we introduce a few new items that came up over the past few months that will make it onto the next MRL Roadmap (which we expect to put out in the next two to three weeks). + +The Monero Research Lab wishes to state emphatically that our concern is to report our findings on Monero, which is an open source project, as honestly and transparently as possible, subject to the restriction that we do not compromise the safety or security of the funds of our users by doing so. Our goal is not to persuade, re-assure, or enrich speculators or investors; our goal is to assist the Monero community and the Monero Core Team in the design of a robust and strong cryptocurrency with an emphasis on user privacy. Consequently, all findings will be responsibly disclosed to the Monero community. Responsible disclosure may involve maintaining secrecy regarding security flaws for a period of time before disclosure to the public, which provides the development team time to correct known issues and protect our users. This also provides time to discreetly contact the developers of other cryptocurrencies so they, also, may protect their users. + +Now that is out of the way, here is what we did with our summer: + + +\section{RingCT Security Proofs} + +We have combined this topic with the threshold signature topic (see next item). In \cite{noether2016ring}, there are certain flaws in the proofs of security for MLSAG signatures that need correction, but in the construction of the threshold signature security proofs, we must first establish the security of the MLSAG signatures and then generalize to the threshold setting. Due to this, the corrected RingCT proofs are now part-and-parcel with the threshold multisignature paper. + + +\section{Threshold multisignatures} + +We are fleshing out an implementation proposed by former contributor \texttt{shen} of $t$-of-$n$ threshold MLSAG multisignatures in Monero. The details of this implementation have been available to the community for months, and vetting those implementations and developing security proofs has been one of the more pressing areas of work for \texttt{surae}, especially in the past six weeks. We currently have a partial draft of MRL Research Bulletin MRL-0006 detailing the implementation in preparation (see the MRL github for a current copy). However, this is only partial because completing this document requires novel security models against insider attacks, where an adversary may corrupt a subthreshold number of private keys. Novel security models require novel security proofs, and so we are ``in the weeds'' on that right now. We hoped this would be accomplished before the end of August but the novelty of the security models have taken MRL a little by surprise. A delightful, surprise, but a surprise nonetheless: the novelty of these results may lead to a peer-reviewed publication on behalf of MRL! + + +On a related note, \texttt{surae} began in June approaching the threshold multisignature scheme as a mere problem of \textit{computing private keys jointly}, and this was a complete misunderstanding of the problem at hand, which is to \textit{compute signatures without directly computing the private key.} Consequently, our work on this topic was initially unified with our work on the sub-address scheme described by \texttt{kenshi84} and \texttt{knaccc}, by considering these both as problems involving revamping Monero's addressing schemes. This is also one of the reasons that MRL-R001 failed to elaborate upon the sub-address scheme. Once this mis-understanding was clarified to us (after several very educational and helpful conversations with \texttt{luigi} and \texttt{kenshi84}), MRL is once again approaching these two topics separately. We anticipate an MRL Research Bulletin on the sub-address scheme very soon after MRL-0006 describing threshold signatures is released; security proofs for the sub-address scheme are (ostensibly) remarkably easier than in the threshold case. + +\section{Recent criticisms} + +Critics have claimed the Monero blockchain is traceable, as in \cite{miller2017empirical} and \cite{kumar2017traceability}; these papers make use of the \emph{distributional problem} mentioned in the first roadmap together with a few other routes of analysis. Some of the concerns and claims made in these papers are irrelevant because they only apply to pre-RingCT Monero outputs. Some of the concerns are relevant and related to the so-called EABE attack (see next item). + + + +\section{Churning, EABE Attack, Large Rings} + +Detailed by \texttt{knaccc} in \cite{knaccc2017}, the EABE (Eve-Alice-Bob-Eve) attack is described. A merchant, Bob, and his customer, Alice, use an exchange, Eve, to convert cryptocurrency to fiat and back again. If Eve sends some moneroj to Alice, who uses it to purchase items from the merchant Bob several times, and if Bob immediately converts all cryptocurrency to fiat after each transaction to limit his exposure to the volatility of cryptocurrency-to-fiat exchange rates, then Bob unintentionally provides information Eve needs to determine the purchasing habits of Alice. This problem is exacerbated if Eve is a know-your-customer exchange. Urgency on this problem is higher than our original estimation: most merchants who accept cryptocurrency enact this behavior, most users do not churn to avoid this problem, and moreover churning transactions can leave a statistical signal (in the sense of the Miller and Kumar criticisms) that is quite undesirable. + +This work dovetailed nicely with our road map item \textbf{hardness of blockchain analysis}. In the study of this (as well as the Miller and Kumar criticisms), \texttt{surae} established three separate probabilistic models of transaction output ownership in a ring signature setting in analyzing this problem. None of these models will see publication soon, however, because each one, a refinement of the previous, is insufficient to describe the problem at hand. We do, however, anticipate some explanatory details to be made public over the coming months. MRL has been reluctant to provide more details, as we stated very clearly in our first MRL Roadmap, \emph{we will not comment thoroughly on these criticisms until our review is complete for security reasons.} We will take as much time as necessary for this, and we recognize that issues such as this one are urgent. + +In the current CryptoNote framework, an elegant solution would be to simply increase ring sizes dramatically. This seems impractical, however, unless ring signatures can be made small (perhaps sub-linearly sized with respect to the number of ring members) which leads us to the next item. + +\section{Signature Size and RingCT} + +Blockchain bloat can be mitigated with efficient signatures. MRL was made aware of research by two separate international teams of researchers (see Section \ref{sec:academ}) making progress on compact Ring Confidental Transactions. One scheme (put forth by Sun, Au, Liu, and Yuen) is very efficient and fast but requires a trusted set-up. Another scheme (put forth by Ruffing, Thyagarajan, Ronge, and Schr{\"o}der, or RTRS) does not use a trusted set-up, but experiences a trade-off since the computation and verification times are quite beastly. An RTRS RingCT may contain thousands of ring members and take up the space of a classic RingCT signature with only a few dozen ring members, but the RTRS RingCT could take hours, days, or more to compute. We believe verification time may be optimized to an extent, but it is also quite slow. Currently, \texttt{knaccc} is working with \texttt{surae} and \texttt{sarang} on a Java prototype of the implementation for testing purposes, and discussions with \texttt{smooth}, \texttt{moneromooo}, and \texttt{luigi} on the practicalities of implementation are constant. MRL anticipates that the scheme may be made sufficiently stream-lined to include in Monero for a moderate increase ring size that was previously unreasonable, but not the epic increase initially hoped for. + + +\section{Zero-knowledge Lit Review} + +We began communication with Jeffrey Quesnelle, a computer science graduate student at the University of Michigan at Dearborn, at the start of this quarter. Jeffrey wrote an extremely helpful and detailed literature review on zero-knowledge schemes with an eye toward ZK-SNARKS. We listed this zero-knowledge literature review first in MRL-R001 because it was rather low-hanging fruit... but it also did not present a high priority compared to practical implementation issues (threshold signatures, sub-addresses) or security issues (the EABE attack, see below). Our original date for pushing this out was the end of August 2017, which has come and gone. To be clear, this work has not come to a stop, it is merely delayed; now that \texttt{sarang} has joined MRL, \texttt{surae} has more time to put into finishing this project. MRL anticipates movement on this document before the end of September (in fact, the first week of September). + + +\section{Future-proofing Monero} + +Unlike the above topics, this is actually a constant ``in-the-background'' thing to keep in mind. For example, when we use Pedersen commitments, we have certain hiding and binding properties, but when we use El Gamal commitments, which are similar, these properties change and the commitments are no longer sufficiently hiding against adversaries with quantum computing. Making decisions such as these throughout algorithm design is a constant issue to be considered. Consequently, this item will be removed from future MRL road maps, as it is more of a design philosophy. + +\section{New stuff} + +We have put effort into projects not initially on the MRL Roadmap either due to merit of those projects or urgency. Something related to these items will each make it onto the next MRL Roadmap. + +\begin{enumerate}[i.] +\item \textbf{Viewkey solutions}. Since the CryptoNote framework is not \emph{unlinkable} in the sense of the original CryptoNote whitepaper, an adversary can infer much information about whether a certain address has received transactions without knowing the associated viewkey (as in the EABE scenario). Moreover, viewkeys lack functionality. For example, users may desire revocable viewkeys, or viewkeys only valid for certain periods of time, or may desire viewkeys that grant visibility to outgoing transactions (which should also be revocable). Discussions on viewkey solutions have begun between contributors \texttt{endogenic}, \texttt{knaccc}, \texttt{moneromooo}, \texttt{surae}, and \texttt{fluffypony}. + +\item \textbf{Zidechains}. Even with very large ring sizes, since the CryptoNote framework is not zero-knowledge, information is leaked with each transaction by definition. One method proposed by \texttt{fluffypony} to mitigate this is to construct a zero-knowledge sidechain to peg to the Monero blockchain which we are tentatively calling \textit{zidechains}. + +\item \textbf{Blacklisting provably spent outputs}. Wallet software should avoid including provably-spent outputs in ring signatures if possible, because doing so reduces the relative signer ambiguity of the signature, degrades Monero's claims toward untraceability, and degrades the fungibility of all other Monero outputs. Recently, \texttt{fluffypony} had a conversation with \texttt{gmaxwell} on maintaining curated blacklists of provably spent outputs, and \texttt{surae} has begun work on algorithms for finding provably-spent transaction outputs. +\end{enumerate} + + +\section{Dead Items} + +Recall that the items deeper on the MRL Roadmap were items of lower priority. We did not have an opportunity to make progress on the following issues, all of which are very long-term, in terms of priority. These items are worthwhile side hustles for future research, but do not have a lot of immediate pay-off. + +\begin{enumerate}[i.] + \item \textbf{Testing Blockchain Dynamics with Population-driven Modeling.} + + \item \textbf{Blockchain Design}. + + \item \textbf{Traceability, extending RingCT to obscure transaction time.} +\end{enumerate} + +\section{Academic Engagement}\label{sec:academ} + +In the past three months, Monero Research Lab has had some great interaction with the broader academic community, briefly mentioned above. We wish to highlight the following, which is big news! + +\begin{enumerate}[(i)] + +\item Shi-Feng Sun at Hong Kong Polytechnic University, Man Ho Au at Shanghai Jiao Tong University, Joseph K Liu at Monash University, and Tsz Hon Yuen at Huawei Technologies wrote ``RingCT 2.0: A Compact Accumulator-Based (Linkable Ring Signature) Protocol for Blockchain Cryptocurrency Monero,'' a paper proposing a much more efficient and speedy implementation of Ring Confidential Transactions. These researchers have been instrumental in ID-based cryptography and ring signatures, so their contribution directly to Monero, literally mentioning us in their paper title was surprising, exciting, and a huge honor! + +\item Nearly at the same time, Tim Ruffing at Saarlang University together with Sri Aravinda Thyagarajan, Viktoria Ronge, and Dominique Schr{\"o}der at Friedrich-Alexander-Universit{\"a}t contacted us directly with a separate Ring Confidental Transaction scheme, with a very different Ring Confidential Transaction scheme (see below). We have had a few conversations with him about implementation choices; thanks to hard work by \texttt{knaccc} and \texttt{surae}, we have a nearly-working prototype (to Ruffing's surprise! \texttt{knaccc} works quick). + +\item In implementing the Ruffing scheme, Monero Research Lab has also been in contact with Jonathan Bootle at University College in London about a set-up presented in one of his papers used in the Ruffing scheme; not only are we the first (to his knowledge) to implement his set-ups, but we also identified a small mistake in the notation of his paper that will be corrected. + +\item Thanks to community donations to the Forum Funding System, hired Sarang Noether! He recently graduated with his Ph.D.\ in Computational Physics (and has a strong background in pure and applied mathematics, computer science, and network security) and was a contributor to MRL several years back. We are already enjoying his contribution to our work. We are extremely grateful that the community has welcomed him; he was facing several competitive offers for some very interesting and varied jobs in a few different engineering sectors, so we are lucky to have sniped him away from the traditional economy! + +\end{enumerate} + + + + +\section{Conclusion} + +We request members of the community contribute their opinions on our above work and ideas they would like to see added. Please do not hesitate to contact us. We will make the current threshold MRL Bulletin (which will be MRL-0006) available on the MRL github upon publication of this quarterly update so that contributors and community members can monitor our progress on that front. + +In the next four weeks, we anticipate MRL-R002 roadmap to be put out, the second draft of the zero-knowledge literature review with Jeffrey Quesnelle to be made available to the community, and MRL-0006 to be completed and put out (unless the novelty of the security proofs becomes a rabbit hole of uknown depth). We also anticipate that the RTRS Ring Confidential Transaction scheme to be finished prototyping and beginning testing very soon. Once MRL-0006 is finished, we will begin an MRL Research Bulletin describing the sub-address scheme invented by \texttt{kenshi84} and \texttt{knaccc} to be fleshed out (MRL-0007). + + + + +\section{Special Thanks} + +We would like to issue a special thanks to the members of the Monero community who used the GetMonero.org Forum Funding System to support the Monero Research Lab. Readers may also regard this as a statement of conflict of interest, since our funding is denominated in Monero and provided directly by members of the Monero community by the Forum Funding System. + +\medskip{} + +\bibliographystyle{plain} +\bibliography{biblio.bib} + +\end{document} diff --git a/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/mrl.cls b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/mrl.cls new file mode 100644 index 0000000..a8c3965 --- /dev/null +++ b/publications/research-bulletins/in-prog/MRL-9999 - Threshold Multisignatures/mrl.cls @@ -0,0 +1,1831 @@ +%% +%% LaTeX 2e class file for the processing of LaTeX2e files +%% for the BioMed Central +%% +%% Macros written by Vytas Statulevicius, VTeX, Lithuania +%% for the BioMed Central +%% Please submit bugs or your comments to vytas@vtex.lt +%% +%% The original distribution is located at: +%% http://support.e-publications.org/bmc +%% +%% This class file loads standart "article.cls" with appropriate +%% settings and then redefines layout according to BMC style +%% A lot of efforts are done for the possibility of extraction of +%% information from the LaTeX file +%% +%% You are free to use this style class as you see fit, provided +%% that you do not make changes to the file. +%% If you DO make changes, you are required to rename this file. +%% +%% It may be distributed under the terms of the LaTeX Project Public +%% License, as described in lppl.txt in the base LaTeX distribution. +%% Either version 1.0 or, at your option, any later version. +%% +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%% +%% +%% Bug fixes and changes: +%% at end of file + +\def\bmcart@name{mrl.cls} +\def\bmcart@version{2012/06/27} + +\NeedsTeXFormat{LaTeX2e} + +\ProvidesClass{mrl} + [\bmcart@version Monero Research Lab] + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% General options: + +% Print id line at bottom of the page: +\DeclareOption{noinfoline}{\AtBeginDocument{\let\info@line\@empty}} +\DeclareOption{infoline} {\AtBeginDocument{\let\info@line\infoline@text}} + +% Put lines numbers in margins +\newif\ifnumberlines@ \numberlines@false +\DeclareOption{linenumbers}{\numberlines@true} +\DeclareOption{nolinenumbers}{\numberlines@false} + +% Spacing +\DeclareOption{doublespacing}{\AtBeginDocument{\renewcommand{\baselinestretch}{1.4}\large\normalsize}} +\DeclareOption{singlespacing}{\AtBeginDocument{\renewcommand{\baselinestretch}{1.0}\large\normalsize}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Loading standart "article" class + +\PassOptionsToClass{twoside}{article} +\PassOptionsToPackage{fleqn}{amsmath} +\PassOptionsToPackage{sort&compress,numbers}{natbib} +\PassOptionsToPackage{colorlinks,citecolor=blue,urlcolor=blue,linkcolor=blue,pagecolor=blue}{hyperref} + +\DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}} +\ProcessOptions* + +\LoadClass{article} + +%%% start of "vsfleqn2.sty" +\newdimen\mathindent +\AtEndOfClass{\mathindent\leftmargini} +% +\def\mathtrivlist{\parsep\parskip\topsep\abovedisplayskip + \ifnum\@listdepth>0 \advance\mathindent by-\leftmargin\fi% + \@trivlist \labelwidth\z@ \leftmargin\z@ + \itemindent\z@ \def\makelabel##1{##1}} + +\def\endmathtrivlist{\endtrivlist} +% \[ \] +\renewcommand\[{\relax + \ifmmode\@badmath + \else + \begin{mathtrivlist}% + \@beginparpenalty\predisplaypenalty + \@endparpenalty\postdisplaypenalty + \item[]\leavevmode + \hb@xt@\linewidth\bgroup $\m@th\displaystyle %$ + \hskip\mathindent\bgroup + \fi} +\renewcommand\]{\relax + \ifmmode + \egroup $\hfil% $ + \egroup + \end{mathtrivlist}% + \else \@badmath + \fi} +% EQUATION +\renewenvironment{equation}% + {\@beginparpenalty\predisplaypenalty + \@endparpenalty\postdisplaypenalty + \refstepcounter{equation}% + \mathtrivlist \item[]\leavevmode + \hb@xt@\linewidth\bgroup $\m@th% $ + \displaystyle + \hskip\mathindent}% + {$\hfil % $ + \displaywidth\linewidth\hbox{\@eqnnum}% + \egroup + \endmathtrivlist} +% EQNARRAY +\renewenvironment{eqnarray}{% + \stepcounter{equation}% + \def\@currentlabel{\p@equation\theequation}% + \global\@eqnswtrue\m@th + \global\@eqcnt\z@ + \tabskip\mathindent + \let\\=\@eqncr +% \setlength\abovedisplayskip{\topsep}% +% \ifvmode +% \addtolength\abovedisplayskip{\partopsep}% +% \fi +% \addtolength\abovedisplayskip{\parskip}% +% \setlength\belowdisplayskip{\abovedisplayskip}% + \setlength\belowdisplayshortskip{\abovedisplayskip}% + \setlength\abovedisplayshortskip{\abovedisplayskip}% + $$\everycr{}\halign to\linewidth% $$ + \bgroup + \hskip\@centering + $\displaystyle\tabskip\z@skip{##}$\@eqnsel&% + \global\@eqcnt\@ne \hskip \tw@\arraycolsep \hfil${##}$\hfil&% + \global\@eqcnt\tw@ \hskip \tw@\arraycolsep + $\displaystyle{##}$\hfil \tabskip\@centering&% + \global\@eqcnt\thr@@ + \hb@xt@\z@\bgroup\hss##\egroup\tabskip\z@skip\cr}% + {\@@eqncr + \egroup + \global\advance\c@equation\m@ne$$% $$ + \@ignoretrue + } +%%% end of "vsfleqn2.sty" + +\RequirePackage{keyval} +\RequirePackage{xcolor} +\definecolor{bmcblue}{rgb}{0,0.2,0.4} + +\RequirePackage{lastpage} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Modifications and "add-on" for article.cls starts: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Initiate some info: +\def\journal@name{Monero Research Lab} +%\let\journal@name\@empty +\def\journal@url{http://monero.cc/} +\def\journal@id{-mrl} +\def\paper@url{} +\def\info@line{} +%\def\copyrightowner@text{Monero Research Lab} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page dimensions + +%% dimensions: text + + \setlength\parindent {8\p@} + \def\true@parindent {8\p@} + \if@twocolumn + \setlength\textheight {651\p@}% 648bp + \setlength\textwidth {484\p@}% 170mm + \else + \setlength\textheight {653\p@}% 650.9bp + \setlength\textwidth {361\p@}% 127mm + \fi + + + \setlength\columnsep {5mm} + \@settopoint\columnsep + \@tempdima=\textwidth + \advance\@tempdima by-\columnsep + \divide\@tempdima by2 + \setlength\columnwidth {\@tempdima} + \@settopoint\columnwidth + \setlength\columnseprule{0\p@} + + \mathindent20\p@ + +%% dimensions: heads + + \setlength\headheight{12\p@} + \setlength\headsep {44\p@} + \setlength\topskip {14\p@} + \setlength\footskip {2\p@} + \setlength\maxdepth {.5\topskip} + +%% dimensions: side margins + + \setlength\topmargin {27\p@} % 12mm + \if@twocolumn + \setlength\oddsidemargin {57\p@}% 20mm gutter margin + \setlength\evensidemargin {57\p@}% 20mm outer margin + \else + \setlength\oddsidemargin {118\p@}% 41.5mm gutter margin + \setlength\evensidemargin {118\p@}% 41.5mm outer margin + \fi + + \advance\oddsidemargin by-1in + \advance\evensidemargin by-1in + \advance\topmargin by-1in + + \def\set@fp@margins{% + \setlength\oddsidemargin {179\p@}% 63mm first page gutter margin + \setlength\evensidemargin {57\p@}% 20mm outer first page margin + \advance\oddsidemargin by-1in + \advance\evensidemargin by-1in + } + \if@twocolumn\else + \let\set@fp@margin@hook\set@fp@margins + \fi + +%% dimensions: skips + + \if@twocolumn + \setlength\smallskipamount{6\p@ \@plus 1\p@ \@minus 1\p@} + \setlength\medskipamount {12\p@ \@plus 3\p@ \@minus 3\p@} + \setlength\bigskipamount {18\p@ \@plus 6\p@ \@minus 3\p@} + \else + \setlength\smallskipamount{7\p@ \@plus 1\p@ \@minus 1\p@} + \setlength\medskipamount {14\p@ \@plus 3\p@ \@minus 3\p@} + \setlength\bigskipamount {22\p@ \@plus 6\p@ \@minus 3\p@} + \fi + +%% dimensions: page-breaking penalties + + \clubpenalty=10000 + \widowpenalty=10000 + \if@twocolumn + \displaywidowpenalty=50 + \fi + \predisplaypenalty=10000 % Breaking before a math display. + \pretolerance=100 % Badness tolerance for the first pass (before hyphenation) + \tolerance=800 % Badness tolerance after hyphenation + \hbadness=800 % Badness above which bad hboxes will be shown + \emergencystretch=3\p@ + \hfuzz=1\p@ % do not be to critical about boxes + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fontsizes + + \if@twocolumn + \renewcommand\normalsize{% + \@setfontsize\normalsize\@xpt{12\p@ \@plus.25\p@ \@minus.4\p@}% + \abovedisplayskip 12\p@ \@plus2\p@ \@minus2\p@ + \abovedisplayshortskip 7\p@ \@plus2\p@ + \belowdisplayshortskip 7\p@ \@plus2\p@ + \belowdisplayskip \abovedisplayskip + \let\@listi\@listI} + \else + \renewcommand\normalsize{% + \@setfontsize\normalsize\@xpt{14.2\p@ \@plus.3\p@ \@minus.5\p@}% + \abovedisplayskip 14.15\p@ \@plus2\p@ \@minus2\p@ + \abovedisplayshortskip 7\p@ \@plus2\p@ + \belowdisplayshortskip 7\p@ \@plus2\p@ + \belowdisplayskip \abovedisplayskip + \let\@listi\@listI} + \fi + + \renewcommand\small{% + \@setfontsize\small\@ixpt{11\p@ plus .2\p@ minus .2\p@}% + \abovedisplayskip 7.5\p@ \@plus4\p@ \@minus1\p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip \abovedisplayskip + \belowdisplayshortskip \abovedisplayskip} + + \renewcommand\footnotesize{% + \@setfontsize\footnotesize\@viiipt{9\p@ plus .1pt minus .1pt}%% + \abovedisplayskip 6\p@ \@plus4\p@ \@minus1\p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip \abovedisplayskip + \belowdisplayshortskip \abovedisplayskip} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% setattribute, getattribute, do@option@list + +\def\setattribute{\@ifnextchar[\@setattribute{\@setattribute[]}} +\def\@setattribute[#1]#2#3#4{\expandafter\gdef\csname #2@#3\endcsname{#4}} +\def\getattribute#1#2{\csname #1@#2\endcsname} +\def\sep@key@value#1=#2/?/#3{\setattribute{#3}{#1}{#2}} +\def\do@option@list#1#2{% + \@for\curr@option:={#2}\do{% + \expandafter\sep@key@value\curr@option/?/{#1}\relax + }% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% newpseudoenvironment +% same as \newenvironment, but new environment do not have additional groups \bgroup \egroup +% (i.e. all definitions are not local + +\let\org@begin\begin +\let\org@end\end +\def\begin#1{% + \@ifundefined{pseudo@#1}% + {\org@begin{#1}}{\csname pseudo@#1\endcsname[0]\relax}% + } +\def\end#1{% + \@ifundefined{pseudo@#1}% + {\org@end{#1}}{\csname pseudo@#1\endcsname[1]\relax}% + } +\def\newpseudoenvironment#1#2#3{% + \expandafter\gdef\csname pseudo@#1\endcsname[##1]{% + \relax\ifcase##1\relax\def\@@next@@{#2}\or\def\@@next@@{#3}\else\let\@@next@@\relax\fi\@@next@@}% + } + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% startlocaldefs, endlocaldefs + +\def\startlocaldefs{\makeatletter} +\def\endlocaldefs{\makeatother} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% thanksref, thanksmark, thankslabel, thankstext +% to be safe with hyperref we will use original LaTeX definitions: +% + +\def\saferef#1{\expandafter\safe@setref\csname r@#1\endcsname\@firstoftwo{#1}} +\let\safe@setref\@setref + +\def\safelabel#1{% + \@ifundefined{thanksnewlabel@#1}% + {\@bsphack\protected@write\@auxout{}{\string\thanksnewlabel{#1}{{\@currentlabel}{\thepage}}}\@esphack} + {}% + \@namedef{thanksnewlabel@#1}{}} + +\let\thanksnewlabel\newlabel + +% we want to use various counters: +\def\usethankscounter#1{% + \@ifundefined{current@thankscounter}{\gdef\previous@thankscounter{#1}}{\xdef\previous@thankscounter{\current@thankscounter}}% + \def\current@thankscounter{#1}} + +\def\restorethankscounter{\xdef\current@thankscounter{\previous@thankscounter}} + +\newcounter{thanks} +%\def\thethanks{\@fnsymbol\c@thanks} +\def\thethanks{\@arabic\c@thanks} +\usethankscounter{thanks} + +\def\thanksmark@fmt#1{\hbox{$^{#1}$}} +\def\thanksref@sep{,} + +% hooks for the hyperref: +\def\thankref@hyperlink#1{\saferef{#1thanks}} +\def\thanks@hypertarget#1{} + +% Isvedame zymes +\def\thanksref{\@ifnextchar[{\@tempswatrue\@thanksref}{\@tempswafalse\@thanksref[]}} + +\def\@thanksref[#1]#2{% + \if@tempswa% [] + \thanksmark@fmt{#1}% + \else% + \let\@tempa\@empty% + \thanksmark@fmt{\@for\@tempb:=#2\do{% + \@tempa\let\@tempa\thanksref@sep% + \edef\@tempb{\expandafter\@firstofone\@tempb\@empty}% + \thankref@hyperlink{\@tempb}}}% + \fi} + +% Suformuojame ir isvedame zyme +\def\thanksmark{\@ifnextchar[{\@tempswatrue\@thanksmark}{\@tempswafalse\@thanksmark[]}} + +\def\@thanksmark[#1]#2{% + \@thankslabel[#1]{#2}% + \safelabel{#2thanks}% + \thanksmark@fmt{\expandafter\saferef{#2thanks}\thanks@hypertarget{#2}}} + +% Suformuojame tik zyme +\def\thankslabel{\@ifnextchar[{\@tempswatrue\@thankslabel}{\@tempswafalse\@thankslabel[]}} + +\def\@thankslabel[#1]#2{% + \if@tempswa% [] + \protected@edef\@currentlabel{#1}% + \else% + \refstepcounter{\current@thankscounter}% + \fi% + \safelabel{#2thanks}}% + +% Suformuojame zyme ir idedame teksta i \@thanks: +\def\thankstext{\@ifnextchar[{\@tempswatrue\@thankstext}{\@tempswafalse\@thankstext[]}} + +\def\@thankstext[#1]#2#3{% + \@thankslabel[#1]{#2}% + \protected@xdef\@thanks{\@thanks\protect\thanks@thefnmark{#2thanks}% + \protect\@footnotetext{\thanks@hypertarget{#2}#3}}}% + +\def\thanks@thefnmark#1{\begingroup\unrestored@protected@xdef\@thefnmark{\saferef{#1}}\endgroup}% + + + +% ST makrosas savo numeracijos sistemos sukurimui +\def\setvaluelist#1#2{\@tempcnta=0\relax + \@for\@curr@val:=#2\do{% + \advance\@tempcnta by1\relax + \expandafter\protected@xdef\csname #1@item@\the\@tempcnta\endcsname{\@curr@val}% + }% + \expandafter\protected@xdef\csname #1@item@0\endcsname{\the\@tempcnta}% +} +\xdef\getitemvalue#1#2{\noexpand\csname #1@item@#2\endcsname} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \ead, \printead + +\def\email@text{} +\def\url@text{http://} +\def\ead@sep{;~} + +% naudojame keyval paketa +\define@key{ead}{email}[true]{\def\ead@type{email}} +\define@key{ead}{url}[true]{\def\ead@type{url}} +\define@key{ead}{label}{\def\ead@label{#1}} + +\DeclareRobustCommand\ead[2][label= ,email]{{% + \def\ead@type{email}% default + \setkeys{ead}{#1}% + \def\texttildelow{\noexpand\texttildelow}% + \protected@edef\@currentlabel{#2}% + \safelabel{\ead@label @\ead@type}}} + +\newif\ifnot@ead@star + +\DeclareRobustCommand{\printead}{\@ifstar{\not@ead@starfalse\@printead}{\not@ead@startrue\@printead}} + +\def\@printead{\@ifnextchar[{\@tempswatrue\@@printead}{\@tempswafalse\@@printead[]}} + +\def\@@printead[#1]#2{% + \if@tempswa% [] + {\ead@size #1}% + \else% + \def\ead@type{email}% + \def\ead@prefix{mailto:}% + \let\ead@text\email@text% + \let\@ead@sep\relax% + \@for\ead@ref:=#2\do{% + \@ead@sep\let\@ead@sep\ead@sep% + \@ifundefined{r@\ead@ref @url}{}{\let\ead@text\url@text\def\ead@type{url}\def\ead@prefix{http://}}% + \ifnot@ead@star\ead@text\fi{\ead@size\def\null{}\ims@href{\ead@prefix\saferef{\ead@ref @\ead@type}}{\saferef{\ead@ref @\ead@type}}}% + \let\ead@text\relax}% + \fi% +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% normaltext, nohyphen, no@harm + +% normalus tekstas (justify) +\def\normaltext{\let\\=\@normalcr% + \leftskip\z@ \@rightskip\z@ \rightskip\@rightskip% + \parfillskip\@flushglue} + +% skiemenavimo isjungimas +\def\nohyphen{\pretolerance=\@M \tolerance=\@M \hyphenpenalty=\@M \exhyphenpenalty=\@M} + +\def\no@harm{\let\thanks=\@gobble\let\thanksref=\@gobble\let~\space\def\ead[##1]##2{}\let\\=\@empty \def\protect{\noexpand\protect\noexpand}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% url@fmt + + +\def\journalurl#1{\def\journal@url{#1}} +\def\paperurl#1{\def\paper@url{#1}} + +\def\doi#1{% + \gdef\@doi{#1}% + \gdef\doi@text{\url@fmt{DOI: }{\ttfamily}{#1}{\doi@base\@doi}}% +} + +\def\@doi{} + +\def\doi@base{http://dx.doi.org/} + +% {url}{text} +\def\ims@href#1#2{#2} + +% {prefix}{font}{text}{url} + +\def\url@fmt#1#2#3#4{% + \edef\@tempa{#3}% + \ifx\@tempa\@empty% + \else% + #1{#2\ims@href{#4}{#3}}% + \fi} + +%%%%%%%%%%%%%%%%%%% doiurl + +\@ifundefined{doi@base}{\def\doi@base{http://dx.doi.org/}}{} + +\DeclareRobustCommand\doiurl[1]{{% + \def\\{}% + \check@doiurl@prefix#1http://\end% + \check@doiurl@break#1\\\end\relax% + \if@doiurlbreak% + \@ifundefined{doi@url}{% + \href{\doi@base\@tempx\@tempy}{\csname doi@size\endcsname\@tempx}% + \break% + \href{\doi@base\@tempx\@tempy}{\csname doi@size\endcsname\@tempy}}% + {% + \expandafter\href{\@tempx\@tempy}{\csname doi@size\endcsname\@tempx}% + \break% + \href{\@tempx\@tempy}{\csname doi@size\endcsname\@tempy}}% + \else% + \@ifundefined{doi@url}% + {\href{\doi@base#1}{\csname doi@size\endcsname #1}}% + {\href{#1}{\csname doi@size\endcsname #1}}% + \fi}} + + +\def\check@doiurl@prefix#1http://#2\end{\ifx.#2.\else\def\doi@url{fullurl}\fi} + +\newif\if@doiurlbreak \@doiurlbreakfalse + +\def\check@doiurl@break#1\\#2\end{% + \ifx.#2.\@doiurlbreakfalse% + \else% + \@doiurlbreaktrue% + \def\@tempx{#1}% + \def\@tempy{#2}% + \fi} + +%%%%%%%%%%%%%%%%%%% arxivurl + +%% \arxivurl{http://arxiv.org/abs/math.PR/0603300} +%% \arxivurl{math.PR/0603300} +%% \arxivurl{http://\\arxiv.org/abs/math.PR/0603300} +%% \arxivurl{math.PR/\\0603300} + +\@ifundefined{arxiv@base}{\def\arxiv@base{http://arxiv.org/abs/}}{} + +\DeclareRobustCommand\arxivurl[1]{{% + \def\\{}% + \check@arxivurl@prefix#1http://\end% + \check@arxivurl@break#1\\\end\relax% + \if@arxivurlbreak% + \@ifundefined{arxiv@url}{% + \href{\arxiv@base\@tempx\@tempy}{\csname arxivurl@size\endcsname\@tempx}% + \break% + \href{\arxiv@base\@tempx\@tempy}{\csname arxivurl@size\endcsname\@tempy}}% + {% + \expandafter\href{\@tempx\@tempy}{\csname arxivurl@size\endcsname\@tempx}% + \break% + \href{\@tempx\@tempy}{\csname arxivurl@size\endcsname\@tempy}}% + \else% + \@ifundefined{arxiv@url}% + {\href{\arxiv@base#1}{\csname arxivurl@size\endcsname #1}}% + {\href{#1}{\csname arxivurl@size\endcsname #1}}% + \fi}} + + +\def\check@arxivurl@prefix#1http://#2\end{\ifx.#2.\else\def\arxiv@url{fullurl}\fi} + +\newif\if@arxivurlbreak \@arxivurlbreakfalse + +\def\check@arxivurl@break#1\\#2\end{% + \ifx.#2.\@arxivurlbreakfalse% + \else% + \@arxivurlbreaktrue% + \def\@tempx{#1}% + \def\@tempy{#2}% + \fi} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% RUNNING HEADS + +\def\runtitle#1{\gdef\@runtitle{#1}} +\def\runauthor#1{\gdef\@runauthor{#1}\global\let\copauthor\@runauthor} +\def\@runauthor{} +\def\@lastpage{0} + +\def\thepage@fmt#1{Page #1 of \@lastpage} +\def\thepage@fmt#1{Page #1 of \pageref{LastPage}} + +\def\headline@hook{} +\let\ps@copyright@hook\relax + +% normal RH +\def\ps@bmcheadings{% + \def\etal{\textit{et al.}}% + \let\@mkboth\@gobbletwo% + \def\@evenfoot{\csname footline@hook\endcsname\hfill}% + \let\@oddfoot\@evenfoot + \def\@oddhead{\headline@hook\hskip-\rhindent@width\hbox to\z@{\parbox[t]{\textarea@width}{\runninghead@size\runninghead@text}\hss}\hfill}% + \let\@evenhead\@oddhead% +}% + + +% First page RH +\def\ps@copyright{\csname set@fp@margin@hook\endcsname% + \def\etal{\textit{et al.}}% + \let\@mkboth\@gobbletwo% + \def\@evenhead{\ps@copyright@hook\headline@hook\hskip-\leftarea@width\parbox[t]{\textarea@width}{\copyright@size\copyright@text}\hfill}% + \let\@oddhead\@evenhead% + \def\@oddfoot{\csname footline@hook\endcsname\hfill\hfill}% + \let\@evenfoot\@oddfoot} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LIST ENVIRONMENTS + +\parsep\z@ +\topsep\z@ +\partopsep\z@ +\itemsep\z@ +\labelsep.5em + +\def\@listI{\leftmargin\leftmargini + \parsep\z@ + \topsep\z@ + \itemsep\z@} + +\def\list@parindent{8\p@} + + +\def\labelenumi{\theenumi\hskip6\p@} + +% quotation +\let\quotation@size\normalsize +\def\quotation@itemindent{\list@parindent} +\def\quotation@parindent{\list@parindent} +\def\quotation@leftmargin{\list@parindent} +\let\quotation@rightmargin\z@ +\let\quotation@topsep\smallskipamount + +\def\quotation{% + \list{}{\quotation@size% + \listparindent\quotation@parindent% + \itemindent \quotation@itemindent% + \rightmargin\quotation@rightmargin \leftmargin\quotation@leftmargin% + \partopsep\z@ \topsep\quotation@topsep \parsep\z@% + }% + \item[\Q@strut]\relax} + +\def\endquotation{\endlist} + +\def\Q@strut{\leavevmode\hbox{\vrule height9pt depth1pt width0pt}} + +% quote +\let\quote@size\normalsize +\def\quote@indent{\z@} +\def\quote@leftmargin{2pc} +\def\quote@rightmargin{\z@} +\let\quote@topsep\smallskipamount + +\def\quote{% + \list{}{\quote@size% + \listparindent\quote@indent% + \itemindent \listparindent% + \rightmargin\quote@rightmargin \leftmargin\quote@leftmargin% + \partopsep\z@ \topsep\quote@topsep \parsep\z@% + }% + \item\relax} + +\def\endquote{\endlist} + +\def\@listii {\leftmargin\leftmarginii + \labelwidth\leftmarginii + \advance\labelwidth-\labelsep + \topsep\z@ + \parsep\z@ + \itemsep \parsep} + +\def\@listiii{\leftmargin\leftmarginiii + \labelwidth\leftmarginiii + \advance\labelwidth-\labelsep + \topsep\z@ + \parsep z@ + \partopsep\z@ + \itemsep\topsep} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TABLE, FIGURE + +% settings for table caption +\setattribute{floatcaption} {size}{\footnotesize\bfseries\mathversion{bold}\raggedright} +\setattribute{floatcaptionname}{size}{\bfseries} + +\setlength\abovecaptionskip{0\p@} +\setlength\belowcaptionskip{4\p@} + +\long\def\@makecaption#1#2{ + \vskip\abovecaptionskip + \parbox[t]{\hsize}{\floatcaption@size{\floatcaptionname@size #1}\hskip.5em #2\par}% + \vskip\belowcaptionskip} + + +\def\@floatboxreset{% + \reset@font + \footnotesize + \sffamily + \@setminipage + \centering +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FIGURE - in box + +\newbox\bmcfloat@box +\newif\if@figurestar + +\setattribute{figure}{sep}{6.25\p@} + +\def\figure{\@figurestarfalse\@ifnextchar[{\@figure}{\@figure[t]}} + +\def\@figure[#1]{\def\figure@pars{#1}% + \def\@captype{figure}% + \def\csentence##1{{\mathversion{bold}\bfseries ##1}}% +% \csname @figure@hook\endcsname% +% \let\@makecaption\@makefigurecaption% +% \let\@floatboxreset\figure@boxreset% + \setbox\bmcfloat@box=\vbox\bgroup\figure@settings} + +\def\endfigure{% + \par% + \egroup% + \edef\reserved@a{\noexpand\@xfloat{figure}[\figure@pars]} + \reserved@a\makefigure@float\end@float +} + + +\DeclareRobustCommand\fig@textbf[1]{{\floatcaptionname@size #1}}% + +\def\figure@settings{% + \let\textbf\fig@textbf% + \setattribute{floatcaption}{size}{\footnotesize\sffamily\raggedright} + \if@figurestar\hsize=\textwidth\fi% + \@tempdima\hsize% + \advance\@tempdima by-\figure@sep% + \advance\@tempdima by-\figure@sep% + \hsize\@tempdima% + \parindent\z@% + \centering% + \setlength\abovecaptionskip{6\p@}% + \setlength\belowcaptionskip{0\p@}% +} + +\def\makefigure@float{ + \setlength{\fboxsep}{\figure@sep}% + \setlength{\fboxrule}{0.25\p@}% + \fcolorbox{bmcblue}{white}{\box\bmcfloat@box}} + +\@namedef{figure*}{\@figurestartrue\@ifnextchar[{\@figure}{\@figure[t]}} + +\@namedef{endfigure*}{% + \egroup% + \edef\reserved@a{\noexpand\@xdblfloat{figure}[\figure@pars]} + \reserved@a\makefigure@float\end@dblfloat +} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FOOTNOTE + +\def\footnoterule{\kern-3\p@ \hrule \@width \footnoterule@width \kern 2.6\p@} % the \hrule is .4pt high + +\let\orig@footnoterule\footnoterule + +\renewcommand\@makefntext[1]{\noindent\parindent8\p@\@makefnmark #1} + +\def\@makefnmark{\csname makefnmark@hook\endcsname\@textsuperscript{\normalfont[\@thefnmark]}}% + +% hook for hyperref +\def\@makefntext@fmt#1{\@makefnmark} + +\def\freefootnotetext[#1]{% + \begingroup\unrestored@protected@xdef\@thefnmark{#1}\endgroup\@footnotetext} + +\def\footnote@size{\fontsize{7}{8}\raggedright} + +\long\def\@footnotetext#1{\insert\footins{% + \reset@font\footnote@size + \interlinepenalty\interfootnotelinepenalty + \splittopskip\footnotesep + \splitmaxdepth \dp\strutbox \floatingpenalty \@MM + \hsize\columnwidth \@parboxrestore + \protected@edef\@currentlabel{% + \csname p@footnote\endcsname\@thefnmark + }% + \color@begingroup + \@makefntext{% + \rule\z@\footnotesep\ignorespaces#1\@finalstrut\strutbox}% + \color@endgroup}}% + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% MAIN SETTINGS - COMMON FOR 1 and 2 col's layouts + + +\setattribute{frontmatter} {style} {\raggedright} +\setattribute{address} {style} {\raggedright} +\setattribute{affiliation} {style} {\raggedright} +\setattribute{abstract} {style} {\raggedright} +\setattribute{keyword} {style} {\normaltext\raggedright} +\setattribute{backmatter} {style} {\raggedright} + +% FRONT MATTER SKIPS +\setattribute{dochead} {skip} {-\topskip} +\setattribute{title} {skip} {10\p@} +\setattribute{subtitle} {skip} {5\p@} +\setattribute{date} {skip} {10\p@} +\setattribute{authors} {skip} {2\p@} +\setattribute{note} {skip} {8\p@} +\setattribute{copyright} {skip} {23\p@} +\setattribute{address} {skip} {4\p@ plus 2\p@} +\setattribute{history} {skip} {\Smallskipamount} +\setattribute{abstract} {skip} {0\p@} +\setattribute{keyword} {skip} {5\p@} +\setattribute{abbr} {skip} {\medskipamount} +\setattribute{frontmatter} {skip} {\bigskip} + +\setattribute{copyrightlogo}{cmd}{} + +% FRONT MATTER FONTS +\setattribute{dochead} {size} {\sffamily\fontsize{13pt}{13pt}\bfseries\selectfont\color{white}} +\setattribute{title} {size} {\sffamily\fontsize{24pt}{26pt}\selectfont\raggedright} +\setattribute{subtitle} {size} {\sffamily\fontsize{20pt}{22pt}\selectfont\raggedright} +\setattribute{author} {size} {\sffamily\fontsize{11pt}{14pt}\selectfont\raggedright} +\setattribute{date} {size} {\sffamily\fontsize{11pt}{14pt}\selectfont\raggedright} +\setattribute{address} {size} {} +\setattribute{note} {size} {\sffamily\fontsize{10pt}{13pt}\selectfont\raggedright} +\setattribute{thanksbox} {size} {\sffamily\fontsize{7pt}{9pt}\selectfont\raggedright} +\setattribute{history} {size} {\mdseries} +\setattribute{abstract} {size} {\sffamily\fontsize{10}{12}\selectfont} +\setattribute{abstractname}{size} {\bfseries} +\setattribute{keyword} {size} {\sffamily\fontsize{10}{12}\selectfont} +\setattribute{keywordname} {size} {\bfseries} + +\setattribute{runninghead} {size} {\sffamily\fontsize{8}{10}\selectfont} +\setattribute{footline} {size} {\sffamily\fontsize{7}{8}\selectfont} +\setattribute{copyright} {size} {\sffamily\fontsize{8}{10}\selectfont} +\setattribute{backmatter} {size} {\sffamily\fontsize{7}{9}\selectfont\raggedright} +\setattribute{ead} {size} {} + +% COPYRIGHT TEXT, etc. +\setattribute{address} {text} {Author details} +\setattribute{corref} {text} {Correspondence: } +\setattribute{authorinfo} {text} {} +\setattribute{presentaddress} {text} {\textit{Present address: }} +\setattribute{copyright} {text} {\copyright\,\textit{\journal@name}} +\setattribute{runninghead} {text} {\copyright\,\textit{\journal@name} \hfill \thepage@fmt{\thepage}} +\setattribute{footline} {text} {} +\setattribute{pdfsubject} {text} {\journal@name} + +% URL +\setattribute{article} {url} {} + +% SEPARATIONS + +\setattribute{author} {sep} {, } +\setattribute{authorand} {sep} {~and } +\setattribute{address} {sep} {. } + +% KEYWORDS +\setattribute{keyword} {AMS} {AMS Subject Classification} +\setattribute{keyword} {MSC} {Mathematics Subject Classification} +\setattribute{keyword} {MSC2010} {Mathematics Subject Classification (2010)} +\setattribute{keyword} {MSCnoyear}{Mathematics Subject Classification} +\setattribute{keyword} {KWD} {Keywords} +\setattribute{keyword} {JEL} {JEL Classification} +\setattribute{keyword} {PACS} {PACS Codes} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FRONT MATTER FORMATTING PARAMETERS + + +% FRONT MATTER SKIPS +\if@twocolumn +\setattribute{abstractbox} {skip} {24\p@} +\else +\setattribute{abstractbox} {skip} {-1\p@} +\fi + +\setattribute{frontmatter} {cmd} {% + \frontmatter@skip% + \global\@afterindentfalse% + \@afterheading} + +% FRONT MATTER DIMENSIONS +\setattribute{textarea} {width} {484\p@} %170mm 1 puslapio maksimalus plotis +\if@twocolumn +\setattribute{leftarea} {width} {\z@} +\setattribute{rhindent} {width} {\z@} +\else +\setattribute{leftarea} {width} {122\p@} %38mm+5mm=43mm +\setattribute{rhindent} {width} {61\p@} %21.5mm = 41.5-20 rh issikisimas normaliuose puslapiuose +\fi +\setattribute{leftcol} {width} {108\p@} %38mm 1 puslapio isnasu dezutes plotis +\setattribute{colsep} {width} {14\p@} %5mm +\if@twocolumn +\setattribute{footnoterule}{width} {\columnwidth}% +\else +\setattribute{footnoterule}{width} {\textwidth}% +\fi + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FRONTMATTER + +% COUNTERS, ETC +\newcounter{author} +\newcounter{address} +\newdimen\sv@mathsurround +\let\hy@frontmatter\relax +\let\hy@endfrontmatter\relax + +\def\frontmatter{% + \global\c@author\z@ + \global\c@address\z@ +% + \thispagestyle{copyright}% +% + \csname frontmatter@hook \endcsname% + \sv@mathsurround\mathsurround% + \m@th + \set@frontmatter@cmd + \set@frontmatter@keys + \parindent\z@ + \frontmatter@style + \hy@frontmatter + \ignorespaces} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ENDFRONTMATTER + +\def\endfrontmatter{% + \global\@topnum\z@ +% + \@thanks% +% + \write@pdfinfo{\hy@fauthor}{\csname fauthor@\firstauthor@id\endcsname} + \write@pdfinfo{\hy@author}{\the\authors@list} + \write@pdfinfo{\hy@subject}{\pdfsubject@text} + \write@pdfinfo{\hy@keywords}{\the\keywords@list} +% + \hy@endfrontmatter +% + \immediate\write\@mainaux{\string\global\string\@namedef{num@address}{\the\c@address}}% + \immediate\write\@mainaux{\string\global\string\@namedef{num@author}{\the\c@author}}% + \set@authorcorref@notset% +% + \global\mathsurround\sv@mathsurround + \global\let\@thanks\@empty +% + \set@runauthor +% + \csname frontmatter@hook\endcsname% + \aftergroup\frontmatter@cmd + \aftergroup\insert@thanksbox + } + \if@twocolumn + \def\insert@thanksbox{\insert\footins{\unvbox\thanks@box}} + \else + \let\insert@thanksbox\relax + \fi + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \set@frontmatter@cmd + +\def\set@frontmatter@cmd{% + \let\maketitle\relax + \let\fmbox\bmc@fmbox + \let\endfmbox\bmc@endfmbox + \let\dochead\bmc@dochead + \let\title\bmc@title + \let\subtitle\bmc@subtitle + \let\author\bmc@author + \let\address\bmc@address + \let\date\bmc@date + \let\artnotes\bmc@artnotes + \let\endartnotes\bmc@endartnotes + \let\abstractbox\bmc@abstractbox + \let\endabstractbox\bmc@endabstractbox + \let\abstract\bmc@abstract + \let\endabstract\bmc@endabstract + \let\keyword\bmc@keyword + \let\endkeyword\bmc@endkeyword + \let\thanksbox\bmc@thanksbox + \let\endthanksbox\bmc@endthanksbox +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% FMBOX + +\newif\if@fmbox \@fmboxfalse +\newbox\fm@box + +\def\bmc@fmbox{% + \setbox\fm@box=\vbox\bgroup + \@fmboxtrue + \hsize=\textarea@width + } + +\def\bmc@endfmbox{% + \par + \auto@set@thanksbox% + \csname endfmbox@hook\endcsname% +\egroup% +\if@twocolumn + \emergencystretch=1pc \twocolumn[\box\fm@box\medskip] +\else + \hbox to\textwidth{\hss\box\fm@box} + \vskip\abstract@skip + \vbox to\z@{\llap{\box\thanks@box\hskip\colsep@width}\vss} +\fi} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DOCHEAD + +\let\dochead@hook\relax + +\def\bmc@dochead{\@ifnextchar[{\dochead@fmt}{\dochead@fmt[]}} + +\def\dochead@fmt[#1]#2{% +\bgroup% + \@tempdima=\hsize% + \advance\@tempdima by-8\p@% + \setlength{\fboxsep}{4\p@}% + \setlength{\fboxrule}{\z@}% + \fcolorbox{bmcblue}{bmcblue}{\hbox to\@tempdima{\dochead@size\MakeUppercase{#2}}}%\hfill\fontshape{n}\selectfont\smash{\dochead@hook}}} +\egroup} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% TITLE + +\let\PREHOOK@title@fmt\@gobble + +\def\bmc@title{\@ifnextchar[{\title@fmt}{\title@fmt[]}} + +\def\title@fmt[#1]#2{% + \vskip\title@skip% + \setkeys{title}{#1}% + \bgroup% + \no@harm% + \let\protect\relax% + \xdef\@runtitle{#2}% + \egroup% + \bgroup% + \no@harm% + \let\protect\relax% + \xdef\@argi{#2}% + \egroup% + \write@pdfinfo{\hy@title}{\@argi}% + \bgroup + \PREHOOK@title@fmt{#2}% + \title@size\csname pretitle@text\endcsname #2\par% + \egroup} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SUBTITLE + +\def\bmc@subtitle{\@ifnextchar[{\subtitle@fmt}{\subtitle@fmt[]}} + +\def\subtitle@fmt[#1]#2{% + \vskip\subtitle@skip + \setkeys{title}{#1}% + \bgroup% + \subtitle@size #2\par% + \egroup} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DATE + +\def\bmc@date{\@ifnextchar[{\date@fmt}{\date@fmt[]}} + +\def\date@fmt[#1]#2{% + \vskip\date@skip + \setkeys{title}{#1}% + \bgroup% + \date@size #2\par% + \egroup} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set@frontmatter@keys + +\def\set@frontmatter@keys{% + \@tempcnta=0\relax% + \@ifundefined{num@address}{}{\@tempcnta=\num@address\relax}% + \ifnum\@tempcnta=1\relax% +% \define@key{author}{addressref}{}% +% \define@key{author}{presentaddressref}{}% + \define@key{author}{corref}{}% + \global\let\address@thanksref\@gobble + \global\let\printaddresses\relax + \fi% + \@tempcnta=0\relax% + \@ifundefined{num@author}{}{\@tempcnta=\num@author\relax}% + \ifnum\@tempcnta=1\relax% + \global\@namedef{num@address}{1} +% \define@key{author}{addressref}{}% +% \define@key{author}{presentaddressref}{\expandafter\gdef\csname presentaddressref@##1\endcsname{}}% +% \gdef\printauthor##1{\unskip}% + \global\let\address@thanksref\@gobble + \global\let\printaddresses\relax + \global\let\corref@thanksmark\@gobble + \global\let\corref@thanksref\@gobble + \fi% +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \thanksmark etc + +\def\thanksmark@fmt#1{{\textsuperscript{#1}}} + +\def\thethanks{\getitemvalue{bmcsymbol}{\@arabic\c@thanks}} + +\setvaluelist{bmcsymbol}{*,\textdagger,\^{}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% AUTHOR - keys + +% \author[id=au1,addressref={aff1,aff2},presentaddressref=aff3,corref={aff1,aff2},thanksref={t1}]{\inits{}\fnm{} \snm{} \suffix{}\ead{}} +% \author@au1 =\inits \snm \suffix +% \fauthor@au1=\fnm \snm \suffix +% \corref@au1 =\corref@text +% +% automatiniam formatavimui: +% \def\addressref@aff1{} +% \emaillist@au1 ={e1,e2} +% \authorslist@aff1 ={au1,au2} +% \authorslist@present@aff1 ={au1,au2} +% \correflist@au1 ={aff1,aff2} +% \authors@id@list ={au1,au2,au3...} +% +% tikriname ar nebuvo panaudotas id: + + \def\check@xx@id#1#2{\@ifundefined{#1@#2}{}{\@latex@error{Command <#1>: id=#2 was allready used!}{}}} + + \newif\ifauthor@corref + \newif\ifauthor@email + + \define@key{author}{id}{% + \def\author@id{#1}% + \check@xx@id{author}{#1}% + \@ifundefined{authors@id@list}{\xdef\authors@id@list{#1}}{\xdef\authors@id@list{\authors@id@list,#1}}} + + \define@key{author}{email}{% + \author@emailtrue% + \ead[label=\author@id]{#1}} + + \define@key{author}{thanksref}{% + % \current@thanksref@list={aff1,aff2} + % \def\thanksref@aff1{} + \edef\current@thanksref@list{#1}% + \@for\thanksref@id:=#1\do{\expandafter\gdef\csname thanksref@\thanksref@id\endcsname{}}} + +% alias for thanksref + \define@key{author}{noteref}{% + % \current@thanksref@list={aff1,aff2} + % \def\thanksref@aff1{} + \edef\current@thanksref@list{#1}% + \@for\thanksref@id:=#1\do{\expandafter\gdef\csname thanksref@\thanksref@id\endcsname{}}} + + \define@key{author}{addressref}{% + % \current@address@list={aff1,aff2} + % \def\addressref@aff1{} + \edef\current@address@list{#1}% + \@for\addressref@id:=#1\do{\expandafter\gdef\csname addressref@\addressref@id\endcsname{}}} + + \define@key{author}{presentaddressref}{% + % \current@address@list={aff1,aff2}% + % \def\presentaddressref@aff1{}% + \@ifundefined{addressref@#1}{\edef\current@paddress@list{#1}}{}% + \@for\addressref@id:=#1\do{\expandafter\gdef\csname presentaddressref@\addressref@id\endcsname{}}% + \@for\addressref@id:=#1\do{\expandafter\gdef\csname addressref@\addressref@id\endcsname{}}} + + \define@key{author}{corref}[]{% +% \corref@list={aff1,aff2}% + \global\let\set@authorcorref@notset\relax% + \global\author@correftrue% + \ifx.#1.\else\xdef\corref@list{#1}\fi% +} + + \def\add@to@addressref@list#1{\@ifundefined{addressref@list}{\edef\addressref@list{#1}}{\edef\addressref@list{\addressref@list, #1}}} + \def\add@to@thanksref@list#1{\@ifundefined{thanksref@list}{\edef\thanksref@list{#1}}{\edef\thanksref@list{\thanksref@list, #1}}} + + \def\set@authorcorref@notset{\immediate\write\@mainaux{\string\global\string\authorcorref@notsettrue}} + + \def\set@author@lists{% + \let\thanksref@list\relax% + \let\addressref@list\relax% + \@ifundefined{current@address@list}{}{\add@to@addressref@list{\current@address@list}}% + \@ifundefined{current@paddress@list}{}{\add@to@addressref@list{\current@paddress@list}}% + \@ifundefined{current@thanksref@list}{}{\add@to@thanksref@list{\current@thanksref@list}}% +} + + \def\print@author@lists{% + \@ifundefined{addressref@list}{}{\address@thanksref{\addressref@list}}% + \ifauthor@corref\def\thanksref@sep{}\corref@thanksref{\corr@author@id}\fi% + \@ifundefined{thanksref@list}{}{\def\thanksref@sep{}\thanksref{\thanksref@list}}% +} + +\let\address@thanksref\thanksref +\let\corref@thanksref\thanksref + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% AUTHOR +% if corref is not set, we will use first author with an email as a corresponding author +% \corr@author@id -> {au1} +% \corref@list -> {aff1,aff2} + +\newif\ifauthorcorref@notset \authorcorref@notsetfalse + + +\def\bmc@author{\@ifnextchar[{\author@fmt}{\author@fmt[]}} + +\def\author@fmt[#1]#2{% + \stepcounter{author}{% + \csname author@cmd\endcsname% + \author@correffalse% + \xdef\author@id{au\the\c@author}% + \setkeys{author}{#1}% + \@ifundefined{num@author}{\@tempcnta=10\relax}{\@tempcnta=\num@author\relax}% + \def\a@sep{, }% + \ifnum\@tempcnta>1\relax% + \ifnum\c@author=\@tempcnta% + \let\a@sep\authorand@sep% + \else% + \let\a@sep\author@sep% + \fi% + \fi% +% + \ifauthorcorref@notset% + \ifauthor@email% email is set + \author@correftrue% + \global\authorcorref@notsetfalse% + \fi% + \fi% + \ifauthor@corref% + \xdef\corr@author@id{\author@id}% + \@ifundefined{corref@list}% + {\@ifundefined{current@address@list}{}{\xdef\corref@list{\current@address@list}}}% + {}% + \fi% +% + \ifnum\c@author=1 \author@fmt@init \let\a@sep\relax \xdef\first@author@id{\author@id}\fi% + \bgroup% F. Author + \def\inits##1{##1}\def\fnm##1{}\def\snm##1{##1}\def\particle##1{##1}\def\suffix##1{##1}% + \no@harm% + \xdef\author@arg{#2}% + \egroup% + \expandafter\protected@xdef\csname author@\author@id\endcsname{\author@arg}% + \bgroup% First Author + \def\inits##1{}\def\fnm##1{##1}\def\particle##1{##1}\def\snm##1{##1}\def\suffix##1{##1}% + \no@harm% + \xdef\author@arg{#2}% + \ifnum\c@author=1\addto@authors@list{#2}\xdef\firstauthor@id{\author@id}\else\addto@authors@list{, #2}\fi% + \egroup% + \expandafter\protected@xdef\csname fauthor@\author@id\endcsname{\author@arg}% + \bgroup% Author + \def\inits##1{}\def\fnm##1{\ignorespaces}\def\particle##1{}\def\snm##1{##1}\def\suffix##1{}% + \no@harm% + \expandafter\xdef\csname runauthor@\the\c@author @snm\endcsname{#2}% + \egroup% + \bgroup% + \author@size% + \def\inits##1{}\def\fnm##1{##1}\def\snm##1{##1}\def\particle##1{##1}\def\suffix##1{##1}% + \set@author@lists% + \a@sep\authorname@fmt{#2}\print@author@lists% + \egroup}% + \ignorespaces} + +\def\author@fmt@init{% + \vskip\authors@skip% + \author@size% + \leavevmode} + +\def\authorname@fmt#1{#1} + +\def\set@runauthor{% + \ifnum\c@author=1\relax + \gdef\@runauthor{\@nameuse{runauthor@1@snm}}% + \else + \ifnum\c@author=2\relax + \gdef\@runauthor{\@nameuse{runauthor@1@snm} and \@nameuse{runauthor@2@snm}}% + \else + \@ifundefined{runauthor@1@snm}{}{\gdef\@runauthor{\@nameuse{runauthor@1@snm} \etal}}% + \fi + \fi} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ADDRESS + +% \address[id=aff1]{} + + \define@key{address}{id}{% + \def\address@id{#1}% + \check@xx@id{address}{#1}% +} + + +\def\bmc@address{\@ifnextchar[{\address@fmt}{\address@fmt[]}} + + +\def\address@fmt[#1]#2{% + \stepcounter{address}% + \xdef\address@id{aff\the\c@address}% + \setkeys{address}{#1}% + \@ifundefined{address@id@list}{\xdef\address@id@list{\address@id}}{\xdef\address@id@list{\address@id@list,\address@id}}% + \expandafter\newtoks\csname address@\address@id\endcsname% + \global\csname address@\address@id\endcsname={#2}% +} + + +\def\address@definitions{ + \def\\{\break}% + \def\orgdiv##1{##1}\def\orgname##1{##1}% + \def\street##1{##1}\def\postcode##1{##1}% + \def\postbox##1{##1}\def\city##1{##1}\def\state##1{##1}\def\cny##1{##1}% + \let\interref\surl% +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% printaddress{aff1} + +\newcounter{addressref} +\def\theaddressref{\arabic{addressref}} + +\newif\if@address@mark \@address@marktrue + +\define@key{printaddress}{nomark}[true]{ + \let\thanksmark\@gobble% + \let\thanksref\@gobble}% + +\define@key{printaddress}{addrprefix}{\def\addr@prefix{#1}}% +\let\addr@prefix\relax + +\DeclareRobustCommand{\printaddress}{\@ifnextchar[{\printaddress@fmt}{\printaddress@fmt[]}} + +\def\printaddress@fmt[#1]#2{% +\bgroup% + \setkeys{printaddress}{#1}% + \address@size% + \parindent\z@% + \address@definitions% + \set@address@mark% + \usethankscounter{addressref}\thanksmark{#2}\restorethankscounter% + \addr@prefix% + \@ifundefined{presentaddressref@#2}{}{\presentaddress@text}% + \expandafter\the\@nameuse{address@#2}\unskip\address@sep% +\egroup} + + +\def\thanksbox@printaddress@fmt[#1]#2{% +\bgroup% + \setkeys{printaddress}{#1}% + \address@size% + \parindent\z@% + \address@definitions% + \set@address@mark% + \thanksref{#2}% + \addr@prefix% + \expandafter\the\@nameuse{address@#2}\par% +\egroup} + + +\def\set@address@mark{% + \ifnum\c@author=1\relax \@address@markfalse\fi% + \ifnum\c@address=1\relax \@address@markfalse \fi% + \if@address@mark\else\let\thanksmark\@gobble\let\thanksref\@gobble\fi% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% printaddresses{} + +\def\printaddresses{ + \heading*{\address@text} + \bgroup + \backmatter@style\backmatter@size + \@ifundefined{address@id@list}{}{\@for\address@id:=\address@id@list\do{\printaddress{\address@id}}}% + \csname contributing@text\endcsname% + \par + \egroup + \global\let\printaddresses\relax} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ARTNOTES + +\newif\if@firstnote \@firstnotetrue + +\newenvironment{bmc@artnotes}{% + \def\note{\@ifnextchar[{\@bmcartnote}{\note@nopars}}% + \def\contributionnote##1{\gdef\contributing@text{##1}}% + \note@size% +}{} + + +\def\note@nopars#1{\if@firstnote\vskip\note@skip\@firstnotefalse\fi #1\par} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \artnote + +\def\bmcartnote{\@ifnextchar[{\@bmcartnote}{\@bmcartnote[]}} + +\define@key{bmcartnote}{id}{% + \def\bmcartnote@id{#1}% + \@ifundefined{bmcartnote@id@list}{\xdef\bmcartnote@id@list{#1}}{\xdef\bmcartnote@id@list{\bmcartnote@id@list,#1}}} + +\define@key{bmcartnote}{symbol}{\def\bmcartnote@symbol{#1}} + + +\def\@bmcartnote[#1]#2{{% + \setkeys{bmcartnote}{#1}% + \expandafter\protected@xdef\csname bmcartnote@\bmcartnote@id\endcsname{#2}% + \@ifundefined{bmcartnote@symbol}{}{\expandafter\protected@xdef\csname bmcartnote@symbol@\bmcartnote@id\endcsname{\bmcartnote@symbol}} +}} + + +\def\printartnote#1{% +\bgroup + \@ifundefined{bmcartnote@symbol@#1}% + {\leavevmode\thanksmark{#1}}% + {\edef\@tempa{\csname bmcartnote@symbol@#1\endcsname}\leavevmode\thanksmark[\@tempa]{#1}}% + \@nameuse{bmcartnote@#1}% +\egroup} + +\def\printartnotes{% + \@ifundefined{bmcartnote@id@list}{}{\@for\bmcnote@id:=\bmcartnote@id@list\do{\printartnote{\bmcnote@id}}}% + \global\let\printartnotes\relax% +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% THANKSBOX + +\newbox\thanks@box + +\def\bmc@thanksbox{\@ifnextchar[{\@thanksbox}{\@thanksbox[]}} + +\def\@thanksbox[#1]{% + \global\let\auto@set@thanksbox\relax% + \global\setbox\thanks@box=\vtop\bgroup + \if@twocolumn% + \hsize=\columnwidth% + \else% + \hsize=\leftcol@width% + \hrule width\leftcol@width height0.15\p@% + \vskip2\p@% + \fi% + \thanksbox@size% + \let\printaddress@fmt\thanksbox@printaddress@fmt% + \setkeys{thanksbox}{#1}% + \parindent\z@% + \if@twocolumn\rule\z@\footnotesep\fi% + \ignorespaces% +} + +\def\bmc@endthanksbox{\par\egroup} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \auto@set@thanksbox + +\def\auto@set@thanksbox{% + \@thanksbox[]{% + \@ifundefined{corr@author@id}{}{\printcorrtext{\corr@author@id}}% + \@ifundefined{corref@list}{}{\@for\address@id:=\corref@list\do{\printaddress{\address@id}}\par}% + \authorinfo@text + \printartnotes% + \par + \egroup}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \printcorremail + +% \printcorremail{}{} + +\def\printcorremail#1#2{% + \@ifundefined{num@author}{\@tempcnta=0}{\@tempcnta=\num@author} + \ifnum\@tempcnta=1\relax\else\thanksmark{#1}\fi% + \corref@text\printead*{#2}\par +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \printcorrtext + +%\printcorrtext{} + +\def\printcorrtext#1{% + \corref@thanksmark{#1}% + \corref@text% + \@ifundefined{r@#1@email}{}{\printead*{#1}}% + \par +} + +\let\corref@thanksmark\thanksmark + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ABSTRACTBOX + +\setattribute{absboxsep} {width} {10.25\p@} + +\newbox\abstract@box + +\def\bmc@abstractbox{\@ifnextchar[{\@abstractbox}{\@abstractbox[]}} + +\def\@abstractbox[#1]{% + \@tempdima=\hsize% + \advance\@tempdima by-\absboxsep@width% + \advance\@tempdima by-\absboxsep@width% + \setkeys{abstractbox}{#1}% + \setbox\abstract@box=\vbox\bgroup% + \hsize=\@tempdima% + \ignorespaces% +} + +\def\bmc@endabstractbox{% + \par% + \egroup% + \vglue\abstractbox@skip + \setlength{\fboxsep}{10\p@}% + \setlength{\fboxrule}{0.5\p@}% + \fcolorbox{bmcblue}{white}{\box\abstract@box} +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ABSTRACT + +\def\abstractname@skip{\par\vskip3\p@} + +\newif\if@first@abstract \@first@abstracttrue + +\define@key{abstract}{title}{\def\abstractname{#1}} + +\gdef\bmc@abstract{\@ifnextchar[{\abstract@fmt}{\abstract@fmt[]}} + +\def\abstract@fmt[#1]{% + \if@first@abstract\csname firstabstract@cmd\endcsname\else \vskip\abstract@skip\fi% + \global\@first@abstractfalse% + \def\parttitle##1{% + \vskip3\p@ + \noindent{\bfseries ##1:}} + \setkeys{abstract}{#1}% + \abstract@style% + \abstract@size% + \parindent\true@parindent% + \phantomsection\addcontentsline{toc}{section}{\abstractname}% + \noindent{\abstractname@size\abstractname}\abstractname@skip\ignorespaces\noindent} + + +\def\bmc@endabstract{\par} + +\let\phantomsection\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% KEYWORD +% raktas=class +\setattribute[default]{keyword}{class}{KWD} +\setattribute[default]{keyword}{language}{english} + +% \keyword@class-> KWD +% \keyword@KWD -> AMS 2000... + +%\setattribute{keyword}{language}{french} + +\gdef\bmc@keyword{\@ifnextchar[{\bmc@@keyword}{\bmc@@keyword[class=KWD]}} + +\gdef\bmc@@keyword[#1]{% +% + \do@option@list{keyword}{#1}% + \long\def\@tempa{MSC}% + \ifx\keyword@class\@tempa% + \def\keyword@skip{\z@}% + \fi% +% + \def\sep{\unskip; }% + \vskip\keyword@skip +% + \def\keyword@name{\csname keyword@\keyword@class\endcsname}% + \let\kwd@sep\relax +% + \keyword@style% + \keyword@size% + \parindent\true@parindent% + \def\\{\hfill\break}% + \noindent{\keywordname@size\keyword@name:}\enspace} + +\def\bmc@endkeyword{\par} + +% \kwd[; ]{foo} + \newif\if@firstkeywordinlist \@firstkeywordinlisttrue + + \DeclareRobustCommand*\kwd{\@ifnextchar[\@kwd{\@kwd[\kwd@sep]}}% + + \def\@kwd[#1]#2{% + \ifx.#2.\else\expandafter\gdef\csname @\keyword@class\endcsname{}\fi% + \unskip#1{#2}\if@firstkeywordinlist\addto@keywords@list{#2}\@firstkeywordinlistfalse\else\addto@keywords@list{, #2}\fi\let\kwd@sep\sep}% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% BACKMATTER + +\newenvironment{backmatter} + {\medskip\backmatter@style\backmatter@size\let\section\heading} + {} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% interaction with hyperref + +\def\test@hyperref{\@ifundefined{Hy@SetCatcodes}{}{\bmcart@hyperref@settings}} + +\AtBeginDocument{\test@hyperref} + +\def\bmcart@hyperref@settings{% +% from hyperref maketitle + \def\hy@frontmatter{% + \let\H@@origfootnotemark\@footnotemark + \let\H@@origfootnotetext\@footnotetext + \let\@footnotemark\H@@footnotemark + \let\@footnotetext\H@@footnotetext} + \def\hy@endfrontmatter{ + \ifx\@footnotemark\H@@footnotemark + \let\@footnotemark\H@@origfootnotemark + \fi + \ifx\@footnotetext\H@@footnotetext + \let\@footnotetext\H@@origfootnotetext + \fi} +% hooks for the \thanksref, \thankstext: + \def\thankref@hyperlink##1{% + \edef\@tempx{##1thanks}% + \hbox{\hyperlink{##1}{\saferef{\@tempx}}}} + \def\thanks@hypertarget##1{\smash{\raise\baselineskip\hbox{\protect\hypertarget{##1}{}}}} +% redefine pagenumbering +% \let\pagenumbering\ims@pagenumbering +% activate href + \let\ims@href\href% + \let\safe@phantomsection\phantomsection +% put document info + \def\write@pdfinfo##1##2{\protected@write\@auxout{\no@harm}{\string\gdef\string##1{##2}}} + \@ifundefined{hy@title}{}{\pdfstringdef\@pdftitle{\hy@title}} + \@ifundefined{hy@author}{}{\pdfstringdef\@pdfauthor{\hy@author}} + \@ifundefined{hy@subject}{}{\pdfstringdef\@pdfsubject{\hy@subject}} + \@ifundefined{hy@keywords}{}{\pdfstringdef\@pdfkeywords{\hy@keywords}} +% MathSciNet: + \def\MR##1{\href{http://www.ams.org/mathscinet-getitem?mr=##1}{MR##1}} +} + +\def\write@pdfinfo#1#2{} + +\newtoks\authors@list +\def\addto@authors@list#1{% + \begingroup% + \no@harm% + \xdef\@act{\global\noexpand\authors@list{\the\authors@list#1}}\@act% + \endgroup} + +\newtoks\keywords@list +\def\addto@keywords@list#1{% + \begingroup% + \no@harm% + \xdef\@act{\global\noexpand\keywords@list{\the\keywords@list#1}}\@act% + \endgroup} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% section, subsection etc. +% we do not like article appearance: + +\renewcommand\section{\@startsection {section}{1}{\z@}% + {-\medskipamount}% + {0.001\p@}% + {\sffamily\large\bfseries\raggedright\nohyphen}} + +\renewcommand\subsection{\@startsection {subsection}{2}{\z@}% + {-\medskipamount}% + {0.001\p@}% + {\sffamily\raggedright\nohyphen}} + +\renewcommand\subsubsection{\@startsection{subsubsection}{3}{\z@}% + {-\medskipamount}% + {0.001\p@}% + {\itshape\raggedright}} + +\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}% + {\medskipamount}% + {-10pt}% + {\itshape}} + +\renewcommand\subparagraph{\@startsection{subparagraph}{5}{\parindent}% + {0.1pt}% + {-1em}% + {\itshape}} + + +% Format for the counter: + \def\section@numbersep{} + \def\subsection@numbersep{} + \def\subsubsection@numbersep{} + \def\paragraph@numbersep{} + \def\subparagraph@numbersep{} + +% Format for the counter: +\def\@seccntformat#1{{\csname #1@prefix\endcsname\csname the#1\endcsname\csname#1@numbersep\endcsname\enspace}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% HEADING + +\newcommand\heading{\@startsection{section}{1}{\z@}% + {\smallskipamount}% + {0.001\p@}% + {\backmatter@size\bfseries}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% APPENDIX + + + \renewcommand\appendix{\par + \let\section@cnt@size\appendix@size% + \let\old@section\section% + \def\section{\@ifnextchar*{\@appsectionstar}{\@appsectionnostar}}% + \def\section@prefix{\appendixname\ }% + \def\section@numbersep{:}% + \setcounter{section}{0}% + \setcounter{subsection}{0}% + \gdef\thesection{\@Alph\c@section} +} + + \def\@appsectionstar*#1{% + \old@section*{#1}% + \setcounter{section}{1}% + \addcontentsline{toc}{section}{#1} +} + + \def\@appsectionnostar#1{% + \ifx.#1.% + \def\section@numbersep{}\old@section[\appendixname\ \thesection]{}% + \else% + \def\section@numbersep{:}\old@section{#1}% + \fi} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% thebibliography + + \let\saved@thebibliography\thebibliography + \def\thebibliography{% + \printaddresses% + \backmatter@style\backmatter@size + \let\section\heading\saved@thebibliography} + \def\@biblabel#1{#1.} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fix if natbib is loaded: + +\def\bmcfix@natbib{% + \def\bibfont{\backmatter@style\backmatter@size} + \def\bibsection{% + \printaddresses% + \heading*{\refname}} + \def\bibnumfmt##1{##1.} + \setlength\bibsep{0pt}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fix if amsmath is loaded: + +\def\bmcfix@amsmath{% + \allowdisplaybreaks +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% fix if amsthm is loaded: + +\def\bmcfix@amsthm{% + \thm@notefont{\upshape} + \newtheoremstyle{plain} {\medskipamount}{\medskipamount}{\itshape}{\z@}{\bfseries}{}{1em}{} + \newtheoremstyle{definition}{\medskipamount}{\medskipamount}{\normalfont}{\z@}{\bfseries}{}{1em}{} + \newtheoremstyle{remark} {\medskipamount}{\medskipamount}{\normalfont}{\z@}{\itshape}{}{1em}{} +% + \renewenvironment{proof}[1][\proofname]{\par + \pushQED{\qed}% + \normalfont \topsep\medskipamount% + \trivlist + \labelsep.5em% + \item[\hskip\labelsep + \itshape ##1\@addpunct{}]\ignorespaces + }{\popQED\endtrivlist\@endpefalse} +} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% check for the loaded classes: + +\AtBeginDocument{% + \@ifpackageloaded{natbib}{\bmcfix@natbib}{}% + \@ifpackageloaded{amsthm}{\bmcfix@amsthm}{}% +} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% number lines + +\ifnumberlines@ + + \long\def\l@addto@macro#1#2{% + \toks@\expandafter{#1#2}% + \edef#1{\the\toks@}} + + \setattribute{numberlines}{size}{\scriptsize\ttfamily} + \setattribute{numberlines}{skip}{0\p@} + + \def\numberlines@hook{% + \l@addto@macro\@evenhead\put@numberlines@box% + \l@addto@macro\@oddhead\put@numberlines@box} + + \g@addto@macro\ps@bmcheadings\numberlines@hook + \g@addto@macro\ps@copyright\numberlines@hook + + \newbox\numberlines@box + \newskip\numberlines@box@skip + + \def\set@numberlines@box{% + \setlength\numberlines@box@skip\headsep + \addtolength\numberlines@box@skip{5\p@} + % + \setbox\numberlines@box\vtop to\textheight{% + \parindent\z@ + \vskip\z@ + \@tempcnta=0 + \@tempdima=\z@ + \loop + \advance\@tempcnta by1 + \advance\@tempdima by\baselineskip + \hbox to\textwidth{% + \llap{\numberlines@size\the\@tempcnta\kern\numberlines@skip} + \hfill + \rlap{\numberlines@size\kern\numberlines@skip\the\@tempcnta}} + \ifdim\@tempdima<\textheight\repeat + \vss + }% + % + \ht\numberlines@box\z@ + \dp\numberlines@box\z@ + } + + \def\put@numberlines@box{\lower\numberlines@box@skip\hbox to\z@{\hss\copy\numberlines@box}} + + \AtBeginDocument{\set@numberlines@box} + +\fi + +%**************** INICIALIZATION + +\@twosidetrue +\pagenumbering{arabic} +\frenchspacing +%\init@settings +\pagestyle{bmcheadings} + +\endinput +%% +%% End of file `bmcart.cls'. diff --git a/publications/research-bulletins/in-prog/Readme.md b/publications/research-bulletins/in-prog/Readme.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/publications/research-bulletins/in-prog/Readme.md @@ -0,0 +1 @@ + diff --git a/publications/research-bulletins/in-prog/snark.pdf b/publications/research-bulletins/in-prog/snark.pdf new file mode 100644 index 0000000..6c21feb Binary files /dev/null and b/publications/research-bulletins/in-prog/snark.pdf differ diff --git a/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL-R001-Update.tex b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL-R001-Update.tex new file mode 100644 index 0000000..c53f7ec --- /dev/null +++ b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL-R001-Update.tex @@ -0,0 +1,256 @@ +\documentclass[12pt,english]{mrl} +\usepackage{graphicx} +\usepackage{listings} +\usepackage{cite} +\usepackage{amsthm} + +\usepackage[toc,page]{appendix} + +\renewcommand{\familydefault}{\rmdefault} +\usepackage[T1]{fontenc} +\usepackage[latin9]{inputenc} +\usepackage{color} +\usepackage{babel} +\usepackage{verbatim} +\usepackage{float} +\usepackage{url} +\usepackage{amsthm} +\usepackage{amsmath} +\usepackage{amssymb} +\usepackage[unicode=true,pdfusetitle, bookmarks=true,bookmarksnumbered=false,bookmarksopen=false, breaklinks=false,pdfborder={0 0 1},backref=false,colorlinks=true]{hyperref} +\usepackage{breakurl} +\usepackage{todonotes} + + +\usepackage{amsmath} +\usepackage{amsfonts} +\usepackage{amssymb,enumerate} +\usepackage{amsthm} +\usepackage{cite} +\usepackage{comment} +\usepackage[all]{xy} +%\usepackage[notref,notcite]{showkeys} +\usepackage{hyperref} +\usepackage{todonotes} + +% THEOREM ENVIRONMENTS +\newtheorem*{example}{Example} +\theoremstyle{definition} +\newtheorem{lem}{Lemma}[section] +\newtheorem{cor}[lem]{Corollary} +\newtheorem{prop}[lem]{Proposition} +\newtheorem{thm}[lem]{Theorem} +\newtheorem{soln}[]{Solution} +\newtheorem{conj}[lem]{Conjecture} +\newtheorem{Defn}[lem]{Definition} +\newtheorem{Ex}[lem]{Example} +\newtheorem{Question}[lem]{Question} +\newtheorem{Property}[lem]{Property} +\newtheorem{Properties}[lem]{Properties} +\newtheorem{Discussion}[lem]{Remark} +\newtheorem{Construction}[lem]{Construction} +\newtheorem{Notation}[lem]{Notation} +\newtheorem{Fact}[lem]{Fact} +\newtheorem{Notationdefinition}[lem]{Definition/Notation} +\newtheorem{Remarkdefinition}[lem]{Remark/Definition} +\newtheorem{rem}[lem]{Remark} +\newtheorem{Subprops}{}[lem] +\newtheorem{Para}[lem]{} +\newtheorem{Exer}[lem]{Exercise} +\newtheorem{Exerc}{Exercise} + +\newenvironment{defn}{\begin{Defn}\rm}{\end{Defn}} +\newenvironment{ex}{\begin{Ex}\rm}{\end{Ex}} +\newenvironment{question}{\begin{Question}\rm}{\end{Question}} +\newenvironment{property}{\begin{Property}\rm}{\end{Property}} +\newenvironment{properties}{\begin{Properties}\rm}{\end{Properties}} +\newenvironment{notation}{\begin{Notation}\rm}{\end{Notation}} +\newenvironment{fact}{\begin{Fact}\rm}{\end{Fact}} +\newenvironment{notationdefinition}{\begin{Notationdefinition}\rm}{\end{Notationdefinition}} +\newenvironment{remarkdefinition}{\begin{Remarkdefinition}\rm}{\end{Remarkdefinition}} +\newenvironment{subprops}{\begin{Subprops}\rm}{\end{Subprops}} +\newenvironment{para}{\begin{Para}\rm}{\end{Para}} +\newenvironment{disc}{\begin{Discussion}\rm}{\end{Discussion}} +\newenvironment{construction}{\begin{Construction}\rm}{\end{Construction}} +\newenvironment{exer}{\begin{Exer}\rm}{\end{Exer}} +\newenvironment{exerc}{\begin{Exerc}\rm}{\end{Exerc}} + +\newtheorem{intthm}{Theorem} +\renewcommand{\theintthm}{\Alph{intthm}} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands. +\floatstyle{ruled} +\newfloat{algorithm}{tbp}{loa} +\providecommand{\algorithmname}{Algorithm} +\floatname{algorithm}{\protect\algorithmname} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. +\numberwithin{equation}{section} +\numberwithin{figure}{section} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. +\usepackage{algpseudocode} + +\usepackage{subcaption} + +\numberwithin{equation}{section} + + +\makeatletter + + +\makeatletter + +\newcommand{\h}{\mathcal{H}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% LyX specific LaTeX commands. +\floatstyle{ruled} +\newfloat{algorithm}{tbp}{loa} +\providecommand{\algorithmname}{Algorithm} +\floatname{algorithm}{\protect\algorithmname} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. +\numberwithin{equation}{section} +\numberwithin{figure}{section} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. +\usepackage{algpseudocode} + +\makeatother + +\begin{document} +\begin{frontmatter} + +\begin{fmbox} +{\huge\sffamily Quarterly update} \hfill\setlength{\fboxrule}{0px}\setlength{\fboxsep}{5px}\fbox{\includegraphics[width=2in]{moneroLogo.png}} +\dochead{} +\date{\today} +\author[ + addressref={mrl}, + email={bggoode@g.clemson.edu} +]{\fnm{Brandon} \snm{Goodell}} + + +\address[id=mrl]{ + \orgname{Monero Research Lab} +} +\end{fmbox} + +%\begin{abstractbox} +%This document describes +%\begin{abstract} +%We outline the various ideas currently under investigation by the Monero Research Lab, provide context for each task, and present some informative sources regarding each task. \end{abstract} +%\end{abstractbox} +\end{frontmatter} + +This document is intended to inform the community of the work done at MRL in the past quarter, sort of as a response to the first MRL Roadmap, MRL-R001, and sort of as a newsletter to inform everyone about Monero Research Lab. We try to address the partial MRL ``to-do'' list of research items from the first MRL Research Bulletin, MRL-R001, and document the work that has been done both directly and indirectly toward those ends. We document which items on those lists are being de-prioritized on the next MRL Roadmap, and we introduce a few new items that came up over the past few months that will make it onto the next MRL Roadmap (which we expect to put out in the next two to three weeks). + +The Monero Research Lab wishes to state emphatically that our concern is to report our findings on Monero, which is an open source project, as honestly and transparently as possible, subject to the restriction that we do not compromise the safety or security of the funds of our users by doing so. Our goal is not to persuade, re-assure, or enrich speculators or investors; our goal is to assist the Monero community and the Monero Core Team in the design of a robust and strong cryptocurrency with an emphasis on user privacy. Consequently, all findings will be responsibly disclosed to the Monero community. Responsible disclosure may involve maintaining secrecy regarding security flaws for a period of time before disclosure to the public, which provides the development team time to correct known issues and protect our users. This also provides time to discreetly contact the developers of other cryptocurrencies so they, also, may protect their users. + +Now that is out of the way, here is what we did with our summer: + + +\section{RingCT Security Proofs} + +We have combined this topic with the threshold signature topic (see next item). In \cite{noether2016ring}, there are certain flaws in the proofs of security for MLSAG signatures that need correction, but in the construction of the threshold signature security proofs, we must first establish the security of the MLSAG signatures and then generalize to the threshold setting. Due to this, the corrected RingCT proofs are now part-and-parcel with the threshold multisignature paper. + + +\section{Threshold multisignatures} + +We are fleshing out an implementation proposed by former contributor \texttt{shen} of $t$-of-$n$ threshold MLSAG multisignatures in Monero. The details of this implementation have been available to the community for months, and vetting those implementations and developing security proofs has been one of the more pressing areas of work for \texttt{surae}, especially in the past six weeks. We currently have a partial draft of MRL Research Bulletin MRL-0006 detailing the implementation in preparation (see the MRL github for a current copy). However, this is only partial because completing this document requires novel security models against insider attacks, where an adversary may corrupt a subthreshold number of private keys. Novel security models require novel security proofs, and so we are ``in the weeds'' on that right now. We hoped this would be accomplished before the end of August but the novelty of the security models have taken MRL a little by surprise. A delightful, surprise, but a surprise nonetheless: the novelty of these results may lead to a peer-reviewed publication on behalf of MRL! + + +On a related note, \texttt{surae} began in June approaching the threshold multisignature scheme as a mere problem of \textit{computing private keys jointly}, and this was a complete misunderstanding of the problem at hand, which is to \textit{compute signatures without directly computing the private key.} Consequently, our work on this topic was initially unified with our work on the sub-address scheme described by \texttt{kenshi84} and \texttt{knaccc}, by considering these both as problems involving revamping Monero's addressing schemes. This is also one of the reasons that MRL-R001 failed to elaborate upon the sub-address scheme. Once this mis-understanding was clarified to us (after several very educational and helpful conversations with \texttt{luigi} and \texttt{kenshi84}), MRL is once again approaching these two topics separately. We anticipate an MRL Research Bulletin on the sub-address scheme very soon after MRL-0006 describing threshold signatures is released; security proofs for the sub-address scheme are (ostensibly) remarkably easier than in the threshold case. + +\section{Recent criticisms} + +Critics have claimed the Monero blockchain is traceable, as in \cite{miller2017empirical} and \cite{kumar2017traceability}; these papers make use of the \emph{distributional problem} mentioned in the first roadmap together with a few other routes of analysis. Some of the concerns and claims made in these papers are irrelevant because they only apply to pre-RingCT Monero outputs. Some of the concerns are relevant and related to the so-called EABE attack (see next item). + + + +\section{Churning, EABE Attack, Large Rings} + +Detailed by \texttt{knaccc} in \cite{knaccc2017}, the EABE (Eve-Alice-Bob-Eve) attack is described. A merchant, Bob, and his customer, Alice, use an exchange, Eve, to convert cryptocurrency to fiat and back again. If Eve sends some moneroj to Alice, who uses it to purchase items from the merchant Bob several times, and if Bob immediately converts all cryptocurrency to fiat after each transaction to limit his exposure to the volatility of cryptocurrency-to-fiat exchange rates, then Bob unintentionally provides information Eve needs to determine the purchasing habits of Alice. This problem is exacerbated if Eve is a know-your-customer exchange. Urgency on this problem is higher than our original estimation: most merchants who accept cryptocurrency enact this behavior, most users do not churn to avoid this problem, and moreover churning transactions can leave a statistical signal (in the sense of the Miller and Kumar criticisms) that is quite undesirable. + +This work dovetailed nicely with our road map item \textbf{hardness of blockchain analysis}. In the study of this (as well as the Miller and Kumar criticisms), \texttt{surae} established three separate probabilistic models of transaction output ownership in a ring signature setting in analyzing this problem. None of these models will see publication soon, however, because each one, a refinement of the previous, is insufficient to describe the problem at hand. We do, however, anticipate some explanatory details to be made public over the coming months. MRL has been reluctant to provide more details, as we stated very clearly in our first MRL Roadmap, \emph{we will not comment thoroughly on these criticisms until our review is complete for security reasons.} We will take as much time as necessary for this, and we recognize that issues such as this one are urgent. + +In the current CryptoNote framework, an elegant solution would be to simply increase ring sizes dramatically. This seems impractical, however, unless ring signatures can be made small (perhaps sub-linearly sized with respect to the number of ring members) which leads us to the next item. + +\section{Signature Size and RingCT} + +Blockchain bloat can be mitigated with efficient signatures. MRL was made aware of research by two separate international teams of researchers (see Section \ref{sec:academ}) making progress on compact Ring Confidental Transactions. One scheme (put forth by Sun, Au, Liu, and Yuen) is very efficient and fast but requires a trusted set-up. Another scheme (put forth by Ruffing, Thyagarajan, Ronge, and Schr{\"o}der, or RTRS) does not use a trusted set-up, but experiences a trade-off since the computation and verification times are quite beastly. An RTRS RingCT may contain thousands of ring members and take up the space of a classic RingCT signature with only a few dozen ring members, but the RTRS RingCT could take hours, days, or more to compute. We believe verification time may be optimized to an extent, but it is also quite slow. Currently, \texttt{knaccc} is working with \texttt{surae} and \texttt{sarang} on a Java prototype of the implementation for testing purposes, and discussions with \texttt{smooth}, \texttt{moneromooo}, and \texttt{luigi} on the practicalities of implementation are constant. MRL anticipates that the scheme may be made sufficiently stream-lined to include in Monero for a moderate increase ring size that was previously unreasonable, but not the epic increase initially hoped for. + + +\section{Zero-knowledge Lit Review} + +We began communication with Jeffrey Quesnelle, a computer science graduate student at the University of Michigan at Dearborn, at the start of this quarter. Jeffrey wrote an extremely helpful and detailed literature review on zero-knowledge schemes with an eye toward ZK-SNARKS. We listed this zero-knowledge literature review first in MRL-R001 because it was rather low-hanging fruit... but it also did not present a high priority compared to practical implementation issues (threshold signatures, sub-addresses) or security issues (the EABE attack, see below). Our original date for pushing this out was the end of August 2017, which has come and gone. To be clear, this work has not come to a stop, it is merely delayed; now that \texttt{sarang} has joined MRL, \texttt{surae} has more time to put into finishing this project. MRL anticipates movement on this document before the end of September (in fact, the first week of September). + + +\section{Future-proofing Monero} + +Unlike the above topics, this is actually a constant ``in-the-background'' thing to keep in mind. For example, when we use Pedersen commitments, we have certain hiding and binding properties, but when we use El Gamal commitments, which are similar, these properties change and the commitments are no longer sufficiently hiding against adversaries with quantum computing. Making decisions such as these throughout algorithm design is a constant issue to be considered. Consequently, this item will be removed from future MRL road maps, as it is more of a design philosophy. + +\section{New stuff} + +We have put effort into projects not initially on the MRL Roadmap either due to merit of those projects or urgency. Something related to these items will each make it onto the next MRL Roadmap. + +\begin{enumerate}[i.] +\item \textbf{Viewkey solutions}. Since the CryptoNote framework is not \emph{unlinkable} in the sense of the original CryptoNote whitepaper, an adversary can infer much information about whether a certain address has received transactions without knowing the associated viewkey (as in the EABE scenario). Moreover, viewkeys lack functionality. For example, users may desire revocable viewkeys, or viewkeys only valid for certain periods of time, or may desire viewkeys that grant visibility to outgoing transactions (which should also be revocable). Discussions on viewkey solutions have begun between contributors \texttt{endogenic}, \texttt{knaccc}, \texttt{moneromooo}, \texttt{surae}, and \texttt{fluffypony}. + +\item \textbf{Zidechains}. Even with very large ring sizes, since the CryptoNote framework is not zero-knowledge, information is leaked with each transaction by definition. One method proposed by \texttt{fluffypony} to mitigate this is to construct a zero-knowledge sidechain to peg to the Monero blockchain which we are tentatively calling \textit{zidechains}. + +\item \textbf{Blacklisting provably spent outputs}. Wallet software should avoid including provably-spent outputs in ring signatures if possible, because doing so reduces the relative signer ambiguity of the signature, degrades Monero's claims toward untraceability, and degrades the fungibility of all other Monero outputs. Recently, \texttt{fluffypony} had a conversation with \texttt{gmaxwell} on maintaining curated blacklists of provably spent outputs, and \texttt{surae} has begun work on algorithms for finding provably-spent transaction outputs. +\end{enumerate} + + +\section{Dead Items} + +Recall that the items deeper on the MRL Roadmap were items of lower priority. We did not have an opportunity to make progress on the following issues, all of which are very long-term, in terms of priority. These items are worthwhile side hustles for future research, but do not have a lot of immediate pay-off. + +\begin{enumerate}[i.] + \item \textbf{Testing Blockchain Dynamics with Population-driven Modeling.} + + \item \textbf{Blockchain Design}. + + \item \textbf{Traceability, extending RingCT to obscure transaction time.} +\end{enumerate} + +\section{Academic Engagement}\label{sec:academ} + +In the past three months, Monero Research Lab has had some great interaction with the broader academic community, briefly mentioned above. We wish to highlight the following, which is big news! + +\begin{enumerate}[(i)] + +\item Shi-Feng Sun at Hong Kong Polytechnic University, Man Ho Au at Shanghai Jiao Tong University, Joseph K Liu at Monash University, and Tsz Hon Yuen at Huawei Technologies wrote ``RingCT 2.0: A Compact Accumulator-Based (Linkable Ring Signature) Protocol for Blockchain Cryptocurrency Monero,'' a paper proposing a much more efficient and speedy implementation of Ring Confidential Transactions. These researchers have been instrumental in ID-based cryptography and ring signatures, so their contribution directly to Monero, literally mentioning us in their paper title was surprising, exciting, and a huge honor! + +\item Nearly at the same time, Tim Ruffing at Saarlang University together with Sri Aravinda Thyagarajan, Viktoria Ronge, and Dominique Schr{\"o}der at Friedrich-Alexander-Universit{\"a}t contacted us directly with a separate Ring Confidental Transaction scheme, with a very different Ring Confidential Transaction scheme (see below). We have had a few conversations with him about implementation choices; thanks to hard work by \texttt{knaccc} and \texttt{surae}, we have a nearly-working prototype (to Ruffing's surprise! \texttt{knaccc} works quick). + +\item In implementing the Ruffing scheme, Monero Research Lab has also been in contact with Jonathan Bootle at University College in London about a set-up presented in one of his papers used in the Ruffing scheme; not only are we the first (to his knowledge) to implement his set-ups, but we also identified a small mistake in the notation of his paper that will be corrected. + +\item Thanks to community donations to the Forum Funding System, hired Sarang Noether! He recently graduated with his Ph.D.\ in Computational Physics (and has a strong background in pure and applied mathematics, computer science, and network security) and was a contributor to MRL several years back. We are already enjoying his contribution to our work. We are extremely grateful that the community has welcomed him; he was facing several competitive offers for some very interesting and varied jobs in a few different engineering sectors, so we are lucky to have sniped him away from the traditional economy! + +\end{enumerate} + + + + +\section{Conclusion} + +We request members of the community contribute their opinions on our above work and ideas they would like to see added. Please do not hesitate to contact us. We will make the current threshold MRL Bulletin (which will be MRL-0006) available on the MRL github upon publication of this quarterly update so that contributors and community members can monitor our progress on that front. + +In the next four weeks, we anticipate MRL-R002 roadmap to be put out, the second draft of the zero-knowledge literature review with Jeffrey Quesnelle to be made available to the community, and MRL-0006 to be completed and put out (unless the novelty of the security proofs becomes a rabbit hole of uknown depth). We also anticipate that the RTRS Ring Confidential Transaction scheme to be finished prototyping and beginning testing very soon. Once MRL-0006 is finished, we will begin an MRL Research Bulletin describing the sub-address scheme invented by \texttt{kenshi84} and \texttt{knaccc} to be fleshed out (MRL-0007). + + + + +\section{Special Thanks} + +We would like to issue a special thanks to the members of the Monero community who used the GetMonero.org Forum Funding System to support the Monero Research Lab. Readers may also regard this as a statement of conflict of interest, since our funding is denominated in Monero and provided directly by members of the Monero community by the Forum Funding System. + +\medskip{} + +\bibliographystyle{plain} +\bibliography{biblio.bib} + +\end{document} diff --git a/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_2017_Q1_Update.pdf b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_2017_Q1_Update.pdf new file mode 100644 index 0000000..b027c8e Binary files /dev/null and b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_2017_Q1_Update.pdf differ diff --git a/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_R001__Roadmap.pdf b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_R001__Roadmap.pdf index c484f7a..8b0d1fd 100644 Binary files a/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_R001__Roadmap.pdf and b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/MRL_R001__Roadmap.pdf differ diff --git a/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/biblio.bib b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/biblio.bib index 27ebf47..d51624f 100644 --- a/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/biblio.bib +++ b/publications/research-roadmaps/MRL-R001 Priorities for Monero Research Lab/biblio.bib @@ -1,16 +1,16 @@ @article{nakamoto2008bitcoin, - title={Bitcoin: A peer-to-peer electronic cash system}, + title={{B}itcoin: {A} peer-to-peer electronic cash system}, author={Nakamoto, Satoshi} } @techreport{grenander1981abstract, - title={Abstract inference}, + title={Abstract {I}nference}, author={Grenander, Ulf and Ulf, Grenander}, year={1981} } @article{massey1996estimating, - title={Estimating the parameters of a nonhomogeneous Poisson process with linear rate}, + title={{E}stimating the parameters of a nonhomogeneous {P}oisson process with linear rate}, author={Massey, William A and Parker, Geraldine A and Whitt, Ward}, journal={Telecommunication Systems}, volume={5}, @@ -21,7 +21,7 @@ } @inproceedings{decker2013information, - title={Information propagation in the bitcoin network}, + title={{I}nformation propagation in the {B}itcoin network}, author={Decker, Christian and Wattenhofer, Roger}, booktitle={Peer-to-Peer Computing (P2P), 2013 IEEE Thirteenth International Conference on}, pages={1--10}, @@ -30,7 +30,7 @@ } @article{sompolinsky2013accelerating, - title={Accelerating Bitcoin's Transaction Processing. Fast Money Grows on Trees, Not Chains.}, + title={Accelerating {B}itcoin's Transaction Processing. Fast Money Grows on Trees, Not Chains.}, author={Sompolinsky, Yonatan and Zohar, Aviv}, journal={IACR Cryptology ePrint Archive}, volume={2013}, @@ -39,13 +39,13 @@ } @article{macheta2014counterfeiting, - title={Counterfeiting via Merkle Tree Exploits within Virtual Currencies Employing the CryptoNote Protocol}, + title={Counterfeiting via Merkle Tree Exploits within Virtual Currencies Employing the {C}ryptoNote Protocol}, author={Macheta, Jan and Noether, Sarang and Noether, Surae and Smooth, Javier}, year={2014} } @incollection{eyal2014majority, - title={Majority is not enough: Bitcoin mining is vulnerable}, + title={Majority is not enough: {B}itcoin mining is vulnerable}, author={Eyal, Ittay and Sirer, Emin G{\"u}n}, booktitle={Financial Cryptography and Data Security}, pages={436--454}, @@ -68,14 +68,14 @@ } @article{miller2017empirical, - title={An Empirical Analysis of Linkability in the Monero Blockchain}, + title={An Empirical Analysis of Linkability in the {M}onero Blockchain}, author={Miller, Andrew and M{\"o}ser, Malte and Lee, Kevin and Narayanan, Arvind}, journal={arXiv preprint arXiv:1704.04299}, year={2017} } @inproceedings{au2006constant, - title={Constant-size ID-based linkable and revocable-iff-linked ring signature}, + title={Constant-size {ID}-based linkable and revocable-iff-linked ring signature}, author={Au, Man Ho and Liu, Joseph K and Susilo, Willy and Yuen, Tsz Hon}, booktitle={International Conference on Cryptology in India}, pages={364--378}, @@ -102,14 +102,14 @@ } @article{kumar2017traceability, - title={A Traceability Analysis of Monero's Blockchain}, + title={A Traceability Analysis of {M}onero's Blockchain}, author={Kumar, Amrit and Fischer, Cl{\'e}ment and Tople, Shruti and Saxena, Prateek}, year={2017} } @misc{knaccc2017, author = {knaccc}, - title = {Potential Privacy Leaks in Monero and Churning}, + title = {Potential Privacy Leaks in {M}onero and Churning}, year = {2017}, publisher = {GitHub}, journal = {GitHub repository}, @@ -164,7 +164,7 @@ url = {http://gen.lib.rus.ec/scimag/index.php?s=10.2307/166755}, } @article{doob1942topics, - title={Topics in the theory of Markoff chains}, + title={Topics in the theory of {M}arkoff chains}, author={Doob, Joseph L}, journal={Transactions of the American Mathematical Society}, volume={52}, @@ -175,7 +175,7 @@ url = {http://gen.lib.rus.ec/scimag/index.php?s=10.2307/166755}, } @article{doob1945markoff, - title={Markoff chains--denumerable case}, + title={{M}arkoff chains--denumerable case}, author={Doob, Joseph L}, journal={Transactions of the American Mathematical Society}, volume={58}, diff --git a/publications/txt-standards/Ruffct.txt b/publications/txt-standards/Ruffct.txt new file mode 100644 index 0000000..1597ce6 --- /dev/null +++ b/publications/txt-standards/Ruffct.txt @@ -0,0 +1,441 @@ + BOOTLE-RUFFING RINGCT SCHEME + ---------------------------- + Sublinear-sized ring signatures without trusted + set-ups or bilinear pairings. Summarized for + Monero Research Lab by B Goodell + +We describe sublinear-sized ring signatures for use in cryptocurrency. This +scheme was first sent to MRL by Ruffing and co-authors. These results use +tools first described by Bootle, et al in the paper "Short Accountable Ring +Signatures Based on DDH," 2015 European Symposium on Research in Computer Sec- +urity, use a "vanilla" elliptic curve multisignature scheme first described by +Bellare and Neven in "Multi-signatures in the plain public-key model and a gen-\ +eral forking lemma," 2006 Proceedings of the 13th, ACM conference on Computer and +Communications Security. + +This is a living document and will be updated. In section I, the introduction, +we introduce the general idea of the scheme together with preliminary stuff. +We have a section on homomorphic commitments and encryption, a section on +ordinary multi-signatures, and a section on the NIZK proof systems presented +by Bootle et al. In section II, we present pseudocode describing Ruffing's +scheme. In section III, references. + + I. INTRODUCTION + +The scheme presented by Ruffing roughly works as follows, exploiting homo- +morphic commitments. Sender Sally uses L of her txnout keys to send some amount +stored in a commitment to receiver Roy. Sally wishes to implicate N-1 other +senders, so she constructs an LxN matrix of public keys (L = # key images used, +N = ring size) by picking random public keys from the anonymity set; she stores +her own pubkeys in some secret column i*. Sally demonstrates that the output +amount from her secret column and the input amount are the same without re- +vealing that column or the amounts by using a NIZK proof from the Bootle paper +to show that at least one commitment in a vector opens to zero. In the constru- +ction of this proof, she uses information from her secret keys, which binds the +index she can open to zero to the column of pubkeys in the matrix without re- +vealing which index. She uses her secret keys to construct a multisignature on +the Bootle proof that is verifiable with the key images only. This way, her +signature consists of some random information, a Bootle proof, and a multi- +signature on the Bootle proof. The multisignature is efficient in construction, +verification, and storage. The Bootle proof, for a vector of commitments of +length N = n^m, takes O(n*m) (roughly) for construction, verification, and sto- +rage. For a ring size N=n^m, for a fixed ring base n (say all ring sizes are +powers of n=16), the Ruffing scheme is approximately log(N). + +The scheme consists of four algorithms, KEYGEN, SPEND, and VER, which we des- +cribe in the next section. The scheme uses multisignatures and Bootle proofs +as subroutines, and hammers on homomorphic commitment very hard, so we describe +these in this section as "pre-requisites". The Bootle method is an interactive +sigma protocol that uses another interactive sigma protocol as a subroutine. We +made these both non-interactive and present the pseudocode in PROVE1, VALID1, +PROVE2, VALID2 (the Ruffing scheme uses PROVE2, VALID2, which use PROVE1, +VALID1). The Ruffing scheme did not specify a multisignature scheme; we desc- +ribe here the pseudocode for the Bellare-Neven multisignature scheme, KEYGEN*, +SIG*, VER*. + + a. Commitments and Encryption + +To commit to a scalar x with some random mask r, we use the following options: + + COMp(x; r) := rG + xHp(xG) # Unconditionally hiding Pedersen + COMeg(x; r) := (rG + xHp(xG), rG) # Computationally hiding El Gamal + +We may extend these to a vector/array/matrix B=[b[j][i]; j=0...m-1,i=0..n-1]: + + COMp(B; r) := rG + b[0][0]Hp(b[0][0]G) + ... + b[m-1][n-1]Hp(b[m-1][n-1]G) + +and we can similarly lift this to an El Gamal commitment by appending rG. In +the first case, we refer to x or the matrix B as the "data under commitment" +and the value r as the "mask." Given a Pedersen commitment c, we open c by +revealing x and r, where a verifier checks that c == rG + xHp(xG). Given an +El Gamal commitment (C1, C2), we open by revealing r and x, a verifier +computes C2' = rG, C1' = rG + xHp(xG) from these, and lastly checks that +C1 == C1' and C2 == C2'. + +These commitments are additive under the following definition: + + COMp(x; r) + COMp(x'; r') := COMp(x+x'; r+r') + COMeg(x; r) + COMeg(x'; r') := COMeg(x+x'; r+r') + + + b. Ordinary Multi-signature + +The Ruffing scheme utilizes as a subroutine an efficient multisignature scheme, +consisting of three algorithms (KEYGEN*, SIG*, VER*). We present a scheme based +on the scheme described by Bellare and Neven in 2006 [3] (which is, in turn, +based on Schnorr signatures). Our variation of the B&N scheme is that it is +executed only by one party holding all the keys, so interaction is unnecessary. +We use a group of prime order q. Ruffing's scheme assumes that the Decisional +Diffie-Hellman assumption holds, so there is no harm in making this assumption +for the ordinary multi-signature scheme. Let G be a commonly known generator of +the group. Let Hs be a hash function that produces a scalar in Zq. Let Zq denote +the integers modulo q. + +KEYGEN*: Each user selects x at random from Zq. The secret key is x. The +public key is X=xG. Output (sk,pk) = (x,X). + +SIG*: Take as input a message M and a list of private keys L = x[0], x[1], +..., x[n-1]. Let L' be the associated list of public keys X[0], ..., X[n-1], +and assume L' is lexicographically ordered. + 1) Compute L* = H(L'). + 2) For each i=0,1,...,n-1, select r[i] at random from Zq. + 3) Compute r=r[0]+r[1]+...+r[n-1] and R=rG. + 4) For each i=0,1,...,n-1: + i) Compute c[i] := Hs(X[i], R, L*, M) + ii) Compute s[i] := r[i] + x[i]*c[i] + 5) Compute s = s[0] + ... + s[n-1]. + 6) Output the signature sigma = (R, s) + +VER*: Take as input a message M, a set of keys L' = X[0], ..., X[n-1], and a +signature sigma = (R,s). + 1) Compute L* = H(L') + 2) For each i=0,1,...,n-1, compute c[i] = Hs(X[i], R, L*, M) + 3) Accept if and only if sG = R + c[0]*X[0] + ... + c[n-1]*X[n-1] + + c. NIZK Proofs +====|====|====|====|====|====|====|====|====|====|====|====|====|====|====|==== +Lastly, the scheme also utilizes the following algorithms, (PROVE1, VALID1), +and (PROVE2, VALID2), which are NIZK prove-and-verify algorithm pairs. These +use the Fiat-Shamir transformation to make the zero-knowledge sigma protocols +presented by Bootle non-interactive under the random oracle model. The second +algorithm requires the usage of a helper algorithm, COEFs, which computes +coefficients of certain polynomials. + +The pair (PROVE1, VALID1) allows a prover to demonstrate that each row of a +matrix is a set of commitments to bits that open to exactly one 1 (the rest +open to 0). The implementation works like this: + +PROVE1: Take as input ([[b[0][0], b[0][1], ..., b[m-1][n-1]] ], r). + 1) Select r[A], r[C], r[D] at random from Zq. + 2) For each j=0, 1,..., m-1 and for each i=1,2,...,n-1, select a[j][i] + from Zq at random. + 3) For each j, compute a[j][0] = -a[j][1] - a[j][2] - ... - a[j][n-1]. + 4) Compute A:=COMp(a[0][0], ..., a[m-1][n-1]; r[A]) + 5) For each j=0,...,m-1 and i=0,...,n-1, compute the values + c[j][i] := a[j][i]*(1-2*b[j][i]) + d[j][i] := -a[j][i]^2 + 6) Compute the commitments C:=COMp(c[0][0], ..., c[m-1][n-1]; r[C]) and + D:=COMp(d[0][0],...,d[m-1][n-1]; r[D]). + 7) Compute x := Hs(A,C,D) + 8) For each j=0,...,m-1, i=0,...,n-1, compute f[j][i]:=b[j][i]*x + a[j][i] + 9) Compute z[A]:= r*x + r[A], z[C]:=r[C]*x+r[D] + 10) Output proof P:=A,C,D, f[0][1],f[0][2], ..., f[0][n-1], f[1][1], + f[1][2], ..., f[1][n-1], ..., f[m-1][1], ..., f[m-1][n-1], z[A], z[C]. + +When PROVE1 is run as a subroutine for PROVE2, the prover will also output the +values of each a[j][i]; these are not part of the formal proof, but they are +used elsewhere. Note that we do not output the first column of the matrix F +whose (ji)^th entry is f[j][i]. Essentially here, we are taking a matrix, we +are showing each row sums to 1 and each element satisfies the equation +b[j][i]*(1-b[j][i]) = 0. + +VALID1: Take as input B (the prover wishes to demonstrate B is a commitment to +the values b[j][i] as described in PROVE1) and proof P. + 1) If A,B,C,D are each elliptic curve points, both z[A] and z[C] are ele- + ments of Zq, and each f[j][i] are elements of Zq, compute the value + x := Hs(A,C,D). Else, output FAIL and terminate. + 2) For each j=0, ..., m-1, compute f[j][0] = x-f[j][1] - ... - f[j][n-1]. + 3) For each j=0, ..., m-1, i=0,...,n-1, compute each of the values + f'[j][i] := f[j][i]*(x-f[j][i]) + 4) Return 1 if and only if all of the conditions hold true: + i) For each j=0, ..., m-1, f[j][0]=x-f[j][1]-f[j][2]- ... -f[j][n-1] + ii) xB + A = COMp(f[0][0], ..., f[m-1][n-1]; z[A]) + iii) xC + D = COMp(f'[0][0], ..., f'[m-1][n-1]; z[C]) + (otherwise return 0). + +The pair (PROVE2, VALID2) allows a prover to demonstrate that a sequence of +commitments contains at least one commitment to 1. The implementation works +like this: + +PROVE2: Take as input a sequence of values c[0], c[1], ... c[N-1] for +some N= n^m, a secret index i* in this list corresponding to a commitment that +opens to 1, and a random scalar r in Zq. For all integers j, i, define the +Kronecker delta function as DELTA(j,i) := 1 if j=i and 0 otherwise. + 1) For k=0, 1, ..., m-1, select random coefficient u[k] at random from Zq. + 2) Select r[B] at random from Zq. + 3) Write i* in n-ary i* = i*[0] + i*[1]*(n) + i*[2]*(n^2) + ... + ... + i*[m-1]*(n^(m-1)), and represent i* as the sequence i*[j]. + 4) For each j=0, 1, ..., m-1 and i=0, 1, ..., n-1, define the values + d[j][i] := DELTA(i*[j],i). + 5) Compute B:=COMp(d[0][0], ..., d[m-1][n-1]; r[B]). + 6) Prover runs PROVE1 and stores the output as the list of data + P <- PROVE1(B, (d[0][0], ..., d[m-1][n-1], r[B])) and stores the values + a[j][i] for use in the next step. Note the prover receives A, C, D from + PROVE1, all the values f[j][i], and the values z[A], z[C]. + 7) coefs <- COEFS(a[0][0], ..., a[m-1][n-1], i*) + 8) For k=0, ..., m-1: + i) G[k] := ENCeg(0, u[k]) # = (rHp(G), rG) + ii) For i=0, ..., N-1, update G[k] by multiplying: + G[k]=G[k]*(co[i]^coefs[i][k]) + =(G[k][1]+coefs[i][k]*co[i][1], G[k][2]+coefs[i][k]*co[i][2]) + The final value for each G[k] from step 8 can be written explicitly: + G[k]=(rHp(G)+coefs[0][k]*co[0][1] + ... +coefs[n-1][k]*co[n-1][1], + rG+coefs[0][k]*co[0][2] + ... +coefs[n-1][k]*co[n-1][2]) + 9) Compute x' = Hs(A,B,C,D, G[0], ..., G[m-1]). + 10) Compute z:= r*(x')^m - u[m-1]*(x')^(m-1) - ... - u[1]*(x')^1 - u[0] + 11) Output proof P':=P, B, G[0], ..., G[m-1], z. + +VALID2: Take as input a list of N El Gamal commitments co[0], ..., co[N-1] and a +proof P' parsed as P, B, G[0],...,G[m-1], where P is a proof parsed as +P = A,C,D, f[0][1],f[0][2], ..., f[m-1][n-1], z[A], z[C]. + 1) If A,B,C,D, each G[k] are all elliptic curve points, and if z[A], z[C], + and z are elements of Zq, and if each f[j][i] are elements of Zq, and + if VALID1(B,P)=1, then compute the value + x' := Hs(A, B, C,D,G[0],...,G[m-1]). + Else, output FAIL and terminate. + 2) Compute c := ENCeg(0,z). + 3) For each k=0,...,m-1, compute + G[k]^(-x^k) := (-x^k*G[k][1],-x^k*G[k][2]). + 4) Compute (G[0]^(-(x')^0))*(G[1]^(-(x')^1))*...*(G[m-1]^(-(x')^(m-1)) + which explicitly is the ordered pair (G*[1], G*[2]): + (-G[0][1] - (x')G[1][1] - ... - (x')^(m-1)G[m-1][1], + -G[0][2] - (x')G[1][2] - ... - (x')^(m-1)G[m-1][2] ) + 5) For each j=0, ..., m-1, i=0,...,n-1, compute each of the values + f[j][0] := x' - f[j][1] - f[j][2] - ... - f[j][n-1]. + 6) For each i=0,...,N-1, write i in n-ary arithmetic as usual as + i = i[0] + i[1]*n + i[2]*(n^2) + ... + i[m-1]*(n^(m-1)). Compute the + values g[i] := f[0][i[0]]*f[1][i[1]]*...*f[m-1][i[m-1] and the + commitments co*[i] := co[i]^g[i] = (g[i]*co[i][1], g[i]*co[i][2]). + 7) Compute (co*[0])*(co*[1])*...*(co*[N-1]) which ends up as the ordered + pair (c**[1], c**[2]) + (c*[0][1] + c*[1][1] + ... c*[N-1][1], c*[0][2] + ... c*[N-1][2]) + 8) Compute c'=(c**[1],c**[2])*(G*[1],G*[2])=(c**[1]+G*[1], c**[2] + G*[2]). + 9) Return 1 if and only if c' == c and 0 otherwise. + +COEFS: We split this into two algorithms. The outer layer, COEFS, is specific +to the Ruffing scheme. The inner layer, COEFPROD, takes two sequences of coef- +ficients as input, representing polynomials, and outputs a sequence of coef- +ficients of the resulting product of those two polynomials. We denote the +Discrete Fourier Transform as DFT, and the inverse IDFT. + +COEFS takes as input a matrix A = a[0][0], ..., a[m-1][n-1] and index i* such +that 0 <= i* < n^m. We decompose 0 <= i* < N into the n-ary representation + i* = i*[0] + i*[1]*n + ... + i*[m-1]*n^(m-1) +In this decomposition, for each 0 <= j < m, we have the constraint +0 <= i*[j] < n (otherwise we could include the "runoff" above n into the co- +efficient one index higher). For index 0 <= k < N we again decompose into +the n-ary representation + k = k[0] + k[1]*n + ... + k[m-1]*n^(m-1) +where for each index 0 <= j < m (where N=n^m), we have 0 <= k[j] < n. We rep- +resent the polynomial defined by DELTA(i*[j],k[j])*x + a[j][k[j]] as an array + q[j][k] = [a[j][k[j]], DELTA(i*[j],k[j])] +We then do the following: + 1) For each k = 0, ..., N-1: + i) Compute coefList[k] : = q[0][k] + ii) For 1<=j + +#include "crypto-ops.h" + +/* sqrt(x) is such an integer y that 0 <= y <= p - 1, y % 2 = 0, and y^2 = x (mod p). */ +/* d = -121665 / 121666 */ +const fe fe_d = {-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116}; /* d */ +const fe fe_sqrtm1 = {-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482}; /* sqrt(-1) */ +const fe fe_d2 = {-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199}; /* 2 * d */ + +/* base[i][j] = (j+1)*256^i*B */ +const ge_precomp ge_base[32][8] = { + { + {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, + {{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303}, + {-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081}, + {26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697}}, + {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, + {{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540}, + {23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397}, + {7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325}}, + {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, + {{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777}, + {-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737}, + {-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652}}, + {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, + {{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726}, + {-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955}, + {27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425}} + }, { + {{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171}, + {27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510}, + {17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660}}, + {{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639}, + {29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963}, + {5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950}}, + {{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568}, + {12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335}, + {25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628}}, + {{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007}, + {-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772}, + {-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653}}, + {{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567}, + {13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686}, + {21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372}}, + {{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887}, + {-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954}, + {-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953}}, + {{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833}, + {-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532}, + {-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876}}, + {{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268}, + {33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214}, + {1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038}} + }, { + {{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800}, + {4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645}, + {-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664}}, + {{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933}, + {-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182}, + {-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222}}, + {{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991}, + {20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880}, + {9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092}}, + {{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295}, + {19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788}, + {8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553}}, + {{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026}, + {11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347}, + {-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033}}, + {{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395}, + {-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278}, + {1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890}}, + {{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995}, + {-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596}, + {-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891}}, + {{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060}, + {11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608}, + {-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606}} + }, { + {{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389}, + {-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016}, + {-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341}}, + {{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505}, + {14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553}, + {-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655}}, + {{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220}, + {12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631}, + {-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099}}, + {{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556}, + {14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749}, + {236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930}}, + {{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391}, + {5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253}, + {20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066}}, + {{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958}, + {-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082}, + {-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383}}, + {{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521}, + {-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807}, + {23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948}}, + {{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134}, + {-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455}, + {27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629}} + }, { + {{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069}, + {-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746}, + {24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919}}, + {{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837}, + {8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906}, + {-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771}}, + {{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817}, + {10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098}, + {10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409}}, + {{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504}, + {-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727}, + {28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420}}, + {{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003}, + {-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605}, + {-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384}}, + {{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701}, + {-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683}, + {29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708}}, + {{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563}, + {-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260}, + {-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387}}, + {{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672}, + {23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686}, + {-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665}} + }, { + {{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182}, + {-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277}, + {14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628}}, + {{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474}, + {-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539}, + {-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822}}, + {{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970}, + {19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756}, + {-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508}}, + {{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683}, + {-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655}, + {-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158}}, + {{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125}, + {-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839}, + {-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664}}, + {{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294}, + {-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899}, + {-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070}}, + {{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294}, + {-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949}, + {-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083}}, + {{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420}, + {-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940}, + {29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396}} + }, { + {{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567}, + {20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127}, + {-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294}}, + {{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887}, + {22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964}, + {16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195}}, + {{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244}, + {24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999}, + {-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762}}, + {{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274}, + {-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236}, + {-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605}}, + {{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761}, + {-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884}, + {-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482}}, + {{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638}, + {-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490}, + {-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170}}, + {{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736}, + {10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124}, + {-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392}}, + {{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029}, + {6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048}, + {28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958}} + }, { + {{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593}, + {26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071}, + {-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692}}, + {{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687}, + {-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441}, + {-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001}}, + {{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460}, + {-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007}, + {-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762}}, + {{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005}, + {-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674}, + {4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035}}, + {{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590}, + {-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957}, + {-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812}}, + {{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740}, + {-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122}, + {-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158}}, + {{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885}, + {26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140}, + {19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857}}, + {{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155}, + {19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260}, + {19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483}} + }, { + {{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677}, + {32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815}, + {22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751}}, + {{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203}, + {-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208}, + {1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230}}, + {{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850}, + {-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389}, + {-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968}}, + {{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689}, + {14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880}, + {5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304}}, + {{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632}, + {-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412}, + {20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566}}, + {{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038}, + {-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232}, + {-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943}}, + {{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856}, + {23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738}, + {15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971}}, + {{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718}, + {-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697}, + {-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883}} + }, { + {{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912}, + {-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358}, + {3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849}}, + {{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307}, + {-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977}, + {-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335}}, + {{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644}, + {-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616}, + {-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735}}, + {{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099}, + {29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341}, + {-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336}}, + {{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646}, + {31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425}, + {-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388}}, + {{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743}, + {-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822}, + {-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462}}, + {{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985}, + {9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702}, + {-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797}}, + {{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293}, + {27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100}, + {19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688}} + }, { + {{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186}, + {2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610}, + {-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707}}, + {{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220}, + {915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025}, + {32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044}}, + {{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992}, + {-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027}, + {21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197}}, + {{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901}, + {31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952}, + {19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878}}, + {{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390}, + {32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730}, + {2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730}}, + {{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180}, + {-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272}, + {-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715}}, + {{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970}, + {-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772}, + {-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865}}, + {{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750}, + {20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373}, + {32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348}} + }, { + {{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144}, + {-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195}, + {5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086}}, + {{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684}, + {-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518}, + {-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233}}, + {{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793}, + {-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794}, + {580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435}}, + {{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921}, + {13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518}, + {2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563}}, + {{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278}, + {-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024}, + {4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030}}, + {{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783}, + {27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717}, + {6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844}}, + {{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333}, + {16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048}, + {22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760}}, + {{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760}, + {-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757}, + {-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112}} + }, { + {{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468}, + {3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184}, + {10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289}}, + {{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066}, + {24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882}, + {13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226}}, + {{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101}, + {29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279}, + {-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811}}, + {{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709}, + {20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714}, + {-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121}}, + {{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464}, + {12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847}, + {13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400}}, + {{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414}, + {-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158}, + {17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045}}, + {{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415}, + {-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459}, + {-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079}}, + {{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412}, + {-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743}, + {-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836}} + }, { + {{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022}, + {18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429}, + {-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065}}, + {{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861}, + {10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000}, + {-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101}}, + {{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815}, + {29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642}, + {10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966}}, + {{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574}, + {-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742}, + {-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689}}, + {{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020}, + {-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772}, + {3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982}}, + {{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953}, + {-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218}, + {-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265}}, + {{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073}, + {-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325}, + {-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798}}, + {{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870}, + {-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863}, + {-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927}} + }, { + {{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267}, + {-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663}, + {22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862}}, + {{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673}, + {15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943}, + {15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020}}, + {{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238}, + {11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064}, + {14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795}}, + {{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052}, + {-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904}, + {29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531}}, + {{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979}, + {-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841}, + {10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431}}, + {{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324}, + {-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940}, + {10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320}}, + {{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184}, + {14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114}, + {30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878}}, + {{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784}, + {-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091}, + {-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585}} + }, { + {{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208}, + {10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864}, + {17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661}}, + {{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233}, + {26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212}, + {-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525}}, + {{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068}, + {9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397}, + {-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988}}, + {{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889}, + {32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038}, + {14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697}}, + {{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875}, + {-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905}, + {-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656}}, + {{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818}, + {27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714}, + {10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203}}, + {{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931}, + {-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024}, + {-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084}}, + {{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204}, + {20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817}, + {27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667}} + }, { + {{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504}, + {-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768}, + {-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255}}, + {{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790}, + {1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438}, + {-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333}}, + {{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971}, + {31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905}, + {29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409}}, + {{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409}, + {6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499}, + {-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363}}, + {{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664}, + {-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324}, + {-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940}}, + {{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990}, + {-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914}, + {-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290}}, + {{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257}, + {-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433}, + {-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236}}, + {{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045}, + {11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093}, + {-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347}} + }, { + {{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191}, + {-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507}, + {-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906}}, + {{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018}, + {-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109}, + {-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926}}, + {{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528}, + {8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625}, + {-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286}}, + {{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033}, + {27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866}, + {21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896}}, + {{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075}, + {26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347}, + {-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437}}, + {{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165}, + {-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588}, + {-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193}}, + {{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017}, + {-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883}, + {21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961}}, + {{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043}, + {29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663}, + {-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362}} + }, { + {{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860}, + {2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466}, + {-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063}}, + {{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997}, + {-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295}, + {-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369}}, + {{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385}, + {18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109}, + {2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906}}, + {{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424}, + {-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185}, + {7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962}}, + {{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325}, + {10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593}, + {696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404}}, + {{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644}, + {17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801}, + {26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804}}, + {{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884}, + {-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577}, + {-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849}}, + {{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473}, + {-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644}, + {-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319}} + }, { + {{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599}, + {-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768}, + {-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084}}, + {{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328}, + {-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369}, + {20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920}}, + {{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815}, + {-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025}, + {-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397}}, + {{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448}, + {6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981}, + {30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165}}, + {{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501}, + {17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073}, + {-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861}}, + {{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845}, + {-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211}, + {18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870}}, + {{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096}, + {33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803}, + {-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168}}, + {{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965}, + {-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505}, + {18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598}} + }, { + {{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782}, + {5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900}, + {-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479}}, + {{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208}, + {8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232}, + {17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719}}, + {{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271}, + {-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326}, + {-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132}}, + {{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300}, + {8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570}, + {15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670}}, + {{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994}, + {-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913}, + {31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317}}, + {{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730}, + {842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096}, + {-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078}}, + {{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411}, + {-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905}, + {-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654}}, + {{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870}, + {-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498}, + {12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579}} + }, { + {{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677}, + {10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647}, + {-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743}}, + {{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468}, + {21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375}, + {-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155}}, + {{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725}, + {-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612}, + {-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943}}, + {{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944}, + {30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928}, + {9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406}}, + {{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139}, + {-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963}, + {-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693}}, + {{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734}, + {-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680}, + {-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410}}, + {{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931}, + {-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654}, + {22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710}}, + {{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180}, + {-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684}, + {-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895}} + }, { + {{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501}, + {-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413}, + {6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880}}, + {{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874}, + {22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962}, + {-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899}}, + {{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152}, + {9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063}, + {7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080}}, + {{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146}, + {-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183}, + {-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133}}, + {{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421}, + {-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622}, + {-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197}}, + {{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663}, + {31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753}, + {4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755}}, + {{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862}, + {-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118}, + {26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171}}, + {{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380}, + {16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824}, + {28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270}} + }, { + {{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438}, + {-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584}, + {-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562}}, + {{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471}, + {18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610}, + {19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269}}, + {{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650}, + {14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369}, + {19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461}}, + {{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462}, + {-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793}, + {-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218}}, + {{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226}, + {18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019}, + {-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037}}, + {{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171}, + {-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132}, + {-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841}}, + {{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181}, + {-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210}, + {-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040}}, + {{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935}, + {24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105}, + {-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814}} + }, { + {{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852}, + {5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581}, + {-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646}}, + {{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844}, + {10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025}, + {27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453}}, + {{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068}, + {4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192}, + {-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921}}, + {{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259}, + {-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426}, + {-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072}}, + {{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305}, + {13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832}, + {28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943}}, + {{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011}, + {24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447}, + {17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494}}, + {{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245}, + {-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859}, + {28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915}}, + {{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707}, + {10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848}, + {-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224}} + }, { + {{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391}, + {15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215}, + {-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101}}, + {{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713}, + {21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849}, + {-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930}}, + {{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940}, + {-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031}, + {-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404}}, + {{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243}, + {-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116}, + {-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525}}, + {{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509}, + {-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883}, + {15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865}}, + {{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660}, + {4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273}, + {-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138}}, + {{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560}, + {-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135}, + {2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941}}, + {{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739}, + {18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756}, + {-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819}} + }, { + {{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347}, + {-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028}, + {21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075}}, + {{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799}, + {-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609}, + {-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817}}, + {{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989}, + {-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523}, + {4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278}}, + {{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045}, + {19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377}, + {24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480}}, + {{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016}, + {510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426}, + {18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525}}, + {{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396}, + {9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080}, + {12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892}}, + {{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275}, + {11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074}, + {20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140}}, + {{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717}, + {-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101}, + {24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127}} + }, { + {{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632}, + {-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415}, + {-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160}}, + {{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876}, + {22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625}, + {-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478}}, + {{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164}, + {26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595}, + {-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248}}, + {{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858}, + {15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193}, + {8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184}}, + {{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942}, + {-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635}, + {21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948}}, + {{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935}, + {-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415}, + {-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416}}, + {{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018}, + {4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778}, + {366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659}}, + {{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385}, + {18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503}, + {476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329}} + }, { + {{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056}, + {-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838}, + {24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948}}, + {{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691}, + {-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118}, + {-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517}}, + {{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269}, + {-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904}, + {-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589}}, + {{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193}, + {-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910}, + {-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930}}, + {{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667}, + {25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481}, + {-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876}}, + {{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640}, + {-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278}, + {-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112}}, + {{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272}, + {17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012}, + {-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221}}, + {{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046}, + {13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345}, + {-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310}} + }, { + {{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937}, + {31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636}, + {-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008}}, + {{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429}, + {-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576}, + {31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066}}, + {{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490}, + {-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104}, + {33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053}}, + {{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275}, + {-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511}, + {22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095}}, + {{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439}, + {23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939}, + {-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424}}, + {{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310}, + {3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608}, + {-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079}}, + {{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101}, + {21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418}, + {18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576}}, + {{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356}, + {9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996}, + {-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099}} + }, { + {{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728}, + {-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658}, + {-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242}}, + {{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001}, + {-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766}, + {18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373}}, + {{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458}, + {-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628}, + {-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657}}, + {{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062}, + {25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616}, + {31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014}}, + {{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383}, + {-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814}, + {-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718}}, + {{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417}, + {2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222}, + {33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444}}, + {{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597}, + {23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970}, + {1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799}}, + {{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647}, + {13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511}, + {-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032}} + }, { + {{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834}, + {-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461}, + {29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062}}, + {{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516}, + {-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547}, + {-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240}}, + {{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038}, + {-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741}, + {16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103}}, + {{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747}, + {-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323}, + {31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016}}, + {{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373}, + {15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228}, + {-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141}}, + {{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399}, + {11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831}, + {-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376}}, + {{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313}, + {-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958}, + {-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577}}, + {{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743}, + {29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684}, + {-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476}} + } +}; + +const ge_precomp ge_Bi[8] = { + {{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605}, + {-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378}, + {-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546}}, {{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024}, + {16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574}, + {30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357}}, {{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380}, + {4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306}, + {19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942}}, {{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766}, + {-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701}, + {28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300}}, {{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877}, + {-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951}, + {4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784}}, {{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436}, + {25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918}, + {23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877}}, {{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800}, + {-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305}, + {-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300}}, {{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876}, + {-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619}, + {-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683}} +}; + +/* A = 2 * (1 - d) / (1 + d) = 486662 */ +const fe fe_ma2 = {-12721188, -3529, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A^2 */ +const fe fe_ma = {-486662, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* -A */ +const fe fe_fffb1 = {-31702527, -2466483, -26106795, -12203692, -12169197, -321052, 14850977, -10296299, -16929438, -407568}; /* sqrt(-2 * A * (A + 2)) */ +const fe fe_fffb2 = {8166131, -6741800, -17040804, 3154616, 21461005, 1466302, -30876704, -6368709, 10503587, -13363080}; /* sqrt(2 * A * (A + 2)) */ +const fe fe_fffb3 = {-13620103, 14639558, 4532995, 7679154, 16815101, -15883539, -22863840, -14813421, 13716513, -6477756}; /* sqrt(-sqrt(-1) * A * (A + 2)) */ +const fe fe_fffb4 = {-21786234, -12173074, 21573800, 4524538, -4645904, 16204591, 8012863, -8444712, 3212926, 6885324}; /* sqrt(sqrt(-1) * A * (A + 2)) */ diff --git a/source-code/RuffCT-java/c/crypto-ops.c b/source-code/RuffCT-java/c/crypto-ops.c new file mode 100644 index 0000000..e104825 --- /dev/null +++ b/source-code/RuffCT-java/c/crypto-ops.c @@ -0,0 +1,2923 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#include +#include + +/*#include "warnings.h"*/ +#include "crypto-ops.h" + +// DISABLE_VS_WARNINGS(4146 4244) + +/* Predeclarations */ + +static void fe_mul(fe, const fe, const fe); +static void fe_sq(fe, const fe); +static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *); +static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *); +static void ge_p2_0(ge_p2 *); +static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *); +static void fe_divpowm1(fe, const fe, const fe); + +/* Common functions */ + +uint64_t load_3(const unsigned char *in) { + uint64_t result; + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + return result; +} + +uint64_t load_4(const unsigned char *in) +{ + uint64_t result; + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + return result; +} + +/* From fe_0.c */ + +/* +h = 0 +*/ + +static void fe_0(fe h) { + h[0] = 0; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + +/* From fe_1.c */ + +/* +h = 1 +*/ + +static void fe_1(fe h) { + h[0] = 1; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + +/* From fe_add.c */ + +/* +h = f + g +Can overlap h with f or 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. +*/ + +void fe_add(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t h0 = f0 + g0; + int32_t h1 = f1 + g1; + int32_t h2 = f2 + g2; + int32_t h3 = f3 + g3; + int32_t h4 = f4 + g4; + int32_t h5 = f5 + g5; + int32_t h6 = f6 + g6; + int32_t h7 = f7 + g7; + int32_t h8 = f8 + g8; + int32_t h9 = f9 + g9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_cmov.c */ + +/* +Replace (f,g) with (g,g) if b == 1; +replace (f,g) with (f,g) if b == 0. + +Preconditions: b in {0,1}. +*/ + +static void fe_cmov(fe f, const fe g, unsigned int b) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t x0 = f0 ^ g0; + int32_t x1 = f1 ^ g1; + int32_t x2 = f2 ^ g2; + int32_t x3 = f3 ^ g3; + int32_t x4 = f4 ^ g4; + int32_t x5 = f5 ^ g5; + int32_t x6 = f6 ^ g6; + int32_t x7 = f7 ^ g7; + int32_t x8 = f8 ^ g8; + int32_t x9 = f9 ^ g9; + assert((((b - 1) & ~b) | ((b - 2) & ~(b - 1))) == (unsigned int) -1); + b = -b; + x0 &= b; + x1 &= b; + x2 &= b; + x3 &= b; + x4 &= b; + x5 &= b; + x6 &= b; + x7 &= b; + x8 &= b; + x9 &= b; + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; +} + +/* From fe_copy.c */ + +/* +h = f +*/ + +static void fe_copy(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; + h[5] = f5; + h[6] = f6; + h[7] = f7; + h[8] = f8; + h[9] = f9; +} + +/* From fe_invert.c */ + +void fe_invert(fe out, const fe z) { + fe t0; + fe t1; + fe t2; + fe t3; + int i; + + fe_sq(t0, z); + fe_sq(t1, t0); + fe_sq(t1, t1); + fe_mul(t1, z, t1); + fe_mul(t0, t0, t1); + fe_sq(t2, t0); + fe_mul(t1, t1, t2); + fe_sq(t2, t1); + for (i = 0; i < 4; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + fe_sq(t2, t1); + for (i = 0; i < 9; ++i) { + fe_sq(t2, t2); + } + fe_mul(t2, t2, t1); + fe_sq(t3, t2); + for (i = 0; i < 19; ++i) { + fe_sq(t3, t3); + } + fe_mul(t2, t3, t2); + fe_sq(t2, t2); + for (i = 0; i < 9; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + fe_sq(t2, t1); + for (i = 0; i < 49; ++i) { + fe_sq(t2, t2); + } + fe_mul(t2, t2, t1); + fe_sq(t3, t2); + for (i = 0; i < 99; ++i) { + fe_sq(t3, t3); + } + fe_mul(t2, t3, t2); + fe_sq(t2, t2); + for (i = 0; i < 49; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + fe_sq(t1, t1); + for (i = 0; i < 4; ++i) { + fe_sq(t1, t1); + } + fe_mul(out, t1, t0); + + return; +} + +/* From fe_isnegative.c */ + +/* +return 1 if f is in {1,3,5,...,q-2} +return 0 if f is in {0,2,4,...,q-1} + +Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +static int fe_isnegative(const fe f) { + unsigned char s[32]; + fe_tobytes(s, f); + return s[0] & 1; +} + +/* From fe_isnonzero.c, modified */ + +static int fe_isnonzero(const fe f) { + unsigned char s[32]; + fe_tobytes(s, f); + return (((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1; +} + +/* From fe_mul.c */ + +/* +h = f * g +Can overlap h with f or g. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +Notes on implementation strategy: + +Using schoolbook multiplication. +Karatsuba would save a little in some cost models. + +Most multiplications by 2 and 19 are 32-bit precomputations; +cheaper than 64-bit postcomputations. + +There is one remaining multiplication by 19 in the carry chain; +one *19 precomputation can be merged into this, +but the resulting data flow is considerably less clean. + +There are 12 carries below. +10 of them are 2-way parallelizable and vectorizable. +Can get away with 11 carries, but then data flow is much deeper. + +With tighter constraints on inputs can squeeze carries into int32. +*/ + +static void fe_mul(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ + int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int32_t g3_19 = 19 * g3; + int32_t g4_19 = 19 * g4; + int32_t g5_19 = 19 * g5; + int32_t g6_19 = 19 * g6; + int32_t g7_19 = 19 * g7; + int32_t g8_19 = 19 * g8; + int32_t g9_19 = 19 * g9; + int32_t f1_2 = 2 * f1; + int32_t f3_2 = 2 * f3; + int32_t f5_2 = 2 * f5; + int32_t f7_2 = 2 * f7; + int32_t f9_2 = 2 * f9; + int64_t f0g0 = f0 * (int64_t) g0; + int64_t f0g1 = f0 * (int64_t) g1; + int64_t f0g2 = f0 * (int64_t) g2; + int64_t f0g3 = f0 * (int64_t) g3; + int64_t f0g4 = f0 * (int64_t) g4; + int64_t f0g5 = f0 * (int64_t) g5; + int64_t f0g6 = f0 * (int64_t) g6; + int64_t f0g7 = f0 * (int64_t) g7; + int64_t f0g8 = f0 * (int64_t) g8; + int64_t f0g9 = f0 * (int64_t) g9; + int64_t f1g0 = f1 * (int64_t) g0; + int64_t f1g1_2 = f1_2 * (int64_t) g1; + int64_t f1g2 = f1 * (int64_t) g2; + int64_t f1g3_2 = f1_2 * (int64_t) g3; + int64_t f1g4 = f1 * (int64_t) g4; + int64_t f1g5_2 = f1_2 * (int64_t) g5; + int64_t f1g6 = f1 * (int64_t) g6; + int64_t f1g7_2 = f1_2 * (int64_t) g7; + int64_t f1g8 = f1 * (int64_t) g8; + int64_t f1g9_38 = f1_2 * (int64_t) g9_19; + int64_t f2g0 = f2 * (int64_t) g0; + int64_t f2g1 = f2 * (int64_t) g1; + int64_t f2g2 = f2 * (int64_t) g2; + int64_t f2g3 = f2 * (int64_t) g3; + int64_t f2g4 = f2 * (int64_t) g4; + int64_t f2g5 = f2 * (int64_t) g5; + int64_t f2g6 = f2 * (int64_t) g6; + int64_t f2g7 = f2 * (int64_t) g7; + int64_t f2g8_19 = f2 * (int64_t) g8_19; + int64_t f2g9_19 = f2 * (int64_t) g9_19; + int64_t f3g0 = f3 * (int64_t) g0; + int64_t f3g1_2 = f3_2 * (int64_t) g1; + int64_t f3g2 = f3 * (int64_t) g2; + int64_t f3g3_2 = f3_2 * (int64_t) g3; + int64_t f3g4 = f3 * (int64_t) g4; + int64_t f3g5_2 = f3_2 * (int64_t) g5; + int64_t f3g6 = f3 * (int64_t) g6; + int64_t f3g7_38 = f3_2 * (int64_t) g7_19; + int64_t f3g8_19 = f3 * (int64_t) g8_19; + int64_t f3g9_38 = f3_2 * (int64_t) g9_19; + int64_t f4g0 = f4 * (int64_t) g0; + int64_t f4g1 = f4 * (int64_t) g1; + int64_t f4g2 = f4 * (int64_t) g2; + int64_t f4g3 = f4 * (int64_t) g3; + int64_t f4g4 = f4 * (int64_t) g4; + int64_t f4g5 = f4 * (int64_t) g5; + int64_t f4g6_19 = f4 * (int64_t) g6_19; + int64_t f4g7_19 = f4 * (int64_t) g7_19; + int64_t f4g8_19 = f4 * (int64_t) g8_19; + int64_t f4g9_19 = f4 * (int64_t) g9_19; + int64_t f5g0 = f5 * (int64_t) g0; + int64_t f5g1_2 = f5_2 * (int64_t) g1; + int64_t f5g2 = f5 * (int64_t) g2; + int64_t f5g3_2 = f5_2 * (int64_t) g3; + int64_t f5g4 = f5 * (int64_t) g4; + int64_t f5g5_38 = f5_2 * (int64_t) g5_19; + int64_t f5g6_19 = f5 * (int64_t) g6_19; + int64_t f5g7_38 = f5_2 * (int64_t) g7_19; + int64_t f5g8_19 = f5 * (int64_t) g8_19; + int64_t f5g9_38 = f5_2 * (int64_t) g9_19; + int64_t f6g0 = f6 * (int64_t) g0; + int64_t f6g1 = f6 * (int64_t) g1; + int64_t f6g2 = f6 * (int64_t) g2; + int64_t f6g3 = f6 * (int64_t) g3; + int64_t f6g4_19 = f6 * (int64_t) g4_19; + int64_t f6g5_19 = f6 * (int64_t) g5_19; + int64_t f6g6_19 = f6 * (int64_t) g6_19; + int64_t f6g7_19 = f6 * (int64_t) g7_19; + int64_t f6g8_19 = f6 * (int64_t) g8_19; + int64_t f6g9_19 = f6 * (int64_t) g9_19; + int64_t f7g0 = f7 * (int64_t) g0; + int64_t f7g1_2 = f7_2 * (int64_t) g1; + int64_t f7g2 = f7 * (int64_t) g2; + int64_t f7g3_38 = f7_2 * (int64_t) g3_19; + int64_t f7g4_19 = f7 * (int64_t) g4_19; + int64_t f7g5_38 = f7_2 * (int64_t) g5_19; + int64_t f7g6_19 = f7 * (int64_t) g6_19; + int64_t f7g7_38 = f7_2 * (int64_t) g7_19; + int64_t f7g8_19 = f7 * (int64_t) g8_19; + int64_t f7g9_38 = f7_2 * (int64_t) g9_19; + int64_t f8g0 = f8 * (int64_t) g0; + int64_t f8g1 = f8 * (int64_t) g1; + int64_t f8g2_19 = f8 * (int64_t) g2_19; + int64_t f8g3_19 = f8 * (int64_t) g3_19; + int64_t f8g4_19 = f8 * (int64_t) g4_19; + int64_t f8g5_19 = f8 * (int64_t) g5_19; + int64_t f8g6_19 = f8 * (int64_t) g6_19; + int64_t f8g7_19 = f8 * (int64_t) g7_19; + int64_t f8g8_19 = f8 * (int64_t) g8_19; + int64_t f8g9_19 = f8 * (int64_t) g9_19; + int64_t f9g0 = f9 * (int64_t) g0; + int64_t f9g1_38 = f9_2 * (int64_t) g1_19; + int64_t f9g2_19 = f9 * (int64_t) g2_19; + int64_t f9g3_38 = f9_2 * (int64_t) g3_19; + int64_t f9g4_19 = f9 * (int64_t) g4_19; + int64_t f9g5_38 = f9_2 * (int64_t) g5_19; + int64_t f9g6_19 = f9 * (int64_t) g6_19; + int64_t f9g7_38 = f9_2 * (int64_t) g7_19; + int64_t f9g8_19 = f9 * (int64_t) g8_19; + int64_t f9g9_38 = f9_2 * (int64_t) g9_19; + int64_t h0 = f0g0+f1g9_38+f2g8_19+f3g7_38+f4g6_19+f5g5_38+f6g4_19+f7g3_38+f8g2_19+f9g1_38; + int64_t h1 = f0g1+f1g0 +f2g9_19+f3g8_19+f4g7_19+f5g6_19+f6g5_19+f7g4_19+f8g3_19+f9g2_19; + int64_t h2 = f0g2+f1g1_2 +f2g0 +f3g9_38+f4g8_19+f5g7_38+f6g6_19+f7g5_38+f8g4_19+f9g3_38; + int64_t h3 = f0g3+f1g2 +f2g1 +f3g0 +f4g9_19+f5g8_19+f6g7_19+f7g6_19+f8g5_19+f9g4_19; + int64_t h4 = f0g4+f1g3_2 +f2g2 +f3g1_2 +f4g0 +f5g9_38+f6g8_19+f7g7_38+f8g6_19+f9g5_38; + int64_t h5 = f0g5+f1g4 +f2g3 +f3g2 +f4g1 +f5g0 +f6g9_19+f7g8_19+f8g7_19+f9g6_19; + int64_t h6 = f0g6+f1g5_2 +f2g4 +f3g3_2 +f4g2 +f5g1_2 +f6g0 +f7g9_38+f8g8_19+f9g7_38; + int64_t h7 = f0g7+f1g6 +f2g5 +f3g4 +f4g3 +f5g2 +f6g1 +f7g0 +f8g9_19+f9g8_19; + int64_t h8 = f0g8+f1g7_2 +f2g6 +f3g5_2 +f4g4 +f5g3_2 +f6g2 +f7g1_2 +f8g0 +f9g9_38; + int64_t h9 = f0g9+f1g8 +f2g7 +f3g6 +f4g5 +f5g4 +f6g3 +f7g2 +f8g1 +f9g0 ; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + /* + |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_neg.c */ + +/* +h = -f + +Preconditions: + |f| 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^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +*/ + +static void fe_neg(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t h0 = -f0; + int32_t h1 = -f1; + int32_t h2 = -f2; + int32_t h3 = -f3; + int32_t h4 = -f4; + int32_t h5 = -f5; + int32_t h6 = -f6; + int32_t h7 = -f7; + int32_t h8 = -f8; + int32_t h9 = -f9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_sq.c */ + +/* +h = f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +static void fe_sq(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_sq2.c */ + +/* +h = 2 * f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +static void fe_sq2(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + int64_t h0 = f0f0 +f1f9_76+f2f8_38+f3f7_76+f4f6_38+f5f5_38; + int64_t h1 = f0f1_2+f2f9_38+f3f8_38+f4f7_38+f5f6_38; + int64_t h2 = f0f2_2+f1f1_2 +f3f9_76+f4f8_38+f5f7_76+f6f6_19; + int64_t h3 = f0f3_2+f1f2_2 +f4f9_38+f5f8_38+f6f7_38; + int64_t h4 = f0f4_2+f1f3_4 +f2f2 +f5f9_76+f6f8_38+f7f7_38; + int64_t h5 = f0f5_2+f1f4_2 +f2f3_2 +f6f9_38+f7f8_38; + int64_t h6 = f0f6_2+f1f5_4 +f2f4_2 +f3f3_2 +f7f9_76+f8f8_19; + int64_t h7 = f0f7_2+f1f6_2 +f2f5_2 +f3f4_2 +f8f9_38; + int64_t h8 = f0f8_2+f1f7_4 +f2f6_2 +f3f5_4 +f4f4 +f9f9_38; + int64_t h9 = f0f9_2+f1f8_2 +f2f7_2 +f3f6_2 +f4f5_2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_sub.c */ + +/* +h = f - g +Can overlap h with f or 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. +*/ + +static void fe_sub(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t h0 = f0 - g0; + int32_t h1 = f1 - g1; + int32_t h2 = f2 - g2; + int32_t h3 = f3 - g3; + int32_t h4 = f4 - g4; + int32_t h5 = f5 - g5; + int32_t h6 = f6 - g6; + int32_t h7 = f7 - g7; + int32_t h8 = f8 - g8; + int32_t h9 = f9 - g9; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + +/* From fe_tobytes.c */ + +/* +Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + +Write p=2^255-19; q=floor(h/p). +Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + +Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 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; + + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + + 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; + /* h10 = carry9 */ + + /* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + Goal: Output h0+...+2^230 h9. + */ + + s[0] = h0 >> 0; + s[1] = h0 >> 8; + s[2] = h0 >> 16; + s[3] = (h0 >> 24) | (h1 << 2); + s[4] = h1 >> 6; + s[5] = h1 >> 14; + s[6] = (h1 >> 22) | (h2 << 3); + s[7] = h2 >> 5; + s[8] = h2 >> 13; + s[9] = (h2 >> 21) | (h3 << 5); + s[10] = h3 >> 3; + s[11] = h3 >> 11; + s[12] = (h3 >> 19) | (h4 << 6); + s[13] = h4 >> 2; + s[14] = h4 >> 10; + s[15] = h4 >> 18; + s[16] = h5 >> 0; + s[17] = h5 >> 8; + s[18] = h5 >> 16; + s[19] = (h5 >> 24) | (h6 << 1); + s[20] = h6 >> 7; + s[21] = h6 >> 15; + s[22] = (h6 >> 23) | (h7 << 3); + s[23] = h7 >> 5; + s[24] = h7 >> 13; + s[25] = (h7 >> 21) | (h8 << 4); + s[26] = h8 >> 4; + s[27] = h8 >> 12; + s[28] = (h8 >> 20) | (h9 << 6); + s[29] = h9 >> 2; + s[30] = h9 >> 10; + s[31] = h9 >> 18; +} + +/* From ge_add.c */ + +void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->YplusX); + fe_mul(r->Y, r->Y, q->YminusX); + fe_mul(r->T, q->T2d, p->T); + fe_mul(r->X, p->Z, q->Z); + fe_add(t0, r->X, r->X); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_add(r->Z, t0, r->T); + fe_sub(r->T, t0, r->T); +} + +/* From ge_double_scalarmult.c, modified */ + +static void slide(signed char *r, const unsigned char *a) { + int i; + int b; + int k; + + for (i = 0; i < 256; ++i) { + r[i] = 1 & (a[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; + } else if (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; + } + } + } + } +} + +void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s) { + ge_p1p1 t; + ge_p3 s2, u; + ge_p3_to_cached(&r[0], s); + ge_p3_dbl(&t, s); ge_p1p1_to_p3(&s2, &t); + ge_add(&t, &s2, &r[0]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[1], &u); + ge_add(&t, &s2, &r[1]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[2], &u); + ge_add(&t, &s2, &r[2]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[3], &u); + ge_add(&t, &s2, &r[3]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[4], &u); + ge_add(&t, &s2, &r[4]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[5], &u); + ge_add(&t, &s2, &r[5]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[6], &u); + ge_add(&t, &s2, &r[6]); ge_p1p1_to_p3(&u, &t); ge_p3_to_cached(&r[7], &u); +} + +/* +r = a * A + b * B +where a = a[0]+256*a[1]+...+256^31 a[31]. +and b = b[0]+256*b[1]+...+256^31 b[31]. +B is the Ed25519 base point (x,4/5) with x positive. +*/ + +void ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) { + signed char aslide[256]; + signed char bslide[256]; + ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */ + ge_p1p1 t; + ge_p3 u; + int i; + + slide(aslide, a); + slide(bslide, b); + ge_dsm_precomp(Ai, A); + + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) break; + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i]/2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i])/2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_madd(&t, &u, &ge_Bi[bslide[i]/2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_msub(&t, &u, &ge_Bi[(-bslide[i])/2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + +/* From ge_frombytes.c, modified */ + +int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) { + fe u; + fe v; + fe vxx; + fe check; + + /* From fe_frombytes.c */ + + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 8388607) << 2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + /* Validate the number to be canonical */ + if (h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 && + h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 && + h1 == 1073741760 && h0 >= 4294967277) { + return -1; + } + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h->Y[0] = h0; + h->Y[1] = h1; + h->Y[2] = h2; + h->Y[3] = h3; + h->Y[4] = h4; + h->Y[5] = h5; + h->Y[6] = h6; + h->Y[7] = h7; + h->Y[8] = h8; + h->Y[9] = h9; + + /* End fe_frombytes.c */ + + fe_1(h->Z); + fe_sq(u, h->Y); + fe_mul(v, u, fe_d); + fe_sub(u, u, h->Z); /* u = y^2-1 */ + fe_add(v, v, h->Z); /* v = dy^2+1 */ + + fe_divpowm1(h->X, u, v); /* 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 */ + if (fe_isnonzero(check)) { + fe_add(check, vxx, u); /* vx^2+u */ + if (fe_isnonzero(check)) { + return -1; + } + fe_mul(h->X, h->X, fe_sqrtm1); + } + + if (fe_isnegative(h->X) != (s[31] >> 7)) { + /* If x = 0, the sign must be positive */ + if (!fe_isnonzero(h->X)) { + return -1; + } + fe_neg(h->X, h->X); + } + + fe_mul(h->T, h->X, h->Y); + return 0; +} + +/* From ge_madd.c */ + +/* +r = p + q +*/ + +static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->yplusx); + fe_mul(r->Y, r->Y, q->yminusx); + fe_mul(r->T, q->xy2d, p->T); + fe_add(t0, p->Z, p->Z); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_add(r->Z, t0, r->T); + fe_sub(r->T, t0, r->T); +} + +/* From ge_msub.c */ + +/* +r = p - q +*/ + +static void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->yminusx); + fe_mul(r->Y, r->Y, q->yplusx); + fe_mul(r->T, q->xy2d, p->T); + fe_add(t0, p->Z, p->Z); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_sub(r->Z, t0, r->T); + fe_add(r->T, t0, r->T); +} + +/* From ge_p1p1_to_p2.c */ + +/* +r = p +*/ + +void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); +} + +/* From ge_p1p1_to_p3.c */ + +/* +r = p +*/ + +void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); + fe_mul(r->T, p->X, p->Y); +} + +/* From ge_p2_0.c */ + +static void ge_p2_0(ge_p2 *h) { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); +} + +/* From ge_p2_dbl.c */ + +/* +r = 2 * p +*/ + +void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { + fe t0; + fe_sq(r->X, p->X); + fe_sq(r->Z, p->Y); + fe_sq2(r->T, p->Z); + fe_add(r->Y, p->X, p->Y); + fe_sq(t0, r->Y); + fe_add(r->Y, r->Z, r->X); + fe_sub(r->Z, r->Z, r->X); + fe_sub(r->X, t0, r->Y); + fe_sub(r->T, r->T, r->Z); +} + +/* From ge_p3_0.c */ + +static void ge_p3_0(ge_p3 *h) { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); + fe_0(h->T); +} + +/* From ge_p3_dbl.c */ + +/* +r = 2 * p +*/ + +static void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) { + ge_p2 q; + ge_p3_to_p2(&q, p); + ge_p2_dbl(r, &q); +} + +/* From ge_p3_to_cached.c */ + +/* +r = p +*/ + +void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { + fe_add(r->YplusX, p->Y, p->X); + fe_sub(r->YminusX, p->Y, p->X); + fe_copy(r->Z, p->Z); + fe_mul(r->T2d, p->T, fe_d2); +} + +/* From ge_p3_to_p2.c */ + +/* +r = p +*/ + +void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) { + fe_copy(r->X, p->X); + fe_copy(r->Y, p->Y); + fe_copy(r->Z, p->Z); +} + +/* From ge_p3_tobytes.c */ + +void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) { + fe recip; + fe x; + fe y; + + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; +} + +/* From ge_precomp_0.c */ + +static void ge_precomp_0(ge_precomp *h) { + fe_1(h->yplusx); + fe_1(h->yminusx); + fe_0(h->xy2d); +} + +/* From ge_scalarmult_base.c */ + +static unsigned char equal(signed char b, signed char c) { + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint32_t y = x; /* 0: yes; 1..255: no */ + y -= 1; /* 4294967295: yes; 0..254: no */ + y >>= 31; /* 1: yes; 0: no */ + return y; +} + +static unsigned char negative(signed char b) { + unsigned long long x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return x; +} + +static void ge_precomp_cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) { + fe_cmov(t->yplusx, u->yplusx, b); + fe_cmov(t->yminusx, u->yminusx, b); + fe_cmov(t->xy2d, u->xy2d, b); +} + +static void select(ge_precomp *t, int pos, signed char b) { + ge_precomp minust; + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + + ge_precomp_0(t); + ge_precomp_cmov(t, &ge_base[pos][0], equal(babs, 1)); + ge_precomp_cmov(t, &ge_base[pos][1], equal(babs, 2)); + ge_precomp_cmov(t, &ge_base[pos][2], equal(babs, 3)); + ge_precomp_cmov(t, &ge_base[pos][3], equal(babs, 4)); + ge_precomp_cmov(t, &ge_base[pos][4], equal(babs, 5)); + ge_precomp_cmov(t, &ge_base[pos][5], equal(babs, 6)); + ge_precomp_cmov(t, &ge_base[pos][6], equal(babs, 7)); + ge_precomp_cmov(t, &ge_base[pos][7], equal(babs, 8)); + fe_copy(minust.yplusx, t->yminusx); + fe_copy(minust.yminusx, t->yplusx); + fe_neg(minust.xy2d, t->xy2d); + ge_precomp_cmov(t, &minust, bnegative); +} + +/* +h = a * B +where a = a[0]+256*a[1]+...+256^31 a[31] +B is the Ed25519 base point (x,4/5) with x positive. + +Preconditions: + a[31] <= 127 +*/ + +void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (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 << 4; + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(h); + for (i = 1; i < 64; i += 2) { + select(&t, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } + + ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + select(&t, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } +} + +/* From ge_sub.c */ + +/* +r = p - q +*/ + +void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->YminusX); + fe_mul(r->Y, r->Y, q->YplusX); + fe_mul(r->T, q->T2d, p->T); + fe_mul(r->X, p->Z, q->Z); + fe_add(t0, r->X, r->X); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_sub(r->Z, t0, r->T); + fe_add(r->T, t0, r->T); +} + +/* From ge_tobytes.c */ + +void ge_tobytes(unsigned char *s, const ge_p2 *h) { + fe recip; + fe x; + fe y; + + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; +} + +/* From sc_reduce.c */ + +/* +Input: + s[0]+256*s[1]+...+256^63*s[63] = s + +Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. +*/ + +void sc_reduce(unsigned char *s) { + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = 2097151 & (load_4(s + 28) >> 7); + int64_t s12 = 2097151 & (load_4(s + 31) >> 4); + int64_t s13 = 2097151 & (load_3(s + 34) >> 1); + int64_t s14 = 2097151 & (load_4(s + 36) >> 6); + int64_t s15 = 2097151 & (load_3(s + 39) >> 3); + int64_t s16 = 2097151 & load_3(s + 42); + int64_t s17 = 2097151 & (load_4(s + 44) >> 5); + int64_t s18 = 2097151 & (load_3(s + 47) >> 2); + int64_t s19 = 2097151 & (load_4(s + 49) >> 7); + int64_t s20 = 2097151 & (load_4(s + 52) >> 4); + int64_t s21 = 2097151 & (load_3(s + 55) >> 1); + int64_t s22 = 2097151 & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + 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 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* New code */ + +static void fe_divpowm1(fe r, const fe u, const fe v) { + fe v3, uv7, t0, t1, t2; + int i; + + fe_sq(v3, v); + fe_mul(v3, v3, v); /* v3 = v^3 */ + fe_sq(uv7, v3); + fe_mul(uv7, uv7, v); + fe_mul(uv7, uv7, u); /* uv7 = uv^7 */ + + /*fe_pow22523(uv7, uv7);*/ + + /* From fe_pow22523.c */ + + fe_sq(t0, uv7); + fe_sq(t1, t0); + fe_sq(t1, t1); + fe_mul(t1, uv7, t1); + fe_mul(t0, t0, t1); + fe_sq(t0, t0); + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + for (i = 0; i < 4; ++i) { + fe_sq(t1, t1); + } + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + for (i = 0; i < 9; ++i) { + fe_sq(t1, t1); + } + fe_mul(t1, t1, t0); + fe_sq(t2, t1); + for (i = 0; i < 19; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + for (i = 0; i < 10; ++i) { + fe_sq(t1, t1); + } + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + for (i = 0; i < 49; ++i) { + fe_sq(t1, t1); + } + fe_mul(t1, t1, t0); + fe_sq(t2, t1); + for (i = 0; i < 99; ++i) { + fe_sq(t2, t2); + } + fe_mul(t1, t2, t1); + for (i = 0; i < 50; ++i) { + fe_sq(t1, t1); + } + fe_mul(t0, t1, t0); + fe_sq(t0, t0); + fe_sq(t0, t0); + fe_mul(t0, t0, uv7); + + /* End fe_pow22523.c */ + /* t0 = (uv^7)^((q-5)/8) */ + fe_mul(t0, t0, v3); + fe_mul(r, t0, u); /* u^(m+1)v^(-(m+1)) */ +} + +static void ge_cached_0(ge_cached *r) { + fe_1(r->YplusX); + fe_1(r->YminusX); + fe_1(r->Z); + fe_0(r->T2d); +} + +static void ge_cached_cmov(ge_cached *t, const ge_cached *u, unsigned char b) { + fe_cmov(t->YplusX, u->YplusX, b); + fe_cmov(t->YminusX, u->YminusX, b); + fe_cmov(t->Z, u->Z, b); + fe_cmov(t->T2d, u->T2d, b); +} + +/* Assumes that a[31] <= 127 */ +void ge_scalarmult(ge_p2 *r, const unsigned char *a, const ge_p3 *A) { + signed char e[64]; + int carry, carry2, i; + ge_cached Ai[8]; /* 1 * A, 2 * A, ..., 8 * A */ + ge_p1p1 t; + ge_p3 u; + + carry = 0; /* 0..1 */ + for (i = 0; i < 31; i++) { + carry += a[i]; /* 0..256 */ + carry2 = (carry + 8) >> 4; /* 0..16 */ + e[2 * i] = carry - (carry2 << 4); /* -8..7 */ + carry = (carry2 + 8) >> 4; /* 0..1 */ + e[2 * i + 1] = carry2 - (carry << 4); /* -8..7 */ + } + carry += a[31]; /* 0..128 */ + carry2 = (carry + 8) >> 4; /* 0..8 */ + e[62] = carry - (carry2 << 4); /* -8..7 */ + e[63] = carry2; /* 0..8 */ + + ge_p3_to_cached(&Ai[0], A); + for (i = 0; i < 7; i++) { + ge_add(&t, A, &Ai[i]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[i + 1], &u); + } + + ge_p2_0(r); + for (i = 63; i >= 0; i--) { + signed char b = e[i]; + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + ge_cached cur, minuscur; + ge_p2_dbl(&t, r); + ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + ge_p1p1_to_p2(r, &t); + ge_p2_dbl(&t, r); + ge_p1p1_to_p3(&u, &t); + ge_cached_0(&cur); + ge_cached_cmov(&cur, &Ai[0], equal(babs, 1)); + ge_cached_cmov(&cur, &Ai[1], equal(babs, 2)); + ge_cached_cmov(&cur, &Ai[2], equal(babs, 3)); + ge_cached_cmov(&cur, &Ai[3], equal(babs, 4)); + ge_cached_cmov(&cur, &Ai[4], equal(babs, 5)); + ge_cached_cmov(&cur, &Ai[5], equal(babs, 6)); + ge_cached_cmov(&cur, &Ai[6], equal(babs, 7)); + ge_cached_cmov(&cur, &Ai[7], equal(babs, 8)); + fe_copy(minuscur.YplusX, cur.YminusX); + fe_copy(minuscur.YminusX, cur.YplusX); + fe_copy(minuscur.Z, cur.Z); + fe_neg(minuscur.T2d, cur.T2d); + ge_cached_cmov(&cur, &minuscur, bnegative); + ge_add(&t, &u, &cur); + ge_p1p1_to_p2(r, &t); + } +} + +void ge_double_scalarmult_precomp_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b, const ge_dsmp Bi) { + signed char aslide[256]; + signed char bslide[256]; + ge_dsmp Ai; /* A, 3A, 5A, 7A, 9A, 11A, 13A, 15A */ + ge_p1p1 t; + ge_p3 u; + int i; + + slide(aslide, a); + slide(bslide, b); + ge_dsm_precomp(Ai, A); + + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) break; + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i]/2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i])/2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Bi[bslide[i]/2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Bi[(-bslide[i])/2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + +void ge_mul8(ge_p1p1 *r, const ge_p2 *t) { + ge_p2 u; + ge_p2_dbl(r, t); + ge_p1p1_to_p2(&u, r); + ge_p2_dbl(r, &u); + ge_p1p1_to_p2(&u, r); + ge_p2_dbl(r, &u); +} + +void ge_fromfe_frombytes_vartime(ge_p2 *r, const unsigned char *s) { + fe u, v, w, x, y, z; + unsigned char sign; + + /* From fe_frombytes.c */ + + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = load_3(s + 29) << 2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + u[0] = h0; + u[1] = h1; + u[2] = h2; + u[3] = h3; + u[4] = h4; + u[5] = h5; + u[6] = h6; + u[7] = h7; + u[8] = h8; + u[9] = h9; + + /* End fe_frombytes.c */ + + fe_sq2(v, u); /* 2 * u^2 */ + fe_1(w); + fe_add(w, v, w); /* w = 2 * u^2 + 1 */ + fe_sq(x, w); /* w^2 */ + fe_mul(y, fe_ma2, v); /* -2 * A^2 * u^2 */ + fe_add(x, x, y); /* x = w^2 - 2 * A^2 * u^2 */ + fe_divpowm1(r->X, w, x); /* (w / x)^(m + 1) */ + fe_sq(y, r->X); + fe_mul(x, y, x); + fe_sub(y, w, x); + fe_copy(z, fe_ma); + if (fe_isnonzero(y)) { + fe_add(y, w, x); + if (fe_isnonzero(y)) { + goto negative; + } else { + fe_mul(r->X, r->X, fe_fffb1); + } + } else { + fe_mul(r->X, r->X, fe_fffb2); + } + fe_mul(r->X, r->X, u); /* u * sqrt(2 * A * (A + 2) * w / x) */ + fe_mul(z, z, v); /* -2 * A * u^2 */ + sign = 0; + goto setsign; +negative: + fe_mul(x, x, fe_sqrtm1); + fe_sub(y, w, x); + if (fe_isnonzero(y)) { + assert((fe_add(y, w, x), !fe_isnonzero(y))); + fe_mul(r->X, r->X, fe_fffb3); + } else { + fe_mul(r->X, r->X, fe_fffb4); + } + /* r->X = sqrt(A * (A + 2) * w / x) */ + /* z = -A */ + sign = 1; +setsign: + if (fe_isnegative(r->X) != sign) { + assert(fe_isnonzero(r->X)); + fe_neg(r->X, r->X); + } + fe_add(r->Z, z, w); + fe_sub(r->Y, z, w); + fe_mul(r->X, r->X, r->Z); +#if !defined(NDEBUG) + { + fe check_x, check_y, check_iz, check_v; + fe_invert(check_iz, r->Z); + fe_mul(check_x, r->X, check_iz); + fe_mul(check_y, r->Y, check_iz); + fe_sq(check_x, check_x); + fe_sq(check_y, check_y); + fe_mul(check_v, check_x, check_y); + fe_mul(check_v, fe_d, check_v); + fe_add(check_v, check_v, check_x); + fe_sub(check_v, check_v, check_y); + fe_1(check_x); + fe_add(check_v, check_v, check_x); + assert(!fe_isnonzero(check_v)); + } +#endif +} + +void sc_0(unsigned char *s) { + int i; + for (i = 0; i < 32; i++) { + s[i] = 0; + } +} + +void sc_reduce32(unsigned char *s) { + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = (load_4(s + 28) >> 7); + int64_t s12 = 0; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +void sc_add(unsigned char *s, const unsigned char *a, const unsigned char *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); + 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); + int64_t s0 = a0 + b0; + int64_t s1 = a1 + b1; + int64_t s2 = a2 + b2; + int64_t s3 = a3 + b3; + int64_t s4 = a4 + b4; + int64_t s5 = a5 + b5; + int64_t s6 = a6 + b6; + int64_t s7 = a7 + b7; + int64_t s8 = a8 + b8; + int64_t s9 = a9 + b9; + int64_t s10 = a10 + b10; + int64_t s11 = a11 + b11; + int64_t s12 = 0; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +void sc_sub(unsigned char *s, const unsigned char *a, const unsigned char *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); + 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); + int64_t s0 = a0 - b0; + int64_t s1 = a1 - b1; + int64_t s2 = a2 - b2; + int64_t s3 = a3 - b3; + int64_t s4 = a4 - b4; + int64_t s5 = a5 - b5; + int64_t s6 = a6 - b6; + int64_t s7 = a7 - b7; + int64_t s8 = a8 - b8; + int64_t s9 = a9 - b9; + int64_t s10 = a10 - b10; + int64_t s11 = a11 - b11; + int64_t s12 = 0; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* +Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + +Output: + s[0]+256*s[1]+...+256^31*s[31] = (c-ab) mod l + where l = 2^252 + 27742317777372353535851937790883648493. +*/ + +void sc_mulsub(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) { + 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); + 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); + int64_t c0 = 2097151 & load_3(c); + int64_t c1 = 2097151 & (load_4(c + 2) >> 5); + int64_t c2 = 2097151 & (load_3(c + 5) >> 2); + int64_t c3 = 2097151 & (load_4(c + 7) >> 7); + int64_t c4 = 2097151 & (load_4(c + 10) >> 4); + int64_t c5 = 2097151 & (load_3(c + 13) >> 1); + int64_t c6 = 2097151 & (load_4(c + 15) >> 6); + int64_t c7 = 2097151 & (load_3(c + 18) >> 3); + int64_t c8 = 2097151 & load_3(c + 21); + int64_t c9 = 2097151 & (load_4(c + 23) >> 5); + int64_t c10 = 2097151 & (load_3(c + 26) >> 2); + int64_t c11 = (load_4(c + 28) >> 7); + int64_t s0; + int64_t s1; + int64_t s2; + int64_t s3; + int64_t s4; + int64_t s5; + int64_t s6; + int64_t s7; + int64_t s8; + int64_t s9; + int64_t s10; + int64_t s11; + int64_t s12; + int64_t s13; + int64_t s14; + int64_t s15; + int64_t s16; + int64_t s17; + int64_t s18; + int64_t s19; + int64_t s20; + int64_t s21; + int64_t s22; + int64_t s23; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + int64_t carry17; + int64_t carry18; + int64_t carry19; + int64_t carry20; + int64_t carry21; + int64_t carry22; + + s0 = c0 - a0*b0; + s1 = c1 - (a0*b1 + a1*b0); + s2 = c2 - (a0*b2 + a1*b1 + a2*b0); + s3 = c3 - (a0*b3 + a1*b2 + a2*b1 + a3*b0); + s4 = c4 - (a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0); + s5 = c5 - (a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0); + s6 = c6 - (a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0); + s7 = c7 - (a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0); + s8 = c8 - (a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0); + s9 = c9 - (a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0); + s10 = c10 - (a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0); + s11 = c11 - (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; + + 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 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + 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 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + s[0] = s0 >> 0; + s[1] = s0 >> 8; + s[2] = (s0 >> 16) | (s1 << 5); + s[3] = s1 >> 3; + s[4] = s1 >> 11; + s[5] = (s1 >> 19) | (s2 << 2); + s[6] = s2 >> 6; + s[7] = (s2 >> 14) | (s3 << 7); + s[8] = s3 >> 1; + s[9] = s3 >> 9; + s[10] = (s3 >> 17) | (s4 << 4); + s[11] = s4 >> 4; + s[12] = s4 >> 12; + s[13] = (s4 >> 20) | (s5 << 1); + s[14] = s5 >> 7; + s[15] = (s5 >> 15) | (s6 << 6); + s[16] = s6 >> 2; + s[17] = s6 >> 10; + s[18] = (s6 >> 18) | (s7 << 3); + s[19] = s7 >> 5; + s[20] = s7 >> 13; + s[21] = s8 >> 0; + s[22] = s8 >> 8; + s[23] = (s8 >> 16) | (s9 << 5); + s[24] = s9 >> 3; + s[25] = s9 >> 11; + s[26] = (s9 >> 19) | (s10 << 2); + s[27] = s10 >> 6; + s[28] = (s10 >> 14) | (s11 << 7); + s[29] = s11 >> 1; + s[30] = s11 >> 9; + s[31] = s11 >> 17; +} + +/* Assumes that a != INT64_MIN */ +static int64_t signum(int64_t a) { + return (a >> 63) - ((-a) >> 63); +} + +int sc_check(const unsigned char *s) { + int64_t s0 = load_4(s); + int64_t s1 = load_4(s + 4); + int64_t s2 = load_4(s + 8); + int64_t s3 = load_4(s + 12); + int64_t s4 = load_4(s + 16); + int64_t s5 = load_4(s + 20); + int64_t s6 = load_4(s + 24); + int64_t s7 = load_4(s + 28); + return (signum(1559614444 - s0) + (signum(1477600026 - s1) << 1) + (signum(2734136534 - s2) << 2) + (signum(350157278 - s3) << 3) + (signum(-s4) << 4) + (signum(-s5) << 5) + (signum(-s6) << 6) + (signum(268435456 - s7) << 7)) >> 8; +} + +int sc_isnonzero(const unsigned char *s) { + return (((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] | + s[9] | s[10] | s[11] | s[12] | s[13] | s[14] | s[15] | s[16] | s[17] | + s[18] | s[19] | s[20] | s[21] | s[22] | s[23] | s[24] | s[25] | s[26] | + s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1; +} \ No newline at end of file diff --git a/source-code/RuffCT-java/c/crypto-ops.h b/source-code/RuffCT-java/c/crypto-ops.h new file mode 100644 index 0000000..9a802ff --- /dev/null +++ b/source-code/RuffCT-java/c/crypto-ops.h @@ -0,0 +1,153 @@ +// Copyright (c) 2014-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers + +#pragma once + +/* From fe.h */ + +typedef int32_t fe[10]; + +/* From ge.h */ + +typedef struct { + fe X; + fe Y; + fe Z; +} ge_p2; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p3; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p1p1; + +typedef struct { + fe yplusx; + fe yminusx; + fe xy2d; +} ge_precomp; + +typedef struct { + fe YplusX; + fe YminusX; + fe Z; + fe T2d; +} ge_cached; + +/* From ge_add.c */ + +void ge_add(ge_p1p1 *, const ge_p3 *, const ge_cached *); + +/* From ge_double_scalarmult.c, modified */ + +typedef ge_cached ge_dsmp[8]; +extern const ge_precomp ge_Bi[8]; +void ge_dsm_precomp(ge_dsmp r, const ge_p3 *s); +void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *); + +/* From ge_frombytes.c, modified */ + +extern const fe fe_sqrtm1; +extern const fe fe_d; +int ge_frombytes_vartime(ge_p3 *, const unsigned char *); + +/* From ge_p1p1_to_p2.c */ + +void ge_p1p1_to_p2(ge_p2 *, const ge_p1p1 *); + +/* From ge_p1p1_to_p3.c */ + +void ge_p1p1_to_p3(ge_p3 *, const ge_p1p1 *); + +/* From ge_p2_dbl.c */ + +void ge_p2_dbl(ge_p1p1 *, const ge_p2 *); + +/* From ge_p3_to_cached.c */ + +extern const fe fe_d2; +void ge_p3_to_cached(ge_cached *, const ge_p3 *); + +/* From ge_p3_to_p2.c */ + +void ge_p3_to_p2(ge_p2 *, const ge_p3 *); + +/* From ge_p3_tobytes.c */ + +void ge_p3_tobytes(unsigned char *, const ge_p3 *); + +/* From ge_scalarmult_base.c */ + +extern const ge_precomp ge_base[32][8]; +void ge_scalarmult_base(ge_p3 *, const unsigned char *); + +/* From ge_tobytes.c */ + +void ge_tobytes(unsigned char *, const ge_p2 *); + +/* From sc_reduce.c */ + +void sc_reduce(unsigned char *); + +/* New code */ + +void ge_scalarmult(ge_p2 *, const unsigned char *, const ge_p3 *); +void ge_double_scalarmult_precomp_vartime(ge_p2 *, const unsigned char *, const ge_p3 *, const unsigned char *, const ge_dsmp); +void ge_mul8(ge_p1p1 *, const ge_p2 *); +extern const fe fe_ma2; +extern const fe fe_ma; +extern const fe fe_fffb1; +extern const fe fe_fffb2; +extern const fe fe_fffb3; +extern const fe fe_fffb4; +void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *); +void sc_0(unsigned char *); +void sc_reduce32(unsigned char *); +void sc_add(unsigned char *, const unsigned char *, const unsigned char *); +void sc_sub(unsigned char *, const unsigned char *, const unsigned char *); +void sc_mulsub(unsigned char *, const unsigned char *, const unsigned char *, const unsigned char *); +int sc_check(const unsigned char *); +int sc_isnonzero(const unsigned char *); /* Doesn't normalize */ + +// internal +uint64_t load_3(const unsigned char *in); +uint64_t load_4(const unsigned char *in); +void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); +void fe_add(fe h, const fe f, const fe g); +void fe_tobytes(unsigned char *, const fe); +void fe_invert(fe out, const fe z); \ No newline at end of file diff --git a/source-code/RuffCT-java/c/how_monero_hodl_jni_CryptoOpsUtil.c b/source-code/RuffCT-java/c/how_monero_hodl_jni_CryptoOpsUtil.c new file mode 100644 index 0000000..5a93fe9 --- /dev/null +++ b/source-code/RuffCT-java/c/how_monero_hodl_jni_CryptoOpsUtil.c @@ -0,0 +1,87 @@ +#include "how_monero_hodl_jni_CryptoOpsUtil.h" +#include +#include +#include "crypto-ops.h" + +JNIEXPORT jbyteArray JNICALL Java_how_monero_hodl_jni_CryptoOpsUtil_scalarMult + (JNIEnv *env, jclass cls, jbyteArray pointBytes, jbyteArray scalarBytes) { + + jbyte* pointBytesBuf = (*env)->GetByteArrayElements(env, pointBytes, NULL); + jbyte* scalarBytesBuf = (*env)->GetByteArrayElements(env, scalarBytes, NULL); + + ge_p3 pointp3; + ge_p2 pointp2; + ge_p2 pointp2result; + + ge_frombytes_vartime(&pointp3, (const unsigned char *) pointBytesBuf); + + ge_p3_to_p2(&pointp2, &pointp3); + + ge_scalarmult(&pointp2result, (const unsigned char *) scalarBytesBuf, &pointp3); + + unsigned char resultBytes[32]; + ge_tobytes(resultBytes, &pointp2result); + + + jbyteArray returnData = (*env)->NewByteArray(env, 32); + (*env)->SetByteArrayRegion(env, returnData, 0, 32, (jbyte *) resultBytes); + + return returnData; + +} + +//void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { +JNIEXPORT jbyteArray JNICALL Java_how_monero_hodl_jni_CryptoOpsUtil_scalarMultBase + (JNIEnv *env, jclass cls, jbyteArray scalarBytes) { + + jbyte* scalarBytesBuf = (*env)->GetByteArrayElements(env, scalarBytes, NULL); + + ge_p3 pointp3result; + ge_p2 pointp2result; + + ge_scalarmult_base(&pointp3result, (const unsigned char *) scalarBytesBuf); + + ge_p3_to_p2(&pointp2result, &pointp3result); + + unsigned char resultBytes[32]; + ge_tobytes(resultBytes, &pointp2result); + + + jbyteArray returnData = (*env)->NewByteArray(env, 32); + (*env)->SetByteArrayRegion(env, returnData, 0, 32, (jbyte *) resultBytes); + + return returnData; + +} + + + + +//ge_double_scalarmult_base_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) +//r = a * A + b * B +JNIEXPORT jbyteArray JNICALL Java_how_monero_hodl_jni_CryptoOpsUtil_doubleScalarMultBaseVartime + (JNIEnv *env, jclass cls, jbyteArray aScalarBytes, jbyteArray pointBytes, jbyteArray bScalarBytes) { + + jbyte* pointBytesBuf = (*env)->GetByteArrayElements(env, pointBytes, NULL); + jbyte* aScalarBytesBuf = (*env)->GetByteArrayElements(env, aScalarBytes, NULL); + jbyte* bScalarBytesBuf = (*env)->GetByteArrayElements(env, bScalarBytes, NULL); + + ge_p3 pointp3; + ge_p2 pointp2; + ge_p2 pointp2result; + + ge_frombytes_vartime(&pointp3, (const unsigned char *) pointBytesBuf); + + ge_double_scalarmult_base_vartime(&pointp2result, (const unsigned char *) aScalarBytesBuf, &pointp3, (const unsigned char *) bScalarBytesBuf); + + unsigned char resultBytes[32]; + ge_tobytes(resultBytes, &pointp2result); + + + jbyteArray returnData = (*env)->NewByteArray(env, 32); + (*env)->SetByteArrayRegion(env, returnData, 0, 32, (jbyte *) resultBytes); + + return returnData; + +} + diff --git a/source-code/RuffCT-java/c/how_monero_hodl_jni_CryptoOpsUtil.h b/source-code/RuffCT-java/c/how_monero_hodl_jni_CryptoOpsUtil.h new file mode 100644 index 0000000..036a416 --- /dev/null +++ b/source-code/RuffCT-java/c/how_monero_hodl_jni_CryptoOpsUtil.h @@ -0,0 +1,29 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class how_monero_hodl_jni_CryptoOpsUtil */ + +#ifndef _Included_how_monero_hodl_jni_CryptoOpsUtil +#define _Included_how_monero_hodl_jni_CryptoOpsUtil +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: how_monero_hodl_jni_CryptoOpsUtil + * Method: scalarMult + * Signature: ([B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_how_monero_hodl_jni_CryptoOpsUtil_scalarMult + (JNIEnv *, jclass, jbyteArray, jbyteArray); + +/* + * Class: how_monero_hodl_jni_CryptoOpsUtil + * Method: doubleScalarMultBaseVartime + * Signature: ([B[B[B)[B + */ +JNIEXPORT jbyteArray JNICALL Java_how_monero_hodl_jni_CryptoOpsUtil_doubleScalarMultBaseVartime + (JNIEnv *, jclass, jbyteArray, jbyteArray, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/source-code/RuffCT-java/c/warnings.h b/source-code/RuffCT-java/c/warnings.h new file mode 100644 index 0000000..df5c7d1 --- /dev/null +++ b/source-code/RuffCT-java/c/warnings.h @@ -0,0 +1,30 @@ +#pragma once + +#if defined(_MSC_VER) + +#define PUSH_WARNINGS __pragma(warning(push)) +#define POP_WARNINGS __pragma(warning(pop)) +#define DISABLE_VS_WARNINGS(w) __pragma(warning(disable: w)) +#define DISABLE_GCC_WARNING(w) +#define DISABLE_CLANG_WARNING(w) +#define DISABLE_GCC_AND_CLANG_WARNING(w) + +#else + +#include + +#define PUSH_WARNINGS _Pragma("GCC diagnostic push") +#define POP_WARNINGS _Pragma("GCC diagnostic pop") +#define DISABLE_VS_WARNINGS(w) + +#if defined(__clang__) +#define DISABLE_GCC_WARNING(w) +#define DISABLE_CLANG_WARNING DISABLE_GCC_AND_CLANG_WARNING +#else +#define DISABLE_GCC_WARNING DISABLE_GCC_AND_CLANG_WARNING +#define DISABLE_CLANG_WARNING(w) +#endif + +#define DISABLE_GCC_AND_CLANG_WARNING(w) _Pragma(BOOST_PP_STRINGIZE(GCC diagnostic ignored BOOST_PP_STRINGIZE(-W##w))) + +#endif diff --git a/source-code/RuffCT-java/doc/readme.txt b/source-code/RuffCT-java/doc/readme.txt new file mode 100644 index 0000000..bb328ce --- /dev/null +++ b/source-code/RuffCT-java/doc/readme.txt @@ -0,0 +1,19 @@ +Instructions for compiling the Ed25519 native library +----------------------------------------------------- + +Note: You don't need to do any of this if you don't want to. The code will automatically fall back to a pure Java Ed25519 implementation. + + +To compile the JNI C library: + +cd + +# replace with darwin on OSX, or with linux on Linux. +gcc -fPIC -c how_monero_hodl_jni_CryptoOpsUtil.c crypto-ops.c crypto-ops-data.c -I //include// -I //include + +gcc -dynamiclib -o libcryptoopsutil.jnilib how_monero_hodl_jni_CryptoOpsUtil.o crypto-ops.o crypto-ops-data.o -framework JavaVM + +When running Java code that uses this JNI library, provide the following command line argument: + +-Djava.library.path=/ + diff --git a/source-code/RuffCT-java/lib/commons-codec-1.10.jar b/source-code/RuffCT-java/lib/commons-codec-1.10.jar new file mode 100644 index 0000000..1d7417c Binary files /dev/null and b/source-code/RuffCT-java/lib/commons-codec-1.10.jar differ diff --git a/source-code/RuffCT-java/lib/commons-pool2-2.4.2.jar b/source-code/RuffCT-java/lib/commons-pool2-2.4.2.jar new file mode 100644 index 0000000..fdf8b6f Binary files /dev/null and b/source-code/RuffCT-java/lib/commons-pool2-2.4.2.jar differ diff --git a/source-code/RuffCT-java/src/com/joemelsha/crypto/hash/Keccak.java b/source-code/RuffCT-java/src/com/joemelsha/crypto/hash/Keccak.java new file mode 100755 index 0000000..1162750 --- /dev/null +++ b/source-code/RuffCT-java/src/com/joemelsha/crypto/hash/Keccak.java @@ -0,0 +1,449 @@ +package com.joemelsha.crypto.hash; + +import java.nio.*; + +/** + * @author Joseph Robert Melsha (jrmelsha@olivet.edu) + * + * Source: https://github.com/jrmelsha/keccak + * Created: Jun 23, 2016 + * + * Copyright 2016 Joseph Robert Melsha + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +public class Keccak { + private static final int MAX_STATE_SIZE = 1600; + private static final int MAX_STATE_SIZE_WORDS = MAX_STATE_SIZE / 64; + + protected int rateSizeBits, digestSizeBits; + private long[] state = new long[MAX_STATE_SIZE_WORDS]; + private int rateBits; + private boolean padded; + + public Keccak(int digestSizeBits) { + reset(digestSizeBits); + } + + public Keccak(Keccak other) { + System.arraycopy(other.state, 0, state, 0, other.state.length); + rateBits = other.rateBits; + rateSizeBits = other.rateSizeBits; + digestSizeBits = other.digestSizeBits; + padded = other.padded; + } + + @Override + public String toString() { + return "Keccak-" + digestSizeBits; + } + + public int rateSize() { + return rateSizeBits >>> 3; + } + + public int digestSize() { + return digestSizeBits >>> 3; + } + + public void reset() { + reset(rateSizeBits, digestSizeBits); + } + + protected int rateSizeBitsFor(int digestSizeBits) { + //@formatter:off + switch (digestSizeBits) { + case 288: return 1024; + case 128: return 1344; + case 224: return 1152; + case 256: return 1088; + case 384: return 832; + case 512: return 576; + default: throw new IllegalArgumentException("Invalid digestSizeBits: " + digestSizeBits + " ⊄ { 128, 224, 256, 288, 384, 512 }"); + } + //@formatter:on + } + + public void reset(int digestSizeBits) { + reset(rateSizeBitsFor(digestSizeBits), digestSizeBits); + } + + protected void reset(int rateSizebits, int digestSizeBits) { + if (rateSizebits + digestSizeBits * 2 != MAX_STATE_SIZE) + throw new IllegalArgumentException("Invalid rateSizebits + digestSizeBits * 2: " + rateSizebits + " + " + digestSizeBits + " * 2 != " + MAX_STATE_SIZE); + if (rateSizebits <= 0 || (rateSizebits & 0x3f) > 0) + throw new IllegalArgumentException("Invalid rateSizebits: " + rateSizebits); + + for (int i = 0; i < MAX_STATE_SIZE_WORDS; ++i) + state[i] = 0; + rateBits = 0; + + rateSizeBits = rateSizebits; + this.digestSizeBits = digestSizeBits; + padded = false; + } + + public void update(byte in) { + updateBits(in & 0xff, 8); + } + + public void update(byte[] in) { + update(ByteBuffer.wrap(in)); + } + + public void update(byte[] in, int offset, int length) { + update(ByteBuffer.wrap(in, offset, length)); + } + + public void update(ByteBuffer in) { + int inBytes = in.remaining(); + if (inBytes <= 0) + return; + + if (padded) + throw new IllegalStateException("Cannot update while padded"); + + int rateBits = this.rateBits; + if ((rateBits & 0x7) > 0) //this could be implemented but would introduce considerable performance degradation - also, it's never technically possible. + throw new IllegalStateException("Cannot update while in bit-mode"); + + long[] state = this.state; + int rateBytes = rateBits >>> 3; + + int rateBytesWord = rateBytes & 0x7; + if (rateBytesWord > 0) { + //logically must have space at this point + int c = 8 - rateBytesWord; + if (c > inBytes) + c = inBytes; + int i = rateBytes >>> 3; + long w = state[i]; + rateBytes += c; + inBytes -= c; + rateBytesWord <<= 3; + c = rateBytesWord + (c << 3); + do { + w ^= (long) (in.get() & 0xff) << rateBytesWord; + rateBytesWord += 8; + } while (rateBytesWord < c); + state[i] = w; + + if (inBytes > 0) { + this.rateBits = rateBytes << 3; + return; + } + } + + int rateWords = rateBytes >>> 3; + int rateSizeWords = rateSizeBits >>> 6; + + int inWords = inBytes >>> 3; + if (inWords > 0) { + ByteOrder order = in.order(); + try { + in.order(ByteOrder.LITTLE_ENDIAN); + do { + if (rateWords >= rateSizeWords) { + Keccak.keccak(state); + rateWords = 0; + } + int c = rateSizeWords - rateWords; + if (c > inWords) + c = inWords; + inWords -= c; + c += rateWords; + do { + state[rateWords] ^= in.getLong(); + rateWords++; + } while (rateWords < c); + } while (inWords > 0); + } finally { + in.order(order); + } + inBytes &= 0x7; + if (inBytes <= 0) { + this.rateBits = rateWords << 6; + return; + } + } + + if (rateWords >= rateSizeWords) { + Keccak.keccak(state); + rateWords = 0; + } + long w = state[rateWords]; + inBytes <<= 3; + int i = 0; + do { + w ^= (long) (in.get() & 0xff) << i; + i += 8; + } while (i < inBytes); + state[rateWords] = w; + + this.rateBits = (rateWords << 6) | inBytes; + } + + protected void updateBits(long in, int inBits) { + if (inBits < 0 || inBits > 64) + throw new IllegalArgumentException("Invalid valueBits: " + 0 + " < " + inBits + " > " + 64); + + if (inBits <= 0) + return; + + if (padded) + throw new IllegalStateException("Cannot update while padded"); + + long[] state = this.state; + int rateBits = this.rateBits; + int rateBitsWord = rateBits & 0x3f; + if (rateBitsWord > 0) { + //logically must have space at this point + int c = 64 - rateBitsWord; + if (c > inBits) + c = inBits; + state[rateBits >>> 6] ^= (in & (-1L >>> c)) << rateBitsWord; + rateBits += c; + inBits -= c; + if (inBits <= 0) { + this.rateBits = rateBits; + return; + } + in >>>= c; + } + if (rateBits >= rateSizeBits) { + Keccak.keccak(state); + rateBits = 0; + } + state[rateBits >>> 6] ^= in & (-1L >>> inBits); + this.rateBits = rateBits + inBits; + } + + public ByteBuffer digest() { + return digest(digestSize()); + } + + public ByteBuffer digest(int outSize) { + return digest(outSize, false); + } + + public ByteBuffer digest(int outSize, boolean direct) { + ByteBuffer buffer = direct ? ByteBuffer.allocateDirect(outSize) : ByteBuffer.allocate(outSize); + digest(buffer); + buffer.flip(); + return buffer; + } + + public byte[] digestArray() { + return digestArray(digestSize()); + } + + public byte[] digestArray(int outSize) { + byte[] array = new byte[outSize]; + digest(array, 0, outSize); + return array; + } + + public void digest(byte[] out) { + digest(ByteBuffer.wrap(out)); + } + + public void digest(byte[] out, int offset, int length) { + digest(ByteBuffer.wrap(out, offset, length)); + } + + public void digest(ByteBuffer out) { + int outBytes = out.remaining(); + if (outBytes <= 0) + return; + + long[] state = this.state; + int rateBits = this.rateBits; + int rateBytes; + if (!padded) { + pad(); + padded = true; + rateBits = 0; + rateBytes = 0; + } else { + if ((rateBits & 0x7) > 0) + throw new IllegalStateException("Cannot digest while in bit-mode"); //this could be implemented but would introduce considerable performance degradation - also, it's never technically possible. + + rateBytes = rateBits >>> 3; + int rateBytesWord = rateBytes & 0x7; + if (rateBytesWord > 0) { + int c = 8 - rateBytesWord; + if (c > outBytes) + c = outBytes; + long w = state[rateBytes >>> 3]; + outBytes -= c; + rateBytes += c; + rateBytesWord <<= 3; + c = (c << 3) + rateBytesWord; + do { + out.put((byte) (w >>> rateBytesWord)); + rateBytesWord += 8; + } while (rateBytesWord < c); + if (outBytes <= 0) { + this.rateBits = rateBytes << 3; + return; + } + } + } + + int rateSizeWords = rateSizeBits >>> 6; + int rateWords = rateBytes >>> 3; + + int outWords = outBytes >>> 3; + if (outWords > 0) { + ByteOrder order = out.order(); + try { + out.order(ByteOrder.LITTLE_ENDIAN); + do { + if (rateWords >= rateSizeWords) { + squeeze(); + rateWords = 0; + } + int c = rateSizeWords - rateWords; + if (c > outWords) + c = outWords; + outWords -= c; + c += rateWords; + do { + out.putLong(state[rateWords]); + rateWords++; + } while (rateWords < c); + } while (outWords > 0); + } finally { + out.order(order); + } + outBytes &= 0x7; + if (outBytes <= 0) { + this.rateBits = rateWords << 6; + return; + } + } + + if (rateWords >= rateSizeWords) { + squeeze(); + rateWords = 0; + } + long w = state[rateWords]; + outBytes <<= 3; + int i = 0; + do { + out.put((byte) (w >>> i)); + i += 8; + } while (i < outBytes); + this.rateBits = (rateWords << 6) | outBytes; + } + + protected void squeeze() { + Keccak.keccak(state); + } + + protected void pad() { + updateBits(0x1, 1); + if (rateBits >= rateSizeBits) { + Keccak.keccak(state); + rateBits = 0; + } + rateBits = rateSizeBits - 1; + updateBits(0x1, 1); + Keccak.keccak(state); + } + + /** + * @formatter:off + */ + private static void keccak(long[] a) { + //@formatter:off + int c, i; + long x, a_10_; + long x0, x1, x2, x3, x4; + long t0, t1, t2, t3, t4; + long c0, c1, c2, c3, c4; + long[] rc = RC; + + i = 0; + do { + //theta (precalculation part) + c0 = a[0] ^ a[5 + 0] ^ a[10 + 0] ^ a[15 + 0] ^ a[20 + 0]; + c1 = a[1] ^ a[5 + 1] ^ a[10 + 1] ^ a[15 + 1] ^ a[20 + 1]; + c2 = a[2] ^ a[5 + 2] ^ a[10 + 2] ^ a[15 + 2] ^ a[20 + 2]; + c3 = a[3] ^ a[5 + 3] ^ a[10 + 3] ^ a[15 + 3] ^ a[20 + 3]; + c4 = a[4] ^ a[5 + 4] ^ a[10 + 4] ^ a[15 + 4] ^ a[20 + 4]; + + t0 = (c0 << 1) ^ (c0 >>> (64 - 1)) ^ c3; + t1 = (c1 << 1) ^ (c1 >>> (64 - 1)) ^ c4; + t2 = (c2 << 1) ^ (c2 >>> (64 - 1)) ^ c0; + t3 = (c3 << 1) ^ (c3 >>> (64 - 1)) ^ c1; + t4 = (c4 << 1) ^ (c4 >>> (64 - 1)) ^ c2; + + //theta (xorring part) + rho + pi + a[ 0] ^= t1; + x = a[ 1] ^ t2; a_10_ = (x << 1) | (x >>> (64 - 1)); + x = a[ 6] ^ t2; a[ 1] = (x << 44) | (x >>> (64 - 44)); + x = a[ 9] ^ t0; a[ 6] = (x << 20) | (x >>> (64 - 20)); + x = a[22] ^ t3; a[ 9] = (x << 61) | (x >>> (64 - 61)); + + x = a[14] ^ t0; a[22] = (x << 39) | (x >>> (64 - 39)); + x = a[20] ^ t1; a[14] = (x << 18) | (x >>> (64 - 18)); + x = a[ 2] ^ t3; a[20] = (x << 62) | (x >>> (64 - 62)); + x = a[12] ^ t3; a[ 2] = (x << 43) | (x >>> (64 - 43)); + x = a[13] ^ t4; a[12] = (x << 25) | (x >>> (64 - 25)); + + x = a[19] ^ t0; a[13] = (x << 8) | (x >>> (64 - 8)); + x = a[23] ^ t4; a[19] = (x << 56) | (x >>> (64 - 56)); + x = a[15] ^ t1; a[23] = (x << 41) | (x >>> (64 - 41)); + x = a[ 4] ^ t0; a[15] = (x << 27) | (x >>> (64 - 27)); + x = a[24] ^ t0; a[ 4] = (x << 14) | (x >>> (64 - 14)); + + x = a[21] ^ t2; a[24] = (x << 2) | (x >>> (64 - 2)); + x = a[ 8] ^ t4; a[21] = (x << 55) | (x >>> (64 - 55)); + x = a[16] ^ t2; a[ 8] = (x << 45) | (x >>> (64 - 45)); + x = a[ 5] ^ t1; a[16] = (x << 36) | (x >>> (64 - 36)); + x = a[ 3] ^ t4; a[ 5] = (x << 28) | (x >>> (64 - 28)); + + x = a[18] ^ t4; a[ 3] = (x << 21) | (x >>> (64 - 21)); + x = a[17] ^ t3; a[18] = (x << 15) | (x >>> (64 - 15)); + x = a[11] ^ t2; a[17] = (x << 10) | (x >>> (64 - 10)); + x = a[ 7] ^ t3; a[11] = (x << 6) | (x >>> (64 - 6)); + x = a[10] ^ t1; a[ 7] = (x << 3) | (x >>> (64 - 3)); + a[10] = a_10_; + + //chi + c = 0; + do { + x0 = a[c + 0]; x1 = a[c + 1]; x2 = a[c + 2]; x3 = a[c + 3]; x4 = a[c + 4]; + a[c + 0] = x0 ^ ((~x1) & x2); + a[c + 1] = x1 ^ ((~x2) & x3); + a[c + 2] = x2 ^ ((~x3) & x4); + a[c + 3] = x3 ^ ((~x4) & x0); + a[c + 4] = x4 ^ ((~x0) & x1); + + c += 5; + } while (c < 25); + + //iota + a[0] ^= rc[i]; + + i++; + } while (i < 24); + //@formatter:on + } + + private static final long[] RC = { 0x0000000000000001L, 0x0000000000008082L, 0x800000000000808AL, 0x8000000080008000L, 0x000000000000808BL, 0x0000000080000001L, 0x8000000080008081L, + 0x8000000000008009L, 0x000000000000008AL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000AL, 0x000000008000808BL, 0x800000000000008BL, + 0x8000000000008089L, 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, 0x000000000000800AL, 0x800000008000000AL, 0x8000000080008081L, + 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L }; +} \ No newline at end of file diff --git a/source-code/RuffCT-java/src/how/monero/hodl/crypto/CryptoUtil.java b/source-code/RuffCT-java/src/how/monero/hodl/crypto/CryptoUtil.java new file mode 100644 index 0000000..266eb04 --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/crypto/CryptoUtil.java @@ -0,0 +1,155 @@ +package how.monero.hodl.crypto; + +import com.joemelsha.crypto.hash.Keccak; +import how.monero.hodl.util.ExceptionAdapter; +import org.apache.commons.pool2.BasePooledObjectFactory; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.nem.core.crypto.ed25519.arithmetic.*; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import static how.monero.hodl.crypto.HashToPoint.hashToPoint; +import static how.monero.hodl.util.ByteUtil.*; + +public class CryptoUtil { + + public static GenericObjectPool keccakPool = new GenericObjectPool(new BasePooledObjectFactory() { + + @Override + public PooledObject wrap(Keccak keccak) { + return new DefaultPooledObject<>(keccak); + } + + @Override + public Keccak create() throws Exception { + return new Keccak(256); + } + }); + + public static final Ed25519GroupElement G = Ed25519Group.BASE_POINT; + public static final Ed25519GroupElement H = new Ed25519EncodedGroupElement(hexToBytes("8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94")).decode(); + static { + H.precomputeForScalarMultiplication(); + } + + public static Scalar hashToScalar(byte[] a) { + return new Scalar(scReduce32(fastHash(a))); + } + + public static byte[] fastHash(byte[] a) { + try { + Keccak keccak = keccakPool.borrowObject(); + try { + keccak.reset(); + keccak.update(a); + return keccak.digestArray(); + } finally { + keccakPool.returnObject(keccak); + } + } catch (Exception e) { + throw ExceptionAdapter.toRuntimeException(e); + } + } + + public static BigInteger l = BigInteger.valueOf(2).pow(252).add(new BigInteger("27742317777372353535851937790883648493")); + + public static byte[] scReduce32(byte[] a) { + byte[] r = getBigIntegerFromUnsignedLittleEndianByteArray(a).mod(l).toByteArray(); + return ensure32BytesAndConvertToLittleEndian(r); + } + + public static byte[] ensure32BytesAndConvertToLittleEndian(byte[] r) { + byte[] s = new byte[32]; + if(r.length>32) System.arraycopy(r, 1, s, 0, s.length); + else System.arraycopy(r, 0, s, 32 - r.length, r.length); + reverseByteArrayInPlace(s); + return s; + } + + public static BigInteger getBigIntegerFromUnsignedLittleEndianByteArray(byte[] a1) { + byte[] a = new byte[a1.length]; + System.arraycopy(a1, 0, a, 0, 32); + reverseByteArrayInPlace(a); + byte[] a2 = new byte[33]; + System.arraycopy(a, 0, a2, 1, 32); + return new BigInteger(a2); + } + public static byte[] getUnsignedLittleEndianByteArrayFromBigInteger(BigInteger n) { + byte[] a = n.toByteArray(); + byte[] a2 = new byte[32]; + System.arraycopy(a, 0, a2, 32-a.length, a.length); + reverseByteArrayInPlace(a2); + return a2; + } + + public static final Random random = new SecureRandom(); + public static byte[] randomPointAsBytes() { + return randomPoint().encode().getRaw(); + } + public static Ed25519GroupElement randomPoint() { + return Ed25519Group.BASE_POINT.scalarMultiply(Scalar.randomScalar()); + } + public static byte[] randomMessage(int len) { + byte[] m = new byte[len]; + random.nextBytes(m); + return m; + } + + public static byte[] toBytes(Ed25519GroupElement[] a) { + byte[] r = new byte[0]; + for(Ed25519GroupElement ai : a) r = concat(r, ai.encode().getRaw()); + return r; + } + + public static Scalar sumArray(Scalar[] a) { + Scalar r = Scalar.ZERO; + for(Scalar ai : a) r = r.add(ai); + return r; + } + + + + public static PointPair COMeg(Scalar xAmount, Scalar rMask) { + return new PointPair(G.scalarMultiply(xAmount).add(getHpnGLookup(1).scalarMultiply(rMask).toCached()), G.scalarMultiply(rMask)); + } + + public static Ed25519GroupElement COMp(Scalar xAmount, Scalar rMask) { + return G.scalarMultiply(xAmount).add(getHpnGLookup(1).scalarMultiply(rMask).toCached()); + } + + public static Ed25519GroupElement COMb(Scalar[][] x, Scalar r) { + int m = x.length; + int n = x[0].length; + Ed25519GroupElement A = G.scalarMultiply(r); + for(int j=0; j HpnGLookup = new HashMap<>(); + + public static Ed25519GroupElement getHpnGLookup(int n) { + if(!HpnGLookup.containsKey(n)) { + Ed25519GroupElement HpnG = hashToPoint(G.scalarMultiply(Scalar.intToScalar(n))); + //HpnG.precomputeForScalarMultiplication(); // try precomputed vs non-precomputed to check best performance + HpnGLookup.put(n, HpnG); + } + return HpnGLookup.get(n); + } + + public static PointPair ENCeg(Ed25519GroupElement X, Scalar r) { + return new PointPair(getHpnGLookup(1).scalarMultiply(r).toP3().add(X.toCached()), G.scalarMultiply(r)); + } + + +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/crypto/HashToPoint.java b/source-code/RuffCT-java/src/how/monero/hodl/crypto/HashToPoint.java new file mode 100644 index 0000000..2a463e6 --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/crypto/HashToPoint.java @@ -0,0 +1,136 @@ +package how.monero.hodl.crypto; + +import org.nem.core.crypto.ed25519.arithmetic.Ed25519EncodedGroupElement; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement; +import org.nem.core.utils.ArrayUtils; + +import java.math.BigInteger; + +import static how.monero.hodl.crypto.CryptoUtil.*; +import static how.monero.hodl.util.ByteUtil.*; + +public class HashToPoint { + + private static BigInteger b = BigInteger.valueOf(256); + private static BigInteger q = BigInteger.valueOf(2).pow(255).subtract(BigInteger.valueOf(19)); + private static BigInteger p = q; + private static BigInteger l = BigInteger.valueOf(2).pow(252).add(new BigInteger("27742317777372353535851937790883648493")); + private static BigInteger I = expmod(BigInteger.valueOf(2), (q.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(4)), q); + + + public static Ed25519GroupElement hashToPoint(Ed25519GroupElement a) { + return hashToPoint(a.encode().getRaw()); + } + + public static Ed25519GroupElement hashToPoint(byte[] a) { + + byte[] hash = fastHash(a); + + BigInteger u = ArrayUtils.toBigInteger(hash).mod(q); + + BigInteger A = BigInteger.valueOf(486662); + + BigInteger sqrtm1 = ed25519Sqroot(BigInteger.valueOf(-1)); + + BigInteger w = (BigInteger.valueOf(2).multiply(u).multiply(u).add(BigInteger.ONE)).mod(q); + BigInteger xp = w.multiply(w).subtract(BigInteger.valueOf(2).multiply(A).multiply(A).multiply(u).multiply(u)).mod(q); + + BigInteger b = w.multiply(ed25519Inv(xp)); + BigInteger e = (q.add(BigInteger.valueOf(3)).divide(BigInteger.valueOf(8))); + BigInteger rx = expmod(b, e, q); + + BigInteger x = rx.multiply(rx).multiply(w.multiply(w).subtract(BigInteger.valueOf(2).multiply(A).multiply(A).multiply(u).multiply(u))).mod(q); + + BigInteger y = (BigInteger.valueOf(2).multiply(u).multiply(u).add(BigInteger.ONE).subtract(x)).mod(q); + + BigInteger z; + + boolean negative = false; + if (!y.equals(BigInteger.ZERO)) { + y = (w.add(x)).mod(q); + if (!y.equals(BigInteger.ZERO)) { + negative = true; + } else { + rx = rx.multiply(BigInteger.valueOf(-1)).multiply(ed25519Sqroot(BigInteger.valueOf(-2).multiply(A).multiply((A.add(BigInteger.valueOf(2)))))).mod(q); + negative = false; + } + } else { + rx = rx.multiply(BigInteger.valueOf(-1)).multiply(ed25519Sqroot(BigInteger.valueOf(2).multiply(A).multiply((A.add(BigInteger.valueOf(2)))))).mod(q); + } + + BigInteger sign; + if (!negative) { + rx = (rx.multiply(u)).mod(q); + z = (BigInteger.valueOf(-2).multiply(A).multiply(u).multiply(u)).mod(q); + sign = BigInteger.ZERO; + } else { + z = BigInteger.valueOf(-1).multiply(A); + x = x.multiply(sqrtm1).mod(q); + y = (w.subtract(x)).mod(q); + if (!y.equals(BigInteger.ZERO)) { + rx = rx.multiply(ed25519Sqroot(BigInteger.valueOf(-1).multiply(sqrtm1).multiply(A).multiply((A.add(BigInteger.valueOf(2)))))).mod(q); + } else { + rx = rx.multiply(BigInteger.valueOf(-1)).multiply(ed25519Sqroot(sqrtm1.multiply(A).multiply((A.add(BigInteger.valueOf(2)))))).mod(q); + } + sign = BigInteger.ONE; + } + if(!(rx.mod(BigInteger.valueOf(2)).equals(sign))) { + rx = rx.mod(q).negate(); + } + BigInteger rz = (z.add(w)).mod(q); + BigInteger ry = (z.subtract(w)).mod(q); + rx = (rx.multiply(rz)).mod(q); + + Ed25519GroupElement P = pointCompress(rx, ry, rz); + Ed25519GroupElement P8 = P.toP2().dbl().toP2().dbl().toP2().dbl().toP3(); + return P8; + + } + + private static Ed25519GroupElement pointCompress(BigInteger P0, BigInteger P1, BigInteger P2) { + BigInteger zinv = modpInv(P2); + BigInteger x = P0.multiply(zinv).mod(p); + BigInteger y = P1.multiply(zinv).mod(p); + + BigInteger r = y.or((x.and(BigInteger.ONE)).shiftLeft(255)); + + byte[] a = r.toByteArray(); + + byte[] b = new byte[32]; + + if(a.length>32) System.arraycopy(a, a.length-32, b, 0, 32); + else if(a.length<32) System.arraycopy(a, 0, b, 32-a.length, a.length); + else System.arraycopy(a, 0, b, 0, 32); + + reverseByteArrayInPlace(b); + return new Ed25519EncodedGroupElement(b).decode(); + } + + private static BigInteger modpInv(BigInteger x) { + return x.modPow(p.subtract(BigInteger.valueOf(2)), p); + } + + private static BigInteger ed25519Inv(BigInteger x) { + return expmod(x, q.subtract(BigInteger.valueOf(2)), q); + } + + private static BigInteger ed25519Sqroot(BigInteger xx) { + BigInteger x = expmod(xx, q.add(BigInteger.valueOf(3)).divide(BigInteger.valueOf(8)), q); + if (!x.multiply(x).subtract(xx).mod(q).equals(BigInteger.ZERO)) { + x = x.multiply(I).mod(q); + } + if (!x.multiply(x).subtract(xx).mod(q).equals(BigInteger.ZERO)) { + throw new RuntimeException("no square root!"); + } + return x; + } + + private static BigInteger expmod(BigInteger b, BigInteger e, BigInteger m) { + if (e.equals(BigInteger.ZERO)) return BigInteger.ONE; + BigInteger t = expmod(b, e.divide(BigInteger.valueOf(2)), m).pow(2).mod(m); + if(e.and(BigInteger.ONE).equals(BigInteger.ONE)) t = (t.multiply(b)).mod(m); + return t; + } + + +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/crypto/PointPair.java b/source-code/RuffCT-java/src/how/monero/hodl/crypto/PointPair.java new file mode 100644 index 0000000..eda3388 --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/crypto/PointPair.java @@ -0,0 +1,37 @@ +package how.monero.hodl.crypto; + +import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement; + +import static how.monero.hodl.util.ByteUtil.*; + +public class PointPair { + public Ed25519GroupElement P1; + public Ed25519GroupElement P2; + public PointPair(Ed25519GroupElement P1, Ed25519GroupElement P2) { + this.P1 = P1; + this.P2 = P2; + } + public byte[] toBytes() { + return concat(P1.encode().getRaw(), P2.encode().getRaw()); + } + public PointPair add(PointPair a) { + return new PointPair(P1.toP3().add(a.P1.toP3().toCached()), P2.toP3().add(a.P2.toP3().toCached())); + } + public PointPair subtract(PointPair a) { + return new PointPair(P1.toP3().subtract(a.P1.toCached()), P2.toP3().subtract(a.P2.toCached())); + } + public PointPair multiply(Scalar n) { + return new PointPair(P1.toP3().scalarMultiply(n), P2.toP3().scalarMultiply(n)); + } + + public boolean equals(PointPair obj) { + return P1.toP3().equals(obj.P1.toP3()) && P2.toP3().equals(obj.P2.toP3()); + } + + @Override + public String toString() { + return "(P1: " + bytesToHex(P1.encode().getRaw()) + ", P2: " + P2 + ")"; + } + +} + diff --git a/source-code/RuffCT-java/src/how/monero/hodl/crypto/Scalar.java b/source-code/RuffCT-java/src/how/monero/hodl/crypto/Scalar.java new file mode 100644 index 0000000..0f23602 --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/crypto/Scalar.java @@ -0,0 +1,100 @@ +package how.monero.hodl.crypto; + +import how.monero.hodl.util.ByteUtil; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519EncodedFieldElement; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519FieldElement; + +import java.math.BigInteger; +import java.util.Arrays; + +import static how.monero.hodl.crypto.CryptoUtil.*; +import static how.monero.hodl.util.ByteUtil.*; + +public class Scalar { + + public final static Scalar ZERO = intToScalar(0); + public final static Scalar ONE = intToScalar(1); + public final static Scalar TWO = intToScalar(2); + public final static Scalar MINUS_ONE = intToScalar(-1); + + // use only for small numbers + public static Scalar intToScalar(int a) { + return new Scalar(scReduce32(getUnsignedLittleEndianByteArrayFromBigInteger(BigInteger.valueOf(a).mod(l)))); + } + + public byte[] bytes; + public Scalar(byte[] bytes) { + this.bytes = bytes; + } + public Scalar(String hex) { + this.bytes = ByteUtil.hexToBytes(hex); + } + public Scalar(BigInteger a) { + this(scReduce32(getUnsignedLittleEndianByteArrayFromBigInteger(a.mod(l)))); + } + public Ed25519EncodedFieldElement toEd25519EncodedFieldElement() { + return new Ed25519EncodedFieldElement(bytes); + } + public Ed25519FieldElement toEd25519FieldElement() { + return new Ed25519EncodedFieldElement(bytes).decode(); + } + + public static Scalar randomScalar() { + byte[] s = new byte[32]; + random.nextBytes(s); + s = CryptoUtil.scReduce32(s); + return new Scalar(s); + } + + @Override + public String toString() { + return bytesToHex(bytes); + } + + public BigInteger toBigInteger() { + return getBigIntegerFromUnsignedLittleEndianByteArray(this.bytes); + } + + @Override + public boolean equals(Object obj) { + return Arrays.equals(this.bytes, ((Scalar)obj).bytes); + } + + public static BigInteger[] scalarArrayToBigIntegerArray(Scalar[] a) { + BigInteger[] r = new BigInteger[a.length]; + for(int i=0; i=128) { + isLastByteInVarInt = false; + i-=128; + } + result += Math.round(i * Math.pow(128, c)); + c++; + pos++; + if(isLastByteInVarInt) break; + } + return result; + } + public BigInteger readVarIntAsBigInteger() { + + BigInteger result = BigInteger.ZERO; + int c = 0; + + while(true) { + boolean isLastByteInVarInt = true; + int i = Byte.toUnsignedInt(data[pos]); + if(i>=128) { + isLastByteInVarInt = false; + i-=128; + } + result = result.add(BigInteger.valueOf(Math.round(i * Math.pow(128, c)))); + c++; + pos++; + if(isLastByteInVarInt) break; + } + return result; + } + + public byte[] readBytes(int len) { + byte[] bytes = new byte[len]; + System.arraycopy(data, pos, bytes, 0, len); + pos+=len; + return bytes; + } + public Scalar readScalar() { + return new Scalar(readBytes(32)); + } + + + public int readByte() { + pos++; + return Byte.toUnsignedInt(data[pos-1]); + } + + public byte[] readKey() { + return readBytes(32); + } + + +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/jni/CryptoOpsUtil.java b/source-code/RuffCT-java/src/how/monero/hodl/jni/CryptoOpsUtil.java new file mode 100644 index 0000000..7e89feb --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/jni/CryptoOpsUtil.java @@ -0,0 +1,11 @@ +package how.monero.hodl.jni; + +public class CryptoOpsUtil { + + static { System.loadLibrary("cryptoopsutil"); } + + public static native byte[] scalarMult(byte[] point, byte[] scalar); + public static native byte[] scalarMultBase(byte[] scalar); + public static native byte[] doubleScalarMultBaseVartime(byte[] aScalar, byte[] point, byte[] bScalar); + +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/ringSignature/BootleRuffing.java b/source-code/RuffCT-java/src/how/monero/hodl/ringSignature/BootleRuffing.java new file mode 100644 index 0000000..e8dcd33 --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/ringSignature/BootleRuffing.java @@ -0,0 +1,560 @@ +package how.monero.hodl.ringSignature; + +import how.monero.hodl.crypto.PointPair; +import how.monero.hodl.crypto.Scalar; +import how.monero.hodl.cursor.BootleRuffingCursor; +import how.monero.hodl.util.VarInt; +import org.nem.core.crypto.ed25519.arithmetic.*; + +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +import static how.monero.hodl.crypto.CryptoUtil.*; +import static how.monero.hodl.crypto.HashToPoint.hashToPoint; +import static how.monero.hodl.crypto.Scalar.bigIntegerArrayToScalarArray; +import static how.monero.hodl.crypto.Scalar.randomScalar; +import static how.monero.hodl.util.ByteUtil.*; + + +public class BootleRuffing { + + public static class SK { + public Scalar r; + public Scalar r1; + public SK(Scalar r, Scalar r1) { + this.r = r; this.r1 = r1; + } + + @Override + public String toString() { + return "(r: " + bytesToHex(r) + ", r1: " + bytesToHex(r1) + ")"; + } + } + + public static KeyGenResult KEYGEN() { + SK sk = new SK(randomScalar(), randomScalar()); + Ed25519GroupElement ki = G.scalarMultiply(sk.r1); + PointPair pk = ENCeg(ki, sk.r); + return new KeyGenResult(sk, ki, pk); + } + public static class KeyGenResult { + public SK sk; + public Ed25519GroupElement ki; + public PointPair pk = null; + public KeyGenResult(SK sk, Ed25519GroupElement ki, PointPair pk) { + this.sk = sk; this.ki = ki; this.pk = pk; + } + + @Override + public String toString() { + return "sk: " + sk.toString() + ", ki: " + bytesToHex(ki.encode().getRaw()) + ", pk: " + (pk==null ? "(no pk)" : "pk: " + pk); + } + } + + public static class F { + public Ed25519GroupElement[] ki; + public PointPair[][] pk; + public Ed25519GroupElement[] co; + public Ed25519GroupElement co1; + byte[] M; + public F(Ed25519GroupElement[] ki, PointPair[][] pk, Ed25519GroupElement[] co, Ed25519GroupElement co1, byte[] M) { + this.ki = ki; this.pk = pk; this.co = co; this.co1 = co1; this.M = M; + } + byte[] toBytes() { + byte[] r = new byte[0]; + for(int i=0; i=0; i--) { + z = z.sub(u[i].mul(x1.pow(i))); + } + return new Proof2(P, B, G, z); + } + + + public static class Proof2 { + Proof1 P; + public Ed25519GroupElement B; + public PointPair[] G; + public Scalar z; + + private Proof2(Proof1 P, Ed25519GroupElement B, PointPair[] G, Scalar z) { + this.P = P; + this.B = B; + this.G = G; + this.z = z; + } + + private byte[] toBytes(int decompositionBase, int decompositionExponent) { + byte[] bytes; + bytes = concat(P.toBytes(decompositionBase, decompositionExponent), B.encode().getRaw()); + for(PointPair g : G) bytes = concat(bytes, g.toBytes()); + bytes = concat(bytes, z.bytes); + return bytes; + } + + } + + private static int delta(int j, int i) { + return j==i ? 1 : 0; + } + private static int intPow(int a, int b) { + return (int) Math.round(Math.pow(a, b)); + } + public static int[] nAryDecompose(int base, int n, int decompositionExponent) { + int[] r = new int[decompositionExponent]; + for(int i=decompositionExponent-1; i>=0; i--) { + int basePow = intPow(base, i); + r[i] = n / basePow; + n-=basePow*r[i]; + } + return r; + } + + public static boolean VALID1(Ed25519GroupElement B, Proof1 P) { + boolean abcdOnCurve = + P.A.satisfiesCurveEquation() + && B.satisfiesCurveEquation() + && P.C.satisfiesCurveEquation() + && P.D.satisfiesCurveEquation(); + if(!abcdOnCurve) { + System.out.println("VALID1: ABCD not on curve"); + return false; + } + + int m = P.fTrimmed.length; + int n = P.fTrimmed[0].length + 1; + + Scalar[][] f = new Scalar[m][n]; + for(int j=0; j=a.length) return BigInteger.ZERO; + else return a[index].toBigInteger(); + } + +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/ringSignature/Multisignature.java b/source-code/RuffCT-java/src/how/monero/hodl/ringSignature/Multisignature.java new file mode 100644 index 0000000..4c0c02f --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/ringSignature/Multisignature.java @@ -0,0 +1,114 @@ +package how.monero.hodl.ringSignature; + +import how.monero.hodl.crypto.Scalar; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement; + +import java.util.*; + +import static how.monero.hodl.crypto.Scalar.randomScalar; +import static how.monero.hodl.util.ByteUtil.bytesToHex; +import static how.monero.hodl.util.ByteUtil.concat; +import static how.monero.hodl.crypto.CryptoUtil.*; + +public class Multisignature { + + public static Ed25519GroupElement[] lexicographicalSort(Ed25519GroupElement[] X) { + SortedMap hexToPoint = new TreeMap<>(); + for(Ed25519GroupElement Xi : X) hexToPoint.put(bytesToHex(Xi.encode().getRaw()), Xi); + return hexToPoint.values().stream().toArray(Ed25519GroupElement[]::new); + } + + /* + VER*: Take as input a message M, public keys L' = X[1], ..., X[n], and a + signature sigma = (R,s). + 1) Compute L* = H(L') + 2) For each i=1,2,...,n, compute c[i] = Hs(X[i], R, L*, M) + 3) Accept if and only if sG = R + c[1]*X[1] + ... + c[n]*X[n] + */ + public static boolean verify(byte[] M, Ed25519GroupElement[] X, Signature signature) { + int n = X.length; + + Scalar XAsterisk = hashToScalar(toBytes(lexicographicalSort(X))); + + Scalar[] c = new Scalar[n]; + for(int i=0; i>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + public static byte[] hexToBytes(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i+1), 16)); + } + return data; + } + + public static void reverseByteArrayInPlace(byte[] array) { + for(int i = 0; i < array.length / 2; i++) + { + byte temp = array[i]; + array[i] = array[array.length - i - 1]; + array[array.length - i - 1] = temp; + } + } + + public static byte[] concat(byte a, byte[] b) { + byte[] r = new byte[1+b.length]; + r[0] = a; + System.arraycopy(b, 0, r, 1, b.length); + return r; + } + public static byte[] concat(byte[] a, byte[] b) { + byte[] r = new byte[a.length+b.length]; + System.arraycopy(a, 0, r, 0, a.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; + } + public static byte[] concat(byte[] a, byte[] b, byte[] c) { + return concat(concat(a, b), c); + } + public static byte[] concat(byte[] a, byte[] b, byte[] c, byte[] d) { + return concat(concat(a, b), concat(c, d)); + } + + public static byte[] subarray(byte[] a, int start, int end) { + byte[] r = new byte[end-start]; + System.arraycopy(a, start, r, 0, r.length); + return r; + } + + public static byte[] xor(byte[] a, byte[] b) { + byte[] r = new byte[a.length]; + for(int i=0; i=0; i--) array[i] = (byte) (value >> i*8); + return array; + } + +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/util/ExceptionAdapter.java b/source-code/RuffCT-java/src/how/monero/hodl/util/ExceptionAdapter.java new file mode 100644 index 0000000..4628fdd --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/util/ExceptionAdapter.java @@ -0,0 +1,8 @@ +package how.monero.hodl.util; + +public class ExceptionAdapter { + public static RuntimeException toRuntimeException(Exception e) { + if(RuntimeException.class.isInstance(e)) return (RuntimeException) e; + else return new RuntimeException(e); + } +} diff --git a/source-code/RuffCT-java/src/how/monero/hodl/util/VarInt.java b/source-code/RuffCT-java/src/how/monero/hodl/util/VarInt.java new file mode 100644 index 0000000..ef21a50 --- /dev/null +++ b/source-code/RuffCT-java/src/how/monero/hodl/util/VarInt.java @@ -0,0 +1,45 @@ +package how.monero.hodl.util; + +public class VarInt { + + public static byte[] writeVarInt(long value) { + byte[] data = new byte[8]; + int pos = 0; + + while ((value & 0xFFFFFF80) != 0L) { + data[pos] = (byte) ((value & 0x7F) | 0x80); + pos++; + value >>>= 7; + } + data[pos] = (byte) (value & 0x7F); + pos++; + + byte[] result = new byte[pos]; + System.arraycopy(data, 0, result, 0, pos); + return result; + } + + public static long readVarInt(byte[] data) { + + long result = 0; + int c = 0; + int pos = 0; + + while(true) { + boolean isLastByteInVarInt = true; + int i = Byte.toUnsignedInt(data[pos]); + if(i>=128) { + isLastByteInVarInt = false; + i-=128; + } + result += Math.round(i * Math.pow(128, c)); + c++; + pos++; + if(isLastByteInVarInt) break; + } + + return result; + } + + +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/Curve.java b/source-code/RuffCT-java/src/org/nem/core/crypto/Curve.java new file mode 100755 index 0000000..5c89399 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/Curve.java @@ -0,0 +1,30 @@ +package org.nem.core.crypto; + +import java.math.BigInteger; + +/** + * Interface for getting information for a curve. + */ +public interface Curve { + + /** + * Gets the name of the curve. + * + * @return The name of the curve. + */ + String getName(); + + /** + * Gets the group order. + * + * @return The group order. + */ + BigInteger getGroupOrder(); + + /** + * Gets the group order / 2. + * + * @return The group order / 2. + */ + BigInteger getHalfGroupOrder(); +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/Ed25519Curve.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/Ed25519Curve.java new file mode 100755 index 0000000..f49a61f --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/Ed25519Curve.java @@ -0,0 +1,41 @@ +package org.nem.core.crypto.ed25519; + +import org.nem.core.crypto.ed25519.arithmetic.Ed25519Group; + +import java.math.BigInteger; + +/** + * Class that wraps the elliptic curve Ed25519. + */ +public class Ed25519Curve implements org.nem.core.crypto.Curve { + + private static final Ed25519Curve ED25519; + + static { + ED25519 = new Ed25519Curve(); + } + + @Override + public String getName() { + return "ed25519"; + } + + @Override + public BigInteger getGroupOrder() { + return Ed25519Group.GROUP_ORDER; + } + + @Override + public BigInteger getHalfGroupOrder() { + return Ed25519Group.GROUP_ORDER.shiftRight(1); + } + + /** + * Gets the Ed25519 instance. + * + * @return The Ed25519 instance. + */ + public static Ed25519Curve ed25519() { + return ED25519; + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/CoordinateSystem.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/CoordinateSystem.java new file mode 100755 index 0000000..29d6df1 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/CoordinateSystem.java @@ -0,0 +1,37 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +/** + * Available coordinate systems for a group element. + */ +public enum CoordinateSystem { + + /** + * Affine coordinate system (x, y). + */ + AFFINE, + + /** + * Projective coordinate system (X:Y:Z) satisfying x=X/Z, y=Y/Z. + */ + P2, + + /** + * Extended projective coordinate system (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT. + */ + P3, + + /** + * Completed coordinate system ((X:Z), (Y:T)) satisfying x=X/Z, y=Y/T. + */ + P1xP1, + + /** + * Precomputed coordinate system (y+x, y-x, 2dxy). + */ + PRECOMPUTED, + + /** + * Cached coordinate system (Y+X, Y-X, Z, 2dT). + */ + CACHED +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519EncodedFieldElement.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519EncodedFieldElement.java new file mode 100755 index 0000000..5acc2ef --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519EncodedFieldElement.java @@ -0,0 +1,1005 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +import org.nem.core.utils.*; + +import java.util.Arrays; + +/** + * Represents a field element of the finite field with p=2^255-19 elements. + * The value of the field element is held in 2^8 bit representation, i.e. in a byte array. + * The length of the array must be 32 or 64. + */ +public class Ed25519EncodedFieldElement { + private final byte[] zero; + private final byte[] values; + + /** + * Creates a new encoded field element. + * + * @param values The byte array that holds the values. + */ + public Ed25519EncodedFieldElement(final byte[] values) { + switch (values.length) { + case 32: + this.zero = Ed25519Field.ZERO_SHORT; + break; + case 64: + this.zero = Ed25519Field.ZERO_LONG; + break; + default: + throw new IllegalArgumentException("Invalid 2^8 bit representation."); + } + + this.values = values; + } + + /** + * Gets the underlying byte array. + * + * @return The byte array. + */ + public byte[] getRaw() { + return this.values; + } + + /** + * Return true if this is in {1,3,5,...,q-2} + * Return false if this is in {0,2,4,...,q-1} + *
+ * Preconditions: + * |x| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + * + * @return true if this is in {1,3,5,...,q-2}, false otherwise. + */ + public boolean isNegative() { + return (this.values[0] & 1) != 0; + } + + /** + * Gets a value indicating whether or not the field element is non-zero. + * + * @return 1 if it is non-zero, 0 otherwise. + */ + public boolean isNonZero() { + return 0 == ArrayUtils.isEqualConstantTime(this.values, this.zero); + } + + /** + * Decodes this encoded (32 byte) representation to a field element in its 10 byte 2^25.5 representation. + * The most significant bit is discarded. + * + * @return The field element in its 2^25.5 bit representation. + */ + public Ed25519FieldElement decode() { + long h0 = fourBytesToLong(this.values, 0); + long h1 = threeBytesToLong(this.values, 4) << 6; + long h2 = threeBytesToLong(this.values, 7) << 5; + long h3 = threeBytesToLong(this.values, 10) << 3; + long h4 = threeBytesToLong(this.values, 13) << 2; + long h5 = fourBytesToLong(this.values, 16); + long h6 = threeBytesToLong(this.values, 20) << 7; + long h7 = threeBytesToLong(this.values, 23) << 5; + long h8 = threeBytesToLong(this.values, 26) << 4; + long h9 = (threeBytesToLong(this.values, 29) & 0x7FFFFF) << 2; + final long carry0; + final long carry1; + final long carry2; + final long carry3; + final long carry4; + final long carry5; + final long carry6; + final long carry7; + final long carry8; + final long carry9; + + // Remember: 2^255 congruent 19 modulo p + carry9 = (h9 + (long)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry1 = (h1 + (long)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry3 = (h3 + (long)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry5 = (h5 + (long)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry7 = (h7 + (long)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry0 = (h0 + (long)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry2 = (h2 + (long)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry4 = (h4 + (long)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry6 = (h6 + (long)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry8 = (h8 + (long)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + final int[] h = new int[10]; + h[0] = (int)h0; + h[1] = (int)h1; + h[2] = (int)h2; + h[3] = (int)h3; + h[4] = (int)h4; + h[5] = (int)h5; + h[6] = (int)h6; + h[7] = (int)h7; + h[8] = (int)h8; + h[9] = (int)h9; + + return new Ed25519FieldElement(h); + } + + /** + * Reduces this encoded field element (64 bytes) modulo the group order q. + * + * @return Encoded field element (32 bytes). + */ + public Ed25519EncodedFieldElement modQ() { + // s0, ..., s22 have 21 bits, s23 has 29 bits + long s0 = 0x1FFFFF & threeBytesToLong(this.values, 0); + long s1 = 0x1FFFFF & (fourBytesToLong(this.values, 2) >> 5); + long s2 = 0x1FFFFF & (threeBytesToLong(this.values, 5) >> 2); + long s3 = 0x1FFFFF & (fourBytesToLong(this.values, 7) >> 7); + long s4 = 0x1FFFFF & (fourBytesToLong(this.values, 10) >> 4); + long s5 = 0x1FFFFF & (threeBytesToLong(this.values, 13) >> 1); + long s6 = 0x1FFFFF & (fourBytesToLong(this.values, 15) >> 6); + long s7 = 0x1FFFFF & (threeBytesToLong(this.values, 18) >> 3); + long s8 = 0x1FFFFF & threeBytesToLong(this.values, 21); + long s9 = 0x1FFFFF & (fourBytesToLong(this.values, 23) >> 5); + long s10 = 0x1FFFFF & (threeBytesToLong(this.values, 26) >> 2); + long s11 = 0x1FFFFF & (fourBytesToLong(this.values, 28) >> 7); + long s12 = 0x1FFFFF & (fourBytesToLong(this.values, 31) >> 4); + long s13 = 0x1FFFFF & (threeBytesToLong(this.values, 34) >> 1); + long s14 = 0x1FFFFF & (fourBytesToLong(this.values, 36) >> 6); + long s15 = 0x1FFFFF & (threeBytesToLong(this.values, 39) >> 3); + long s16 = 0x1FFFFF & threeBytesToLong(this.values, 42); + long s17 = 0x1FFFFF & (fourBytesToLong(this.values, 44) >> 5); + final long s18 = 0x1FFFFF & (threeBytesToLong(this.values, 47) >> 2); + final long s19 = 0x1FFFFF & (fourBytesToLong(this.values, 49) >> 7); + final long s20 = 0x1FFFFF & (fourBytesToLong(this.values, 52) >> 4); + final long s21 = 0x1FFFFF & (threeBytesToLong(this.values, 55) >> 1); + final long s22 = 0x1FFFFF & (fourBytesToLong(this.values, 57) >> 6); + final long s23 = (fourBytesToLong(this.values, 60) >> 3); + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + long carry10; + long carry11; + final long carry12; + final long carry13; + final long carry14; + final long carry15; + final long carry16; + + /** + * Lots of magic numbers :) + * To understand what's going on below, note that + * + * (1) q = 2^252 + q0 where q0 = 27742317777372353535851937790883648493. + * (2) s11 is the coefficient of 2^(11*21), s23 is the coefficient of 2^(^23*21) and 2^252 = 2^((23-11) * 21)). + * (3) 2^252 congruent -q0 modulo q. + * (4) -q0 = 666643 * 2^0 + 470296 * 2^21 + 654183 * 2^(2*21) - 997805 * 2^(3*21) + 136657 * 2^(4*21) - 683901 * 2^(5*21) + * + * Thus + * s23 * 2^(23*11) = s23 * 2^(12*21) * 2^(11*21) = s3 * 2^252 * 2^(11*21) congruent + * s23 * (666643 * 2^0 + 470296 * 2^21 + 654183 * 2^(2*21) - 997805 * 2^(3*21) + 136657 * 2^(4*21) - 683901 * 2^(5*21)) * 2^(11*21) modulo q = + * s23 * (666643 * 2^(11*21) + 470296 * 2^(12*21) + 654183 * 2^(13*21) - 997805 * 2^(14*21) + 136657 * 2^(15*21) - 683901 * 2^(16*21)). + * + * The same procedure is then applied for s22,...,s18. + */ + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + /** + * Time to reduce the coefficient in order not to get an overflow. + */ + 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; + + /** + * Continue with above procedure. + */ + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + + /** + * Reduce coefficients again. + */ + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + // s0, ..., s11 got 21 bits each. + final byte[] result = new byte[32]; + result[0] = (byte)(s0); + result[1] = (byte)(s0 >> 8); + result[2] = (byte)((s0 >> 16) | (s1 << 5)); + result[3] = (byte)(s1 >> 3); + result[4] = (byte)(s1 >> 11); + result[5] = (byte)((s1 >> 19) | (s2 << 2)); + result[6] = (byte)(s2 >> 6); + result[7] = (byte)((s2 >> 14) | (s3 << 7)); + result[8] = (byte)(s3 >> 1); + result[9] = (byte)(s3 >> 9); + result[10] = (byte)((s3 >> 17) | (s4 << 4)); + result[11] = (byte)(s4 >> 4); + result[12] = (byte)(s4 >> 12); + result[13] = (byte)((s4 >> 20) | (s5 << 1)); + result[14] = (byte)(s5 >> 7); + result[15] = (byte)((s5 >> 15) | (s6 << 6)); + result[16] = (byte)(s6 >> 2); + result[17] = (byte)(s6 >> 10); + result[18] = (byte)((s6 >> 18) | (s7 << 3)); + result[19] = (byte)(s7 >> 5); + result[20] = (byte)(s7 >> 13); + result[21] = (byte)(s8); + result[22] = (byte)(s8 >> 8); + result[23] = (byte)((s8 >> 16) | (s9 << 5)); + result[24] = (byte)(s9 >> 3); + result[25] = (byte)(s9 >> 11); + result[26] = (byte)((s9 >> 19) | (s10 << 2)); + result[27] = (byte)(s10 >> 6); + result[28] = (byte)((s10 >> 14) | (s11 << 7)); + result[29] = (byte)(s11 >> 1); + result[30] = (byte)(s11 >> 9); + result[31] = (byte)(s11 >> 17); + + return new Ed25519EncodedFieldElement(result); + } + + /** + * Multiplies this encoded field element with another and adds a third. + * The result is reduced modulo the group order. + *
+ * See the comments in the method modQ() for an explanation of the algorithm. + * + * @param b The encoded field element which is multiplied with this. + * @param c The third encoded field element which is added. + * @return The encoded field element (32 bytes). + */ + public Ed25519EncodedFieldElement multiplyAndAddModQ(final Ed25519EncodedFieldElement b, final Ed25519EncodedFieldElement c) { + final long a0 = 0x1FFFFF & threeBytesToLong(this.values, 0); + final long a1 = 0x1FFFFF & (fourBytesToLong(this.values, 2) >> 5); + final long a2 = 0x1FFFFF & (threeBytesToLong(this.values, 5) >> 2); + final long a3 = 0x1FFFFF & (fourBytesToLong(this.values, 7) >> 7); + final long a4 = 0x1FFFFF & (fourBytesToLong(this.values, 10) >> 4); + final long a5 = 0x1FFFFF & (threeBytesToLong(this.values, 13) >> 1); + final long a6 = 0x1FFFFF & (fourBytesToLong(this.values, 15) >> 6); + final long a7 = 0x1FFFFF & (threeBytesToLong(this.values, 18) >> 3); + final long a8 = 0x1FFFFF & threeBytesToLong(this.values, 21); + final long a9 = 0x1FFFFF & (fourBytesToLong(this.values, 23) >> 5); + final long a10 = 0x1FFFFF & (threeBytesToLong(this.values, 26) >> 2); + final long a11 = (fourBytesToLong(this.values, 28) >> 7); + final long b0 = 0x1FFFFF & threeBytesToLong(b.values, 0); + final long b1 = 0x1FFFFF & (fourBytesToLong(b.values, 2) >> 5); + final long b2 = 0x1FFFFF & (threeBytesToLong(b.values, 5) >> 2); + final long b3 = 0x1FFFFF & (fourBytesToLong(b.values, 7) >> 7); + final long b4 = 0x1FFFFF & (fourBytesToLong(b.values, 10) >> 4); + final long b5 = 0x1FFFFF & (threeBytesToLong(b.values, 13) >> 1); + final long b6 = 0x1FFFFF & (fourBytesToLong(b.values, 15) >> 6); + final long b7 = 0x1FFFFF & (threeBytesToLong(b.values, 18) >> 3); + final long b8 = 0x1FFFFF & threeBytesToLong(b.values, 21); + final long b9 = 0x1FFFFF & (fourBytesToLong(b.values, 23) >> 5); + final long b10 = 0x1FFFFF & (threeBytesToLong(b.values, 26) >> 2); + final long b11 = (fourBytesToLong(b.values, 28) >> 7); + final long c0 = 0x1FFFFF & threeBytesToLong(c.values, 0); + final long c1 = 0x1FFFFF & (fourBytesToLong(c.values, 2) >> 5); + final long c2 = 0x1FFFFF & (threeBytesToLong(c.values, 5) >> 2); + final long c3 = 0x1FFFFF & (fourBytesToLong(c.values, 7) >> 7); + final long c4 = 0x1FFFFF & (fourBytesToLong(c.values, 10) >> 4); + final long c5 = 0x1FFFFF & (threeBytesToLong(c.values, 13) >> 1); + final long c6 = 0x1FFFFF & (fourBytesToLong(c.values, 15) >> 6); + final long c7 = 0x1FFFFF & (threeBytesToLong(c.values, 18) >> 3); + final long c8 = 0x1FFFFF & threeBytesToLong(c.values, 21); + final long c9 = 0x1FFFFF & (fourBytesToLong(c.values, 23) >> 5); + final long c10 = 0x1FFFFF & (threeBytesToLong(c.values, 26) >> 2); + final long c11 = (fourBytesToLong(c.values, 28) >> 7); + long s0; + long s1; + long s2; + long s3; + long s4; + long s5; + long s6; + long s7; + long s8; + long s9; + long s10; + long s11; + long s12; + long s13; + long s14; + long s15; + long s16; + long s17; + long s18; + long s19; + long s20; + long s21; + long s22; + long s23; + long carry0; + long carry1; + long carry2; + long carry3; + long carry4; + long carry5; + long carry6; + long carry7; + long carry8; + long carry9; + long carry10; + long carry11; + long carry12; + long carry13; + long carry14; + long carry15; + long carry16; + final long carry17; + final long carry18; + final long carry19; + final long carry20; + final long carry21; + final long carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + 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; + + 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 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + + 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 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + 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 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + + 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; + + final byte[] result = new byte[32]; + result[0] = (byte)(s0); + result[1] = (byte)(s0 >> 8); + result[2] = (byte)((s0 >> 16) | (s1 << 5)); + result[3] = (byte)(s1 >> 3); + result[4] = (byte)(s1 >> 11); + result[5] = (byte)((s1 >> 19) | (s2 << 2)); + result[6] = (byte)(s2 >> 6); + result[7] = (byte)((s2 >> 14) | (s3 << 7)); + result[8] = (byte)(s3 >> 1); + result[9] = (byte)(s3 >> 9); + result[10] = (byte)((s3 >> 17) | (s4 << 4)); + result[11] = (byte)(s4 >> 4); + result[12] = (byte)(s4 >> 12); + result[13] = (byte)((s4 >> 20) | (s5 << 1)); + result[14] = (byte)(s5 >> 7); + result[15] = (byte)((s5 >> 15) | (s6 << 6)); + result[16] = (byte)(s6 >> 2); + result[17] = (byte)(s6 >> 10); + result[18] = (byte)((s6 >> 18) | (s7 << 3)); + result[19] = (byte)(s7 >> 5); + result[20] = (byte)(s7 >> 13); + result[21] = (byte)(s8); + result[22] = (byte)(s8 >> 8); + result[23] = (byte)((s8 >> 16) | (s9 << 5)); + result[24] = (byte)(s9 >> 3); + result[25] = (byte)(s9 >> 11); + result[26] = (byte)((s9 >> 19) | (s10 << 2)); + result[27] = (byte)(s10 >> 6); + result[28] = (byte)((s10 >> 14) | (s11 << 7)); + result[29] = (byte)(s11 >> 1); + result[30] = (byte)(s11 >> 9); + result[31] = (byte)(s11 >> 17); + + return new Ed25519EncodedFieldElement(result); + } + + private static long threeBytesToLong(final byte[] in, int offset) { + int result = in[offset++] & 0xff; + result |= (in[offset++] & 0xff) << 8; + result |= (in[offset] & 0xff) << 16; + return result; + } + + private static long fourBytesToLong(final byte[] in, int offset) { + int result = in[offset++] & 0xff; + result |= (in[offset++] & 0xff) << 8; + result |= (in[offset++] & 0xff) << 16; + result |= in[offset] << 24; + return ((long)result) & 0xffffffffL; + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.values); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Ed25519EncodedFieldElement)) { + return false; + } + + final Ed25519EncodedFieldElement encoded = (Ed25519EncodedFieldElement)obj; + return 1 == ArrayUtils.isEqualConstantTime(this.values, encoded.values); + } + + @Override + public String toString() { + return HexEncoder.getString(this.values); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519EncodedGroupElement.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519EncodedGroupElement.java new file mode 100755 index 0000000..b8cb4ec --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519EncodedGroupElement.java @@ -0,0 +1,129 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +import org.nem.core.utils.ArrayUtils; + +import java.util.Arrays; + +public class Ed25519EncodedGroupElement { + + private final byte[] values; + + /** + * Creates a new encoded group element. + * + * @param values The values. + */ + public Ed25519EncodedGroupElement(final byte[] values) { + if (32 != values.length) { + throw new IllegalArgumentException("Invalid encoded group element."); + } + + this.values = values; + } + + /** + * Gets the underlying byte array. + * + * @return The byte array. + */ + public byte[] getRaw() { + return this.values; + } + + /** + * Decodes this encoded group element and returns a new group element in P3 coordinates. + * + * @return The group element. + */ + public Ed25519GroupElement decode() { + final Ed25519FieldElement x = this.getAffineX(); + final Ed25519FieldElement y = this.getAffineY(); + return Ed25519GroupElement.p3(x, y, Ed25519Field.ONE, x.multiply(y)); + } + + /** + * Gets the affine x-coordinate. + * x is recovered in the following way (p = field size): + *
+ * x = sign(x) * sqrt((y^2 - 1) / (d * y^2 + 1)) = sign(x) * sqrt(u / v) with u = y^2 - 1 and v = d * y^2 + 1. + * Setting β = (u * v^3) * (u * v^7)^((p - 5) / 8) one has β^2 = +-(u / v). + * If v * β = -u multiply β with i=sqrt(-1). + * Set x := β. + * If sign(x) != bit 255 of s then negate x. + * + * @return the affine x-coordinate. + */ + public Ed25519FieldElement getAffineX() { + Ed25519FieldElement x; + final Ed25519FieldElement y; + final Ed25519FieldElement ySquare; + final Ed25519FieldElement u; + final Ed25519FieldElement v; + final Ed25519FieldElement vxSquare; + Ed25519FieldElement checkForZero; + y = this.getAffineY(); + ySquare = y.square(); + + // u = y^2 - 1 + u = ySquare.subtract(Ed25519Field.ONE); + + // v = d * y^2 + 1 + v = ySquare.multiply(Ed25519Field.D).add(Ed25519Field.ONE); + + // x = sqrt(u / v) + x = Ed25519FieldElement.sqrt(u, v); + + vxSquare = x.square().multiply(v); + checkForZero = vxSquare.subtract(u); + if (checkForZero.isNonZero()) { + checkForZero = vxSquare.add(u); + if (checkForZero.isNonZero()) { + throw new IllegalArgumentException("not a valid Ed25519EncodedGroupElement."); + } + + x = x.multiply(Ed25519Field.I); + } + + if ((x.isNegative() ? 1 : 0) != ArrayUtils.getBit(this.values, 255)) { + x = x.negate(); + } + + return x; + } + + /** + * Gets the affine y-coordinate. + * + * @return the affine y-coordinate. + */ + public Ed25519FieldElement getAffineY() { + // The affine y-coordinate is in bits 0 to 254. + // Since the decode() method of Ed25519EncodedFieldElement ignores bit 255, + // we can use that method without problems. + final Ed25519EncodedFieldElement encoded = new Ed25519EncodedFieldElement(this.values); + return encoded.decode(); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.values); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Ed25519EncodedGroupElement)) { + return false; + } + + final Ed25519EncodedGroupElement encoded = (Ed25519EncodedGroupElement)obj; + return 1 == ArrayUtils.isEqualConstantTime(this.values, encoded.values); + } + + @Override + public String toString() { + return String.format( + "x=%s\ny=%s\n", + this.getAffineX().toString(), + this.getAffineY().toString()); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519Field.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519Field.java new file mode 100755 index 0000000..12ac16c --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519Field.java @@ -0,0 +1,43 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +import org.nem.core.utils.*; + +import java.math.BigInteger; + +/** + * Represents the underlying finite field for Ed25519. + * The field has p = 2^255 - 19 elements. + */ +public class Ed25519Field { + + /** + * P: 2^255 - 19 + */ + public static final BigInteger P = new BigInteger(HexEncoder.getBytes("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed")); + public static final Ed25519FieldElement ZERO = getFieldElement(0); + public static final Ed25519FieldElement ONE = getFieldElement(1); + public static final Ed25519FieldElement TWO = getFieldElement(2); + public static final Ed25519FieldElement D = getD(); + public static final Ed25519FieldElement D_Times_TWO = D.multiply(TWO); + public static final byte[] ZERO_SHORT = new byte[32]; + public static final byte[] ZERO_LONG = new byte[64]; + + /** + * I ^ 2 = -1 + */ + public static final Ed25519FieldElement I = new Ed25519EncodedFieldElement(HexEncoder.getBytes( + "b0a00e4a271beec478e42fad0618432fa7d7fb3d99004d2b0bdfc14f8024832b")).decode(); + + private static Ed25519FieldElement getFieldElement(final int value) { + final int[] f = new int[10]; + f[0] = value; + return new Ed25519FieldElement(f); + } + + private static Ed25519FieldElement getD() { + final BigInteger d = new BigInteger("-121665") + .multiply(new BigInteger("121666").modInverse(Ed25519Field.P)) + .mod(Ed25519Field.P); + return new Ed25519EncodedFieldElement(ArrayUtils.toByteArray(d, 32)).decode(); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519FieldElement.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519FieldElement.java new file mode 100755 index 0000000..b611c81 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519FieldElement.java @@ -0,0 +1,1026 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +import java.util.Arrays; + +/** + * Represents a element of the finite field with p=2^255-19 elements. + *

+ * values[0] ... values[9], represent the integer
+ * values[0] + 2^26 * values[1] + 2^51 * values[2] + 2^77 * values[3] + 2^102 * values[4] + ... + 2^230 * values[9].
+ * Bounds on each values[i] vary depending on context. + *

+ * This implementation is based on the ref10 implementation of SUPERCOP. + */ +public class Ed25519FieldElement { + private final int[] values; + + /** + * Creates a field element. + * + * @param values The 2^25.5 bit representation of the field element. + */ + public Ed25519FieldElement(final int[] values) { + if (values.length != 10) { + throw new IllegalArgumentException("Invalid 2^25.5 bit representation."); + } + + this.values = values; + } + + /** + * Gets the underlying int array. + * + * @return The int array. + */ + public int[] getRaw() { + return this.values; + } + + /** + * Gets a value indicating whether or not the field element is non-zero. + * + * @return 1 if it is non-zero, 0 otherwise. + */ + public boolean isNonZero() { + return this.encode().isNonZero(); + } + + /** + * Adds the given field element to this and returns the result. + * h = this + g + *
+	 * Preconditions:
+	 *     |this| 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.
+	 * 
+ * + * @param g The field element to add. + * @return The field element this + val. + */ + public Ed25519FieldElement add(final Ed25519FieldElement g) { + final int[] gValues = g.values; + final int[] h = new int[10]; + for (int i = 0; i < 10; i++) { + h[i] = this.values[i] + gValues[i]; + } + + return new Ed25519FieldElement(h); + } + + /** + * Subtract the given field element from this and returns the result. + * h = this - g + *
+	 * Preconditions:
+	 *     |this| 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.
+	 * 
+ * + * @param g The field element to subtract. + * @return The field element this - val. + */ + public Ed25519FieldElement subtract(final Ed25519FieldElement g) { + final int[] gValues = g.values; + final int[] h = new int[10]; + for (int i = 0; i < 10; i++) { + h[i] = this.values[i] - gValues[i]; + } + + return new Ed25519FieldElement(h); + } + + /** + * Negates this field element and return the result. + * h = -this + *
+	 * Preconditions:
+	 *     |this| 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^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+	 * 
+ * + * @return The field element (-1) * this. + */ + public Ed25519FieldElement negate() { + final int[] h = new int[10]; + for (int i = 0; i < 10; i++) { + h[i] = -this.values[i]; + } + + return new Ed25519FieldElement(h); + } + + /** + * Multiplies this field element with the given field element and returns the result. + * h = this * g + * Preconditions: + *
+	 *     |this| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+	 *        |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+	 * Postconditions:
+	 *        |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+	 * 
+ * Notes on implementation strategy: + *
+ * Using schoolbook multiplication. Karatsuba would save a little in some + * cost models. + *
+ * Most multiplications by 2 and 19 are 32-bit precomputations; cheaper than + * 64-bit postcomputations. + *
+ * There is one remaining multiplication by 19 in the carry chain; one *19 + * precomputation can be merged into this, but the resulting data flow is + * considerably less clean. + *
+ * There are 12 carries below. 10 of them are 2-way parallelizable and + * vectorizable. Can get away with 11 carries, but then data flow is much + * deeper. + *
+ * With tighter constraints on inputs can squeeze carries into int32. + * + * @param g The field element to multiply. + * @return The (reasonably reduced) field element this * val. + */ + public Ed25519FieldElement multiply(final Ed25519FieldElement g) { + final int[] gValues = g.values; + final int f0 = this.values[0]; + final int f1 = this.values[1]; + final int f2 = this.values[2]; + final int f3 = this.values[3]; + final int f4 = this.values[4]; + final int f5 = this.values[5]; + final int f6 = this.values[6]; + final int f7 = this.values[7]; + final int f8 = this.values[8]; + final int f9 = this.values[9]; + final int g0 = gValues[0]; + final int g1 = gValues[1]; + final int g2 = gValues[2]; + final int g3 = gValues[3]; + final int g4 = gValues[4]; + final int g5 = gValues[5]; + final int g6 = gValues[6]; + final int g7 = gValues[7]; + final int g8 = gValues[8]; + final int g9 = gValues[9]; + final int g1_19 = 19 * g1; /* 1.959375*2^29 */ + final int g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + final int g3_19 = 19 * g3; + final int g4_19 = 19 * g4; + final int g5_19 = 19 * g5; + final int g6_19 = 19 * g6; + final int g7_19 = 19 * g7; + final int g8_19 = 19 * g8; + final int g9_19 = 19 * g9; + final int f1_2 = 2 * f1; + final int f3_2 = 2 * f3; + final int f5_2 = 2 * f5; + final int f7_2 = 2 * f7; + final int f9_2 = 2 * f9; + final long f0g0 = f0 * (long)g0; + final long f0g1 = f0 * (long)g1; + final long f0g2 = f0 * (long)g2; + final long f0g3 = f0 * (long)g3; + final long f0g4 = f0 * (long)g4; + final long f0g5 = f0 * (long)g5; + final long f0g6 = f0 * (long)g6; + final long f0g7 = f0 * (long)g7; + final long f0g8 = f0 * (long)g8; + final long f0g9 = f0 * (long)g9; + final long f1g0 = f1 * (long)g0; + final long f1g1_2 = f1_2 * (long)g1; + final long f1g2 = f1 * (long)g2; + final long f1g3_2 = f1_2 * (long)g3; + final long f1g4 = f1 * (long)g4; + final long f1g5_2 = f1_2 * (long)g5; + final long f1g6 = f1 * (long)g6; + final long f1g7_2 = f1_2 * (long)g7; + final long f1g8 = f1 * (long)g8; + final long f1g9_38 = f1_2 * (long)g9_19; + final long f2g0 = f2 * (long)g0; + final long f2g1 = f2 * (long)g1; + final long f2g2 = f2 * (long)g2; + final long f2g3 = f2 * (long)g3; + final long f2g4 = f2 * (long)g4; + final long f2g5 = f2 * (long)g5; + final long f2g6 = f2 * (long)g6; + final long f2g7 = f2 * (long)g7; + final long f2g8_19 = f2 * (long)g8_19; + final long f2g9_19 = f2 * (long)g9_19; + final long f3g0 = f3 * (long)g0; + final long f3g1_2 = f3_2 * (long)g1; + final long f3g2 = f3 * (long)g2; + final long f3g3_2 = f3_2 * (long)g3; + final long f3g4 = f3 * (long)g4; + final long f3g5_2 = f3_2 * (long)g5; + final long f3g6 = f3 * (long)g6; + final long f3g7_38 = f3_2 * (long)g7_19; + final long f3g8_19 = f3 * (long)g8_19; + final long f3g9_38 = f3_2 * (long)g9_19; + final long f4g0 = f4 * (long)g0; + final long f4g1 = f4 * (long)g1; + final long f4g2 = f4 * (long)g2; + final long f4g3 = f4 * (long)g3; + final long f4g4 = f4 * (long)g4; + final long f4g5 = f4 * (long)g5; + final long f4g6_19 = f4 * (long)g6_19; + final long f4g7_19 = f4 * (long)g7_19; + final long f4g8_19 = f4 * (long)g8_19; + final long f4g9_19 = f4 * (long)g9_19; + final long f5g0 = f5 * (long)g0; + final long f5g1_2 = f5_2 * (long)g1; + final long f5g2 = f5 * (long)g2; + final long f5g3_2 = f5_2 * (long)g3; + final long f5g4 = f5 * (long)g4; + final long f5g5_38 = f5_2 * (long)g5_19; + final long f5g6_19 = f5 * (long)g6_19; + final long f5g7_38 = f5_2 * (long)g7_19; + final long f5g8_19 = f5 * (long)g8_19; + final long f5g9_38 = f5_2 * (long)g9_19; + final long f6g0 = f6 * (long)g0; + final long f6g1 = f6 * (long)g1; + final long f6g2 = f6 * (long)g2; + final long f6g3 = f6 * (long)g3; + final long f6g4_19 = f6 * (long)g4_19; + final long f6g5_19 = f6 * (long)g5_19; + final long f6g6_19 = f6 * (long)g6_19; + final long f6g7_19 = f6 * (long)g7_19; + final long f6g8_19 = f6 * (long)g8_19; + final long f6g9_19 = f6 * (long)g9_19; + final long f7g0 = f7 * (long)g0; + final long f7g1_2 = f7_2 * (long)g1; + final long f7g2 = f7 * (long)g2; + final long f7g3_38 = f7_2 * (long)g3_19; + final long f7g4_19 = f7 * (long)g4_19; + final long f7g5_38 = f7_2 * (long)g5_19; + final long f7g6_19 = f7 * (long)g6_19; + final long f7g7_38 = f7_2 * (long)g7_19; + final long f7g8_19 = f7 * (long)g8_19; + final long f7g9_38 = f7_2 * (long)g9_19; + final long f8g0 = f8 * (long)g0; + final long f8g1 = f8 * (long)g1; + final long f8g2_19 = f8 * (long)g2_19; + final long f8g3_19 = f8 * (long)g3_19; + final long f8g4_19 = f8 * (long)g4_19; + final long f8g5_19 = f8 * (long)g5_19; + final long f8g6_19 = f8 * (long)g6_19; + final long f8g7_19 = f8 * (long)g7_19; + final long f8g8_19 = f8 * (long)g8_19; + final long f8g9_19 = f8 * (long)g9_19; + final long f9g0 = f9 * (long)g0; + final long f9g1_38 = f9_2 * (long)g1_19; + final long f9g2_19 = f9 * (long)g2_19; + final long f9g3_38 = f9_2 * (long)g3_19; + final long f9g4_19 = f9 * (long)g4_19; + final long f9g5_38 = f9_2 * (long)g5_19; + final long f9g6_19 = f9 * (long)g6_19; + final long f9g7_38 = f9_2 * (long)g7_19; + final long f9g8_19 = f9 * (long)g8_19; + final long f9g9_38 = f9_2 * (long)g9_19; + + /** + * Remember: 2^255 congruent 19 modulo p. + * h = h0 * 2^0 + h1 * 2^26 + h2 * 2^(26+25) + h3 * 2^(26+25+26) + ... + h9 * 2^(5*26+5*25). + * So to get the real number we would have to multiply the coefficients with the corresponding powers of 2. + * To get an idea what is going on below, look at the calculation of h0: + * h0 is the coefficient to the power 2^0 so it collects (sums) all products that have the power 2^0. + * f0 * g0 really is f0 * 2^0 * g0 * 2^0 = (f0 * g0) * 2^0. + * f1 * g9 really is f1 * 2^26 * g9 * 2^230 = f1 * g9 * 2^256 = 2 * f1 * g9 * 2^255 congruent 2 * 19 * f1 * g9 * 2^0 modulo p. + * f2 * g8 really is f2 * 2^51 * g8 * 2^204 = f2 * g8 * 2^255 congruent 19 * f2 * g8 * 2^0 modulo p. + * and so on... + */ + long h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + long h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19; + long h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38; + long h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19; + long h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38; + long h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19; + long h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38; + long h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19; + long h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38; + long h9 = f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0; + long carry0; + final long carry1; + final long carry2; + final long carry3; + long carry4; + final long carry5; + final long carry6; + final long carry7; + final long carry8; + final long carry9; + + /** + * |h0| <= (1.65*1.65*2^52*(1+19+19+19+19)+1.65*1.65*2^50*(38+38+38+38+38)) + * i.e. |h0| <= 1.4*2^60; narrower ranges for h2, h4, h6, h8 + * |h1| <= (1.65*1.65*2^51*(1+1+19+19+19+19+19+19+19+19)) + * i.e. |h1| <= 1.7*2^59; narrower ranges for h3, h5, h7, h9 + */ + + carry0 = (h0 + (long)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (long)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + /* |h0| <= 2^25 */ + /* |h4| <= 2^25 */ + /* |h1| <= 1.71*2^59 */ + /* |h5| <= 1.71*2^59 */ + + carry1 = (h1 + (long)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (long)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + /* |h1| <= 2^24; from now on fits into int32 */ + /* |h5| <= 2^24; from now on fits into int32 */ + /* |h2| <= 1.41*2^60 */ + /* |h6| <= 1.41*2^60 */ + + carry2 = (h2 + (long)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (long)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + /* |h2| <= 2^25; from now on fits into int32 unchanged */ + /* |h6| <= 2^25; from now on fits into int32 unchanged */ + /* |h3| <= 1.71*2^59 */ + /* |h7| <= 1.71*2^59 */ + + carry3 = (h3 + (long)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (long)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + /* |h3| <= 2^24; from now on fits into int32 unchanged */ + /* |h7| <= 2^24; from now on fits into int32 unchanged */ + /* |h4| <= 1.72*2^34 */ + /* |h8| <= 1.41*2^60 */ + + carry4 = (h4 + (long)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (long)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + /* |h4| <= 2^25; from now on fits into int32 unchanged */ + /* |h8| <= 2^25; from now on fits into int32 unchanged */ + /* |h5| <= 1.01*2^24 */ + /* |h9| <= 1.71*2^59 */ + + carry9 = (h9 + (long)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + /* |h9| <= 2^24; from now on fits into int32 unchanged */ + /* |h0| <= 1.1*2^39 */ + + carry0 = (h0 + (long)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + /* |h0| <= 2^25; from now on fits into int32 unchanged */ + /* |h1| <= 1.01*2^24 */ + + final int[] h = new int[10]; + h[0] = (int)h0; + h[1] = (int)h1; + h[2] = (int)h2; + h[3] = (int)h3; + h[4] = (int)h4; + h[5] = (int)h5; + h[6] = (int)h6; + h[7] = (int)h7; + h[8] = (int)h8; + h[9] = (int)h9; + + return new Ed25519FieldElement(h); + } + + /** + * Squares this field element and returns the result. + * h = this * this + *
+	 * Preconditions:
+	 *     |this| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+	 * Postconditions:
+	 *        |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+	 * 
+ * See multiply for discussion of implementation strategy. + * + * @return The square of this field element. + */ + public Ed25519FieldElement square() { + return this.squareAndOptionalDouble(false); + } + + /** + * Squares this field element, multiplies by two and returns the result. + * h = 2 * this * this + *
+	 * Preconditions:
+	 *     |this| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+	 * Postconditions:
+	 *        |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+	 * 
+ * See multiply for discussion of implementation strategy. + * + * @return The square of this field element times 2. + */ + public Ed25519FieldElement squareAndDouble() { + return this.squareAndOptionalDouble(true); + } + + /** + * Squares this field element, optionally multiplies by two and returns the result. + * h = 2 * this * this if dbl is true or + * h = this * this if dbl is false. + *
+	 * Preconditions:
+	 *     |this| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+	 * Postconditions:
+	 *        |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+	 * 
+ * See multiply for discussion of implementation strategy. + * + * @return The square of this field element times 2. + */ + private Ed25519FieldElement squareAndOptionalDouble(final boolean dbl) { + final int f0 = this.values[0]; + final int f1 = this.values[1]; + final int f2 = this.values[2]; + final int f3 = this.values[3]; + final int f4 = this.values[4]; + final int f5 = this.values[5]; + final int f6 = this.values[6]; + final int f7 = this.values[7]; + final int f8 = this.values[8]; + final int f9 = this.values[9]; + final int f0_2 = 2 * f0; + final int f1_2 = 2 * f1; + final int f2_2 = 2 * f2; + final int f3_2 = 2 * f3; + final int f4_2 = 2 * f4; + final int f5_2 = 2 * f5; + final int f6_2 = 2 * f6; + final int f7_2 = 2 * f7; + final int f5_38 = 38 * f5; /* 1.959375*2^30 */ + final int f6_19 = 19 * f6; /* 1.959375*2^30 */ + final int f7_38 = 38 * f7; /* 1.959375*2^30 */ + final int f8_19 = 19 * f8; /* 1.959375*2^30 */ + final int f9_38 = 38 * f9; /* 1.959375*2^30 */ + final long f0f0 = f0 * (long)f0; + final long f0f1_2 = f0_2 * (long)f1; + final long f0f2_2 = f0_2 * (long)f2; + final long f0f3_2 = f0_2 * (long)f3; + final long f0f4_2 = f0_2 * (long)f4; + final long f0f5_2 = f0_2 * (long)f5; + final long f0f6_2 = f0_2 * (long)f6; + final long f0f7_2 = f0_2 * (long)f7; + final long f0f8_2 = f0_2 * (long)f8; + final long f0f9_2 = f0_2 * (long)f9; + final long f1f1_2 = f1_2 * (long)f1; + final long f1f2_2 = f1_2 * (long)f2; + final long f1f3_4 = f1_2 * (long)f3_2; + final long f1f4_2 = f1_2 * (long)f4; + final long f1f5_4 = f1_2 * (long)f5_2; + final long f1f6_2 = f1_2 * (long)f6; + final long f1f7_4 = f1_2 * (long)f7_2; + final long f1f8_2 = f1_2 * (long)f8; + final long f1f9_76 = f1_2 * (long)f9_38; + final long f2f2 = f2 * (long)f2; + final long f2f3_2 = f2_2 * (long)f3; + final long f2f4_2 = f2_2 * (long)f4; + final long f2f5_2 = f2_2 * (long)f5; + final long f2f6_2 = f2_2 * (long)f6; + final long f2f7_2 = f2_2 * (long)f7; + final long f2f8_38 = f2_2 * (long)f8_19; + final long f2f9_38 = f2 * (long)f9_38; + final long f3f3_2 = f3_2 * (long)f3; + final long f3f4_2 = f3_2 * (long)f4; + final long f3f5_4 = f3_2 * (long)f5_2; + final long f3f6_2 = f3_2 * (long)f6; + final long f3f7_76 = f3_2 * (long)f7_38; + final long f3f8_38 = f3_2 * (long)f8_19; + final long f3f9_76 = f3_2 * (long)f9_38; + final long f4f4 = f4 * (long)f4; + final long f4f5_2 = f4_2 * (long)f5; + final long f4f6_38 = f4_2 * (long)f6_19; + final long f4f7_38 = f4 * (long)f7_38; + final long f4f8_38 = f4_2 * (long)f8_19; + final long f4f9_38 = f4 * (long)f9_38; + final long f5f5_38 = f5 * (long)f5_38; + final long f5f6_38 = f5_2 * (long)f6_19; + final long f5f7_76 = f5_2 * (long)f7_38; + final long f5f8_38 = f5_2 * (long)f8_19; + final long f5f9_76 = f5_2 * (long)f9_38; + final long f6f6_19 = f6 * (long)f6_19; + final long f6f7_38 = f6 * (long)f7_38; + final long f6f8_38 = f6_2 * (long)f8_19; + final long f6f9_38 = f6 * (long)f9_38; + final long f7f7_38 = f7 * (long)f7_38; + final long f7f8_38 = f7_2 * (long)f8_19; + final long f7f9_76 = f7_2 * (long)f9_38; + final long f8f8_19 = f8 * (long)f8_19; + final long f8f9_38 = f8 * (long)f9_38; + final long f9f9_38 = f9 * (long)f9_38; + long h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + long h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + long h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + long h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + long h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + long h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + long h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + long h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + long h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + long h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + long carry0; + final long carry1; + final long carry2; + final long carry3; + long carry4; + final long carry5; + final long carry6; + final long carry7; + final long carry8; + final long carry9; + + if (dbl) { + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + } + + carry0 = (h0 + (long)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (long)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + + carry1 = (h1 + (long)(1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (long)(1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + + carry2 = (h2 + (long)(1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (long)(1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + + carry3 = (h3 + (long)(1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (long)(1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry4 = (h4 + (long)(1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (long)(1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + carry9 = (h9 + (long)(1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + + carry0 = (h0 + (long)(1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + + final int[] h = new int[10]; + h[0] = (int)h0; + h[1] = (int)h1; + h[2] = (int)h2; + h[3] = (int)h3; + h[4] = (int)h4; + h[5] = (int)h5; + h[6] = (int)h6; + h[7] = (int)h7; + h[8] = (int)h8; + h[9] = (int)h9; + return new Ed25519FieldElement(h); + } + + /** + * Invert this field element and return the result. + * The inverse is found via Fermat's little theorem: + * a^p congruent a mod p and therefore a^(p-2) congruent a^-1 mod p + * + * @return The inverse of this field element. + */ + public Ed25519FieldElement invert() { + Ed25519FieldElement f0, f1; + + // comments describe how exponent is created + + // 2 == 2 * 1 + f0 = this.square(); + + // 9 == 9 + f1 = this.pow2to9(); + + // 11 == 9 + 2 + f0 = f0.multiply(f1); + + // 2^252 - 2^2 + f1 = this.pow2to252sub4(); + + // 2^255 - 2^5 + for (int i = 1; i < 4; ++i) { + f1 = f1.square(); + } + + // 2^255 - 21 + return f1.multiply(f0); + } + + /** + * Computes this field element to the power of (2^9) and returns the result. + * + * @return This field element to the power of (2^9). + */ + private Ed25519FieldElement pow2to9() { + Ed25519FieldElement f; + + // 2 == 2 * 1 + f = this.square(); + + // 4 == 2 * 2 + f = f.square(); + + // 8 == 2 * 4 + f = f.square(); + + // 9 == 1 + 8 + return this.multiply(f); + } + + /** + * Computes this field element to the power of (2^252 - 4) and returns the result. + * This is a helper function for calculating the square root. + * + * @return This field element to the power of (2^252 - 4). + */ + private Ed25519FieldElement pow2to252sub4() { + Ed25519FieldElement f0, f1, f2; + + // 2 == 2 * 1 + f0 = this.square(); + + // 9 + f1 = this.pow2to9(); + + // 11 == 9 + 2 + f0 = f0.multiply(f1); + + // 22 == 2 * 11 + f0 = f0.square(); + + // 31 == 22 + 9 + f0 = f1.multiply(f0); + + // 2^6 - 2^1 + f1 = f0.square(); + + // 2^10 - 2^5 + for (int i = 1; i < 5; ++i) { + f1 = f1.square(); + } + + // 2^10 - 2^0 + f0 = f1.multiply(f0); + + // 2^11 - 2^1 + f1 = f0.square(); + + // 2^20 - 2^10 + for (int i = 1; i < 10; ++i) { + f1 = f1.square(); + } + + // 2^20 - 2^0 + f1 = f1.multiply(f0); + + // 2^21 - 2^1 + f2 = f1.square(); + + // 2^40 - 2^20 + for (int i = 1; i < 20; ++i) { + f2 = f2.square(); + } + + // 2^40 - 2^0 + f1 = f2.multiply(f1); + + // 2^41 - 2^1 + f1 = f1.square(); + + // 2^50 - 2^10 + for (int i = 1; i < 10; ++i) { + f1 = f1.square(); + } + + // 2^50 - 2^0 + f0 = f1.multiply(f0); + + // 2^51 - 2^1 + f1 = f0.square(); + + // 2^100 - 2^50 + for (int i = 1; i < 50; ++i) { + f1 = f1.square(); + } + + // 2^100 - 2^0 + f1 = f1.multiply(f0); + + // 2^101 - 2^1 + f2 = f1.square(); + + // 2^200 - 2^100 + for (int i = 1; i < 100; ++i) { + f2 = f2.square(); + } + + // 2^200 - 2^0 + f1 = f2.multiply(f1); + + // 2^201 - 2^1 + f1 = f1.square(); + + // 2^250 - 2^50 + for (int i = 1; i < 50; ++i) { + f1 = f1.square(); + } + + // 2^250 - 2^0 + f0 = f1.multiply(f0); + + // 2^251 - 2^1 + f0 = f0.square(); + + // 2^252 - 2^2 + return f0.square(); + } + + /** + * Calculates and returns one of the square roots of u / v. + *
{@code
+	 * x = (u * v^3) * (u * v^7)^((p - 5) / 8) ==> x^2 = +-(u / v).
+	 * }
+ * Note that this means x can be sqrt(u / v), -sqrt(u / v), +i * sqrt(u / v), -i * sqrt(u / v). + * + * @param u The nominator of the fraction. + * @param v The denominator of the fraction. + * @return The square root of u / v. + */ + public static Ed25519FieldElement sqrt(final Ed25519FieldElement u, final Ed25519FieldElement v) { + Ed25519FieldElement x; + final Ed25519FieldElement v3; + + // v3 = v^3 + v3 = v.square().multiply(v); + + // x = (v3^2) * v * u = u * v^7 + x = v3.square().multiply(v).multiply(u); + + // x = (u * v^7)^((q - 5) / 8) + x = x.pow2to252sub4().multiply(x); // 2^252 - 3 + + // x = u * v^3 * (u * v^7)^((q - 5) / 8) + x = v3.multiply(u).multiply(x); + + return x; + } + + /** + * Reduce this field element modulo field size p = 2^255 - 19 and return the result. + * The idea for the modulo p reduction algorithm is as follows: + *
+	 * {@code
+	 * Assumption:
+	 * p = 2^255 - 19
+	 * h = h0 + 2^25 * h1 + 2^(26+25) * h2 + ... + 2^230 * h9 where 0 <= |hi| < 2^27 for all i=0,...,9.
+	 * h congruent r modulo p, i.e. h = r + q * p for some suitable 0 <= r < p and an integer q.
+	 * 
+ * Then q = [2^-255 * (h + 19 * 2^-25 * h9 + 1/2)] where [x] = floor(x). + *
+ * Proof: + * We begin with some very raw estimation for the bounds of some expressions: + * |h| < 2^230 * 2^30 = 2^260 ==> |r + q * p| < 2^260 ==> |q| < 2^10. + * ==> -1/4 <= a := 19^2 * 2^-255 * q < 1/4. + * |h - 2^230 * h9| = |h0 + ... + 2^204 * h8| < 2^204 * 2^30 = 2^234. + * ==> -1/4 <= b := 19 * 2^-255 * (h - 2^230 * h9) < 1/4 + * Therefore 0 < 1/2 - a - b < 1. + * Set x := r + 19 * 2^-255 * r + 1/2 - a - b then + * 0 <= x < 255 - 20 + 19 + 1 = 2^255 ==> 0 <= 2^-255 * x < 1. Since q is an integer we have + * [q + 2^-255 * x] = q (1) + * Have a closer look at x: + * x = h - q * (2^255 - 19) + 19 * 2^-255 * (h - q * (2^255 - 19)) + 1/2 - 19^2 * 2^-255 * q - 19 * 2^-255 * (h - 2^230 * h9) + * = h - q * 2^255 + 19 * q + 19 * 2^-255 * h - 19 * q + 19^2 * 2^-255 * q + 1/2 - 19^2 * 2^-255 * q - 19 * 2^-255 * h + 19 * 2^-25 * h9 + * = h + 19 * 2^-25 * h9 + 1/2 - q^255. + * Inserting the expression for x into (1) we get the desired expression for q. + * } + *
+ * + * @return The mod p reduced field element; + */ + private Ed25519FieldElement modP() { + int h0 = this.values[0]; + int h1 = this.values[1]; + int h2 = this.values[2]; + int h3 = this.values[3]; + int h4 = this.values[4]; + int h5 = this.values[5]; + int h6 = this.values[6]; + int h7 = this.values[7]; + int h8 = this.values[8]; + int h9 = this.values[9]; + int q; + final int carry0; + final int carry1; + final int carry2; + final int carry3; + final int carry4; + final int carry5; + final int carry6; + final int carry7; + final int carry8; + final int carry9; + + // Calculate q + q = (19 * h9 + (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; + + // r = h - q * p = h - 2^255 * q + 19 * q + // First add 19 * q then discard the bit 255 + h0 += 19 * q; + + 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; + + final int[] h = new int[10]; + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; + + return new Ed25519FieldElement(h); + } + + /** + * Encodes a given field element in its 32 byte 2^8 bit representation. This is done in two steps. + * Step 1: Reduce the value of the field element modulo p. + * Step 2: Convert the field element to the 32 byte representation. + * + * @return Encoded field element (32 bytes). + */ + public Ed25519EncodedFieldElement encode() { + // Step 1: + final Ed25519FieldElement g = this.modP(); + final int[] gValues = g.getRaw(); + final int h0 = gValues[0]; + final int h1 = gValues[1]; + final int h2 = gValues[2]; + final int h3 = gValues[3]; + final int h4 = gValues[4]; + final int h5 = gValues[5]; + final int h6 = gValues[6]; + final int h7 = gValues[7]; + final int h8 = gValues[8]; + final int h9 = gValues[9]; + + // Step 2: + final byte[] s = new byte[32]; + s[0] = (byte)(h0); + s[1] = (byte)(h0 >> 8); + s[2] = (byte)(h0 >> 16); + s[3] = (byte)((h0 >> 24) | (h1 << 2)); + s[4] = (byte)(h1 >> 6); + s[5] = (byte)(h1 >> 14); + s[6] = (byte)((h1 >> 22) | (h2 << 3)); + s[7] = (byte)(h2 >> 5); + s[8] = (byte)(h2 >> 13); + s[9] = (byte)((h2 >> 21) | (h3 << 5)); + s[10] = (byte)(h3 >> 3); + s[11] = (byte)(h3 >> 11); + s[12] = (byte)((h3 >> 19) | (h4 << 6)); + s[13] = (byte)(h4 >> 2); + s[14] = (byte)(h4 >> 10); + s[15] = (byte)(h4 >> 18); + s[16] = (byte)(h5); + s[17] = (byte)(h5 >> 8); + s[18] = (byte)(h5 >> 16); + s[19] = (byte)((h5 >> 24) | (h6 << 1)); + s[20] = (byte)(h6 >> 7); + s[21] = (byte)(h6 >> 15); + s[22] = (byte)((h6 >> 23) | (h7 << 3)); + s[23] = (byte)(h7 >> 5); + s[24] = (byte)(h7 >> 13); + s[25] = (byte)((h7 >> 21) | (h8 << 4)); + s[26] = (byte)(h8 >> 4); + s[27] = (byte)(h8 >> 12); + s[28] = (byte)((h8 >> 20) | (h9 << 6)); + s[29] = (byte)(h9 >> 2); + s[30] = (byte)(h9 >> 10); + s[31] = (byte)(h9 >> 18); + + return new Ed25519EncodedFieldElement(s); + } + + /** + * Return true if this is in {1,3,5,...,q-2} + * Return false if this is in {0,2,4,...,q-1} + *
+	 * Preconditions:
+	 *     |x| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+	 * 
+ * + * @return true if this is in {1,3,5,...,q-2}, false otherwise. + */ + public boolean isNegative() { + return this.encode().isNegative(); + } + + @Override + public int hashCode() { + return Arrays.hashCode(this.values); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Ed25519FieldElement)) { + return false; + } + + final Ed25519FieldElement f = (Ed25519FieldElement)obj; + return this.encode().equals(f.encode()); + } + + @Override + public String toString() { + return this.encode().toString(); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519Group.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519Group.java new file mode 100755 index 0000000..ca222e0 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519Group.java @@ -0,0 +1,36 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +import org.nem.core.utils.HexEncoder; + +import java.math.BigInteger; + +/** + * Represents the underlying group for Ed25519. + */ +public class Ed25519Group { + + /** + * 2^252 - 27742317777372353535851937790883648493 + */ + public static final BigInteger GROUP_ORDER = BigInteger.ONE.shiftLeft(252).add(new BigInteger("27742317777372353535851937790883648493")); + + /** + *
{@code
+	 * (x, 4/5); x > 0
+	 * }
+ */ + public static final Ed25519GroupElement BASE_POINT = getBasePoint(); + + // different representations of zero + public static final Ed25519GroupElement ZERO_P3 = Ed25519GroupElement.p3(Ed25519Field.ZERO, Ed25519Field.ONE, Ed25519Field.ONE, Ed25519Field.ZERO); + public static final Ed25519GroupElement ZERO_P2 = Ed25519GroupElement.p2(Ed25519Field.ZERO, Ed25519Field.ONE, Ed25519Field.ONE); + public static final Ed25519GroupElement ZERO_PRECOMPUTED = Ed25519GroupElement.precomputed(Ed25519Field.ONE, Ed25519Field.ONE, Ed25519Field.ZERO); + + private static Ed25519GroupElement getBasePoint() { + final byte[] rawEncodedGroupElement = HexEncoder.getBytes("5866666666666666666666666666666666666666666666666666666666666666"); + final Ed25519GroupElement basePoint = new Ed25519EncodedGroupElement(rawEncodedGroupElement).decode(); + basePoint.precomputeForScalarMultiplication(); + basePoint.precomputeForDoubleScalarMultiplication(); + return basePoint; + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519GroupElement.java b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519GroupElement.java new file mode 100755 index 0000000..19a7d58 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/crypto/ed25519/arithmetic/Ed25519GroupElement.java @@ -0,0 +1,1012 @@ +package org.nem.core.crypto.ed25519.arithmetic; + +import how.monero.hodl.crypto.Scalar; +import how.monero.hodl.jni.CryptoOpsUtil; +import org.nem.core.utils.ByteUtils; + +import java.io.Serializable; +import java.util.*; + +/** + * A point on the ED25519 curve which represents a group element. + * This implementation is based on the ref10 implementation of SUPERCOP. + *
+ * Literature: + * [1] Daniel J. Bernstein, Niels Duif, Tanja Lange, Peter Schwabe and Bo-Yin Yang : High-speed high-security signatures + * [2] Huseyin Hisil, Kenneth Koon-Ho Wong, Gary Carter, Ed Dawson: Twisted Edwards Curves Revisited + * [3] Daniel J. Bernsteina, Tanja Lange: A complete set of addition laws for incomplete Edwards curves + * [4] Daniel J. Bernstein, Peter Birkner, Marc Joye, Tanja Lange and Christiane Peters: Twisted Edwards Curves + * [5] Christiane Pascale Peters: Curves, Codes, and Cryptography (PhD thesis) + * [6] Daniel J. Bernstein, Peter Birkner, Tanja Lange and Christiane Peters: Optimizing double-base elliptic-curve single-scalar multiplication + */ +public class Ed25519GroupElement implements Serializable { + + private final CoordinateSystem coordinateSystem; + @SuppressWarnings("NonConstantFieldWithUpperCaseName") + private final Ed25519FieldElement X; + @SuppressWarnings("NonConstantFieldWithUpperCaseName") + private final Ed25519FieldElement Y; + @SuppressWarnings("NonConstantFieldWithUpperCaseName") + private final Ed25519FieldElement Z; + @SuppressWarnings("NonConstantFieldWithUpperCaseName") + private final Ed25519FieldElement T; + + /** + * Precomputed table for a single scalar multiplication. + */ + private Ed25519GroupElement[][] precomputedForSingle; + + /** + * Precomputed table for a double scalar multiplication + */ + private Ed25519GroupElement[] precomputedForDouble; + + //region constructors + + /** + * Creates a new group element using the AFFINE coordinate system. + * + * @param x The x coordinate. + * @param y The y coordinate. + * @param Z The Z coordinate. + * @return The group element using the P2 coordinate system. + */ + public static Ed25519GroupElement affine( + final Ed25519FieldElement x, + final Ed25519FieldElement y, + final Ed25519FieldElement Z) { + return new Ed25519GroupElement(CoordinateSystem.AFFINE, x, y, Z, null); + } + + /** + * Creates a new group element using the P2 coordinate system. + * + * @param X The X coordinate. + * @param Y The Y coordinate. + * @param Z The Z coordinate. + * @return The group element using the P2 coordinate system. + */ + public static Ed25519GroupElement p2( + final Ed25519FieldElement X, + final Ed25519FieldElement Y, + final Ed25519FieldElement Z) { + return new Ed25519GroupElement(CoordinateSystem.P2, X, Y, Z, null); + } + + /** + * Creates a new group element using the P3 coordinate system. + * + * @param X The X coordinate. + * @param Y The Y coordinate. + * @param Z The Z coordinate. + * @param T The T coordinate. + * @return The group element using the P3 coordinate system. + */ + public static Ed25519GroupElement p3( + final Ed25519FieldElement X, + final Ed25519FieldElement Y, + final Ed25519FieldElement Z, + final Ed25519FieldElement T) { + return new Ed25519GroupElement(CoordinateSystem.P3, X, Y, Z, T); + } + + /** + * Creates a new group element using the P1xP1 coordinate system. + * + * @param X The X coordinate. + * @param Y The Y coordinate. + * @param Z The Z coordinate. + * @param T The T coordinate. + * @return The group element using the P1xP1 coordinate system. + */ + public static Ed25519GroupElement p1xp1( + final Ed25519FieldElement X, + final Ed25519FieldElement Y, + final Ed25519FieldElement Z, + final Ed25519FieldElement T) { + return new Ed25519GroupElement(CoordinateSystem.P1xP1, X, Y, Z, T); + } + + /** + * Creates a new group element using the PRECOMPUTED coordinate system. + * + * @param yPlusx The y + x value. + * @param yMinusx The y - x value. + * @param xy2d The 2 * d * x * y value. + * @return The group element using the PRECOMPUTED coordinate system. + */ + public static Ed25519GroupElement precomputed( + final Ed25519FieldElement yPlusx, + final Ed25519FieldElement yMinusx, + final Ed25519FieldElement xy2d) { + //noinspection SuspiciousNameCombination + return new Ed25519GroupElement(CoordinateSystem.PRECOMPUTED, yPlusx, yMinusx, xy2d, null); + } + + /** + * Creates a new group element using the CACHED coordinate system. + * + * @param YPlusX The Y + X value. + * @param YMinusX The Y - X value. + * @param Z The Z coordinate. + * @param T2d The 2 * d * T value. + * @return The group element using the CACHED coordinate system. + */ + public static Ed25519GroupElement cached( + final Ed25519FieldElement YPlusX, + final Ed25519FieldElement YMinusX, + final Ed25519FieldElement Z, + final Ed25519FieldElement T2d) { + return new Ed25519GroupElement(CoordinateSystem.CACHED, YPlusX, YMinusX, Z, T2d); + } + + /** + * Creates a group element for a curve. + * + * @param coordinateSystem The coordinate system used for the group element. + * @param X The X coordinate. + * @param Y The Y coordinate. + * @param Z The Z coordinate. + * @param T The T coordinate. + */ + public Ed25519GroupElement( + final CoordinateSystem coordinateSystem, + final Ed25519FieldElement X, + final Ed25519FieldElement Y, + final Ed25519FieldElement Z, + final Ed25519FieldElement T) { + this.coordinateSystem = coordinateSystem; + this.X = X; + this.Y = Y; + this.Z = Z; + this.T = T; + } + + //endregion + + //region accessors + + /** + * Gets the coordinate system for the group element. + * + * @return The coordinate system. + */ + public CoordinateSystem getCoordinateSystem() { + return this.coordinateSystem; + } + + /** + * Gets the X value of the group element. + * This is for most coordinate systems the projective X coordinate. + * + * @return The X value. + */ + public Ed25519FieldElement getX() { + return this.X; + } + + /** + * Gets the Y value of the group element. + * This is for most coordinate systems the projective Y coordinate. + * + * @return The Y value. + */ + public Ed25519FieldElement getY() { + return this.Y; + } + + /** + * Gets the Z value of the group element. + * This is for most coordinate systems the projective Z coordinate. + * + * @return The Z value. + */ + public Ed25519FieldElement getZ() { + return this.Z; + } + + /** + * Gets the T value of the group element. + * This is for most coordinate systems the projective T coordinate. + * + * @return The T value. + */ + public Ed25519FieldElement getT() { + return this.T; + } + + /** + * Gets a value indicating whether or not the group element has a + * precomputed table for double scalar multiplication. + * + * @return true if it has the table, false otherwise. + */ + public boolean isPrecomputedForDoubleScalarMultiplication() { + return null != this.precomputedForDouble; + } + + /** + * Gets the table with the precomputed group elements for single scalar multiplication. + * + * @return The precomputed table. + */ + public Ed25519GroupElement[][] getPrecomputedForSingle() { + return this.precomputedForSingle; + } + + /** + * Gets the table with the precomputed group elements for double scalar multiplication. + * + * @return The precomputed table. + */ + public Ed25519GroupElement[] getPrecomputedForDouble() { + return this.precomputedForDouble; + } + + //endregion + + /** + * Converts the group element to an encoded point on the curve. + * + * @return The encoded point as byte array. + */ + public Ed25519EncodedGroupElement encode() { + switch (this.coordinateSystem) { + case P2: + case P3: + final Ed25519FieldElement inverse = this.Z.invert(); + final Ed25519FieldElement x = this.X.multiply(inverse); + final Ed25519FieldElement y = this.Y.multiply(inverse); + final byte[] s = y.encode().getRaw(); + s[s.length - 1] |= (x.isNegative() ? (byte)0x80 : 0); + + return new Ed25519EncodedGroupElement(s); + default: + return this.toP2().encode(); + } + } + + /** + * Converts the group element to the P2 coordinate system. + * + * @return The group element in the P2 coordinate system. + */ + public Ed25519GroupElement toP2() { + return this.toCoordinateSystem(CoordinateSystem.P2); + } + + /** + * Converts the group element to the P3 coordinate system. + * + * @return The group element in the P3 coordinate system. + */ + public Ed25519GroupElement toP3() { + return this.toCoordinateSystem(CoordinateSystem.P3); + } + + /** + * Converts the group element to the CACHED coordinate system. + * + * @return The group element in the CACHED coordinate system. + */ + public Ed25519GroupElement toCached() { + return this.toCoordinateSystem(CoordinateSystem.CACHED); + } + + /** + * Convert a Ed25519GroupElement from one coordinate system to another. + *
+ * Supported conversions: + * - P3 -> P2 + * - P3 -> CACHED (1 multiply, 1 add, 1 subtract) + * - P1xP1 -> P2 (3 multiply) + * - P1xP1 -> P3 (4 multiply) + * + * @param newCoordinateSystem The coordinate system to convert to. + * @return A new group element in the new coordinate system. + */ + private Ed25519GroupElement toCoordinateSystem(final CoordinateSystem newCoordinateSystem) { + switch (this.coordinateSystem) { + case P2: + switch (newCoordinateSystem) { + case P2: + return p2(this.X, this.Y, this.Z); + default: + throw new IllegalArgumentException(); + } + case P3: + switch (newCoordinateSystem) { + case P2: + return p2(this.X, this.Y, this.Z); + case P3: + return p3(this.X, this.Y, this.Z, this.T); + case CACHED: + return cached(this.Y.add(this.X), this.Y.subtract(this.X), this.Z, this.T.multiply(Ed25519Field.D_Times_TWO)); + default: + throw new IllegalArgumentException(); + } + case P1xP1: + switch (newCoordinateSystem) { + case P2: + return p2(this.X.multiply(this.T), this.Y.multiply(this.Z), this.Z.multiply(this.T)); + case P3: + return p3(this.X.multiply(this.T), this.Y.multiply(this.Z), this.Z.multiply(this.T), this.X.multiply(this.Y)); + case P1xP1: + return p1xp1(this.X, this.Y, this.Z, this.T); + default: + throw new IllegalArgumentException(); + } + case PRECOMPUTED: + switch (newCoordinateSystem) { + case PRECOMPUTED: + //noinspection SuspiciousNameCombination + return precomputed(this.X, this.Y, this.Z); + default: + throw new IllegalArgumentException(); + } + case CACHED: + switch (newCoordinateSystem) { + case CACHED: + return cached(this.X, this.Y, this.Z, this.T); + default: + throw new IllegalArgumentException(); + } + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Precomputes the group elements needed to speed up a scalar multiplication. + */ + public void precomputeForScalarMultiplication() { + if (null != this.precomputedForSingle) { + return; + } + + Ed25519GroupElement Bi = this; + this.precomputedForSingle = new Ed25519GroupElement[32][8]; + + for (int i = 0; i < 32; i++) { + Ed25519GroupElement Bij = Bi; + for (int j = 0; j < 8; j++) { + final Ed25519FieldElement inverse = Bij.Z.invert(); + final Ed25519FieldElement x = Bij.X.multiply(inverse); + final Ed25519FieldElement y = Bij.Y.multiply(inverse); + this.precomputedForSingle[i][j] = precomputed(y.add(x), y.subtract(x), x.multiply(y).multiply(Ed25519Field.D_Times_TWO)); + Bij = Bij.add(Bi.toCached()).toP3(); + } + // Only every second summand is precomputed (16^2 = 256). + for (int k = 0; k < 8; k++) { + Bi = Bi.add(Bi.toCached()).toP3(); + } + } + } + + /** + * Precomputes the group elements used to speed up a double scalar multiplication. + */ + public void precomputeForDoubleScalarMultiplication() { + if (null != this.precomputedForDouble) { + return; + } + Ed25519GroupElement Bi = this; + this.precomputedForDouble = new Ed25519GroupElement[8]; + for (int i = 0; i < 8; i++) { + final Ed25519FieldElement inverse = Bi.Z.invert(); + final Ed25519FieldElement x = Bi.X.multiply(inverse); + final Ed25519FieldElement y = Bi.Y.multiply(inverse); + this.precomputedForDouble[i] = precomputed(y.add(x), y.subtract(x), x.multiply(y).multiply(Ed25519Field.D_Times_TWO)); + Bi = this.add(this.add(Bi.toCached()).toP3().toCached()).toP3(); + } + } + + /** + * Doubles a given group element p in P^2 or P^3 coordinate system and returns the result in P x P coordinate system. + * r = 2 * p where p = (X : Y : Z) or p = (X : Y : Z : T) + *
+ * r in P x P coordinate system: + *
+ * r = ((X' : Z'), (Y' : T')) where + * X' = (X + Y)^2 - (Y^2 + X^2) + * Y' = Y^2 + X^2 + * Z' = y^2 - X^2 + * T' = 2 * Z^2 - (y^2 - X^2) + *
+ * r converted from P x P to P^2 coordinate system: + *
+ * r = (X'' : Y'' : Z'') where + * X'' = X' * T' = ((X + Y)^2 - Y^2 - X^2) * (2 * Z^2 - (y^2 - X^2)) + * Y'' = Y' * Z' = (Y^2 + X^2) * (y^2 - X^2) + * Z'' = Z' * T' = (y^2 - X^2) * (2 * Z^2 - (y^2 - X^2)) + *
+ * Formula for the P^2 coordinate system is in agreement with the formula given in [4] page 12 (with a = -1) + * (up to a common factor -1 which does not matter): + *
+ * B = (X + Y)^2; C = X^2; D = Y^2; E = -C = -X^2; F := E + D = Y^2 - X^2; H = Z^2; J = F − 2 * H; + * X3 = (B − C − D) · J = X' * (-T'); + * Y3 = F · (E − D) = Z' * (-Y'); + * Z3 = F · J = Z' * (-T'). + * + * @return The doubled group element in the P x P coordinate system. + */ + public Ed25519GroupElement dbl() { + switch (this.coordinateSystem) { + case P2: + case P3: + final Ed25519FieldElement XSquare; + final Ed25519FieldElement YSquare; + final Ed25519FieldElement B; + final Ed25519FieldElement A; + final Ed25519FieldElement ASquare; + final Ed25519FieldElement YSquarePlusXSquare; + final Ed25519FieldElement YSquareMinusXSquare; + XSquare = this.X.square(); + YSquare = this.Y.square(); + B = this.Z.squareAndDouble(); + A = this.X.add(this.Y); + ASquare = A.square(); + YSquarePlusXSquare = YSquare.add(XSquare); + YSquareMinusXSquare = YSquare.subtract(XSquare); + return p1xp1(ASquare.subtract(YSquarePlusXSquare), YSquarePlusXSquare, YSquareMinusXSquare, B.subtract(YSquareMinusXSquare)); + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Ed25519GroupElement addition using the twisted Edwards addition law for extended coordinates. + * this must be given in P^3 coordinate system and g in PRECOMPUTED coordinate system. + * r = this + g where this = (X1 : Y1 : Z1 : T1), g = (g.X, g.Y, g.Z) = (Y2/Z2 + X2/Z2, Y2/Z2 - X2/Z2, 2 * d * X2/Z2 * Y2/Z2) + *
+ * r in P x P coordinate system: + *
+ * r = ((X' : Z'), (Y' : T')) where + * X' = (Y1 + X1) * g.X - (Y1 - X1) * q.Y = ((Y1 + X1) * (Y2 + X2) - (Y1 - X1) * (Y2 - X2)) * 1/Z2 + * Y' = (Y1 + X1) * g.X + (Y1 - X1) * q.Y = ((Y1 + X1) * (Y2 + X2) + (Y1 - X1) * (Y2 - X2)) * 1/Z2 + * Z' = 2 * Z1 + T1 * g.Z = 2 * Z1 + T1 * 2 * d * X2 * Y2 * 1/Z2^2 = (2 * Z1 * Z2 + 2 * d * T1 * T2) * 1/Z2 + * T' = 2 * Z1 - T1 * g.Z = 2 * Z1 - T1 * 2 * d * X2 * Y2 * 1/Z2^2 = (2 * Z1 * Z2 - 2 * d * T1 * T2) * 1/Z2 + *
+ * Formula for the P x P coordinate system is in agreement with the formula given in + * file ge25519.c method add_p1p1() in ref implementation. + * Setting A = (Y1 - X1) * (Y2 - X2), B = (Y1 + X1) * (Y2 + X2), C = 2 * d * T1 * T2, D = 2 * Z1 * Z2 we get + * X' = (B - A) * 1/Z2 + * Y' = (B + A) * 1/Z2 + * Z' = (D + C) * 1/Z2 + * T' = (D - C) * 1/Z2 + *
+ * r converted from P x P to P^2 coordinate system: + *
+ * r = (X'' : Y'' : Z'' : T'') where + * X'' = X' * T' = (B - A) * (D - C) * 1/Z2^2 + * Y'' = Y' * Z' = (B + A) * (D + C) * 1/Z2^2 + * Z'' = Z' * T' = (D + C) * (D - C) * 1/Z2^2 + * T'' = X' * Y' = (B - A) * (B + A) * 1/Z2^2 + *
+ * Formula above for the P^2 coordinate system is in agreement with the formula given in [2] page 6 + * (the common factor 1/Z2^2 does not matter) + * E = B - A, F = D - C, G = D + C, H = B + A + * X3 = E * F = (B - A) * (D - C); + * Y3 = G * H = (D + C) * (B + A); + * Z3 = F * G = (D - C) * (D + C); + * T3 = E * H = (B - A) * (B + A); + * + * @param g The group element to add. + * @return The resulting group element in the P x P coordinate system. + */ + private Ed25519GroupElement precomputedAdd(final Ed25519GroupElement g) { + if (this.coordinateSystem != CoordinateSystem.P3) { + throw new UnsupportedOperationException(); + } + if (g.coordinateSystem != CoordinateSystem.PRECOMPUTED) { + throw new IllegalArgumentException(); + } + + final Ed25519FieldElement YPlusX; + final Ed25519FieldElement YMinusX; + final Ed25519FieldElement A; + final Ed25519FieldElement B; + final Ed25519FieldElement C; + final Ed25519FieldElement D; + YPlusX = this.Y.add(this.X); + YMinusX = this.Y.subtract(this.X); + A = YPlusX.multiply(g.X); + B = YMinusX.multiply(g.Y); + C = g.Z.multiply(this.T); + D = this.Z.add(this.Z); + + return p1xp1(A.subtract(B), A.add(B), D.add(C), D.subtract(C)); + } + + /** + * Ed25519GroupElement subtraction using the twisted Edwards addition law for extended coordinates. + * this must be given in P^3 coordinate system and g in PRECOMPUTED coordinate system. + * r = this - g where this = (X1 : Y1 : Z1 : T1), g = (g.X, g.Y, g.Z) = (Y2/Z2 + X2/Z2, Y2/Z2 - X2/Z2, 2 * d * X2/Z2 * Y2/Z2) + *
+ * Negating g means negating the value of X2 and T2 (the latter is irrelevant here). + * The formula is in accordance to the above addition. + * + * @param g he group element to subtract. + * @return The result in the P x P coordinate system. + */ + private Ed25519GroupElement precomputedSubtract(final Ed25519GroupElement g) { + if (this.coordinateSystem != CoordinateSystem.P3) { + throw new UnsupportedOperationException(); + } + if (g.coordinateSystem != CoordinateSystem.PRECOMPUTED) { + throw new IllegalArgumentException(); + } + + final Ed25519FieldElement YPlusX; + final Ed25519FieldElement YMinusX; + final Ed25519FieldElement A; + final Ed25519FieldElement B; + final Ed25519FieldElement C; + final Ed25519FieldElement D; + YPlusX = this.Y.add(this.X); + YMinusX = this.Y.subtract(this.X); + A = YPlusX.multiply(g.Y); + B = YMinusX.multiply(g.X); + C = g.Z.multiply(this.T); + D = this.Z.add(this.Z); + + return p1xp1(A.subtract(B), A.add(B), D.subtract(C), D.add(C)); + } + + /** + * Ed25519GroupElement addition using the twisted Edwards addition law for extended coordinates. + * this must be given in P^3 coordinate system and g in CACHED coordinate system. + * r = this + g where this = (X1 : Y1 : Z1 : T1), g = (g.X, g.Y, g.Z, g.T) = (Y2 + X2, Y2 - X2, Z2, 2 * d * T2) + *
+ * r in P x P coordinate system.: + * X' = (Y1 + X1) * (Y2 + X2) - (Y1 - X1) * (Y2 - X2) + * Y' = (Y1 + X1) * (Y2 + X2) + (Y1 - X1) * (Y2 - X2) + * Z' = 2 * Z1 * Z2 + 2 * d * T1 * T2 + * T' = 2 * Z1 * T2 - 2 * d * T1 * T2 + *
+ * Setting A = (Y1 - X1) * (Y2 - X2), B = (Y1 + X1) * (Y2 + X2), C = 2 * d * T1 * T2, D = 2 * Z1 * Z2 we get + * X' = (B - A) + * Y' = (B + A) + * Z' = (D + C) + * T' = (D - C) + *
+ * Same result as in precomputedAdd() (up to a common factor which does not matter). + * + * @param g The group element to add. + * @return The result in the P x P coordinate system. + */ + public Ed25519GroupElement add(final Ed25519GroupElement g) { + if (this.coordinateSystem != CoordinateSystem.P3) { + throw new UnsupportedOperationException(); + } + if (g.coordinateSystem != CoordinateSystem.CACHED) { + throw new IllegalArgumentException(); + } + + final Ed25519FieldElement YPlusX; + final Ed25519FieldElement YMinusX; + final Ed25519FieldElement ZSquare; + final Ed25519FieldElement A; + final Ed25519FieldElement B; + final Ed25519FieldElement C; + final Ed25519FieldElement D; + YPlusX = this.Y.add(this.X); + YMinusX = this.Y.subtract(this.X); + A = YPlusX.multiply(g.X); + B = YMinusX.multiply(g.Y); + C = g.T.multiply(this.T); + ZSquare = this.Z.multiply(g.Z); + D = ZSquare.add(ZSquare); + + return p1xp1(A.subtract(B), A.add(B), D.add(C), D.subtract(C)); + } + + /** + * Ed25519GroupElement subtraction using the twisted Edwards addition law for extended coordinates. + *
+ * Negating g means negating the value of the coordinate X2 and T2. + * The formula is in accordance to the above addition. + * + * @param g The group element to subtract. + * @return The result in the P x P coordinate system. + */ + public Ed25519GroupElement subtract(final Ed25519GroupElement g) { + if (this.coordinateSystem != CoordinateSystem.P3) { + throw new UnsupportedOperationException(); + } + if (g.coordinateSystem != CoordinateSystem.CACHED) { + throw new IllegalArgumentException(); + } + + final Ed25519FieldElement YPlusX; + final Ed25519FieldElement YMinusX; + final Ed25519FieldElement ZSquare; + final Ed25519FieldElement A; + final Ed25519FieldElement B; + final Ed25519FieldElement C; + final Ed25519FieldElement D; + YPlusX = this.Y.add(this.X); + YMinusX = this.Y.subtract(this.X); + A = YPlusX.multiply(g.Y); + B = YMinusX.multiply(g.X); + C = g.T.multiply(this.T); + ZSquare = this.Z.multiply(g.Z); + D = ZSquare.add(ZSquare); + + return p1xp1(A.subtract(B), A.add(B), D.subtract(C), D.add(C)); + } + + /** + * Negates this group element by subtracting it from the neutral group element. + * (only used in MathUtils so it doesn't have to be fast) + * + * @return The negative of this group element. + */ + public Ed25519GroupElement negate() { + if (this.coordinateSystem != CoordinateSystem.P3) { + throw new UnsupportedOperationException(); + } + + return Ed25519Group.ZERO_P3.subtract(this.toCached()).toP3(); + } + + @Override + public int hashCode() { + return this.encode().hashCode(); + } + + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof Ed25519GroupElement)) { + return false; + } + Ed25519GroupElement ge = (Ed25519GroupElement)obj; + if (!this.coordinateSystem.equals(ge.coordinateSystem)) { + try { + ge = ge.toCoordinateSystem(this.coordinateSystem); + } catch (final Exception e) { + return false; + } + } + switch (this.coordinateSystem) { + case P2: + case P3: + if (this.Z.equals(ge.Z)) { + return this.X.equals(ge.X) && this.Y.equals(ge.Y); + } + + final Ed25519FieldElement x1 = this.X.multiply(ge.Z); + final Ed25519FieldElement y1 = this.Y.multiply(ge.Z); + final Ed25519FieldElement x2 = ge.X.multiply(this.Z); + final Ed25519FieldElement y2 = ge.Y.multiply(this.Z); + + return x1.equals(x2) && y1.equals(y2); + case P1xP1: + return this.toP2().equals(ge); + case PRECOMPUTED: + return this.X.equals(ge.X) && this.Y.equals(ge.Y) && this.Z.equals(ge.Z); + case CACHED: + if (this.Z.equals(ge.Z)) { + return this.X.equals(ge.X) && this.Y.equals(ge.Y) && this.T.equals(ge.T); + } + + final Ed25519FieldElement x3 = this.X.multiply(ge.Z); + final Ed25519FieldElement y3 = this.Y.multiply(ge.Z); + final Ed25519FieldElement t3 = this.T.multiply(ge.Z); + final Ed25519FieldElement x4 = ge.X.multiply(this.Z); + final Ed25519FieldElement y4 = ge.Y.multiply(this.Z); + final Ed25519FieldElement t4 = ge.T.multiply(this.Z); + + return x3.equals(x4) && y3.equals(y4) && t3.equals(t4); + default: + //return false; + throw new RuntimeException("Coordinate system problem"); + } + } + + /** + * Convert a to 2^16 bit representation. + * + * @param encoded The encode field element. + * @return 64 bytes, each between -8 and 7 + */ + private static byte[] toRadix16(final Ed25519EncodedFieldElement encoded) { + final byte[] a = encoded.getRaw(); + final byte[] e = new byte[64]; + int i; + for (i = 0; i < 32; i++) { + e[2 * i] = (byte)(a[i] & 15); + e[2 * i + 1] = (byte)((a[i] >> 4) & 15); + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + int carry = 0; + for (i = 0; i < 63; i++) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + e[63] += carry; + + return e; + } + + /** + * Constant-time conditional move. + * Replaces this with u if b == 1. + * Replaces this with this if b == 0. + * + * @param u The group element to return if b == 1. + * @param b in {0, 1} + * @return u if b == 1; this if b == 0; null otherwise. + */ + private Ed25519GroupElement cmov(final Ed25519GroupElement u, final int b) { + Ed25519GroupElement ret = null; + for (int i = 0; i < b; i++) { + // Only for b == 1 + ret = u; + } + for (int i = 0; i < 1 - b; i++) { + // Only for b == 0 + ret = this; + } + return ret; + } + + /** + * Look up 16^i r_i B in the precomputed table. + * No secret array indices, no secret branching. + * Constant time. + *
+ * Must have previously precomputed. + * + * @param pos = i/2 for i in {0, 2, 4,..., 62} + * @param b = r_i + * @return The Ed25519GroupElement + */ + private Ed25519GroupElement select(final int pos, final int b) { + // Is r_i negative? + final int bNegative = ByteUtils.isNegativeConstantTime(b); + // |r_i| + final int bAbs = b - (((-bNegative) & b) << 1); + + // 16^i |r_i| B + final Ed25519GroupElement t = Ed25519Group.ZERO_PRECOMPUTED + .cmov(this.precomputedForSingle[pos][0], ByteUtils.isEqualConstantTime(bAbs, 1)) + .cmov(this.precomputedForSingle[pos][1], ByteUtils.isEqualConstantTime(bAbs, 2)) + .cmov(this.precomputedForSingle[pos][2], ByteUtils.isEqualConstantTime(bAbs, 3)) + .cmov(this.precomputedForSingle[pos][3], ByteUtils.isEqualConstantTime(bAbs, 4)) + .cmov(this.precomputedForSingle[pos][4], ByteUtils.isEqualConstantTime(bAbs, 5)) + .cmov(this.precomputedForSingle[pos][5], ByteUtils.isEqualConstantTime(bAbs, 6)) + .cmov(this.precomputedForSingle[pos][6], ByteUtils.isEqualConstantTime(bAbs, 7)) + .cmov(this.precomputedForSingle[pos][7], ByteUtils.isEqualConstantTime(bAbs, 8)); + // -16^i |r_i| B + //noinspection SuspiciousNameCombination + final Ed25519GroupElement tMinus = precomputed(t.Y, t.X, t.Z.negate()); + // 16^i r_i B + return t.cmov(tMinus, bNegative); + } + + public static int precomps = 0; + public static int scalarMults = 0; + public static int scalarBaseMults = 0; + + public Ed25519GroupElement scalarMultiply(final Ed25519EncodedFieldElement a) { + return scalarMultiply(a, true); + } + /** + * h = a * B where a = a[0]+256*a[1]+...+256^31 a[31] and + * B is this point. If its lookup table has not been precomputed, it + * will be at the start of the method (and cached for later calls). + * Constant time. + * + * @param a The encoded field element. + * @return The resulting group element. + */ + public static String lineRecordingSourceFile = null; + public static boolean enableLineRecording = false; + private static boolean noNativeLibraryAvailable = false; + public static Map lineNumberCallFrequencyMap = new TreeMap<>((a,b)->a.compareTo(b)); + public Ed25519GroupElement scalarMultiply(final Ed25519EncodedFieldElement a, boolean useNativeImplementation) { + + if(enableLineRecording) { + Optional optionalCaller = Arrays.stream(new Exception().getStackTrace()).filter(e -> e.getFileName().equals(lineRecordingSourceFile)).findFirst(); + if (optionalCaller.isPresent()) { + StackTraceElement caller = optionalCaller.get(); + lineNumberCallFrequencyMap.putIfAbsent(caller.getLineNumber(), 0); + lineNumberCallFrequencyMap.computeIfPresent(caller.getLineNumber(), (key, oldValue) -> oldValue + 1); + } + } + + scalarMults++; + + if(this==Ed25519Group.BASE_POINT) scalarBaseMults++; + + try { + if(!noNativeLibraryAvailable && this==Ed25519Group.BASE_POINT) return new Ed25519EncodedGroupElement(CryptoOpsUtil.scalarMultBase(a.getRaw())).decode(); + } + catch (java.lang.UnsatisfiedLinkError e) { + System.err.println("WARNING: No C library available for native Ed25519"); + noNativeLibraryAvailable = true; + } + + + if(precomputedForSingle==null) { + + // there is only a performance advantage to using native code if the element has not been precomputed + if(useNativeImplementation && !noNativeLibraryAvailable) { + try { + return new Ed25519EncodedGroupElement(CryptoOpsUtil.scalarMult(this.encode().getRaw(), a.getRaw())).decode(); + } + catch (java.lang.UnsatisfiedLinkError e) { + System.err.println("WARNING: No C library available for native Ed25519"); + noNativeLibraryAvailable = true; + } + } + + precomps++; + precomputeForScalarMultiplication(); + } + + Ed25519GroupElement g; + int i; + final byte[] e = toRadix16(a); + Ed25519GroupElement h = Ed25519Group.ZERO_P3; + for (i = 1; i < 64; i += 2) { + g = this.select(i / 2, e[i]); + h = h.precomputedAdd(g).toP3(); + } + + h = h.dbl().toP2().dbl().toP2().dbl().toP2().dbl().toP3(); + + for (i = 0; i < 64; i += 2) { + g = this.select(i / 2, e[i]); + h = h.precomputedAdd(g).toP3(); + } + + return h; + } + + public Ed25519GroupElement scalarMultiply(final Ed25519FieldElement a) { + return scalarMultiply(a.encode()); + } + public Ed25519GroupElement scalarMultiply(final byte[] a) { + return scalarMultiply(new Ed25519EncodedFieldElement(a)); + } + public Ed25519GroupElement scalarMultiply(final Scalar a) { + return scalarMultiply(a, true); + } + public Ed25519GroupElement scalarMultiply(final Scalar a, boolean useNativeImplementation) { + return scalarMultiply(new Ed25519EncodedFieldElement(a.bytes), useNativeImplementation); + } + + /** + * Calculates a sliding-windows base 2 representation for a given encoded field element a. + * To learn more about it see [6] page 8. + *
+ * Output: r which satisfies + * a = r0 * 2^0 + r1 * 2^1 + ... + r255 * 2^255 with ri in {-15, -13, -11, -9, -7, -5, -3, -1, 0, 1, 3, 5, 7, 9, 11, 13, 15} + *
+ * Method is package private only so that tests run. + * + * @param encoded The encoded field element. + * @return The byte array r in the above described form. + */ + private static byte[] slide(final Ed25519EncodedFieldElement encoded) { + final byte[] a = encoded.getRaw(); + final byte[] r = new byte[256]; + + // Put each bit of 'a' into a separate byte, 0 or 1 + for (int i = 0; i < 256; ++i) { + r[i] = (byte)(1 & (a[i >> 3] >> (i & 7))); + } + + // Note: r[i] will always be odd. + for (int i = 0; i < 256; ++i) { + if (r[i] != 0) { + for (int b = 1; b <= 6 && i + b < 256; ++b) { + // Accumulate bits if possible + if (r[i + b] != 0) { + if (r[i] + (r[i + b] << b) <= 15) { + r[i] += r[i + b] << b; + r[i + b] = 0; + } else if (r[i] - (r[i + b] << b) >= -15) { + r[i] -= r[i + b] << b; + for (int k = i + b; k < 256; ++k) { + if (r[k] == 0) { + r[k] = 1; + break; + } + r[k] = 0; + } + } else { + break; + } + } + } + } + } + + return r; + } + + /** + * r = b * B - a * A where + * a and b are encoded field elements and + * B is this point. + * A must have been previously precomputed for double scalar multiplication. + * + * @param A in P3 coordinate system. + * @param a = The first encoded field element. + * @param b = The second encoded field element. + * @return The resulting group element. + */ + public Ed25519GroupElement doubleScalarMultiplyVariableTime( + final Ed25519GroupElement A, + final Ed25519EncodedFieldElement a, + final Ed25519EncodedFieldElement b) { + final byte[] aSlide = slide(a); + final byte[] bSlide = slide(b); + Ed25519GroupElement r = Ed25519Group.ZERO_P2; + + int i; + for (i = 255; i >= 0; --i) { + if (aSlide[i] != 0 || bSlide[i] != 0) { + break; + } + } + + for (; i >= 0; --i) { + Ed25519GroupElement t = r.dbl(); + + if (aSlide[i] > 0) { + t = t.toP3().precomputedSubtract(A.precomputedForDouble[aSlide[i] / 2]); + } else if (aSlide[i] < 0) { + t = t.toP3().precomputedAdd(A.precomputedForDouble[(-aSlide[i]) / 2]); + } + + if (bSlide[i] > 0) { + t = t.toP3().precomputedAdd(this.precomputedForDouble[bSlide[i] / 2]); + } else if (bSlide[i] < 0) { + t = t.toP3().precomputedSubtract(this.precomputedForDouble[(-bSlide[i]) / 2]); + } + + r = t.toP2(); + } + + return r; + } + + /** + * Verify that the group element satisfies the curve equation. + * + * @return true if the group element satisfies the curve equation, false otherwise. + */ + public boolean satisfiesCurveEquation() { + switch (this.coordinateSystem) { + case P2: + case P3: + final Ed25519FieldElement inverse = this.Z.invert(); + final Ed25519FieldElement x = this.X.multiply(inverse); + final Ed25519FieldElement y = this.Y.multiply(inverse); + final Ed25519FieldElement xSquare = x.square(); + final Ed25519FieldElement ySquare = y.square(); + final Ed25519FieldElement dXSquareYSquare = Ed25519Field.D.multiply(xSquare).multiply(ySquare); + return Ed25519Field.ONE.add(dXSquareYSquare).add(xSquare).equals(ySquare); + + default: + return this.toP2().satisfiesCurveEquation(); + } + } + + @Override + public String toString() { + return String.format( + "X=%s\nY=%s\nZ=%s\nT=%s\n", + this.X.toString(), + this.Y.toString(), + this.Z.toString(), + this.T.toString()); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/AbstractTwoLevelMap.java b/source-code/RuffCT-java/src/org/nem/core/utils/AbstractTwoLevelMap.java new file mode 100755 index 0000000..30fdfea --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/AbstractTwoLevelMap.java @@ -0,0 +1,74 @@ +package org.nem.core.utils; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A two-level map of items. + *
+ * Items are automatically created on access. + * Item associations are order-dependent. + */ +public abstract class AbstractTwoLevelMap { + private final Map> impl = new ConcurrentHashMap<>(); + + /** + * Gets the TValue associated with key1 and key2. + * + * @param key1 The first key. + * @param key2 The second key. + * @return The value associated with key and key2. + */ + public TValue getItem(final TKey key1, final TKey key2) { + final Map keyOneValues = this.getItems(key1); + + TValue value = keyOneValues.get(key2); + if (null == value) { + value = this.createValue(); + keyOneValues.put(key2, value); + } + + return value; + } + + /** + * Gets the (TKey, TValue) map associated with key. + * + * @param key The first key. + * @return The map associated with key. + */ + public Map getItems(final TKey key) { + Map keyValues = this.impl.get(key); + if (null == keyValues) { + keyValues = new ConcurrentHashMap<>(); + this.impl.put(key, keyValues); + } + + return keyValues; + } + + /** + * Removes a key from the map. + * + * @param key The key to remove. + */ + public void remove(final TKey key) { + this.impl.remove(key); + } + + /** + * Gets the key set of this map. + * + * @return The key set. + */ + public Set keySet() { + return this.impl.keySet(); + } + + /** + * Creates a new blank value. + * + * @return A new value. + */ + protected abstract TValue createValue(); +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/ArrayUtils.java b/source-code/RuffCT-java/src/org/nem/core/utils/ArrayUtils.java new file mode 100755 index 0000000..5e9170c --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/ArrayUtils.java @@ -0,0 +1,156 @@ +package org.nem.core.utils; + +import java.math.BigInteger; + +/** + * Static class that contains a handful of array helper functions. + */ +public class ArrayUtils { + + /** + * Creates duplicate of given array + * + * @param src The array to duplicate. + * @return A copy of the array. + */ + public static byte[] duplicate(final byte[] src) { + final byte[] result = new byte[src.length]; + System.arraycopy(src, 0, result, 0, src.length); + return result; + } + + /** + * Concatenates byte arrays and returns the result. + * + * @param arrays The arrays. + * @return A single array containing all elements in all arrays. + */ + public static byte[] concat(final byte[]... arrays) { + int totalSize = 0; + for (final byte[] array : arrays) { + totalSize += array.length; + } + + int startIndex = 0; + final byte[] result = new byte[totalSize]; + for (final byte[] array : arrays) { + System.arraycopy(array, 0, result, startIndex, array.length); + startIndex += array.length; + } + + return result; + } + + /** + * Splits a single array into two arrays. + * + * @param bytes The input array. + * @param splitIndex The index at which the array should be split. + * @return Two arrays split at the splitIndex. + * The first array will contain the first splitIndex elements. + * The second array will contain all trailing elements. + */ + public static byte[][] split(final byte[] bytes, final int splitIndex) { + if (splitIndex < 0 || bytes.length < splitIndex) { + throw new IllegalArgumentException("split index is out of range"); + } + + final byte[] lhs = new byte[splitIndex]; + final byte[] rhs = new byte[bytes.length - splitIndex]; + + System.arraycopy(bytes, 0, lhs, 0, lhs.length); + System.arraycopy(bytes, splitIndex, rhs, 0, rhs.length); + return new byte[][] { lhs, rhs }; + } + + /** + * Converts a BigInteger to a little endian byte array. + * + * @param value The value to convert. + * @param numBytes The number of bytes in the destination array. + * @return The resulting little endian byte array. + */ + public static byte[] toByteArray(final BigInteger value, final int numBytes) { + final byte[] outputBytes = new byte[numBytes]; + final byte[] bigIntegerBytes = value.toByteArray(); + + int copyStartIndex = (0x00 == bigIntegerBytes[0]) ? 1 : 0; + int numBytesToCopy = bigIntegerBytes.length - copyStartIndex; + if (numBytesToCopy > numBytes) { + copyStartIndex += numBytesToCopy - numBytes; + numBytesToCopy = numBytes; + } + + for (int i = 0; i < numBytesToCopy; ++i) { + outputBytes[i] = bigIntegerBytes[copyStartIndex + numBytesToCopy - i - 1]; + } + + return outputBytes; + } + + /** + * Converts a little endian byte array to a BigInteger. + * + * @param bytes The bytes to convert. + * @return The resulting BigInteger. + */ + public static BigInteger toBigInteger(final byte[] bytes) { + final byte[] bigEndianBytes = new byte[bytes.length + 1]; + for (int i = 0; i < bytes.length; ++i) { + bigEndianBytes[i + 1] = bytes[bytes.length - i - 1]; + } + + return new BigInteger(bigEndianBytes); + } + + /** + * Constant-time byte[] comparison. The constant time behavior eliminates side channel attacks. + * + * @param b An array. + * @param c An array. + * @return 1 if b and c are equal, 0 otherwise. + */ + public static int isEqualConstantTime(final byte[] b, final byte[] c) { + int result = 0; + result |= b.length - c.length; + for (int i = 0; i < b.length; i++) { + result |= b[i] ^ c[i]; + } + + return ByteUtils.isEqualConstantTime(result, 0); + } + + /** + * NON constant-time lexicographical byte[] comparison. + * + * @param b first of arrays to compare. + * @param c second of arrays to compare. + * @return 1, -1, or 0 depending on comparison result. + */ + public static int compare(final byte[] b, final byte[] c) { + int result = b.length - c.length; + if (0 != result) { + return result; + } + + for (int i = 0; i < b.length; i++) { + result = b[i] - c[i]; + if (0 != result) { + return result; + } + } + + return 0; + } + + /** + * Gets the i'th bit of a byte array. + * + * @param h The byte array. + * @param i The bit index. + * @return The value of the i'th bit in h + */ + public static int getBit(final byte[] h, final int i) { + return (h[i >> 3] >> (i & 7)) & 1; + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/Base32Encoder.java b/source-code/RuffCT-java/src/org/nem/core/utils/Base32Encoder.java new file mode 100755 index 0000000..74b33d6 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/Base32Encoder.java @@ -0,0 +1,37 @@ +package org.nem.core.utils; + +import org.apache.commons.codec.binary.Base32; + +/** + * Static class that contains utility functions for converting Base32 strings to and from bytes. + */ +public class Base32Encoder { + + /** + * Converts a string to a byte array. + * + * @param base32String The input Base32 string. + * @return The output byte array. + */ + public static byte[] getBytes(final String base32String) { + final Base32 codec = new Base32(); + final byte[] encodedBytes = StringEncoder.getBytes(base32String); + if (!codec.isInAlphabet(encodedBytes, true)) { + throw new IllegalArgumentException("malformed base32 string passed to getBytes"); + } + + return codec.decode(encodedBytes); + } + + /** + * Converts a byte array to a Base32 string. + * + * @param bytes The input byte array. + * @return The output Base32 string. + */ + public static String getString(final byte[] bytes) { + final Base32 codec = new Base32(); + final byte[] decodedBytes = codec.encode(bytes); + return StringEncoder.getString(decodedBytes); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/Base64Encoder.java b/source-code/RuffCT-java/src/org/nem/core/utils/Base64Encoder.java new file mode 100755 index 0000000..e8aeaf1 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/Base64Encoder.java @@ -0,0 +1,37 @@ +package org.nem.core.utils; + +import org.apache.commons.codec.binary.Base64; + +/** + * Static class that contains utility functions for converting Base64 strings to and from bytes. + */ +public class Base64Encoder { + + /** + * Converts a string to a byte array. + * + * @param base64String The input Base64 string. + * @return The output byte array. + */ + public static byte[] getBytes(final String base64String) { + final Base64 codec = new Base64(); + final byte[] encodedBytes = StringEncoder.getBytes(base64String); + if (!codec.isInAlphabet(encodedBytes, true)) { + throw new IllegalArgumentException("malformed base64 string passed to getBytes"); + } + + return codec.decode(encodedBytes); + } + + /** + * Converts a byte array to a Base64 string. + * + * @param bytes The input byte array. + * @return The output Base64 string. + */ + public static String getString(final byte[] bytes) { + final Base64 codec = new Base64(); + final byte[] decodedBytes = codec.encode(bytes); + return StringEncoder.getString(decodedBytes); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/ByteUtils.java b/source-code/RuffCT-java/src/org/nem/core/utils/ByteUtils.java new file mode 100755 index 0000000..b5087c7 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/ByteUtils.java @@ -0,0 +1,100 @@ +package org.nem.core.utils; + +import java.nio.ByteBuffer; + +public class ByteUtils { + + /** + * Converts an array of 8 bytes into a long. + * + * @param bytes The bytes. + * @return The long. + */ + public static long bytesToLong(final byte[] bytes) { + final ByteBuffer buffer = ByteBuffer.allocate(8); + buffer.put(bytes, 0, 8); + buffer.flip(); + return buffer.getLong(); + } + + /** + * Converts a long value into an array of 8 bytes. + * + * @param x The long. + * @return The bytes. + */ + public static byte[] longToBytes(final long x) { + final ByteBuffer buffer = ByteBuffer.allocate(8); + buffer.putLong(x); + return buffer.array(); + } + + /** + * Converts an array of 4 bytes into a int. + * + * @param bytes The bytes. + * @return The int. + */ + public static int bytesToInt(final byte[] bytes) { + final ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.put(bytes, 0, 4); + buffer.flip(); + return buffer.getInt(); + } + + /** + * Converts an int value into an array of 4 bytes. + * + * @param x The int. + * @return The bytes. + */ + public static byte[] intToBytes(final int x) { + final ByteBuffer buffer = ByteBuffer.allocate(4); + buffer.putInt(x); + return buffer.array(); + } + + /** + * Constant-time byte comparison. The constant time behavior eliminates side channel attacks. + * + * @param b One byte. + * @param c Another byte. + * @return 1 if b and c are equal, 0 otherwise. + */ + public static int isEqualConstantTime(final int b, final int c) { + int result = 0; + final int xor = b ^ c; + for (int i = 0; i < 8; i++) { + result |= xor >> i; + } + + return (result ^ 0x01) & 0x01; + } + + /** + * Constant-time check if byte is negative. The constant time behavior eliminates side channel attacks. + * + * @param b The byte to check. + * @return 1 if the byte is negative, 0 otherwise. + */ + public static int isNegativeConstantTime(final int b) { + return (b >> 8) & 1; + } + + /** + * Creates a human readable representation of an array of bytes. + * + * @param bytes The bytes. + * @return An string representation of the bytes. + */ + public static String toString(final byte[] bytes) { + final StringBuilder builder = new StringBuilder(); + builder.append("{ "); + for (final byte b : bytes) { + builder.append(String.format("%02X ", (byte)(0xFF & b))); + } + + builder.append("}"); + return builder.toString(); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/CircularStack.java b/source-code/RuffCT-java/src/org/nem/core/utils/CircularStack.java new file mode 100755 index 0000000..19ff1b9 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/CircularStack.java @@ -0,0 +1,88 @@ +package org.nem.core.utils; + +import java.util.*; + +/** + * Circular stack is a last in first out buffer with fixed size that replace its oldest element if full. + * The removal order is inverse of insertion order. The iteration order is the same as insertion order. + * Note that implementation is not synchronized. + * + * @param Type of elements on the stack. + */ +public class CircularStack implements Iterable { + private final List elements; + private final int limit; + + /** + * Creates circular stack with at most limit elements. + * + * @param limit Maximum number of elements on the stack. + */ + public CircularStack(final int limit) { + this.elements = new ArrayList<>(limit); + this.limit = limit; + } + + /** + * Creates shallow copy in destination. + * + * @param destination CircularStack to which elements should be copied. + */ + public void shallowCopyTo(final CircularStack destination) { + destination.elements.clear(); + destination.pushAll(this); + } + + private void pushAll(final CircularStack rhs) { + int i = 0; + for (final E element : rhs) { + if (i >= rhs.size() - this.limit) { + this.push(element); + } + + ++i; + } + } + + /** + * Adds element to the stack. + * + * @param element Element to be added. + */ + public void push(final E element) { + this.elements.add(element); + if (this.elements.size() > this.limit) { + this.elements.remove(0); + } + } + + /** + * Gets most recently added element. + * + * @return Most recently added element. + */ + public E peek() { + return this.elements.get(this.elements.size() - 1); + } + + /** + * Removes most recently added element. + */ + public void pop() { + this.elements.remove(this.elements.size() - 1); + } + + /** + * Returns size of a stack. + * + * @return Size of a stack (can be smaller than limit). + */ + public int size() { + return this.elements.size(); + } + + @Override + public Iterator iterator() { + return this.elements.iterator(); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/ExceptionUtils.java b/source-code/RuffCT-java/src/org/nem/core/utils/ExceptionUtils.java new file mode 100755 index 0000000..d1dac1a --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/ExceptionUtils.java @@ -0,0 +1,102 @@ +package org.nem.core.utils; + +import java.util.concurrent.*; +import java.util.function.Function; + +/** + * Static class that contains helper functions for dealing with exceptions. + */ +public class ExceptionUtils { + + private ExceptionUtils() { + } + + /** + * Interface that mimics Runnable but can additionally throw checked exceptions. + */ + public interface CheckedRunnable { + + /** + * Executes the runnable. + * + * @throws Exception Any exception. + */ + void call() throws Exception; + } + + /** + * Propagates checked exceptions as a runtime exception. + * + * @param runnable The checked runnable. + */ + public static void propagateVoid(final CheckedRunnable runnable) { + propagateVoid(runnable, RuntimeException::new); + } + + /** + * Propagates checked exceptions as a specific runtime exception. + * + * @param runnable The checked runnable. + * @param wrap A function that wraps an exception in a runtime exception. + * @param The specific exception type. + */ + public static void propagateVoid( + final CheckedRunnable runnable, + final Function wrap) { + propagate(new CheckedRuntimeToCallableAdapter(runnable), wrap); + } + + /** + * Propagates checked exceptions as a runtime exception. + * + * @param callable The function. + * @param The function return type. + * @return The function result. + */ + public static T propagate(final Callable callable) { + return propagate(callable, RuntimeException::new); + } + + /** + * Propagates checked exceptions as a specific runtime exception. + * + * @param callable The function. + * @param wrap A function that wraps an exception in a runtime exception. + * @param The function return type. + * @param The specific exception type. + * @return The function result. + */ + public static T propagate( + final Callable callable, + final Function wrap) { + try { + return callable.call(); + } catch (final ExecutionException e) { + if (RuntimeException.class.isAssignableFrom(e.getCause().getClass())) { + throw (RuntimeException)e.getCause(); + } + throw wrap.apply(e); + } catch (final RuntimeException e) { + throw e; + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } catch (final Exception e) { + throw wrap.apply(e); + } + } + + private static class CheckedRuntimeToCallableAdapter implements Callable { + private final CheckedRunnable runnable; + + public CheckedRuntimeToCallableAdapter(final CheckedRunnable runnable) { + this.runnable = runnable; + } + + @Override + public Void call() throws Exception { + this.runnable.call(); + return null; + } + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/FormatUtils.java b/source-code/RuffCT-java/src/org/nem/core/utils/FormatUtils.java new file mode 100755 index 0000000..5fc4383 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/FormatUtils.java @@ -0,0 +1,63 @@ +package org.nem.core.utils; + +import java.text.*; +import java.util.Arrays; + +/** + * Static class containing helper functions for formatting. + */ +public class FormatUtils { + + /** + * Gets a default decimal format that should be used for formatting decimal values. + * + * @return A default decimal format. + */ + public static DecimalFormat getDefaultDecimalFormat() { + final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(); + decimalFormatSymbols.setDecimalSeparator('.'); + final DecimalFormat format = new DecimalFormat("#0.000", decimalFormatSymbols); + format.setGroupingUsed(false); + return format; + } + + /** + * Gets a decimal format that with the desired number of decimal places. + * + * @param decimalPlaces The number of decimal places. + * @return The desired decimal format. + */ + public static DecimalFormat getDecimalFormat(final int decimalPlaces) { + if (decimalPlaces < 0) { + throw new IllegalArgumentException("decimalPlaces must be non-negative"); + } + + final DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(); + decimalFormatSymbols.setDecimalSeparator('.'); + final StringBuilder builder = new StringBuilder(); + builder.append("#0"); + + if (decimalPlaces > 0) { + builder.append('.'); + final char[] zeros = new char[decimalPlaces]; + Arrays.fill(zeros, '0'); + builder.append(zeros); + } + + final DecimalFormat format = new DecimalFormat(builder.toString(), decimalFormatSymbols); + format.setGroupingUsed(false); + return format; + } + + /** + * Formats a double value with a given number of decimal places. + * + * @param value The value to format. + * @param decimalPlaces The desired number of decimal places. + * @return The formatted string. + */ + public static String format(final double value, final int decimalPlaces) { + final DecimalFormat formatter = getDecimalFormat(decimalPlaces); + return formatter.format(value); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/HexEncoder.java b/source-code/RuffCT-java/src/org/nem/core/utils/HexEncoder.java new file mode 100755 index 0000000..a8d380e --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/HexEncoder.java @@ -0,0 +1,57 @@ +package org.nem.core.utils; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.codec.binary.Hex; + +/** + * Static class that contains utility functions for converting hex strings to and from bytes. + */ +public class HexEncoder { + + /** + * Converts a hex string to a byte array. + * + * @param hexString The input hex string. + * @return The output byte array. + */ + public static byte[] getBytes(final String hexString) { + try { + return getBytesInternal(hexString); + } catch (final DecoderException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Tries to convert a hex string to a byte array. + * + * @param hexString The input hex string. + * @return The output byte array or null if the input string is malformed. + */ + public static byte[] tryGetBytes(final String hexString) { + try { + return getBytesInternal(hexString); + } catch (final DecoderException e) { + return null; + } + } + + private static byte[] getBytesInternal(final String hexString) throws DecoderException { + final Hex codec = new Hex(); + final String paddedHexString = 0 == hexString.length() % 2 ? hexString : "0" + hexString; + final byte[] encodedBytes = StringEncoder.getBytes(paddedHexString); + return codec.decode(encodedBytes); + } + + /** + * Converts a byte array to a hex string. + * + * @param bytes The input byte array. + * @return The output hex string. + */ + public static String getString(final byte[] bytes) { + final Hex codec = new Hex(); + final byte[] decodedBytes = codec.encode(bytes); + return StringEncoder.getString(decodedBytes); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/HttpStatus.java b/source-code/RuffCT-java/src/org/nem/core/utils/HttpStatus.java new file mode 100755 index 0000000..dc48d5c --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/HttpStatus.java @@ -0,0 +1,494 @@ +package org.nem.core.utils; + +/* We don't want to get spring dependancy just to get this... */ + +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Java 5 enumeration of HTTP status codes. + * + * @author Arjen Poutsma + * @author Sebastien Deleuze + * @see HTTP Status Code Registry + * @see List of HTTP status codes - Wikipedia + */ +public enum HttpStatus { + + // 1xx Informational + + /** + * {@code 100 Continue}. + * + * @see HTTP/1.1: Semantics and Content, section 6.2.1 + */ + CONTINUE(100, "Continue"), + /** + * {@code 101 Switching Protocols}. + * + * @see HTTP/1.1: Semantics and Content, section 6.2.2 + */ + SWITCHING_PROTOCOLS(101, "Switching Protocols"), + /** + * {@code 102 Processing}. + * + * @see WebDAV + */ + PROCESSING(102, "Processing"), + /** + * {@code 103 Checkpoint}. + * + * @see A proposal for supporting + * resumable POST/PUT HTTP requests in HTTP/1.0 + */ + CHECKPOINT(103, "Checkpoint"), + + // 2xx Success + + /** + * {@code 200 OK}. + * + * @see HTTP/1.1: Semantics and Content, section 6.3.1 + */ + OK(200, "OK"), + /** + * {@code 201 Created}. + * + * @see HTTP/1.1: Semantics and Content, section 6.3.2 + */ + CREATED(201, "Created"), + /** + * {@code 202 Accepted}. + * + * @see HTTP/1.1: Semantics and Content, section 6.3.3 + */ + ACCEPTED(202, "Accepted"), + /** + * {@code 203 Non-Authoritative Information}. + * + * @see HTTP/1.1: Semantics and Content, section 6.3.4 + */ + NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information"), + /** + * {@code 204 No Content}. + * + * @see HTTP/1.1: Semantics and Content, section 6.3.5 + */ + NO_CONTENT(204, "No Content"), + /** + * {@code 205 Reset Content}. + * + * @see HTTP/1.1: Semantics and Content, section 6.3.6 + */ + RESET_CONTENT(205, "Reset Content"), + /** + * {@code 206 Partial Content}. + * + * @see HTTP/1.1: Range Requests, section 4.1 + */ + PARTIAL_CONTENT(206, "Partial Content"), + /** + * {@code 207 Multi-Status}. + * + * @see WebDAV + */ + MULTI_STATUS(207, "Multi-Status"), + /** + * {@code 208 Already Reported}. + * + * @see WebDAV Binding Extensions + */ + ALREADY_REPORTED(208, "Already Reported"), + /** + * {@code 226 IM Used}. + * + * @see Delta encoding in HTTP + */ + IM_USED(226, "IM Used"), + + // 3xx Redirection + + /** + * {@code 300 Multiple Choices}. + * + * @see HTTP/1.1: Semantics and Content, section 6.4.1 + */ + MULTIPLE_CHOICES(300, "Multiple Choices"), + /** + * {@code 301 Moved Permanently}. + * + * @see HTTP/1.1: Semantics and Content, section 6.4.2 + */ + MOVED_PERMANENTLY(301, "Moved Permanently"), + /** + * {@code 302 Found}. + * + * @see HTTP/1.1: Semantics and Content, section 6.4.3 + */ + FOUND(302, "Found"), + /** + * {@code 302 Moved Temporarily}. + * + * @see HTTP/1.0, section 9.3 + * @deprecated In favor of {@link #FOUND} which will be returned from {@code HttpStatus.valueOf(302)} + */ + @Deprecated + MOVED_TEMPORARILY(302, "Moved Temporarily"), + /** + * {@code 303 See Other}. + * + * @see HTTP/1.1: Semantics and Content, section 6.4.4 + */ + SEE_OTHER(303, "See Other"), + /** + * {@code 304 Not Modified}. + * + * @see HTTP/1.1: Conditional Requests, section 4.1 + */ + NOT_MODIFIED(304, "Not Modified"), + /** + * {@code 305 Use Proxy}. + * + * @see HTTP/1.1: Semantics and Content, section 6.4.5 + * @deprecated due to security concerns regarding in-band configuration of a proxy + */ + @Deprecated + USE_PROXY(305, "Use Proxy"), + /** + * {@code 307 Temporary Redirect}. + * + * @see HTTP/1.1: Semantics and Content, section 6.4.7 + */ + TEMPORARY_REDIRECT(307, "Temporary Redirect"), + /** + * {@code 308 Permanent Redirect}. + * + * @see RFC 7238 + */ + PERMANENT_REDIRECT(308, "Permanent Redirect"), + + // --- 4xx Client Error --- + + /** + * {@code 400 Bad Request}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.1 + */ + BAD_REQUEST(400, "Bad Request"), + /** + * {@code 401 Unauthorized}. + * + * @see HTTP/1.1: Authentication, section 3.1 + */ + UNAUTHORIZED(401, "Unauthorized"), + /** + * {@code 402 Payment Required}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.2 + */ + PAYMENT_REQUIRED(402, "Payment Required"), + /** + * {@code 403 Forbidden}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.3 + */ + FORBIDDEN(403, "Forbidden"), + /** + * {@code 404 Not Found}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.4 + */ + NOT_FOUND(404, "Not Found"), + /** + * {@code 405 Method Not Allowed}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.5 + */ + METHOD_NOT_ALLOWED(405, "Method Not Allowed"), + /** + * {@code 406 Not Acceptable}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.6 + */ + NOT_ACCEPTABLE(406, "Not Acceptable"), + /** + * {@code 407 Proxy Authentication Required}. + * + * @see HTTP/1.1: Authentication, section 3.2 + */ + PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required"), + /** + * {@code 408 Request Timeout}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.7 + */ + REQUEST_TIMEOUT(408, "Request Timeout"), + /** + * {@code 409 Conflict}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.8 + */ + CONFLICT(409, "Conflict"), + /** + * {@code 410 Gone}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.9 + */ + GONE(410, "Gone"), + /** + * {@code 411 Length Required}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.10 + */ + LENGTH_REQUIRED(411, "Length Required"), + /** + * {@code 412 Precondition failed}. + * + * @see HTTP/1.1: Conditional Requests, section 4.2 + */ + PRECONDITION_FAILED(412, "Precondition Failed"), + /** + * {@code 413 Payload Too Large}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.11 + * @since 4.1 + */ + PAYLOAD_TOO_LARGE(413, "Payload Too Large"), + /** + * {@code 413 Request Entity Too Large}. + * + * @see HTTP/1.1, section 10.4.14 + * @deprecated In favor of {@link #PAYLOAD_TOO_LARGE} which will be returned from {@code HttpStatus.valueOf(413)} + */ + @Deprecated + REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large"), + /** + * {@code 414 URI Too Long}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.12 + * @since 4.1 + */ + URI_TOO_LONG(414, "URI Too Long"), + /** + * {@code 414 Request-URI Too Long}. + * + * @see HTTP/1.1, section 10.4.15 + * @deprecated In favor of {@link #URI_TOO_LONG} which will be returned from {@code HttpStatus.valueOf(414)} + */ + @Deprecated + REQUEST_URI_TOO_LONG(414, "Request-URI Too Long"), + /** + * {@code 415 Unsupported Media Type}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.13 + */ + UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"), + /** + * {@code 416 Requested Range Not Satisfiable}. + * + * @see HTTP/1.1: Range Requests, section 4.4 + */ + REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable"), + /** + * {@code 417 Expectation Failed}. + * + * @see HTTP/1.1: Semantics and Content, section 6.5.14 + */ + EXPECTATION_FAILED(417, "Expectation Failed"), + /** + * {@code 418 I'm a teapot}. + * + * @see HTCPCP/1.0 + */ + I_AM_A_TEAPOT(418, "I'm a teapot"), + /** + * @deprecated See WebDAV Draft Changes + */ + @Deprecated + INSUFFICIENT_SPACE_ON_RESOURCE(419, "Insufficient Space On Resource"), + /** + * @deprecated See WebDAV Draft Changes + */ + @Deprecated + METHOD_FAILURE(420, "Method Failure"), + /** + * @deprecated See WebDAV Draft Changes + */ + @Deprecated + DESTINATION_LOCKED(421, "Destination Locked"), + /** + * {@code 422 Unprocessable Entity}. + * + * @see WebDAV + */ + UNPROCESSABLE_ENTITY(422, "Unprocessable Entity"), + /** + * {@code 423 Locked}. + * + * @see WebDAV + */ + LOCKED(423, "Locked"), + /** + * {@code 424 Failed Dependency}. + * + * @see WebDAV + */ + FAILED_DEPENDENCY(424, "Failed Dependency"), + /** + * {@code 426 Upgrade Required}. + * + * @see Upgrading to TLS Within HTTP/1.1 + */ + UPGRADE_REQUIRED(426, "Upgrade Required"), + /** + * {@code 428 Precondition Required}. + * + * @see Additional HTTP Status Codes + */ + PRECONDITION_REQUIRED(428, "Precondition Required"), + /** + * {@code 429 Too Many Requests}. + * + * @see Additional HTTP Status Codes + */ + TOO_MANY_REQUESTS(429, "Too Many Requests"), + /** + * {@code 431 Request Header Fields Too Large}. + * + * @see Additional HTTP Status Codes + */ + REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large"), + + // --- 5xx Server Error --- + + /** + * {@code 500 Internal Server Error}. + * + * @see HTTP/1.1: Semantics and Content, section 6.6.1 + */ + INTERNAL_SERVER_ERROR(500, "Internal Server Error"), + /** + * {@code 501 Not Implemented}. + * + * @see HTTP/1.1: Semantics and Content, section 6.6.2 + */ + NOT_IMPLEMENTED(501, "Not Implemented"), + /** + * {@code 502 Bad Gateway}. + * + * @see HTTP/1.1: Semantics and Content, section 6.6.3 + */ + BAD_GATEWAY(502, "Bad Gateway"), + /** + * {@code 503 Service Unavailable}. + * + * @see HTTP/1.1: Semantics and Content, section 6.6.4 + */ + SERVICE_UNAVAILABLE(503, "Service Unavailable"), + /** + * {@code 504 Gateway Timeout}. + * + * @see HTTP/1.1: Semantics and Content, section 6.6.5 + */ + GATEWAY_TIMEOUT(504, "Gateway Timeout"), + /** + * {@code 505 HTTP Version Not Supported}. + * + * @see HTTP/1.1: Semantics and Content, section 6.6.6 + */ + HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported"), + /** + * {@code 506 Variant Also Negotiates} + * + * @see Transparent Content Negotiation + */ + VARIANT_ALSO_NEGOTIATES(506, "Variant Also Negotiates"), + /** + * {@code 507 Insufficient Storage} + * + * @see WebDAV + */ + INSUFFICIENT_STORAGE(507, "Insufficient Storage"), + /** + * {@code 508 Loop Detected} + * + * @see WebDAV Binding Extensions + */ + LOOP_DETECTED(508, "Loop Detected"), + /** + * {@code 509 Bandwidth Limit Exceeded} + */ + BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded"), + /** + * {@code 510 Not Extended} + * + * @see HTTP Extension Framework + */ + NOT_EXTENDED(510, "Not Extended"), + /** + * {@code 511 Network Authentication Required}. + * + * @see Additional HTTP Status Codes + */ + NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required"); + + private final int value; + + private final String reasonPhrase; + + HttpStatus(final int value, final String reasonPhrase) { + this.value = value; + this.reasonPhrase = reasonPhrase; + } + + /** + * Return the integer value of this status code. + */ + public int value() { + return this.value; + } + + /** + * Return the reason phrase of this status code. + */ + public String getReasonPhrase() { + return this.reasonPhrase; + } + + /** + * Return a string representation of this status code. + */ + @Override + public String toString() { + return Integer.toString(this.value); + } + + /** + * Return the enum constant of this type with the specified numeric value. + * + * @param statusCode the numeric value of the enum to be returned + * @return the enum constant with the specified numeric value + * @throws IllegalArgumentException if this enum has no constant for the specified numeric value + */ + public static HttpStatus valueOf(final int statusCode) { + for (final HttpStatus status : values()) { + if (status.value == statusCode) { + return status; + } + } + throw new IllegalArgumentException("No matching constant for [" + statusCode + "]"); + } +} \ No newline at end of file diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/LockFile.java b/source-code/RuffCT-java/src/org/nem/core/utils/LockFile.java new file mode 100755 index 0000000..941d015 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/LockFile.java @@ -0,0 +1,82 @@ +package org.nem.core.utils; + +import java.io.*; +import java.nio.channels.*; + +/** + * Static class that exposes functions for interacting with lock files. + */ +public class LockFile { + + /** + * Tries to acquire a file lock for the specified file. + * + * @param lockFile The lock file. + * @return A handle to the file lock if acquired, or null otherwise. + */ + public static Closeable tryAcquireLock(final File lockFile) { + FileLockHandle handle = null; + try { + handle = new FileLockHandle(lockFile); + + // try to acquire the lock 5 times + for (int i = 0; i < 5; ++i) { + if (handle.tryLock()) { + return handle; + } + + ExceptionUtils.propagateVoid(() -> Thread.sleep(10)); + } + + return null; + } catch (final IOException | OverlappingFileLockException e) { + return null; + } finally { + if (null != handle && null == handle.lock) { + try { + handle.close(); + } catch (final IOException ignored) { + } + } + } + } + + /** + * Determines whether or not the specified file is locked. + * + * @param lockFile The lock file. + * @return true if the file is locked, false otherwise. + */ + public static boolean isLocked(final File lockFile) { + try (final FileLockHandle handle = new FileLockHandle(lockFile)) { + return !handle.tryLock(); + } catch (final OverlappingFileLockException e) { + return true; + } catch (final IOException e) { + return false; + } + } + + private static class FileLockHandle implements Closeable { + private final RandomAccessFile file; + private FileLock lock; + + public FileLockHandle(final File lockFile) throws IOException { + this.file = new RandomAccessFile(lockFile, "rw"); + } + + private boolean tryLock() throws IOException { + this.lock = this.file.getChannel().tryLock(); + return null != this.lock; + } + + @Override + public void close() throws IOException { + if (null != this.lock) { + this.lock.close(); + } + + this.file.close(); + } + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/MustBe.java b/source-code/RuffCT-java/src/org/nem/core/utils/MustBe.java new file mode 100755 index 0000000..cd5e65d --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/MustBe.java @@ -0,0 +1,118 @@ +package org.nem.core.utils; + +import java.util.Collection; +import java.util.regex.Pattern; + +/** + * Helper class for validating parameters. + */ +public class MustBe { + + /** + * Throws an exception if the specified object is null. + * + * @param obj The object. + * @param name The object name. + */ + public static void notNull(final Object obj, final String name) { + if (null == obj) { + final String message = String.format("%s cannot be null", name); + throw new IllegalArgumentException(message); + } + } + + /** + * Throws an exception if the specified string contains no non-whitespace characters. + * + * @param str The string. + * @param name The string name. + * @param maxLength The max length. + */ + public static void notWhitespace(final String str, final String name, final int maxLength) { + if (StringUtils.isNullOrWhitespace(str) || str.length() > maxLength) { + final String message = String.format("%s cannot be null, empty, or whitespace, or have length greater than %d", name, maxLength); + throw new IllegalArgumentException(message); + } + } + + /** + * Throws an exception if the specified string does not match the pattern, is empty, or longer than the max length. + * + * @param str The string. + * @param name The string name. + * @param pattern The pattern to match. + * @param maxLength The max length. + */ + public static void match(final String str, final String name, final Pattern pattern, final int maxLength) { + if (null == str || str.isEmpty() || str.length() > maxLength || !pattern.matcher(str).matches()) { + final String message = String.format("%s does not match the desired pattern", name); + throw new IllegalArgumentException(message); + } + } + + /** + * Throws an exception if the specified integer value is not in the specified inclusive range. + * + * @param value The integer value. + * @param name The value name. + * @param minInclusive The min allowed value (inclusive). + * @param maxInclusive The max allowed value (inclusive). + */ + public static void inRange(final int value, final String name, final int minInclusive, final int maxInclusive) { + inRange((long)value, name, minInclusive, maxInclusive); + } + + /** + * Throws an exception if the specified long value is not in the specified inclusive range. + * + * @param value The long value. + * @param name The value name. + * @param minInclusive The min allowed value (inclusive). + * @param maxInclusive The max allowed value (inclusive). + */ + public static void inRange(final long value, final String name, final long minInclusive, final long maxInclusive) { + if (value < minInclusive || value > maxInclusive) { + final String message = String.format("%s must be between %d and %d inclusive", name, minInclusive, maxInclusive); + throw new IllegalArgumentException(message); + } + } + + /** + * Throws an exception if the specified collection is not empty. + * + * @param collection The collection. + * @param name The collection name. + */ + public static void empty(final Collection collection, final String name) { + if (!collection.isEmpty()) { + final String message = String.format("%s must be empty", name); + throw new IllegalArgumentException(message); + } + } + + /** + * Throws an exception if the specified value is not true. + * + * @param value The value. + * @param name The value name. + */ + public static void trueValue(final boolean value, final String name) { + if (!value) { + final String message = String.format("%s must be true", name); + throw new IllegalArgumentException(message); + } + } + + /** + * Throws an exception if the specified value is not false. + * + * @param value The value. + * @param name The value name. + */ + public static void falseValue(final boolean value, final String name) { + if (value) { + final String message = String.format("%s must be false", name); + throw new IllegalArgumentException(message); + } + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/SetOnce.java b/source-code/RuffCT-java/src/org/nem/core/utils/SetOnce.java new file mode 100755 index 0000000..7704d02 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/SetOnce.java @@ -0,0 +1,42 @@ +package org.nem.core.utils; + +/** + * Wrapper that allows an object to be set once (or reset and set again). + * + * @param The inner type. + */ +public class SetOnce { + private final T defaultValue; + private T value; + + /** + * Creates a wrapper. + * + * @param defaultValue The default value. + */ + public SetOnce(final T defaultValue) { + this.defaultValue = defaultValue; + } + + /** + * Gets the inner object. + * + * @return The inner object. + */ + public T get() { + return null == this.value ? this.defaultValue : this.value; + } + + /** + * Sets the inner object. + * + * @param value The inner object. + */ + public void set(final T value) { + if (null != this.value && null != value) { + throw new IllegalStateException("cannot change value because it is already set"); + } + + this.value = value; + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/StringEncoder.java b/source-code/RuffCT-java/src/org/nem/core/utils/StringEncoder.java new file mode 100755 index 0000000..25bb127 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/StringEncoder.java @@ -0,0 +1,31 @@ +package org.nem.core.utils; + +import java.nio.charset.Charset; + +/** + * Static class that contains utility functions for converting strings to and from UTF-8 bytes. + */ +public class StringEncoder { + + private static final Charset ENCODING_CHARSET = Charset.forName("UTF-8"); + + /** + * Converts a string to a UTF-8 byte array. + * + * @param s The input string. + * @return The output byte array. + */ + public static byte[] getBytes(final String s) { + return s.getBytes(ENCODING_CHARSET); + } + + /** + * Converts a UTF-8 byte array to a string. + * + * @param bytes The input byte array. + * @return The output string. + */ + public static String getString(final byte[] bytes) { + return new String(bytes, ENCODING_CHARSET); + } +} diff --git a/source-code/RuffCT-java/src/org/nem/core/utils/StringUtils.java b/source-code/RuffCT-java/src/org/nem/core/utils/StringUtils.java new file mode 100755 index 0000000..b721bc7 --- /dev/null +++ b/source-code/RuffCT-java/src/org/nem/core/utils/StringUtils.java @@ -0,0 +1,50 @@ +package org.nem.core.utils; + +/** + * Static class that contains string utility functions. + */ +public class StringUtils { + + /** + * Determines if the specified string is null or empty. + * + * @param str The string. + * @return true if the string is null or empty. + */ + public static boolean isNullOrEmpty(final String str) { + return null == str || str.isEmpty(); + } + + /** + * Determines if the specified string is null or whitespace. + * + * @param str The string. + * @return true if the string is null or whitespace. + */ + public static boolean isNullOrWhitespace(final String str) { + if (isNullOrEmpty(str)) { + return true; + } + + for (int i = 0; i < str.length(); i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return false; + } + } + + return true; + } + + /** + * Replaces a variable contained in a string with a value. A variable is defined as ${variable}. + * This pattern is replaced by the given value. + * + * @param string String that contains variables. + * @param name Name of the variable to be replaced with its value. + * @param value Value that will replace the variable. + * @return string with value replacing the variable with the given name + */ + public static String replaceVariable(final String string, final String name, final String value) { + return string.replace(String.format("${%s}", name), value); + } +} diff --git a/source-code/RuffCT-java/src/test/how/monero/hodl/BootleRuffingBenchmarks.java b/source-code/RuffCT-java/src/test/how/monero/hodl/BootleRuffingBenchmarks.java new file mode 100644 index 0000000..1db643d --- /dev/null +++ b/source-code/RuffCT-java/src/test/how/monero/hodl/BootleRuffingBenchmarks.java @@ -0,0 +1,126 @@ +package test.how.monero.hodl; + +import how.monero.hodl.ringSignature.SpendParams; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static how.monero.hodl.ringSignature.BootleRuffing.*; +import static test.how.monero.hodl.BootleRuffingSpendTest.createTestSpendParams; + +public class BootleRuffingBenchmarks { + + public static void spendTest() throws IOException { + + int[] inputsVariants = new int[]{1, 2, 3, 4, 5, 10, 20}; + int[] decompositionExponentVariants = new int[]{2, 3, 4, 5, 6, 7, 8, 9, 10}; + + List> sheet = new ArrayList<>(); + List sheetColTitles = new ArrayList<>(); + sheetColTitles.add("Inputs"); + sheetColTitles.add("Base"); + sheetColTitles.add("Exponent"); + sheetColTitles.add("Ring size"); + sheetColTitles.add("Generation time (ms)"); + sheetColTitles.add("Generation scalar mults"); + sheetColTitles.add("Generation G scalar mults"); + sheetColTitles.add("Verification time (ms)"); + sheetColTitles.add("Verification scalar mults"); + sheetColTitles.add("Verification G scalar mults"); + sheetColTitles.add("Signature length excl. vins (bytes)"); + sheetColTitles.add("MLSAG equiv. length excl. vins (bytes)"); + sheet.add(sheetColTitles); + + int testIterations = 1; + int decompositionBase = 2; + + for(int inputs : inputsVariants) { + for(int decompositionExponent : decompositionExponentVariants) { + + System.out.println("******* inputs: " + inputs + ", decompositionExponent: " + decompositionExponent); + + long startMs = new Date().getTime(); + SpendParams[] sp = new SpendParams[testIterations]; + for (int i=0; i sheetCols = new ArrayList<>(); + sheetCols.add(inputs+""); + sheetCols.add(decompositionBase+""); + sheetCols.add(decompositionExponent+""); + sheetCols.add(((int)Math.pow(decompositionBase, decompositionExponent))+""); + sheetCols.add((spendSignatureGenerationDuration/testIterations)+""); + sheetCols.add((spendScalarMults)+""); + sheetCols.add((spendScalarBaseMults)+""); + sheetCols.add((spendSignatureVerificationDuration/testIterations)+""); + sheetCols.add((verifyScalarMults)+""); + sheetCols.add((verifyScalarBaseMults)+""); + sheetCols.add((spendSignatureBytes[0].length)+""); + sheetCols.add((inputs * (32 + 64 * ((int) Math.pow(decompositionBase, decompositionExponent))))+""); + sheet.add(sheetCols); + + } + } + + String csv = ""; + for(List row : sheet) { + for(int i=0; ii.amount.longValue()).sum()).subtract(fee).subtract(outputs[0].amount)); + + sp.iAsterisk = (int) Math.floor(Math.random()*ringSize); // the ring index of the sender's owned inputs + + // input commitments + // commitments to the amounts of all inputs referenced in the transaction (real inputs and decoys) + Ed25519GroupElement[][] inputCommitments = new Ed25519GroupElement[inputs][ringSize]; + for(int j=0; j{System.out.println("line: " + e.getKey() + ", calls: " + e.getValue());}); + + } + + public static void main(String[] args) { + long startTime = new Date().getTime(); + spendTest(); + System.out.println("Total duration: " + (new Date().getTime()-startTime) + " ms"); + } + +} diff --git a/source-code/RuffCT-java/src/test/how/monero/hodl/Prove1Valid1Test1.java b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove1Valid1Test1.java new file mode 100644 index 0000000..9427c18 --- /dev/null +++ b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove1Valid1Test1.java @@ -0,0 +1,29 @@ +package test.how.monero.hodl; + +import how.monero.hodl.crypto.Scalar; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement; + +import static how.monero.hodl.crypto.CryptoUtil.COMb; +import static how.monero.hodl.ringSignature.BootleRuffing.*; + +public class Prove1Valid1Test1 { + + public static void main(String[] args) { + + Scalar[][] b = new Scalar[][] { + new Scalar[]{Scalar.ONE, Scalar.ZERO}, + new Scalar[]{Scalar.ZERO, Scalar.ONE} + }; + + Scalar r = Scalar.ONE; + + Proof1 P = PROVE1(b, r); + + Ed25519GroupElement B = COMb(b, r); + + System.out.println("VALID1 returns " + VALID1(B, P)); + + } + + +} diff --git a/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1.java b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1.java new file mode 100644 index 0000000..a21b373 --- /dev/null +++ b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1.java @@ -0,0 +1,37 @@ +package test.how.monero.hodl; + +import how.monero.hodl.crypto.PointPair; +import how.monero.hodl.crypto.Scalar; + +import static how.monero.hodl.crypto.CryptoUtil.COMeg; +import static how.monero.hodl.ringSignature.BootleRuffing.*; + +public class Prove2Valid2Test1 { + + public static void main(String[] args) { + + System.out.println("Test: " + new Object(){}.getClass().getEnclosingClass().getName()); + + // [c[0], c[1]] = [ COMeg(0, r), COMeg(1, s) ] with secret index 0 should PASS + Scalar r = Scalar.ONE; + Scalar s = Scalar.ONE; + + PointPair[] co = new PointPair[]{ + COMeg(Scalar.ZERO, r), + COMeg(Scalar.ONE, s) + }; + + int iAsterisk = 0; + + int inputs = 1; + int decompositionBase = 2; + int decompositionExponent = 1; + + Proof2 P2 = PROVE2(co, iAsterisk, r, inputs, decompositionBase, decompositionExponent); + + System.out.println("VALID2 result: " + VALID2(decompositionBase, P2, co)); + + } + + +} diff --git a/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1a.java b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1a.java new file mode 100644 index 0000000..9f0cee7 --- /dev/null +++ b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1a.java @@ -0,0 +1,42 @@ +package test.how.monero.hodl; + +import how.monero.hodl.crypto.PointPair; +import how.monero.hodl.crypto.Scalar; + +import static how.monero.hodl.crypto.CryptoUtil.COMeg; +import static how.monero.hodl.ringSignature.BootleRuffing.*; + +public class Prove2Valid2Test1a { + + public static void main(String[] args) { + + System.out.println("Test: " + new Object(){}.getClass().getEnclosingClass().getName()); + + Scalar r = Scalar.ONE; + + PointPair[] co = new PointPair[]{ + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ZERO, Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + COMeg(Scalar.ONE,Scalar.ONE), + }; + + int iAsterisk = 5; + + int inputs = 1; + int decompositionBase = 3; + int decompositionExponent = 2; + + Proof2 P2 = PROVE2(co, iAsterisk, r, inputs, decompositionBase, decompositionExponent); + + System.out.println("VALID2 result: " + VALID2(decompositionBase, P2, co)); + + } + + +} diff --git a/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1b.java b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1b.java new file mode 100644 index 0000000..891b464 --- /dev/null +++ b/source-code/RuffCT-java/src/test/how/monero/hodl/Prove2Valid2Test1b.java @@ -0,0 +1,61 @@ +package test.how.monero.hodl; + +import how.monero.hodl.crypto.PointPair; +import how.monero.hodl.crypto.Scalar; +import org.nem.core.crypto.ed25519.arithmetic.Ed25519GroupElement; + +import java.util.Date; + +import static how.monero.hodl.crypto.CryptoUtil.COMeg; +import static how.monero.hodl.ringSignature.BootleRuffing.*; + +public class Prove2Valid2Test1b { + + public static void main(String[] args) { + + System.out.println("Test: " + new Object(){}.getClass().getEnclosingClass().getName()); + + Scalar r = Scalar.ONE; + + for(int k=1; k<=64; k++) { + + System.out.println("---------------------------------------------------------------------------"); + int len = (int) Math.pow(2, k); + PointPair[] co = new PointPair[len]; + for (int i = 0; i < len; i++) co[i] = COMeg(Scalar.intToScalar(i), Scalar.ONE); + + int iAsterisk = 0; + + int inputs = 1; + int decompositionBase = 2; + int decompositionExponent = k; + + System.out.println("k: " + k); + System.out.println("decompositionBase: " + decompositionBase); + System.out.println("decompositionExponent: " + decompositionExponent); + + Ed25519GroupElement.scalarMults = 0; + Ed25519GroupElement.scalarBaseMults = 0; + long startMs = new Date().getTime(); + + Proof2 P2 = PROVE2(co, iAsterisk, r, inputs, decompositionBase, decompositionExponent); + + System.out.println("PROVE2 duration: " + (new Date().getTime() - startMs) + " ms"); + System.out.println("PROVE2 ScalarMults: " + Ed25519GroupElement.scalarMults); + System.out.println("PROVE2 BaseScalarMults: " + Ed25519GroupElement.scalarBaseMults); + Ed25519GroupElement.scalarMults = 0; + Ed25519GroupElement.scalarBaseMults = 0; + startMs = new Date().getTime(); + + System.out.println("VALID2 result: " + VALID2(decompositionBase, P2, co)); + + System.out.println("VALID2 ScalarMults: " + Ed25519GroupElement.scalarMults); + System.out.println("VALID2 BaseScalarMults: " + Ed25519GroupElement.scalarBaseMults); + + System.out.println("VALID2 duration: " + (new Date().getTime() - startMs) + " ms"); + } + + } + + +}