diff --git a/doc/utr/utr-prng/larson.jpg b/doc/utr/utr-prng/larson.jpg new file mode 100644 index 000000000..3e9ff4b7a Binary files /dev/null and b/doc/utr/utr-prng/larson.jpg differ diff --git a/doc/utr/utr-prng/utr-prng.tex b/doc/utr/utr-prng/utr-prng.tex new file mode 100644 index 000000000..3c09ba137 --- /dev/null +++ b/doc/utr/utr-prng/utr-prng.tex @@ -0,0 +1,2305 @@ +\documentclass[letterpaper,12pt]{article} +\usepackage{utr} +\usepackage{graphicx} +\usepackage{url} +% +\title{Replacing Unicon's Random\\ Number Generator} +\author{Don Ward} +\trnumber{??} +\date{2019-08-20} +% +\begin{document} +\abstract{ +% The normal typeface means that the front matter overflows into two pages. +% Presumably, the abstract is too prolix for its own good, but it is +% difficult to condense it further. +% +% Even with \small, the front matter is two pages (but the second page is +% blank, which is slightly better). +% +% But, with a blank affiliation, all is well. +\affiliation{~} +{\small +This report discusses whether the random number generator used by Unicon +should be replaced and, if so, with what. The report concludes that the +best option would be to provide an extensible portfolio of generators with +different characteristics and leave the choice of which one to employ to +the user. It also suggests a possible implementation. +} +} +\maketitle +% +% The &random keyword is used a lot, so save some typing +\newcommand{\rndkwd}{{\sf \&random}\ } +% If the name "rnglib" is changed, don't forget to also replace it +% in the verbatim environments +\newcommand{\rndlibkwd}{{\sf \&rnglib}\ } +% A convenient way to get a consistent style of error messages. +\newcommand{\UniconError}[2]{{\sf#1} --- {\sf #2}} +% Smaller urls +\newcommand{\surl}[1]{{\small\url{#1}}} +% +\section{Introduction} +The ``{\sf Help Wanted!}'' page of \surl{www.unicon.org} +contains the following item: +\begin{quote} + {\sf + {\bf Improve random number generator (S) } + --- Unicon should consider changing its random number generator to use a + Mersenne twister. What are the pros and cons? A first step would be to + acquire or develop an implementation that is suitable. + } +\end{quote} +This is the second draft of a report that summarizes the advantages and +disadvantages of a replacement random number generator (RNG). +In some respects, it exceeds its brief by discussing other generators +alongside the Mersenne Twister. + +All but one of the generators discussed later are {\em pseudo} random rather +than genuinely random% +\footnote{ + A genuinely random generator requires access to a high quality supply of + entropy provided either by hardware, often external, or by using software + that gathers entropy from the operation of the computer system itself + such as the \texttt{/dev/random} device in modern Unix systems. +}. +For this reason, the abbreviation PRNG will usually be used in the rest of +this report. + +There is no consensus on how to rate the quality of a PRNG: that is, given +a collection of PRNGs, there is no generally accepted method to rank them in +strict order from ``lowest quality'' to ``highest quality''. +% +Several aspects of quality (such as randomness, resistance to +cryptanalysis, speed etc.) are in play and people disagree about which is +most important --- in some cases the relative importance of the factors to +consider depends on the application --- so the best that can be achieved is +a partial ordering. Everyone might be able to agree that a particular +subset of PRNGs are all better than another subset, whilst disagreeing +about the relative ordering within the subsets themselves. + +This, perhaps regrettable, lack of consensus motivates the proposals made +later on in this document, which would allow the choice of PRNG to be made +by the user% +\footnote{ + ``User'' here means ``system designer'' or ``programmer'' although, if + the design of the application program permits it (and it is possible to + choose at run time), it could also mean the actual user of the Unicon + application. +}. + +Before considering the Mersenne Twister PRNG and others, it is useful to +list the advantages and disadvantages of {\em any} replacement PRNG. + +\section{The Pros and Cons of changing the PRNG} + +There are some aspects of a replacement that are common to all +candidates. That is, they are more to do with the change itself than the +characteristics of a particular algorithm. This section discusses those +aspects. + +\newcommand{\GoodThing}{\protect{\makebox[20pt][l]{$\oplus$}}} +\newcommand{\BadThing}{\protect{\makebox[20pt][l]{$\ominus$}}} +\newcommand{\PossiblyGoodThing}{\protect{\makebox[20pt][l]{$\oplus$?}}} +\newcommand{\PossiblyBadThing}{\protect{\makebox[20pt][l]{$\ominus$?}}} + +Each of the following topics will be labelled with a ``$\oplus$'' denoting +something that is considered advantageous or a ``$\ominus$'' denoting a +disadvantage. Sometimes, if the issue is not so clear-cut or if there are +differing opinions about its relevance, a ``{\bf ?}'' will be appended to +the label. + +\begin{description} + +\item[\GoodThing] + Presumably, any new PRNG will be better than the existing + algorithm --- nobody would want the replacement if it was + worse. Possibilities for improvement include + \begin{itemize} + \item Longer period. + \item Better results on statistical tests for randomness (i.e. pass more + tests or pass more stringent tests). + \item Better resistance to cryptanalysis. + \item Faster or smaller (although this is unlikely, given the speed and + extremely small state of the current algorithm). + \item Compatibility with the PRNG used in other software. + \end{itemize} + +\item[\BadThing] + Backwards incompatibility: many programs assign a seed to \rndkwd to get + reproducible behaviour between runs. Any replacement of the existing + PRNG, which is used both by Unicon and by Icon, will mean that the output + will not be same: Unicon programs using \rndkwd that are written in the + Icon subset will produce different results on Icon and Unicon. + + This doesn't mean that the behaviour won't be reproducible --- the output + will be the same between runs --- but it will be {\em different} + reproducible behaviour on each platform. However, programs that depend on + reproducible behaviour between this and previous versions of Unicon will + definitely break% + \footnote{ + This is not just a theoretical possibility: the author uses a DiceWare + program, written in Unicon, that generates random passphrases based on + the input credentials. The passphrases aren't written down anywhere, + they are generated (again) when needed. Changing the PRNG would require + that {\em every} passphrase be changed. + }. + +\item[\PossiblyBadThing] + It is very likely that a replacement PRNG will be slower than the current + one or will require more space for its state (or both). Resistance to + cryptanalyis or better statistical properties practically {\em demand} more + than 32 bits of state. + + Whether the increase in memory footprint or the decrease in speed has a + perceptible impact on program performance is susceptible to + experiment (and Appendix C makes a proposal to find out). + If the experiments are done, they will need to be performed on as + wide a range of target hardware as possible. The underlying hardware can + have a surprisingly large impact on the {\em relative} as well as the + absolute performance of PRNGs\cite{Bernstein:cypherSpeed}. + +\end{description} + +\subsection{Discussion: should the present PRNG be replaced?} + +The designers of Unicon have usually been very careful to ensure that a +Unicon program that also happens to be an Icon program produces the same +results on both platforms% +\footnote{ + It is notable that the Unicon designers chose to depart from backwards + compatibility in the very topic we are discussing --- the generation of + random numbers. An Icon program that does not set the value of \rndkwd + will always produce the same random sequence + --- see \cite{IconBook} \S 5 page 66 --- + the same code fed into a Unicon system will produce a different random + sequence each time it is run. The reasons cited in the Unicon Book + (chapter 4) come down to Unicon's behavour being more generally useful, + and it's easy to restore the previous behaviour with one assignment. +}. + +There needs to be a very good reason to break that backwards compatibility +and, for many people, a better PRNG will not necessarily be a good enough +reason, especially as the current PRNG is still satisfactory for many +purposes. Accordingly, the answer to a strict interpretation of the +question posed above is ``No'' --- Job done; now we can all go home and +relax; no further action is required. + +However, a key insight is that replacement is not the only option. We could +make more than one PRNG available and somehow switch between them. The +choice could be implemented at run time or, possibly, at compile time. + +In any event, if we do have a choice between PRNGs it is clear from the +strong desire to retain backwards compatibility that the current algorithm +should be one of the choices and, furthermore, it should be the default +choice. Explicit action should be required to switch to a new PRNG. + +\subsection{Mission Creep} +If we have a choice between continuing to use the existing PRNG or +switching to the new one, the question ``why are there only two options?'' +naturally arises. As mentioned in the introduction, there are different +opinions about which aspects of a PRNG are most important and it will be +very difficult to land on a single alternative that pleases most of the +people most of the time. But a small, judiciously chosen, collection +of PRNGs with differing characteristics might just do the job. + +We can go further: if the mechanism to add PRNGs is {\em extensible}, so a +user may add to the available alternatives, the pressure to make the right +choice of PRNGs up-front is greatly reduced. As the state of the art +develops we can add new shinier PRNGs to the standard collection and users +with special requirements, or a pressing need for a newer algorithm, can +add their own at any time. + +\section{Candidate PRNGs} +Where to start? A lot has happened in the field of random number generation +since the original Icon PRNG was chosen in the mid to late seventies. +Significant progress% +\footnote{ + An idea of how much progress can be got by comparing the second edition + of Numerical Recipes \cite{PressEtAl:numericalRecipes-2} \S 7 (published + in 1992) with the same chapter of the third edition + \cite{PressEtAl:numericalRecipes} published in 2007. + + The references in this report are in approximate chronological order from + oldest to newest. So a rough and ready guide to whether one reference is + newer than another is to compare the reference numbers. +} +has been made since then and there are now many hundreds of generators from +which to make a selection. The problem is to winnow the hundreds of +candidates down to a manageable number. We should certainly include the +Mersenne Twister in the list for consideration, since that was the original +suggestion. A generator that is cryptographically secure might also be a +useful addition for some applications. + +\noindent +\begin{tabular*}{7in}{cc} +\begin{minipage}{3.4in} +A good starting point is to see what choices have been made by other +people, especially experts, although it might be wise to prefer recent +choices, over those made some time ago, because of the advances in the +field. Another idea is to consult authoritative tomes such as +\cite{PressEtAl:numericalRecipes,Knuth:SemiNumerical3}. +The eSTREAM project% +\footnote{ +The eSTREAM project\cite{eStream} was a multi-year effort, running from +2004 to 2008, to promote the design of efficient and compact stream ciphers +suitable for widespread adoption. +} +is a good source for candidate algorithms that are thought to be +cryptographically secure. The recommendations made by the GNU Scientific +Library \cite{GnuScientificLibrary} and the selection in the latest draft +of the C++ standard\cite{CplusplusStd:N4820} might also prove instructive. + +\end{minipage} +& +\parbox{2.5in}{ + \includegraphics[width=2.5in,height=2.5in]{larson.jpg} +} +\end{tabular*} + +It would be nice to follow the recommendations of NIST but experience --- +see \cite{Schneier:BackDoor} amongst many others --- suggests that it isn't +always a good choice. + +\vspace{0.1in} + +As a last resort we could roll our own generator, although history +indicates that would be a very bad idea indeed. A quote from +\cite{PressEtAl:numericalRecipes-2} \S 7, which contains a devastating list +of examples of lousy PRNGs, seems apposite +\begin{quote} + The historical record (of random number generators) is nothing if not + appalling. +\end{quote} +It would be a brave decision to fly in the face of so much negative +evidence. In the early nineties --- at the time of writing of +\cite{PressEtAl:numericalRecipes-2} --- it might, just possibly, have been +a sensible thing to do. Not now. + +A significant benefit of choosing somebody else's generator is that +somebody else has already done the work of evaluating the statistical +properties% +\footnote{ + If the technical paper (or other material) describing the generator + doesn't mention statistical tests for randomness, such as + Diehard\cite{Marsarglia:Diehard} + or Dieharder\cite{Brown:Dieharder} + or NIST--STS (a.k.a. NIST--SP 800-22)\cite{BassinghamEtAl:Statistical} + or TESTU01\cite{McCullough:TESTU01,L'Ecuyer:TESTU01}, + then walk away. +}. +Everyone agrees that a new generator should undergo substantial testing +before being put to serious use. Some of the tests referred to in the +footnote will take {\em days} to complete a single test run. + +Note that in the following sections describing each generator, all +generators are permissively licensed unless the description says otherwise. + +%---------------------------------------- +\subsection{Mersenne Twister (MT)} +The Mersenne Twister was invented in 1997 and was designed to avoid the +deficiencies of most of the PRNGs extant at the time. It is described in +\cite{Matsumoto:MersenneTwister}. +\begin{description} +\item[\GoodThing] + Extremely long period ($2^{19937} - 1 \simeq 4.3 \times 10^{6001}$). +\item[\GoodThing] + Quite fast; perhaps not as fast as some others, but certainly in the same ballpark. +\item[\GoodThing] + In very wide use. Chosen for inclusion into the GNU Scientific Library, + the C++ standard library and many others. +\item[\GoodThing] + Very good statistical properties. +\item[\PossiblyBadThing] + Not cryptographically secure --- there is a secure variant, called + CryptMT, but it is patented. CryptMT is free for non commercial use, + but incorporating it into Unicon might restrict the availability of + Unicon to commercial users --- note this does not apply to MT itself: that + is free to use for everyone. +\item[\PossiblyBadThing] + The original algorithm was slow to recover from a bad seed (one with a + high proportion of zero bits). ``Slow'' in this context means up to $7 + \times 10^5$ iterations. A 2002 update to the algorithm now makes the + possibility of starting in a bad state ``very unlikely'' --- although it + does not preclude stumbling into it by accident. + % ToDo: Add reference and find out if the mod always gets the same good + % seed if fed the same bad seed. +\item[\PossiblyBadThing] + It has a large state (2.5KB) compared to other generators, which is + perhaps not so good for multi-threaded applications. + +\item[\GoodThing] + The random sequence can be efficiently advanced, by jumping ahead. This is + particularly important when doing Monte Carlo simulations in parallel% + \footnote{ + The basic problem is that parallel simulations should not share the + same sequence of pseudorandom numbers, because that would destroy the + assumption that the values produced in parallel are independant of each + other. One idea is to use different seed values in each thread, but + there is usually no guarantee that they might not collide --- perhaps + after a short time --- and begin to use the same sequence, thus + destroying the independence. A common way around this problem is to + partition the random sequence into several disjoint sequences that are + a {\em very} long way apart. \cite{HiroshiEtAl:EfficientJumping} gives + details of an efficient way of doing this for MT and other similar + algorithms. + }. + +\item[\PossiblyBadThing] + CryptMT was one of the finalists in the eSTREAM project\cite{eStream} but + didn't make the final cut. The comments (in 2008) were: + \begin{quote} + {\sf + CryptMT v3. The cipher CryptMT has a very unusual design which delivers + very reasonable performance. While there have been no negative + cryptanalytic results against the cipher in the last phase of eSTREAM, + we are somewhat concerned that the security of the cipher, in + particular the non-linear filter component, might not yet be as + well-understood as some of the other finalists. We anticipate that + elements of CryptMT will continue to be of interest to the + cryptographic community, and we hope that the full advantages of the + approach embodied in CryptMT v3 can be evaluated. However, we are + currently not sufficiently confident in the design and security of this + algorithm for us to include it in the final portfolio. + } + \end{quote} + Note that these comments are about CryptMT, not about MT itself. + It doesn't make MT a bad PRNG, but the very existence of CryptMT implies + that MT isn't suitable as the basis of a cryptographically secure stream + cipher without the ``special sauce'' of a non-linear filter (and the + eSTREAM comments raise some doubts% + \footnote{ + Not too much should be made of this: cryptographers are a cautious + bunch at the best of times. + } + even when such a filter is in use). + + An attempt to build a stream cipher based on the MT may run afoul of the + cryptMT patents. However, there is a large amount of ``anecdata'' about + good engineers (but not cryptographers) making a mess of things when they + roll their own encryption, so perhaps an obstacle to doing so wouldn't be + such a bad thing. + +\end{description} + +%---------------------------------------- +\subsection{Rabbit (Rbt)} +Rabbit is from profile 1 (software)% +\footnote{ + The eSTREAM portfolio ciphers fall into two profiles. Profile 1 + contains stream ciphers more suitable for software applications with high + throughput requirements. Profile 2 stream ciphers are particularly + suitable for hardware applications with restricted resources such as + limited storage, gate count, or power consumption. +} +of the eSTREAM project\cite{eStream}. It uses a 128 bit key and 64 bit IV to +initialize the generator which produces a stream of 128 bit blocks. Up to +$2^{64}$ blocks may be produced before a new key/IV pair is required% +\footnote{ + The reader may be wondering why a re-key is needed after this + comparatively short number of operations compared to the period. The + answer is to maintain the {\em security} of the cipher. When used as a + normal (non-cryptographically secure) PRNG, the re-key is not required. +}. + +\begin{description} +\item[\PossiblyGoodThing] + Comparatively short period (compared to MT) of + $2^{256}-1 \simeq 1.2 \times 10^{77}$, + but still more than long enough for all practical purposes. +\item[\GoodThing] + Fast (faster than MT on most processors, but not always + faster\cite{Bernstein:cypherSpeed}) +\item[\GoodThing] + Fairly small state (513 bits, 65 bytes). +\item[\GoodThing] + Chosen by eSTREAM --- i.e. selected by a consensus of people with + expertise in the field. +\item[\PossiblyGoodThing] + Cryptographically secure% + \footnote{ + The {\bf ?} after the $\oplus$ doesn't mean there are doubts about its + security, it means that some authorities consider that cryptographic + security is not a requirement for a general purpose RNG. + } + (almost by definition). +\item[\GoodThing] + Passes the statistical tests for randomness --- {\em all} + cryptographically secure PRNGs pass the randomness tests. +\item[\GoodThing] + Unchanged since 2003 which, given the scrutiny of the algorithm during + the duration of the eSTREAM project and afterwards, lends + credence to the claims of cryptographic security. +\item[\PossiblyBadThing] + No method to advance the random sequence by jumping ahead. Not so good + for Monte Carlo simulations in parallel. + +\end{description} + +%---------------------------------------- +\subsection{Numerical Recipes \texttt{Ran}} +\texttt{Ran} is published in the third edition of Numerical Recipes +\cite{PressEtAl:numericalRecipes} \S 7. According to the authors it is +``our suspenders-and-belt, full-body-armour, never-any-doubt generator'' +and will ``generate all the uniform deviates you will ever need''. +\begin{description} +\item[\GoodThing] + Decently long period ($3.138 \times 10^{57}$). +\item[\PossiblyGoodThing] + Fast% + \footnote{ + The reason for the {\bf ?} is that it appears to be similar to the + Wichmann--Hill generator (discussed next) which is reported to to be + about five times slower than MT. + }. +\item[\GoodThing] + Small state (24 bytes). +\item[\GoodThing] + Passes the standard statistical tests for randomness. +\item[\PossiblyGoodThing] + Not ``overengineered''% + \footnote{ + Numerical Recipes (2007), in a section discussing overengineering, contains + the following advice ``Avoid using generators with period $> + 10^{100}$. You {\em really} will never need it and, above some minimum + bound, the period of a generator has little to do with its quality''. + Clearly, given the widespread use of MT, some people disagree. See also + \cite{James:HighQualityRNGs}(2019) which says (amongst other requirements + for the highest quality), ``Period must be long enough, $> 10^{100}$ ''. + }. + +\item[\PossiblyBadThing] + Not cryptographically secure% + \footnote{ + The section referred to in the previous footnote also advises against + generators that are ``(over)designed for cryptographic use'', but we + should remember that the focus of the book is numerical algorithms for + scientific computing and, from that limited perspective, a + cryptographically secure PRNG might very well be considered as + overengineered. + }. + +\item[\PossiblyBadThing] + No algorithm to advance the state efficiently (for Monte Carlo in parallel). + +\item[\BadThing] + It is {\em licensed}. The license conditions permit personal use if you + own a copy of the Numerical Recipes book (providing you haven't already + helped yourself wholesale to the contents of the book). Commercial users + can purchase a site licence or per-seat licences. It isn't entirely clear + how incorporating it into a copyleft language like Unicon could readily + be achieved. + + Note that the license conditions do not (and cannot) prohibit the + implementation of the {\em ideas} that underly \texttt{Ran}. The section + on licensing in \cite{PressEtAl:numericalRecipes} has the following + statement + \begin{quote} + If you analyze the ideas contained in a program, and then express those + ideas in a completely different implementation then that new program + implementation belongs to you. + \end{quote} + However, it is not clear whether rewriting \texttt{Ran} {\em using the + same operations and magic numbers that give it the good properties it posseses} + constitutes ``expressing those ideas in a completely different + implementation'' or whether we would have to find some different, equally + good, operations and magic numbers. If the latter, we are in the perilous state of + ``rolling our own'' discussed above. + +\end{description} + +%---------------------------------------- +\subsection{Wichmann--Hill 2006 (WH)} +The Wichmann--Hill generator (2006)\cite{WichmannHill:2006} comes from the +UK National Physical Laboratory and is a redevelopment of a much earlier +generator\cite{WichmannHill:1982} that was well thought of in its day, but +overtaken by progress in the field. The 2006 generator carries on the same +approach as the earlier generator but ``beefs it up''. Like \texttt{Ran}, +it is a combination of four simpler generators. +\begin{description} +\item[\GoodThing] + Reasonably long period ($2^{120} \simeq 1.3 \times 10^{36}$). +\item[\PossiblyBadThing] + Not as fast as MT: the authors report a factor of about five slower. +\item[\PossiblyBadThing] + Not cryptographically secure. +\item[\GoodThing] + Small state (16 bytes). +\item[\GoodThing] + Passes the statistical tests for randomness. +\item[\GoodThing] + The random sequence can be efficiently advanced, by jumping ahead. This is + particularly important when doing Monte Carlo simulations in parallel. +\item[\BadThing] + It is licensed. The license is reproduced in Appendix E. The problematic + part is contained in the paragraph ``{\bf\small Other Restrictions}''. As with + \texttt{Ran}, we may be able to implement the ideas without infringing + the license conditions. +\end{description} + +%---------------------------------------- +\subsection{WELL} +The ``Well Equidistributed Long-period Linear (WELL)'' is a family of +pseudorandom number generators invented in 2006 and described in% +\cite{PannetonEtAl:WELL}, which asserts that MT is a ``simplified version'' +of WELL. + +\begin{description} +\item[\GoodThing] + WELL has all of the good properties of MT. +\item [\GoodThing] + Escapes from a bad (mostly zero) state much faster than MT. +\item[\GoodThing] + Better statistical properties than MT with approximately the same performance. +\item[\PossiblyBadThing] + WELL is a family, not a specific generator: we would have to choose which + member of the family to implement. There are at least eighteen choices. +\end{description} + + +%---------------------------------------- +\subsection{Ranlux (Rlx)} +The Ranlux generators were introduced in 1994 by +L\"uscher\cite{Luscher:1994}. They are highly thought of, but considered to +be slow. A second generation, using floating point rather than integer +arithmetic, is available and gives better performance: typically between a +factor of two and four\cite{Luscher:Ranlux2}. All Ranlux generators offer +the user some choice in the trade-off between statistical quality and speed +called {\em luxury}. Higher values of luxury mean better (or very much +better) statistical quality but lower speed. All versions of Ranlux are +incorporated in the GNU Scientific Library\cite{GnuScientificLibrary}. +The generators have a solid theoretical foundation in the theory of chaotic +systems. +\begin{description} +\item[\GoodThing] + Long period ($\simeq 5 \times 10^{171}$). +\item[\PossiblyBadThing] + Slow, especially at high luxury levels. +\item[\PossiblyBadThing] + Fairly large state (384 to 768 bytes, depending on floating point precision). +\item[\GoodThing] + Extremely high quality at the high luxury level. Passes statistical tests + at the default luxury level. +\item[\PossiblyBadThing] + Not cryptographically secure. +\item[\GoodThing] + Different seed values are {\em guaranteed} to give different sequences, + making Monte Carlo simulation in parallel easy to achieve. +\end{description} + +%---------------------------------------- +\subsection{Ranlux++ (Rlx+)} +Ranlux++ is a recent reimplementation of the Ranlux algorithm\cite{Sibidanov:Ranlux++}. +It can generate the same sequences as the original algorithm but is reported +to be an order of magnitude faster {\em and} can achieve even higher luxury +levels. It achieves this by a ``clever algorithm'' +to do multiple precision arithmetic, combined with some assembly level +coding. +\begin{description} +\item[\GoodThing] + Except for speed, it shares all of the properties of Ranlux. +\item[\GoodThing] + Fast, probably comparable with MT +\item[\GoodThing] + Even higher quality than Ranlux, according to\cite{James:HighQualityRNGs} +\item[\BadThing] + Not portable. The algorithm is said to be ``not expressible in a high + level language''. Although it should run on many Intel architecture + machines% + \footnote{ + It is notable that the authors of \cite{James:HighQualityRNGs} say that + it didn't run on their macBook, which is almost certainly an Intel + architecture machine --- unless they're running a + secret new prototype from Apple. + }, + other architectures, e.g. Arm, may be out of luck. +\end{description} + +%---------------------------------------- +\subsection{Trivium (Trv)} +Trivium is from the {\em hardware} profile of the eSTREAM +project\cite{eStream} but, despite that, it can also be implemented quite +efficiently in software, giving comparable performance% +\cite{Bernstein:cypherSpeed} to Rabbit. It is initialized with an 80 bit +key and an 80 bit IV and can encrypt $2^{64}$ {\em bits} with each key/IV +pair. +\begin{description} +\item[\GoodThing] + Decent length period: the authors say it is ``hard to determine'' but is + {\em estimated} at about $2^{80}$. +\item[\GoodThing] + Fast. +\item[\PossiblyGoodThing] + Cryptographically secure. +\item[\PossiblyGoodThing] + It is bit oriented, so if you need a supply of random numbers to go into + your special 27 bit hardware (or 137 bit hardware, for that matter), + Trivium could produce them directly. +\item[\GoodThing] + Comparatively small state (288 bits --- 36 bytes, or 37 if the three + components of the state are not packed). +\item[\PossiblyBadThing] + About 2 exaBytes of randomness may be produced before a new key/IV + pair is required% + \footnote{ + Similar reasons to Rabbit explain the difference between the + period and the interval between required re-key operations. + }: + this equates to about $1.25 \times 10^{16}$ 32 bit integers or half that + number of 64 bit integers. +\end{description} + +%---------------------------------------- +\subsection{Fortuna} +Fortuna is unlike all of the other generators considered here in that it +may be used as a {\em genuine} random number generator accepting inputs +from analog random sources, as opposed to a pseudo random number generator +(although it can also be used as a PRNG). It is described in +\cite{Schneier:PracticalCryptography} \S 10. + +\begin{description} +\item[\GoodThing] + Cryptographically secure, although \cite{DodisEtAl:Entropy} analyses + Fortuna's security and provides an alternative that has better recovery + from a state compromise attack --- which implies, perhaps, that + cryptographic security might be better considered as a spectrum rather + than a binary property. +\item[\BadThing] + It is unclear how an assignment to \rndkwd could produce a repeatable + sequence. The essence of Fortuna is that the numbers are derived from a + source of entropy. The provision of standard test vectors is thus + particularly problematic. + +\item[\PossiblyBadThing] + Fortuna is not so much an algorithm, more a toolkit of techniques from + which a competent implementor may choose in order to achieve a secure + implementation. To be fair, there are recommendations about what choices + to make, but it comes uncomfortably close to ``rolling our own''. + Collecting the entropy to fill the pools used by the algorithm (and + making sure it is available after a restart, but not duplicated) seems + particularly challenging, and will lead to platform dependant code. + +\item[\PossiblyBadThing] + The use case for Fortuna is to generate a comparatively small amount of + high quality random data for use as encryption keys, or similar, rather + than as a general purpose PRNG. In this application, forward secrecy + would be a desirable property. + +\item[\PossiblyBadThing] + Our implementation of Fortuna would require statistical testing. There is + some doubt whether it would stand up to the {\em huge} number of random + deviates that such testing requires, especially if forward secrecy is + desired (which uses a new key after every request). We will exhaust the + available supply of entropy many times over and have to wait for it to be + replenished. The tests might stretch from days to complete to weeks. If + used as a PRNG, we might get away with it. +\end{description} + + +%---------------------------------------- +\subsection{Icon} +To give some idea of how the other candidates compare against the incumbent +PRNG, its advantages and disadvantages are presented here in a similar way +to the others. It's still a respectable choice provided the application +requires neither statistical rigour nor cryptographic security but, like +the earlier Wichmann--Hill generator\cite{WichmannHill:1982}, it has been +overtaken by events. However, to a large extent, the disadvantages of the +current PRNG don't matter: irrespective of how bad it is compared to modern +practice, we are going to include it anyway because of the first item in +the list. +\begin{description} +\item[\GoodThing] + Backwards compatibility. +\item[\BadThing] + A very short period by modern standards + ($2^{31} - 1 \simeq 4.3 \times 10^{9}$). +\item[\GoodThing] + Very fast. +\item[\PossiblyBadThing] + Not cryptographically secure (not even close). +\item[\BadThing] + Fails the statistical tests for randomness. +\item[\PossiblyBadThing] + The Icon PRNG is a linear congruential generator that is a derivative of + the Berkeley 4.2 \texttt{rand} function% + \footnote{ + The multiplicative constant and period are the same, but the additive + constant is different. The Berkeley 4.2 generator isn't well thought of: + even its own manual page describes it as a ``bad random number generator''. + } + and it shares the deficiencies of that function such as not very random + lower order bits. It is possible that a different additive constant was + chosen in an attempt to ameliorate the non-random behavour of the low + order bits% + \footnote{ + If so, the advice from \cite{Knuth:SemiNumerical2} + \S 3.6 was ignored. It says ``The value of (the additive constant) is + immaterial when (the multiplicative constant) is a good multiplier''. + }, but no evidence can be found in the Icon implementation + book\cite{IconImplementationBook} (or subsequent reports): The topic of + how the constants were chosen is not discussed. + +\item[\BadThing] Very small state, which helps with speed but makes + Monte Carlo simulations of dubious value --- see + \cite{PressEtAl:numericalRecipes} \S 7.1. Unsuitability for Monte Carlo + simulations appears to be a general property of any linear congruential + generator, especially if the simulations are conducted in + parallel\cite{ParkAndMiller}. +\item[\PossiblyBadThing] + There is no way to advance the generator to deal with simulations in + parallel (although, given the short period and other problems, that might + not be a very sensible thing to do anyway). +\end{description} + +\section{Which PRNGs should Unicon adopt?} + +``Adopt'' in this context means ``provide as part of the standard Unicon +distribution''. Given the existence of an extensible mechanism to add +generators (so users can add any PRNGs that are thought to be needed) one +possible answer is ``None'': leave it up to the marketplace. + +But, as already mentioned, the existing (Icon) generator is in: no +question. Given its mediocre properties by modern standards, the Icon PRNG +cannot be the only choice; we have to provide a better alternative to act +as the ``workhorse generator''. So which is the best choice? The main +problem, as this section hopes to demonstrate, is that there is no ``best +choice''. In the table below, the generators are ranked from left to right +(where towards the right means better) using several different criteria% +\footnote{ + The reader may disagree with the ordering in some cases --- the point is + not to reach consensus on the individual rankings but to demonstrate that + no one generator consistently outshines the others. +}. + +\newcommand{\gap}{\parbox{1.3cm}{}} +\newcommand{\bx}[1]{\parbox{1.3cm}{\sf #1}} +\noindent +\begin{tabular}{|cccccccc|} +\hline +\multicolumn{8}{|c|}{ +{\small Slower} $\longleftarrow$ {\bf Speed} $\longrightarrow$ {\small Faster} +}\\ +\bx{Rlx} & \gap & \bx{Ran\\WH} & \bx{MT\\Rlx+} & \bx{Rbt\\Trv} & \gap & +\gap & \bx{Icon}\\ +\hline +\multicolumn{8}{|c|}{ +{\small Larger} $\longleftarrow$ {\bf Size} $\longrightarrow$ {\small Smaller} +}\\ +\bx{MT} & \bx{Rlx\\Rlx+} & \gap & \bx{Rbt} & \bx{Trv} & \bx{WH} & \bx{Ran} & \bx{Icon}\\ +\hline +\multicolumn{8}{|c|}{ +{\small Lower} $\longleftarrow$ {\bf Quality} $\longrightarrow$ {\small Higher} +}\\ +\bx{Icon} & \gap & \gap & \gap & \bx{WH\\Ran} & \bx{MT\\Rbt\\Trv} &\bx{Rlx} & \bx{Rlx+}\\ +\hline +\multicolumn{8}{|c|}{ +{\small Shorter} $\longleftarrow$ {\bf Period} $\longrightarrow$ {\small Longer} +}\\ +\bx{Icon} & \bx{Trv} & \bx{WH} & \bx{Ran} & \bx{Rbt} & \gap & \bx{Rlx\\Rlx+} +& \bx{MT}\\ +\hline +\multicolumn{8}{|c|}{ +{\small Less Suitable} $\longleftarrow$ {\bf Parallel Monte Carlo} $\longrightarrow$ +{\small More Suitable} +}\\ +\bx{Icon} & \gap & \bx{Rbt\\Trv\\Ran} & \gap & \gap & \bx{MT\\WH} & \bx{Rlx} & \bx{Rlx+}\\ +\hline +\multicolumn{8}{|c|}{ +{\small Less Permissive} $\longleftarrow$ {\bf Licensing} $\longrightarrow$ +{\small More Permissive} +}\\ +\multicolumn{4}{|c}{\bx{Ran\\WH}} & \multicolumn{4}{c|}{Everything else}\\ +\hline +\multicolumn{8}{|c|}{ +{\small Not Secure} $\longleftarrow$ {\bf Cryptographic Security} $\longrightarrow$ +{\small Secure} +}\\ +\multicolumn{4}{|c}{Everything else} & \multicolumn{4}{c|}{\bx{Rbt\\Trv}}\\ +\hline +\end{tabular} + +\vspace{0.5cm} + +Ranlux++ is an outstanding candidate, it is theoretically well founded and +combines the highest quality and decent speed with a reasonably sized +state. Were it not for its portability problems it could be the choice for +the {\em single} extra PRNG to supplement the existing generator. But its +reliance on machine dependent assembly (and the impossibility of +representing that in a high level language) mean that it must be rejected, +at least for now. + +Fortuna appears aimed at a niche use case that may not justify its +inclusion as part of the generally available algorithms --- and the +difficulties of testing it properly and implementing it securely (security +is, after all, its raison d'\^{e}tre) should not be +underestimated. Portability will also be difficult to achieve. + +Rabbit is a strong candidate that will provide cryptographic security +to the subset of applications for which this is important. It is comparable +in speed to Trivium, but the larger key size and the older creation date% +\footnote{ + Cryptographically secure PRNGs are perhaps an exception to the rule that + older algorithms are less preferable: providing the security has not + been broken, there has been a longer time during which the algorithm has + been subject to scrutiny and attack. + } +make it preferable. + +\texttt{Ran} from Numerical Recipes and Wichmann--Hill are both licensed +and cannot be included as they are. However, if the licensing questions can +be resolved% +\footnote{ + Discussions are underway --- see Appendix D. + } +and it proves to be fast enough, then \texttt{Ran} could fill the r\^ole +of the ``Goldilocks generator''% +\footnote{ + Not too hot, not too cold, just right. +} +--- fast enough, small enough, with decent statistical properties. +If not, the Wichmann--Hill generator will be a worthy +substitute% +\footnote{ + There is an argument for implementing both and testing them, head to + head, for speed and, possibly, for randomness (there is a hint in + \cite{WichmannHill:2006} that their generator might pass more stringent + tests than \texttt{Ran}). Note that randomness testing is computationally + very intensive and might literally take days to complete. +}. +Rabbit might also prove small enough and fast enough to fit the bill and +has the advantage of a permissive license. + +If very high quality is required, Ranlux is the obvious choice amongst +the generators discussed here. It's theoretical foundations mean that it +doesn't have to depend so much on the empirical tests of randomness to +guarantee high quality. Those who need it may be prepared to tolerate its +comparatively poor performance. + +Finally, MT is an excellent candidate, for its good statistical +properties, its reasonably good performance and for the possibility of +compatibility with other software that use it. For this reason we should +probably prefer the 32bit version of MT to the 64bit version, which +generates a different sequence, but further work should be undertaken to +choose the most popular version. WELL is arguably better than MT --- and +either is suitable for Monte Carlo simulations --- but the compatibility +with other software means that MT just edges it. + +The unfortunate user that falls into the ``Zeroland'' problem of a state +that is mostly full of zeroes (and the long escape from it) has a ready +alternative, albeit at the price of rolling up some sleeves and +implementing (or adapting an existing implementation of) WELL. The existing +adaption of MT --- when we have one --- should provide a good model. + +\subsection{The proposed portfolio} +The final list in this draft is thus +\begin{description} +\item[{\sf rngIcon}] + The existing (Icon) generator. +\item[{\sf rngRlx}] + The second generation of Ranlux\cite{Luscher:Ranlux2}. +\item[{\sf rngRbt}] + Rabbit from the eSTREAM (software) portfolio\cite{eStream}. +\item[{\sf rngMT}] + The 32bit Mersenne Twister, modified to improve initialization\cite{ImprovedMT}. +\end{description} + +The overlap between the Mersenne Twister and Ranlux is substantial. If +we were limited to only three generators, then the Mersenne Twister would have +to go: Ranlux would suffice, albeit more slowly. If there were just two, +then Rabbit would be next for the chop (sic). We would have to hope that +Ranlux at the lowest luxury level would prove fast enough if the +application demands more than the Icon generator can supply. + +Note that this portfolio is provisional. If Ranlux makes it into the final +set of choices then we will have to solve the problem of how to supply the +user's choice of luxury to the runtime system. The simplest (and easiest) +way is to supply different libraries for each of the three defined luxury +levels. But if only one Ranlux library is wanted, further thought will be +needed. + +\subsection{What next?} +It is proposed to implement all of the generators in the portfolio. They +will be used to refine the PRNG interface discussed below and we will be +able to establish a better idea of comparative performance in the situation +that we propose to employ them. In particular, we need to find out if +Rabbit can indeed act as our ``workhorse generator'' or if we must find +something a bit more lightweight (such as \texttt{Ran} or Wichmann--Hill). + +By the time the generators in the portfolio are implemented and tested, it +will be clear whether \texttt{Ran} and/or Wichmann--Hill may be included in +the portfolio or whether they must be discarded for licensing reasons. It +will also be clear if they (or alternatives with similar characteristics) +are necessary. + +%\newpage +\section{A proposed implementation} +This section describes a proposed implementation that enables the user to +choose between the available generators and to add additional ones. +Appendix A has a discussion of alternative ways to achieve the same end: In +particular, this draft assumes a new keyword is defined, but it might +turn out that a new standard function is the preferred option. + +\subsection{A new keyword} +A new thread-specific keyword \rndlibkwd specifies the +name of a dynamically loaded library that contains the functions +necessary to implement the PRNG. Assignment to \rndlibkwd loads the library. + +To allow the program to revert to the Icon generator, the implementation +behaves as if \rndlibkwd\texttt{:=~"rngIcon"} specifies a real library +(even if the file doesn't actually exist because the Icon PRNG is +built-in). + +Programs that specify a library that doesn't exist, and +isn't \texttt{"rngIcon"}, should fail with system error +\UniconError{1002}{No such file or directory} +% +If the file exists, but there is something wrong with it (for example, it +isn't a dynamic library) the program should fail with system error +\UniconError{1022}{Invalid argument}. +% +If a required function within the library is missing, the program should +fail with system error \UniconError{1038}{Function not implemented}. + +The value of \rndlibkwd is whatever a successful assignment sets it to. So +the following Unicon program +\begin{verbatim} +procedure main() + write( &rnglib ) +end +\end{verbatim} +would output the string \texttt{rngIcon} --- because no assignment to +\rndlibkwd has been made, the default PRNG is in use. + +\subsection{Changes to \rndkwd} +To allow different PRNGs to have different requirements for +initialization, the type of \rndkwd is changed from \texttt{integer} +to \texttt{any}. The assignment may fail if the PRNG doesn't like what is given to it +as the starting seed. + +If the assignment fails, the most generic value for \texttt{\&errno} is +\UniconError{113}{Invalid type to random operation}, +but it may be possible to be more helpful and set \texttt{\&errno} to one +of the values between \UniconError{101}{integer expected or out of range} +and \UniconError{110}{string or list expected} or something else that +describes the problem more specifically. + +Reading the value of \rndkwd may also fail: +In particular, when using a different PRNG, it would be unwise to assume that the following +code will give the expected result. +\begin{verbatim} + x := &random # Save the current point in the random sequence + ... generate some random numbers + &random := x # Restart at the previous point + ... generate the same sequence again +\end{verbatim} + +\begin{samepage} +\noindent + Obviously +\begin{verbatim} + &random := x + ... generate some random numbers + &random := x # Restart at the previous point + ... generate the same sequence again +\end{verbatim} +will work just as before, using any PRNG (assuming \texttt{x} has a valid +value for the generator that is in use). +\end{samepage} + +If \rndkwd is not initialized before using the random operator, the +effect is dependent on the particular PRNG --- although the +recommendation is that the starting seed be set to an arbitrary value +that varies between runs of the program (as at present). + + +\subsection{The PRNG interface} +Each PRNG library should conform to a standard interface so the Unicon +run-time system can use it conveniently without special case code. The +interface must be bidirectional: data will be passed both to and from the +PRNG. The API is described in Appendix B. + +\subsection{Error Codes} +Five new error codes may be used by a PRNG to indicate specific +problems. The PRNG must provide the text used for \texttt{\&errortext} +if it uses the new error codes. + +\section{Verification} +How do we know that the ``random'' output of the new PRNG is correct? +Clearly, some independently produced test vectors are required. If the +implemented PRNG reproduces the vectors then a full battery of statistical +tests won't be needed. + +\subsection{Icon} +If the current PRNG is not reimplemented as a library then, arguably, +nothing has changed so verification is not needed. If we want extra +assurance, then we can use an Icon --- n.b. Icon% +\footnote{ + Using Icon lets us test backwards compatibility with Icon for free and + removes any doubt that the new work to implement several PRNGs might have + altered things. +}, +not Unicon --- system to generate as many test streams as we need and +compare the results. We can also include the generator program so that the +correctness of the vectors themselves can be verified. + +\subsection{Rabbit} +Official test vectors are available. + +\subsection{Ranlux} +Official test vectors are available. + +\subsection{Mersenne Twister} +Official test vectors are available. + +\subsection{Numerical Recipes \texttt{Ran} and Wichmann--Hill} +We may not need test vectors for these generators, especially if the +licensing discussions do not conclude satisfactorily. If we need test +vectors they are available, albeit not as conveniently. +\subsubsection{Numerical Recipes \texttt{Ran}} +Neither \cite{{PressEtAl:numericalRecipes}} nor the accompanying CD +contains test vectors for any of the PRNGs in the book. Searching online +has also come up empty handed; but the internet is a big place and something +may yet turn up. + +In the absence of official test vectors it is possible to produce some +unofficial tests. The author's personal license permits the incorporation +of \texttt{Ran} directly from the CD into a test vector generation program +and this can be used to produce as much test data as we need. There are no +licensing restrictions on incorporating this data into the Unicon +distribution. We could even include the executable files for popular +platforms. + +Unfortunately, the license does {\em not} permit the entire source of the +test vector generator to be published --- although the rest of the code +(sans \texttt{Ran} itself) can be put into the Unicon distribution, meaning +that anybody with a copy of the book and a C++ compiler would be +able to assure themselves that the vectors are correct. + +\subsubsection{Wichmann--Hill} +\cite{WichmannHill:2006} does not contain test vectors, nor example +code. NPL have reorganized their web site (possibly several times) since +the original work was done and most references to the generator end up with +``404''. However, a +reference implementation is still available at +\surl{http://resource.npl.co.uk/docs/science_technology/scientific_computing/ssfm/documents/wh_rng_version096.zip} +and, if that stops working, the ``WayBack Machine''\cite{WayBack} has copies. +The zip file does contain test vectors. + +\subsection{Tests for all generators} +\begin{itemize} +\item + Test reinitialization with the same seed produces the same stream again. +\item + Test that a program with no explicit initialization produces different + output on different runs. +\item + Test generation in parallel. +\item + Test different generators in use at the same time. +\item + Reproduce the test vectors. +\end{itemize} + +Possible differences in floating point arithmetic mean that there is a tiny +pitfall in the last item of this test plan. To get uniform deviates in a +particular range, the Unicon runtime first converts the 31 random bits +returned by the linear congruential generator into a floating point value +in the range [0,1) --- in future it will call \texttt{getRandomFpt()} to +achieve the same effect. If the hardware does not provide IEEE 754 +compliant arithmetic, or provides it imperfectly% +\footnote{ + For example, the default rounding is not ``Round to nearest, ties to + even''. + } +then it's possible that different results might be obtained on different +machines when using the random operator% +\footnote{ + What has to happen is that the model numbers on each machine fall either + side of 0.5 so they round differently, or the rounding rules are + different on the two machines. +}. +Conceivably, even the test vectors might be different if we are +sufficiently unlucky. Note that the random sequence won't diverge on +different machines. If we ever hit this problem then the worst that will +occur is a vanishingly small proportion of the numbers in the random +sequence of integers will differ by one. + +It seems Draconian, to say the least, to demand that an individual porting +Unicon to a machine that does not use IEEE 754 floating point arithmetic to +provide a full emulation of it so that the random operator works as +expected. + +We could avoid this problem by using a different method to produce +uniform deviates that doesn't involve floating point, but that is a +non-starter for the Icon PRNG because it would {\em guarantee} that the +random sequences produced would differ from previous versions of Unicon and +Icon given the same starting seed% +\footnote{ + If we want to, we can avoid floating point methods for producing uniform + deviates when using the other PRNGs because there is no ``backwards'' to + be compatible with. +}. + +It is proposed, for essentially pragmatic reasons, to ignore the +problem. The near ubiquity of IEEE 754 compliant systems --- or systems +which say they are compliant --- means that a different set of model +numbers is very unlikely to be encountered in practice. Thus any +differences would have to come from an incorrect implementation {\em and} +we would have to land on a number where it made a difference. + +\subsubsection{Reproduction of test vectors} + +\label{rawBits} +The usual interface to the PRNG when producing random results --- a uniform +floating point deviate in the range $[0,1)$ --- is not condusive to the +checking of standard test vectors, which requires access to the raw bits +rather than any converted version of them. Although it might be possible to +``reverse engineer'' the raw bits from the uniform deviates, it would be +simpler and better to provide access to the raw bit stream directly. There +are also some applications other than verification --- encryption is the +notable example --- where access to the raw bitstream would be much more +convenient than a sequence of random values. + +\section{Conclusions} + +The progress made in the field of random number generation since the +existing PRNG was defined certainly warrants a change, but backwards +compatibility with previous Unicon and Icon systems leads to its +continuing availability alongside alternative generators. Making it +the default choice is another inevitable consequence of backwards +compatibility. + +The language extensions for an extensible choice of PRNGs are small: +\begin{itemize} +\item A new thread-specific keyword \rndlibkwd to control which PRNG is in use. +\item The possibility of assignment to \rndkwd (and reading its value) + failing, plus a change in its type from \texttt{integer} to \texttt{any}. +\item A small number of additional values to \texttt{\&errno} (and + associated keywords like \texttt{\&errortext}). +\item A new standard function to provide access to the raw random bit stream. +\end{itemize} +None of these changes affects backwards compatibility: An Icon program that +used to run on a previous release of Unicon will continue to run and give +the same results as before. + +The choices made mean that the user has access to the original PRNG, a +decent quality modern equivalent, a generator that is particularly suitable +for Monte Carlo work and a cryptographically secure option. The provision +of a small number of alternatives to the existing PRNG should cover a large +number of possible applications but, when% +\footnote{ + The author would like to say ``if'' here, but knows that ``when'' is + correct. + } +they prove insufficient, the user may install a PRNG that is more suited +to the task at hand. + +Appendix F contains some preliminary performance figures. + +\begin{thebibliography}{99} + +%---------- Pre 1980 +%---------- 1980 +%---------- 1981 +\bibitem{Knuth:SemiNumerical2} +\begin{samepage} + Knuth D.E.\\* + "Seminumerical Algorithms'', Second edition. Volume 2 of ``The Art of Computer + Programming'' + (Adison Wesley 1981) +\end{samepage} + +%---------- 1982 +\bibitem{WichmannHill:1982} + Wichmann B.A, Hill I.D. (1982). "Algorithm AS 183: An Efficient and + Portable Pseudo-Random Number Generator". + Journal of the Royal Statistical Society. Series C (Applied Statistics). 31 (2): 1 88–190. + +%---------- 1983 +%---------- 1984 +%---------- 1985 +%---------- 1986 +\bibitem{IconImplementationBook} +\begin{samepage} + Griswold R., Griswold M.\\* + ``The Implementation of the Icon Programming Language'' + Available via \surl{https://www2.cs.arizona.edu/icon/ftp/doc/ib1up.pdf} +\end{samepage} + +%---------- 1987 +%---------- 1988 +\bibitem{ParkAndMiller} +\begin{samepage} + Park S.K. and Miller K.W\\* + ``Portable Random Generators: Good Ones Are Hard To Find''. + Communications of the ACM (1988) Vol 31, pp 1192-1201 +\end{samepage} + +%---------- 1989 +%---------- 1990 +%---------- 1991 +%---------- 1992 +\bibitem{PressEtAl:numericalRecipes-2} +\begin{samepage} + Press W.H., Teukolsky S.A., Vetterling W.T., Flannery B.P.\\* + ``Numerical Recipes in C, second edition'' (Cambridge University Press 1992). +\end{samepage} + +%---------- 1993 +%---------- 1994 +\bibitem{Luscher:1994} +\begin{samepage} + L\"uscher M.\\* + ``A Portable High-Quality Random Number Generator for + Lattice Field Theory Simulations'' + Computer Physics Communications 79(1994) 100 - 110 +\end{samepage} + +%---------- 1995 +\bibitem{Marsarglia:Diehard} + Marsarglia G.\\* + ``The Marsaglia Random Number CDROM including the Diehard Battery of Tests + of Randomness''\\* + Available from \surl{http://www.stat.fsu.edu/pub/diehard}\\* + Use the wayback machine\cite{WayBack} and get a copy from circa 2015 or before. + +%---------- 1996 +\bibitem{IconBook} +\begin{samepage} + Griswold R., Griswold M.\\* + ``The Icon Programming Language (Third Edition)'' + Available via \surl{https://www2.cs.arizona.edu/icon/ftp/doc/lb1up.pdf} +\end{samepage} + +%---------- 1997 +%---------- 1998 +%---------- 1999 +%---------- 2000 +%---------- 2001 +%---------- 2002 +\bibitem{ImprovedMT} +\begin{samepage} + ``Mersenne Twister with improved initialization''\\* + Available from\\* + \surl{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html} +\end{samepage} + +%---------- 2003 +\bibitem{Schneier:PracticalCryptography} +\begin{samepage} + Schneier B. and Ferguson N,\\* + ``Practical Cryptography'' + John Wiley and Sons (2003) +\end{samepage} + +%---------- 2004 +%---------- 2005 +%---------- 2006 +\bibitem{WichmannHill:2006} + Wichmann B.A, Hill I.D.\\* + ``Generating good pseudo-random numbers'' + Computational Statistics \& Data Analysis 51 (2006) 1614 – 1622. + +\bibitem{McCullough:TESTU01} + McCullough B.D.\\* + ``A review of TESTU01''. + Journal Of Applied Econometrics (2006) 21: 677 – 682 + +\bibitem{PannetonEtAl:WELL} +\begin{samepage} + Panneton F., l'Ecuyer P., Matsumoto M. (March 2006).\\* + "Improved long-period generators based on linear recurrences modulo~2".\\* + ACM Transactions on Mathematical Software. 32 (1): 1–16. +\end{samepage} + +%---------- 2007 +\bibitem{PressEtAl:numericalRecipes} +\begin{samepage} + Press W.H., Teukolsky S.A., Vetterling W.T., Flannery B.P.\\* + ``Numerical Recipes, third edition'' (Cambridge University Press 2007). +\end{samepage} + +\bibitem{Schneier:BackDoor} +\begin{samepage} + Schneier B.\\* + ``Did NSA Put a Secret Backdoor in New Encryption Standard?''\\* + Wired : November 15 2007. Available from\\* + \surl{https://www.schneier.com/essays/archives/2007/11/did_nsa_put_a_secret.html} +\end{samepage} + +\bibitem{L'Ecuyer:TESTU01} + Pierre L’Ecuyer P, Simard R\\* + "TestU01: A Software Library in ANSI C for Empirical Testing of Random + Number Generators", + ACM Transactions on Mathematical Software (2007), 33: 22. + +%---------- 2008 +\bibitem{Matsumoto:MersenneTwister} +\begin{samepage} + Matsumoto M, Nishimura T.\\* + "Mersenne Twister: a 623-dimensionally equi-distributed uniform + pseudo-random number generator".\\* + ACM Transactions on Modeling and Computer Simulation (1988). ACM. 8 (1): + 3–30.\\* + Available from\\* + \surl{http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/mt.pdf} +\end{samepage} + +\bibitem{HiroshiEtAl:EfficientJumping} +\begin{samepage} + Hiroshi Haramoto H.; Makoto Matsumoto M.; Takuji Nishimura T.; Panneton F.; + Pierre L’Ecuyer.\\* + "Efficient Jump Ahead for F2-Linear Random Number Generators"\\* + Available from\\* + \surl{http://www.iro.umontreal.ca/~lecuyer/myftp/papers/jumpf2.pdf} +\end{samepage} + +\bibitem{eStream} +\begin{samepage} + The home page of the eSTREAM project is at\newline + \surl{https://www.ecrypt.eu.org/stream/index.html} +\end{samepage} + +\bibitem{Bernstein:cypherSpeed} +\begin{samepage} + Bernstein D.\\* + ``Which phase-3 eSTREAM ciphers provide the best software speeds?'' + Available via \surl{cr.yp.to/streamciphers/phase3speed-20080331.pdf}. +\end{samepage} + +%---------- 2009 +%---------- 2010 +\bibitem{BassinghamEtAl:Statistical} + Bassingham L. et al\\* + ``A Statistical Test Suite for Random and Pseudorandom Number Generators + for Cryptographic Applications'' + Available from\\* + \surl{https://csrc.nist.gov/publications/detail/sp/800-22/rev-1a/final} + +%---------- 2011 +%---------- 2012 +%---------- 2013 +%---------- 2014 +\bibitem{Brown:Dieharder} + Brown R.G, EdelBuettel D, Bauer D\\* + ``Dieharder: A Random Number Test Suite'' + Available from\\* + \surl{https://webhome.phy.duke.edu/~rgb/General/dieharder.php} + +\bibitem{DodisEtAl:Entropy} +\begin{samepage} + Y. Dodis, A. Shamir, N. Stephens-Davidowitz, D. Wichs\\* + ``How to Eat Your Entropy and Have it Too---Optimal Recovery Strategies for + Compromised RNGs', + Cryptology ePrint Archive, Report 2014/167, 2014. +\end{samepage} + +\bibitem{Knuth:SemiNumerical3} +\begin{samepage} + Knuth D.E.\\* + "Seminumerical Algorithms'', Third edition. Volume 2 of ``The Art of Computer + Programming'' + (Adison Wesley 2014) +\end{samepage} + +%---------- 2015 +%---------- 2016 +%---------- 2017 +\bibitem{Sibidanov:Ranlux++} + Sibidanov A.\\* + ``A revision of the subtract-with-borrow random numbergenerators'', + Comput. Phys. Comm. 221 (2017) 299-303 + Code available from \surl{https://github.com/sibidanov/ranluxpp/} + +%---------- 2018 +\bibitem{GnuScientificLibrary} +\begin{samepage} + GSL -- the GNU Scientific Library\\* + Available from \surl{https://www.gnu.org/software/gsl} +\end{samepage} + +%---------- 2019 +\bibitem{James:HighQualityRNGs} +\begin{samepage} + James F. and Moneta L.\\* + ``Review of High-Quality Random Number Generators'' (March 2019)\\* + Available from \surl{https://arxiv.org/pdf/1903.01247.pdf} +\end{samepage} + +\bibitem{Luscher:Ranlux2} +\begin{samepage} + L\"uscher M.\\* + ``User's guide for ranlxs and ranlxd v3.4'' (May 2019) + Available from \surl{http://luscher.web.cern.ch/luscher/ranlux} +\end{samepage} + +\bibitem{CplusplusStd:N4820} +\begin{samepage} + Working Draft, Standard for Programming Language C++\\* + Document N4820 (July 2019)\\* + Available from \surl{https://github.com/cplusplus/draft/raw/master/papers/n4820.pdf} +\end{samepage} +%---------- 2020 + +\bibitem{WayBack} + The Internet Archive ``WayBack Machine'' is available at\\* + \surl{https://web.archive.org} + +\end{thebibliography} + + +\bibliographystyle{abbrv} + +\appendix +\renewcommand{\thesection}{Appendix \Alph{section}} +\pagebreak +\section{Implementation choices} +This appendix discusses the options that are available when +implementing a system that supports more than one PRNG. +\subsection{How to choose the generator} +One way to choose the generator is a compiler switch that governs +which of the (standard) generators should be used. This option is +unattractive for several reasons: +\begin{itemize} +\item It is not readily extensible by the user. +\item It isn't obvious, by reading the source code, which PRNG is in use. +\item It doesn't easily% + \footnote{ + We might be able to achieve it by specifying a different generator in + separate compilations and combining them into one program, but that + seems an uneccessarily complicated way of doing things. + } + allow the possibility of two (or more) PRNGs being in use --- either + simultaneously or consecutively. +\end{itemize} +The same considerations also apply to implementing the choice via a new +switch to \texttt{iconx}, with the provision of multiple PRNGs seeming +particularly intractable. + +It is clear that the choice must be made at run time via something that is +visible in the source code. We could introduce the notion of a pragma into +the language, but that seems an unecessarily large hammer with which to +crack this particular nut; especially when an alternative mechanism exists +that is {\em already} commonly used to affect program behaviour: the +keyword. + +A new keyword \rndlibkwd is proposed. It specifies the name (without a +path, prefix or suffix) +of a dynamically loaded library that contains the functions necessary to +implement the PRNG. The reason for removing path, standard prefix and +suffix is so that the same string can be used on different systems (with +different conventions on how to name or locate libraries% +\footnote{ +For example: On a macOS system, if the library to implement the Mersenne +Twister was located in \surl{/Users/Don/Unicon/bin/librngMT.so}, the +assignment \rndlibkwd\texttt{:=~"rngMT"} would be sufficient to load and +initialize the library. On a Microsoft Windows system, the location might be +\surl{c:\users\don\unicon\bin\rngMT.dll}, but the same assignment to +\rndlibkwd would still work. +}) without modification. + +It is an open question whether the previous standard PRNG should be +reimplemented as a dynamically loaded library or retained in it's current, +built-in form. In either case, we will have to come up with a standard name +for it, so that programs which use a new PRNG, but wish to revert to the +old algorithm, can do so. For the present, it is suggested that the +implementation behaves as if \rndlibkwd\texttt{:=~"rngIcon"} specified a +real library, even if the file doesn't actually exist because the Icon PRNG +is built-in. + +Another open question is how to bundle dynamically loaded libraries into a +standalone executable file. + +\subsubsection{Could the PRNG be a plugin?} +The mechanism proposed above shares many characteristics with Unicon's +plugin facility but there are also some differences; notably, a plugin is +used by Unicon code to interface with dynamically loaded routines whereas a +PRNG is used by the run-time and the two have a more intimate bidirectional +connection. + +It is worth exploring further whether implementing a PRNG as a plugin is +possible and, if so, whether there are advantages to doing so. + +\subsection{Changes to \rndkwd} +Different PRNGs have different requirements for initialization. The seed +material might be large, or have several more or less independent +components. Fitting this into an integer, even a large integer, is +problematic. Rather than prescribe the type of the value that may be +assigned to \rndkwd it seems sensible to change it to \texttt{any} and to +allow the assignment to fail if the PRNG doesn't like what is given to it +as the starting seed. Relaxing the type of the seed value allows PRNGs that +have different components to specify the seed value as a record, whereas if +the requirement is just for a huge string of bits, it could be implemented +by supplying the PRNG with an array of \texttt{integer} values. +Note that if the original generator is in use (\rndlibkwd \verb/== "rngIcon"/) +then the return type of \rndkwd must be the same as before to avoid +breaking existing code. + +\subsubsection{Saving and restoring PRNG state} +It would be useful to be able to save the PRNG state and subsequently to +restore it, perhaps in a different run of the program. Using the value of +\rndkwd to return the state is an obvious idea but it may lead to some +non-obvious consequences. For example, if the PRNG does a substantial +amount of work to derive the state from the seed then after the program +fragment +\begin{verbatim} + &random := x + y := &random +\end{verbatim} +it's possible that \verb/x/ will be nothing like \verb/y/ --- one +might be an integer, the other might be an array of 193 integers. The +effect on the type inferencing performed by the compiler will +need to be considered. + +Unfortunately, changing the return type of \rndkwd breaks existing code: +here is an extract from the unicon compiler's utility routines (inside the +procedure \verb/tempname/ in the routine \verb/io.icn/) +\begin{verbatim} + repeat { + ?1 # change &random + name := prefix || left(&random, 8, "0") || suffix + if not exists(name) then return name + } +\end{verbatim} +It's expecting \rndkwd to return an integer; an array won't do. So, for the +default case where the library has not been changed, the return value from +\rndkwd {\em must} be an integer ( more accurately, must be of type +\verb/T_Kywdint/). + +It also becomes necessary for the runtime to distinguish between an +assignment to \rndkwd which is intended to set a new seed (which might +involve the PRNG calculating a new state) and an assignment that is +intended to restore the state to a previous condition (which might not +involve the PRNG at all). It would also be very helpful to detect the error +of restoring the state of a different generator to a new one. +\begin{verbatim} + &rnglib := "rngMT" + ... generate some random numbers + x := &random + &rnglib := "rngRbt" + &random := x # We want to detect an error at this point. +\end{verbatim} +Whatever is proposed, it should be able to survive a round trip through the +file system (i.e. programs which save the PRNG state to a file then, on a +different run, attempt to restore that state to a different generator should +also fail). Storing just the ``raw'' state will not suffice; it will have to +be labeled% +\footnote{ + The requirement to survive a round trip through the file system probably + rules out implementing the label solely by a ``PRNG state'' bit in the + descriptor of the variable that holds the state. +} +by the runtime in some way. + +Should the PRNG be able to {\em prohibit} its state from being visible to the +application program? There are some arguments for this --- mostly coming +from a governmental or ``three letter agency'' perspective --- to do with +security, but it is difficult to see why it should be needed in the world +in which Unicon programs run. If required, we can easily implement it via an +extra routine in the API to grant permission to copy the state. + +\subsubsection{Reversible assignment} +The reversible assignment (and reversible swap) operators will require the +old value of \rndkwd to be stored. This means we can no longer use a type +of \verb/T_Kywdint/ to represent the type of \rndkwd in cases where the +generator is not \verb/"rngIcon"/. + +\subsection{is the PRNG global or thread-specific?} +\rndkwd is thread-specific (and that won't change). Should \rndlibkwd also +be thread-specific? There is no immediately obvious reason why it must be: +there could just be one global PRNG in use at any one time; but a little +thought soon leads to difficulties with a global PRNG. Consider what +happens when \rndlibkwd changes; what happens to threads that are using the +previous PRNG? Various options spring to mind: +\begin{itemize} +\item + Subsequent uses of the random operator fail in threads that were using a + different PRNG. +\item + The threads silently switch to the new generator (what happens to the + PRNG state?) +\item + The threads carry on using the old PRNG. +\end{itemize} +The first option isn't particularly attractive --- applying the rule +blindly would mean that the PRNG could only be changed once, before any use +had been made of the default generator; the second option isn't much +better, especially if a thread tries to reinitialize the PRNG with an +inappropriate assignment to \rndkwd, and the third option means that the +PRNG isn't global after all. We might as well make \rndlibkwd +thread-specific from the start and allow different PRNGs to be used in +different threads by making an assignment to \rndlibkwd after the thread +has been started% +\footnote{ + This has implications for thread creation: when the thread is created, we + may not know what provision to make to store the state of the PRNG. We + could just allow enough space for the largest (MT) or, if that is thought + to be too wasteful, perhaps we could allow enough space for a ``small'' + state (such as Rabbit) and allocate dynamically if any PRNG needed more than + that. Dynamic allocation will be needed in the general case because + future PRNGs added by the user will have an unknown space requirement. +}. +\subsubsection{Can the same thread use two PRNGs?} +The short answer is ``No''. The slightly longer answer is that two (or +more) PRNGs may be used consecutively in the same thread, one after +another, but each switch to a different generator can only be achieved by +assignment to \rndlibkwd, which will cause the generator to be +(re)initialized: there is no way to mix results from different random +sequences using a single thread. To achieve that, use two (or more) +threads, each with its own generator, and in another thread ask for random +values using the message passing facilities. Using a co-expression will not +work: all co-expressions within a thread share the same generator (as at +present). + +\subsection{Access to the raw bitstream} +The need for access to the raw bitstream was mentioned on page +\pageref{rawBits}. This section discusses how to provide such access. The +issues come down to three questions +\begin{itemize} +\item How to return the raw bits to the application (i.e. the type of the + output). +\item How to specify how many bits are needed. +\item How to control whether raw or normal output is produced. +\end{itemize} + +\subsubsection{The type of raw output} +The raw output could, literally, be a string of \texttt{"0"} and \texttt{"1"} +characters. This is the most general form, which makes no assumptions about +word size, but is probably not the most useful: in practice, a numeric type +(or a type containing numeric types) is more likely to be wanted. A string of +ones and zeros can easily be converted to a numeric value +\begin{verbatim} + number := integer("2R" || bitstring) +\end{verbatim} +but that seems an unnecessary, and inefficent, way of doing things if +numbers are wanted in most cases. + +Although a scalar value might be the most efficient type, it won't deal +with the case where more bits are needed than will fit into the scalar. It +seems better to specify a list of numbers (in practice, an integer array) +as the type of raw output. The array will have as many elements as is +needed to hold the requested number of bits. + +\subsubsection{Controlling whether raw output is produced} +One possibility would be to switch between the usual output and raw output +via a new keyword (for example {\sf \&rawbits}), analogous to the way that +{\sf \&error} switches between failure or runtime error. +When {\sf \&rawbits} is set, the random operator produces a bit stream, +rather than the usual values. Such a keyword would probably have to be +thread specific, rather than global. + +Another question is whether the switch setting survives the loading of a +new generator or is reset to the default value upon load. Specifying how +many bits to return on each invocation could be achieved by assigning a +numerical value to {\sf \&rawbits} with zero meaning the default of +whatever is best for the generator% +\footnote{ + Many generators produce their random output in fixed sized chunks --- + Trivium is a notable counter-example --- and it is much more efficient to + consume random bits in the natural chunk size of the generator. + } +and a negative value meaning revert to the default output. + +If we want to provide a bitstring output as well as a numeric output, there +doesn't appear to be any alternative to yet another keyword. + +A final complication is that we will have changed the type returned by the +random operator, which means the information that controls the compiler's +type inferencing must be altered. + +An new standard function is the alternative to a new keyword changing the +behaviour of the random operator. It's probably clearer --- there is no +need to track which way the output switch is set when reading the code --- +and it's certainly easier to implement. We can easily specify how many bits +are needed by adding a \texttt{bits} parameter, with \texttt{0} meaning the +default of whatever is best for the generator. If it were thought useful to +provide the bitstring output as well as a numeric output, two functions +would be needed rather than one. + +\subsection{What happens if \rndkwd is not initialized?} +Under these proposals, if no assignment has been made to \rndlibkwd then +what happens is exactly the same as before: the seed is set to a random +integer value. However, if a successful assignment to \rndlibkwd has been +made (and the value isn't \texttt{"rngIcon"}) the run-time doesn't know how +to initialize the generator, so it cannot supply a suitable seed value. + +If an attempt is made to read the generator state using \rndkwd before any +initialization has occurred then, for all generators except the Icon +generator, it is proposed the attempt should fail. Thus +\begin{verbatim} +procedure main(args) + &rnglib := args[1] | exit() + write("The state is ", &random | "unknown") +end +\end{verbatim} +will always produce {\sf The state is unknown} (or nothing at all) unless +the program argument happens to be {\sf rngIcon}. + +If the random operator is used before \rndkwd has been assigned we could +follow the philosophy adopted by Icon and start from a ``zero'' value but +some generators may not allow a zero starting state and in others it can +produce startlingly bad results. It seems more +consistent to adopt the Unicon approach and start from a ``random'' state: +the PRNG can either derive the initial randomness by itself or, perhaps +better, call the \texttt{getInitialBits} routine (defined below) to get the +run-time to supply some random data using the same method as at present% +\footnote{ + The run-time system calls the routine \texttt{getrandom} which ``attempts + to use the same algorithm as in \surl{ipl/procs/random.icn}''. +}. +More than one call of \texttt{getInitialBits} may be required, depending on +how much initial state is to be initialized. + +Note that there is no guarantee that \texttt{getInitialBits} will return a +different value on successive calls% +\footnote{ + If this constitutes a problem for a particular PRNG, there is a simple + technique to mitigate it: use the value to XOR a longer sequence (for + example the hexadecimal encoding of ``Mary had a little lamb, its's + fleece as white \ldots'' to get a longer random sequence of bits. Other, + and probably better, techniques are available. +}. +Using \texttt{getInitialBits} is only required if \rndkwd has not been +initialized after setting \rndlibkwd and the random operator is used% +\footnote{ + The initialization of the PRNG need not be performed when the library is + loaded, especially if it is expensive. It may be deferred until \rndkwd + is assigned a value or until the first use of the random operator. +}. + +Note that leaving the decision about what to do to the generator means +that the program behaviour when \rndkwd isn't used depends on the PRNG +in use, which might be thought unsatisfactory but it's inevitable given +the runtime doesn't know how to initialize the generator. + + +\subsection{Is a new keyword really necessary?} +In this section, two alternatives to a new keyword are considered: +\begin{itemize} +\item + Overloading an assignment to \rndkwd to select the PRNG library. +\item + A new standard function. +\end{itemize} + +\subsubsection{Overloading assignment to \rndkwd} + +We have seen that the type of \rndkwd must be extended to allow for the +different (and unknown) initialization needs of future PRNGs. Could we also +use an assignment to \rndkwd to select the PRNG library by assigning a +special value? Most of Unicon's types do not readily lend themselves to the +task of specifying a library file but three could conceivably be put to +use: strings, files, and patterns. + +Assigning a string value to \rndkwd is possible candidate: we could either +ban the initialization of a PRNG using a string value altogether, or +special case the values so that (for example) if any string begins with +``\texttt{library:=}'' the rest of the string is taken to be a specification +of the library to be loaded. + +Another alternative would be an open file --- the program would open the +library file and assign the file value to \rndkwd. The run-time stores the +name of the open file in the file descriptor so, in principle, it would be +able to reload the file as a dynamic library. + +It's hard to see how a pattern literal could be used to supply a seed +value, so appropriating pattern values to specify a library wouldn't be a +great inconvenience and would not require special case values. +One could also interpret +\begin{verbatim} + &random := +\end{verbatim} +to mean load the WELL generator or, if that can't be found, load the +Mersenne Twister. + +Beauty is in the eye of the beholder, but none of these options is very +attractive. They all have the disadvantage that, if \rndkwd is used +subsequently to supply a starting seed to the PRNG, there is no mechanism +supplied by the language to find out what library is in use: Of course, the +program could always store the value somewhere else and refer to it when +needed. + +Disallowing strings as initialization values seems capricious (one viable +use of strings might be making a secure hash of the string inside the +library and using those bits to initialize the generator) and a special +case string that looks like an assignment is downright ugly% +\footnote{ + It also leads to questions about white space: + % + is \texttt{\rndkwd := "library :=rngIcon"} a normal string to be passed + as a seed value, or will it select the default generator? + % + Does \texttt{\rndkwd := "library:= rngMT"} mean that the name of the + specified library has a leading space? + % + An alternative prefix that doesn't involve what looks like an assignment + operator may solve these problems, but it's still ugly. +}. + +If a file value is used then the user program will have to reinvent any +mechanisms for searching along standard paths to locate the file. Using a +file value also precludes a design where the initialization data itself is +actually in an open file and supplied to the PRNG that way. Granted, using +a pipe or a file to feed seed data into a Unicon program is unlikely to be +very common, but it will be more difficult% +\footnote{ + It's easy enough if the amount of data is fixed: just read it in and + assign it to \texttt{\rndkwd} as normal. But if the PRNG itself decides + how much data it wants, it's not quite so easy. To be fair, this + objection also applies to any assignment to \texttt{\rndkwd}that isn't a + file value. + + Note that nothing stops a user from implementing a PRNG that is + initialized with a variable amount of data using a file value, providing + we don't appropriate the mechanism to load the library. It's not for the + faint-hearted though, and will require a good understanding of the + implementation of I/O in Unicon's run-time system. +} +if we appropriate file values as a way of loading the PRNG library. + +Pattern literals are more difficult to dismiss out of hand, but they entail +a great deal of complication for not much extra benefit. The example given +above can just as easily be coded as +\begin{verbatim} + &rnglib := "rngWELL" | "rngMT" +\end{verbatim} +with no loss of clarity or concision. + +A minor inconvenience is that libraries with a special character in their +name that means something to the pattern matcher --- ``.'' and ``-'' are +notable examples, but there are others --- must have that character escaped +in the pattern literal. + +The difficulties start with only slightly more complicated patterns: +consider the meaning of +\begin{verbatim} + &random := <.*> +\end{verbatim} +Presumably, the library {\em with the shortest name} that is encountered along +the search path is specified, whether or not it turns out to be a PRNG. + +Although a clever counter-example may turn up, it appears that any pattern +may be replaced by explicit Unicon code to achieve the same effect by +surrounding assignments to \rndlibkwd with suitable logic: there is not +much to be gained by implementing a pattern matcher in the library +loading code when it is unnecessary and, perhaps, unlikely to be useful. + +On balance, a new keyword is a better design than overloading the assignment +to \rndkwd to load the PRNG library. It's simpler to implement, easier to +understand, just as powerful and provides a way of finding out which PRNG +is in use. + +\subsubsection{A new standard function} +It would be nice to stand on one's theoretical high horse% +\footnote{ + Does one stand on horses? It seems an awfully easy way to fall off. +} +and assert that a function isn't a good idea because, in this case, it +changes the hidden state of the computation --- functions should be pure, +mathematical, things. Nice, but not supported by the evidence. Unicon (and +Icon) is littered with functions that alter the program state (from the +string scanning functions and the I/O functions, passing through the list +manipulation functions and ending up at \texttt{exit()}, not to mention the +graphics functions, practically all of which affect the state of the +program). Let's face it; in this language, function means procedure --- +with side effects. + +So, taking current practice into account, there isn't any reason why the +\rndlibkwd keyword couldn't be replaced by a function. The expression +\begin{verbatim} + loadrng("rngWELL") | loadrng("rngMT") +\end{verbatim} +is no less perspicuous than the alternative using a keyword and +\begin{verbatim} + x := loadrng() +\end{verbatim} +could be made to serve as an observer function, returning the current +value. This function $\equiv$ keyword argument is quite general: if we had +a mind to, most of the existing keywords could be replaced with functions. + +In the end, it comes down to aesthetics. In the mind of this author, at +least, a keyword seems a more ``Unicon-ish'' way to proceed that +complements the use of the existing \rndkwd keyword to control the +computation of random numbers. But a new standard function would be just as +expressive and no less powerful --- it is probably easier to implement +too% +\footnote{ + Fewer files need to be modified for a new standard function compared to a + new keyword. The new function can be made optional by conditional + compilation (which is not true for a new keyword: at present, keywords + cannot be optional). + The work needed to add a new keyword to the compiler has also not yet + been considered. + }. +The only risk is invalidating an existing program that already has a +\texttt{loadrng} function. On the basis of no evidence whatsoever, the risk +appears small. + +\subsection{The PRNG interface} +Each PRNG library should conform to a standard interface so the Unicon +run-time system can use it conveniently without special case code. The +interface must be bidirectional: data will be passed both to and from the +PRNG. + +In this draft the interface, especially the API, is a sketch: it will be +fleshed out in future drafts, taking into account the experience gained +whilst implementing the generators that are chosen to be in the standard +distribution. + +\subsubsection{Error Codes} +There is a case for extending the list of standard error codes to cover a +PRNG error that might plausibly be returned by several generators, such as +\begin{quote} + \UniconError{700}{Sequence limit reached: re-initialization is required}% + \footnote{ + There is no implication here that a PRNG is {\em required} to detect + such a case, merely that some might wish to do so. + }. +\end{quote} +Other error codes might only apply to particular generators +\begin{quote} + %Admittedly, this is funnier if the reader knows what a Norn is. + %Especially if they recall that Thursday comes from "Thor's day" + \UniconError{666} + {It's a Thursday: I can't provide random numbers on Thursdays because + the Norns don't like it.} +\end{quote} +To allow for these, more recherch\'{e}, situations it is proposed to add +five standard error codes which any PRNG may use. They don't have to be +used but, if they are, the PRNG should specify what they mean by providing +a suitable string when the \texttt{getErrorText} routine is called by the run-time. +\begin{quote} + \UniconError{700}{PRNG error 1}\\ + \UniconError{701}{PRNG error 2}\\ + \UniconError{702}{PRNG error 3}\\ + \UniconError{703}{PRNG error 4}\\ + \UniconError{704}{PRNG error 5} +\end{quote} +The program that is using the PRNG may recover the string from the +\texttt{\&errortext} keyword. +In this draft no specific extra error codes are proposed, only the five +generic codes above. + + +\subsubsection{Garbage Collection} +The garbage collector moves stuff around. If, as seems likely, the run-time +allocates storage for use by the PRNG that storage won't always remain at +the same address. We must make provision in the interface for this. We +must also ensure that the garbage collector doesn't treat the storage +allocated to the (external) PRNG as unreferenced and collect it by mistake +whilst it is still in use. + +\begin{description} +\item[Note:] + It is assumed here, because \texttt{random} is a virtual machine + instruction, that garbage collection {\em cannot} occur whilst the PRNG + is executing. It may occur between successive calculations of a random + number, but not in the middle of one. + + There is no assumption that only one random number calculation is in + progress at any one time: different threads may invoke the library + concurrently. +\end{description} + +\section{The PRNG API} +All library routines except \texttt{startRng} {\em must} be re-entrant. +``\texttt{get}'' and ``\texttt{put}'' are from the perspective of the +caller:\\ +In the ``Called by run-time'' section ( $\Rightarrow$ means ``supplies data to'')\\ +\indent +``\texttt{get}'' means PRNG $\Rightarrow$ run-time; +``\texttt{put}'' means run-time $\Rightarrow$ PRNG.\\ +In the ``Called by PRNG'' section it's the other way around\\ +\indent +``\texttt{put}'' means PRNG $\Rightarrow$ run-time; +``\texttt{get}'' means run-time $\Rightarrow$ PRNG.\\\\ + +\noindent +\begin{tabular*}{10.5cm}{|l|p{8.5cm}|} + \cline{1-2} %\hline doesn't work + \multicolumn{2}{|c|}{Called by run-time}\\ + \cline{1-2} +% + \texttt{startRng()} & Called once only, after the library is first loaded. + May be used to perform PRNG initialization. Returns the maximum number of + {\em bits} needed to store the PRNG state and the types that are expected + in an assignment to \rndkwd that reinitializes the generator.\\ +% +% [DPW] remove this for now. We don't unload libraries so, any resource +% allocation done in start cannot be undone. + %% \texttt{stop()} & Is this useful (or needed)?\\ +% + \texttt{putSeed()} & Supply the value assigned to \rndkwd --- a nil value + means that no value has been assigned to \rndkwd in this thread since + the library was loaded.\\ +% + \texttt{getRandomBits()} & Return the requested number of random bits. + This routine is {\em optional}.\\ +% + \texttt{getRandomFpt()} & Return a random floating point number in the + range $[0,1)$.\\ +% + \texttt{getErrorText()} & Return the string associated with one of the PRNG + error codes.\\ + \cline{1-2} +\end{tabular*}\\ + + +One possibility for \texttt{startRng} might be computing the values of a +large array that is used (read-only) to assist the generation of random +numbers. Whatever is done in \texttt{startRng} should not be specific to a +thread because it is called once only, not once per thread. Perhaps there +is a case for a per-thread initialization routine. + +\texttt{putSeed} will be called by the run-time with a nil value if the +random operator is used but there has been no assignment to \rndkwd in the +current thread since the library was loaded. The call will occur before the +call to \texttt{getRandomFpt}. + +\noindent +\begin{tabular*}{10cm}{|l|p{8cm}|} + \cline{1-2} + \multicolumn{2}{|c|}{Called by PRNG}\\ + \cline{1-2} +% + \texttt{putErrorCode()} & Set the value of \texttt{\&error}.\\ +% + \texttt{getRngState()} & Get a pointer to where the PRNG state is + stored. Needed at the start of each generation. Cannot be called from + within \texttt{startRng}.\\ +% + \texttt{getInitialBits()} & Get 32 bits of ``random'' data.\\ +% + \cline{1-2} +\end{tabular*}\\ + +%% Calls to \texttt{getRngState} will fail if they occur before the call to +%% \texttt{getSize} because it is only after that call that the runtime will +%% have created the state vector. + +\pagebreak +\section*{Appendix C: Open Questions} +This appendix lists the open issues that are raised in this draft. As time +passes the questions should be answered. In an ideal world this appendix +will eventually vanish. + +\subsection*{Can standard PRNGs be replaced?} +Clearly, it is impossible for the Unicon system to stop a PRNG library file +being replaced with an alternative. We could store an MD5 hash of the +original file at build time and refuse to load it if the hash differed% +\footnote{ + This is no defence against a user that rebuilds the distribution from + source. +} +but no other part of the Unicon system is protected in this way, and there +is no compelling reason except, perhaps, preservation of guarantees of +cryptographic security why we should care. In the face of an adversary that +can fiddle around with your executable files, you already have much bigger +problems. + +There is a compatibility argument --- programs that only rely on standard +facilities should give the same results on different systems --- but it is +difficult to see how trying to defend the PRNG library against replacement +contributes all that much. + +So the answer is looking like ``Yes'' at this point. + +\subsection*{Should the Icon PRNG be a library, or built in?} +Efficiency probably dictates the Icon PRNG being built-in, although it may +also be worth implementing it as a ``reference'' design to act as a simple +model for PRNG libraries provided by the user. +We could then easily measure the overhead of a dynamic library by comparing +the reference with the built-in library. + +Another idea would be to extend the type accepted for initialization to a +record with three components. The first being the seed, the second being +the space required and the third being how much to slow down each call. +Providing we can find a representative set of programs, it would then be +very easy to establish the negative consequences, or otherwise, of +increased state space and reduced speed. + +\subsection*{How should PRNGs be bundled into a standalone executable?} +This is a general question that applies to plugins as well as PRNG +libraries. Further work is needed to see the best way to proceed. + +\subsection*{How is the compiler affected?} +What effect does the addition of a new keyword, or the change in type of +\rndkwd have on the compiler, especially the type inferencing? + +\section*{Appendix D: Communications with Numerical Recipes} + The following message was sent to the authors of + \cite{PressEtAl:numericalRecipes} on July 1, 2019. + +{\sf\small +\noindent\rule{80mm}{0.25mm}\\ +I am considering including (a reworked implementation) of the Ran function +(section 7.1 page 342) in the runtime system of the Unicon programming +language, so that a high quality RNG would be available to users of the +language. FYI, Unicon is distributed under the Gnu General Public License. + +My implementation wouldn't be a copy because it must be written in C, not +C++, and must be adapted to the needs of the Unicon runtime. There will be +no copy and paste involved, it will be written from scratch. However, I +would like to use the specific combination of generators together with the +magic numbers specified inside Ran. + +Would you consider this a "translation into another language", (in which +case it is clear that you would explicitly not allow it), or would you +consider it an "expression of those ideas in a completely different +implementation"? + +The crucial questions are +\begin{enumerate} +\item May I use the same combination of generators? +\item May I reuse the carefully chosen constants? +\end{enumerate} +Regards + +Don Ward + +\noindent\rule{80mm}{0.25mm}\\ +} +\vspace{0.5cm} + +\noindent +At the present time(\today), no reply has been received. + +\pagebreak +\section*{Appendix E: The Wichmann--Hill licence} +{\hspace{1.5cm}{\bf SOFTWARE END-USER LICENCE AGREEMENT}}\\ +{\small\raggedright +This User Licence Agreement (Ref: MSC/5/590) is between NPL Management Ltd +(hereinafter referred to as “NPL”), a wholly owned subsidiary of Serco +Group plc acting under Contract to the Department of Trade \& Industry and +you, the ``User'' either acting on behalf of your organisation or yourself. + +It is hereby agreed that User will be permitted to use NPL's Wichmann--Hill +Random Number software package free of charge for the express purpose of +their own use in accordance with the following terms and conditions of this +Agreement: +\begin{description} +\item[Copyright] + Copyright ownership of the Wichmann--Hill Random Number software package + is vested in the Crown. The User may only make one copy of the Software + and any associated written material, as a back up. +\item[Performance of the Software] + The Software is provided “as is” without warranty of any kind. NPL will + use its reasonable endeavours to resolve any reported problems found in + running the Software, but NPL does not guarantee to fix any problems in + the Software nor to provide any updates or patches by a particular + date. NPL further disclaims all implied warranties including without + limitation any implied warranties of merchantability or of fitness for + a particular purpose. The entire risk arising out of the use or + performance of the Software and documentation remains with the User. +\item[Other Restrictions] + The User will not rent, lease, sublicense, transfer, resell the Software + (either in whole or in part) or use it for commercial purposes without + NPL’s prior written permission. +\item[No Liability for Consequential Damages] + To the maximum extent permitted by applicable law, in no event shall NPL + or its suppliers be liable for any damages whatsoever (including without + limitation, damages for loss of business profits, business interruption, + loss of business information or other pecuniary loss) arising out of + the use or inability to use the Software. +\item[Assignment] + NPL will be fully entitled to assign or novate this Agreement to the + Department of Trade and Industry (DTI) or any party nominated by the DTI. +\end{description} + +{\bf +The User hereby understands that any use of NPL's Wichmann--Hill Random +Number software package (including small or unlimited use) will be entirely +subject to the terms of this Licence Agreement. + +The User also understands that they will NOT make use of (or be permitted +to gain access to) NPL's Wichmann--Hill Random Number software package if +they are unable to accept and/or comply to the terms of this Licence +Agreement unless a written agreement is obtained from NPL. +} + +{\em +National Physical Laboratory, Teddington, Middlesex, UK, TW11 0LW\\ +\copyright Crown Copyright 2005. Reproduced with the permission of the +Controller of HMSO and the Queen's Printer for Scotland. +} +}% end small + +\pagebreak +\section*{Appendix F: Preliminary Performance Results} +This program was used to measure the performance of the generators (using +the time command, averaged over 10 runs). +{\small +\begin{verbatim} +procedure main(args) +$ifdef _RNG_LIBRARY + local rng := args[1] | "rngIcon" # Default generator is the built-in one. + local limit := args[2] | 10000000 # Default number of iterations + local total := 0.0 + local percentFromPerfect + + loadrng(rng) + + if \args[3] then { # just the loop overhead + every 1 to limit do { total +:= 0.5 } + } else { + every 1 to limit do { total +:= ?0 } + } + + write(loadrng(), " : total = ", total) + + if limit >= 100000 then { + # Complain if the total isn't close to 50% of the limit. + percentFromPerfect := abs(total + total - limit)/(0.0 + limit) + if percentFromPerfect >= 0.01 then { + write(loadrng(), + " isn't looking good (", + integer(100.0*percentFromPerfect), "% from the ideal value)") + } + } +$else + write(&errout, "RNG libraries are not available") +$endif +end +\end{verbatim} +} +\newpage\noindent +Two generators have been implemented at this stage: +\begin{description} +\item[{\sf rngIconEx}] + A re-implementation of the built-in Icon generator to see what the + overheads are when using a shared library. It also acts as an example for + how to implement other libraries. +\item[{\sf rngRbt}] + An implementation of the Rabbit stream cipher as a random number + generator. +\end{description} + +The program was run with two different counts, the default (of $10^7$ +iterations) and also with five times as many. Each run was repeated 10 +times and an average taken, with the following results (times are in seconds). + +\begin{center} +\begin{tabular}{|lcccc|} + \hline + & {\sf loop} & {\sf rngIcon} & {\sf rngIconEx} & {\sf rngRbt}\\ + \hline +$10^7$ &&&&\\ + Average & 1.221 & 1.775 & 1.825 & 2.025\\ + Av - loop & & 0.554 & 0.604 & 0.804\\ + Percent & & 100\% & 109.03\% & 145.13\% \\ +\hline +$5\times 10^7$&&&&\\ + Average & 5.882 & 9.047 & 9.309 & 10.27\\ + Av - loop & & 3.165 & 3.427 & 4.388\\ + Percent & & 100\% & 108.28\% & 138.64\%\\ +\hline +\end{tabular} +\end{center} + +Thus, the overhead of a loadable library is around 8\%. The performance of +Rabbit compared to the built-in generator is really quite good --- just +under 40\% slower (or just under 30\% if the overhead of calling the +library is taken into account). The figures may improve if the present +implementation of Rabbit can be optimized. + +\end{document} diff --git a/doc/utr/utr-prng/utr.sty b/doc/utr/utr-prng/utr.sty new file mode 100644 index 000000000..6bb15d1b4 --- /dev/null +++ b/doc/utr/utr-prng/utr.sty @@ -0,0 +1,38 @@ +% tr.sty +\gdef\@abstract{}\gdef\@trnumber{} +\gdef\@affiliation{University of Idaho\\Department of Computer Science\\Moscow, ID, 83844, USA} +\def\maketitle{\begin{titlepage} +\let\footnotesize\small \let\footnoterule\relax \setcounter{page}{0} +\null +\vfil +\vskip 40pt \begin{center} +{\LARGE\bf \@title \par} \vskip 3em {\large \lineskip .75em +{\bf \@author} +\par} +\vskip 1.0em {\bf Unicon Technical Report: \@trnumber}\par +\vskip 1.0em {\large\bf \@date} +\vskip 5.5em \par + +{\bf Abstract} +\begin{quote} +\@abstract +\end{quote} +\vskip 0.8in +{\large\bf +Unicon Project\\ +http://unicon.org\\ +\ \\ +\@affiliation +} +\end{center} + +\@thanks +\vfil +\null +\end{titlepage} +\setcounter{footnote}{0} \let\thanks\relax +\gdef\@thanks{}\gdef\@author{}\gdef\@title{}\let\maketitle\relax} +\def\trnumber#1{\gdef\@trnumber{#1}} +\def\abstract#1{\gdef\@abstract{#1}} +\def\affiliation#1{\gdef\@affiliation{#1}} + diff --git a/plugins/README b/plugins/README index bbfdc0439..ff6029599 100644 --- a/plugins/README +++ b/plugins/README @@ -1,9 +1,28 @@ Unicon Plugins - February 2017 ------------------------------ -This directory is home for Unicon's official shared/loadable objects and their sources. This is where some of the new experimental features are added that eventually could be moved to be part of the language, or those features that are deemed to be nonessential to be added as built-in to the language. Contributions are welcome. If you plan to contribute a new feature in the form of a shared object please follow the guidelines below as this makes it easier for us to integrate them with our build system on various platforms. +This directory is home for Unicon's official shared/loadable objects and their +sources. This is where some of the new experimental features are added that +eventually could be moved to be part of the language, or those features that are +deemed to be nonessential to be added as built-in to the language. Contributions +are welcome. If you plan to contribute a new feature in the form of a shared +object please follow the guidelines below as this makes it easier for us to +integrate them with our build system on various platforms. 1- Make sure every source file has a licence at the top 2- Please use consistent formatting across your source files 3- Add rules to the make file to build your shared library +Note that, as of August 2019, there are now two different kinds of additional +features: + Conventional plugins, as before. + Random Number Generator (RNG) shared libraries. + +The RNG libraries are implemented differently to a conventional plugin and each +library is located in a separate subdirectory of plugins/rngLibraries. The +simplest example is in plugins/rngLibraries/rngIconEx, which contains a +re-implementation of the built-in (Icon) generator as a shared library. +The "Ex" may be interpreted as "External" or "Example" (or both). + +Note that, for any shared RNG library to work, your implementation of Unicon +must be built with the symbol RngLibrary defined. \ No newline at end of file diff --git a/plugins/rngLibraries/Makefile b/plugins/rngLibraries/Makefile new file mode 100644 index 000000000..e7fcaf3d4 --- /dev/null +++ b/plugins/rngLibraries/Makefile @@ -0,0 +1,64 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# Makefile for the rng shared libraries +# +# Don Ward +# March 2021 +# +################################################################################ +include ../../Makedefs + +.PHONY: Pure clean install test testPrograms + +TESTPROGS = rngConfidence rngPutGet rngSpeed +UNILIB = $(shell unicon -features | grep "Libraries at" | sed -e "s/Libraries at //") + +default: all_prngs + +all_prngs: + $(MAKE) -C rngIconEx + $(MAKE) -C rngRbt + +test: all_prngs testPrograms + $(MAKE) -C rngIconEx test + $(MAKE) -C rngRbt test + ./rngConfidence + +testPrograms: $(TESTPROGS) + +rngConfidence: rngConfidence.icn + unicon -s $^ -o $@ + +rngPutGet: rngPutGet.icn + unicon -s $^ -o $@ + +rngSpeed: rngSpeed.icn + unicon -s $^ -o $@ + +install: all_prngs +# Each install places a shared library in plugins/lib (a.k.a ../lib) + @$(MAKE) -C rngIconEx install + @$(MAKE) -C rngRbt install +# If Unicon is installed somewhere, place the shared libraries in +# the installed location. + @if test "X$(UNILIB)" != "X" ; then \ + cp ../lib/rngIconEx.so $(UNILIB); \ + cp ../lib/rngRbt.so $(UNILIB); \ + fi + +clean: + $(MAKE) -C rngIconEx clean + $(MAKE) -C rngRbt clean + rm -f $(TESTPROGS) + +Pure: + $(MAKE) -C rngIconEx Pure + $(MAKE) -C rngRbt Pure + rm -f $(TESTPROGS) + diff --git a/plugins/rngLibraries/rngConfidence.icn b/plugins/rngLibraries/rngConfidence.icn new file mode 100644 index 000000000..64d910569 --- /dev/null +++ b/plugins/rngLibraries/rngConfidence.icn @@ -0,0 +1,598 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# A "confidence test" of rng libraries: +# +# a) Test that the &random state may be saved and restored. +# b) Check the default library and the transmission of the main thread's library +# to other threads on creation. +# c) Check that the rng library structures survive garbage collection. +# d) Check that different threads may have different libraries. +# e) Test the loading of libraries that +# (i) Don't exist. +# (ii) Exist but have essential routines missing. +# f) Test custom errors returned by a generator. +# g) Test the outputs from rngbits() and rngbitstring(). +# +# Note that the tests are not performed in the order listed above. +# +# Don Ward +# August 2019 +# +################################################################################ + +import threads + +# Comment this definition away to miss out calls to debugging routines that +# don't exist in a production build of Unicon. e.g. dbgrng() and dbgbrk() +$define RNGDBG 1 + +global IconNumber, IconExNumber, RbtNumber +global Rbt1000000, Icon1000000 + +procedure main(args) +$ifndef _RNG_LIBRARY + write(&errout, "RNG libraries are not available") +$else + local state, n, differences, duplicates + local bits,bitstring + local a, unRbt, x + + &error := -1 # Errors are expected + + banner("Initial testing") # ---------------------------------------- + write("The default library at the start of main is <", loadrng(), ">") + printGC("main at start") + printLibChain("main at start: ") + + if "loadable RNGs" == &features then { + write("&features has \"loadable RNGs\"") + } else { + write(" **** &features does NOT have \"loadable RNGs\" (Error) ***") + } + + # It would be a catastrophe if this didn't work with the built-in generator + banner("Assignment to &random") # ---------------------------------------- + doRepeat() + &random := 42; every 1 to 1000000 do Icon1000000 := ?0 # Used (much) later + + banner("Non-existent rng library") # ---------------------------------------- + if "frimble" == loadrng("frimble") then { + write(" **** A non-existent library has been loaded (Error) ****") + } else { + writes("loadrng(\"frimble\") failed as expected:") + write(" &errornumber = ", &errornumber, ", &errortext = \"", &errortext, "\"") + } + printGC("After failed load (1)") + printLibChain("After failed load (1): ") + write("The current rng library is <", loadrng(), ">") + + banner("Library exists but isn't a rng Library") # --------------------------- + if "upexample" == loadrng("upexample") then { + write(" **** A library has been loaded that isn't a PRNG (Error) ****") + } else { + writes("loadrng(\"upexample\") failed as expected:") + write(" &errornumber = ", &errornumber, ", &errortext = \"", &errortext, "\"") + } + printGC("After failed load (2)") + printLibChain("After failed load (2): ") + write("The current rng library is <", loadrng(), ">") + + &error := 0 # We want to know if an error is generated when we expect failure + banner("rngIcon rngbits()") # ---------------------------------------- + if \bits := rngbits(0) then { + write("**** rngbits returned a value with the built-in generator (Error) ****") + } else { + write(,"rngbits() failed as expected") + } + + banner("rngIcon rngbitstring()") # ---------------------------------------- + if \bitstring := rngbitstring(0) then { + write("**** rngbitstring() returned a value with the built-in generator (Error) ****") + } else { + write(,"rngbitstring() failed as expected") + } + + &error := -1 + # Set up a list of random numbers for later comparison + banner("100 numbers from the built-in generator") # ------------------------------ + &random := 42 + IconNumber := list() + writes("&random = ", &random, " -->") + every 1 to 100 do { put(IconNumber, ?0) } + every n := 1 to 3 do writes(" ", IconNumber[n]) + write(" ..."); writes(repl(" ",16)) + every n := 98 to 100 do writes(" ", IconNumber[n]) + write() + + + banner(" Load rngIconEx") # ---------------------------------------- + if not("rngIconEx" == loadrng("rngIconEx")) then { + write("**** loadrng(\"rngIconEx\") failed ***") + write(" &errornumber = ", &errornumber, ", &errortext = \"", &errortext, "\"") + exit() + } + printGC("After loadrng(\"rngIconEx\")") + printLibChain("After loadrng(\"rngIconEx\"): ") + write("The current rng library is <", loadrng(), ">") + + banner("rngbits() and rngbitstring() before initialization") # -------------------- + if \ (bits := rngbits(0)) then { + writes("rngbits(0) ="); every writes(" ", !bits); write() + } else { + write("**** rngbits(0) failed (Error) ****") + } + if \ (bitstring := rngbitstring(0)) then { + write("rngbitstring(0) = <", bitstring, ">") + } else { + write("**** rngbitstring(0) failed (Error) ****") + } + &error := -1 + + banner("100 numbers from rngIconEx") # ------------------------------ + # If we just assign to state like this + # state := &random + # state just points to the &random array (and when we restore the state nothing happens; + # the sequence isn't reset). We need a copy of &random. + &random := 42; state := copyArray(&random) + writes("&random ="); every writes(" ", !&random); write() + writes("&state ="); every writes(" ", !state); write() + IconExNumber := list() + writes("&random = ", &random[2], " -->") # Note indexing of &random: it's an array + every 1 to 100 do { put(IconExNumber, ?0) } + every n := 1 to 3 do writes(" ", IconExNumber[n]) + write(" ..."); writes(repl(" ",16)) + every n := 98 to 100 do writes(" ", IconExNumber[n]) + write() + + differences := 0.0 + every n := 1 to 100 do differences +:= abs(IconNumber[n] - IconExNumber[n]) + if differences = 0.0 then { + write("There were no differences between rngIcon and rngIconEx") + } else { + write("*** Different sequence (Error) ***") + writes("Differences at ") + every n := 1 to 100 do { if IconNumber[n] ~= IconExNumber[n] then writes(" ",n) } + write() + } + + banner("restore &random state") # ---------------------------------------- + if not (&random := state) then { + write("**** restoration of &random state failed (Error) ****") + } + differences := 0 + every n := 1 to 100 do { + if IconExNumber[n] ~= ?0 then differences +:= 1 + } + if differences > 0 then { + write("**** there were ", n, " differences (Error) ****") + } else { + write("There were no differences after the state was restored") + } + + banner("rngbits() and rngbitstring() after initialization") # -------------------- + &random := 42 + writes("&random = ", &random[2], " rngbits(0) --> ") + if /(bits := rngbits(0)) then { + write("**** rngbits() failed (Error) ****") + } else { + write(bits[1]) # bits is always an array, even if it only has one element + } + &random := 42 + writes("&random = ", &random[2], " rngbitstring(0) --> ") + if /(bitstring := rngbitstring(0)) then { + write("**** rngbits() failed (Error) ****") + } else { + write("<", bitstring, ">") + } + + banner("Load rngRbt") # ---------------------------------------- + if not("rngRbt" == loadrng("rngRbt")) then { + write("**** loadrng(\"rngRbt\") failed ***") + write(" &errornumber = ", &errornumber, ", &errortext = \"", &errortext, "\"") + exit() + } + printGC("After loadrng(\"rngRbt\")") + printLibChain("After loadrng(\"rngRbt\"): ") + write("The current rng library is <", loadrng(), ">") + + unRbt := copyArray(&random) # Save unitialized state for later tests + + banner(" rngbits() and rngbitstring() before initialization") # -------------------- + writes("&random = ", &random[2], " ... rngbits(0) --> ") + if /(bits := rngbits(0)) then { + write("**** rngbits() failed (Error) ****") + } else { + every writes(!bits, " "); write() + } + + writes("&random = ", &random[2], " ... rngbitstring(0) --> ") + if /(bitstring := rngbitstring(0)) then { + write("**** rngbits() failed (Error) ****") + } else { + write("<", bitstring, ">") + } + + banner("100 numbers from rngRbt") # ------------------------------ + &random := unRbt # Set back to uninitialized state + &random := 42; state := copyArray(&random) # note copy, not state := &random + printRandomState() + + RbtNumber := list() + every 1 to 100 do { put(RbtNumber, ?0) } + writes(repl(" ",9)) + every n := 1 to 3 do writes(" ", RbtNumber[n]) + write(" ..."); writes(repl(" ",9)) + every n := 98 to 100 do writes(" ", RbtNumber[n]) + write() + + differences := 0.0; n := 0 + every n := 1 to 100 do { + differences +:= abs(IconNumber[n] - RbtNumber[n]) + if IconNumber ~= RbtNumber then n+:= 1 + } + if differences = 0.0 then { + write("**** There were no differences between rngIcon and rngRbt (Error) ****") + } else { + write("There were ", n, " differences") # assume n > 1 + write("The average difference between rngIcon and rngRbt was ", differences/100.0) + } + + banner("restore &random state") # ---------------------------------------- + printRandomState() + if not (&random := state) then { + write("**** restoration of &random state failed (Error) ****") + } + printRandomState() + differences := 0 + every n := 1 to 100 do { + if RbtNumber[n] ~= ?0 then differences +:= 1 + } + if differences > 0 then { + write("**** there were ", n, " differences (Error) ****") + } else { + write("There were no differences in the sequence after the state was restored") + } + + banner("rngbits() and rngbitstring() after initialization") # -------------------- + &random := 42 + writes("&random = ", &random[2], " ... rngbits(0) --> ") + if /(bits := rngbits(0)) then { + write("**** rngbits() failed (Error) ****") + } else { + every writes(!bits, " "); write() + } + + &random := 42 + writes("&random = ", &random[2], " ... rngbitstring(0) --> ") + if /(bitstring := rngbitstring(0)) then { + write("**** rngbits() failed (Error) ****") + } else { + write("<", bitstring, ">") + } + + banner("Swap back to the built-in generator") # ------------------------------ + if "rngIcon" ~= loadrng("rngIcon") then { + write("**** Reload of rngIcon failed (Error) ****") + } else { + &random := 42 + differences := 0.0 + every n := 1 to 100 do differences +:= abs(IconNumber[n] - ?0) + if differences = 0.0 then { + write("There were no differences in the random sequence") + } else { + write("*** Different sequence (Error) ***") + } + } + printGC("After loadrng(\"rngIcon\")") + printLibChain("After loadrng(\"rngIcon\"): ") + write("The current rng library is <", loadrng(), ">") + + banner("Initialization with an array") # ---------------------------------------- + # If the generator has not been initialized and an integer is given, the Rabbit putSeed() + # routine "stretches" the value by copying the value into each element of an array and then + # initializes the generator with that. So this should give the same results + # + # We have to reload the generator for this test to work (if the generator has been used + # before, an assignment of an integer to &random keeps the key and just changes the IV) + + if not("rngRbt" == loadrng("rngRbt")) then { + write(**** "loadrng(\"rngRbt\") failed (Error) ****") + } else { + if not (&random := a := array(192/intBits(),42)) then { + write("**** Initialization with an array failed (Error) ****") + } else { + printRandomState() + differences := 0 + every n := 1 to 100 do { + if RbtNumber[n] ~= ?0 then differences +:= 1 + } + if differences > 0 then { + write("**** there were ", differences, " differences (Error) ****") + } else { + write("There were no differences in the sequence after the state was initialized") + } + } + + printGC("After loadrng(\"rngRbt\")") + printLibChain("After loadrng(\"rngRbt\"): ") + write("The current rng library is <", loadrng(), ">") + + # Change a single bit + a[1] := 43 + &random := a + duplicates := differences := 0 + every n := 1 to 100 do { + if RbtNumber[n] ~= (x := ?0) then differences +:= 1 + every if x = !RbtNumber then duplicates +:= 1 + } + if differences > 0 then { + write("There were ", differences, + " differences after a single bit was changed in key/IV") + } else { + write("*** There were no differences after a ", + "single bit was changed in key/IV (Error) ****") + } + if duplicates = 0 then { + write("There were no duplicates") + } else { + write("There were ", duplicates, " duplicates ?") # possible but very unlikely + } + } + + banner("Not enough bits supplied to Rbt initialization") # ------------------------------ + if not(&random := array(2,42)) then { + write("Initialization with array(2,42) failed as expected") + write(" &errornumber = ", &errornumber, ", &errortext = \"", &errortext, "\"") + } else { + write("**** Initialization with array(2,42) unexpectedly succeeded (Error) ****") + } + + + # ------------------------------ Tests with threads ------------------------------ + + banner("sequence test in parallel") # ---------------------------------------- + loadrng("rngIcon") + printGC("After loadrng(\"rngIcon\")") + printLibChain("After loadrng(\"rngIcon\"): ") + write("The current rng library is <", loadrng(), ">") + MakePool() + printGC("After MakePool()") + printLibChain("After MakePool(): ") + write("The current rng library is <", loadrng(), ">") + + write(repl("-",60)) + write("Note that the threads start with the same generator as main") + write("but subsequent activations have the value that was set last time") + + Dispatch(checkSequence, IconNumber, "rngIcon") + Dispatch(checkSequence, IconExNumber, "rngIconEx") + Dispatch(checkSequence, RbtNumber, "rngRbt") + + write("main waiting ...") + every 1 to 3 do <<@ + printGC("After sequence test") + printLibChain("After sequence test: ") + write("The current rng library is <", loadrng(), ">") + + Dispatch(checkSequence, IconExNumber, "rngIconEx") + Dispatch(checkSequence, RbtNumber, "rngRbt") + Dispatch(checkSequence, IconNumber, "rngIcon") + + write("main waiting ...") + every 1 to 3 do <<@ + printGC("After 2nd sequence test") + printLibChain("After 2nd sequence test: ") + write("The current rng library is <", loadrng(), ">") + + banner("Change main's rng") + loadrng("rngRbt") + write("The current rng library is <", loadrng(), ">") + Dispatch(checkSequence, IconNumber, "rngIcon") + Dispatch(checkSequence, IconExNumber, "rngIconEx") + Dispatch(checkSequence, RbtNumber, "rngRbt") + + write("main waiting ...") + every 1 to 3 do <<@ + + printGC("After 3rd sequence test") + printLibChain("After 3rd sequence test: ") + write("The current rng library is <", loadrng(), ">") + write(repl("-",60)) + write("Threads that haven't been used before will have the rng that") + write("main had when they were created, not the current one") + every 1 to 6 do { + Dispatch(checkSequence, IconNumber, "rngIcon") + Dispatch(checkSequence, IconExNumber, "rngIconEx") + Dispatch(checkSequence, RbtNumber, "rngRbt") + } + write("main waiting ...") + every 1 to 18 do <<@ + printGC("After 4th sequence test") + printLibChain("After 4th sequence test: ") + write("The current rng library is <", loadrng(), ">") + + # One round of ClosePool(); MakePool() is usually enough to cause the + # invocatiotion of the garbage collector + ClosePool() + MakePool() + + printGC("After recreating thread pool") + printLibChain("After recreating thread pool: ") + write("The current rng library is <", loadrng(), ">") + + write(repl("-",60)) + write("All threads should start with rngRBt") + + every 1 to 6 do { + Dispatch(checkSequence, IconNumber, "rngIcon") + Dispatch(checkSequence, IconExNumber, "rngIconEx") + Dispatch(checkSequence, RbtNumber, "rngRbt") + } + write("main waiting ...") + every 1 to 18 do <<@ + printGC("After 5th sequence test") + printLibChain("After 5th sequence test: ") + write("The current rng library is <", loadrng(), ">") + + &random := 42 + every 1 to 1000000 do Rbt1000000 := ?0 + write("The value of the millionth number after 42 is ", Rbt1000000) + + banner("Run Iconx in parallel") + every n := 1 to 16 do { + every 1 to n do Dispatch(check1000000,5, "rngIconEx", Icon1000000) + write("main waiting ...") + every 1 to n do <<@ + } + banner("Run Rbt in parallel") + every n := 1 to 16 do { + every 1 to n do Dispatch(check1000000,5, "rngRbt", Rbt1000000) + write("main waiting ...") + every 1 to n do <<@ + } + banner("Run a combination of all three in parallel") + every n := 1 to 6 do { + every 1 to n do { + Dispatch(check1000000,5, "rngRbt", Rbt1000000) + Dispatch(check1000000,5, "rngIconEx", Icon1000000) + Dispatch(check1000000,5, "rngIcon", Icon1000000) + } + write("main waiting ...") + every 1 to n*3 do <<@ + } + + write(repl("-",10), " End of tests ", repl("-",10)) +$endif +end + +# See if the generated sequence matches the one given +procedure checkSequence(seq, rnglib) + local differences, n + alterRng(rnglib) + &random := 42 + differences := 0 + every 1 to 100 do if seq[n] ~= ?0 then differences +:= 1 + + if (differences = 0) then { + write("Thread ", serial(¤t), " (", rnglib, ") no differences") + } else { + write("Thread ", serial(¤t), + "**** There were ", differences, " differences (Error) ****") + } + wait(10) + @>&main +end + +# Generate 1000000 numbers starting from 42 and check that the last number +# matches the one we prepared earlier. Repeat the test the specified number +# of times. +procedure check1000000(limit, rnglib, theLastOne) + local x, differences + differences := 0 + every 1 to limit do { + loadrng(rnglib) + &random := 42 + every 1 to 1000000 do x := ?0 + if x ~= theLastOne then differences +:= 1 + } + + if differences = 0 then { + write("Thread ", serial(¤t), " no differences") + } else { + write("Thread ", serial(¤t), + " **** ", differences, " differences (Error) ****") + } + @>&main +end + + +# Load a library showing before and after +procedure alterRng(lib) + write("In thread ", serial(¤t), " : pre-value of loadrng() is <", loadrng(), ">") + loadrng(lib) + write("In thread ", serial(¤t), " : post-value of loadrng() is <", loadrng(), ">") +end + +procedure doRepeat(state :integer: 42) + local n + every 1 to 2 do { + &random := state + writes("&random = ", &random, " -->") + every n := 1 to 10 do writes(" ", ?1000) + write() + } +end + +procedure banner(s) + write(repl("-",10), " ", s, " ... ", repl("-",10)) +end + +# Print out the rng library structures. A higher level means more information. +procedure printLibChain(s, level : integer : 3) +$ifdef RNGDBG + dbgrng(s,level) # writes to &errout +$endif +end + +procedure debugBreak() +$ifdef RNGDBG + dbgbrk() +$endif +end + +# Print out garbage collector stats. +procedure printGC(s) + writes(s, ": GC heap: ", &collections) + writes(" static: ", &collections) + writes(" string: ", &collections) + write(" block: ", &collections) +end + +# Print out value of &random (or a copy) +# Note: not to be used when the built-in generator is selected +procedure printRandomState(name : string, state) + if /name then { + writes("&random ="); every writes(" ", !&random); write() + } else { + writes(name, " ="); every writes(" ",!state); write() + } +end + +# This procedure should NOT be necessary !! +procedure copyArray(a) + local ans := array(*a, 0) + local n + every n := 1 to *a do ans[n] := a[n] + return ans +end + + # return the number of bits in an integer + procedure intBits() + local str, errs, test + static bits + initial { +$ifdef _LARGE_INTEGERS + errs := &error + &error := -1 +$endif + bits := 0; str := "" + repeat { + bits +:= 1; str ||:= "1" + test := integer("2R" || str) +$ifdef _LARGE_INTEGERS + # If large integers are configured we have to test an operation that fails on them + if not seq(test) then {&error := errs; break} +$else + # If large integers are not configured this will detect overflow + if ishift(ishift(test,+1),-1) ~= test then break +$endif + } + } + return bits + end diff --git a/plugins/rngLibraries/rngIconEx/Icon.test-vectors b/plugins/rngLibraries/rngIconEx/Icon.test-vectors new file mode 100644 index 000000000..d613bf871 --- /dev/null +++ b/plugins/rngLibraries/rngIconEx/Icon.test-vectors @@ -0,0 +1,404 @@ +&random = 0 +28363544 +55354187 +42385314 +68510120 +56604374 +41029224 +10684869 +98989400 +6807549 +96227020 +18486159 +45110162 +71546123 +83325176 +77344641 +94969042 +98962561 +31705453 +114055195 +42498459 +47752416 +120747177 +113422301 +1579627 +96642214 +46782254 +87490888 +55326659 +114760276 +131210618 +47398619 +56889892 +78347371 +84524047 +19792662 +127037964 +66464106 +65138540 +15536248 +112076796 +78964688 +82000912 +126865794 +23759990 +54224415 +98168444 +123852980 +127401973 +61455061 +105552689 +68509839 +15493887 +105571443 +112107181 +109431698 +30653967 +56314234 +116956530 +35791933 +80245159 +79116393 +14746623 +109026575 +11798088 +66152383 +41584339 +127144073 +81233008 +55670270 +93233775 +119046443 +45874337 +3828133 +4332373 +26450295 +111871833 +91828530 +58818049 +25963497 +120538393 +66790185 +62234357 +56865540 +69000802 +7110152 +4201138 +72929606 +94503859 +71231566 +104846774 +120705328 +64974219 +9957501 +52264067 +17769795 +126409835 +27757844 +56624023 +15067134 +67999956 +&random = 42 +106518773 +37189791 +64016125 +82210613 +99030133 +110392661 +983986 +126672655 +39339903 +23512820 +126947117 +3584531 +123789966 +76731386 +114398706 +3863229 +54746663 +102558440 +76612734 +60216207 +87112392 +104841791 +74059603 +19410698 +20152561 +7010430 +103690991 +68159404 +35340577 +94999588 +109720532 +12388343 +33166298 +116425650 +91397760 +1966698 +27433370 +97852841 +114837365 +58487172 +129039074 +36413576 +35965746 +58652614 +127625266 +51229390 +83824182 +80994224 +21666316 +29942525 +98024706 +84122563 +28987628 +87369619 +45992983 +32196222 +86103380 +66281234 +16447476 +106898016 +52721605 +68407288 +33047832 +108337642 +92934333 +111454406 +32145413 +100089757 +33521854 +94928893 +80133433 +58609144 +123678790 +49599516 +100587829 +45361018 +117542870 +108563362 +126220409 +4085413 +43358192 +40531217 +77399942 +30445047 +117524751 +64997095 +82262747 +82257905 +80358328 +105553829 +71732984 +111781651 +109432936 +6325709 +67127388 +125122014 +97669025 +15263707 +27882377 +76490449 +&random = 250151 +119081488 +112043835 +25962475 +83113330 +33809339 +93780326 +51537264 +77337673 +76574332 +14549707 +60995022 +6015257 +105161685 +127074021 +71790211 +10926945 +114070854 +72245561 +1752337 +41896608 +105114704 +24925509 +23865079 +91115095 +9923186 +115359368 +62785972 +24286727 +92170539 +63977604 +1776330 +73951534 +109861372 +27825847 +21227447 +107546445 +81413734 +32990371 +87315964 +77735909 +130568167 +65004998 +25240346 +36010613 +106377217 +70653345 +877712 +103818876 +77183027 +64104373 +26740701 +124406651 +113136124 +127666048 +60904066 +60719347 +53509854 +97441924 +120087039 +57235043 +89282647 +66352704 +96512981 +23122763 +38670313 +18412595 +41909635 +70514474 +25128723 +129375710 +71400584 +54671745 +32855892 +47642306 +113780325 +86706641 +109789741 +32717406 +3100828 +131420056 +35307807 +117627952 +3844265 +24046168 +88407464 +38373309 +117126158 +31732112 +122960201 +123347071 +5034060 +72316095 +62213507 +114442747 +28029666 +132152166 +92875733 +5095344 +132245838 +129762565 +&random = 999 +75402189 +64302151 +20018695 +30080862 +59098422 +109036338 +57964876 +9670902 +99937208 +121085269 +19409770 +111961220 +125417681 +108639793 +19177952 +94609804 +111410690 +39272773 +57526829 +42100620 +82781388 +125905424 +68741586 +109334019 +98807470 +126587923 +118103631 +63366259 +114341159 +132733647 +34200869 +91304538 +10316217 +85955011 +45249491 +47396666 +87201250 +95487086 +95782872 +83716753 +33299236 +4306515 +83465909 +105921504 +16937726 +7496430 +34567659 +58954408 +35401455 +99876289 +41931513 +94785127 +95910008 +22229581 +57717598 +76924575 +45846810 +33285136 +35845276 +23939791 +16929364 +16035468 +113757233 +7185015 +32091557 +64120127 +120473502 +31231254 +8203407 +56857515 +113822820 +22823470 +45576336 +26475854 +25860098 +54194493 +89895721 +34086314 +119357431 +121258436 +65488347 +15771710 +65941957 +5165892 +102437412 +60164233 +93598442 +14138684 +77404550 +102490636 +844008 +47058731 +103937407 +33329224 +22163774 +57430162 +118380432 +12363452 +13103467 +30277874 diff --git a/plugins/rngLibraries/rngIconEx/Makefile b/plugins/rngLibraries/rngIconEx/Makefile new file mode 100644 index 000000000..e49ed41a7 --- /dev/null +++ b/plugins/rngLibraries/rngIconEx/Makefile @@ -0,0 +1,45 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# Makefile for the rngIconEx shared library +# +# Don Ward +# August 2019 +# +################################################################################ +include ../../../Makedefs + +.PHONY: Pure clean install test + +# Source files for the shared library +SRC=rngIconEx.c +# Name of the target shared library +RNGLIB=rngIconEx.so +# Special flags for dynamic shared libraries +CCSHFLAGS=-shared -fpic +# Installation directory is plugins/lib +LIBSDIR=../../lib + +all: $(RNGLIB) + +$(RNGLIB): $(SRC) + $(CC) $(CFLAGS) $(CCSHFLAGS) $^ -o $@ + +install: $(RNGLIB) + cp $^ $(LIBSDIR) + +clean: + rm -f *.o *.so test-vectors test.output + +Pure: clean + rm -f $(LIBDIR)/$(RNGLIB) + +test: + unicon -s test-vectors + ./test-vectors > test.output + diff Icon.test-vectors test.output diff --git a/plugins/rngLibraries/rngIconEx/rngIconEx.c b/plugins/rngLibraries/rngIconEx/rngIconEx.c new file mode 100644 index 000000000..fae94af1c --- /dev/null +++ b/plugins/rngLibraries/rngIconEx/rngIconEx.c @@ -0,0 +1,255 @@ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + * + * This is a reimplementation of the built in (Icon) random number generator as + * a dynamically loaded rng library. + * + *-------------------------------------------------------------------------------- + * + * Don Ward + * August 2019 + * + *-------------------------------------------------------------------------------- + */ + +#include "../rngLib.h" + +struct rng_rt_api runtime; /* A place to store the routines callable by the rng */ + +/*-------------------------------------------------------------------------------*/ +/* This routine is called once by the runtime when the library + * is first loaded. + */ +int startRng(struct rngprops *props, struct rng_rt_api *rtapi) +{ /* + * Tell the runtime how much state is needed. + * NB. the state size is in bits, not bytes. + */ + props->stateBits = 32; + /* + * Specify what types are acceptable as a parameter to putSeed + * If more than one type is acceptable, or them together + * eg RngTypeFlag(T_Integer) | RngTypeFlag(T_String) + * + * See icall.h for the names of types. + * + * The easy types to deal with are + * strings + * integers, reals (and arrays of either) + * + * Other types are possible, but require a detailed understanding of + * how Unicon represents the type values internally. Familiarity with + * the Unicon implementation book is essential. + */ + props->typeFlags = RngTypeFlag(T_Integer); + + /* + * Tell the runtime what the "natural size" of the random output is. + * For example, if the generator algorithm naturally produces a block + * of output, tell the runtime what the size of the block is. + * NB. the block size is in bits, not bytes. + */ + props->blockBits = 31; + + /* Store the routines that we can call */ + runtime = *rtapi; + + /* + * If the generator reuires any "first time" set up (e.g. to build S-Boxes + * or similar tables), here is the best place to call the setup routine. + */ + + return 0; /* Success */ +} + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime to get the string values of + * the custom error numbers set by the generator. + */ +char * getErrorText(int err) +{ + switch (err) + { + case 700: return "Unexpected type supplied to putSeed"; + case 701: return "Unexpected size supplied to putSeed"; + case 702: return "Bad seed value"; + + default: return "??"; /* Not one of our errors */ + } +} + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime when an assignment that is not + * a restored state is made to &random. The runtime detects an assignment + * that is a restoration of the state and handles that internally. + * e.g. + * &random := 42 # putSeed will be called + * x := &random # copy the state + * ... + * &random := x # putSeed will not be called, the state will be + * # restored to what it was when x was assigned. + * + * type contains one of the values that was specified in the assignment + * of props->typeFlags in the startRng function. + * size contains the number of bytes supplied. + * Note bytes, not bits (i.e. different to startRng). + * param points to the value of the specified type ... + * T_String pointer to the first character in the string. + * Note that string parameters are NOT null terminated. + * T_Integer pointer to the word value. + * T_Real pointer to the double value. + * T_Intarray pointer to the first (word) element of the array. + * T_Realarray pointer to the first (double) element of the array. + * + * other pointer to the descriptor. In this case the size parameter + * will be zero (all the information needed is in the descriptor). + * Familiarity with the implementation book is essential. + * + * If no assignment to &random has been made after the library has been loaded + * and the random operator is used, putSeed will be called with nil values. + * i.e. putSeed(T_Null, 0, NULL) + */ +int putSeed(word type, word size, void *param) +{ + word *state, seed; + if (type == T_Null || param == NULL) { + /* No seed has been supplied before a use of the random operator: + * call the runtime to supply some random seed data. + * getInitialBits may be called more than once, but there is no guarantee + * that it will return a different value on subsequent calls. + */ + state = (word *)runtime.getRngState(); /* get the location of generator's state */ + seed = runtime.getInitialBits(); /* get some random bits */ + + *state = seed; /* initialize the state */ + return 0; /* return success */ + } + + /* Check the supplied parameters. + * None of these failures should ever happen (unless there is a bug in the runtime) + * but the code demonstrates how to report a custom error. + */ + if (type != T_Integer) { + runtime.putErrorCode(700); /* Unexpected type */ + return -1; /* The assignment to &random will fail */ + } + + /* The runtime will supply the whole word even if fewer bits have been specified */ + if (size > sizeof(word)) { + runtime.putErrorCode(701); /* Unexpected size */ + return -1; + } + + if (param == NULL) { + runtime.putErrorCode(702); /* Bad seed */ + return -1; + } + + /* + * Store the supplied seed in the state variable. + * getRngState must be called for each invocation of putSeed, in case the + * garbage collector has moved the state to another location. + * + * We could just write + * *((word *)runtime.getRngState()) = *(word *)param; + * but, for clarity, three assignments are made. It is to be hoped that + * a decent compiler will optimise them to produce the same code. + */ + state = (word *)runtime.getRngState(); + seed = *(word *)param; + *state = seed; + + return 0; /* success */ +} + +/*-------------------------------------------------------------------------------*/ +/* These values are copied from rmacros.h */ +#define RandA 1103515245 /* random seed multiplier */ +#define RandC 453816694 /* random seed additive constant */ +#define RanScale 4.65661286e-10 /* random scale factor = 1/(2^31-1) */ +/* + * Accuracy demands that we point out that 4.65661286e-10 isn't 1/(2^31-1). + * The actual double precision figure is 4.656612875245797e-10. + * + * The value chosen for RanScale is actually much cleverer than that: it is very + * close to the largest value that will NOT return 1.0 when multiplied by 0x7FFFFFF + * in single precision IEEE floating point arithmetic. I.e. it guarantees the range + * of values returned is [0.0,1.0) rather than [0.0,1.0] + * + * On a 64 bit machine, with double precision arithmetic, we could do slightly better + * and use a constant of 4.656612875245793e-10: it would make the spread of deviates + * imperceptibly more uniform. But if we did that, the 32 bit and 64 bit generators + * would no longer produce the same answers. + */ + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime when the random operator is invoked. + * It is expected to return a floating point number in the range [0.0,1.0). + * Note the interval is half closed (i.e. 1.0 is not allowed). + */ +double getRandomFpt(void) +{ + word *state = (word *)runtime.getRngState(); + word seed = *state; + double ans; + + *state=((RandA*seed+RandC)&0x7FFFFFFFL); + ans = RanScale * (*state); + + return ans; +} + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime when either of the standard functions + * rngbitstring() or rngbits() is called. + * It is expected to return a bit vector of the required size, although it is + * also allowed to fail. + * + * It is not expected that any bits left over are retained for the next output + * i.e. it is almost certainly true that + * rngbitstring(n) || rngbitstring(n) ~== rngbitstring(n*2) + * The number of bits may exceed the "natural size". If so, the routine is expected + * to concatenate several random values together (or fail). + * + * For most generator algorithms, it will be particularly efficient to ask for + * random bits in integer multiples of the natural size. + * + * In the case of the IconEx generator, the natural size is 31 bits, leading to + * a requirement to concatenate a sequence of 31 bit generated values together. + * This example generator ducks the issue by refusing to supply more than 31 bits. + */ + +int getRandomBits(int nBits, void *buffer) +{ + if (nBits > 31) { + /* One day, when I'm feeling courageous, I may write the code that concatenates + * a sequence of 31 bit values into a contiguous sequence of 32 bit values with + * no gaps. Today is not that day. + */ + return -1; /* Fail */ + } else { + word *state = (word *)runtime.getRngState(); + word seed = *state; + /* Should a new random value be generated, even if none of it is required? + * It's possible to argue either way, but it seems better to consistently + * generate a new value on every call, rather than have no bits as a special case. + */ + *state=((RandA*seed+RandC)&0x7FFFFFFFL); + /* Note that, in the usual case, it's quite hard for the user to ask for no bits + * because the runtime interprets rngbits(0) as a request for the natural size. + * nBits == 0 can only happen if the generator specifies 0 as its natural size. + */ + if (nBits == 0) { + return 0; /* supplying no bits is easy */ + } else { + size_t bytes = (nBits + 7)/8; + memcpy(buffer,state,bytes); + return bytes; + } + } +} diff --git a/plugins/rngLibraries/rngIconEx/test-vectors.icn b/plugins/rngLibraries/rngIconEx/test-vectors.icn new file mode 100644 index 000000000..30b67c18d --- /dev/null +++ b/plugins/rngLibraries/rngIconEx/test-vectors.icn @@ -0,0 +1,42 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# A program to recreate test vectors for the rngIconEx generator. +# +# The generator may be tested by +# Unicon -s test-vectors.icn +# ./test-vectors > test-output +# diff Icon.test-vectors test.output +# +# The Icon.test-vectors file was created by running the same program using +# an Icon system (version 9.5.1) +# +# Don Ward +# August 2019 +# +################################################################################ +# This unicon program is also an icon program +procedure main(args) + local n + local seeds + +$ifdef _RNG_LIBRARY + loadrng("rngIconEx") | stop(&errout, "Cannot load the rngIconEx library") +$else + # any program argument overrides the error exit + if *args = 0 then stop(&errout, "RNG libraries are not available") +$endif + + # Produce some random numbers + seeds := [0, 42, 250151, 999] + while n := pop(seeds) do { + write("&random = ", n) + &random := n + every n := 1 to 100 do { write(? 16R7FFFFFF) } + } +end diff --git a/plugins/rngLibraries/rngLib.h b/plugins/rngLibraries/rngLib.h new file mode 100644 index 000000000..43b06232d --- /dev/null +++ b/plugins/rngLibraries/rngLib.h @@ -0,0 +1,40 @@ +#ifndef _rnglib_h +#define _rnglib_h +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + * + * This is the header file used by all RNG libraries + * + *-------------------------------------------------------------------------------- + * + * Don Ward + * August 2019 + * + *-------------------------------------------------------------------------------- + */ + +/* Make sure the RngLibrary extensions are active */ +#define RngLibrary 1 + +/* There are a few icall.h files: we want this one */ +#include "../src/icall.h" + +/* These routines must be defined by the RNG library */ +extern char * (getErrortext)(int); +extern double (getRandomFpt)(void); +extern int (putSeed)(word, word, void *); /* Type, Size, Seed parameter */ +extern int (startRng)(struct rngprops *, struct rng_rt_api *); + +/* This routine is optional + * extern int (*getRandomBits)(int, void *); No of bits, output buffer + * + * If the RNG library does not provide it then rngbits() and rngbitstring() + * will always fail (but everything else will work). + */ + +#endif /* _rnglib_h */ diff --git a/plugins/rngLibraries/rngPutGet.icn b/plugins/rngLibraries/rngPutGet.icn new file mode 100644 index 000000000..42044407c --- /dev/null +++ b/plugins/rngLibraries/rngPutGet.icn @@ -0,0 +1,135 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# A simple test to save and restore &random +# usage: rngPutGet file rngLib n +# +# If the file exists, &random will be restored from it, otherwise &random +# will be written to the newly created file. +# In each case, the next n random values will be printed out +# +# A simple test is +# ./rngPutGet testfile rngRbt 1000 > op1 +# ./rngPutGet testfile rngRbt 1000 > op2 +# diff op1 op2 +# +# It can also be used to test the assignment of one rng's state to another. +# +# +# Don Ward +# August 2019 +# +################################################################################ + +procedure main(args) +$ifndef _RNG_LIBRARY + write(&errout, "RNG libraries are not available") +$else + local rngFile, rngLib, n + + if *args ~= 3 then usage() + + rngLib := args[2] + n := args[3] + + loadrng(rngLib) # load the chosen generator + &error := -1 + + if rngFile := open(args[1],"r") then { + if not (getRngState(rngFile)) then { # read from the file and set &random + exit() + } + } else { + if rngFile := open(args[1],"c") then { + every 1 to n do {?0} # run the generator for a while + putRngState(rngFile) # write &random to the file + } else { + write(&errout, "Cannot create ", rngFile) + exit() + } + } + # write the next n values in the random sequence + every 1 to n do write(?0) + +$endif +end + +# -------------------------------------------------------------------------------- +# Write the Rng state to a file. For every rng (except rngIcon) the state is an +# integer array. The format of the file is +# rngName +# n (no of state elements) +# state[1] +# state[2] +# ... +# state[n] +# when the default rng is in use, the format is +# rngIcon +# value of &random + +procedure putRngState(rngFile) + local rng := loadrng() + local state, n + + write(rngFile, rng) # write the name of the generator + if rng == "rngIcon" then { + write(rngFile, &random) # write the state + } else { + state := &random + write(rngFile, *state) # write the number of state elements + every n := 1 to *state do write(rngFile, state[n]) # and each element + } +end + +# -------------------------------------------------------------------------------- +# Read the Rng state from a file and assign it to &random +procedure getRngState(rngFile) + local rng + local state, n + + rng := read(rngFile) + # We don't check that rng == loadrng() to allow the testing + # of assigning states from another generator. + + if rng == "rngIcon" then { + state := integer(read(rngFile)) + &random := state + } else { + n := integer(read(rngFile)) + state := array(n, 0) + every n := 1 to *state do { + state[n] := integer(read(rngFile)) + } + + # This will fail if the state from one generator is assigned to another. + if not (&random := state) then { + write("*** assignment to &random failed ***") + write("The error was \"", &errortext, "\"") + fail + } + } + return # success +end + +# -------------------------------------------------------------------------------- +procedure usage() + every write(&errout, ![ + "rngPutGet file rng n", + "", + "If the file does not exist, the generator specified in the second param", + "is loaded, run for n iterations, then the state is stored in the file.", + "After that the generator is run for another n iterations, each result is", + "printed to the standard output.", + "", + "If the file does exist, the generator is loaded and its state restored", + "the file. Then the generator is run for n iterations, each each result is", + "printed to the standard output." + ]) + + exit() +end diff --git a/plugins/rngLibraries/rngRbt/Makefile b/plugins/rngLibraries/rngRbt/Makefile new file mode 100644 index 000000000..a1605a34d --- /dev/null +++ b/plugins/rngLibraries/rngRbt/Makefile @@ -0,0 +1,49 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# Makefile for the rngRbt shared library +# +# Don Ward +# August 2019 +# +################################################################################ +include ../../../Makedefs + +.PHONY: Pure clean install test + +# Source files for the shared library +SRC=rngRbt.c rabbit.c ecrypt-sync.c +# Name of the target shared library +RNGLIB=rngRbt.so +# Special flags for dynamic shared libraries +CCSHFLAGS=-shared -fpic +# Installation directory is plugins/lib +LIBSDIR=../../lib + +all: $(RNGLIB) + +$(RNGLIB): $(SRC) + $(CC) $(CFLAGS) $(CCSHFLAGS) $^ -o $@ + +install: $(RNGLIB) + cp $^ $(LIBSDIR) + +clean: + rm -f *.o *.so test.output test-vectors + +Pure: clean + rm -f $(LIBDIR)/$(RNGLIB) + +etest: ecrypt-test.c rabbit.c ecrypt-sync.c + $(CC) $(CFLAGS) $^ -o $@ + +test: + unicon -s test-vectors.icn + ./test-vectors > test.output + diff selected.test-vectors test.output + diff --git a/plugins/rngLibraries/rngRbt/OriginalSource/rabbit_p3source.zip b/plugins/rngLibraries/rngRbt/OriginalSource/rabbit_p3source.zip new file mode 100644 index 000000000..cb54b2b6a Binary files /dev/null and b/plugins/rngLibraries/rngRbt/OriginalSource/rabbit_p3source.zip differ diff --git a/plugins/rngLibraries/rngRbt/README b/plugins/rngLibraries/rngRbt/README new file mode 100644 index 000000000..3e52e6123 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/README @@ -0,0 +1,33 @@ +Two posts (via the wayback machine) from https://www.ecrypt.eu.org/stream/phorum/read.php?1,1244) + +The test-vectors.txt file in this directory is the original (uncorrected) version. + +------------------------------------------------------------------------------------------ +Rabbit becomes public domain +Posted by: Erik Zenner (IP Logged) +Date: October 6, 2008 09:33AM + +Hi all! + +On behalf of Cryptico A/S, the company who designed the Rabbit stream cipher, I'm happy to relay the following: + +"Rabbit has been released into the public domain and may be used freely for +any purpose." + +So in retrospect, I think that it was a good decision not to make patent issues a key criterion for the eStream portfolio: The patent status can change, the algorithmic properties can't. + +Best regards + +Erik Zenner + +------------------------------------------------------------------------------------------ +Re: Rabbit becomes public domain +Posted by: mb (IP Logged) +Date: April 1, 2009 09:53PM + +I can confirm that there is a bug in the third line in the first three test vectors in the file test-vectors.txt inside rabbit_p3source.zip. + +See the thread "Question about RABBIT Test-Vector" in this forum for more information. + +Best regards, +Martin Boesgaard diff --git a/plugins/rngLibraries/rngRbt/ecrypt-config.h b/plugins/rngLibraries/rngRbt/ecrypt-config.h new file mode 100644 index 000000000..823f62884 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/ecrypt-config.h @@ -0,0 +1,280 @@ +/* ecrypt-config.h */ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + */ +/* *** Normally, it should not be necessary to edit this file. *** */ + +#ifndef ECRYPT_CONFIG +#define ECRYPT_CONFIG + +/* ------------------------------------------------------------------------- */ + +/* Guess the endianness of the target architecture. */ + +/* + * The LITTLE endian machines: + */ +#if defined (__LITTLE_ENDIAN__) +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__ultrix) /* Older MIPS */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__alpha) /* Alpha */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__i386) /* x86 (gcc) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_M_IX86) /* x86 (MSC, Borland) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(_MSC_VER) /* x86 (surely MSC) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */ +#define ECRYPT_LITTLE_ENDIAN +#elif defined(__ARMEL__) /* Raspberry Pi (gcc) */ +#define ECRYPT_LITTLE_ENDIAN + +/* + * The BIG endian machines: + */ +#elif defined(sun) /* Newer Sparc's */ +#define ECRYPT_BIG_ENDIAN +#elif defined(__ppc__) /* PowerPC */ +#define ECRYPT_BIG_ENDIAN + +/* + * Finally machines with UNKNOWN endianness: + */ +#elif defined (_AIX) /* RS6000 */ +#define ECRYPT_UNKNOWN +#elif defined(__hpux) /* HP-PA */ +#define ECRYPT_UNKNOWN +#elif defined(__aux) /* 68K */ +#define ECRYPT_UNKNOWN +#elif defined(__dgux) /* 88K (but P6 in latest boxes) */ +#define ECRYPT_UNKNOWN +#elif defined(__sgi) /* Newer MIPS */ +#define ECRYPT_UNKNOWN +#else /* Any other processor */ +#define ECRYPT_UNKNOWN +#endif + +/* ------------------------------------------------------------------------- */ + +/* + * Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit + * integers. + * + * Note: to enable 64-bit types on 32-bit compilers, it might be + * necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc + * -std=c99), or to allow compiler-specific extensions. + */ + +#include + +/* --- check char --- */ + +#if (UCHAR_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T char +#define U8C(v) (v##U) + +#if (UCHAR_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UCHAR_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T char +#define U16C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T char +#define U32C(v) (v##U) +#endif + +#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T char +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check short --- */ + +#if (USHRT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T short +#define U8C(v) (v##U) + +#if (USHRT_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (USHRT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T short +#define U16C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T short +#define U32C(v) (v##U) +#endif + +#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T short +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check int --- */ + +#if (UINT_MAX / 0xFU > 0xFU) +#ifndef I8T +#define I8T int +#define U8C(v) (v##U) + +#if (ULONG_MAX == 0xFFU) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (UINT_MAX / 0xFFU > 0xFFU) +#ifndef I16T +#define I16T int +#define U16C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFU > 0xFFFFU) +#ifndef I32T +#define I32T int +#define U32C(v) (v##U) +#endif + +#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU) +#ifndef I64T +#define I64T int +#define U64C(v) (v##U) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long --- */ + +#if (ULONG_MAX / 0xFUL > 0xFUL) +#ifndef I8T +#define I8T long +#define U8C(v) (v##UL) + +#if (ULONG_MAX == 0xFFUL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULONG_MAX / 0xFFUL > 0xFFUL) +#ifndef I16T +#define I16T long +#define U16C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL) +#ifndef I32T +#define I32T long +#define U32C(v) (v##UL) +#endif + +#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL) +#ifndef I64T +#define I64T long +#define U64C(v) (v##UL) +#define ECRYPT_NATIVE64 +#endif + +#endif +#endif +#endif +#endif + +/* --- check long long --- */ + +#ifdef ULLONG_MAX + +#if (ULLONG_MAX / 0xFULL > 0xFULL) +#ifndef I8T +#define I8T long long +#define U8C(v) (v##ULL) + +#if (ULLONG_MAX == 0xFFULL) +#define ECRYPT_I8T_IS_BYTE +#endif + +#endif + +#if (ULLONG_MAX / 0xFFULL > 0xFFULL) +#ifndef I16T +#define I16T long long +#define U16C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL) +#ifndef I32T +#define I32T long long +#define U32C(v) (v##ULL) +#endif + +#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL) +#ifndef I64T +#define I64T long long +#define U64C(v) (v##ULL) +#endif + +#endif +#endif +#endif +#endif + +#endif + +/* --- check __int64 --- */ + +#if !defined(__STDC__) && defined(_UI64_MAX) + +#ifndef I64T +#define I64T __int64 +#define U64C(v) (v##ui64) +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/plugins/rngLibraries/rngRbt/ecrypt-machine.h b/plugins/rngLibraries/rngRbt/ecrypt-machine.h new file mode 100644 index 000000000..7dec068a2 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/ecrypt-machine.h @@ -0,0 +1,56 @@ +/* ecrypt-machine.h */ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + */ +/* + * This file is included by 'ecrypt-portable.h'. It allows to override + * the default macros for specific platforms. Please carefully check + * the machine code generated by your compiler (with optimisations + * turned on) before deciding to edit this file. + */ + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT)) + +#define ECRYPT_MACHINE_ROT + +#if (defined(WIN32) && defined(_MSC_VER)) + +#undef ROTL32 +#undef ROTR32 +#undef ROTL64 +#undef ROTR64 + +#include + +#pragma intrinsic(_lrotl) /* compile rotations "inline" */ +#pragma intrinsic(_lrotr) + +#define ROTL32(v, n) _lrotl(v, n) +#define ROTR32(v, n) _lrotr(v, n) +#define ROTL64(v, n) _rotl64(v, n) +#define ROTR64(v, n) _rotr64(v, n) + +#endif + +#endif + +/* ------------------------------------------------------------------------- */ + +#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP)) + +#define ECRYPT_MACHINE_SWAP + +/* + * If you want to overwrite the default swap macros, put it here. And so on. + */ + +#endif + +/* ------------------------------------------------------------------------- */ diff --git a/plugins/rngLibraries/rngRbt/ecrypt-portable.h b/plugins/rngLibraries/rngRbt/ecrypt-portable.h new file mode 100644 index 000000000..670146945 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/ecrypt-portable.h @@ -0,0 +1,310 @@ +/* ecrypt-portable.h */ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + */ +/* + * WARNING: the conversions defined below are implemented as macros, + * and should be used carefully. They should NOT be used with + * parameters which perform some action. E.g., the following two lines + * are not equivalent: + * + * 1) ++x; y = ROTL32(x, n); + * 2) y = ROTL32(++x, n); + */ + +/* + * *** Please do not edit this file. *** + * + * The default macros can be overridden for specific architectures by + * editing 'ecrypt-machine.h'. + */ + +#ifndef ECRYPT_PORTABLE +#define ECRYPT_PORTABLE + +#include "ecrypt-config.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following types are defined (if available): + * + * u8: unsigned integer type, at least 8 bits + * u16: unsigned integer type, at least 16 bits + * u32: unsigned integer type, at least 32 bits + * u64: unsigned integer type, at least 64 bits + * + * s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64 + * + * The selection of minimum-width integer types is taken care of by + * 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit + * compilers, it might be necessary to switch from ISO C90 mode to ISO + * C99 mode (e.g., gcc -std=c99). + */ + +#ifdef I8T +typedef signed I8T s8; +typedef unsigned I8T u8; +#endif + +#ifdef I16T +typedef signed I16T s16; +typedef unsigned I16T u16; +#endif + +#ifdef I32T +typedef signed I32T s32; +typedef unsigned I32T u32; +#endif + +#ifdef I64T +typedef signed I64T s64; +typedef unsigned I64T u64; +#endif + +/* + * The following macros are used to obtain exact-width results. + */ + +#define U8V(v) ((u8)(v) & U8C(0xFF)) +#define U16V(v) ((u16)(v) & U16C(0xFFFF)) +#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF)) +#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF)) + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return words with their bits rotated over n + * positions to the left/right. + */ + +#define ECRYPT_DEFAULT_ROT + +#define ROTL8(v, n) \ + (U8V((v) << (n)) | ((v) >> (8 - (n)))) + +#define ROTL16(v, n) \ + (U16V((v) << (n)) | ((v) >> (16 - (n)))) + +#define ROTL32(v, n) \ + (U32V((v) << (n)) | ((v) >> (32 - (n)))) + +#define ROTL64(v, n) \ + (U64V((v) << (n)) | ((v) >> (64 - (n)))) + +#define ROTR8(v, n) ROTL8(v, 8 - (n)) +#define ROTR16(v, n) ROTL16(v, 16 - (n)) +#define ROTR32(v, n) ROTL32(v, 32 - (n)) +#define ROTR64(v, n) ROTL64(v, 64 - (n)) + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +/* + * The following macros return a word with bytes in reverse order. + */ + +#define ECRYPT_DEFAULT_SWAP + +#define SWAP16(v) \ + ROTL16(v, 8) + +#define SWAP32(v) \ + ((ROTL32(v, 8) & U32C(0x00FF00FF)) | \ + (ROTL32(v, 24) & U32C(0xFF00FF00))) + +#ifdef ECRYPT_NATIVE64 +#define SWAP64(v) \ + ((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \ + (ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \ + (ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \ + (ROTL64(v, 56) & U64C(0xFF000000FF000000))) +#else +#define SWAP64(v) \ + (((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32))) +#endif + +#include "ecrypt-machine.h" + +#define ECRYPT_DEFAULT_WTOW + +#ifdef ECRYPT_LITTLE_ENDIAN +#define U16TO16_LITTLE(v) (v) +#define U32TO32_LITTLE(v) (v) +#define U64TO64_LITTLE(v) (v) + +#define U16TO16_BIG(v) SWAP16(v) +#define U32TO32_BIG(v) SWAP32(v) +#define U64TO64_BIG(v) SWAP64(v) +#endif + +#ifdef ECRYPT_BIG_ENDIAN +#define U16TO16_LITTLE(v) SWAP16(v) +#define U32TO32_LITTLE(v) SWAP32(v) +#define U64TO64_LITTLE(v) SWAP64(v) + +#define U16TO16_BIG(v) (v) +#define U32TO32_BIG(v) (v) +#define U64TO64_BIG(v) (v) +#endif + +#include "ecrypt-machine.h" + +/* + * The following macros load words from an array of bytes with + * different types of endianness, and vice versa. + */ + +#define ECRYPT_DEFAULT_BTOW + +#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE)) + +#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0]) +#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0]) +#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0]) + +#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0]) +#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0]) +#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0]) + +#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v)) +#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v)) +#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v)) + +#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v)) +#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v)) +#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v)) + +#else + +#define U8TO16_LITTLE(p) \ + (((u16)((p)[0]) ) | \ + ((u16)((p)[1]) << 8)) + +#define U8TO32_LITTLE(p) \ + (((u32)((p)[0]) ) | \ + ((u32)((p)[1]) << 8) | \ + ((u32)((p)[2]) << 16) | \ + ((u32)((p)[3]) << 24)) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_LITTLE(p) \ + (((u64)((p)[0]) ) | \ + ((u64)((p)[1]) << 8) | \ + ((u64)((p)[2]) << 16) | \ + ((u64)((p)[3]) << 24) | \ + ((u64)((p)[4]) << 32) | \ + ((u64)((p)[5]) << 40) | \ + ((u64)((p)[6]) << 48) | \ + ((u64)((p)[7]) << 56)) +#else +#define U8TO64_LITTLE(p) \ + ((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32)) +#endif + +#define U8TO16_BIG(p) \ + (((u16)((p)[0]) << 8) | \ + ((u16)((p)[1]) )) + +#define U8TO32_BIG(p) \ + (((u32)((p)[0]) << 24) | \ + ((u32)((p)[1]) << 16) | \ + ((u32)((p)[2]) << 8) | \ + ((u32)((p)[3]) )) + +#ifdef ECRYPT_NATIVE64 +#define U8TO64_BIG(p) \ + (((u64)((p)[0]) << 56) | \ + ((u64)((p)[1]) << 48) | \ + ((u64)((p)[2]) << 40) | \ + ((u64)((p)[3]) << 32) | \ + ((u64)((p)[4]) << 24) | \ + ((u64)((p)[5]) << 16) | \ + ((u64)((p)[6]) << 8) | \ + ((u64)((p)[7]) )) +#else +#define U8TO64_BIG(p) \ + (((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4)) +#endif + +#define U16TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_LITTLE(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + (p)[2] = U8V((v) >> 16); \ + (p)[3] = U8V((v) >> 24); \ + (p)[4] = U8V((v) >> 32); \ + (p)[5] = U8V((v) >> 40); \ + (p)[6] = U8V((v) >> 48); \ + (p)[7] = U8V((v) >> 56); \ + } while (0) +#else +#define U64TO8_LITTLE(p, v) \ + do { \ + U32TO8_LITTLE((p), U32V((v) )); \ + U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \ + } while (0) +#endif + +#define U16TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) ); \ + (p)[1] = U8V((v) >> 8); \ + } while (0) + +#define U32TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 24); \ + (p)[1] = U8V((v) >> 16); \ + (p)[2] = U8V((v) >> 8); \ + (p)[3] = U8V((v) ); \ + } while (0) + +#ifdef ECRYPT_NATIVE64 +#define U64TO8_BIG(p, v) \ + do { \ + (p)[0] = U8V((v) >> 56); \ + (p)[1] = U8V((v) >> 48); \ + (p)[2] = U8V((v) >> 40); \ + (p)[3] = U8V((v) >> 32); \ + (p)[4] = U8V((v) >> 24); \ + (p)[5] = U8V((v) >> 16); \ + (p)[6] = U8V((v) >> 8); \ + (p)[7] = U8V((v) ); \ + } while (0) +#else +#define U64TO8_BIG(p, v) \ + do { \ + U32TO8_BIG((p), U32V((v) >> 32)); \ + U32TO8_BIG((p) + 4, U32V((v) )); \ + } while (0) +#endif + +#endif + +#include "ecrypt-machine.h" + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/plugins/rngLibraries/rngRbt/ecrypt-sync.c b/plugins/rngLibraries/rngRbt/ecrypt-sync.c new file mode 100644 index 000000000..dbae82432 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/ecrypt-sync.c @@ -0,0 +1,69 @@ +/* ecrypt-sync.c */ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + */ +/* *** Please do not edit this file. *** */ + +#include "ecrypt-sync.h" + +#ifdef ECRYPT_USES_DEFAULT_ALL_IN_ONE + +/* + * Default implementation of all-in-one encryption/decryption of + * (short) packets. + */ + +#ifdef ECRYPT_HAS_SINGLE_PACKET_FUNCTION + +void ECRYPT_process_packet( + int action, + ECRYPT_ctx* ctx, + const u8* iv, + const u8* input, + u8* output, + u32 msglen) +{ + ECRYPT_ivsetup(ctx, iv); + +#ifdef ECRYPT_HAS_SINGLE_BYTE_FUNCTION + ECRYPT_process_bytes(action, ctx, input, output, msglen); +#else + if (action == 0) + ECRYPT_encrypt_bytes(ctx, input, output, msglen); + else + ECRYPT_decrypt_bytes(ctx, input, output, msglen); +#endif +} + +#else + +void ECRYPT_encrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* plaintext, + u8* ciphertext, + u32 msglen) +{ + ECRYPT_ivsetup(ctx, iv); + ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, msglen); +} + +void ECRYPT_decrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* ciphertext, + u8* plaintext, + u32 msglen) +{ + ECRYPT_ivsetup(ctx, iv); + ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, msglen); +} + +#endif + +#endif diff --git a/plugins/rngLibraries/rngRbt/ecrypt-sync.h b/plugins/rngLibraries/rngRbt/ecrypt-sync.h new file mode 100644 index 000000000..b58209167 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/ecrypt-sync.h @@ -0,0 +1,373 @@ +/* ecrypt-sync.h */ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + */ +/* + * Header file for synchronous stream ciphers without authentication + * mechanism. + * + * *** Please only edit parts marked with "[edit]". *** + */ + +#ifndef ECRYPT_SYNC +#define ECRYPT_SYNC + +#include "ecrypt-portable.h" + +/* ------------------------------------------------------------------------- */ + +/* Cipher parameters */ + +/* + * The name of your cipher. + */ +#define ECRYPT_NAME "Rabbit Stream Cipher" + +/* + * Specify which key and IV sizes are supported by your cipher. A user + * should be able to enumerate the supported sizes by running the + * following code: + * + * for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i) + * { + * keysize = ECRYPT_KEYSIZE(i); + * + * ... + * } + * + * All sizes are in bits. + */ + +#define ECRYPT_MAXKEYSIZE 128 +#define ECRYPT_KEYSIZE(i) (128 + (i)*32) + +#define ECRYPT_MAXIVSIZE 64 +#define ECRYPT_IVSIZE(i) (64 + (i)*64) + +/* ------------------------------------------------------------------------- */ + +/* Data structures */ + +/* + * ECRYPT_ctx is the structure containing the representation of the + * internal state of your cipher. + */ + +typedef struct +{ + u32 x[8]; + u32 c[8]; + u32 carry; +} RABBIT_ctx; + +typedef struct +{ + /* + * Put here all state variable needed during the encryption process. + */ + RABBIT_ctx master_ctx; + RABBIT_ctx work_ctx; + /* This is used a buffer (Rabbit generates 2 doubles every cycle) */ + double hiowpe; /* Here Is One We Prepared Earlier :-) */ +} ECRYPT_ctx; + +/* ------------------------------------------------------------------------- */ + +/* Mandatory functions */ + +/* + * Key and message independent initialization. This function will be + * called once when the program starts (e.g., to build expanded S-box + * tables). + */ +void ECRYPT_init(void); + +/* + * Key setup. It is the user's responsibility to select the values of + * keysize and ivsize from the set of supported values specified + * above. + */ +void ECRYPT_keysetup( + ECRYPT_ctx* ctx, + const u8* key, + u32 keysize, /* Key size in bits. */ + u32 ivsize); /* IV size in bits. */ + +/* + * IV setup. After having called ECRYPT_keysetup(), the user is + * allowed to call ECRYPT_ivsetup() different times in order to + * encrypt/decrypt different messages with the same key but different + * IV's. + */ +void ECRYPT_ivsetup( + ECRYPT_ctx* ctx, + const u8* iv); + +/* + * Encryption/decryption of arbitrary length messages. + * + * For efficiency reasons, the API provides two types of + * encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function + * (declared here) encrypts byte strings of arbitrary length, while + * the ECRYPT_encrypt_blocks() function (defined later) only accepts + * lengths which are multiples of ECRYPT_BLOCKLENGTH. + * + * The user is allowed to make multiple calls to + * ECRYPT_encrypt_blocks() to incrementally encrypt a long message, + * but he is NOT allowed to make additional encryption calls once he + * has called ECRYPT_encrypt_bytes() (unless he starts a new message + * of course). For example, this sequence of calls is acceptable: + * + * ECRYPT_keysetup(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_blocks(); + * + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_bytes(); + * + * The following sequence is not: + * + * ECRYPT_keysetup(); + * ECRYPT_ivsetup(); + * ECRYPT_encrypt_blocks(); + * ECRYPT_encrypt_bytes(); + * ECRYPT_encrypt_blocks(); + */ + +/* + * By default ECRYPT_encrypt_bytes() and ECRYPT_decrypt_bytes() are + * defined as macros which redirect the call to a single function + * ECRYPT_process_bytes(). If you want to provide separate encryption + * and decryption functions, please undef + * ECRYPT_HAS_SINGLE_BYTE_FUNCTION. + */ +#define ECRYPT_HAS_SINGLE_BYTE_FUNCTION +#ifdef ECRYPT_HAS_SINGLE_BYTE_FUNCTION + +#define ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, msglen) \ + ECRYPT_process_bytes(0, ctx, plaintext, ciphertext, msglen) + +#define ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, msglen) \ + ECRYPT_process_bytes(1, ctx, ciphertext, plaintext, msglen) + +void ECRYPT_process_bytes( + int action, /* 0 = encrypt; 1 = decrypt; */ + ECRYPT_ctx* ctx, + const u8* input, + u8* output, + u32 msglen); /* Message length in bytes. */ + +#else + +void ECRYPT_encrypt_bytes( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 msglen); /* Message length in bytes. */ + +void ECRYPT_decrypt_bytes( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 msglen); /* Message length in bytes. */ + +#endif + +/* ------------------------------------------------------------------------- */ + +/* Optional features */ + +/* + * For testing purposes it can sometimes be useful to have a function + * which immediately generates keystream without having to provide it + * with a zero plaintext. If your cipher cannot provide this function + * (e.g., because it is not strictly a synchronous cipher), please + * reset the ECRYPT_GENERATES_KEYSTREAM flag. + */ + +#define ECRYPT_GENERATES_KEYSTREAM +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_bytes( + ECRYPT_ctx* ctx, + u8* keystream, + u32 length); /* Length of keystream in bytes. */ + +#endif + +/* ------------------------------------------------------------------------- */ + +/* Optional optimizations */ + +/* + * By default, the functions in this section are implemented using + * calls to functions declared above. However, you might want to + * implement them differently for performance reasons. + */ + +/* + * All-in-one encryption/decryption of (short) packets. + * + * The default definitions of these functions can be found in + * "ecrypt-sync.c". If you want to implement them differently, please + * undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag. + */ +#define ECRYPT_USES_DEFAULT_ALL_IN_ONE + +/* + * Undef ECRYPT_HAS_SINGLE_PACKET_FUNCTION if you want to provide + * separate packet encryption and decryption functions. + */ +#define ECRYPT_HAS_SINGLE_PACKET_FUNCTION +#ifdef ECRYPT_HAS_SINGLE_PACKET_FUNCTION + +#define ECRYPT_encrypt_packet( \ + ctx, iv, plaintext, ciphertext, mglen) \ + ECRYPT_process_packet(0, \ + ctx, iv, plaintext, ciphertext, mglen) + +#define ECRYPT_decrypt_packet( \ + ctx, iv, ciphertext, plaintext, mglen) \ + ECRYPT_process_packet(1, \ + ctx, iv, ciphertext, plaintext, mglen) + +void ECRYPT_process_packet( + int action, /* 0 = encrypt; 1 = decrypt; */ + ECRYPT_ctx* ctx, + const u8* iv, + const u8* input, + u8* output, + u32 msglen); + +#else + +void ECRYPT_encrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* plaintext, + u8* ciphertext, + u32 msglen); + +void ECRYPT_decrypt_packet( + ECRYPT_ctx* ctx, + const u8* iv, + const u8* ciphertext, + u8* plaintext, + u32 msglen); + +#endif + +/* + * Encryption/decryption of blocks. + * + * By default, these functions are defined as macros. If you want to + * provide a different implementation, please undef the + * ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions + * declared below. + */ + +#define ECRYPT_BLOCKLENGTH 16 + +#undef ECRYPT_USES_DEFAULT_BLOCK_MACROS +#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS + +#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \ + ECRYPT_keystream_bytes(ctx, keystream, \ + (blocks) * ECRYPT_BLOCKLENGTH) + +#endif + +#else + +/* + * Undef ECRYPT_HAS_SINGLE_BLOCK_FUNCTION if you want to provide + * separate block encryption and decryption functions. + */ +#define ECRYPT_HAS_SINGLE_BLOCK_FUNCTION +#ifdef ECRYPT_HAS_SINGLE_BLOCK_FUNCTION + +#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \ + ECRYPT_process_blocks(0, ctx, plaintext, ciphertext, blocks) + +#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \ + ECRYPT_process_blocks(1, ctx, ciphertext, plaintext, blocks) + +void ECRYPT_process_blocks( + int action, /* 0 = encrypt; 1 = decrypt; */ + ECRYPT_ctx* ctx, + const u8* input, + u8* output, + u32 blocks); /* Message length in blocks. */ + +#else + +void ECRYPT_encrypt_blocks( + ECRYPT_ctx* ctx, + const u8* plaintext, + u8* ciphertext, + u32 blocks); /* Message length in blocks. */ + +void ECRYPT_decrypt_blocks( + ECRYPT_ctx* ctx, + const u8* ciphertext, + u8* plaintext, + u32 blocks); /* Message length in blocks. */ + +#endif + +#ifdef ECRYPT_GENERATES_KEYSTREAM + +void ECRYPT_keystream_blocks( + ECRYPT_ctx* ctx, + u8* keystream, + u32 blocks); /* Keystream length in blocks. */ + +#endif + +#endif + +/* + * If your cipher can be implemented in different ways, you can use + * the ECRYPT_VARIANT parameter to allow the user to choose between + * them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please + * only use this possibility if you really think it could make a + * significant difference and keep the number of variants + * (ECRYPT_MAXVARIANT) as small as possible (definitely not more than + * 10). Note also that all variants should have exactly the same + * external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.). + */ +#define ECRYPT_MAXVARIANT 1 + +#ifndef ECRYPT_VARIANT +#define ECRYPT_VARIANT 1 +#endif + +#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT) +#error this variant does not exist +#endif + +/* ------------------------------------------------------------------------- */ + +#endif diff --git a/plugins/rngLibraries/rngRbt/ecrypt-test.c b/plugins/rngLibraries/rngRbt/ecrypt-test.c new file mode 100644 index 000000000..b789f8f77 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/ecrypt-test.c @@ -0,0 +1,948 @@ +/* ecrypt-test.c */ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + */ +/* + * API conformance test and test vector generation (DRAFT) + * + * Based on the NESSIE test suite (http://www.cryptonessie.org/) + */ + +/* ------------------------------------------------------------------------- */ + +#define ECRYPT_API ecrypt-sync.h + +#define QUOTE(str) QUOTE_HELPER(str) +#define QUOTE_HELPER(str) # str + +#include "ecrypt-portable.h" +//#include "ecrypt-config.h" +#include QUOTE(ECRYPT_API) + +#if defined(ECRYPT_SSYN) || defined(ECRYPT_SSYN_AE) +#error self-synchronising stream ciphers are not supported yet +#endif + +#if defined(ECRYPT_SYNC_AE) || defined(ECRYPT_SSYN_AE) +#define ECRYPT_AE +#endif + +#include +#include + +#define MAXKEYSIZEB ((ECRYPT_KEYSIZE(ECRYPT_MAXKEYSIZE) + 7) / 8) +#define MAXIVSIZEB ((ECRYPT_IVSIZE(ECRYPT_MAXIVSIZE) + 7) / 8) +#define MAXMACSIZEB ((ECRYPT_MACSIZE(ECRYPT_MAXMACSIZE) + 7) / 8) + +/* ------------------------------------------------------------------------- */ + +int compare_blocks(const u8 *m1, const u8 *m2, int len_bits) +{ + int i; + const int lenb = (len_bits + 7) >> 3; + const int mask0 = (1 << (((len_bits - 1) & 7) + 1)) - 1; + + if ((m1[0] & mask0) != (m2[0] & mask0)) + return 1; + + for (i = 1; i < lenb; i++) + if (m1[i] != m2[i]) + return 1; + + return 0; +} + +void print_data(FILE *fd, const char *str, const u8 *val, int len) +{ + int i; + + static const char hex[] = "0123456789ABCDEF"; + + fprintf(fd, "%28s = ", str); + + for (i = 0; i < len; i++) + { + if (i > 0 && (i & 0xF) == 0 && (len > 24)) + fprintf(fd, "\n%28s ", ""); + + putc(hex[(val[i] >> 4) & 0xF], fd); + putc(hex[(val[i] ) & 0xF], fd); + } + + fprintf(fd, "\n"); +} + +void print_chunk(FILE *fd, const char *str, const u8 *val, int start, int len) +{ + char indexed[80]; + + sprintf(indexed, "%s[%d..%d]", str, start, start + len - 1); + print_data(fd, indexed, val + start, len); +} + +void xor_digest(const u8 *stream, int size, u8 *out, int outsize) +{ + int i; + memset(out, 0, outsize); + for (i = 0; i < size; i++) + out[i % outsize] ^= stream[i]; +} + +/* ------------------------------------------------------------------------- */ + +#define TEST_STREAM_SIZEB 0x200 +#define TEST_STREAM_SIZEB_SET4 0x20000 +#define TEST_CHUNK 64 + +#ifdef ECRYPT_AE + +#define CTX ECRYPT_AE_ctx +#define IVSETUP ECRYPT_AE_ivsetup +#define ENCRYPT_BYTES ECRYPT_AE_encrypt_bytes +#define DECRYPT_BYTES ECRYPT_AE_decrypt_bytes +#define AUTHENTICATE_BYTES ECRYPT_AE_authenticate_bytes +#define ENCRYPT_BLOCKS ECRYPT_AE_encrypt_blocks +#define DECRYPT_BLOCKS ECRYPT_AE_decrypt_blocks +#define KEYSETUP ECRYPT_AE_keysetup +#define ENCRYPT_PACKET ECRYPT_AE_encrypt_packet +#define DECRYPT_PACKET ECRYPT_AE_decrypt_packet +#define FINALIZE ECRYPT_AE_finalize + +#else + +#define CTX ECRYPT_ctx +#define IVSETUP ECRYPT_ivsetup +#define ENCRYPT_BYTES ECRYPT_encrypt_bytes +#define DECRYPT_BYTES ECRYPT_decrypt_bytes +#define ENCRYPT_BLOCKS ECRYPT_encrypt_blocks +#define DECRYPT_BLOCKS ECRYPT_decrypt_blocks + +#define KEYSETUP(ctx, key, keysize, ivsize, macsize) \ + ECRYPT_keysetup(ctx, key, keysize, ivsize) + +#define ENCRYPT_PACKET( \ + ctx, iv, aad, aadlen, plaintext, ciphertext, msglen, mac) \ + ECRYPT_encrypt_packet(ctx, iv, plaintext, ciphertext, msglen) + +#define DECRYPT_PACKET( \ + ctx, iv, aad, aadlen, ciphertext, plaintext, msglen, mac) \ + ECRYPT_decrypt_packet(ctx, iv, ciphertext, plaintext, msglen) + +#define FINALIZE(ctx, checkmac) + +#endif + +typedef struct +{ + int keysize; + int ivsize; + int msglen; + + CTX ctx; + + u8 key[MAXKEYSIZEB]; + u8 iv[MAXIVSIZEB]; + + u8 plaintext[TEST_STREAM_SIZEB_SET4]; + u8 ciphertext[TEST_STREAM_SIZEB_SET4]; + u8 checktext[TEST_STREAM_SIZEB_SET4]; + +#ifdef ECRYPT_AE + int macsize; + int aadlen; + + u8 aad[TEST_CHUNK]; + u8 mac[MAXMACSIZEB]; + u8 checkmac[MAXMACSIZEB]; +#endif + + u8 xored[TEST_CHUNK]; + + FILE *fd; + +} test_struct; + +int errors = 0; + +void encrypt_and_check(test_struct* t, void (*print)(test_struct*, int)) +{ + const int blocks = t->msglen / ECRYPT_BLOCKLENGTH; + const int tail = blocks * ECRYPT_BLOCKLENGTH; + const int bytes = t->msglen % ECRYPT_BLOCKLENGTH; + + memset(t->ciphertext, 0, sizeof(t->ciphertext)); +#ifdef ECRYPT_AE + memset(t->mac, 0, sizeof(t->mac)); +#endif + + KEYSETUP(&t->ctx, t->key, t->keysize, t->ivsize, t->macsize); + ENCRYPT_PACKET(&t->ctx, t->iv, + t->aad, t->aadlen, t->plaintext, t->ciphertext, t->msglen, t->mac); + + print(t, 0); + +#ifdef ECRYPT_AE + memset(t->checkmac, 0, sizeof(t->checkmac)); +#endif + memset(t->checktext, 0, sizeof(t->checktext)); + + KEYSETUP(&t->ctx, t->key, t->keysize, t->ivsize, t->macsize); + DECRYPT_PACKET(&t->ctx, t->iv, + t->aad, t->aadlen, t->ciphertext, t->checktext, t->msglen, t->checkmac); + + if (compare_blocks(t->plaintext, t->checktext, t->msglen * 8) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> decrypt_packet:\n" + "*** decrypted text differs from plaintext:\n"); + print(t, 1); + } +#ifdef ECRYPT_AE + else if (compare_blocks(t->mac, t->checkmac, t->macsize) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> decrypt_packet:\n" + "*** decryption MAC differs from encryption MAC:\n"); + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); + } + + memset(t->checkmac, 0, sizeof(t->checkmac)); +#endif + memset(t->checktext, 0, sizeof(t->checktext)); + + IVSETUP(&t->ctx, t->iv); + +#ifdef ECRYPT_SUPPORTS_AAD + AUTHENTICATE_BYTES(&t->ctx, t->aad, t->aadlen); +#endif + + ENCRYPT_BYTES(&t->ctx, t->plaintext, t->checktext, t->msglen); + FINALIZE(&t->ctx, t->checkmac); + + if (compare_blocks(t->ciphertext, t->checktext, t->msglen * 8) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> encrypt_bytes:\n" + "*** encrypt_bytes generates different ciphertext:\n"); + print(t, 2); + } +#ifdef ECRYPT_AE + else if (compare_blocks(t->mac, t->checkmac, t->macsize) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> encrypt_bytes:\n" + "*** encrypt_bytes generates different MAC:\n"); + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); + } + + memset(t->checkmac, 0, sizeof(t->checkmac)); +#endif + memset(t->checktext, 0, sizeof(t->checktext)); + + IVSETUP(&t->ctx, t->iv); + +#ifdef ECRYPT_SUPPORTS_AAD + AUTHENTICATE_BYTES(&t->ctx, t->aad, t->aadlen); +#endif + + DECRYPT_BYTES(&t->ctx, t->ciphertext, t->checktext, t->msglen); + FINALIZE(&t->ctx, t->checkmac); + + if (compare_blocks(t->plaintext, t->checktext, t->msglen * 8) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> decrypt_bytes:\n" + "*** decrypt_bytes generates different plaintext:\n"); + print(t, 2); + } +#ifdef ECRYPT_AE + else if (compare_blocks(t->mac, t->checkmac, t->macsize) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> decrypt_bytes:\n" + "*** decrypt_bytes generates different MAC:\n"); + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); + } + + memset(t->checkmac, 0, sizeof(t->checkmac)); +#endif + memset(t->checktext, 0, sizeof(t->checktext)); + + IVSETUP(&t->ctx, t->iv); + +#ifdef ECRYPT_SUPPORTS_AAD + AUTHENTICATE_BYTES(&t->ctx, t->aad, t->aadlen); +#endif + + ENCRYPT_BLOCKS(&t->ctx, t->plaintext, t->checktext, blocks); + ENCRYPT_BYTES(&t->ctx, t->plaintext + tail, t->checktext + tail, bytes); + FINALIZE(&t->ctx, t->checkmac); + + if (compare_blocks(t->ciphertext, t->checktext, t->msglen * 8) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> encrypt_blocks/bytes:\n" + "*** encrypt_blocks/bytes generates different ciphertext:\n"); + print(t, 2); + } +#ifdef ECRYPT_AE + else if (compare_blocks(t->mac, t->checkmac, t->macsize) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> encrypt_blocks/bytes:\n" + "*** encrypt_blocks/bytes generates different MAC:\n"); + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); + } + + memset(t->checkmac, 0, sizeof(t->checkmac)); +#endif + memset(t->checktext, 0, sizeof(t->checktext)); + + IVSETUP(&t->ctx, t->iv); + +#ifdef ECRYPT_SUPPORTS_AAD + AUTHENTICATE_BYTES(&t->ctx, t->aad, t->aadlen); +#endif + + DECRYPT_BLOCKS(&t->ctx, t->ciphertext, t->checktext, blocks); + DECRYPT_BYTES(&t->ctx, t->ciphertext + tail, t->checktext + tail, bytes); + FINALIZE(&t->ctx, t->checkmac); + + if (compare_blocks(t->plaintext, t->checktext, t->msglen * 8) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> decrypt_blocks/bytes:\n" + "*** decrypt_blocks/bytes generates different plaintext:\n"); + print(t, 2); + } +#ifdef ECRYPT_AE + else if (compare_blocks(t->mac, t->checkmac, t->macsize) != 0) + { + ++errors; + fprintf(t->fd, + "*** ERROR: encrypt_packet <-> decrypt_blocks/bytes:\n" + "*** decrypt_blocks/bytes generates different MAC:\n"); + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); + } +#endif + + fprintf(t->fd, "\n"); +} + +void print_stream(test_struct* t, int type) +{ + const int chunk = TEST_CHUNK; + + switch (type) + { + case 0: + print_data(t->fd, "key", t->key, (t->keysize + 7) / 8); + print_data(t->fd, "IV", t->iv, (t->ivsize + 7) / 8); + + print_chunk(t->fd, "stream", t->ciphertext, 0, chunk); + print_chunk(t->fd, "stream", t->ciphertext, t->msglen/2-chunk, chunk); + print_chunk(t->fd, "stream", t->ciphertext, t->msglen/2, chunk); + print_chunk(t->fd, "stream", t->ciphertext, t->msglen-chunk, chunk); + + xor_digest(t->ciphertext, t->msglen, t->xored, chunk); + print_data(t->fd, "xor-digest", t->xored, chunk); + +#ifdef ECRYPT_AE + print_data(t->fd, "MAC", t->mac, (t->macsize + 7) / 8); +#endif + break; + case 1: + print_chunk(t->fd, "decryption", t->checktext, 0, chunk); + print_chunk(t->fd, "decryption", t->checktext, t->msglen/2-chunk, chunk); + print_chunk(t->fd, "decryption", t->checktext, t->msglen/2, chunk); + print_chunk(t->fd, "decryption", t->checktext, t->msglen-chunk, chunk); + + xor_digest(t->checktext, t->msglen, t->xored, chunk); + print_data(t->fd, "xor-digest", t->xored, chunk); + +#ifdef ECRYPT_AE + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); +#endif + break; + case 2: + print_chunk(t->fd, "stream", t->checktext, 0, chunk); + print_chunk(t->fd, "stream", t->checktext, t->msglen/2-chunk, chunk); + print_chunk(t->fd, "stream", t->checktext, t->msglen/2, chunk); + print_chunk(t->fd, "stream", t->checktext, t->msglen-chunk, chunk); + + xor_digest(t->checktext, t->msglen, t->xored, chunk); + print_data(t->fd, "xor-digest", t->xored, chunk); + +#ifdef ECRYPT_AE + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); +#endif + break; + } +} + +void print_pair(test_struct* t, int type) +{ + switch (type) + { + case 0: + print_data(t->fd, "key", t->key, (t->keysize + 7) / 8); + print_data(t->fd, "IV", t->iv, (t->ivsize + 7) / 8); + +#ifdef ECRYPT_SUPPORTS_AAD + if (t->aadlen) + print_data(t->fd, "AAD", t->aad, t->aadlen); +#endif + print_data(t->fd, "plaintext", t->plaintext, t->msglen); + print_data(t->fd, "ciphertext", t->ciphertext, t->msglen); +#ifdef ECRYPT_AE + print_data(t->fd, "MAC", t->mac, (t->macsize + 7) / 8); +#endif + break; + case 1: + print_data(t->fd, "decryption", t->checktext, t->msglen); +#ifdef ECRYPT_AE + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); +#endif + break; + case 2: + print_data(t->fd, "ciphertext", t->checktext, t->msglen); +#ifdef ECRYPT_AE + print_data(t->fd, "MAC", t->checkmac, (t->macsize + 7) / 8); +#endif + break; + } +} + +void test_vectors(FILE *fd, int keysize, int ivsize, int macsize) +{ + +#define STREAM_VECTOR(set, vector) \ + do { \ + fprintf(fd, "Set %d, vector#%3d:\n", set, vector); \ + encrypt_and_check(&t, print_stream); \ + } while (0) + +#define MAC_VECTOR(set, vector) \ + do { \ + fprintf(fd, "Set %d, vector#%3d:\n", set, vector); \ + encrypt_and_check(&t, print_pair); \ + } while (0) + +#define AAD_VECTOR(set, vector) \ + do { \ + fprintf(fd, "Set %d, vector#%3d:\n", set, vector); \ + encrypt_and_check(&t, print_pair); \ + } while (0) + + test_struct t; + int i, v; + + fprintf(fd, + "****************************************" + "****************************************\n"); + fprintf(fd, + "* ECRYPT Stream" + " Cipher Project *\n"); + fprintf(fd, + "****************************************" + "****************************************\n"); + fprintf(fd, "\n"); + fprintf(fd, "Primitive Name: %s\n", ECRYPT_NAME); + fprintf(fd, "================%.*s\n", (int)strlen(ECRYPT_NAME), + "=========================================="); + fprintf(fd, "Key size: %d bits\n", keysize); + fprintf(fd, "IV size: %d bits\n", ivsize); +#ifdef ECRYPT_AE + fprintf(fd, "MAC size: %d bits\n", macsize); +#endif + fprintf(fd, "\n"); + fprintf(fd, "Preferred block length: %d bytes\n", ECRYPT_BLOCKLENGTH); + fprintf(fd, "\n"); + + memset(t.plaintext, 0, sizeof(t.plaintext)); + memset(t.ciphertext, 0, sizeof(t.ciphertext)); + + /* check key stream */ + + t.fd = fd; + + t.keysize = keysize; + t.ivsize = ivsize; +#ifdef ECRYPT_AE + t.macsize = macsize; + t.aadlen = 0; +#endif + t.msglen = TEST_STREAM_SIZEB; + + fprintf(t.fd, "Test vectors -- set 1\n"); + fprintf(t.fd, "=====================\n\n"); + fprintf(t.fd, "(stream is generated by encrypting %d zero bytes)\n\n", + t.msglen); + + memset(t.iv, 0, sizeof(t.iv)); + + for (v = 0; v < t.keysize; v++) + { + memset(t.key, 0, sizeof(t.key)); + t.key[v >> 3] = 1 << (7 - (v & 7)); + + STREAM_VECTOR(1, v); + } + + fprintf(t.fd, "Test vectors -- set 2\n"); + fprintf(t.fd, "=====================\n\n"); + + memset(t.iv, 0, sizeof(t.iv)); + + for (v = 0; v < 256; v++) + { + memset(t.key, v, sizeof(t.key)); + + STREAM_VECTOR(2, v); + } + + fprintf(fd, "Test vectors -- set 3\n"); + fprintf(fd, "=====================\n\n"); + + memset(t.iv, 0, sizeof(t.iv)); + + for (v = 0; v < 256; v++) + { + for (i = 0; i < sizeof(t.key); i++) + t.key[i] = (i + v) & 0xFF; + + STREAM_VECTOR(3, v); + } + + t.msglen = TEST_STREAM_SIZEB_SET4; + + fprintf(t.fd, "Test vectors -- set 4\n"); + fprintf(t.fd, "=====================\n\n"); + + for (v = 0; v < 4; v++) + { + for (i = 0; i< sizeof(t.key); i++) + t.key[i] = (i * 0x53 + v * 5) & 0xFF; + + STREAM_VECTOR(4, v); + } + + t.msglen = TEST_STREAM_SIZEB; + + fprintf(t.fd, "Test vectors -- set 5\n"); + fprintf(t.fd, "=====================\n\n"); + + memset(t.key, 0, sizeof(t.key)); + + for (v = 0; v < t.ivsize; v++) + { + memset(t.iv, 0, sizeof(t.iv)); + t.iv[v >> 3] = 1 << (7 - (v & 7)); + + STREAM_VECTOR(5, v); + } + + t.msglen = TEST_STREAM_SIZEB_SET4; + + fprintf(t.fd, "Test vectors -- set 6\n"); + fprintf(t.fd, "=====================\n\n"); + + for (v = 0; v < 4; v++) + { + for (i = 0; i < sizeof(t.key); i++) + t.key[i] = (i * 0x53 + v * 5) & 0xFF; + + for (i = 0; i < sizeof(t.iv); i++) + t.iv[i] = (i * 0x67 + v * 9 + 13) & 0xFF; + + STREAM_VECTOR(6, v); + } + + t.msglen = TEST_STREAM_SIZEB; + +#if defined(ECRYPT_AE) || !defined(ECRYPT_GENERATES_KEYSTREAM) + /* check MAC */ + + fprintf(t.fd, "Test vectors -- set 7\n"); + fprintf(t.fd, "=====================\n\n"); + + memset(t.key, 0, sizeof(t.key)); + memset(t.iv, 0, sizeof(t.iv)); + memset(t.plaintext, 0, sizeof(t.plaintext)); + + for (i = 0; i < sizeof(t.key); i++) + t.key[i] = (i * 0x11) & 0xFF; + + for (v = 0; v <= TEST_CHUNK; v++) + { + t.msglen = v; + + MAC_VECTOR(7, v); + } + + t.msglen = TEST_CHUNK / 2; + + fprintf(t.fd, "Test vectors -- set 8\n"); + fprintf(t.fd, "=====================\n\n"); + + memset(t.key, 0, sizeof(t.key)); + memset(t.iv, 0, sizeof(t.iv)); + + for (v = 0; v < t.msglen * 8; v++) + { + memset(t.plaintext, 0, sizeof(t.plaintext)); + t.plaintext[v >> 3] = 1 << (7 - (v & 7)); + + MAC_VECTOR(8, v); + } + + fprintf(t.fd, "Test vectors -- set 9\n"); + fprintf(t.fd, "=====================\n\n"); + + for (v = 0; v < 4; v++) + { + for (i = 0; i < sizeof(t.key); i++) + t.key[i] = (i * 0x53 + v * 5) & 0xFF; + + for (i = 0; i < sizeof(t.iv); i++) + t.iv[i] = (i * 0x67 + v * 9 + 13) & 0xFF; + + for (i = 0; i < t.msglen; i++) + t.plaintext[i] = (i * 0x61 + v * 7 + 109) & 0xFF; + + MAC_VECTOR(9, v); + } + +#ifdef ECRYPT_SUPPORTS_AAD + /* check AAD */ + + t.msglen = TEST_CHUNK / 2; + + fprintf(t.fd, "Test vectors -- set 10\n"); + fprintf(t.fd, "======================\n\n"); + + memset(t.key, 0, sizeof(t.key)); + memset(t.iv, 0, sizeof(t.iv)); + memset(t.plaintext, 0, sizeof(t.plaintext)); + memset(t.aad, 0, sizeof(t.aad)); + + for (i = 0; i < sizeof(t.key); i++) + t.key[i] = (i * 0x11) & 0xFF; + + for (v = 0; v <= TEST_CHUNK; v++) + { + t.aadlen = v; + + AAD_VECTOR(10, v); + } + + t.aadlen = TEST_CHUNK / 2; + + fprintf(t.fd, "Test vectors -- set 11\n"); + fprintf(t.fd, "======================\n\n"); + + memset(t.key, 0, sizeof(t.key)); + memset(t.iv, 0, sizeof(t.iv)); + memset(t.plaintext, 0, sizeof(t.plaintext)); + + for (v = 0; v < t.aadlen * 8; v++) + { + memset(t.aad, 0, sizeof(t.aad)); + t.aad[v >> 3] = 1 << (7 - (v & 7)); + + AAD_VECTOR(11, v); + } + + fprintf(t.fd, "Test vectors -- set 12\n"); + fprintf(t.fd, "======================\n\n"); + + for (v = 0; v < 4; v++) + { + for (i = 0; i < sizeof(t.key); i++) + t.key[i] = (i * 0x53 + v * 5) & 0xFF; + + for (i = 0; i < sizeof(t.iv); i++) + t.iv[i] = (i * 0x67 + v * 9 + 13) & 0xFF; + + for (i = 0; i < t.msglen; i++) + t.plaintext[i] = (i * 0x61 + v * 7 + 109) & 0xFF; + + for (i = 0; i < t.aadlen; i++) + t.aad[i] = (i * 0x25 + v * 13 + 11) & 0xFF; + + AAD_VECTOR(12, v); + } +#endif +#endif + + fprintf(t.fd, "\n\nEnd of test vectors\n"); +} + +/* ------------------------------------------------------------------------- */ + +void test_if_conform_to_api(FILE *fd, int keysize, int ivsize, int macsize) +{ + CTX ctx[2]; + + u8 key[2][MAXKEYSIZEB]; + u8 iv[2][MAXIVSIZEB]; + + u8 plaintext[TEST_CHUNK + ECRYPT_BLOCKLENGTH]; + u8 ciphertext[3][TEST_CHUNK + ECRYPT_BLOCKLENGTH]; +#ifdef ECRYPT_AE + u8 mac[3][MAXMACSIZEB]; +#endif + + int msglen = TEST_CHUNK; + + int i; + + for(i = 0; i < MAXKEYSIZEB; i++) + { + key[0][i] = 3 * i + 5; + key[1][i] = 240 - 5 * i; + } + + for(i = 0; i < MAXIVSIZEB; i++) + { + iv[0][i] = 9 * i + 25; + iv[1][i] = 11 * i + 17; + } + + memset(plaintext, 0, sizeof(plaintext)); + memset(ciphertext, 0, sizeof(ciphertext)); + + KEYSETUP(&ctx[0], key[0], keysize, ivsize, macsize); + + IVSETUP(&ctx[0], iv[0]); + ENCRYPT_BYTES(&ctx[0], plaintext, ciphertext[0], msglen); + FINALIZE(&ctx[0], mac[0]); + + IVSETUP(&ctx[0], iv[0]); + ENCRYPT_BYTES(&ctx[0], plaintext, ciphertext[1], msglen); + FINALIZE(&ctx[0], mac[1]); + + if (compare_blocks(ciphertext[0], ciphertext[1], msglen * 8) != 0) + { + ++errors; + fprintf(fd, + "*** ERROR: Code does not conform to ECRYPT API:\n" + "*** Two calls to ivsetup produced different results:\n"); + + print_data(fd, "K", key[0], (keysize + 7) / 8); + print_data(fd, "IV", iv[0], (ivsize + 7) / 8); + + print_data(fd, "P", plaintext, msglen); + print_data(fd, "C after 1st IV setup", ciphertext[0], msglen); + print_data(fd, "C after 2nd IV setup", ciphertext[1], msglen); + fprintf(fd, "\n"); + fflush(fd); + } +#ifdef ECRYPT_AE + else if (compare_blocks(mac[0], mac[1], macsize) != 0) + { + ++errors; + fprintf(fd, + "*** ERROR: Code does not conform to ECRYPT API:\n" + "*** Two calls to ivsetup produced different results:\n"); + + print_data(fd, "K", key[0], (keysize + 7) / 8); + print_data(fd, "IV", iv[0], (ivsize + 7) / 8); + + print_data(fd, "P", plaintext, msglen); + print_data(fd, "MAC after 1st IV setup", mac[0], (macsize + 7) / 8); + print_data(fd, "MAC after 2nd IV setup", mac[1], (macsize + 7) / 8); + fprintf(fd, "\n"); + fflush(fd); + } +#endif + + memset(ciphertext, 0, sizeof(ciphertext)); + + KEYSETUP(&ctx[0], key[0], keysize, ivsize, macsize); + IVSETUP(&ctx[0], iv[0]); + ENCRYPT_BYTES(&ctx[0], plaintext, ciphertext[0], msglen); + FINALIZE(&ctx[0], mac[0]); + + KEYSETUP(&ctx[1], key[1], keysize, ivsize, macsize); + IVSETUP(&ctx[1], iv[1]); + ENCRYPT_BYTES(&ctx[1], plaintext, ciphertext[1], msglen); + FINALIZE(&ctx[1], mac[1]); + + IVSETUP(&ctx[0], iv[0]); + + IVSETUP(&ctx[1], iv[1]); + + ENCRYPT_BYTES(&ctx[0], plaintext, ciphertext[2], msglen); + FINALIZE(&ctx[0], mac[2]); + + if (compare_blocks(ciphertext[0], ciphertext[2], msglen * 8) != 0) + { + ++errors; + fprintf(fd, + "*** ERROR: Code does not conform to ECRYPT API:\n" + "*** code produces inconsistent results when calls with different\n" + "*** contexts are interleaved:\n"); + + if (compare_blocks(ciphertext[1], ciphertext[2], msglen * 8) == 0) + fprintf(fd, + "*** (this is probably due to the use of static state variables)\n"); + + print_data(fd, "K1", key[0], (keysize + 7) / 8); + print_data(fd, "K2", key[1], (keysize + 7) / 8); + print_data(fd, "IV1", iv[0], (ivsize + 7) / 8); + print_data(fd, "IV2", iv[0], (ivsize + 7) / 8); + + print_data(fd, "P", plaintext, msglen); + print_data(fd, "C by K1", ciphertext[0], msglen); + print_data(fd, "C by K2", ciphertext[1], msglen); + print_data(fd, "C by K1 after IV2 setup", ciphertext[2], msglen); + fprintf(fd, "\n"); + fflush(fd); + } +#ifdef ECRYPT_AE + else if (compare_blocks(mac[0], mac[2], macsize) != 0) + { + ++errors; + fprintf(fd, + "*** ERROR: Code does not conform to ECRYPT API:\n" + "*** code produces inconsistent results when calls with different\n" + "*** contexts are interleaved:\n"); + + if (compare_blocks(mac[1], mac[2], macsize) == 0) + fprintf(fd, + "*** (this is probably due to the use of static state variables)\n"); + + print_data(fd, "K1", key[0], (keysize + 7) / 8); + print_data(fd, "K2", key[1], (keysize + 7) / 8); + print_data(fd, "IV1", iv[0], (ivsize + 7) / 8); + print_data(fd, "IV2", iv[0], (ivsize + 7) / 8); + + print_data(fd, "P", plaintext, msglen); + print_data(fd, "MAC by K1", mac[0], (macsize + 7) / 8); + print_data(fd, "MAC by K2", mac[1], (macsize + 7) / 8); + print_data(fd, "MAC by K1 after IV2 setup", mac[2], (macsize + 7) / 8); + fprintf(fd, "\n"); + fflush(fd); + } +#endif + +#define B ECRYPT_BLOCKLENGTH + + memset(ciphertext, 0, sizeof(ciphertext)); + + KEYSETUP(&ctx[0], key[0], keysize, ivsize, macsize); + IVSETUP(&ctx[0], iv[0]); + ENCRYPT_BYTES(&ctx[0], plaintext + B, ciphertext[0] + B, msglen); + FINALIZE(&ctx[0], mac[0]); + + KEYSETUP(&ctx[1], key[1], keysize, ivsize, macsize); + IVSETUP(&ctx[1], iv[1]); + ENCRYPT_BLOCKS(&ctx[1], plaintext, ciphertext[1], 1); + ENCRYPT_BYTES(&ctx[1], plaintext + B, ciphertext[1] + B, msglen); + FINALIZE(&ctx[1], mac[1]); + + IVSETUP(&ctx[0], iv[0]); + + IVSETUP(&ctx[1], iv[1]); + ENCRYPT_BLOCKS(&ctx[1], plaintext, ciphertext[2], 1); + + ENCRYPT_BYTES(&ctx[0], plaintext + B, ciphertext[2] + B, msglen); + FINALIZE(&ctx[0], mac[2]); + + if (compare_blocks(ciphertext[0] + B, ciphertext[2] + B, msglen * 8) != 0) + { + ++errors; + fprintf(fd, + "*** ERROR: Code does not conform to ECRYPT API:\n" + "*** code produces inconsistent results when calls with different\n" + "*** contexts are interleaved:\n"); + + if (compare_blocks(ciphertext[1], ciphertext[2], (msglen + B) * 8) == 0) + fprintf(fd, + "*** (this is probably due to the use of static state variables)\n"); + + print_data(fd, "K1", key[0], (keysize + 7) / 8); + print_data(fd, "K2", key[1], (keysize + 7) / 8); + print_data(fd, "IV1", iv[0], (ivsize + 7) / 8); + print_data(fd, "IV2", iv[1], (ivsize + 7) / 8); + + print_data(fd, "(last part of) P", plaintext + B, msglen); + print_data(fd, "C by K1", ciphertext[0] + B, msglen); + print_data(fd, "last part of C by K2", ciphertext[1] + B, msglen); + print_data(fd, "C by K1 after calls K2", ciphertext[2] + B, msglen); + fprintf(fd, "\n"); + fflush(fd); + } +#ifdef ECRYPT_AE + else if (compare_blocks(mac[0], mac[2], macsize) != 0) + { + ++errors; + fprintf(fd, + "*** ERROR: Code does not conform to ECRYPT API:\n" + "*** code produces inconsistent results when calls with different\n" + "*** contexts are interleaved:\n"); + + if (compare_blocks(mac[1], mac[2], macsize) == 0) + fprintf(fd, + "*** (this is probably due to the use of static state variables)\n"); + + print_data(fd, "K1", key[0], (keysize + 7) / 8); + print_data(fd, "K2", key[1], (keysize + 7) / 8); + print_data(fd, "IV1", iv[0], (ivsize + 7) / 8); + print_data(fd, "IV2", iv[1], (ivsize + 7) / 8); + + print_data(fd, "(last part of) P", plaintext, msglen); + print_data(fd, "MAC by K1", mac[0], (macsize + 7) / 8); + print_data(fd, "MAC by K2", mac[1], (macsize + 7) / 8); + print_data(fd, "MAC by K1 after K2 calls", mac[2], (macsize + 7) / 8); + fprintf(fd, "\n"); + fflush(fd); + } +#endif +} + +/* ------------------------------------------------------------------------- */ + +int main() +{ + int ikey; + int iiv; + + ECRYPT_init(); + + for(ikey=0; ikey<=ECRYPT_MAXKEYSIZE; ikey++) + for(iiv=0; iiv<=ECRYPT_MAXIVSIZE; iiv++) + { + const int keysize = ECRYPT_KEYSIZE(ikey); + const int ivsize = ECRYPT_IVSIZE(iiv); +#ifdef ECRYPT_AE + const int macsize = ECRYPT_MACSIZE(0); +#else + const int macsize = 0; +#endif + if(keysize&(keysize-1)) continue; /* Only powers of 2 */ + if(ivsize&(ivsize-1)) continue; /* Only powers of 2 */ + + test_if_conform_to_api(stderr, keysize, ivsize, macsize); + test_vectors(stdout, keysize, ivsize, macsize); + } + + fprintf(stderr, "There where %d errors.\n", errors); + + return 0; +} diff --git a/plugins/rngLibraries/rngRbt/rabbit.c b/plugins/rngLibraries/rngRbt/rabbit.c new file mode 100644 index 000000000..7f9e3776d --- /dev/null +++ b/plugins/rngLibraries/rngRbt/rabbit.c @@ -0,0 +1,335 @@ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + * + * The original version of this code was released into the public domain in + * October 2008 (despite the copyright notice below, which has not been altered). + * See the README file in this directory for details. + * + */ +/******************************************************************************/ +/* File name: rabbit.c */ +/*----------------------------------------------------------------------------*/ +/* Rabbit C source code in ECRYPT format */ +/*----------------------------------------------------------------------------*/ +/* Copyright (C) Cryptico A/S. All rights reserved. */ +/* */ +/* YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE. */ +/* */ +/* This software is developed by Cryptico A/S and/or its suppliers. */ +/* All title and intellectual property rights in and to the software, */ +/* including but not limited to patent rights and copyrights, are owned by */ +/* Cryptico A/S and/or its suppliers. */ +/* */ +/* The software may be used solely for non-commercial purposes */ +/* without the prior written consent of Cryptico A/S. For further */ +/* information on licensing terms and conditions please contact Cryptico A/S */ +/* at info@cryptico.com */ +/* */ +/* Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption" are */ +/* either trademarks or registered trademarks of Cryptico A/S. */ +/* */ +/* Cryptico A/S shall not in any way be liable for any use of this software. */ +/* The software is provided "as is" without any express or implied warranty. */ +/* */ +/******************************************************************************/ + +#include "ecrypt-sync.h" +#include "ecrypt-portable.h" + +/* -------------------------------------------------------------------------- */ + +/* Square a 32-bit unsigned integer to obtain the 64-bit result and return */ +/* the upper 32 bits XOR the lower 32 bits */ +static u32 RABBIT_g_func(u32 x) +{ + /* Temporary variables */ + u32 a, b, h, l; + + /* Construct high and low argument for squaring */ + a = x&0xFFFF; + b = x>>16; + + /* Calculate high and low result of squaring */ + h = (((U32V(a*a)>>17) + U32V(a*b))>>15) + b*b; + l = x*x; + + /* Return high XOR low */ + return U32V(h^l); +} + +/* -------------------------------------------------------------------------- */ + +/* Calculate the next internal state */ +static void RABBIT_next_state(RABBIT_ctx *p_instance) +{ + /* Temporary variables */ + u32 g[8], c_old[8], i; + + /* Save old counter values */ + for (i=0; i<8; i++) + c_old[i] = p_instance->c[i]; + + /* Calculate new counter values */ + p_instance->c[0] = U32V(p_instance->c[0] + 0x4D34D34D + p_instance->carry); + p_instance->c[1] = U32V(p_instance->c[1] + 0xD34D34D3 + (p_instance->c[0] < c_old[0])); + p_instance->c[2] = U32V(p_instance->c[2] + 0x34D34D34 + (p_instance->c[1] < c_old[1])); + p_instance->c[3] = U32V(p_instance->c[3] + 0x4D34D34D + (p_instance->c[2] < c_old[2])); + p_instance->c[4] = U32V(p_instance->c[4] + 0xD34D34D3 + (p_instance->c[3] < c_old[3])); + p_instance->c[5] = U32V(p_instance->c[5] + 0x34D34D34 + (p_instance->c[4] < c_old[4])); + p_instance->c[6] = U32V(p_instance->c[6] + 0x4D34D34D + (p_instance->c[5] < c_old[5])); + p_instance->c[7] = U32V(p_instance->c[7] + 0xD34D34D3 + (p_instance->c[6] < c_old[6])); + p_instance->carry = (p_instance->c[7] < c_old[7]); + + /* Calculate the g-values */ + for (i=0;i<8;i++) + g[i] = RABBIT_g_func(U32V(p_instance->x[i] + p_instance->c[i])); + + /* Calculate new state values */ + p_instance->x[0] = U32V(g[0] + ROTL32(g[7],16) + ROTL32(g[6], 16)); + p_instance->x[1] = U32V(g[1] + ROTL32(g[0], 8) + g[7]); + p_instance->x[2] = U32V(g[2] + ROTL32(g[1],16) + ROTL32(g[0], 16)); + p_instance->x[3] = U32V(g[3] + ROTL32(g[2], 8) + g[1]); + p_instance->x[4] = U32V(g[4] + ROTL32(g[3],16) + ROTL32(g[2], 16)); + p_instance->x[5] = U32V(g[5] + ROTL32(g[4], 8) + g[3]); + p_instance->x[6] = U32V(g[6] + ROTL32(g[5],16) + ROTL32(g[4], 16)); + p_instance->x[7] = U32V(g[7] + ROTL32(g[6], 8) + g[5]); +} + +/* ------------------------------------------------------------------------- */ + +/* No initialization is needed for Rabbit */ +void ECRYPT_init(void) +{ + return; +} + +/* ------------------------------------------------------------------------- */ + +/* Key setup */ +void ECRYPT_keysetup(ECRYPT_ctx* ctx, const u8* key, u32 keysize, u32 ivsize) +{ + /* Temporary variables */ + u32 k0, k1, k2, k3, i; + + /* Generate four subkeys */ + k0 = U8TO32_LITTLE(key+ 0); + k1 = U8TO32_LITTLE(key+ 4); + k2 = U8TO32_LITTLE(key+ 8); + k3 = U8TO32_LITTLE(key+12); + + /* Generate initial state variables */ + ctx->master_ctx.x[0] = k0; + ctx->master_ctx.x[2] = k1; + ctx->master_ctx.x[4] = k2; + ctx->master_ctx.x[6] = k3; + ctx->master_ctx.x[1] = U32V(k3<<16) | (k2>>16); + ctx->master_ctx.x[3] = U32V(k0<<16) | (k3>>16); + ctx->master_ctx.x[5] = U32V(k1<<16) | (k0>>16); + ctx->master_ctx.x[7] = U32V(k2<<16) | (k1>>16); + + /* Generate initial counter values */ + ctx->master_ctx.c[0] = ROTL32(k2, 16); + ctx->master_ctx.c[2] = ROTL32(k3, 16); + ctx->master_ctx.c[4] = ROTL32(k0, 16); + ctx->master_ctx.c[6] = ROTL32(k1, 16); + ctx->master_ctx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF); + ctx->master_ctx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF); + ctx->master_ctx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF); + ctx->master_ctx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF); + + /* Clear carry bit */ + ctx->master_ctx.carry = 0; + + /* Iterate the system four times */ + for (i=0; i<4; i++) + RABBIT_next_state(&(ctx->master_ctx)); + + /* Modify the counters */ + for (i=0; i<8; i++) + ctx->master_ctx.c[i] ^= ctx->master_ctx.x[(i+4)&0x7]; + + /* Copy master instance to work instance */ + for (i=0; i<8; i++) + { + ctx->work_ctx.x[i] = ctx->master_ctx.x[i]; + ctx->work_ctx.c[i] = ctx->master_ctx.c[i]; + } + ctx->work_ctx.carry = ctx->master_ctx.carry; +} + +/* ------------------------------------------------------------------------- */ + +/* IV setup */ +void ECRYPT_ivsetup(ECRYPT_ctx* ctx, const u8* iv) +{ + /* Temporary variables */ + u32 i0, i1, i2, i3, i; + + /* Generate four subvectors */ + i0 = U8TO32_LITTLE(iv+0); + i2 = U8TO32_LITTLE(iv+4); + i1 = (i0>>16) | (i2&0xFFFF0000); + i3 = (i2<<16) | (i0&0x0000FFFF); + + /* Modify counter values */ + ctx->work_ctx.c[0] = ctx->master_ctx.c[0] ^ i0; + ctx->work_ctx.c[1] = ctx->master_ctx.c[1] ^ i1; + ctx->work_ctx.c[2] = ctx->master_ctx.c[2] ^ i2; + ctx->work_ctx.c[3] = ctx->master_ctx.c[3] ^ i3; + ctx->work_ctx.c[4] = ctx->master_ctx.c[4] ^ i0; + ctx->work_ctx.c[5] = ctx->master_ctx.c[5] ^ i1; + ctx->work_ctx.c[6] = ctx->master_ctx.c[6] ^ i2; + ctx->work_ctx.c[7] = ctx->master_ctx.c[7] ^ i3; + + /* Copy state variables */ + for (i=0; i<8; i++) + ctx->work_ctx.x[i] = ctx->master_ctx.x[i]; + ctx->work_ctx.carry = ctx->master_ctx.carry; + + /* Iterate the system four times */ + for (i=0; i<4; i++) + RABBIT_next_state(&(ctx->work_ctx)); +} + +/* ------------------------------------------------------------------------- */ + +/* Encrypt/decrypt a message of any size */ +void ECRYPT_process_bytes(int action, ECRYPT_ctx* ctx, const u8* input, + u8* output, u32 msglen) +{ + /* Temporary variables */ + u32 i; + u8 buffer[16]; + + /* Encrypt/decrypt all full blocks */ + while (msglen >= 16) + { + /* Iterate the system */ + RABBIT_next_state(&(ctx->work_ctx)); + + /* Encrypt/decrypt 16 bytes of data */ + *(u32*)(output+ 0) = *(u32*)(input+ 0) ^ U32TO32_LITTLE(ctx->work_ctx.x[0] ^ + (ctx->work_ctx.x[5]>>16) ^ U32V(ctx->work_ctx.x[3]<<16)); + *(u32*)(output+ 4) = *(u32*)(input+ 4) ^ U32TO32_LITTLE(ctx->work_ctx.x[2] ^ + (ctx->work_ctx.x[7]>>16) ^ U32V(ctx->work_ctx.x[5]<<16)); + *(u32*)(output+ 8) = *(u32*)(input+ 8) ^ U32TO32_LITTLE(ctx->work_ctx.x[4] ^ + (ctx->work_ctx.x[1]>>16) ^ U32V(ctx->work_ctx.x[7]<<16)); + *(u32*)(output+12) = *(u32*)(input+12) ^ U32TO32_LITTLE(ctx->work_ctx.x[6] ^ + (ctx->work_ctx.x[3]>>16) ^ U32V(ctx->work_ctx.x[1]<<16)); + + /* Increment pointers and decrement length */ + input += 16; + output += 16; + msglen -= 16; + } + + /* Encrypt/decrypt remaining data */ + if (msglen) + { + /* Iterate the system */ + RABBIT_next_state(&(ctx->work_ctx)); + + /* Generate 16 bytes of pseudo-random data */ + *(u32*)(buffer+ 0) = U32TO32_LITTLE(ctx->work_ctx.x[0] ^ + (ctx->work_ctx.x[5]>>16) ^ U32V(ctx->work_ctx.x[3]<<16)); + *(u32*)(buffer+ 4) = U32TO32_LITTLE(ctx->work_ctx.x[2] ^ + (ctx->work_ctx.x[7]>>16) ^ U32V(ctx->work_ctx.x[5]<<16)); + *(u32*)(buffer+ 8) = U32TO32_LITTLE(ctx->work_ctx.x[4] ^ + (ctx->work_ctx.x[1]>>16) ^ U32V(ctx->work_ctx.x[7]<<16)); + *(u32*)(buffer+12) = U32TO32_LITTLE(ctx->work_ctx.x[6] ^ + (ctx->work_ctx.x[3]>>16) ^ U32V(ctx->work_ctx.x[1]<<16)); + + /* Encrypt/decrypt the data */ + for (i=0; i= 16) + { + /* Iterate the system */ + RABBIT_next_state(&(ctx->work_ctx)); + + /* Generate 16 bytes of pseudo-random data */ + *(u32*)(keystream+ 0) = U32TO32_LITTLE(ctx->work_ctx.x[0] ^ + (ctx->work_ctx.x[5]>>16) ^ U32V(ctx->work_ctx.x[3]<<16)); + *(u32*)(keystream+ 4) = U32TO32_LITTLE(ctx->work_ctx.x[2] ^ + (ctx->work_ctx.x[7]>>16) ^ U32V(ctx->work_ctx.x[5]<<16)); + *(u32*)(keystream+ 8) = U32TO32_LITTLE(ctx->work_ctx.x[4] ^ + (ctx->work_ctx.x[1]>>16) ^ U32V(ctx->work_ctx.x[7]<<16)); + *(u32*)(keystream+12) = U32TO32_LITTLE(ctx->work_ctx.x[6] ^ + (ctx->work_ctx.x[3]>>16) ^ U32V(ctx->work_ctx.x[1]<<16)); + + /* Increment pointers and decrement length */ + keystream += 16; + length -= 16; + } + + /* Generate remaining pseudo-random data */ + if (length) + { + /* Iterate the system */ + RABBIT_next_state(&(ctx->work_ctx)); + + /* Generate 16 bytes of pseudo-random data */ + *(u32*)(buffer+ 0) = U32TO32_LITTLE(ctx->work_ctx.x[0] ^ + (ctx->work_ctx.x[5]>>16) ^ U32V(ctx->work_ctx.x[3]<<16)); + *(u32*)(buffer+ 4) = U32TO32_LITTLE(ctx->work_ctx.x[2] ^ + (ctx->work_ctx.x[7]>>16) ^ U32V(ctx->work_ctx.x[5]<<16)); + *(u32*)(buffer+ 8) = U32TO32_LITTLE(ctx->work_ctx.x[4] ^ + (ctx->work_ctx.x[1]>>16) ^ U32V(ctx->work_ctx.x[7]<<16)); + *(u32*)(buffer+12) = U32TO32_LITTLE(ctx->work_ctx.x[6] ^ + (ctx->work_ctx.x[3]>>16) ^ U32V(ctx->work_ctx.x[1]<<16)); + + /* Copy remaining data */ + for (i=0; iwork_ctx)); + + /* Encrypt/decrypt 16 bytes of data */ + *(u32*)(output+ 0) = *(u32*)(input+ 0) ^ U32TO32_LITTLE(ctx->work_ctx.x[0] ^ + (ctx->work_ctx.x[5]>>16) ^ U32V(ctx->work_ctx.x[3]<<16)); + *(u32*)(output+ 4) = *(u32*)(input+ 4) ^ U32TO32_LITTLE(ctx->work_ctx.x[2] ^ + (ctx->work_ctx.x[7]>>16) ^ U32V(ctx->work_ctx.x[5]<<16)); + *(u32*)(output+ 8) = *(u32*)(input+ 8) ^ U32TO32_LITTLE(ctx->work_ctx.x[4] ^ + (ctx->work_ctx.x[1]>>16) ^ U32V(ctx->work_ctx.x[7]<<16)); + *(u32*)(output+12) = *(u32*)(input+12) ^ U32TO32_LITTLE(ctx->work_ctx.x[6] ^ + (ctx->work_ctx.x[3]>>16) ^ U32V(ctx->work_ctx.x[1]<<16)); + + /* Increment pointers to input and output data */ + input += 16; + output += 16; + } +} + +/* ------------------------------------------------------------------------- */ diff --git a/plugins/rngLibraries/rngRbt/rngRbt.c b/plugins/rngLibraries/rngRbt/rngRbt.c new file mode 100644 index 000000000..c2162d18e --- /dev/null +++ b/plugins/rngLibraries/rngRbt/rngRbt.c @@ -0,0 +1,211 @@ +/*-------------------------------------------------------------------------------- + * + * This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE + * (LGPL) version 2. The licence may be found in the root directory of the Unicon + * source directory in the file COPYING. + * + *-------------------------------------------------------------------------------- + * + * This is an implementation of the Rabbit random number generator as + * a dynamically loaded rng library. The underlying code also does encryption, + * but we only use the keystream as a source of random bits to generate + * random numbers. + * + *-------------------------------------------------------------------------------- + * + * Don Ward + * August 2019 + * + *-------------------------------------------------------------------------------- + */ + +#include "../rngLib.h" +#include "ecrypt-sync.h" + +struct rng_rt_api runtime; /* A place to store the routines callable by the rng */ + +RABBIT_ctx zero_ctx; /* A zero context, useful for checking initialization */ + +/*-------------------------------------------------------------------------------*/ +/* This routine is called once by the runtime when the library + * is first loaded. + */ +int startRng(struct rngprops *props, struct rng_rt_api *rtapi) +{ /* + * Tell the runtime how much state is needed. + * NB. the state size is in bits, not bytes. + */ + props->stateBits = 8 * sizeof(ECRYPT_ctx); + /* + * Specify what types are acceptable as a parameter to putSeed + * If more than one type is acceptable, or them together. + */ + + /* ---------------------------------------------------------------------- */ + props->typeFlags = RngTypeFlag(T_Integer) | RngTypeFlag(T_Intarray); + /* Why are there two types specified for putSeed? + * + * T_Intarray is used to alter both key and IV (i.e. a full setup). + * T_Integer is used to just alter the IV after a full set up. + * + * This means that putSeed() must detect whether a full setup has been done. + * + * For convenience, we "stretch" an integer value to a full key/IV so + * that users can assign an integer to &random without bothering to + * create an integer array. For random numbers this is probably good + * enough. But, for proper security, the full key/IV should be set to + * unique values from a good source of entropy. + * ---------------------------------------------------------------------- */ + + /* + * Tell the runtime what the "natural size" of the random output is. + * For example, if the generator algorithm naturally produces a block + * of output, tell the runtime what the size of the block is. + * NB. the block size is in bits, not bytes. + */ + props->blockBits = 128; + + /* Store the routines that we can call */ + runtime = *rtapi; + + /* + * The Rabbit generator does not need to do any "first time" setup. + * If it did, we would call the setup routine here. + */ + + return 0; /* Success */ +} + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime to get the string values of + * the custom error numbers set by the generator. + */ +char * getErrorText(int err) +{ + switch (err) + { + case 700: return "Unexpected type supplied to putSeed"; + case 701: return "Unexpected size supplied to putSeed"; + case 702: return "Bad seed value"; + case 703: return "Fewer than 192 bits in seed"; + + default: return "??"; /* Not one of our errors */ + } +} + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime when an assignment that is not + * a restored state is made to &random. The runtime detects an assignment + * that is a restoration of the state and handles that internally. + */ +int putSeed(word type, word size, void *param) +{ + ECRYPT_ctx *state; + word seed; + if (type == T_Null || param == NULL) { + /* No seed has been supplied before a use of the random operator: + * call the runtime to supply some random seed data. + * getInitialBits may be called more than once, but there is no guarantee + * that it will return a different value on subsequent calls. + */ + state = (ECRYPT_ctx *)runtime.getRngState(); /* get the location of generator's state */ + seed = runtime.getInitialBits(); /* get some random bits */ + + return putSeed(T_Integer, sizeof(seed), &seed); + } + + /* Check the supplied parameters. + * None of these failures should ever happen (unless there is a bug in the runtime) + */ + if ((type != T_Integer) && (type != T_Intarray)) { + runtime.putErrorCode(700); /* Unexpected type */ + return -1; /* The assignment to &random will fail */ + } + + if (param == NULL) { + runtime.putErrorCode(702); /* Bad seed */ + return -1; + } + + if (type == T_Intarray) { + /* We need a 128 bit key and a 64 bit IV. + * Fail if there aren't enough bits in the supplied parameter. + */ + if ((size * 8) < 128 + 64) { + runtime.putErrorCode(703); /* Insufficient data */ + return -1; + } else { + /* Set up key and IV */ + state = (ECRYPT_ctx *)runtime.getRngState(); /* get the location of generator's state */ + /* This only sets up the key (it uses neither of the two size parameters) */ + ECRYPT_keysetup(state, param, 16, 8); + /* Set up the IV */ + ECRYPT_ivsetup(state, (unsigned char *)param + 16); + state->hiowpe = 1.0; /* Clear any stored value */ + } + } else { /* type == T_Integer */ + state = (ECRYPT_ctx *)runtime.getRngState(); /* get the location of generator's state */ + + /* Check if the generator has been initialized before */ + if ((0 == memcmp(&zero_ctx, &state->master_ctx, sizeof(RABBIT_ctx))) && + (0 == memcmp(&zero_ctx, &state->work_ctx, sizeof(RABBIT_ctx)))) { + /* Not initialized */ + u64 keyIv[3]; + /* "stretch" the data to 192 bits. There are probably better ways to do this. */ + keyIv[0] = keyIv[1] = keyIv[2] = *(u64 *)param; + return putSeed(T_Intarray, sizeof(keyIv), keyIv); + } else { + /* This is a reinitilization with an integer: just change the IV */ + ECRYPT_ivsetup(state, param); + state->hiowpe = 1.0; /* Clear any stored value */ + } + } + + return 0; /* success */ +} + +/*-------------------------------------------------------------------------------*/ +#define RanScale 5.421010862427517e-20 /* Almost, but not quite, 1/(2^64-1) */ + +/* This routine is called by the runtime when the random operator is invoked. + * It is expected to return a floating point number in the range [0.0,1.0). + * Note the interval is half closed (i.e. 1.0 is not allowed). + */ +double getRandomFpt(void) +{ + ECRYPT_ctx *state = (ECRYPT_ctx *)runtime.getRngState(); + + /* Rabbit generates 2 double's worth of bits every call of ECRYPT_keystream_bytes() + * so the second double is stored for the next time around. + */ + if (state->hiowpe < 1.0) { /* There is a number waiting to go */ + double ans = state->hiowpe; + state->hiowpe = 1.0; /* Clear the stored value */ + return ans; + } else { + u64 ans[2]; + /* Get a block's worth of random bits */ + ECRYPT_keystream_bytes(state, (u8 *)ans, sizeof(ans)); + state->hiowpe = RanScale * ans[1]; /* Stash one away for later */ + return RanScale * ans[0]; /* and return one to the caller */ + } +} + +/*-------------------------------------------------------------------------------*/ +/* This routine is called by the runtime when either of the standard functions + * rngbitstring() or rngbits() is called. + * It is expected to return a bit vector of the required size, although it is + * also allowed to fail. + * + * It is not expected that any bits left over are retained for the next output + */ + +int getRandomBits(int nBits, void *buffer) +{ + ECRYPT_ctx *state = (ECRYPT_ctx *)runtime.getRngState(); + int bytes = (nBits + 7)/8; + + ECRYPT_keystream_bytes(state, buffer, bytes); + state->hiowpe = 1.0; /* Clear the stored value */ + return bytes; +} diff --git a/plugins/rngLibraries/rngRbt/selected.test-vectors b/plugins/rngLibraries/rngRbt/selected.test-vectors new file mode 100644 index 000000000..a5b2e7811 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/selected.test-vectors @@ -0,0 +1,95 @@ +Set 2, vector# 0: + key = 00000000000000000000000000000000 + IV = 0000000000000000 + stream[0..63] = EDB70567375DCD7CD89554F85E27A7C6 + 8D4ADC7032298F7BD4EFF504ACA6295F + 668FBF478ADB2BE51E6CDE292B82DE2A + B48D2AC6565979220EC909A7E7576098 + stream[192..255] = 706630D4C431BC49E07D9CBF98FAB946 + 7108299DD9B358BBB4AEE64AF67F1E5F + EC3DBA07A0CEE1BE2E2F0AAB10BB8106 + 35F403DA20B8ACAACDE4D85546D0A820 + stream[256..319] = B35DB614A32070FE8CAC67B378184C45 + 354753D37EE6D057ECB36E0D5BE5DAC4 + 11CC36DA10A2B670BC201B2C8804377F + 25C599ED29294F3E267C866DCC68276B + stream[448..511] = 109D5563D46DD78C2905F7D90036300C + 60326EBE3B1AA385FB75F1C5C7311BFD + 6DDA960C716C33E51C5A2B1906200C40 + CFF62FB5782A41BF816F7639C9341244 +Set 2, vector# 9: + key = 09090909090909090909090909090909 + IV = 0000000000000000 + stream[0..63] = E7F8DC75257F98D89124464C5DDCDC86 + 93F8456B7FA2E2E0A907F6B4D9A56F2C + 86E5978203A6C8791C119D7AEC91D5CD + F087AE3943091B2788B675353A0AB24A + stream[192..255] = FB8986A91C6CAD907E90A47F962ACB15 + 5112027212D69E08C230A8495147F6B4 + 3E769D9CCB01F6472E8FBA993AC6ACB1 + D37918D00C269B7BBE14766579938E69 + stream[256..319] = C665BDB6306B6C8AD987BBDAAD5C3B35 + EC8D0552058472C8E6E2A068C7BAFB3A + 301724B7B601FBBC2289114CED423467 + 59BCF7776083801EAC2C6330C81B0E45 + stream[448..511] = EB0629217238ABDA20897FA7D81CE478 + F83CE9BD5B45490D94780C17F796CAC8 + B16A60B66D31BF21F0BA3A7AB08C6262 + 3AB28229B1B716E21C6D2DAB92559B71 +Set 3, vector# 0: + key = 000102030405060708090A0B0C0D0E0F + IV = 0000000000000000 + stream[0..63] = A8F7E69B6940A78D136A5C154A157952 + A6E4235859E30220EA686436BB38EF53 + 9C2940556B09ECD7FEA2B0AC8307F169 + 6265A3D644281C39C9CD5E1E2F9BE4D0 + stream[192..255] = B3378F62D121027463200A43E2DDA9CF + 91F02D4810282CB9990E28D857EAC359 + D83BF4C5BFEA00EC6815E0B208B9D1F2 + E0BF3649EC4B9A25E76498F857420788 + stream[256..319] = 422F2A8ECBBDA3496414C8D1A0B72350 + AEFAC933F5D4880E2680FB0B9DBB3195 + 64E56EC9222C50F7E2608325D068F178 + 22F8A7438AF00C282C9AA0486342EF2D + stream[448..511] = F9AF33AAF2F0293C0739E052C5BF732F + B721B00CF97D0E71B755686DDD739B70 + C99E194E2181C1AD8D36D0F1B130CF79 + EA4E32F9D2BE3479758CFCCC98155A1D +Set 5, vector# 0: + key = 00000000000000000000000000000000 + IV = 8000000000000000 + stream[0..63] = 8C3E70D63D8541A33621912CC8385F9E + A74DFE692DBF17090767E5D7D8468D9A + A5E3FD7FE6164F731B49C92E42AAA448 + 4635D6480BA792AD013655F19C47C599 + stream[192..255] = A7CFF1A495CB9B1162767912050D4961 + 59EB515A34B1828E38B0540D3D4C3A5B + 7D0121F6C76C47FD3AF92788E694FC5E + FBB28E611DC1CD8EDAF4266E140B5147 + stream[256..319] = 806E59A52AE255D282623985344FE728 + EAF4E37DEB249603F419F31FE833ED6C + 04A9BA1D83FFE372975D132380D232F5 + 82AC8DF10C244FE2996A3F29304661E8 + stream[448..511] = 046433985C9FA18B949BCB73194176E2 + 6CBD4F854A9E1E9D81423C817220E771 + 690FCD44B3B849EEC317F4B924A8DAE0 + 13EA88D817E1170A0EDF4E650721CAD9 +Set 6, vector# 3: + key = 0F62B5085BAE0154A7FA4DA0F34699EC + IV = 288FF65DC42B92F9 + stream[0..63] = 613CB0BA96AFF6CACF2A459A102A7F78 + CA985CF8FDD1474018758E36AE9923F5 + 19D13D718DAF8D7C0C109B79D5749439 + B7EFA4C4C9C8D29DC5B3888314A6816F + stream[65472..65535] = 743222D98533857C9EE38BDC410ACF39 + A823CE0C4CF2939EBE6B95DA668396BB + D823429F47F81B5D65308E83604C95B4 + E419FDB115F6E9E77B7225F14464C396 + stream[65536..65599] = F2732DC10349ABC9C212326CE22A3C2A + CF233A6EF8469659BDA3EDAACC759CD5 + 3EA71F9E338302F802C3A90793721BCF + 875CFA332B4BA4E14B41C689F1FA4C1D + stream[131008..131071] = 79037775E485C71704F308611AD1FE54 + 5B77CFFD982AF1FE0EDD3E926931AA54 + EE55F24DBC7B385ECA940EA73EE627CF + A3BD376BF5D8D7F1E8AFFE344D6A34F0 diff --git a/plugins/rngLibraries/rngRbt/test-vectors.icn b/plugins/rngLibraries/rngRbt/test-vectors.icn new file mode 100644 index 000000000..06c7cd397 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/test-vectors.icn @@ -0,0 +1,273 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# A program to recreate selected test vectors for the rngRbt generator. +# The output is in the same format as the verified.test-vectors file to +# facilitate mechanical comparison. +# +# The selected.test-vectors file was created by hand by copying selected +# excerpts from verified.test-vectors. +# +# The generator may be tested by +# Unicon -s test-vectors.icn +# ./test-vectors > test-output +# diff selected.test-vectors test.output +# +# Don Ward +# August 2019 +# +# March 2021 Add test code for 32-bit platforms +# +################################################################################ + +global bit64 + +procedure main() +$ifndef _RNG_LIBRARY + write(&errout, "RNG libraries are not available") +$else + local zeroSeed := array(196/intBits(),0) + local seed := array(196/intBits(),0) + local op + local n + write(&errout, intBits(), " bits") + loadrng("rngRbt") | stop(&errout, "Cannot load the Rabbit library") + + case intBits() of { + 32: {bit64 := &null} + 64: {bit64 := 64} + default: { stop(&errout, "Neither a 32 bit nor a 64 bit machine")} + } + + # if /bit64 then { + # every n := !["7FFFF", "7FFFFFFF", "FFFFFFFF"] do { + # write(&errout, "s32(", n, ") = ", s32(n), " 16R", n, " = ", "16R" || n) + # } + # } + + # Set 2 vector 0 (00000000000000000000000000000000 0000000000000000) + write("Set 2, vector# 0:") + test(&output,zeroSeed,0,192,256,448) + + # Set 2 vector 9 (09090909090909009090909090909090 0000000000000000) + write("Set 2, vector# 9:") + if \bit64 then { # 64-bit machine + seed[1] := seed[2] := s64("0909090909090909") + seed[3] := 0 + } else { # 32-bit machine + every seed[1 to 4] := s32("09090909") + seed[5] := seed[6] := 0 + } + test(&output,seed,0,192,256,448) + + # Set 3 vector 0 (000102030405060708090A0B0C0D0E0F 0000000000000000) + write("Set 3, vector# 0:") + if \bit64 then { # 64-bit machine + seed[1] := s64("0706050403020100") + seed[2] := s64("0F0E0D0C0B0A0908") + seed[3] := 0 + } else { # 32-bit machine + seed[1] := s32("03020100") + seed[2] := s32("07060504") + seed[3] := s32("0B0A0908") + seed[4] := s32("0F0E0D0C") + seed[5] := seed[6] := 0 + } + test(&output,seed,0,192,256,448) + + # Set 5 Vector 0 (00000000000000000000000000000000 8000000000000000) + write("Set 5, vector# 0:") + if \bit64 then { # 64-bit machine + seed[1] := seed[2] := 0 + seed[3] := 16R80 + } + else { # 32-bit machine + every seed[1 to 4] := 0 + seed[5] := 16R80 + seed[6] := 0 + } + test(&output,seed,0,192,256,448) + + # Set 6 vector 3 (0F62B5085BAE0154A7FA4DA0F34699EC 288FF65DC42B92F9) + write("Set 6, vector# 3:") + if \bit64 then { # 64-bit machine + seed[1] := s64("5401AE5B08B5620F") + seed[2] := s64("EC9946F3A04DFAA7") + seed[3] := s64("F9922BC45DF68F28") + } else { # 32-bit machine + seed[1] := s32("08B5620F") + seed[2] := s32("5401AE5B") + seed[3] := s32("A04DFAA7") + seed[4] := s32("EC9946F3") + seed[5] := s32("5DF68F28") + seed[6] := s32("F9922BC4") + } + test(&output,seed,0,65472,65536,131008) +$endif +end + +# Produce a signed 64 bit integer from a hex string +procedure s64(hex: string) + static hexchars + initial { + hexchars := "FEDCBAfedcba9876543210" + } + if /bit64 then stop("s64 called on a 32 bit machine") + if *hex > 16 then stop("Hex string \"", hex, "\" is too long") + if *hex > (hex ? many(hexchars)) then stop("Bad hex string ", hex) + if *hex < 16 then { + return integer("16R" || hex) + } else { + if hex[1] ? any(hexchars[1:13]) then { # Top bit set + return ior(ishift("16R" || hex[1:9], 32), "16R" || hex[9:17]) + } else { + return integer("16R" || hex) + } + } +end + +# Produce a signed 32 bit integer from a hex string +procedure s32(hex: string) + static hexchars, use_ishift + initial { + hexchars := "FEDCBAfedcba9876543210" + # check if ishift produces a large int if the 31st bit is set + if -1 = ior(ishift(16RFFFF,16),16RFFFF) then use_ishift := 1 else use_ishift := &null + } + if \bit64 then stop("s32 called on a 64 bit machine") + if *hex > 8 then stop("Hex string \"", hex, "\" is too long") + if *hex > (hex ? many(hexchars)) then stop("Bad hex string ", hex) + if *hex < 8 then { + return integer("16R" || hex) + } else { + if hex[1] ? any(hexchars[1:15]) then { # Top bit set + if \use_ishift then { + return ior(ishift("16R" || hex[1:5], 16), "16R" || hex[5:9]) + } else { + # We can't use ishift because it produces a large int if the top bit is set. + # So we make a 31 bit integer and subtract 16R80000000 from it (we do it in + # two lots of 16R40000000 to avoid large integers). + return integer("16R" || map(hex[1], hexchars[1:15], "76543276543210") || hex[2:9]) - + 16R40000000 - 16R40000000 + } + } else { + return integer("16R" || hex) + } + } +end + + +# The test vectors are specified by the ls byte being the first value +# So we produce the data in the correct order +# HB stands for Hex Byte, HB8 constructs 8 hex byes in the correct sequence +# + +procedure hexChar(n: integer) + static hexchars + initial { + hexchars := "0123456789ABCDEF" + } + if (n < 0) | (n > 15) then stop(&errout, "hexChar: out of range <", n, ">") + return hexchars[n+1] +end + +procedure HB(n: integer) + return hexChar(iand(ishift(n,-4), 16RF)) || hexChar(iand(n, 16RF)) +end + +procedure HB2(n: integer) + return HB(iand(n, 16RFF)) || HB(iand(ishift(n,-8), 16RFF)) +end + +procedure HB4(n: integer) + return HB2(iand(n, 16RFFFF)) || HB2(iand(ishift(n,-16), 16RFFFF)) +end + +procedure HB8(n: integer) + if /bit64 then stop("HB8 called on 32 bit machine") + return HB4(iand(n, 16RFFFFFFFF)) || HB4(iand(ishift(n,-32), 16RFFFFFFFF)) +end + +# Produce 64 bytes of output +procedure p64(f:file:&output, b, pos:integer) + local p := pos % 512 + if p > (512 - 64) then stop("Buffer overflow at ",pos) + if pos < 0 then stop("Buffer underflow at ", pos) + + if \bit64 then { # 64 bit machine + write(right("stream[" || pos || ".." || pos+63 || "] = ",31), + HB8(b[1 + p/8]), HB8(b[2 + p/8])) + write(right("",31), HB8(b[3 + p/8]), HB8(b[4 + p/8])) + write(right("",31), HB8(b[5 + p/8]), HB8(b[6 + p/8])) + write(right("",31), HB8(b[7 + p/8]), HB8(b[8 + p/8])) + } else { # 32 bit machine + write(right("stream[" || pos || ".." || pos+63 || "] = ",31), + HB4(b[1 + p/4]), HB4(b[2 + p/4]), HB4(b[3 + p/4]), HB4(b[4 + p/4])) + write(right("",31), HB4(b[5 + p/4]), HB4(b[6 + p/4]), HB4(b[7 + p/4]), HB4(b[8 + p/4])) + write(right("",31), HB4(b[9 + p/4]), HB4(b[10+ p/4]), HB4(b[11+ p/4]), HB4(b[12+ p/4])) + write(right("",31), HB4(b[13+ p/4]), HB4(b[14+ p/4]), HB4(b[15+ p/4]), HB4(b[16+ p/4])) + } +end + +# Produce the output in the same format as the verified.test-vectors file +procedure test(f :file, seed, pos[]) + local b + local p, cpos, bpos + + if not (*seed = (3 | 6)) then stop("Bad Seed") + if *pos > 1 then { + every p := 1 to *pos - 1 do { + if pos[p] >= pos[p+1] then stop("Cannot run the generator backwards") + } + } + + if \bit64 then { # 64-bit machine + write(right("key = ",31), HB8(seed[1]), HB8(seed[2])) + write(right("IV = ",31), HB8(seed[3])) + } else { # 32-bit machine + writes(right("key = ",31)); every writes(HB4(seed[1 to 4])); write() + write(right("IV = ",31), HB4(seed[5]), HB4(seed[6])) + } + + &random := seed + cpos := 0 + every p := !pos do { + while cpos <= p do { + b := rngbits(512*8) + cpos +:= 512 + } + + p64(f, b, p) # output 64 bytes + } + end + + # return the number of bits in an integer + procedure intBits() + local str, errs, test + static bits + initial { +$ifdef _LARGE_INTEGERS + errs := &error + &error := -1 +$endif + bits := 0; str := "" + repeat { + bits +:= 1; str ||:= "1" + test := integer("2R" || str) +$ifdef _LARGE_INTEGERS + # If large integers are configured we have to test an operation that fails on them + if not seq(test) then {&error := errs; break} +$else + # If large integers are not configured this will detect overflow + if ishift(ishift(test,+1),-1) ~= test then break +$endif + } + } + return bits + end + diff --git a/plugins/rngLibraries/rngRbt/test-vectors.txt b/plugins/rngLibraries/rngRbt/test-vectors.txt new file mode 100644 index 000000000..c5132c87d --- /dev/null +++ b/plugins/rngLibraries/rngRbt/test-vectors.txt @@ -0,0 +1,66 @@ +TEST VECTORS FOR THE RABBIT STREAM CIPHER + +The keys, IVs and outputs are presented byte-wise in hexadecimal format. +The leftmost byte is the one to be put on the lowest address. + +================================================================================ +Test 1: Key setup and encryption/decryption/prng + +key1 = [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00] + +out1 = [02 F7 4A 1C 26 45 6B F5 EC D6 A5 36 F0 54 57 B1 + A7 8A C6 89 47 6C 69 7B 39 0C 9C C5 15 D8 E8 88 + EF 9A 69 71 8B 82 49 A1 A7 3C 5A 6E 5B 90 45 95] + +================================================================================ +Test 2: Key setup and encryption/decryption/prng + +key2 = [C2 1F CF 38 81 CD 5E E8 62 8A CC B0 A9 89 0D F8] + +out2 = [3D 02 E0 C7 30 55 91 12 B4 73 B7 90 DE E0 18 DF + CD 6D 73 0C E5 4E 19 F0 C3 5E C4 79 0E B6 C7 4A + 9F B4 92 E1 B5 40 36 3A E3 83 C0 1F 9F A2 26 1A] + +================================================================================ +Test 3: Key setup and encryption/decryption/prng + +key3 = [1D 27 2C 6A 2D 8E 3D FC AC 14 05 6B 78 D6 33 A0] + +out3 = [A3 A9 7A BB 80 39 38 20 B7 E5 0C 4A BB 53 82 3D + C4 42 37 99 C2 EF C9 FF B3 A4 12 5F 1F 4C 99 A8 + 97 C0 73 3F F1 F1 8D 25 6A 59 E2 BA AB C1 F4 F1] + +================================================================================ +Test 4: Key setup, iv setup and encryption/decryption/prng + +key4 = [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00] + +iv4 = [00 00 00 00 00 00 00 00] + +out4 = [ED B7 05 67 37 5D CD 7C D8 95 54 F8 5E 27 A7 C6 + 8D 4A DC 70 32 29 8F 7B D4 EF F5 04 AC A6 29 5F + 66 8F BF 47 8A DB 2B E5 1E 6C DE 29 2B 82 DE 2A] + +================================================================================ +Test 5: Key setup, iv setup and encryption/decryption/prng + +key5 = [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00] + +iv5 = [59 7E 26 C1 75 F5 73 C3] + +out5 = [6D 7D 01 22 92 CC DC E0 E2 12 00 58 B9 4E CD 1F + 2E 6F 93 ED FF 99 24 7B 01 25 21 D1 10 4E 5F A7 + A7 9B 02 12 D0 BD 56 23 39 38 E7 93 C3 12 C1 EB] + +================================================================================ +Test 6: Key setup, iv setup and encryption/decryption/prng + +key6 = [00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00] + +iv6 = [27 17 F4 D2 1A 56 EB A6] + +out6 = [4D 10 51 A1 23 AF B6 70 BF 8D 85 05 C8 D8 5A 44 + 03 5B C3 AC C6 67 AE AE 5B 2C F4 47 79 F2 C8 96 + CB 51 15 F0 34 F0 3D 31 17 1C A7 5F 89 FC CB 9F] + +================================================================================ diff --git a/plugins/rngLibraries/rngRbt/verified.test-vectors b/plugins/rngLibraries/rngRbt/verified.test-vectors new file mode 100644 index 000000000..f30c284e2 --- /dev/null +++ b/plugins/rngLibraries/rngRbt/verified.test-vectors @@ -0,0 +1,2169 @@ +******************************************************************************** +* ECRYPT Stream Cipher Project * +******************************************************************************** + +Primitive Name: Rabbit +====================== +Profile: S._H. +Key size: 128 bits +IV size: 64 bits + +Test vectors -- set 1 +===================== + +(stream is generated by encrypting 512 zero bytes) + +Set 1, vector# 0: + key = 80000000000000000000000000000000 + IV = 0000000000000000 + stream[0..63] = DCDCB614F738A20CE103637E58091766 + 010B16EACD06A9108671B1EEEFE8CC17 + 2EC9402DD54C53079767A6299561EE50 + 66A5DD404C4D6875F4B5D611B007B106 + stream[192..255] = 7117ABB7629B9853960F256CC2BD5739 + F1AA813DCFAA0CD49E132E64459789C2 + 01295F09CA42F88CDBBE2B4D5B11FB2E + CCB36DD1ED6CFE96FE21FB5401DA1E20 + stream[256..319] = 12555C74594362AC415427715F62AC35 + 6344F4EB3D384382EA4B7724F4707699 + 6BBB73449FB55D7DCB59E96A8C674D0F + 7398193E519A33FB3C7F49015AFC3C56 + stream[448..511] = 63FB65776A91527C170EBFD625D0D5BB + 3715D348FA47C027FCA3AF0CA1A716D6 + 304F2E82E888531FAB33A57E8230E36F + 0922F8C744BDD1755644D1C83352A958 + xor-digest = 5E681B68614BB795C35EE3C0D0A84953 + 170EE94E9B01ED744E33801591345B8E + 9D90EA87123CD30312204A6499BBD413 + 29EB409967B125F24CBA7608D4A56B0A + +Set 1, vector# 9: + key = 00400000000000000000000000000000 + IV = 0000000000000000 + stream[0..63] = 0847A3706C54B746E480F34DF10AC86E + C67799AA56694ABBE8A2D10AB5B32D7B + 575DDAB74D2D8F37AFDF0923B9A1C504 + 0DC31CF5A11E43A5E92B326A2A366D8A + stream[192..255] = 1D9527A29B459829DC9524F266AB10F4 + B288EB887C85A36AE628281C43A96C6A + A99C2CF791098B30611DB96690D1CB6C + 2E283E819BE12053040113DC1865B017 + stream[256..319] = 56467CF20A734D51CC3EABCA1A44BE54 + 2308DB174D37FE67F015CB8D395BA7DA + 43B947F5FEE26780F02EA3BCA36F0465 + 86B2713C1AB4FB460982F19EA6DEC945 + stream[448..511] = 1A04CA6C992E6930A551A01D56B403CC + 2A348CD66FB7B5921051BF1D73A47F7F + 4C1CFB5EFC9395DDBA74374C2F27EA3B + D656ACAA87D701CB09D39945482C5399 + xor-digest = 879ECB08604CCAD26AC8706F621485C2 + 2180AD25C088702444AB1779657EEF5F + 76ADB9E7657BA8DC0480A58D6C453155 + F04A739297E966E8BA50F51F74CDC1BF + +Set 1, vector# 18: + key = 00002000000000000000000000000000 + IV = 0000000000000000 + stream[0..63] = 178EDB78577D3F241A490303CC019F1D + FD286FE86DC73287B43CF5CE60DB3D7F + 2A35768D44B8325F5F91A0AFCD8D8EEE + B4F7188A087FBB156AF0833F669C11D2 + stream[192..255] = 30CEC1DE9C101E5ECE19ED7E31D8F307 + F97D86F5FF71B09CA84F84327FC2BA1F + E876776BC4FEA6CA11E1C99B7DC46993 + 898A1CCD7D901E464365FE5ED3D97010 + stream[256..319] = DFAB7A700E747801E03B43B503CA02BF + B6862DF1CA287683FC0AA4AC6D6F9FE3 + C36D9F289CAACC42BAC35BF1B1CD2838 + BF15086131C7DFCBD626CAD4CC14984D + stream[448..511] = 85FFCBD014E13679EA9AB9F0D4B2E453 + E5FDE7E41080B9A360A069DDEA8DA2CD + 6B69FB27FD8C1ABEFE63322B4A2F0A40 + 7ED2D6F7E4D4B80D2A79C0A6CDE4D367 + xor-digest = 903E1B7F2A5B1FA04B9E81A946A1C7DB + 9962506A652A0FB3D05D2B959221214F + ACE2A69DEB4A70B9A5D7C06EC8514C17 + 61BC83EA753AD3EB31E592F479F7B1A0 + +Set 1, vector# 27: + key = 00000010000000000000000000000000 + IV = 0000000000000000 + stream[0..63] = 77FE705EE55BAB05978AA54D63071707 + 009ADC8C18FC68A4D5941E0CAFB8E68C + A218F1724EB5FA29485F0924F612AE67 + 0D975B485190040F9E112783D665E031 + stream[192..255] = 2BEAB3BB73A4DB0A4F8CA65FC6D52C02 + 9D4E7678EE1C063B86D24B7D1C981B27 + 6965B5E787FACEFB3D1FD03473252970 + 55DF4909BFA8E54452C9BD4775018C48 + stream[256..319] = 1D318B326B705E0E07263CAAE8B4F842 + F7595FA3B05BEE9EA595B51BA7F17AD4 + 85899E1B550D3AC8735AC5BD13D6F658 + A7AC51BCC039110FD313978639A28AF9 + stream[448..511] = 091F49BDC8504F7FDCA3AA469F4C331E + 52C81B2C4458F8D5E9CFE7B2D649DEF1 + BBA70D51AFC4C3F713C1CFF92C819BB0 + 9BEC67AA7D45274B95D90F409209711A + xor-digest = 6B7856EB005B9CEEDF4D1300961C67D7 + 5CD309BA37E632D339EFD24F72AA5D2D + AB20C1218533CE8E2F30C1F65D63FD03 + 8955076A5358F0887A3C84C30FE72861 + +Set 1, vector# 36: + key = 00000000080000000000000000000000 + IV = 0000000000000000 + stream[0..63] = 6414520BFA7AD13784F125CA63868602 + B83A834E403F6ED50F097107EFF80FE5 + 67987486EDC31CBFF000A52CB9AEDEA4 + B35F5DBD8438E901356A542A94232350 + stream[192..255] = DB271F6264119C704197219DFD7702A9 + 6196CD64C6E3F2558C330174BCF3DFB3 + 67294EB0AAE517BF8DE9F58E2849E885 + 195D0F86B30280AC048605372FB3A2B9 + stream[256..319] = 43541F31E889E83D7BB532111A364AD0 + 6ACFE745DD93FC6CD6B11078EED66F0D + 9402A48D7C9F5F0ACCD9EE49E03A28DD + E13FE9D694FD21D056ECA0F6AF53CB2A + stream[448..511] = 63F7181EB551CAEE406A54BB95FA4401 + 36268D73758528ECB01620224661473D + DF663FEAF506FA01F9A6B7FA5E4B5296 + E0CAD52A242275C346CC385EF3D04441 + xor-digest = 3F701BA013EB02D51C6060D25FDDC912 + EA8C11A4FCDB9FA3236F40EBFD1A63EE + B04CB11E9CC0809FAE402656D5BA618B + 23630775786717E99297A47CEE7107ED + +Set 1, vector# 45: + key = 00000000000400000000000000000000 + IV = 0000000000000000 + stream[0..63] = BAA234DC594C3D1CC88CC9EC7D012730 + 45D2E6157174BE898070ED8AED84988D + 07E8496AA0EEABCD0ED86F68F5705F25 + 490DE5E3D40611E3E8AAC382E99EB7B7 + stream[192..255] = 8AFD7873CB17CA9113A5C3B4DA41E6B8 + 837A0B2FE4F360702CCA80F364210F51 + D83EF8D12599571B40C150B40705B3B1 + 99D84B03F5AC154CCD485F862D5E915C + stream[256..319] = EFA5B5E9A59C63BF8A230A5C4266E159 + 36BAE705BCF15824D82EC2435218B3DC + 72B1B11EB63F29D5224C68E19F651AF1 + 8E05038A1689C70DED473710C9141035 + stream[448..511] = FB89F9AE501FC080F84285A080B12589 + 548EB87D6926511E036151DB7AF7DA1D + CE10635B672DB5BBD7437AE3234F0D99 + B2BC0619A2C87D322849946BF393F59E + xor-digest = 472066F9AFF63926784E81EB0C2CB197 + 51B8B2C4359B62077739761E50CAF90F + 2ACD0A59FF17CD9627D8138E17DA1740 + C1B18C94A27F17187763E8E07F842593 + +Set 1, vector# 54: + key = 00000000000002000000000000000000 + IV = 0000000000000000 + stream[0..63] = 8105BB206CCCED69F9132B7FB44902BA + C0C2206FB09AB8989A09A15562EAEDD6 + 3A7D1E9ADF90CA8A3F7107E452D5488C + A386A722C4F73762C1E4672B0D01868E + stream[192..255] = 3D660C3E7BDD436118F49C4839F577BD + 82910452B5FEBB0AF245B2711BC37D03 + 3E9E5BC90E7C238765270CAFC38D987B + 50499A55BD0C29E40FC01FD56DCCACFD + stream[256..319] = 26F935F3274A49DBB15445809F44833F + E952AC5A424B5E3E8F23CE6834743CC3 + 09D8269EFD7DD78BC8727AA7873A9CAA + 6A84354B46E770465E2E2DA48E34990D + stream[448..511] = 33453B4A5294C04C680420CBFC5D62DB + 4EB42F5B3535D3DDEF1845BB6A4B952B + 9A0D06018A0E3DE76DF672A94C067CAE + F48B1D2EF19E78DDBD5112CFECE5834A + xor-digest = EF9F1C5B04AC3656EDAC919AA7B80B5F + 669642AFAEEFE0B51A7A01DE3CC9B798 + 7F509098E9901734718A290B74FB954D + E4B9A3962643CC524F8991CB1F7A6517 + +Set 1, vector# 63: + key = 00000000000000010000000000000000 + IV = 0000000000000000 + stream[0..63] = B2F746E4CBC062068FA953B1EDC2C7C0 + 5BFFBAABC77CEBDC6D1C9C930C3DE23A + 2BE98C3EA3E2A49BFD2C7987DBD4516C + FC6E5F81FC1F58EF9DA996D565B6FA21 + stream[192..255] = C28157C3DBB101C812823A3D2201835D + BDA16B3006EDF9C2A89FBD0566F651AB + F4DFD31548C34079DD63782CE9A8ECBA + 1ECF590D6645090C333DD5240EA4F17E + stream[256..319] = 1D74EA209542EF7B09A1B03D995D178D + 3088E4AAE0E30FEAAE531A53246C78E5 + 0A4D6E2AC70B11A7E123E4FE26D82E66 + 9EC9248785FD7EB5BE1D36FC85BFBCB8 + stream[448..511] = 48CBA063235997E9E93A4D3F9E994103 + 0680C0636ED64D055E057F7461A1B660 + 71AEE9BC86EFF9EEABE02DFCDA753948 + A7C14057339314092CB3750CC4EDB7D3 + xor-digest = 1D3D67A63568877BE046E107C1A548B2 + 34EAF54CF4BE9630B886C8E846173330 + 798132C040BBE341AEBDEFB671E359C2 + 21C0FFFDF3B1524C4EF4439DA4BAE537 + +Set 1, vector# 72: + key = 00000000000000000080000000000000 + IV = 0000000000000000 + stream[0..63] = F6B2157EDE86467D5EB6AB4201F8C3FD + F309ED03CC3B83213F31ADA62BAC1089 + 1A4A4FCC9C1586D47655594CA3D6873F + 175FB977B5C188707A72416EF64A7FBD + stream[192..255] = 41F37DF1EE2987CB567672880D2B6046 + 67BD8F347A4DEE5082CB4C3C3496E399 + 6566C8800CBE194B994382760E981571 + A52ACE1FDFC0CC5C1ACEC5FC17D46E0C + stream[256..319] = 6EAC6BD474192CF1461E73F7B2357625 + 93616AD2EA10CAE5AC56893A5DC68DD0 + F839D49F0DF076AC2373F5CBC2FFB224 + 9F43C984FABEC387A2C195CE77407295 + stream[448..511] = 19B0F855E69328BB3467ECE9C47C2F8D + F389803CDECEFB7EFDB4D872527C05C0 + DB80286F0F606C2EC43F48B64CA2CEC5 + 77951C1DFF73024D5D52FA048EA47F58 + xor-digest = A1848B0D933572FB2FCF58035893F88D + 01D95BB6598647A9DC8EA326254FFC43 + DF34FB16BE6FB8A830EFC584DE2D5BEC + 7A68A03B4956CB89FEA243B54F6D8FCC + +Set 1, vector# 81: + key = 00000000000000000000400000000000 + IV = 0000000000000000 + stream[0..63] = FBF7BF104F3EB499BCD76A4D90AB9F49 + 4DAB13F5888DB91FCB94AA3663384118 + 3F8DA5008EBA653A56CFE160D97CA7E9 + 345D5262DDBF047E401DF8AA6A9C3660 + stream[192..255] = 7E8B3CA581D546B3CA71BC6FF852C602 + 3D83D85641A7582DFE4BFA0BA035859B + 87141018DDBDC3075CB7DB5F0A7C1A3A + E98F41F6F81D275324B5ADCB1DFBBCCB + stream[256..319] = B8DBBA37593A92AC49B54E01834BCD9C + 01D482150AE64B6D3E4FDEC546231245 + 480217E7B0007BCC12F81E841BB8ED13 + 5A17964F27BCC08269ED900709F7E5CB + stream[448..511] = CA073241DEA3E74D0AD65B5B5BC3A728 + 637C42263CE6ED5FB60760DEB7709901 + 39D6E784FF306C7B91FC9CA87B760596 + 54EF5F0B0A1CD518D89C31AB13A97AB1 + xor-digest = FD5A37EF99CD511340250D71074318A0 + F9EBFA19242AE466CD64D60286843510 + 6A741DBC09F86BA7C5DF38B606FDCC0E + 652D4AE2B1271DF63CA71B49639B809C + +Set 1, vector# 90: + key = 00000000000000000000002000000000 + IV = 0000000000000000 + stream[0..63] = A48202A2119A3809D95031267D92471F + 83774767C0F38A6D69D7A5FAE6827E2B + 687F878FD3582A83BD41AECCBA2A9189 + 7C7CC66C1BC7E090D17E5B22C7245136 + stream[192..255] = 8731DEED2A95CDF8CA78FAEC4ED9F2D3 + B782AE73D50549ECD92889F0624E7C4E + 67C8FBFFAA09FACF8523E578800355E3 + D5568304D3FF78A12452371570F0885E + stream[256..319] = BCEC4E14C2E112E66347B218421D1823 + 325A3D7866FB654AA247F4CCFE1E5772 + A3975B88D84BE71A7392EAE83E836DD9 + A0E422E2C191080F1478C55EC8E70EE0 + stream[448..511] = 4D334A264A4596DE241152DC705C09FF + C61E771659488096FD2B088456A067E3 + 680C0C060BCB072B3F5553156048379B + 26845BAD16A0E6C996AD1E6B94926B63 + xor-digest = 40269A7002F3910AECD0DAA32568537F + 27E19E221B5BA830AF317B294BF40363 + 07E3D1E52F894707133AE15129AB070D + 22A3064254B52374DDDC02C50CB2ACA7 + +Set 1, vector# 99: + key = 00000000000000000000000010000000 + IV = 0000000000000000 + stream[0..63] = 73A1348E48E50F450ABCEF31F8C777FB + 80754EDE5B17D226391FF1AE3394D81C + E47B748155E1FB7EE5289CDDFB872A59 + 083BDCAC8BF36DF8B7DF265EE1A5E4DB + stream[192..255] = D77041F6E5F9E992E0A6B735344A7ACA + 5038453D4409DF0DF40077256F47F203 + 1602B65530DF45AE4C75A00E7D85C35F + 5228157DF511F970334F79D256E8C2A4 + stream[256..319] = 45503E7C51C62DB78A736484BB3ECA38 + CF520F6417A54C460DC345CBF20975BB + 6D96A8DCA5F8D9E87DD8DDD90DAA63B7 + EE15BB426ED88DE79D4568EDE5F4008A + stream[448..511] = F313C6E3D2C09C36372AB808CD1D4BC2 + C1BF5C88409059935A812B059EE70513 + E96356B1525B6DA7C50EC0E3312EB5C3 + 12839384038A933C1C1D20276B76A16E + xor-digest = 6BB72FBDF66E44C6292AA5CFC2F59F5A + 50251793125E28D9F2860B75F4CA4E65 + 9CC449227191CD9BCDA4B2E5076727DB + BC210B0D5BA09CC8C39E3A946FB879DA + +Set 1, vector#108: + key = 00000000000000000000000000080000 + IV = 0000000000000000 + stream[0..63] = AE8AAC412BC6B6F81AD0100B231A84BE + EE3686E0ED509F08A7B40E4329883212 + 32198A234B5115F1360B4F93EA74F20F + 295FBDCD1805CA4D68145A9024B0754F + stream[192..255] = 2B182FF4FC75360E8E5B923E7ADE0AAA + 9013E613CE8378F1AFB29C1254C84E2D + 1B4864DF76120CEEB123908699AE1DA5 + 48F23E67C1DAEF359DA0498E6DCDF2B2 + stream[256..319] = E90BA1D435CCC1DE56FBCCC6A84DCBE7 + 9E18D7EDB585BD8E6D36EF692DF9C78B + 2695BBE2DB8E46166F1DF03F8003A2CD + 96EB1CEA4111FE22B30CCC52B0EFE07E + stream[448..511] = D41C9F872600EEDFDACF659D9FFD9260 + 5944446D321E0CBD1B12C2106FD7CFDE + 7A2A5A52B9B3DDDD8253176B9C9F9F55 + 687ED6A310F923978A2B27D99BDF32C3 + xor-digest = 00D0133EBAE055DB7F000B24E58EA36B + 82018514417EA1AC2B69B6D96BF8DD45 + 9063725F32CA06CB4DCB7335E8EEEEFA + A338BF9C98E01DCAE9297FAFB1DED59D + +Set 1, vector#117: + key = 00000000000000000000000000000400 + IV = 0000000000000000 + stream[0..63] = BED2F045FD3AE491375F44FF89915FB5 + 77B8AE4949BE93D027C999D4B0FA24B3 + 0DE2C9A498350F9D19879C477D791E31 + CD29D20E5575428B5035A26B4EBA52A4 + stream[192..255] = D5B1D692191B789C154C9F73080DA95A + FA5029189CDC7675DF29E8260EA589EB + 07D22713C074AB04F17D1B608808D371 + 6D514626FEE626962B1FD417B637A534 + stream[256..319] = DE7854CFCBF99FE8D68025711E78CBAA + 6029E88DC7620F9B87308D97D4F46DC4 + FF40A3F3D4E781FD7B899C621D42AA9E + 07871DBB8DBD2B8398AF921B01B17E62 + stream[448..511] = A408101324D5B636A4D67D11DEB3DC14 + 911C7412181944C8268127303163F4FF + FA4681D85352B1230ACD8663797A0C45 + A6DF090A2229B93C6EC7D08959919E42 + xor-digest = 9C45A25D754235C191A748811F9C8483 + 7C06795D0636CAF8984DD1C3E1DC9A84 + 639481D2629D363A8F3AE7952048FCCD + 122AF5B2F9C1F1E9736B0894514F692C + +Set 1, vector#126: + key = 00000000000000000000000000000002 + IV = 0000000000000000 + stream[0..63] = 2668749B5D1436CC4A7C43AB4381EC91 + BF447D1F1F552F7C2493DACB72ADD952 + 2A0A3397D2550C01CAA56B107BA2AF0C + 8A107A285BF087515E6973C128581B80 + stream[192..255] = D79AF153B28AB48B6E18F79357E56906 + 0AA8A10D528014AE4F6C8A088F38DAAD + 6DA52A44D52EA554E195AD84E6180EB5 + D9B4EB680BBBD715105DAA9041F73646 + stream[256..319] = 401F99CB4DD08640B512F8E0899A97E7 + F98A7B9A60B93B3BCE05661A93699470 + 6FB4B484BB3CD05D4B7855F6A54FEEF1 + 47E850FF33E8BC2B4801C6A96F306DBF + stream[448..511] = 610B5B3AA681D9A5B8A3FA34F1B273A0 + A1643935C609BEFE896CA2E91FD13D79 + B4423DA10E93CEF63C34F0CF9C552346 + C180D73C7AC283CD9E6193406038AC17 + xor-digest = 8AA39CD16339D283557423BE770F25E8 + B897345FE6CE733C81709269C0E2E65C + 8105B7A62BB8C8B0BF9F3407DBDAD0C0 + 781E452D54BC73BC8518D9679762F322 + +Test vectors -- set 2 +===================== + +Set 2, vector# 0: + key = 00000000000000000000000000000000 + IV = 0000000000000000 + stream[0..63] = EDB70567375DCD7CD89554F85E27A7C6 + 8D4ADC7032298F7BD4EFF504ACA6295F + 668FBF478ADB2BE51E6CDE292B82DE2A + B48D2AC6565979220EC909A7E7576098 + stream[192..255] = 706630D4C431BC49E07D9CBF98FAB946 + 7108299DD9B358BBB4AEE64AF67F1E5F + EC3DBA07A0CEE1BE2E2F0AAB10BB8106 + 35F403DA20B8ACAACDE4D85546D0A820 + stream[256..319] = B35DB614A32070FE8CAC67B378184C45 + 354753D37EE6D057ECB36E0D5BE5DAC4 + 11CC36DA10A2B670BC201B2C8804377F + 25C599ED29294F3E267C866DCC68276B + stream[448..511] = 109D5563D46DD78C2905F7D90036300C + 60326EBE3B1AA385FB75F1C5C7311BFD + 6DDA960C716C33E51C5A2B1906200C40 + CFF62FB5782A41BF816F7639C9341244 + xor-digest = B4BCD9E0E9CAAE180CE6EBEB12826CE7 + 8FEBC2BA6A374C39C90F1FFF0C059FCE + 2A197950302FEC15C2C21602C83233D9 + A8DAADCBCB0C5E93F1361E7C29E1BEE9 + +Set 2, vector# 9: + key = 09090909090909090909090909090909 + IV = 0000000000000000 + stream[0..63] = E7F8DC75257F98D89124464C5DDCDC86 + 93F8456B7FA2E2E0A907F6B4D9A56F2C + 86E5978203A6C8791C119D7AEC91D5CD + F087AE3943091B2788B675353A0AB24A + stream[192..255] = FB8986A91C6CAD907E90A47F962ACB15 + 5112027212D69E08C230A8495147F6B4 + 3E769D9CCB01F6472E8FBA993AC6ACB1 + D37918D00C269B7BBE14766579938E69 + stream[256..319] = C665BDB6306B6C8AD987BBDAAD5C3B35 + EC8D0552058472C8E6E2A068C7BAFB3A + 301724B7B601FBBC2289114CED423467 + 59BCF7776083801EAC2C6330C81B0E45 + stream[448..511] = EB0629217238ABDA20897FA7D81CE478 + F83CE9BD5B45490D94780C17F796CAC8 + B16A60B66D31BF21F0BA3A7AB08C6262 + 3AB28229B1B716E21C6D2DAB92559B71 + xor-digest = 0D6B57A05FD49F29D9B90297B5DE1D51 + 38846792553D4B5766AD55C04A6DC58C + 58B678EE1313F96293D6CA6BD6AA2E7E + 8D5B500C2BFDF05DCF2D1435B8C5E00C + +Set 2, vector# 18: + key = 12121212121212121212121212121212 + IV = 0000000000000000 + stream[0..63] = 62B5D123F8E578D991AD64A698339366 + 6EE1107AB0EE844D000087F52F9E9038 + A413E3B500D1A7B50F94359B004F2132 + D1F229686673D12DCEF24700C297AD74 + stream[192..255] = 28277E2776C9D0917541F37A1EF8E761 + 06E75AFB73BB9217AB350F3D78411A63 + A6D3E8AD8850178D241E969F9A035228 + 92FB2EED1EB486802C9DD456ED42F67A + stream[256..319] = 56476411E296B39BDF320E5FCFE843F7 + 4592BA463785CA8FA7BE44CA965E0F5E + 347CD9703F9CE09856817F8F2F221F62 + D0762E166E9A7737903DC0CC06DF5628 + stream[448..511] = 21F84D08F4A321A883C2C9ADBEA4342E + 6F490D3D44417AE971324F3A0A6DE56F + E1A2C791DFD35B73355F9CE8F9C30D94 + 94F97CCFEFCBA9613423595BD95D11F6 + xor-digest = CB88021CA78ED00336DD0FEEB7186864 + 1B5CA80234B91E6A12A079048EF3AFD6 + D4DF9AE4237E9B367D56E7F61A563DB1 + 94E5D00218CB7DA829AC23757A6A4A20 + +Set 2, vector# 27: + key = 1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B1B + IV = 0000000000000000 + stream[0..63] = B8BE166D69975D3D9D991DC28F7B334B + D14CA741BAE95E93FEE603D54509F8E0 + A265373D1A5BFA0EF97B61E2998E7228 + 3727FE5A3DED85B73CD41B86BE594684 + stream[192..255] = 6A883DFC1E145178A884566EBDAC1BA2 + 5ED178C449E6609CB2C500DAF811C876 + 3B96A073A74A8E5B461AA88290352BBC + D3CB63F8D071B76F78A939147AD5E0D6 + stream[256..319] = E531C743E67BC628C9FD3D8312940115 + 8BFECEC99A22DF0ADC73501ACFF26011 + 5B6D1094EA51A841817919FA5375599E + 60652CF37FE2100FEC4E6C45B6AB162D + stream[448..511] = 01C885E74B3A5438A005E35E8F04ADF2 + DA312163CCE2372B2E89EA10FA9D269B + 6D9301A30A652D4CDDA0EE147DF05286 + 8D16156743B90439F66C018FF4FED91A + xor-digest = F0FB24690E099CCBBFC949D2AB526549 + A0279BB0289370DCD79F96D3C8E91BB5 + 9588FFEF12E9333349002EF3CDBFF5B7 + 560CF367DC52E75A1C0AB920358B921F + +Set 2, vector# 36: + key = 24242424242424242424242424242424 + IV = 0000000000000000 + stream[0..63] = 97260F8165CB32935F6E82380645E129 + 05550F2DE054C5C443489C27706D8E40 + 5B02C5F17288C72B5E91D9635B7FFED5 + E20A533FC30AAB90362A4CFFE1158446 + stream[192..255] = 5E5426797F310DEA867640CA530B1F9D + 2F8178F9B9996E1435EE0541580F1D08 + D2AD17DDCC93A4E250800D902CD56FBD + E779D40A0958550709CAC29040F9BF70 + stream[256..319] = 86CF2D6EA2FE0DE8BEE8F52CC742E98D + 55763BF9EC2F7ABA63C12E9487E7948C + 0A864D78FB5E99D0587254286196B239 + 02F4BC3A5E55B3C63142D10F8401AF63 + stream[448..511] = 4A809F1147E7FF8B541DB96B56567268 + 741E623467751CF3AD7FDFE88525A052 + 60DEB94B88FD630433D568C5C964168B + 8CF3EF696841ED6E4FADAF86E3D920C3 + xor-digest = D5FAF09F542D5B25286E6DEB8CBCB0EE + F6070718EFB5D4C320B2EB4A57401A55 + CFB921E2C33C1802D0A190D5CFCBFB22 + DD8ED5D0C1BDCE5B37438A2F9ADD2973 + +Set 2, vector# 45: + key = 2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D + IV = 0000000000000000 + stream[0..63] = A98720472640C385E68F7407CCA56859 + E667C471121418C3F1F653EDD1A2DDE7 + AC6735CE67A92CA65772773829CBA796 + ABF7F318AE8F6E0FEB8C8D20D099627C + stream[192..255] = F62CE9708066A91A88EA206F2E1B4899 + DD81D6194868B67B6144470AFA708810 + 36F624ED7BED52A5A1C68E953E22F5D8 + 3ED08F9B4819BA0DACAB6B8E5DE254B1 + stream[256..319] = CA275CD70DA59F4D0EBB25D5F347C421 + CDD4B7739DA4226824FEBD7C598322BD + 2C8AC19059FC7857239CEFE7D3570927 + DF199C62570723FEBCE55E5D2E97C230 + stream[448..511] = 4974E94DDBE366813E27CBEE6CE96A4A + D09E2D6BF52037AE474B05B1A1B55703 + EE529170AE3DBA70EE7159892660249C + AAB273AFC70AB8C8E47844017E6581C3 + xor-digest = FECBD4C1438F3E74A3AEF0F4809F9DF5 + 564345AA54D338B71DF1D457CF9235D8 + CC2BB61B758F08DDB16B5E29713A9AA0 + 5F50D69C2279E64194BE87A8DA1B6609 + +Set 2, vector# 54: + key = 36363636363636363636363636363636 + IV = 0000000000000000 + stream[0..63] = 215C64657D3E1F9103C791A68D1B2CE3 + 0FB7E40AE433E5D490C76F3FC87C3E43 + 12798A3468E7A9BE956966C9C23969F8 + E7F5732F046AF520162F559D6C5DEF8D + stream[192..255] = 3FA8C3032AD52534D2D18395FF42D32F + 271B2BE17A79FDD809B5FC0BA8840B03 + 32DA45D5B47ACEE16B0F2E567CEC953C + 63810E98F4FD978525A770B6CD520ECD + stream[256..319] = 326170765A7499E7826E4DE5AE7DA1FF + 506E6693DEA0816934A04470A9A6F820 + 89687B52EEB399E9E7491F6F50F66146 + BF551711108E279B3ABA667EAC965EB4 + stream[448..511] = 0AC5911B6BCB6E3110A4EC1AC0FD473F + 1D4E8AACB643022C376E2231F6039ABA + 9A3B81A155D3972F8987CDE1E467069E + B889BEA2F814950A0FB9D97D17B6B1A7 + xor-digest = D5A28A548DD779BF9D8ADD8047C09973 + 7218D27AB9B357F62382E4FA35364672 + FB71A0B735C1DE9F6A3695EF6DBCA5B8 + 233B5CA9C7E2D42650469C860F7711BF + +Set 2, vector# 63: + key = 3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F + IV = 0000000000000000 + stream[0..63] = 07A2104DF55468A03A06D5A031DC2CB3 + BA0AE5D8262133A553630048B0F0C19C + CEA0CD6D03A5ED394698F6DF83C8D16E + 6E578BD1B2145AD9D92AEC5F298EA6E7 + stream[192..255] = E8E5FC6B90D0E9745F7E26CB6E6318D3 + B09DB532355C29D451183B83AFB24A5A + 309FFA6D9ACFD6059775522E6616B5FF + 0F994D08657304D560573974A39FA086 + stream[256..319] = 3ACA2DAD216828E27A8A69ED65BDB748 + F612A7891B734E39291B86A19DABBB55 + 942539D6275A94A60EC29007EBAF4DFE + 7A4911D83B951D226EB992FBBF552B08 + stream[448..511] = FC03429989E2B4549D88DF29C39290AA + 087E2ACD95404F1E605FF510F63D1FFE + 9F2D0BF8B709B92038C56A3FCF60A8C3 + 208A50A09F015078EB14E972C45C73EE + xor-digest = 3E0084DDB6836BC98BA3E878FE321128 + A56218279BA6155C6BCB601ABD259CB9 + 8D4CC8FD6F547D8E7DB155DA0DE3A6DD + 4F957C6BD41A1A09FFB6214AD39779BA + +Set 2, vector# 72: + key = 48484848484848484848484848484848 + IV = 0000000000000000 + stream[0..63] = 7D492821BA504459DDF1B750789689C8 + 79363F723E05AC35302C46219B542AD4 + AFDD29854FDB8753235354C9F2D9AF71 + 5BA712F8AF8E9C98328597A63AE9E338 + stream[192..255] = D79196E3EBAE2CC7B1E361D693DEDF92 + 3020B5B69B96FA91CB54D0A039CBEAC5 + D85C6F192B57AB2AD2C5818E946D4275 + 08956D83FCBC2883266BD702A43A7242 + stream[256..319] = F06D97724EF4A84819C18A9F039F8007 + A7FAF92A4670370C84FFAA31D5AB00EE + 29A541A23511FE62E10077FB274EE114 + E667D96ABF0D2FD2249AC38F11C627CB + stream[448..511] = 1C692D1455CAB3D3CF9B4D0C6DDDDEE4 + F63ABC2FA458917B4CF04436EAB75CE3 + FBC6B56CF1D3D24CD285F1080BFB6189 + EF8B8F2A9B851A721445FFED5B66C073 + xor-digest = B5560C273215214C7E1B552528BD100B + 87CDA0FC7DD3DE92827787F3BF41FD51 + E35EF7237F14E2A027573D05995297F0 + D559383CF9CAC082A215D113B2FE255B + +Set 2, vector# 81: + key = 51515151515151515151515151515151 + IV = 0000000000000000 + stream[0..63] = 9B50B71FDEC27AF3F5224C02D0BF435E + 64EAA7E927F6E0FA4B6F0E444389DDA1 + C8AC946BF3BCE3EC2F8474E386634D0D + DDD2399C592D41B6B9242948E29722C1 + stream[192..255] = 58425A250481646F6C4114C73D4148FC + CBF2A8EFE6094232C10D7DA2F2B3283B + F80C101C6F42A0B45024509AACA67EB5 + 7972C8D1842A2D452CFEA460FF9C65BA + stream[256..319] = B03B836E5E1536CEECCD98FE0E30DA3B + 2106B0480E599765DB406BDB9FDF2313 + 2B4B4D4D0B8B321B1CA1AAE0E62A8676 + B7D0CA9D953B6F80CCEF7CF33E91DD20 + stream[448..511] = D36E8B836369ED37416D47D699C7EC92 + 75A30B8BD30B3831042A41D2D7418AC1 + 847E9F918B6E348644EED62B47B6ECF0 + 906D3B8D4CC533100652E7503CE77FF0 + xor-digest = 86A6D63324A4A691A3110F89C9809B09 + 61FB6E36E181C9715A56B5C07A890DFD + 48687CA7D5006A364EC9EFE8D4C7E1D4 + D9306C85A09351FA9063D8AF3D007F95 + +Set 2, vector# 90: + key = 5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A5A + IV = 0000000000000000 + stream[0..63] = 947BF8D9CB76D72AD11300E9F87DC775 + CAD0F21E55A9B4E3442A811848C8D3C4 + 403733DEC1E0AD651762E9C76649FD34 + 9B161773B20FA271CF88753173CC9A3E + stream[192..255] = 250E5FDC25CFA6556EC8D14291213495 + 9C48BE9E99FA11204C4F0D2E60256BD2 + E7BDDB750028D1FFCA7890F2E1052A99 + C5FF22A1EECA028B42E48ACBFC022CFE + stream[256..319] = E13B33F7C1D963D4306902C90ABDB406 + 847EF90C72574CD04CB8407DD1B1F984 + 5732F9E7D782B93E1A76D8B3D55A4635 + D2F56730C54F7099B80C843AC738A641 + stream[448..511] = F80EE18B800754361D4008E630A34740 + B7D07A89A711F0F3F3FD18AA2B9CA689 + 29A1E8684EC396188E9A4E970217624E + 22BE83F87B593FB548DA290256F072BD + xor-digest = B258C26705ED398D8912A42D5E87E326 + 1A25E341828A19E14D0C2C628DA3C105 + 69816731909374079DB5F9FA68E499EE + 6FCDF2D00CC1BEFAE0EADEF7AA1C8365 + +Set 2, vector# 99: + key = 63636363636363636363636363636363 + IV = 0000000000000000 + stream[0..63] = 51CDD88200CC5E396ECDEE75342E2797 + 09AA9675D6945A1046AAFA2171FA3ADE + 5126A367BB1DE48B9751F9CFB9A617CE + 365964AF30AB56F36C436D095C9140CD + stream[192..255] = EC7DB5108C2B535694E1B2CAD6EEC51F + E52B2587F8A0DFAC557B15A8F30CB73E + A87C5ED19079265FDB218D364F3E09C4 + 7E733376E8005BD2A198A1D13BA75E77 + stream[256..319] = 4112BE43D8BD6668DFA0C1F2B688906B + 338F6CFCD500F004E7BF2BC903C6E1EF + DE4039331A26A144298759002F7464A7 + FE5B68CF7DDCE26001D9EE6BF8318FD3 + stream[448..511] = 7893CAC1C6065126DC81170B16EC751F + 69012E1E3CF63CD7E34FFD4231D89FD0 + 6D3933066527A096E2E2ABCEE979C950 + 771302C80EFF7A69FE0960390BCEA519 + xor-digest = 48B42918042606E89451B9CB4E943B48 + 79E9384F1394561A8CB45000BADF1BB6 + 66834FAB3AD77AD3D4F449E8706C52E8 + 38E071357076B8D0E6D4D9C07028A23E + +Set 2, vector#108: + key = 6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C + IV = 0000000000000000 + stream[0..63] = 718EC9CE30AFA1D0227EB4C258E3E021 + E5A8C79FDE66D5E77DA9AC2E03C4B215 + 438961E4B7547DE3D25364139603680B + ABB795E71E68DC8BE87D2044B5C3A6EA + stream[192..255] = 2BE5B79C27D0DF9E5C9664D6BF5A0809 + D77EDE0CCA5F975EC178AB63D3DC660A + AA79118FB469BDBB118A7EC3B0782BA3 + 6F9E5681020A77FC0F63096D4CC4FEAE + stream[256..319] = AFFDA31EBB725443EE0913591359D3D3 + FC82DC94F39E331FFD9A622C260778BD + 2BF519E6C6048251254654159E4CBE24 + 6310BB1A7B6EA285586AACF0F84F3D98 + stream[448..511] = 10310F70CFF2222A64C1CF1CED8CA57B + BAC520E01B2035EB4C4E029C5E7E8DBC + 4A02C3095A1AAA65A7779A5FC9C8D1C4 + 8CD462021A992E2FF0D782E042E96EDC + xor-digest = 7EEE6D4E90322574C6694FFE5D2E21E3 + 8D9639EA13B0C38F428ED8B9F8FD0158 + A26F50CEDBDE38772A7E069ACC4E2203 + 39EC4288EBAB10CF1F0A54B0D8FA1B9D + +Set 2, vector#117: + key = 75757575757575757575757575757575 + IV = 0000000000000000 + stream[0..63] = 735BDE23068FCD60A416443FA9C0689C + 5239DFF5785E7852F08EE0904BEA8BD3 + 9DA1B26EC7025F91179B7B7A421B999D + 716EB9653312FCA12F4829C5012A802D + stream[192..255] = 6AFE2440ABB1AC5EBAB9246DACC8554E + B5E8F9B2A256E99AC6418BAECF68D3FF + 66087F0F82B3D3E3900527B1FC8DEB8E + 7915673DC0FAE985FFBFAECC8E4AF31D + stream[256..319] = 4BB43B3E90BF7E949B77924790EC46B3 + 522C2B413983C4B0DE143772E2A35F9D + D27EA8A3723EE996D79F6A07C957405D + 3B264FFE5A4B3EBD985A459EBF30AA8D + stream[448..511] = BB9E0A1828F1451B1D12FECCA3B9DA6B + 15F7B80BB16A2EEC694945ED3034C799 + F15D1754820F8B1AF07DC5B5F8566320 + EB1162641025DAD7C99856050A92A6C0 + xor-digest = 0C46AA24CADA3276ABED94075916980F + BB3B609B8898036BA0824403771FD240 + 51858E248985B6F6F6DB450000BF3144 + 909084962E5AD310C049EBDD37110F6E + +Set 2, vector#126: + key = 7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E7E + IV = 0000000000000000 + stream[0..63] = 97CB4027B82651B0CB7D6CE5B391307E + 830190157E94E8F0F4A51177006AE316 + 9A0EF288684AD26E960F28CE91A74C80 + 40E153A6436100F3629E54DE8A7543AA + stream[192..255] = 730F3617B24C69D06B69ADBC0FDADAC3 + 736DE952DDD088BDEF58E33AFE75FC40 + B44A3014ACFD59A41FF785FA79F8C4C8 + 24783435F6DFB1280484CE23BBFCD13E + stream[256..319] = 2E4158B11314F19A08A6CED50ED9B751 + ABF952E7F803A60FBF497C56EE6B0016 + 1857ECE7AAAE45715405C2A1CFD5780B + 906A11E3383B9539F0B47F325F278E51 + stream[448..511] = 2AE2FFBCF916B76CF0C12B5F15312331 + 316A7CA30D1DFF8EE7307F4B9182E73F + F3951640C0E1BE2F62EC909D7F1AA193 + B9BB78BC67269BA40CC80C068123D812 + xor-digest = 96CF2189FE7BF7919EF7518DF21DEC7E + 33AC83F6002D9DC83777AFB7C883549B + 6BA6790EDF911A1C732EE1E7FEE3286F + 8A521B18A5495C93948219BD86302591 + +Set 2, vector#135: + key = 87878787878787878787878787878787 + IV = 0000000000000000 + stream[0..63] = 691C8D4B72F476352162F33DB1C2D4BF + 0093525DA58DD95F092599E3F79D7E4F + 81B241314E9C701F93CE1D5104D0BFAF + 8226B3D7F89FA3C0DF85F387264BD1B6 + stream[192..255] = 54545F7F0C033B3987DFD2F262BDA81C + 9AFCC996841E9EEDC56CA8624FF1C8BA + 7A5E9312A3F60DAD2D3AFAF374CC8801 + 54389AC3E9B671D7E3DE35CB2F5070AD + stream[256..319] = B1FF911D70563286EC15DD205E255484 + DCEE25DB2FD91C0370341266812EE245 + 3989AA76B1CF122DE8407137491A8CA6 + 470ED10B208D146C014D2598FFF29971 + stream[448..511] = 6264AB7DFD5F9B519B20BF4338BE57D4 + 70D9A2FAC0800A1C3FBFDE4BE56CEE62 + 9D9C4DD638CB9AED526A4F9DF5E6DC98 + 03AFB8CAF727D3920F48B32F7D10D3C2 + xor-digest = A703B8C516343A5A7BDA170ED35AE0E7 + 8C3AD265CE8108CFC6894EEB172018D3 + 3369BA9635576641E381B3DEB3709894 + 001B31DF53A7A21BD3365479C055DCE5 + +Set 2, vector#144: + key = 90909090909090909090909090909090 + IV = 0000000000000000 + stream[0..63] = BC29877AC7EEBA85EB0CCD51520A2DA5 + F12B9B8BF67BF79914805B7CFB885B50 + E4486A6B986D2D72F90B7FFF720BFAD9 + 9560CCDD9AC940A9FEDCE4E57B7D1D6E + stream[192..255] = 933AEB49B31D4D912A42989EF0DFB3E9 + 6E58AAFB82A9734906EFA9438C213ED7 + 650806FD669F8E8351685E6C9A80E54E + A392F7E976BCB4A9950ED13FF8525950 + stream[256..319] = 7774781474D51E242AA0ED506FADD4BF + 819F4D4B5940D3C4B9FE29137F44C240 + CC7703D605ED34756FFCE645B8B739DA + 89D101D9417331652790D11E945E022E + stream[448..511] = 8A2AE04BE3C2EC0A80543E7FB1FD5B8D + 3C37A388B926CC2E07557F69BAD423E4 + A48B7140FED20CCB311A5367B15FC7E9 + 4599882B51B4EF7553227DC645D1EB12 + xor-digest = EF83377A740FAA9F53967E618A2F83AC + 85EDD1D47AB532930C85AC7E2C06D170 + C7C11CC9D12DB35CC5A33FEE72F51306 + EE8B295D5B379F96469B0EAEDA9F7ADD + +Set 2, vector#153: + key = 99999999999999999999999999999999 + IV = 0000000000000000 + stream[0..63] = FFF8FFA5CAE356592905AB22F66D9C1B + 4C163EC0213E2485996FF1BF67C81C93 + CA37F2195D03DE03AEFE7295DAE49C1A + FFD2ADAC39212A73BFC0FD9C78946004 + stream[192..255] = 5D05324036F89E337415058019D12847 + 787875A2358C4CC99FC1A540D63D5391 + C1392A152276D94F32B0B7239BCC98F5 + D3D051371724EA9D905784FCC42AE9D1 + stream[256..319] = 1B61EB32CB5E3636A178CA53E88632F5 + E777C04BBFDCB9B737077A10E34EAD3B + 17A4A37AF5F15DF29FF69032F8187C9A + 907B0EF39060E5B828248BDED883DB7B + stream[448..511] = 643E75D6C08C2F0D0DDABF94B4963B26 + 95F45FAA44B440CDFBAA7270DCC41828 + 0AA1CCE520845A6C89B6357C2B03AA3F + 3216B26690C1804408B9B76DE64AB5D6 + xor-digest = FB18205988C1A8F57138CF821120688F + 51CB7030ABD1A9513380C6D07BD667C9 + 281D8DBC2D745F4A2F8E0E7CC2968B4D + F2A2409455BF45970A66B212C4932E59 + +Set 2, vector#162: + key = A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2A2 + IV = 0000000000000000 + stream[0..63] = 067EB690A95E007395D0D7557C696EF9 + 37A3FB5403F6CEC8A76612C4A8AC48DF + BA2EFE0BFAD60D6841C8D1ACD1C4C79C + ED6EEF0AF9E289BC1A88F000A553B753 + stream[192..255] = 5D4B1B0BA65454466C778EF5DEF9827E + 79AC5F042551964F3725C5CCA5E5E283 + D0ACD45088D1F67E2D85B918569D69DC + E323733E16C83D3428E2478D6F1E8766 + stream[256..319] = 2AE22BD0B6DE5565DA5E82F10BC62BE2 + 32AAFEB29190C3189320CB512C0CB544 + C173743D6BFD18E4037571F68B34987F + 6956A8E932A0B89759A691594A22CA49 + stream[448..511] = 1A563154F3CF5EBB95962A0F1DF8E37A + F0A286273ADBF25B37762DC042E70D5D + BDB28FBABBD50CC35A7590C1E9BA24B5 + 75B45A147A514C038024577B8AEBD681 + xor-digest = 17EE61E94001F77D8F3C436768E5B6BB + E202704AD61FA9DB9C32EABBD5C55729 + F9BBF56FC4686C65E4E341AF86420BDB + 24CFB0B1A9A9024A9C5C901B2059C4ED + +Set 2, vector#171: + key = ABABABABABABABABABABABABABABABAB + IV = 0000000000000000 + stream[0..63] = 545C27A12E1DD9411BC1BCF189105E8E + A2286537B78122FCE0E95DF7ACC9088D + 37461D61817CFDAECADDC8663D2FF849 + C2A1BAF9999C67537654CBA119EE1F94 + stream[192..255] = 2FFD4F6CB89432E59E4CE374AE175DFB + 99995172DD0D122854E47C4CAD5B1D1B + 4A8EB2612C8C21559D92713765DA0B86 + 1E6F75929B8B235B154B224E28A0FF0A + stream[256..319] = E3A12DC9155DE6C1040D44185B644648 + A67B787ACF472FE054F9A106496AE778 + 3DC7F313DE299E385C74D4088647BDD2 + 0198FA4A0E613BD41D6D80E5470AA7DF + stream[448..511] = 0FD043205ACD3163FCFCBCE388C8E912 + 0AF0E34F9FB2C46D9AFFBA7385D51872 + 1D53349FB44822270A863415CAB90600 + 1F412376709B7ADFD3F99EEE5A9A25A6 + xor-digest = 3365C1CDD5C7C60BBF75402829BC7582 + 4989105902270967E240EBF6ABCF3B06 + 9426AD0668D6AF70D5BD32C1C398A0D8 + 5723E976AD93CBB93BEF46E5578F3C43 + +Set 2, vector#180: + key = B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4B4 + IV = 0000000000000000 + stream[0..63] = 97C252D3DC5B0BC06A9E3CCFF0A88593 + 451B5207CF1299AC5061386B3706BF69 + 45FFBC060E250146F0725B096C2A3390 + DA6B4548DA3440BB6245AEAF8FC5C1BF + stream[192..255] = 965194C8A4163FD2DE3F82E4B50C0997 + 016E88EF508657CC86DABB70B185624D + D9CE3C74BD735B78BAA3D35F0C99EF85 + 8096CC51472D4B73ABE69765A77EEE47 + stream[256..319] = 89E4A8FDB029B59B61EE7619F75E8EFF + 37FBA6E011C2E669546F80301FB21CED + D58C928D6EDBB9AD1AB0BADAF88FCB19 + 2AB3473868AA7409C48CEBE690D007F8 + stream[448..511] = CDFE4AF0D25CC0CE5469422F3EF2EEE7 + 9B1365D01A36B9D159EC9730524AFD49 + 59A36A2AF2EECAC181C08F14AECE9123 + 9DBCA8A7C86601C4A4445B0036BC7A77 + xor-digest = 7DCC8F903C429AA1524A2C5B8B362AD8 + DB74C8B56A17083591D2DBA843F1FE09 + 4931DCBFDB18C59C251055B71F303287 + CA3CDF2989639EF6AA7F22496EA784B8 + +Set 2, vector#189: + key = BDBDBDBDBDBDBDBDBDBDBDBDBDBDBDBD + IV = 0000000000000000 + stream[0..63] = 4C90ED8E7CDE917A218A58DE158CBF98 + DE171190BEFFCB31C1F6318578D210D9 + 5F2707EE1D6BEFC7303598061460894C + 7B2DB117E1998B24193B57F9121CF00E + stream[192..255] = 65E99A7815A4F7227A28BD253D275D1F + 8BFCBC8D72267CA221FC28E14C2B0FB5 + 8F0312BC8DADF8BAEEA838AE314C8BF9 + 4D9B292D0C8F093E3EAD6D8CCE1C4E05 + stream[256..319] = 47DD67B6D1778546BFDFFA83202A15DE + A0A02B7172D764E8EBD41D7D4C6B1AF5 + 164532367FAA52F35C63029E7EB6DF0D + 69D693FA41099EFFB3DC24A183CEC482 + stream[448..511] = BD4E150CCD803DF7A70307B306D69EBE + A04033C5889709F1E8D2FAA01BC236CB + D3EA172F53CE1C3B05FEA8874ED2F6BF + 1A7A64D69317C121B47F018C7B03B6CC + xor-digest = A72F5D1A12628451F19AB66FF5F5DDC0 + E1F6AE4E03D97E8BFA917EFA14877E83 + 6352AC191030FDAE82A0CDC57CFFBDC0 + 79D6D1309B2D228BFB050164A6ED5506 + +Set 2, vector#198: + key = C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6C6 + IV = 0000000000000000 + stream[0..63] = 61761E8265DCD6428005F25C66430E69 + E508B4D63E7A0746123AF7959DE08D64 + 286A22946A03D623E57C59B5FBC78185 + 84CD0FFAFCD313A9D03384BDCE947703 + stream[192..255] = 722E974795C1EAC480268959F71BCC89 + 53AE515C290C7132EC448297C0BDC7D2 + F24A9AA9BE107A241F2FEF07AAD735F2 + D98995C21A3F204916F98E68EC6B7AF5 + stream[256..319] = 0116AFB180A3E154522F4BD234997887 + EC424889A0DC92683FB924DA28E750C6 + F4F91D21146708C5130A8A6864CC3CAA + 7EFF7BA1A1F09E1B92EB2BDD103810E9 + stream[448..511] = 6AEE8931388A469AC8B5E5641E870B8A + 39D22BD7C8A61EF04F9D988F17130BD9 + 8DFBAD94C7E68C5F161B46571E8C4396 + 2109C393B9AD566778DEAC09687020A8 + xor-digest = 02E032A9A4EFABD204131C39F36E18D9 + 2777BDF68F5A6B85B1563436B7DB9AD5 + 0B4BB47C80FE8330D50A4ECCCD76FB9F + E77E53A799AD95111FEB7EA2C0CE781E + +Set 2, vector#207: + key = CFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCF + IV = 0000000000000000 + stream[0..63] = 07ECA06EDF7435732E1A3DF0C8FD5FE5 + E9A14EC485950AF0586769584346D9C0 + F501EDA74407F0259F17533A32B98EFD + 19351EB8FDE4317CBCE57ACD76E528B1 + stream[192..255] = 06392E1B9A23F685F65E1DB264D4F9CC + C16A5840403F7AE9E261E41A0ED8F5B2 + C958B7B8CD7EF8AA1BC43FD1D88ED5B1 + 9DC0D5F99A8F0C119CDB25D5A73E593F + stream[256..319] = D520C6CB4461EA4D57BB3D93AF5CB2D1 + 222EFE518CB9FF5C1319CFBD7E751EEA + 847CB491E49FF4DEB914355C91A5D98A + 8ACE00A3798A04EAF30BA0CBB163A149 + stream[448..511] = 6194F2657A0FF3F2AA9329EBACCC660C + 121AAFE3B5CA4D45801177DB48652860 + 950B6F2BA2C88535B0EFDAABE4F7D8C0 + A07CAD3417F5495A6348E2076D83DC9C + xor-digest = C6417A693D5B27F82B115DCEE4EAAF7A + DEE0061728D59023C4E707C41B5830B0 + DCBD60E662FB7D747837D55842672948 + 4939C2C8AA1EE53899B4CEF1CC80682E + +Set 2, vector#216: + key = D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8D8 + IV = 0000000000000000 + stream[0..63] = 7F51E124DE7011292790C991D92AA730 + B0C28EC739CDF7497D9B0B7299A46E8D + 82ACA3593EAEB4705ED2E310940F55CA + B2D152AD7D4936BAD877AD328C1D1E57 + stream[192..255] = 67A961516B49F08D550C61443B2668B8 + 891F6FFF0D690DAEA7844757CBA0E3FC + 910209AFC9972854426FC57003C5A11E + FBA5C4D2DFDD1CEE5C7E616C61BCAD7A + stream[256..319] = C02B7A7ECEAFCED8D8EA92F53DE40A1C + BF26F0A24EF73AD81924168FB6AFA085 + ACB72647FB6B259160BC3E29D1C87912 + E4F6755B33E2E34F86E31B0D63011FF2 + stream[448..511] = 4C0CBC0DDFD5881B04D321342D8890AA + EEFFD98E3110656F60C8600D5D11CF00 + B071FF8769DD775A5C09B92EC68DC494 + 6C5C6A2E2AC5C037BFE3C00346C4112C + xor-digest = 2DF067AAF237429388B235E728B3D917 + E0EDFA56CCDC81E55F33D5A332E52D68 + 81E0DE585840AE5D93B23403F60ACD63 + EC0DF42D4DA322AFBFCD886E1A581468 + +Set 2, vector#225: + key = E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1E1 + IV = 0000000000000000 + stream[0..63] = ED1FDD5ADA19BECAE0FE43BD3C6813BA + A54C70D0F270407ACA453A4FDBBE4D0A + B14482673B74281385496EEBA9548DA7 + A3E9012F702E3155A3F8108D79FBBE5B + stream[192..255] = F11DC4E2CE10EA7859015A36808B45B7 + F1CB4B9C699975D15991FD8DEE2AB52C + 7F505F6D1DD2BED794D4747D6813DEC1 + F50CA56251EB814D32FE9776ADE56D22 + stream[256..319] = 8E9FF31F7A370CF111F0537B208272ED + DF88E13B871F9B5FFD1DE2EFB22BFDEA + A42F96CA49A1F1E0E2598343C953F6CB + 2B7DED9B557925A3F24CCA83329AC6FF + stream[448..511] = FE8280084BF7F75AE6917333CF6D9CD5 + 3B5EB638FD1FC47436255FC249A2C65D + 8D3CC92A5E55313A2B9FD1C3DFAB29F0 + 5393C7D50CF5F1C6F0A49E61DB3E8844 + xor-digest = F6215C116D2942069BE90B9BFA43F9F4 + DA855215E57F479472F65300220A53AB + FE9051AA965E303D9404C85D8D9F9837 + 87B5EF73D5747AD67D3B9A559068A44E + +Set 2, vector#234: + key = EAEAEAEAEAEAEAEAEAEAEAEAEAEAEAEA + IV = 0000000000000000 + stream[0..63] = 19BAF0AB98DC18BFC7F18C4EA0895AE9 + 2B5CE05E692208F0540EA02AD6683539 + 00F2C6456E001C19B274C3D120B2E000 + 58A941390A93703CBFBFFDBAE6D6999B + stream[192..255] = 4F9E5B8605A975BC66575441377901F7 + DAD3A34F2EFBBF8F4F396B1357E51B51 + 3095B8874136E59B0BFC12B65846F379 + A73BEDE415D9E3CF0AE3F9C2188AED09 + stream[256..319] = DEF4E5823763FB50F9421F6415E64D19 + DD6A2857CBF578339E0CDD96A53ECFA8 + 14B0ED3F25E35999EB1B29D16BEC526F + BDCE8C7A4BA6FC5C8375673CA2E1C1B1 + stream[448..511] = F3183BF8876E91A1DC4FECFA22538777 + AB9DDDD736C9F3BCF75D583A8AB61D25 + 35E16969BD6A492A648BEA0D9A7C7424 + 12DCB9DCC6F41630634CBAD201AD1A87 + xor-digest = 1F31814EAD7F918E293366CAA6AB5A2F + 2B39C6AE5FB851B092DAFDE3607C0795 + 9F1F027689D64DCD341B34949E4DC3CF + CAA73F1F73F478B0762801321843E5DA + +Set 2, vector#243: + key = F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3 + IV = 0000000000000000 + stream[0..63] = 23B2D353FE88CED2F55235FF0C4F7057 + 9D0BC72FD108C1D87B95B879261248D2 + E6D6B536E9C5B096D7B6DD101AB1B99E + 8FE6ADC9DFFB0C183DDC23C26EDC6709 + stream[192..255] = E552DE13929EFA66F421A8DA140E418D + 1011B9A44A46D4F9A5DD24E5D68F7D38 + E4D043DF4E46D2C6D4A4E5CB8AC02708 + 3317C50A1755D50E4C74D69CA9C6FEEB + stream[256..319] = 29EEE8B0E77DD5D445805CA0A7A4D21F + 4BC45E4BD10099ABDB9A0605CC51E64B + 9FDF7EA5ABB394247729585EE934DF7F + DC3D0AC0D0D500F655083628FA7F7657 + stream[448..511] = 3020F4ECA0972842E3A14B0729BCB401 + B4AE6F110D596361A5FE7153DF1CF2D5 + 3544552FAD0B8FAD79CA28136AB58873 + D7C359CD5DF5836355C9C208F5E4779A + xor-digest = 5B55C2C11190D429E7A6DB6A498A66CC + 8759825A363E33E4AB8575D313667CA4 + 84793E2D9791A51CAEF569C27251435B + 8C4E0BE710EC1597EE6BD420AFDB8F02 + +Set 2, vector#252: + key = FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFC + IV = 0000000000000000 + stream[0..63] = C739A8B50201D54EB5DAAC71D922A67F + DBEB286F909E2DB02CFF896B2253DD83 + D17A171CE063F3DB1FE898AFC8F4887B + 4776A9D645B1625B10C4C61DAA46BECD + stream[192..255] = 35A7790648C6BC56627893C32155CBDB + 879CBF8414FC294C6F69586CE081FBC8 + BFB7C23E165F28F571ADECA3C8703B5F + B2194C798E2C3CD35F9714C08772EC18 + stream[256..319] = C61B1C1FDC54873AD65FE0E452853172 + 44D446147338C6B11DB6CCC15F5C94E3 + 078C3315AD2EBDB435B7CCD322533274 + BB7B09C79473A0E2150DFA99814E07B8 + stream[448..511] = 72D3A4EAE1E7C83A78E4AC79AFE2B88A + E33ADAFCB177938429026E291C187FF0 + 0AC89BE3CA542124289FC607FED0408B + F379359A67BEBD85D9584D3A68A2C443 + xor-digest = B5C9850723BBE418AC19BC47159643ED + B1D72EF577432499F2D42A989FEEADD7 + F9955A14600D5B6D62E0DE239C265884 + 6879323E63E6DE12F2FC7B200AF789DB + +Test vectors -- set 3 +===================== + +Set 3, vector# 0: + key = 000102030405060708090A0B0C0D0E0F + IV = 0000000000000000 + stream[0..63] = A8F7E69B6940A78D136A5C154A157952 + A6E4235859E30220EA686436BB38EF53 + 9C2940556B09ECD7FEA2B0AC8307F169 + 6265A3D644281C39C9CD5E1E2F9BE4D0 + stream[192..255] = B3378F62D121027463200A43E2DDA9CF + 91F02D4810282CB9990E28D857EAC359 + D83BF4C5BFEA00EC6815E0B208B9D1F2 + E0BF3649EC4B9A25E76498F857420788 + stream[256..319] = 422F2A8ECBBDA3496414C8D1A0B72350 + AEFAC933F5D4880E2680FB0B9DBB3195 + 64E56EC9222C50F7E2608325D068F178 + 22F8A7438AF00C282C9AA0486342EF2D + stream[448..511] = F9AF33AAF2F0293C0739E052C5BF732F + B721B00CF97D0E71B755686DDD739B70 + C99E194E2181C1AD8D36D0F1B130CF79 + EA4E32F9D2BE3479758CFCCC98155A1D + xor-digest = 5C9460F674596ED739332147ACB6B2DA + 662C1A4A9C0A470E3686951E690CFB99 + 3E31BDA80E006EDC8877B3AE044759AD + AA153D767715B44E90CAFF983C93F73F + +Set 3, vector# 9: + key = 090A0B0C0D0E0F101112131415161718 + IV = 0000000000000000 + stream[0..63] = 9C75803C70528B539235C01796AA016C + 7A5ED9AF5B54F3B9232C43727318801A + A11E406463C68D6E5A3252D2BE4F387D + B8D09713EF02EB6DAB6E3A3FC2DAE936 + stream[192..255] = 41D7BD566BCC2FE295CDFC4C98C9107D + 88DB492FC1F7DDFC9421A62705EDC9E8 + 5E25AA954BD0B85AACC83957E624B1C1 + 10005D5E6DDC353DF0BD5E26D9B79E9E + stream[256..319] = B0A9151C1DBF6EDD60E4994D87FA1BB6 + 8DB1733CADD3455C1DC56981755DAC9E + 0C16A17DAE062A382881FBD5DC4B7B43 + 543039EC1A0445C07981208FD73410BF + stream[448..511] = 4887700FF78520D280E81CC71B51EC09 + E58A1FD72500538DC2A04A946C1F6525 + F9711922248FF47D06C824E40B5512C0 + 46F028F3E5CEC7252FA4BD95E890505E + xor-digest = DBB8BC98482B5C3996F0A4AAA54AB27A + 32A6E1807A8DC772BB9CCE2F8DF2B4A9 + D6F5FA93DF893ADECB74721F269F20EE + C27AB5353597E3C525A6F3C1687EB347 + +Set 3, vector# 18: + key = 12131415161718191A1B1C1D1E1F2021 + IV = 0000000000000000 + stream[0..63] = CEB8BE2CA5CEBBB8259C6ECA73FBC5F3 + D1E527A864E03CBF077FAEF9160F7393 + 7B75A6E13B056AA47AB962F6E97961D1 + B529A7FF1B580F393A1097328C1F7D0F + stream[192..255] = 5E27DB13939D6923B9B516E183D75552 + 7C19F16689D1EA89AA1E50857A9F3F0B + C90696747F21D9FC69511611836B34BA + FA6CF379D8553EE4A3010AD275B13B42 + stream[256..319] = FEBDFF94C13CCAEC8DDA7CE54DCBB5B5 + 74D33BDD8380834AB018717B6F97FA97 + D3C33727D22E53EB2C249D129169441A + FD94F6FC96B8339F2842501074808825 + stream[448..511] = 19054D7AA84BC7E662383E1215CC137E + 9F8001CCD02D895641029519DE50956B + 38264F96B531FBEB509FDBE9759CF61B + B98F599AE146B41EF6563B5D864C2B6A + xor-digest = 4520A8F72839DA7EB3EE38BF9DB60DC7 + 3ECC852DCE725F83319744A9C75BB84E + 4EF1B0D318B34D08CCE1369CACB5A0E8 + 790005C0D431D2CFD380D872FDC1146E + +Set 3, vector# 27: + key = 1B1C1D1E1F202122232425262728292A + IV = 0000000000000000 + stream[0..63] = 8AA4421F2858E1BC0125939C4F6F0E7B + 5418CF975674E57F17A4CFDA935F04F2 + 958847A37DCF577A1D35320EB01797CF + AC41EAECF1D1B19A01AD353B9B7FA387 + stream[192..255] = 24633DDE77AFC07D48A8DFADC8E25C2B + 2F3AE3297EEB3ACE8562F2406F2A1FEE + 9E9E19AC6A8D2904745C35C48FD0E4F7 + B4C7C261DAC8F536341A352C92DFE86F + stream[256..319] = D97482F65AAE9678EB9883524491FD40 + B57C31D5AAF0DB436252B3D6AABA12D1 + 80BECB346C8A4AC3710C182A084B322A + 937C68FF4C05197EDC6720128374046F + stream[448..511] = 8F604597C790334398A2F4A818D12FC3 + 63BE3E8CE33662A259F109951DE5CD60 + E2C86869C2D54E49B892125D49F1ADAF + 63ACBADDAC218AB227637675A11DE12E + xor-digest = C8BA461613A40511C3C8E324BBB93BBA + 85FDC45ACD88952EDD22E0CB30CA0C18 + 59416169DCF3679D5A094B01B4584585 + 03044E59FD3A430FD5E61AFCF40F830F + +Set 3, vector# 36: + key = 2425262728292A2B2C2D2E2F30313233 + IV = 0000000000000000 + stream[0..63] = 3FD49CEC6AD6D112A23AFBC78959FC84 + 35FA11A8279D4A9F1C385CDFD9E081F1 + 788C19D0B797C448A61E593703006882 + 3D23FA98350955A8DE1A20D2433919E4 + stream[192..255] = BDD2DF9AB00F131E6A3FA9D0F1E8E42B + 3701FBADA64D18371953486E0913525A + 8DD760FF62931B4921DD43D0536EB935 + 3200A55F58DB7BA9E428485F98D57B1C + stream[256..319] = 3240488DE5123777C17AA3858D0F45CC + D6272BF7FFC1F30010243BEEE9CEB429 + 86D22FFDC576E68DBB9E11A114720855 + B32631A84467F8F25ADC795987C8F396 + stream[448..511] = DF0B64330DCB54BF390DEB8F5B593395 + 643A2468F0DE4268148D17B94A72E039 + D7A4CA53CE5D65A5E559B5E053B609CD + 77DEC40BF2BACAF6E7E9C4B68345FBB8 + xor-digest = 5BBE5B0A961F3F7372144943273DB23C + 42D40D3DC34F6532700FFE767982F63A + C5A9AD0687EF49C9A309E1E2700FCECE + F8FA3080D15F61FE45E0E2C140D3883B + +Set 3, vector# 45: + key = 2D2E2F303132333435363738393A3B3C + IV = 0000000000000000 + stream[0..63] = 3F1DE6C663092E7C2BBD00E2FE8041A6 + D3FC3BAF6C46B783B29855BB8C58EED5 + 4E83B368329B5C1C995217770787965A + C7EF9C416197F5FD238C24BBC7B1C8BC + stream[192..255] = 27D566FFB20758DF87E6B981125572AD + D6663D95E7DF277716EC2B92166D7E4D + B30E396ECA96A0E8F020EF3185B313F8 + 1D5449B10E5CD308FCEA9860C03F7499 + stream[256..319] = C0C84E0CAE2AEDE28A5C61C21103AB2E + F338A6B1E6DABAD989F09F80242FA5A8 + 7CD49D7097BA8077FB1B5A86459663C9 + 14D6060B0701D6CBC5CA36E2D4F16391 + stream[448..511] = D2782ACBF9BF5B9A7D5F954B7E237F0C + D6D7D71BBA72D996C5FD8DE7C6534CDE + BBF63382F812B62A007C56CC0BDB705B + 540D7D7D4C3DEA49BE0B47AA17E540F1 + xor-digest = 6178A04F576C327AD94B29644222B566 + 8A973BE850685D8D3D81FA5B81594D71 + BE558CC2EF588ED0CDC515A1EE602A33 + AF27F1D64E17504971D1EE4F7D16E483 + +Set 3, vector# 54: + key = 363738393A3B3C3D3E3F404142434445 + IV = 0000000000000000 + stream[0..63] = 598EF6260979853F06470BD98FBE6C5E + 4399C6240743789F096DD2B4024116DF + 328AB398AF4C2B8D49A2484526240489 + 918A7FEB2F1E60473BDDE6F6460E05A7 + stream[192..255] = 01EEFD56FF31574CD05FFC35BA0654E2 + D621A8B937EF5738384779C5BE3AF999 + 6551ED266A2224CF40DE82A669CAF835 + 435BD74080AB3B480B91822DCB6181F8 + stream[256..319] = 568025C9091317B00E7EEAAB3AF91373 + E6239CB5C65BD626AA8A0E195EA59FEA + B24B9733EE8E58370C481196DF56DF8A + 2C8739CEEAAD38061AE32E961C4A86D2 + stream[448..511] = F5BE34F3B5790E0B28A80F9B94407866 + 092A4F3EF2A650882DF027F744A64789 + 94EB41ECC5EB79ECE17B87450F0BD48D + 8A9866F373EBBDFE78A56E1B02C86A90 + xor-digest = 13F75D32B948D7D0FA260DAD241FF615 + 8FEA17E68F8C40DB209D959F84907F05 + 4EBAFAA2F846C3805A672ABB8F574F29 + BB5F6CEAFFF71EC61C838CC4B3D577D9 + +Set 3, vector# 63: + key = 3F404142434445464748494A4B4C4D4E + IV = 0000000000000000 + stream[0..63] = ED55F27D6789B97BDCAD0F0C86C9423F + 84A6F4EBF5891173F958E77D7E0C7488 + 28D03F55223F0116F5F36C8849E408A3 + FE4D6976284D1EE93D20E4E7235BF874 + stream[192..255] = 82975D508A7AAE7A057C9E7C9044E54B + 0C40CDEF737E393A1608E9753D6DD6A9 + B93E91585D2F6D427281D3B082442997 + 5159562C1039E29558A9A8C308597C4A + stream[256..319] = A506106FDC1A32959123E20AE275CF0F + 2E8E1794794EAFF1BB8FE59CDAB5D7D4 + 7065032F250F41D1B8DA9C6AA691429B + 961EC13DBC9247D5C883BF747E3D35A6 + stream[448..511] = 5EF107C90BD579ACCDABC4FDE47C3C78 + 02D89CE984262E86227FB066425733A4 + 26771FCB37A12B2621D1AFEAC10D383C + D996A5E0616335D5F512ED9693D4962C + xor-digest = A2C4BF12F052978B03D59E2DDF54EA7D + 254FC13F7D2AF32E23F8148BC46D4878 + 127BC53590282F3C4848C9499F567375 + B30F3C22DB38941DD1199DA8B977FBB5 + +Set 3, vector# 72: + key = 48494A4B4C4D4E4F5051525354555657 + IV = 0000000000000000 + stream[0..63] = BBE36FAC29E8097873AAD0BD26C41B38 + 4AF8FEF4153744E79732CA8F7CC0130B + 470A6B1D32EB62BAC555DA88A69A7091 + 069E56A26E44447411666ACF2000DD62 + stream[192..255] = 844BEB56299A05C635682966DC15F6C0 + 8A28147C36272AA1FA136F7ECAFD7C62 + 1B23B9DBBE3C25F9F6F6B7C7C9931C56 + AC47A2CF61F504E55A5BDB6BB26E3FB5 + stream[256..319] = 6371F94DB065B3E125BD0BE899C83A1D + 01DCD89AE781E9A90E12FF48E4B6046C + AEC9DCE7DFEB3036D97E5D1AB0215BF1 + 081084EB16EE562DC9E613F3A615A9AC + stream[448..511] = 43994C6E8701610AEAE9190F3116690B + BE0950B706DA3CE1D86A6AEF4D4FB781 + 70BD84674CBF3EB6CCB0C588D53B2DD4 + A3923A6F6968C06541C422248B66D115 + xor-digest = A8B60A61C42E5ABCF9B0040BB380CE6B + 9D54F41EEAB4E0822B4A1BD9733D96DA + 7A16CBBF104C8B0CDED360099A0582F7 + 1E957ECFAB3D46591A6461E688067D46 + +Set 3, vector# 81: + key = 5152535455565758595A5B5C5D5E5F60 + IV = 0000000000000000 + stream[0..63] = 17B496C4F998676C6D57D00B973B392E + F055805142AA6B5D94F23CAD740A2290 + 11F0770C57590D1B301ADF2E6FE3B3F5 + 30F355C527330373CF8A3AAFCBE0BE2B + stream[192..255] = 6F44FD362D8A3B559E2D267AB821D91F + A43B67F59DDD7EFC8E90B8BAB6A8AFA9 + CC5120761FE0F9E047C4978E761E5146 + CA01E2431E1A44809D6E0786D5729B36 + stream[256..319] = 8EDCE30988CC80F96FF9649069688C53 + C8E6FCF57F00BB4B00E47E143B4DBFDB + C48AB43A8972EFE9FAC3E9C10858AEDF + ECA5AE463845A3C5434CE92DD03B8FCC + stream[448..511] = B8C415B59D0A661525D1A01D6B8F2BC3 + F2C9087CE11C0B49EC84205D15054495 + 550913ADA21A64684FB2257CC3612967 + 795E8560FC7D64D84A20065173788F36 + xor-digest = 66E287C220F5E9CC0973891E49A55D24 + 6A9EB718894022BD5155DF2E5A4EED4F + FA0B7DA22DF5749D5D4541B221022B31 + E3A291C8A00CEC86FCD42B888E5F626F + +Set 3, vector# 90: + key = 5A5B5C5D5E5F60616263646566676869 + IV = 0000000000000000 + stream[0..63] = F901D64CFCB8FA39F8FB8310C169063D + 9986203380EF433C3B01B72422E1DC45 + C40575CCAB09A87EC4B070A1F6DD25C4 + 3463DC8074E8E985522BE574C5DE6155 + stream[192..255] = A045600187B251BF1A4370FB00B692DF + EBBFE447A2C58EFF954941EF22DBBA29 + 4759533997C73170D8944B68BDB9223E + 20F3EDE5D9DCEF7BD3DD27CBD2457B0B + stream[256..319] = 570A1D6A383DECAD2A1AAF2F838BC7D0 + 7F2D6E7DF74D4CB36FB60C9B4BCFE562 + 96538DE0A8DE1116D5C1868BFF8C789B + 8A895429BE96101F060233F9D7A1ADCA + stream[448..511] = 52D62CC7050822CDCF515F4D8ECA66FE + BBA746A767AAA6CE4EE90ABB0836176D + B5AE9A3BECF2B8A9D405B9505A194104 + AA37349D18E2E98BD2FA21519E005494 + xor-digest = 57920FABFB00D455D515E6E95AEF8240 + 89194649C16508A6DEE47597F564D148 + A5D921791F777C175FC027C3FBA680CC + A928E2E1ACB6385EA3EE0D518170B026 + +Set 3, vector# 99: + key = 636465666768696A6B6C6D6E6F707172 + IV = 0000000000000000 + stream[0..63] = 4BDC73208B12082D1CD306ADA9E7C893 + DFF7B299BDCD08755FF58B8C99B6CFDC + 3F3D3F42F7FA1B68D925B1D6C40E8113 + 69308768D435A3EA6BC8EE6B04E244F3 + stream[192..255] = DDCC077A122916E50EFEE81E9E53AE83 + 746A9B855CCC1CFCEAFC7117D6846376 + E072ABB32C54151D8DE3354F45A0A777 + C606049F7E815D5EFE066BC2B9B5037C + stream[256..319] = A148C1449969EDC4CF0691CC486FB9BD + 657A7B00CC47D520EBE63BE0BE9EE00B + 0D33F478649CF1C69A3E37104059CC13 + BEE66E820B1F583F483BD9F69B6A0D89 + stream[448..511] = 6A6293FC21975C345F2B7D82F8EE1846 + 589AA1062046F7B794431571B9653A29 + 594054832E0AA3B9F6FA12AAC43B8845 + F5C393547EC6C2A3976613F583C3CA43 + xor-digest = 6E3B68281D2E5E408B22C7C03EFC0874 + B105E1C59DE05394B9DF75CD16154D43 + A32A02C0C52CAF74082948DF2C3F004C + 3A42A2E89BBD5D4CC29F8BE0FD0AE13C + +Set 3, vector#108: + key = 6C6D6E6F707172737475767778797A7B + IV = 0000000000000000 + stream[0..63] = AB3E96DE9D091FF94F6E41681441A788 + BFF6EEE5562505C56CC69773EC1D9B36 + 142C811EFD0AFFFF1D6FE198825DB029 + 5E2282B1836D3CB6FC3EE32A0B27E331 + stream[192..255] = 105A113A6FEDAE8A270CD144A9523848 + F5E3B1C6D0E486B331DCC230DC06D2C1 + 51512D6CEE10558C771EFF5FB9EEB3BB + F756019882B48587E027561476DAF949 + stream[256..319] = 1DFD142EA63D1752D6DABDAFCF01A141 + 76A29186AE16100D85D0FDB484A36912 + 4B70D7AEA207E95662DB08298A945B95 + C8B793C8B8CA0B9AD59F9DB593E3F825 + stream[448..511] = CB52F4D67C19887BA565EA4DE18EA6C5 + 9367553F05C364B974BD337302655A87 + 3B44FE6DB5473D0FCB34A72B15206D4E + 32546236A4D568DD69AFF50D38E57BFA + xor-digest = 4C352758A2086EB13BB10B1131FA15B3 + F889AF58C3DD4F9CF94D9847EEC1A814 + AD4D159DAC1EF7DD4F7E8AD58F40024D + A97BCA9A56F7939EE0B1F12B36205EBC + +Set 3, vector#117: + key = 75767778797A7B7C7D7E7F8081828384 + IV = 0000000000000000 + stream[0..63] = 76BB00C566E1AB42102D9DECE873C28F + D4938D8AA8D3FC052225D33D156A9A4D + 10A81FE9581B0FE0769452CDA51EFECC + 5E2D72D149E6EA4F2766F4B20FB2FD38 + stream[192..255] = 59B419C334C5221D065DB8B598F8C071 + 3F5B6D8A3D1190A1066E9CACC18DDF36 + E3CA201C72517BD170C900D5572AAA3F + 51836704EEFF50FA1B8B2EA695A50263 + stream[256..319] = 4DA1F66FC5BDAAD59E183F6E2A61A56E + 4FB5E5F8CE7D4726E39121B0F6C5DBB9 + 8FF719A52CC56870A83888C1A798AE56 + 4E8A440C59445BD33E9C6E59F51919D7 + stream[448..511] = 268824C6E8F0E50D2A1D1E92FB87F51C + 3DDC0448C13887C1F66594808B49B971 + 713E8D48B5F9077DA4267330CB4945FD + 6F4DF4F1F2EE13BA54A398C1C910B350 + xor-digest = E71462ACA328FC592014D68A489F2453 + 85E57C42C4FE16F6B213FA27B2E19C32 + 2C3053992B51316F1A6E6B12DD3C841E + BEFB0DFA389D60FE4F562400E23BF93C + +Set 3, vector#126: + key = 7E7F808182838485868788898A8B8C8D + IV = 0000000000000000 + stream[0..63] = E3A9CC680C0773F34D33696AD7BCB5E5 + BA1D70D66C78DC99DFA778B1F5A8F98B + 2D1E13A7761A6505010896618166011D + 4F3D873422B63FBE6731488C95E24E0E + stream[192..255] = 21C4CA8606898C138AF1DC62D2E96D35 + 04B7FC5EF7D8FE39081A6B83CA0B5738 + 37F028346492B429E0C9426962A2373E + 25BABB2D9A82D983092DE4ACE437627D + stream[256..319] = A7A1CE3AF5B675147B985A0B884A8C56 + 8AB6CFDF8C2CA6E1414A98DE90107270 + 38FBD1C77C904CE2025CBC708D510F78 + 001E9B387427A9210190CFA1EAF76B6E + stream[448..511] = 3D3C6A3915A16E9E8A6690D4AC61DB15 + 098B4BBCD39227ACC88E6C0B2A2A15AC + 3FF032435BAD05C525813B4940EB15EB + 21B38E6E931E7A55220F6B561C9E60F3 + xor-digest = F2C9E1E9963C2105CF32EF030552A4E5 + 550660D81620439C78F6C878E7D3AA04 + 34C933F1661B7EBA4B4C03738B0FAFAE + DFB0F6F7F472C29B9D63AA910F1385FC + +Set 3, vector#135: + key = 8788898A8B8C8D8E8F90919293949596 + IV = 0000000000000000 + stream[0..63] = F8E0E1A0BE45C2F3019BDDA7123F7CDE + ACF74FEBFBDE272B532D55F26AD1564E + 1314D5267A69BCACAB2CFDC7217662AE + EAF848FCC9C3CC7067BB93F3FBCF4D7E + stream[192..255] = EAED3FB03B7C496648B6BA14B6D1DF51 + FD88F7FF9D8EB55C0491EA603ACAA8DF + AED64FB48345472067914606DEB344FE + 21FE34182E99883CCC0CAF6C47D00B88 + stream[256..319] = A72D36A455DBE937118E13FAB653D8D3 + C29EF2E81B635C59D605F2E438269875 + F8D1545E44FF0D8918BD9F8F7EDF1A2E + B4F8150E0F9F465AE465E0D0BB319795 + stream[448..511] = 8E17D0390EB35B039A0EC1A3CF09B942 + BB637C6DD6551DFB3C2AE2A69A91FFD1 + A9D7385B1B23CF56AD63A31505781F25 + 42A43F8B3A5EC7CEF39C3C1FD5127454 + xor-digest = 39C51BFC1980990BBBF136199F509D3B + 9FBC7B41D4861AFDE9C04482E504ABAC + 4460791C91C6D32FA17A1310E3A674B4 + 566A598B6954B2970F2A82790EB7DE3A + +Set 3, vector#144: + key = 909192939495969798999A9B9C9D9E9F + IV = 0000000000000000 + stream[0..63] = DB5DB3C8AD550940017570BABC37DC40 + 5B39E1EAB64FA9A281BB545548909A26 + 0DB3CE59E35E48C6D8511C5239317152 + CEB3AEDA8675B470B221AC0439A2BFCC + stream[192..255] = 2FFC234C2391A5A44BD98FC5B89F51B5 + 05FCB12D9E65E889DA8A514031878E7F + BF87A5720A5B6FE9E6139AEF3A3CCAD8 + A1CE1DFD6592CB2CEA04618C15FAF7DB + stream[256..319] = 1D716F258E16F5ED837958F506B00B6E + B784CF3BA415EB2CD301021493A3B654 + D644A9A52BD3560B91F5224EDE24C72A + 4508CB78DFBCCE6034AE0AF26DC5F9DF + stream[448..511] = 2EB24B1048E053781B564255FEF304A6 + EAA79ED748AF357BC1FF061FB308C820 + 65083C216A31D23DC3018B03F356CF33 + 67653DCAF14194F0725012EDD674A740 + xor-digest = D76C3B99D66D3C58A1D6338658AF76BE + 4BE6099C40F0461298CF7F008BA91979 + 45A370F3794F822FC0D2637F01C3CAED + 9616CF5069D6FB261D89EB2523338CEF + +Set 3, vector#153: + key = 999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8 + IV = 0000000000000000 + stream[0..63] = C08ED7A73C376240AA50C4941C23C76E + 314B4A5BD1947AED90D9F8F95E63FDD6 + 1FC8EB7E674BF49AB44D411C5C2640DC + BDB7F7A136C49AA5897C058D3421CD57 + stream[192..255] = 9CFE56D456837A4B0CDE3F46A424F2A7 + 5FF901ADED22AF434F14AE66EA8C3446 + 61D2EEE405A37E821FC78A19F09CBB63 + 5E3CCB143D20963A3A29BEB258FFD5BD + stream[256..319] = 084AB28D158B038CE8C10D185580A2EF + 37DC167EE908BD14A041526CA91BC3ED + 95BEED5406F51E541026324FA7E395A3 + 79484319783738B3C6688107141C140F + stream[448..511] = 4CEC62A9A8547134642F790E9819C533 + 4B27054A3FA222A1C8513B9C32E8028B + A0DE4A3FF59BC76EB8730252D49E7195 + 4892F39C21A3DE11376956462C39A60A + xor-digest = 285487F7108B86E18F9EA613E65C8F5E + 46A74C5F9C6EB9E9E870B0C18F130DA4 + 1DB858320F3B1C13C047F5FD47DE5343 + 804330B03CA3AA9925C3143A184C135D + +Set 3, vector#162: + key = A2A3A4A5A6A7A8A9AAABACADAEAFB0B1 + IV = 0000000000000000 + stream[0..63] = 2DBC230A1D4077730133CB681C63803C + FE655F1F83628A49A0E74BCACC9185C9 + 32C61657E653D98D88EA9EA7D97BDDAE + D2627AAE38494630178A72ABDE934395 + stream[192..255] = 2C193A98DCA4BE342DF061456538095C + E96612F6E319A2884694A9E436A69DF8 + 35DC45A6BD750099DF49C4F5B11B8C5D + 0BF9939CBE55A39C7B1A1F7F5C55AC71 + stream[256..319] = F98313F042A755DDA8A1BD1BD6E1C6DF + E9F63282598225C7C2FB43438278B0C8 + F37985D8F99BF0E88D9C4AC2A00F9FB3 + FE2C7585574A4846D6B0F107198D9842 + stream[448..511] = 779D4449233A4790DC0FB467D720041D + C55097068381D5C06847A45973DFCDA3 + CB9570A83B7DB21AC572E5EBD33ED557 + 2DB842E7331DE32B3848149279B5E358 + xor-digest = 12A33437E6CA1F733B009817B0602B5F + 9F2785DAD2176B256BBE16F8477C425B + 1A2D29173ED791F0F9C5E8BE4D5CCF96 + 6CD8090EE59FF9880D836EBFEB62F9E2 + +Set 3, vector#171: + key = ABACADAEAFB0B1B2B3B4B5B6B7B8B9BA + IV = 0000000000000000 + stream[0..63] = 2AD70E5D6074FF8692077E8EA3A7065C + 6542A2C44DD873C2B37DF8A12FA41C7F + B460A5FD7904613CE9E013BD1B93F7C9 + 23FBDA997C538423F20C026173A6B14C + stream[192..255] = D13EC8E72786E941F00778FDACFA5725 + A492BA589423B67048912D154C21EABE + 0B44AE534B5EF031C37F1FE868D1DFE7 + 42DC82A7595F0BC8C87EBD3D8952A307 + stream[256..319] = E76DD6290D8A97E4D52FF3CFE619F2CA + 80F9FE773E9C05D214C7ED782BEAC1CA + 0375C8D0C27BEB8734682AA24B1F7895 + 0D8B27728F277E0D5F647769794C596A + stream[448..511] = 7ACA69E52A3A394093750862B4681B14 + 2F64810C39808C3796615D5D26166920 + 2F9B14336CCEFEECD0F556EB57747A66 + AFA55E3C0F65BC2D668A354A9179537E + xor-digest = 6F624E09773A90A696623CFEB4641365 + 3C80738E53FE029499F0CAC108DE703D + B72A543BB726BEC219F866338BE81A32 + E359A076D2D7ECA632D68CCCEACC9958 + +Set 3, vector#180: + key = B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3 + IV = 0000000000000000 + stream[0..63] = 3796064A20EE2432983FFEAEF238BDFA + EBE4EEC8BDD2243A12B226A4E4AB73D1 + 8A1A3B85A9A6E8C1B73D7A35E634AFF3 + 53C500FFA905BD00A57E2884D278CE48 + stream[192..255] = 668C680E63C447175F14D290474D5556 + 07877E0962775596A6F865737CCCA16C + CD5879978EFF9D6CA02F6F4406B8B801 + 5BDBDF02B188F6AC3ED46AE30D403810 + stream[256..319] = 806BB3ADD4D4AD22E1BF3BF3AEB98E85 + CC54E714B20281FAF72655963C76031B + 38F0FA6132AC9ADE3F712FEC747BF114 + 9C30C023F63E17336AB508188165DBA6 + stream[448..511] = FE2DB543BC4F4A89510FC9442B83F304 + 6A77EC2086861CA7959DF633513ABDCA + BC23AB39FBB97078202B73787404FF4C + 8F38FEC8BCE76D29A9D675F6E85FB5F5 + xor-digest = 3C6894118B379B4F625357C4FA56C8E3 + D747CFB06CECDFF2E98E52D3FE5C2C5E + A3216EAF35F6D86734162056A2CF9232 + C99E571FB7C1CAAE835FD5941DD2315D + +Set 3, vector#189: + key = BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCC + IV = 0000000000000000 + stream[0..63] = 450EF26E87C27359A71BE95BE322B656 + 6609B25A34090E97462D93369850AB4A + D61C7F9F67F9B12847899C40F0EAFA22 + 8B7A6BC7F1BC4CBA7A85F5266177B0A0 + stream[192..255] = B28AB576E12232FB85B3B854A3991526 + 8D1AED4D5A96F7E71F9E4F55AAC75993 + A9D2780C5EFA4191F506D9FFE1153B90 + 4C15394CF60269D715697D7B2163F32F + stream[256..319] = 4F1671090637F6E96159EB93B26B779C + 1C31EDF7E13B1BF23E3A67953FCD5A45 + 07DAAA1D0EB1E352C621F5C4C3CAC2E0 + 25C7631345E7C46D2BA641B915705BF7 + stream[448..511] = 78C100DE69AE45C1B10EEF08B91CC675 + 29356C7D44DF8FF8EEB2646B528F5F8F + AFCD97E36005D72185D90B52A09F38A7 + 80332270DCC28AFC85FB68390315BB20 + xor-digest = E58B774698C56AE46F5A3393EBFE1F49 + 2948859745368817D41C99EFC019F2A0 + 55EBA9182818888103681DEA9D5B07AE + E7A758D602437217B6E782419B651CE9 + +Set 3, vector#198: + key = C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5 + IV = 0000000000000000 + stream[0..63] = 96E4CF1A2758D880AADBB05273DF3E03 + 69BB35AC9B71160C0E893355DBE033FA + DAE988C496D15BE772BC5E6A46283DBC + 8A0BC506DB145FD2BF309992B37F0963 + stream[192..255] = 173473B2C415BDD25932D8A969077ACD + 6BFB6D34F92611B3264A268E5F2D2E52 + 9B9979DB645E2530B318E85D6018D82C + AA6A85F7DAF9AC9731769021708C5431 + stream[256..319] = B79574437BDAC05826104F473DBEE18A + 2B4919577599E3360189C7DF666B56B9 + C814834E8644C98C42BB05D4E54692F8 + 8FB69AA708C4051E5E0DDF4E39887BED + stream[448..511] = DB9661BDC10059CDDB501C1AB1AE9E8C + CB8E192EBABBDEE6B0CF1DD7F7B02F7E + F3ADC85AFFC380D977CE9462A5951107 + D9C20AAA87D9FC790591994B96AA4761 + xor-digest = 682D31225C8415A2FEE30A2FA180B5D8 + 10B54936B2029086C72ABBE0544054E4 + 4AEA61FB87FE50C6B6DDC28AF0932EEC + 41A5A5988E5CBDC3B9F4DFBCDE63FF40 + +Set 3, vector#207: + key = CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE + IV = 0000000000000000 + stream[0..63] = 3B662BCC798F80C6426786FB81D2C2C9 + BCCBD772216A31A626C9F54E6577495E + 773989D830F03A230B9B2C37B6432C56 + 4550AFF6C63BB220BC4BFC4B07678580 + stream[192..255] = B63D8B4CE396950F7291360B6122FE5C + EBE69E43D3D0B4EF1F55664E9D6AFF3F + 35DEDFAB5971395403FC2A88A76FBA68 + 959F8DDE7B1D07D3D2F42FF6CA7AAF08 + stream[256..319] = A0FC0EB648C3236EF72D6C9CC38456C7 + 9FCD5E22415C7C1ED26CAB2E5E3DA6A0 + 9AA6616798B37147D3DDE6EB8AA63DDA + 31B5CDBCE315FA267B7DED7FF54CFB82 + stream[448..511] = 059FD351E88F27F793E3A1CD61B2FAE2 + 7D9AF1DAC4558BED9D1B59E339EBFF37 + 41E150E2C714E29B64075119B26793EE + BD4C854AFDE7BE17DDB3E47CB7FAC255 + xor-digest = 8A00652704B7A1D1E92D3C8D607ED02B + DD22C20142826474E40EC2E08C57DDF3 + 94D9BF77B46E74F74230C60720C5EF9D + 03264AE59599027DEE4CE5B8942971C4 + +Set 3, vector#216: + key = D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7 + IV = 0000000000000000 + stream[0..63] = B846B5C09ED72772529CE3FA897AD2A7 + 737C5B6CEE99896812A051E6EA98D584 + 54FE1BAA29AF50B50DA15B093EBC67A5 + 6DAF9F3AEB5E838177820E0056BC1909 + stream[192..255] = 0866854B2B80E405FC09F2E68C869B4B + 76043A96F4B31C3C7052A2F0C81B9DEE + 75DC8197AAAA396643A16E484E9422D6 + D4E8C3FDB9044F236B7968943994D134 + stream[256..319] = DDE30AD953EE55C9C69C794F9147D2B6 + 7C27029B6B35BB4678D383140C93D7C4 + EF1C42D66C8E1557FA9F7122423C525F + FDC06407EA90FE8DD2FB267B680BA44E + stream[448..511] = 64E714C1298785190F9C2871293D3BD9 + 84889FC5CDCE9C4E1110CDF5F0EBDDDC + 0233AA81715D55C2205CD105662E14BB + B02F937A159DE32F518D3A2A5E2B7B02 + xor-digest = 6410131CC0C81448A94959D7C42AE896 + A615AD69571488BE8310B88D90F9A221 + 1625D608D03625C8097FF29D5D16142D + E44094582DA29D09365A969C35BB1BB0 + +Set 3, vector#225: + key = E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0 + IV = 0000000000000000 + stream[0..63] = A3B43F8553B670D450AFEAE6A477AB98 + B5910C7E4FD443006A09FC88E0EF8A60 + DC951FD794F6F79A82E32D803D53D293 + 9BEE4AB66917D7D6F795EB22BB60876C + stream[192..255] = 6A1B01499E4FF44563879C3A1146CE6D + 7A1D3BEF1FE59C522A78FD8F3DE2A3D6 + 1B6D42F2FF3ABCFEEE24FAEFFB1DF01E + 8408FEE0701D1FEF5C13197194A71C6C + stream[256..319] = 5627CC31308C06067E54303BA576DAE8 + 0FEB49B0AA6DF21224F5B4FD4F0AAC03 + 363ED2188A3BBC18F4808362CFC18407 + F5A4B3E8AE93E271875ED208C77D96B8 + stream[448..511] = F45B25AAECD34C2BDE2B5735A945B10A + ACDD6BC4257FFF3BB3DCE5C0352655E0 + E855B71482A97887C74B6709F4DB006A + 6BB9F6B11E48E437063C48FA9EF6CC46 + xor-digest = 74A2A448F6FEF9F5A12BB04D6386845B + 8EF85072C29A36BD6FD84CD3E92D965E + 60600E999EF0668B2E62A0A59356AE76 + 4B5ABED9AA5BAE74BED25E56A804B687 + +Set 3, vector#234: + key = EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9 + IV = 0000000000000000 + stream[0..63] = 8381B53D5301DBE45CC692C81D125D17 + CE55CCD0C28B36B37EF77CD326CC3F22 + 9EF3C2509BD7B94F7D6A2B6CDB98A83C + 9D40B37869D27CE76A753BD80E5C2197 + stream[192..255] = BC1754703E057CBACC863E8DF3E013F4 + 6FA6798B281074ED5C7B09AD6B11BC02 + 5F509F6B398A57D9F96B1E422B4324FA + EB7C2B22C2F564862D3720973F5FEB85 + stream[256..319] = 816758D426295057847E101E0AB6EB91 + 5AFF310E44564EE0C56F064B5502EDA0 + AF568A0F07E040A54969DF2AF1D503A8 + F44FAD5FAB32585F8706CB46A9192BD4 + stream[448..511] = 72F6FBDBFAF78752767E853764FAE20D + 94ECF8F2D3AF283C6737D2411CFE1EDD + 362274C3281616E15D79549E5ED20F74 + 4DBD2BD2DC40D42AF7C87ED4E36ADB0A + xor-digest = B137019A384CB7689EB1AFA9EEEA9A8E + 597C15F897072EC491473ABFF86C5F70 + 8DB1519D72619A00CB3C1A1D0ED882A1 + 1A4EDFBB582998E8A036CC12F0A4DDCB + +Set 3, vector#243: + key = F3F4F5F6F7F8F9FAFBFCFDFEFF000102 + IV = 0000000000000000 + stream[0..63] = AC7A285AD6C329DAFC4C24B7082C56A1 + 1267101A40123E8BA3D26753FEC8E492 + D7C7FD6C6C7871AFCD2B90DEFB9ACA82 + 61A568F6566F14B98F5D7B57DBD02372 + stream[192..255] = 4E6B2E9F7CAB0E633D2988B48A5E4812 + B813629CFE4D31ED00FAD6EB2D999B06 + 810BE53BB739E8153BD8783F2500FDFC + 2E59959596276159F6D56ECAD1FC8B1B + stream[256..319] = 4269B2EEFE51858D2E16262FF9E44576 + CA0402E234B73EEE10A4388FA477996D + 0F0DEA985C2BDB06641A060228DDCAAD + 37E5BF555348A04F04A0408B15E6CCDC + stream[448..511] = 6B7FAE2235360C09C3A25901E773C13C + 559DCE935685A7695DD05466CEBF4B6E + 73AFC1705842C2212A382D8CC658A332 + FBFF451071B5A72930D92A1EB6199EC7 + xor-digest = 8A4E381256C845006DB04B853BD1A68F + DCEF054903875142BB34D09BB496E035 + 4A111C754A7DAAFEA22F173CEBDC2A46 + 950912739905FC8B8F5252F5734447E3 + +Set 3, vector#252: + key = FCFDFEFF000102030405060708090A0B + IV = 0000000000000000 + stream[0..63] = B4F871C18B4BBA8E427AB5C06985D403 + 27943574F02CA0A6BBBB27F8B72A6787 + BC8211C25FF3E180F0F1326E4D24BAA5 + 0B293633535FE6D3B1323C9188211AA2 + stream[192..255] = 4C69731BFDEF59A443688DFEBF345AF2 + 2A42CAF816824246254D1D2EC09461A5 + 77014047EB0A8A300DAE0E461CA5D536 + 1A29BA8C68A1F1BFD1ABA0FEA96BE7D9 + stream[256..319] = A86A988B6C0B65A354D43F4C342C0FF0 + 629FD4FF3C6CE05AB2B1386CFC094D0D + 16F5496D31F9DCA6F583708722FD2BAA + 248170602C87007EE428F574DA725CBB + stream[448..511] = 064CFE4EA4580AB39F27811DF269BDBF + 8AA58157C97CDF454D6B50430EA518F7 + 39F70449AE6AE35D8E50C818A2EB169E + 595B86587475EF7001945098E20B5A62 + xor-digest = 21E47DCE3950D31956CA26371008A79B + 2B79361C719DB799481294D6913006C8 + 3766DFFCF186B5A21B0C63A4D5303A89 + BE1118BD4096D5C388C88139109D9B7F + +Test vectors -- set 4 +===================== + +Set 4, vector# 0: + key = 0053A6F94C9FF24598EB3E91E4378ADD + IV = 0000000000000000 + stream[0..63] = B1D49BA344C9B6E8D439A2D0BBD004E7 + 03D49516938A231AC30F868C93233D38 + E679549FDFEFBE314D548B457946ECC5 + DFF062DA84EC561DF55F95AD1A13211C + stream[65472..65535] = B7FBF55E9E9430A0411BE9EEFFF15786 + 899FE9D89955B99396ABA845D9D19596 + 7CDA3F357216CA4E6BA9D8FDAAC41EEE + 37C48C144C143228ADA892E5649E560A + stream[65536..65599] = 811976603CBCE60AB97FD73179AB9184 + B3A2861B47AE4A6DADF3338F118920A6 + 60FB1944F04712802227C1BF7F270821 + DF4A85699D96C69CA8D13178F5EF5407 + stream[131008..131071] = 4AAB727DDFC1996787C40E969AFC6241 + CEB02F3D2DF9E72F17D4316CBAD15297 + 46E3D0A347776C6FB5523050742EC23F + 3D8EB54DA83D4721AC90B443E5B7897C + xor-digest = 575E0A4B0EE5BA64E0037B8D5B4CB1E5 + F8470765A9C43D94DE01DF68F2691376 + 1CA9768B3796E9691C73671CC35110F9 + 314CDB97773FF2C6FD81D28D030CBF83 + +Set 4, vector# 1: + key = 0558ABFE51A4F74A9DF04396E93C8FE2 + IV = 0000000000000000 + stream[0..63] = 4F02EFC370C559549DE321F2BFB5AEA6 + 5279F3855ED9E03972FC3EB954063644 + C4721C6F23CDF6DAA6CC18637E6AADB0 + 04136F6814B55FEDC3BFBE1E54CE1037 + stream[65472..65535] = A121054D6B04FC419494ED83C13ECF89 + D82E7D0372EB12E2A0BE31867E52E1D5 + C8C8E3762ABAC1546AB0E0AA023C4567 + 13515F4B743A55D00E2D09FBF816C2B1 + stream[65536..65599] = 749CCDDCB3869D30500ABDB940AA49AF + 240F1F563DCB72F27040AA81A8C0A916 + 59BB1DF537DE4E0B5CABFC606A07F926 + A78A17F6A1B60D38E707CD0D9642357F + stream[131008..131071] = D54A39330C57875A0241302C45BA9808 + 790228A0967534904FDC810504E8AAE9 + B5DE76BB50F0F53EA9488565E44B55E1 + 2F1E17CBA3F9E31B21B7C5DFC31FC0B5 + xor-digest = 56155DF6B0503D7108264B9A21C0891F + 3575D50A697C5C4DD708A733F2964446 + 18E618B627E7F34FB72CBE34BFABE5C2 + 09BDFD51AD2A8EF567BEEE56D10217E7 + +Set 4, vector# 2: + key = 0A5DB00356A9FC4FA2F5489BEE4194E7 + IV = 0000000000000000 + stream[0..63] = C31AE4DCE8209D9F78B080FDC84BA5DB + 36A71F2FEECB6E9FCBC1ACB8D295D85F + FE420068D7CCB265F5EB2F6D483ACDF5 + 1DBCCFCF113906CEF57495D437E4D62E + stream[65472..65535] = 2F7142D43A6496E6EAA53487788CEF37 + 975C73E679FE630295ABECE5A82F556D + 0A76F4676473A223A08A9EE3ED18AED6 + 27C61A48B5A7655D096B73BD4AFEB5B9 + stream[65536..65599] = 34EF0C90B6FB4580E7EDC0908CD41158 + 2D6C4101AD8D4C198693FF75F6008E71 + EC790DB82B8F1080E709770F072732C7 + A77758449A9F5B63095A5CAA86E70878 + stream[131008..131071] = CB3EFA61C5FDE9C369BD641F840983D8 + B366F631AABD1CEE7F03A5E6DAF93427 + D4ACBDEE6D005B962E325703BC3528E0 + 13FEC419EF2E4BD8B472429652F9B9EE + xor-digest = F6FF458A757C5886A04538A0F4F24022 + 20D27148FEBF791BC13D2DA63C443E72 + 68E5D547F176D945B1A12AD15BE11A04 + E819FD4D3C7E6B672EA6E3A95653A342 + +Set 4, vector# 3: + key = 0F62B5085BAE0154A7FA4DA0F34699EC + IV = 0000000000000000 + stream[0..63] = 9AF7391762B4D5793B26A1DAA5FC9DA8 + 387BBBD1301D3931F761CF2C34634AB3 + FEDDB3B4C8833077367095AC02D3D788 + 03650FAF6156D27B08A8888572BFBFBE + stream[65472..65535] = 359727441F419C0AF5E28CDCE21CBF03 + 7CFBC26D8756912EF895A601AD4FE124 + 4B044DE78C52AD0917EF641ECB82130C + 60B33DFF82A1FF4517561CCFAA42ECC3 + stream[65536..65599] = ACDB13B4B4EFFF36DE5F8BE675537D3F + 62DFBB2529511A6038E2540469FDEF7F + 5603FE388A094BA2C43592002EDAE9F4 + D4A9C73F0C229F19DCFCED6586D9CBBB + stream[131008..131071] = A6F0676C38330BC828E57E7193A05FA1 + 57836E04837DA478CEB8EDB8E0BD7F20 + A2B83BBED25799CFB3D748FF4F2E06C0 + 29FE28C1F41C93DC7816AA3D2FFE10BB + xor-digest = 997D53473AA526C2C455561DB22F4F62 + 33334FAAE8833FFE88F31A51357D1F60 + A8D0C53253F79FE499F2C5F5E5F69653 + A61520DE49381B5884595A3B3FFCE035 + +Test vectors -- set 5 +===================== + +Set 5, vector# 0: + key = 00000000000000000000000000000000 + IV = 8000000000000000 + stream[0..63] = 8C3E70D63D8541A33621912CC8385F9E + A74DFE692DBF17090767E5D7D8468D9A + A5E3FD7FE6164F731B49C92E42AAA448 + 4635D6480BA792AD013655F19C47C599 + stream[192..255] = A7CFF1A495CB9B1162767912050D4961 + 59EB515A34B1828E38B0540D3D4C3A5B + 7D0121F6C76C47FD3AF92788E694FC5E + FBB28E611DC1CD8EDAF4266E140B5147 + stream[256..319] = 806E59A52AE255D282623985344FE728 + EAF4E37DEB249603F419F31FE833ED6C + 04A9BA1D83FFE372975D132380D232F5 + 82AC8DF10C244FE2996A3F29304661E8 + stream[448..511] = 046433985C9FA18B949BCB73194176E2 + 6CBD4F854A9E1E9D81423C817220E771 + 690FCD44B3B849EEC317F4B924A8DAE0 + 13EA88D817E1170A0EDF4E650721CAD9 + xor-digest = 86FA5BDD94242A1DC63FD46744F7B74A + 48BAD4F2272EC61B0F046CDF65250538 + 4210E838D5E391F9BE4F80D68ABC379A + 3E20E90A01B5AC4004D5D518EB184A4D + +Set 5, vector# 9: + key = 00000000000000000000000000000000 + IV = 0040000000000000 + stream[0..63] = 691CB2E41CB212A1954126DAF622BFF7 + F1B10335B9775EE2D44DF8179C582583 + F0116EFE70537F4F336E7B13851BE7C7 + CADFE15702AEC662830C40EF3E5CDAB2 + stream[192..255] = 55AB6D8C6500E9743E481F589D5DE55E + 1E6C80BCB3B9A4F349EF55EF02B7A99F + 8F9EDAB2FCBC91D50D43E9A87A861846 + C44E00EEBBCF4D25449F27BE22A4A590 + stream[256..319] = 7B843EFA230A1B609B8AB310EBF53AED + 4E2DE7FDA117E3CFF2B7BCD37A7DDC0D + 2BBCDD806854AE330E09F5B55133BEAD + 73D7F6C41B3EE3EC221F12E3D2CED02E + stream[448..511] = D522C112371EDAB20456AEE8A5603920 + 5EC3451D013B50B33343A2950088EA4E + 66E282DA12455C5EF6F8BF0011A2B3DF + 06DF1B24A4979FF8966527D2F8EDF420 + xor-digest = 2943923E644706ED585C9C60A0BE5816 + 598CE026DEBC7835F02D28DF2D4C53E1 + C5DBDAB5A21182B4D5B4259A7C185593 + E0D91AD07C63F3E1E5B71EB4A6BA5091 + +Set 5, vector# 18: + key = 00000000000000000000000000000000 + IV = 0000200000000000 + stream[0..63] = A8346F600E8B4B335BDC2BF73BAFBE7C + FA9BAB3F4136DC162853184D14897412 + 88924BB8C1C3856EADA27C0A78A0CB5B + FB7D31F207378B7DD0781C51FB9AAFB9 + stream[192..255] = 3E80F6ECFF37DE8B053B0A0DF55FDDBC + 995F6C65BF11A035369F1B924884D9C8 + 357B4BE42C0329C3E30698B511FDD106 + 6073D332FC61FA1EEF4F6434833CD5A8 + stream[256..319] = 9186CB5B8DA3BCFA90C4768BD9B27BE2 + B38B9A65995C5791D8197AFE3188B53F + BA5DAFEAE2B179AC0799A25AEEF539E8 + 2AC8FBA1F8DD1DF7006B7373696F6486 + stream[448..511] = 41D8F9AD87DC7A70DF1639A2DD3E18F9 + C2FCF9C70DF45F06950D84C655150305 + 55B0A418189F3E10266CFB89CDE5C2E0 + 04A0CB031D45F7EB60E96556182D181D + xor-digest = B152B86A3A175808797E611B79505815 + 7ED95B9747EF8F449DC0FFF0F020EC72 + 35726C5CB6650B33AB88AE2B151A5E83 + 45B39F97949037002276DBE9851A5F5D + +Set 5, vector# 27: + key = 00000000000000000000000000000000 + IV = 0000001000000000 + stream[0..63] = AD1CEF2DBC992972709AD20046F141DE + 692C0A1960425A7E97CD5CA012974946 + 3F3D9F605EDEB7B104DD648C5AC03035 + 106F90B8879DA7F5AA59EB0E7B348F67 + stream[192..255] = 82693BDC426221E5250934A2089154E8 + 1B0B2D2D398E903DA3F15541C9B0BDF6 + 162AFD2E3CBCECDD3EE3E187F67225E3 + 6C425A461EABA7FC11312370F54EC727 + stream[256..319] = 83AED2E804EB005C4A6149EC98FC23BD + 287FB680FBBCD74B8E0D11BC7468D315 + EE80378859CFAC5D05A9AC03351D9286 + 2EE56C841308FE15641F14F1FF1226DD + stream[448..511] = 0DC61BC0188D40CEB3FF1F5609FAC338 + 063490128A2D90529BC769F5434DA68D + 58C5F6812D40B67303445407FF2395E9 + 57A2D4CDD9A0C7129596B36E9A187A5D + xor-digest = 3FE6B175DAB56A211E0846CE1BF146CD + 59C2FE9BEFDFF644607C68B31FB5FE54 + 31D32FAD6639011115DD4E0271573510 + 2F356FBDFF9E96CE991B28AC7234E036 + +Set 5, vector# 36: + key = 00000000000000000000000000000000 + IV = 0000000008000000 + stream[0..63] = 3A2A8DC611360210D764A8461B18CBB7 + C9E7683C14DB3AFADB084220821CC6BC + 292D4F2519CABDAE9948ED6763660B6C + B2E8F80E987E95EB15995990EE1AEC47 + stream[192..255] = E6FB803B9F92355BC191D9211AC4434E + 3B9F3EC20FB043D80A02F3082CA062C7 + 8D5AB8C56571EC113500A61908733825 + 1A1FF1A9DD11DF9154D7E7954AADEE0D + stream[256..319] = 219F88C3EB9F2ED869FB680121D463E6 + E74480406032B4C25D9ADA942F9301D3 + F93914CC09DCBA4A4699189FE033E6ED + F2809FB5A16779EB5D1483DF4CAC7BE4 + stream[448..511] = 9D8B1483CA286AFCBC5A56F6EC99205A + C40DCDE3239E3224D5F4E33B5A10785B + F4EEEA0F5AD1817C81EC9F6A3BA707F3 + 5C570217C7B55B1810E8B75CCD14ACBE + xor-digest = EA24BC34FF6BFB75F8C1CAADDF993972 + D16A8F6B54A189104A401609D5A04A6B + 615177DAA4968FEB10940C6E530447EA + B5CA0067D8EFCFD362EE8A956AC3425D + +Set 5, vector# 45: + key = 00000000000000000000000000000000 + IV = 0000000000040000 + stream[0..63] = 091021A7297C69E10442E24B0D06DBB6 + E3B30829BC0BA7AED758DF6E35487701 + 25FE1E3BED56CD212B249DFA7B040AA5 + 0087FEF28729239A272BC0CA7C82EED3 + stream[192..255] = 635ED01A5A21FFA51F18190F4908DC3E + 68E09644DCFE1E4F3C5B4B9BFD0D4AAB + 7E995DF674DE183EE261C6D42D8BEF5B + 265AB53DE0CE0781603886B90B07657B + stream[256..319] = FFE79E722B87D8767421C01FE16C7E51 + 43150CD79CEAEFC45683459F08713282 + 09FB7850F3DD1052DA55D6B34367D56E + 4D37EBD37114C3C495122529246918F5 + stream[448..511] = 5519177B672C421F4B96494222188E82 + EE7CCF83DE51397ECCDD5A5B96965BCE + 00DA24C8188475BF04E8501E1440FCA3 + B1C0B8104EC8D6DBE7341F2194F0C3F5 + xor-digest = 4850B008CEFBF281BA581C067E5224AA + 1E4920503D373335FE14B99AFEDBC883 + D24CFDC9E6D1A7DB473C9BD77845E08A + 654570A9DF0809FDF4C0D769368FC20F + +Set 5, vector# 54: + key = 00000000000000000000000000000000 + IV = 0000000000000200 + stream[0..63] = 5FD06EDB1E00BFB4465CDAFAEDD38725 + B37BDCC92558651CF9233DE0CE17CD92 + 1EBF9ABBD37C1A3DEBD7E34BBB0885B1 + E370C510811F4FAE7B3CCCB3A2FB7851 + stream[192..255] = F4611AD0A04D3281AE3312FACE53DE10 + 7BCCDC6487F4FF40FAECF0E342E04023 + 1AF3FA1EC0D97C2E497BEF918AB98EE2 + 6B88C3A41C89C1C003F43FC802F3978F + stream[256..319] = 141057F473D4ACA6AD9761DFA8F5172A + CB381F7E6E9F0AD929D16F8E86512AA3 + 8645B74020C7F86DED2713FD854E0349 + DB77BDDDD52E742B35AE362C7A7267DA + stream[448..511] = CCD2A83A7D6D353F24EA309165FC20A3 + F4AB36D578CAAC4658D08C6DE4480908 + 9C33B5F536B041C28A02A1C725FE4F9B + 2DBE4621CDAE50BE84E863F2B58AAB05 + xor-digest = 99463BD3014AAB2C07E6227763E170FC + E14CE3A1AEFDC3683193889E316C6428 + 4B0665B75E43440C0DB54771EB410223 + 5F78865DB8D4AF1206523090C3310E55 + +Set 5, vector# 63: + key = 00000000000000000000000000000000 + IV = 0000000000000001 + stream[0..63] = 55FB0B90A9FB953AE96D372BADBEBD30 + F531A454D31B669BCD8BAAD78C6C9994 + FFCCEC7ACB22F914A072DA22A617C0B7 + B1ABC91C8604D55ABB61B7AA88749C29 + stream[192..255] = 09336FD5B777A613FC490DE262D72787 + 2B066C2A5DAA406224FB1CD844A98D90 + 2E56E734FFBA09F524292C8CF655E123 + C6FC9EDDB0D794ED3351E1F15F403AAE + stream[256..319] = 7673EFDB39793122B538847DF651EDBF + 2F2DB7959EDFA01E73075F8125F47E14 + 1198528ED6F6D74F3DA5239B4FF003D5 + EBB28B9319ECE253C844A86E44892611 + stream[448..511] = A9BDEFF05695E0835C3596571177C489 + 848E6B99221F71DFA5B77F92466CBFAB + 6D3514A6B172C4F5B3E163BC5A844BC1 + 0402A13EC657FF82B23AB3B1C6793195 + xor-digest = B923DC54547EEE7A9A45E6283B7BD0E1 + 80F91F1ADD1F6A2A02835AF643BD0AB9 + 5B2C684E9867ABF5D56EA7E8583CD08D + 81572A6DC04CC290AB04BF6D917366F7 + +Test vectors -- set 6 +===================== + +Set 6, vector# 0: + key = 0053A6F94C9FF24598EB3E91E4378ADD + IV = 0D74DB42A91077DE + stream[0..63] = 75D186D6BC6905C64F1B2DFDD51F7BFC + D74F926E6976CD0A9B1A3AE9DD8CB43F + F5CD60F2541FF7F22C5C70CE07613989 + 71D8779A8423157A9136C194BD0570A4 + stream[65472..65535] = 8B043B72E059CDD5444436D4FF0440B4 + C0A7A6BD84A3D958C70B9945DBE07E08 + 889482606365B39976A538D94E12D800 + 526151C540FCFC9B46D6841D5FF330BC + stream[65536..65599] = 3460B5305B19C17C3E5B023616628F57 + D3CAC65E4065DBE6A2A3A786C1D5EE6E + 4DF2227E0D1D366756746420D1B54252 + 74B66CE57B0C05077E09DAD1BAF9AA37 + stream[131008..131071] = 7C28F9D069B6D1380AAA5A21F165DE47 + 149BB4AEEDFA75C56F52B1375878C340 + 30EB6C77CA5271E12FB28067B7A48915 + 47C7149DC562326941DE8DDA4A91AEE1 + xor-digest = 3D2DF1B3EB9EF523140A679F5A9E3650 + B37C8B34D98B6298E678753E1018E222 + 99E469418E9B0F2483FA5E655FF1785F + B6492CA458A013929973F4C8DCF3EEA3 + +Set 6, vector# 1: + key = 0558ABFE51A4F74A9DF04396E93C8FE2 + IV = 167DE44BB21980E7 + stream[0..63] = 476E2750C73856C93563B5F546F56A6A + E5F97D8888655222812E3EDDB86BB8AD + 214AE0AA107CEAB4993CC74F63932885 + F0A585C735D590D194AC90717D0BADCF + stream[65472..65535] = 3D5E36D1D7DE3AB2905F27EAD076D990 + 47AB98783EFB85EBF454256736D27126 + 69DEE9B78F1D9E26E958C3E0065FE5E2 + 91384E884A885CFFB68B29129483368E + stream[65536..65599] = 4206D36807E7935012303086A3977E83 + 740A7B00A1773F7FE76DA6A569F02056 + 1B0BD6C640573F585565D6CADA5F38A5 + 45763C7ABDA4CEA8D210BFE3F8839DEE + stream[131008..131071] = 8C044756D4610B9BA4292E3C67F166C4 + 5AD0E1D6666050BDADDF6CAA609D3E8E + 3C76CC20D1C3D0C7CD2CA6006CDB3B23 + A26901C1CB989FA74797A16FDBE03428 + xor-digest = 0EE069762C0F2E6EE05446FCA071A147 + BD23359A1A3141B550658319725EEA8B + 570AB7FF253C6735B64D3E2B99403403 + 69E597C0E1230B102E38B2CBC49EED4F + +Set 6, vector# 2: + key = 0A5DB00356A9FC4FA2F5489BEE4194E7 + IV = 1F86ED54BB2289F0 + stream[0..63] = 921FCF4983891365A7DC901924B5E24B + 50F615D59FCD61CBD27280474F3D23C9 + ADF14BACADF99E5A163B836B0CFF02C0 + FF60F4B64EE7C824C98C3481EF656894 + stream[65472..65535] = 60F32B38AC646685723EE812C1C5EB87 + 48D9C367CB5B320C79338A3F76CC095C + 9D26D5933216230E787C5C3AF2B000E4 + 1842FE39ED966F41AB36DECA719B92A3 + stream[65536..65599] = E562F28ECA6D9606D792EEBAB1694C6E + D9C0C34C59F7CE59D0BE302AF58D065F + 59F8AC95F4722143B3AC55D711381F33 + D87AF8B4FE0BEEFFA86A0E879CA84123 + stream[131008..131071] = C73A00E366B8F5FE717802F1BC843B8C + 4603B902EF2D6D65567E2F637EC99FC4 + 6321FA6F5A1CCDDE9447807EE21C0460 + 7569D1F793F413699A1E8921559AFC0C + xor-digest = 56C1143571F210037B9857DDC9A51690 + 75AB5A9DD158B141A83F50D3DD171ED7 + 8927DEC249E06212216284723C5F8988 + 38F5FC5035100BF7C1FFBD2A54CF9329 + +Set 6, vector# 3: + key = 0F62B5085BAE0154A7FA4DA0F34699EC + IV = 288FF65DC42B92F9 + stream[0..63] = 613CB0BA96AFF6CACF2A459A102A7F78 + CA985CF8FDD1474018758E36AE9923F5 + 19D13D718DAF8D7C0C109B79D5749439 + B7EFA4C4C9C8D29DC5B3888314A6816F + stream[65472..65535] = 743222D98533857C9EE38BDC410ACF39 + A823CE0C4CF2939EBE6B95DA668396BB + D823429F47F81B5D65308E83604C95B4 + E419FDB115F6E9E77B7225F14464C396 + stream[65536..65599] = F2732DC10349ABC9C212326CE22A3C2A + CF233A6EF8469659BDA3EDAACC759CD5 + 3EA71F9E338302F802C3A90793721BCF + 875CFA332B4BA4E14B41C689F1FA4C1D + stream[131008..131071] = 79037775E485C71704F308611AD1FE54 + 5B77CFFD982AF1FE0EDD3E926931AA54 + EE55F24DBC7B385ECA940EA73EE627CF + A3BD376BF5D8D7F1E8AFFE344D6A34F0 + xor-digest = 92CA61A5E18F6081082008975C842332 + 2AB413AFB1874755D7ED9742062A4C40 + 77CF6106CEC3452E2C1023013B5C5B5D + D72FAFF59B4C82FD0C5A1979B7550DC8 + + + +End of test vectors diff --git a/plugins/rngLibraries/rngSpeed.icn b/plugins/rngLibraries/rngSpeed.icn new file mode 100644 index 000000000..584491b38 --- /dev/null +++ b/plugins/rngLibraries/rngSpeed.icn @@ -0,0 +1,61 @@ +################################################################################ +# +# This file is released under the terms of the GNU LIBRARY GENERAL PUBLIC LICENSE +# (LGPL) version 2. The licence may be found in the root directory of the Unicon +# source directory in the file COPYING. +# +################################################################################ +# +# A simple speed test to see how fast a generator is. +# usage: time ./rngSpeed rnglib iterations +# (add a third parameter to measure the loop overhead). +# +# The actual values returned by time may not be all that useful, but the +# relative differences between different rnglibs should be illuminating. +# +# Don Ward +# August 2019 +# +################################################################################ + +procedure main(args) +$ifdef _RNG_LIBRARY + local rng := args[1] | "rngIcon" # Default generator is the built-in one. + local limit := args[2] | 10000000 # Default number of iterations + local total := 0.0 + local percentFromPerfect + + loadrng(rng) + + # It would be nice to set the initial seed (via an assignment to &random) + # so repeatable sequences are generated. + # + # But the disadvantage of explicitly setting a value to &random in a + # test program like this is that the values needed will vary between + # generators; there is no one "good value" that fits all generators. + # + # Not initializing &random means that the generator has to initialize its + # own state, which works for all generators, but with the downside that + # the sequences are not repeatable. + + if \args[3] then { # just the loop overhead + every 1 to limit do { total +:= 0.5 } + } else { + every 1 to limit do { total +:= ?0 } + } + + write(loadrng(), " : total = ", total) + + if limit >= 100000 then { + # Complain if the total isn't close to 50% of the limit. + percentFromPerfect := abs(total + total - limit)/(0.0 + limit) + if percentFromPerfect >= 0.01 then { + write(loadrng(), + " isn't looking good (", + integer(100.0*percentFromPerfect), "% from the ideal value)") + } + } +$else + write(&errout, "RNG libraries are not available") +$endif +end diff --git a/plugins/src/icall.h b/plugins/src/icall.h index 4aa2f3f04..805e523a0 100644 --- a/plugins/src/icall.h +++ b/plugins/src/icall.h @@ -130,9 +130,14 @@ #define D_Typecode (F_Nqual | F_Typecode) /* - * There is no type T_String: all non-string descriptors have a negative + * There is no type T_String really: all non-string descriptors have a negative * dword field because of F_Nqual (see definition of IconType below). + * T_String is used solely in RngTypeFlag (see below); We should probably find a better name. */ +#ifdef RngLibrary +#define T_String -1 /* string -- for reference; not used (except in RngTypeFlag) */ +#endif /* RngLibrary */ + #define T_Null 0 /* null value */ #define T_Integer 1 /* integer */ #define T_Real 3 /* real number */ @@ -233,6 +238,49 @@ extern descriptor nulldesc; /* null descriptor */ ? 's' \ : "niIrcfpRL.S.T.....CE.........aA..............................."[(d).dword&63]) +#ifdef RngLibrary +struct rngprops { + word stateBits; /* No of bits in rng state */ + word typeFlags; /* Which types are acceptible as a seed */ + word blockBits; /* No of bits in the "natural size" of the random output */ +}; + +/* Routines in the run-time that are called by the rng */ +struct rng_rt_api { + word (*getInitialBits)(void); + void * (*getRngState)(void); + void (*putErrorCode)(int); +}; + +/* Routines in the rng that are called by the run-time */ +struct rt_rng_api { + char * (*getErrorText)(int); + double (*getRandomFpt)(void); + int (*getRandomBits)(int, void *); /* No of bits, output buffer */ + int (*putSeed)(word, word, void *); /* Type, Size, Seed parameter */ + #if 0 + /* Not needed after initial load, so no need to remember it */ + int (*startRng)(struct rngprops *, struct rng_rt_api *); + #endif +}; + +/* + * Define the acceptable types to PutSeed with RngTypeFlag + * e.g. (RngTypeFlag(T_String) | RngTypeFlag(T_Integer)) + * means that PutSeed can accept either a string or an integer as a seed value + * + * Any type t for which IconType(t) != '.' is a possibility, although some + * might be more "adventurous" than others. + * Note that T_String takes the place of T_Null in the flags. The run-time passes + * a NULL parameter to putSeed if no initialization has taken place before a call + * to getRandomFpt() ( it actually calls putSeed(T_Null, 0, NULL); ). + * + * Store the acceptable type(s) in the typeFlags word of the structure passed in + * the first parameter to startRng(). + */ +#define RngTypeFlag(t) ((t)==T_String ? 1 : 1 << ((t) & 63)) +#endif /* RngLibrary */ + #define FileVal(d) (((fileblock *)((d).vword.bptr))->fp) #define FileStat(d) (((fileblock *)((d).vword.bptr))->stat) @@ -499,8 +547,8 @@ do {if (sizeof(a[0]) != sizeof(double)) FailCode(102); \ /* * if you are not going to use list operations (pop/push... etc) on the newly - * created list, then use the array fucntions instead. They create a more - * effecient form of the list optimized for the int or real data types. + * created list, then use the array functions instead. They create a more + * efficient form of the list optimized for the int or real data types. */ listblock * mkIlist(int x[], int n); listblock * mkRlist(double x[], int n); diff --git a/src/h/cpuconf.h b/src/h/cpuconf.h index 2a08e087b..e6552bbe2 100644 --- a/src/h/cpuconf.h +++ b/src/h/cpuconf.h @@ -57,6 +57,9 @@ #define F_Typecode 0x2000000000000000 /* set if dword incls typecode*/ #endif /* F_Typecode */ + #ifdef RngLibrary + #define F_RngState 0x0800000000000000 /* set if RNG state */ + #endif /* RngLibrary */ #endif /* WordBits == 64 */ /* @@ -76,6 +79,9 @@ #define F_Var 0x40000000 /* set if variable */ #define F_Ptr 0x10000000 /* set if value field is pointer */ #define F_Typecode 0x20000000 /* set if dword includes type code */ +#ifdef RngLibrary + #define F_RngState 0x08000000 /* set if RNG state */ +#endif /*RngLibrary */ #endif /* WordBits == 32 */ diff --git a/src/h/define.h b/src/h/define.h index e69de29bb..4298cc6a3 100644 --- a/src/h/define.h +++ b/src/h/define.h @@ -0,0 +1 @@ +#define RngLibrary 1 diff --git a/src/h/fdefs.h b/src/h/fdefs.h index a95314741..7318ce55b 100644 --- a/src/h/fdefs.h +++ b/src/h/fdefs.h @@ -34,6 +34,9 @@ FncDef(cset,1) #if defined(DEVMODE) FncDef(dbgbrk,0) #endif /* DEVMODE */ +#if defined(RngLibrary) +FncDef(dbgrng,2) +#endif /* RngLibrary */ FncDef(delay,1) FncDefV(delete) FncDefV(detab) @@ -58,6 +61,9 @@ FncDef(ixor,2) FncDef(key,1) FncDef(left,3) FncDef(list,2) +#if defined(RngLibrary) +FncDefV(loadrng) +#endif /* RngLibrary */ FncDef(log,2) FncDef(many,4) FncDef(map,3) @@ -81,6 +87,10 @@ FncDef(rename,2) FncDef(repl,2) FncDef(reverse,1) FncDef(right,3) +#if defined(RngLibrary) +FncDef(rngbits,1) +FncDef(rngbitstring,1) +#endif /* RngLibrary */ FncDef(rtod,1) FncDefV(runerr) FncDef(seek,2) diff --git a/src/h/feature.h b/src/h/feature.h index 9cbde7b65..c515f215e 100644 --- a/src/h/feature.h +++ b/src/h/feature.h @@ -14,6 +14,13 @@ * * The translator and compiler modify this list of predefined symbols * through calls to ppdef(). + * + * Note: + * If you add a new feature that comes with a predefined symname, + * don't forget to amend the preprocessor file uni/unicon/preproce.icn. + * It "reverse engineers" these definitions from &features and your + * new feature must be added explicitly to the predefs() procedure, + * rather than happening automatically. */ Feature(1, "_V9", 0) /* Version 9 (unconditional) */ @@ -96,6 +103,10 @@ Feature(1, "_DYNAMIC_LOADING", "dynamic loading") #endif /* LoadFunc */ +#ifdef RngLibrary + Feature(1, "_RNG_LIBRARY", "loadable RNGs") +#endif /* RNG libraries */ + Feature(1, "", "environment variables") #ifdef EventMon diff --git a/src/h/rexterns.h b/src/h/rexterns.h index e14df8d9d..7fb14a8e3 100644 --- a/src/h/rexterns.h +++ b/src/h/rexterns.h @@ -54,6 +54,13 @@ extern struct descrip onedesc; /* one */ extern struct descrip ucase; /* uppercase string */ extern struct descrip zerodesc; /* zero */ +#ifdef RngLibrary +extern struct rnglibchain *rngDefInfo; /* Default properties of RNG */ +extern word rngIconId; +extern struct descrip rngIconName; +extern struct b_cons *rngLibs; /* chain of loaded libraries */ +#endif /* RngLibrary */ + extern word mstksize; /* size of main stack in words */ extern word stksize; /* size of co-expression stacks in words */ extern word qualsize; /* size of string qualifier list */ diff --git a/src/h/rmacros.h b/src/h/rmacros.h index 6cce1821c..8e6943cdb 100644 --- a/src/h/rmacros.h +++ b/src/h/rmacros.h @@ -1374,16 +1374,21 @@ #define MTX_BLOCKTOTAL 35 #define MTX_COLL 36 +#ifdef RngLibrary + #define MTX_RNG_CHAIN 37 /* This should be the last mutex, becasue it has special initialization*/ - #define MTX_INITIAL 37 - + #define MTX_INITIAL 38 /* total is: */ - #define NUM_STATIC_MUTEXES 38 - - /* used by wait4GC function*/ - + #define NUM_STATIC_MUTEXES 39 +#else + /* This should be the last mutex, becasue it has special initialization*/ + #define MTX_INITIAL 37 + + /* total is: */ + #define NUM_STATIC_MUTEXES 38 +#endif /* RngLibrary */ #define TC_NONE -1 diff --git a/src/h/rproto.h b/src/h/rproto.h index 0f70595c0..2c8f9c5b3 100644 --- a/src/h/rproto.h +++ b/src/h/rproto.h @@ -92,6 +92,17 @@ void set_gzerrortext(gzFile f); struct b_cons *alccons (union block *); +#ifdef RngLibrary +struct b_external *alcext(uword size); +void * tryLoad(struct descrip *name, const char *format, char *path); +void *getRngState( void); +void putErrorCode(int n); +int rngAsgnState(struct threadstate *ts, struct descrip v); +/* These are for debugging and will eventually disapear */ +void pstr(struct descrip str); +void dbgplibchain(struct b_cons *p, int level); +#endif /* RngLibrary */ + int anycmp (dptr dp1,dptr dp2); #ifdef Arrays int arraytolist (struct descrip *arr); diff --git a/src/h/rstructs.h b/src/h/rstructs.h index d6814c39f..c9f83e753 100644 --- a/src/h/rstructs.h +++ b/src/h/rstructs.h @@ -495,6 +495,68 @@ union numeric { /* long integers or real numbers */ #endif /* LargeInts */ }; +#ifdef RngLibrary + +/* + * Define the acceptable types to PutSeed with RngTypeFlag + * e.g. (RngTypeFlag(T_String) | RngTypeFlag(T_Integer)) + * means that PutSeed can accept either a string or an integer as a seed value + * + * Any type t for which IconType(t) != '.' is a possibility, although some + * might be more "adventurous" than others. + * Note that T_String takes the place of T_Null in the flags. The run-time passes + * a NULL parameter to putSeed if no initialization has taken place before a call + * to getRandomFpt() ( it actually calls putSeed(T_Null, 0, NULL); ). + * + * Store the acceptable type(s) in the typeFlags word of the structure passed in + * the first parameter to startRng(). + */ +#define RngTypeFlag(t) ((t)==T_String ? 1 : 1 << ((t) & 63)) + +struct rngprops { + word stateBits; /* No of bits in rng state */ + word typeFlags; /* Which types are acceptible as a seed */ + word blockBits; /* No of bits in the "natural size" of the random output */ +}; + +/* Routines in the run-time that are called by the rng */ +struct rng_rt_api { + word (*getInitialBits)(void); + void * (*getRngState)(void); + void (*putErrorCode)(int); +}; + +/* Routines in the rng that are called by the run-time */ +struct rt_rng_api { + char * (*getErrorText)(int); + double (*getRandomFpt)(void); + int (*getRandomBits)(int, void *); /* No of bits, output buffer */ + int (*putSeed)(word, word, void *); /* Type, Size, Seed parameter */ + #if 0 + /* Not needed after initial load, so no need to remember it */ + int (*startRng)(struct rngprops *, struct rng_rt_api *); + #endif +}; + +struct rnginfo { + word id; /* Hash of rng name */ + struct descrip name; /* Name of rng library */ + struct rngprops property; /* rng properties */ + struct rt_rng_api api; +}; + +/* The chain of loaded rng libraries */ +/* The first two fields mimic struct b_exernal */ +/* They are linked together with b_cons elements */ +struct rnglibchain { + word title; /* T_External */ + word blksize; /* size of block */ + struct rnginfo info; +}; + + +#endif /* RngLibrary */ + /* * We want to support pthreads eventually even under COMPILER. * Towards that end, threadstate defined for both COMPILER and VM, @@ -564,6 +626,10 @@ struct threadstate { struct descrip Kywd_pos; /* TLS */ struct descrip ksub; /* TLS */ struct descrip Kywd_ran; /* TLS */ +#ifdef RngLibrary + struct rnglibchain *rng; /* TLS */ + int hasSeed; /* non zero if initialized */ +#endif /* RngLibrary */ #ifdef PatternType int K_patindex; /* TLS */ #endif /* PatternType */ diff --git a/src/runtime/cnv.r b/src/runtime/cnv.r index 2f84430a9..2fd6b9992 100644 --- a/src/runtime/cnv.r +++ b/src/runtime/cnv.r @@ -742,6 +742,12 @@ void f(dptr s, dptr d) } default: { +#ifdef RngLibrary + if (CHECK_FLAG(s->dword, F_RngState)) { + /* Dereference &random */ + *d = *s; + } else +#endif /* RngLibrary */ #ifdef Arrays if (Offset(*s) > 0) { if (BlkLoc(*s)->Realarray.title == T_Realarray) { diff --git a/src/runtime/data.r b/src/runtime/data.r index 85b7e4040..60f2b6a81 100644 --- a/src/runtime/data.r +++ b/src/runtime/data.r @@ -254,6 +254,23 @@ unsigned char allchars[256] = { 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, }; + + +/* + * Definitions for loadable RNGs + * rngDefInfo starts at "rngIcon" but may be changed by the main thread. + * rngIconInfo is the default values for "rngIcon" and never changes thereafter + * which gives an easy test for whether the RNG is the default. + * New threads start with whatever is in rngDefInfo. + * Each library's properties is stored in rngLibs. + */ +#ifdef RngLibrary +struct rnglibchain *rngDefInfo; /* Default properties of RNG */ +word rngIconId; +struct descrip rngIconName; +struct b_cons *rngLibs; /* chain of loaded libraries */ +#endif /* RngLibrary */ + /* * Run-time error numbers and text. @@ -395,6 +412,24 @@ struct errtab errtab[] = { 500, "program malfunction", /* for use by runerr() */ 600, "vidget usage error", /* yeah! */ +#ifdef RngLibrary + 700, "PRNG error 1", /* Boilerplate error messages */ + 701, "PRNG error 2", /* replaced by text from each */ + 702, "PRNG error 3", /* library by calling the */ + 703, "PRNG error 4", /* getErrorText() routine. */ + 704, "PRNG error 5", + /* Although only 5 are defined here, the putErrorCode routine + * assumes there might be up to 50, so don't use 700 .. 750 + * for anything else. If any RNG wants more than 5 error messages, + * add some more boilerplate messages to the above. + */ + + 800, "Library not loaded", + 801, "Function not found in PRNG library", + 802, "startRng() failed", + +#endif /* RngLibrary */ + #ifdef PosixFns 1040, "socket error", 1041, "cannot initialize network library", diff --git a/src/runtime/fmisc.r b/src/runtime/fmisc.r index d8335d7eb..85e35fc23 100644 --- a/src/runtime/fmisc.r +++ b/src/runtime/fmisc.r @@ -2513,6 +2513,443 @@ end #endif /* MultiProgram */ +#ifdef RngLibrary + +void *getRngState( void) +{ + CURTSTATE(); + + if (curtstate->rng != NULL) { + return &(curtstate->Kywd_ran.vword.bptr->List.listhead->Intarray.a[1]); + } + return NULL; +} + +extern struct errtab errtab[]; /* error numbers and messages */ + +void putErrorCode(int n) +{ + CURTSTATE(); +/*dbg* fprintf(stderr, "*** rngLib has set error %d ***\n", n); fflush(stderr); */ + + /* err_msg() (called below) picks out the error text from errtab + * So, if the error is one of the RNG boilerplate errors, replace + * the boilerplate text by the text supplied by the generator. + */ + + /* FixMe? + * Two (or more) threads each using the same boilerplate error for + * a different message will fight each other if they happen to report + * the error simultaneously. + */ + /* FixMe? Change these magic numbers into defines */ + if ((700 <= n) && (n <= 750)) { + register struct errtab *p; + for (p = errtab; p->err_no > 0; p++) { + if (p->err_no == n) { + p->errmsg = curtstate->rng->info.api.getErrorText(n); + break; + } + } + } + err_msg(n,NULL); +} + +/* ============================== Debugging Code ============================== */ +/* ========================= Will eventually disapear ========================= */ + +void pstr(struct descrip str) +{ +#if 0 + char *tmps; + int n; + for (n=StrLen(str), tmps= StrLoc(str); n > 0; --n,++tmps) fprintf(stderr,"%c",*tmps); +#else + fprintf(stderr, "%.*s", (int)StrLen(str), StrLoc(str)); +#endif +} + +/* Can be called directly from the debugger, if needed */ +void dbgplibchain(struct b_cons *p, int level) +{ + struct rnglibchain *lib; + + for( ; p != NULL; p = (struct b_cons *)p->next) { + lib = (struct rnglibchain *) p->data; + fprintf(stderr, "\n%p (-> %p) %p : Name <", p, p->next, lib); + pstr(lib->info.name); + fprintf(stderr, "> Id %08lx", lib->info.id); + if (level > 4) { /* Add the rest of the library data */ + fprintf(stderr, "\n stateBits %ld typeFlags %08lx", + lib->info.property.stateBits,lib->info.property.typeFlags); + fprintf(stderr,"\n getErrorText %p", lib->info.api.getErrorText); + fprintf(stderr,"\n getRandomFpt %p", lib->info.api.getRandomFpt); + fprintf(stderr,"\n putSeed %p", lib->info.api.putSeed); +#if 0 + fprintf(stderr,"\n startRng %p", lib->info.api.startRng); +#endif + + } + } + fprintf(stderr,"\n"); + fflush(stderr); +} + +"dbgrng(str,level) - debugging print at given verbosity level, labelled by str" +function{0,1} dbgrng(str,level) + if !is:string(str) then + runerr(103,str) + + if !def:C_integer(level,1) then + runerr(101,level) + + abstract { return null } + +body { + pstr(str); + if (level >= 1) { /* Just the header info */ + fprintf(stderr, "IconId %08lx rngLibs %p rngDefInfo %p", rngIconId, rngLibs, rngDefInfo); + if (level >= 2) { /* Add the default library Name & id */ + if (rngDefInfo != NULL) { + fprintf(stderr," Name <"); pstr(rngDefInfo->info.name); + fprintf(stderr, "> Id %08lx", rngDefInfo->info.id); + } + } + if ((level >= 3) && (rngLibs != NULL)) { /* Add the loaded library chain */ + dbgplibchain((struct b_cons *)rngLibs, level); + } + } + fprintf(stderr,"\n"); + fflush(stderr); + return nulldesc; + } +end + +/* =========================== End of Debugging Code ============================ */ + +" rngbits(n) - return a list containing n random bits" +function{0,1} rngbits(n) + if !cnv:C_integer(n) then + runerr(101,n) + abstract { return new list(integer) } + body { + int elems; + tended struct b_intarray *ap; + CURTSTATE(); + if (curtstate->rng != NULL) { + if (!curtstate->rng->info.api.getRandomBits) { + fail; /* getRandomBits not present*/ + } else { + /* Check the rng has been initialized */ + if (curtstate->hasSeed == 0) { + if (curtstate->rng->info.api.putSeed(T_Null, 0, NULL) == 0) { + curtstate->hasSeed = 1; + } else { + fail; + } + } + + if (n == 0 ) n = curtstate->rng->info.property.blockBits; + + elems = (((n+7)/8 + sizeof(word) - 1)/sizeof(word)); + Protect(ap = (struct b_intarray *) alcintarray(elems), runerr(0)); + if (0 > curtstate->rng->info.api.getRandomBits(n, &(ap->a[0]))) { + fail; + } + +/*dbg* fprintf(stderr, "%016lx%016lx\n", ap->a[0], ap->a[1]); fflush(stderr); */ + result.dword = D_List; + result.vword.bptr = (union block *)alclisthdr(elems, (union block *) ap); + return result; + } + } else { + fail; /* built-in rng does not have rngbits */ + } + } +end + + +" rngbitstring(n) - return a string of n random bits" + +function{0,1} rngbitstring(n) + if !cnv:C_integer(n) then + runerr(101,n) + abstract { return string } + body { + CURTSTATE(); + + if (curtstate->rng != NULL) { + if (n == 0 ) n = curtstate->rng->info.property.blockBits; + + if (!curtstate->rng->info.api.getRandomBits) { + fail; /* getRandomBits not present*/ + } else { + char bitbuff[(n+7)/8]; + word bytes, byte, bits, b; + char *bstr; + + /* Check the rng has been initialized */ + if (curtstate->hasSeed == 0) { + if (curtstate->rng->info.api.putSeed(T_Null, 0, NULL) == 0) { + curtstate->hasSeed = 1; + } else { + fail; + } + } + + if ( 0 < curtstate->rng->info.api.getRandomBits(n, bitbuff)) { + /* Allocate a string of the required size for the answer */ + Protect(StrLoc(result) = alcstr(NULL, n), runerr(0)); + + /* Populate result with '0' and '1' characters. + * The bits are in the natural left to right reading order, + * i.e. the least significant bit is at the _end_ of the string. + */ + bstr = n + StrLoc(result); + bits = 0; bytes = 0; + while( bits < n ) { + byte = bitbuff[bytes++]; + for (b = 0; b < 8; b++) { + *--bstr = (byte & 1 ? '1' : '0'); + byte >>= 1; + if (++bits >= n) break; + } + } + StrLen(result) = n; + } else { + fail; /* getRandomBits failed */ + } + } + } else { + fail; /* built-in rng does not have rngbitstring */ + } + return result; + } +end + + +/* Try to load a library. Note that the format must have a precision spec + * in it (eg "%.*s") or things will go badly wrong. + */ +void * tryLoad(struct descrip *name, const char *format, char *path) +{ + char filename[MaxPath]; + int n = StrLen(*name); + + if (path != NULL) { + int pn = strlen(path); + strncpy(filename, path, pn); + snprintf(filename + pn, MaxPath, format, n, StrLoc(*name)); + } else { + snprintf(filename, MaxPath, format, n, StrLoc(*name)); + } + +/*dbg fprintf(stderr, "Trying %s\n", filename); fflush(stderr); */ + return dlopen(filename, RTLD_LAZY); +} + + +"loadrng(lib) - with no args, return the current library, else load the rng library" + +function{0,1} loadrng(argv[argc]) +abstract { return string } +body { + tended struct rnglibchain *rngp; + struct descrip dtmp; + word newId, currId; + struct b_cons *rl; + CURTSTATE(); + + if (argc > 1) runerr(130, argv[1]); + if (argc == 0) { /* Return name of current RNG library */ + if (curtstate->rng != NULL) { + return curtstate->rng->info.name; + } else { + return rngIconName; + } + } else { /* Load the specified library */ + dtmp = argv[0]; + if (!is:string(dtmp)) runerr(103, dtmp); + newId = hash(&dtmp); + + currId = (curtstate->rng != NULL) ? curtstate->rng->info.id : rngIconId; + + /* Has rng library changed? (Ignore possibility of hash collision) */ + if (currId != newId) { + if ((StrLen(dtmp) == 7) && (newId == rngIconId)) { + /* Revert to built-in rngIcon */ + curtstate->rng = NULL; + curtstate->Kywd_ran = zerodesc; + IntVal(curtstate->Kywd_ran) = getrandom(); /* Reinitialize */ +/*dbg* fprintf(stderr, "*** Restart rngIcon ***\n"); fflush(stderr); */ + } else { +#ifndef Arrays + /* The rng state is stored as an array of integers */ + #error RngLibrary option requires Arrays +#endif + + /* Try to load the new library */ + /* Assume it isn't already loaded, so we will need */ + /* a new entry in the chain of loaded libraries */ + Protect(reserve(Blocks, sizeof(struct b_cons) + sizeof(struct rnglibchain)), runerr(0)); + + MUTEX_LOCKID(MTX_RNG_CHAIN); + /* Is it already loaded? */ + for (rl = rngLibs; rl != NULL; rl = (struct b_cons *) rl->next) { + rngp = (struct rnglibchain *) rl->data; + if (rngp->info.id == newId) break; + } + + if (rl == NULL) { + /* Not found: load the new library. + * Try the following (where Unicon/ is wherever the distribution is installed) + * ./name + * ./name.so + * ./libname.so + * Unicon/plugins/lib.name + * Unicon/plugins/lib/name.so + * Unicon/plugins/lib/libname.so + */ + /* TODO: incorporate Windows naming conventions */ + void *handle = NULL; + + if (StrLen(dtmp) + strlen("lib.so") >= MaxPath) runerr(1022, dtmp); + + handle = tryLoad(&dtmp, "%.*s", NULL); /* Try just the supplied string */ + if (!handle) handle = tryLoad(&dtmp, "%.*s.so", NULL); /* Try .so */ + if (!handle) handle = tryLoad(&dtmp, "lib%.*s.so", NULL); /* Try lib.so */ + #if UNIX + if (!handle) { + char path[MaxPath]; + int n; + if (findonpath(UNICONX, path, MaxPath)) { + n = strlen(path); + if (StrLen(dtmp) + n - strlen(UNICONX) + strlen("../lib/unicon/plugins/lib/") > MaxPath) + runerr(1022, dtmp); + + snprintf(path+n-strlen(UNICONX), MaxPath - n, "../lib/unicon/plugins/lib/"); + handle = tryLoad(&dtmp, "%.*s", path); /* Try path/ */ + if (!handle) handle = tryLoad(&dtmp, "%.*s.so", path); /* Try path/.so */ + if (!handle) handle = tryLoad(&dtmp, "lib%.*s.so", path); /* Try path/lib.so */ + if (!handle) { +/*dbg* fprintf(stderr, "%s\n", dlerror()); fflush(stderr); */ + runerr(800, dtmp); + } + } + } +#endif /* UNIX */ + if (!handle) { + fprintf(stderr, "%s", dlerror()); fflush(stderr); + runerr(800, dtmp); + } else { + char * (*getErrorText)(int); + double (*getRandomFpt)(void); + int (*putSeed)(word, word, void *); /* Type, Size, Seed parameter */ + int (*startRng)(struct rngprops *, struct rng_rt_api *); + int (*getRandomBits)(int, void *); /* No of bits, output buffer */ + struct descrip fname; + +/*dbg* fprintf(stderr, "%s is loaded\n", filename); fflush(stderr); */ + startRng = (int (*)(struct rngprops *, struct rng_rt_api *)) dlsym(handle, "startRng"); + if (!startRng) { + AsgnCStr(fname, "startRng"); + errno = 0; + runerr(801, fname); /* Can't find startRng */ + } +/*dbg* fprintf(stderr, "startRng() found\n"); fflush(stderr); */ + + putSeed = (int (*)(word, word, void *)) dlsym(handle, "putSeed"); + if (!putSeed) { + AsgnCStr(fname, "putSeed"); + runerr(801, fname); /* Can't find putSeed */ + } +/*dbg* fprintf(stderr, "putSeed() found\n"); fflush(stderr); */ + + getRandomFpt = (double (*)()) dlsym(handle, "getRandomFpt"); + if (!getRandomFpt) { + AsgnCStr(fname, "getRandomFpt"); + runerr(801, fname); /* can't find getRandomFpt */ + } +/*dbg* fprintf(stderr, "getRandomFpt() found\n"); fflush(stderr); */ + + getErrorText = (char * (*)(int)) dlsym(handle, "getErrorText"); + if (!getErrorText) { + AsgnCStr(fname, "getErrorText"); + runerr(801, fname); /* Can't find getErrorText */ + } +/*dbg* fprintf(stderr, "getErrorText() found\n"); fflush(stderr); */ + + /* getRandomBits is optional: don't complain if it isn't here */ + getRandomBits = (int (*)(int, void *)) dlsym(handle, "getRandomBits"); +/*dbg* fprintf(stderr, "getRandomBits()%s found\n", (!getRandomBits ? " not" : "")); */ +/*dbg* fflush(stderr); */ + + /* put the new library onto the chain*/ + rngp = (struct rnglibchain *) alcext(sizeof(struct rnglibchain)); + rngp->info.id = newId; + rngp->info.name = dtmp; + rl = alccons((union block *)rngp); + rl->next = (union block *)rngLibs; + rngLibs = rl; + + /* Store the RNG routines (no need to store startRng) */ + rngp->info.api.getErrorText = getErrorText; + rngp->info.api.getRandomFpt = getRandomFpt; + rngp->info.api.getRandomBits = getRandomBits; + rngp->info.api.putSeed = putSeed; + + /* Call startRng */ + { + struct rng_rt_api api; + api.getInitialBits = getrandom; + api.getRngState = getRngState; + api.putErrorCode = putErrorCode; + + if (0 != (startRng)(&rngp->info.property, &api)) { + runerr(802, dtmp); + } + } + } + } + + /* Compute size of rng state and make an int array to hold it */ + { + int elems = 1 + (((rngp->info.property.stateBits + 7)/8 + sizeof(word) - 1)/sizeof(word)); + int bsize = sizeof(struct b_intarray) + (elems-1) * sizeof(word); + struct descrip d; + +/*dbg* fprintf(stderr, "Need an array with %d elements\n", elems); fflush(stderr); */ + + if (!reserve(Blocks, (word)(sizeof(sizeof(struct b_list) + bsize)))) runerr(0); + d.vword.bptr = (union block *) alclisthdr(elems, (union block *)alcintarray(elems)); + d.dword = D_List | F_RngState | F_Var; + /* Clear the rng's state */ + memset(&d.vword.bptr->List.listhead->Intarray.a[0], 0, elems * sizeof(word)); + /* Store the rng ID */ + d.vword.bptr->List.listhead->Intarray.a[0] = rngp->info.id; + curtstate->Kywd_ran = d; + } + + curtstate->rng = rngp; + curtstate->hasSeed = 0; /* Not (yet) initialized with a starting seed */ + + + MUTEX_UNLOCKID(MTX_RNG_CHAIN); + } + + /* If main thread, overwrite default rng for new threads. */ + /* Note that existing threads (e.g. in a thread pool) will not change. */ + if (IS_TS_MAIN(curtstate->c->status)) { + rngDefInfo = curtstate->rng; + } + + } + return (curtstate->rng != NULL) ? curtstate->rng->info.name : rngIconName; + } +} +end +#endif /* RngLibrary */ + #ifdef Concurrent /* diff --git a/src/runtime/init.r b/src/runtime/init.r index 7477c70be..98f9a9bfa 100644 --- a/src/runtime/init.r +++ b/src/runtime/init.r @@ -627,8 +627,19 @@ void init_threadstate( struct threadstate *ts) StrLen(ts->ksub) = 0; StrLoc(ts->ksub) = ""; +#ifndef RngLibrary ts->Kywd_ran = zerodesc; IntVal(ts->Kywd_ran) = getrandom(); +#else + ts->rng = rngDefInfo; + if (ts->rng) { + ts->hasSeed = 0; + } else { + ts->Kywd_ran = zerodesc; + IntVal(ts->Kywd_ran) = getrandom(); + } +#endif /* RngLibrary */ + ts->K_errornumber = 0; ts->K_level = 0; ts->T_errornumber = 0; @@ -1084,6 +1095,14 @@ Deliberate Syntax Error EVInit(); #endif /* MultiProgram */ +#ifdef RngLibrary + StrLen(rngIconName) = 7; + StrLoc(rngIconName) = "rngIcon"; + rngIconId = hash(&rngIconName); + rngLibs = NULL; + rngDefInfo = NULL; +#endif /* RngLibrary */ + /* this is the end of yonggang's compressed icode else-branch ! */ /* diff --git a/src/runtime/keyword.r b/src/runtime/keyword.r index 0173e1310..1b202af2f 100644 --- a/src/runtime/keyword.r +++ b/src/runtime/keyword.r @@ -744,6 +744,7 @@ end "&random - a variable containing the current seed for random operations." keyword{1} random +#ifndef RngLibrary abstract { return kywdint } @@ -751,9 +752,22 @@ keyword{1} random #if !ConcurrentCOMPILER /* plausible to omit is there is only one program, one seed */ CURTSTATE(); -#endif /* !ConcurrentCOMPILER */ +#endif /* !ConcurrentCOMPILER */ return kywdint(&kywd_ran); } +#else + abstract { + return any_value + } + inline { + CURTSTATE(); + if (curtstate->rng == NULL) { + return kywdint(&kywd_ran); + } else { + return curtstate->Kywd_ran; + } + } +#endif /* RngLibrary */ end "®ions - generates regions sizes" diff --git a/src/runtime/oasgn.r b/src/runtime/oasgn.r index fd9d2fa50..c64c687a9 100644 --- a/src/runtime/oasgn.r +++ b/src/runtime/oasgn.r @@ -2,6 +2,37 @@ * File: oasgn.r */ +#ifdef RngLibrary +int rngAsgnState(struct threadstate *ts, struct descrip v) +{ + word elems; + + if (ts->rng == NULL) return 0; /* No rng is loaded (shouldn't happen) */ + + elems = 1 + (((ts->rng->info.property.stateBits + 7)/8 + sizeof(word) - 1)/sizeof(word)); + + /* + * if v is an intArray and the first element is the RNG id and the size + * is right, assign the rest of the array to the Rng State, otherwise refuse. + */ + if ((Type(v) == T_List) && + (v.vword.bptr->List.size == elems) && + (v.vword.bptr->List.listhead->Intarray.title == T_Intarray) && + (v.vword.bptr->List.listhead->Intarray.a[0] == ts->rng->info.id)) + { + /* Copy the array into the rng state */ +/*dbg* fprintf(stderr, "Overwriting rng state vector\n"); fflush(stderr); */ + memcpy(&(ts->Kywd_ran.vword.bptr->List.listhead->Intarray.a[0]), + &(v.vword.bptr->List.listhead->Intarray.a[0]), + elems * sizeof(word)); + ts->hasSeed = 1; + return 1; + } + return 0; /* No assignment */ +} + +#endif /* RngLibrary */ + /* * Asgn - perform an assignment when the destination descriptor might * be within a block. @@ -144,6 +175,88 @@ store[type(x)] = type(y) } inline { +#ifdef RngLibrary +#ifdef DescriptorDouble + double r; +#endif /* DescriptorDouble */ + CURTSTATE(); + if (CHECK_FLAG(x.dword, F_RngState)) { + /* This is an assignment to &random */ + /* Check if it's for the state or a new seed */ + if (!rngAsgnState(curtstate, y)) { /* New Seed */ + int seeded = 0; + /* Check the type of y is acceptable to the RNG */ + /* Special check for strings and arrays */ + if (is:string(y)) { + if (CHECK_FLAG(curtstate->rng->info.property.typeFlags, RngTypeFlag(T_String))) { + seeded = curtstate->rng->info.api.putSeed(T_String, StrLen(y), (char *) StrLoc(y)); + } else { + runerr(113, y); + } + } else if (is:list(y)) { + if (CHECK_FLAG(curtstate->rng->info.property.typeFlags, RngTypeFlag(T_Intarray)) && + (y.vword.bptr->List.listhead->Intarray.title == T_Intarray)) { + seeded = curtstate->rng->info.api.putSeed(T_Intarray, + y.vword.bptr->List.size * sizeof(word), + &(y.vword.bptr->List.listhead->Intarray.a[0])); + } else if (CHECK_FLAG(curtstate->rng->info.property.typeFlags, RngTypeFlag(T_Realarray)) && + (y.vword.bptr->List.listhead->Intarray.title == T_Realarray)) { + seeded = curtstate->rng->info.api.putSeed(T_Realarray, + y.vword.bptr->List.size * sizeof(double), + &(y.vword.bptr->List.listhead->Realarray.a[0])); + } else if (CHECK_FLAG(curtstate->rng->info.property.typeFlags, RngTypeFlag(T_List))) { + /* They really want a list ... good luck with that */ + seeded = curtstate->rng->info.api.putSeed(T_List, 0, &(y.vword.bptr->List)); + } else { + runerr(113,y); + } + } else { + if (CHECK_FLAG(curtstate->rng->info.property.typeFlags, RngTypeFlag(Type(y)))) { + if (Pointer(y)) { + seeded = curtstate->rng->info.api.putSeed(Type(y),0 ,VarLoc(y)); + } else { +#ifdef DescriptorDouble + /* If it's not a string (or an array) and it's not a pointer */ + /* it must either be an integer or a real */ + if (Type(y) == T_Integer) { + seeded = curtstate->rng->info.api.putSeed(T_Integer, sizeof(IntVal(y)), &IntVal(y)); + } else { +#if 0 + /* ???????????? + * This causes rtt to complain + * rtt: file oasgn.r, line 170, warning: dx may be modified + * iconc does not handle conversion of modified parameter + * rtt: file oasgn.r, line 152, warning: dx may be modified + * iconc does not handle conversion of modified parameter + * rtt: file oasgn.r, line 170, warning: dy may be modified + * iconc does not handle conversion of modified parameter + * rtt: file oasgn.r, line 152, warning: dy may be modified + * iconc does not handle conversion of modified parameter + */ + GetReal(&y,r); +#else + r = RealVal(y); +#endif + seeded = curtstate->rng->info.api.putSeed(T_Real, sizeof(r), &r); + } +#else + /* If it's not a string (or an array) or a pointer, it must be an integer */ + seeded = curtstate->rng->info.api.putSeed(T_Integer, sizeof(IntVal(y)), &IntVal(y)); +#endif /* DescriptorDouble */ + } + } else { + runerr(113, y); + } + } + /* Mark the rng as "initialized" */ + if (seeded == 0) { + curtstate->hasSeed = 1; + } else { + fail; + } + } + } else +#endif /* RngLibrary */ #ifdef Arrays if ( Offset(x)>0 ) { /* don't know actual title, don't use checking BlkD macro */ diff --git a/src/runtime/oref.r b/src/runtime/oref.r index 5385919e7..f5740453f 100644 --- a/src/runtime/oref.r +++ b/src/runtime/oref.r @@ -391,7 +391,27 @@ operator{*} ! bang(underef x -> dx) end +#ifdef RngLibrary + +/* Check we have had a seed if a rng library is loaded. + * If not, call putSeed(nil) to warn the library that + * initialization is needed. + */ +#define CHECKINIT \ + if ((curtstate->rng != NULL) && (curtstate->hasSeed == 0)) { \ + if (curtstate->rng->info.api.putSeed(T_Null, 0, NULL) == 0) { \ + curtstate->hasSeed = 1; \ + } else { \ + fail; \ + } \ + } +#define RandVal ((curtstate->rng != NULL) \ + ? curtstate->rng->info.api.getRandomFpt() \ + : (RanScale*(k_random=(RandA*k_random+RandC)&0x7FFFFFFFL))) +#else +#define CHECKINIT /* No test needed */ #define RandVal (RanScale*(k_random=(RandA*k_random+RandC)&0x7FFFFFFFL)) +#endif /* RngLibrary */ "?x - produce a randomly selected element of x." @@ -414,6 +434,7 @@ operator{0,1} ? random(underef x -> dx) CURTSTATE(); #endif /* ConcurrentCOMPILER */ + CHECKINIT; /* * A string from a variable is being banged. Produce a one * character substring trapped variable. @@ -442,6 +463,7 @@ operator{0,1} ? random(underef x -> dx) CURTSTATE(); #endif /* ConcurrentCOMPILER */ + CHECKINIT; if ((val = StrLen(dx)) <= 0) fail; rval = RandVal; @@ -468,7 +490,7 @@ operator{0,1} ? random(underef x -> dx) #if ConcurrentCOMPILER CURTSTATE(); #endif /* ConcurrentCOMPILER */ - + CHECKINIT; if ((val = StrLen(dx)) <= 0) fail; rval = RandVal; @@ -494,6 +516,8 @@ operator{0,1} ? random(underef x -> dx) #if ConcurrentCOMPILER CURTSTATE(); #endif /* ConcurrentCOMPILER */ + + CHECKINIT; val = BlkD(dx,List)->size; if (val <= 0) fail; @@ -559,6 +583,7 @@ operator{0,1} ? random(underef x -> dx) CURTSTATE(); #endif /* ConcurrentCOMPILER */ + CHECKINIT; bp = BlkLoc(dx); val = Blk(bp,Table)->size; if (val <= 0) @@ -604,7 +629,7 @@ operator{0,1} ? random(underef x -> dx) #if ConcurrentCOMPILER CURTSTATE(); #endif /* ConcurrentCOMPILER */ - + CHECKINIT; bp = BlkLoc(dx); val = Blk(bp,Set)->size; if (val <= 0) @@ -645,6 +670,7 @@ operator{0,1} ? random(underef x -> dx) CURTSTATE(); #endif /* ConcurrentCOMPILER */ + CHECKINIT; rec = BlkD(dx, Record); val = Blk(rec->recdesc,Proc)->nfields; if (val <= 0) @@ -691,6 +717,7 @@ operator{0,1} ? random(underef x -> dx) CURTSTATE(); #endif /* ConcurrentCOMPILER */ + CHECKINIT; /* * x is an integer, be sure that it's non-negative. */ diff --git a/src/runtime/ralc.r b/src/runtime/ralc.r index 8c6ac29ec..f2e7ca263 100644 --- a/src/runtime/ralc.r +++ b/src/runtime/ralc.r @@ -636,6 +636,22 @@ struct b_cons *alccons(union block *data) return rv; } +#ifdef RngLibrary +/* + * Allocate an external block. + * size is the number of bytes of extra data required. + */ +struct b_external *alcext(uword size) +{ + struct b_external *rv; + uword bsize = (size + sizeof(struct b_external) - sizeof(rv->exdata)); + CURTSTATE(); + AlcBlk(rv, b_external, T_External, bsize); + rv->blksize = bsize; + return rv; +} +#endif /* RngLibrary */ + /* * allocate just a list header block. internal use only (alc*array family). */ diff --git a/src/runtime/rmemmgt.r b/src/runtime/rmemmgt.r index 39e000bdf..e842760dd 100644 --- a/src/runtime/rmemmgt.r +++ b/src/runtime/rmemmgt.r @@ -605,6 +605,30 @@ int region; markblock(&k_main); markblock(&k_current); +#ifdef RngLibrary + /* GC doesn't know about any descriptors in the T_External blocks. */ + /* NB. walk the chain of loaded libraries *before* marking the chain itself */ + /* (because, after marking the chain, the pointers are all backwards). */ + { + struct b_cons *rl; + struct rnglibchain *rngp; + for (rl = rngLibs; rl != NULL; rl = (struct b_cons *)(rl->next)) { + rngp = (struct rnglibchain *) rl->data; + postqual(&rngp->info.name); + } + } + + /* + * Mark the chain of loaded rng libraries. GC will follow + * the chain and mark each b_cons and the T_External block. + */ + if (rngLibs) markptr((union block **) &rngLibs); + + /* Add the default rng pointer to the basis */ + if (rngDefInfo != NULL) { + markptr((union block **) &rngDefInfo); + } +#endif /* RngLibrary */ /* * Mark &subject and the cached s2 and s3 strings for map. @@ -781,6 +805,11 @@ static void markthread(struct threadstate *tcp) if(!is:null(tcp->Kywd_ran)) { PostDescrip(tcp->Kywd_ran); } +#ifdef RngLibrary + if (tcp->rng != NULL) { + markptr((union block **)&(tcp->rng)); + } +#endif /* RngLibrary */ if(!is:null(tcp->K_current)) { PostDescrip(tcp->K_current); } diff --git a/src/runtime/rmisc.r b/src/runtime/rmisc.r index 665c98c71..1303818c6 100644 --- a/src/runtime/rmisc.r +++ b/src/runtime/rmisc.r @@ -150,9 +150,21 @@ int getvar(s,vp) return Succeeded; } else if (strcmp(s,"&random") == 0) { +#ifdef RngLibrary + if (curtstate->rng == NULL) { + vp->dword = D_Kywdint; /* Built-in generator */ + VarLoc(*vp) = &kywd_ran; + return Succeeded; + } else { + vp->dword = D_Intarray | F_RngState | F_Var; /* RNG library */ + VarLoc(*vp) = kywd_ran.vword.descptr; + return Succeeded; + } +#else vp->dword = D_Kywdint; VarLoc(*vp) = &kywd_ran; return Succeeded; +#endif /*RngLibrary */ } else if (strcmp(s,"&subject") == 0) { vp->dword = D_Kywdsubj; diff --git a/uni/unicon/preproce.icn b/uni/unicon/preproce.icn index bbe7fbe1b..592b47b1e 100644 --- a/uni/unicon/preproce.icn +++ b/uni/unicon/preproce.icn @@ -60,6 +60,7 @@ procedure predefs() "concurrent threads":"_CONCURRENT" "console window":"_CONSOLE_WINDOW" "dynamic loading":"_DYNAMIC_LOADING" + "loadable RNGs":"_RNG_LIBRARY" # "" environment variables "event monitoring":"_EVENT_MONITOR" "external functions":"_EXTERNAL_FUNCTIONS"