<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="rfc7991bis.rnc"?>  <!-- Required for schema
      validation and schema-aware editing --> 
<!-- <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?> --> 
<!-- This third-party XSLT can be enabled for direct transformations
in XML processors, including most browsers --> 

<!DOCTYPE rfc [
  <!ENTITY filename "draft-eastlake-rfc3797bis-03">
  <!ENTITY nbsp   "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<!-- If further character entities are required then they should be
added to the DOCTYPE above. Use of an external entity file is not
recommended. --> 
<?rfc strict="yes" ?>
<?rfc toc="yes"?>

<rfc
  xmlns:xi="http://www.w3.org/2001/XInclude"
  category="bcp"
  docName="&filename;"
  ipr="trust200902"
  obsoletes="3797"
  updates=""
  submissionType="IETF"
  xml:lang="en"
  version="3">
<!-- 
    * docName should be the name of your draft * category should be
    one of std, bcp, info, exp, historic * ipr should be one of
    trust200902, noModificationTrust200902, noDerivativesTrust200902,
    pre5378Trust200902 * updates can be an RFC number as NNNN *
    obsoletes can be an RFC number as NNNN
-->


<!-- ____________________FRONT_MATTER____________________ -->
<front>
   <title abbrev="Verifiable Random Selection">Publicly Verifiable
   Nominations Committee (NomCom) Random Selection</title>
   <!--  The abbreviated title is required if the full title is
        longer than 39 characters --> 

   <seriesInfo name="Internet-Draft"
               value="&filename;"/>

   <author fullname="Donald E. Eastlake 3rd" initials="D."
           surname="Eastlake">
     <organization>Futurewei Technologies</organization>
     <address>
       <postal>
         <street>2386 Panoramic Circle</street>
         <city>Apopka</city>
         <region>Florida</region>
         <code>32703</code>
         <country>USA</country>
       </postal>        
       <phone>+1-508-333-2270</phone>
       <email>d3e3e3@gmail.com</email>
       <email>donald.eastlake@futurewei.com</email>
     </address>
   </author>
   
   <date year="2023" month="6" day="23"/>

   <area>General</area>
   <workgroup>Network Working Group</workgroup>
   <!-- "Internet Engineering Task Force" is fine for individual
        submissions.  If this element is not present, the default is
        "Network Working Group", which is used by the RFC Editor as a
        nod to the history of the RFC Series. --> 

   <keyword/>
   <!-- Multiple keywords are allowed.  Keywords are incorporated
        into HTML output files for use by search engines. --> 

<abstract>
   <t>This document describes a method for making random selections in
   such a way as to promote public confidence in the unbiased nature
   of the choice. This method is referred to in this document as
   "verifiable selection". It focuses on the selection of the voting
   members of the IETF Nominations Committee (NomCom) from the pool of
   eligible volunteers; however, similar or, in some cases, identical
   techniques could be and have been applied to other cases. This
   document obsoletes RFC 3797.</t>
</abstract>
 
</front>


<!-- ____________________MIDDLE_MATTER____________________ -->
<middle>
    
<section>  <!-- 1. -->
  <name>Introduction</name>
  
 <t>This document describes a method for making random selections in
 such a way that as to promote public confidence in the
 unbiased nature of the choice. This method is referred to in this
 document as "verifiable selection". It focuses on the selection of
 the voting members of the IETF Nominations Committee (NomCom) from
 the pool of eligible volunteers; however, similar or, in some cases,
 identical methods could be and have been applied to other
 cases such as the following:</t>

 <ul>
   <li>This method as documented in <xref target="RFC2777"/> was used
   by IANA in February 2003 to determine the ACE prefix for
   Internationalized Domain Names ("xn--") <xref target="RFC5890"/> so
   as to avoid claim jumping.</li>
   
   <li>For fairness, this method as documented in <xref
   target="RFC3797"/> was sometimes used to determine the agenda order
   for the presentation of submissions to the effort which produced
   IEEE Std 802.11aq-2018.</li>
 </ul>

 <t>This document obsoletes <xref target="RFC3797"/>. The primary
 changes to that RFC are listed in <xref target="Changes3797"/>.</t>
 
 <t>Under the IETF rules, each year from among eligible volunteers as
 specified in <xref target="RFC9389"/> a set of people are randomly
 selected to be members of the IETF nominations committee
 (NomCom). The NomCom nominates members of the Internet Engineering
 Steering Group (IESG), the Internet Architecture Board (IAB), and
 other bodies as described in <xref target="RFC8713"/>.  The number of
 eligible volunteers in the early years of the use of the NomCom
 mechanism was around 50 but in recent years has been around 200.</t>

 <t>It is highly desirable that the random selection of the voting
 NomCom be done in an unimpeachable fashion so that no reasonable
 charges of bias or favoritism can be brought. This is as much for
 the protection of the selection administrator (currently, the
 appointed NomCom Chair) from suspicion of bias as it is
 for the protection of the IETF. </t>

 <t>A method meets this criterion if public information will enable
 any person to reproduce the selection process and have reasonable
 confidence that it is unbiased.  This document specifies such a
 method. </t>


 <section>
   <name>Requirements Language</name>

 <t>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
 NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED",
 "MAY", and "OPTIONAL" in this document are to be interpreted as
 described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/>
 when, and only when, they appear in all capitals, as shown here.</t>

 </section>
 
</section>

<section> <!-- 2. -->
  <name>General Flow of a Publicly Verifiable Process</name>

 <t>A selection of NomCom members or similar selection could follow
 the three steps given in the subsections below: Determination of the
 Pool, Publication of the Algorithm, and Publication of the
 Selection.</t>

 <section>
   <name>Determination of the Pool</name>

 <t>First, determine the pool from which the selection is to be
 made.</t>

 <t>For the IETF NomCom, this is as provided in <xref
 target="RFC9389"/> or its successor. Currently, volunteers are
 solicited by the selection administrator. Their names are then
 checked for eligibility.  The full list of eligible volunteers MUST
 be made public early enough that a reasonable amount of time can be
 given to resolve any disputes as to who should be in the pool before
 a deadline at which the pool is frozen. Although no one can be added
 after this deadline, the initial selection of someone included in the
 list who should not have been included can be easily handled as
 described below.</t>

 </section>
 <section>
   <name>Publication of the Algorithm</name>

 <t>The exact algorithm to be used, including the future public
 sources of randomness, is made public. For example, the members of
 the final list of eligible volunteers are ordered by publicly
 numbering them, some public future sources of randomness such as
 government run lotteries are specified, and an exact algorithm is
 specified whereby eligible volunteers are selected based on a hash
 function <xref target="RFC4086"/> of these future sources of
 randomness, such as the algorithm in this document.</t>

 </section>
 <section>
   <name>The Selection</name>

 <t>When the pre-specified sources of randomness produce their output,
 those values plus a summary of the execution of the algorithm for
 selection and its results SHOULD be announced so that anyone can
 verify that the correct randomness source values were used and the
 algorithm properly executed.</t>

 <t>For the IETF NomCom, the algorithm SHOULD be run to select, in an
 ordered fashion, a larger number than are actually necessary so that
 if any of those selected need to be passed over or replaced for any
 reason, an ordered set of additional alternate selections is
 available. Under some circumstances, additional rounds of Extended
 Selection may be useful as specified in <xref
 target="Extension"/>.</t>

 <t>A cut off time for any complaint that the algorithm was run with
 the wrong inputs or not faithfully executed MUST be specified for the
 initial selection and any extensions under <xref target="Extension"/>
 to finalize the output and provide a stable selection.</t>

 </section>
</section>

<section>  <!-- 3. -->
  <name>Randomness</name>

 <t>The crux of the unbiased nature of the selection is that it is
 based in an exact, predetermined fashion on random information which
 will be revealed in the future and cannot be known to the person
 specifying the algorithm.  That random information will be used to
 control the selection.  The random information MUST be such that it
 will be publicly and unambiguously revealed in a timely fashion.</t>

 <section>  <!-- 3.1 -->
   <name>Sources of Randomness</name>

 <t>The random sources MUST NOT include anything that a reasonable
 person would believe to be under the control or influence of the
 selection administrator. In the case of the IETF NomCom, that
 includes anything under the control or influence the IETF or its
 components, such as IETF meeting attendance statistics, numbers of
 documents issued, or the like.</t>

 <t>Examples of good information to use are winning lottery numbers
 for specified runnings of specified public lotteries.  Particularly
 for major government run lotteries, great care is taken to see that
 they occur on time (or with minimal delay) and produce random
 quantities.  Even in the very unlikely case one was to have been
 rigged, it would almost certainly be in connection with winning money
 in the lottery, not in connection with IETF use.  Other possibilities
 are such things as the daily balance in the US Treasury on a
 specified day, the volume of trading on the New York Stock exchange
 on a specified day, etc.  (However, the example code given below will
 not handle integers that are too large.)  Sporting events can also be
 used. Experience has indicated that individual stock prices and/or
 volumes are a poor source of unambiguous data due trading
 suspensions, company mergers, delistings, splits, multiple markets,
 etc. In all cases, great care MUST be taken to specify exactly what
 quantities are being used for randomness and what will be done if
 their issuance is cancelled, delayed, or advanced. </t>

 <t>It is important that the last source of randomness,
 chronologically, produce a substantial amount of the entropy needed.
 If most of the randomness has come from the earlier of the specified
 sources, and someone has even limited influence on the final source,
 they might do an exhaustive analysis and exert such influence so as
 to bias the selection in the direction they wanted.  Thus, it is
 RECOMMENDED that the last source be an especially strong and unbiased
 source of a large amount of randomness such as a major government run
 lottery. </t>

 <t>It is best not to use too many different sources.  Every
 additional source increases the probability that one or more sources
 might be delayed, cancelled, or just plain screwed up somehow,
 calling into play contingency provisions or, worst of all, creating
 an unanticipated situation.  This would either require arbitrary
 judgment by the selection administrator, defeating the randomness of
 the selection, or a re-run with a new set of sources, causing much
 delay in what, for the IETF NomCom, needs to be a time bounded
 process.  Three or four would be a good number of randomness sources.
 More than five is too many. </t>

 </section>
 <section>  <!-- 3.2 -->
   <name>Skew</name>

 <t>Some of the sources of randomness produce data that is not
 uniformly distributed.  This is certainly true of volumes, prices,
 and horse race results, for example.  However, use of a strong mixing
 function <xref target="RFC4086"/> will extract the available entropy
 and produce a hash value whose bits and whose remainder modulo a
 small divisor, only deviate from a uniform distribution by an
 insignificant amount.</t>

 </section>
 <section>  <!-- 3.3 -->
   <name>Entropy Needed</name>

 <t>What we are doing is selecting N items without replacement from a
 population of P items.  The number of different ways to do this is as
 follows, where "!" represents the factorial function:</t>

<artwork type="ascii-art" align="center">
  <![CDATA[
     P!
-------------
N! * (P - N)!
  ]]>
</artwork>

 <t>To do this in a completely random fashion requires as many random
 bits as the logarithm base 2 of that quantity.  Some example
 approximate calculated number of random bits for the completely
 random selection of 10 items, such as IETF NomCom members, or 1 item,
 from various pool sizes are given below:</t>

<table align="center">
  <thead>
<tr><th colspan="9">Completely Random Selection of One or Ten Items
From A Pool</th></tr>
  </thead>
  <tbody>
<tr>
<td>Pool size</td><td align="right">60</td><td
align="right">80</td><td align="right">100</td><td
align="right">125</td><td align="right">150</td><td
align="right">175</td><td align="right">200</td><td
align="right">250</td>
</tr>
<tr>
<td>Bits needed to select 1</td><td
align="right">5.9</td><td align="right">6.3</td><td
align="right">6.6</td><td align="right">7.0</td><td
align="right">7.2</td><td align="right">7.4</td><td
align="right">7.6</td><td align="right">8.0</td>
</tr>
<tr>
<td>Bits needed to select 10</td><td
align="right">36</td><td align="right">41</td><td
align="right">44</td><td align="right">47</td><td
align="right">50</td><td align="right">52</td><td
align="right">54</td><td align="right">58</td>
</tr>
  </tbody>
</table>

 <t>Using a smaller number of bits means that not all of the possible
 selections would be available, for example not all sets of 10 if 10
 things are being selected.  For a substantially smaller amount of
 entropy, if multiple things are being selected, there could be a
 correlation between the selection of two different members of the
 pool.  However, as a practical matter, for pool sizes likely to be
 encountered in IETF NomCom membership selection, 42 bits of entropy
 should be adequate to randomly select 10 items as discussed in <xref
 target="EqNumbers"/>. </t>

 <t>The current USA Power Ball and Mega Millions lottery drawings have
 23.5 bits of entropy each in the five selected regular numbers and
 about 6 bits of entropy each in the Power Ball / Mega Ball. A
 four-digit daily numbers game drawing that selects four decimal
 digits has a bit over 13 bits of entropy.</t>

 <t>The source code in <xref target="Source"/> uses the SHA-256 <xref
 target="RFC6234"/> hash function which has 256 bits of output and
 therefore can preserve no more than that number of bits of entropy.
 However, this is very much more than what is likely to be needed for
 IETF NomCom membership selection. </t>

 </section>
</section>

<section anchor="SpecificAlg">  <!-- 4. -->
  <name>A Specific Algorithm for Initial Selection</name>

 <t>It is important that a precise algorithm be given for
 canonicalizing and mixing the random sources being used and making
 the selection based thereon.  Sources suggested above produce either
 a single positive number (i.e., NY Stock Exchange volume in thousands
 of shares) or a small set of positive numbers (many lotteries provide
 6 numbers in the range of 1 through 70 or the like, a sporting event
 could produce the scores of two teams, etc.).  A suggested precise
 algorithm is as follows:</t>

 <ol>
   <li><t>For each source producing one or more numeric values, each
   value is canonicalized by representing the value as a decimal
   number terminated by a period (or with a period separating the
   whole from the fractional part), without leading zeroes except for
   a single leading zero if the integer part is zero, and without
   trailing zeroes on the fractional part after the period. Some
   examples follow:</t>

<table align="center">
  <thead>
    <tr><th align="center">Input</th><th>Canonicalized</th></tr>
  </thead>
  <tbody>
<tr><td align="center">0</td><td align="center">0.</td></tr>
<tr><td align="center">0.0</td><td align="center">0.</td></tr>
<tr><td align="center">42</td><td align="center">42</td></tr>
<tr><td align="center">7.0</td><td align="center">7.</td></tr>
<tr><td align="center">013.</td><td align="center">13.</td></tr>
<tr><td align="center">.420</td><td align="center">0.42</td></tr>
<tr><td align="center">12.34</td><td align="center">12.34</td></tr>
<tr><td align="center">1.2340</td><td align="center">1.234</td></tr>
  </tbody>
</table>
   </li>
   
   <li>If a source produced multiple values, order those values from
   smallest to the largest.  This sorting is necessary because the
   same lottery results, for example, are sometimes reported in the
   order numbers were drawn and sometimes in numeric order and such
   things as the scores of two sports teams that play a game have no
   inherent order.</li>
   
   <li>If a source produced multiple values, concatenate them and
   suffix the result with a "/".  If a source produced a single
   number, simply represent it as above with an added "/" suffix.</li>

   <li>At this point you have a string for each source, say s1/, s2/,
   ... for source 1, source 2, ... Concatenate these strings in a
   pre-specified order, the order in which the sources were listed
   when they were announced if no other order is specified, and
   represent each character as its ASCII code <xref target="RFC0020"/>
   producing "s1/s2/.../" as the random seed from which selection is
   derived.</li>

   <li>Produce a sequence of random values derived from a mixing of
   these sources by calculating the SHA-256 hash <xref
   target="RFC6234"/> of the seed specified in step 4 prefixed and
   suffixed with an all zeros two-byte sequence for the first value,
   the string prefixed and suffixed by 0x0001 for the second value,
   etc., treating the two bytes as a big-endian counter.  Treat each
   of these derived "random" MD5 output values as a positive 128-bit
   multiprecision big endian integer.</li>

   <li>Finally, impose a total pseudo-random ordering on the pool of
   listed items (e.g., NomCom volunteers) as follows: If there are P
   pool members, select the first by dividing the first derived random
   value by P and using the remainder plus one as the position of the
   selectee in the published list.  Select the second by dividing the
   second derived random value by P-1 and using the remainder plus one
   as the position in the list with the first selected person
   eliminated.  And so on.</li>

 </ol>

 <t>Any ambiguity in the above procedure is resolved by consulting the
 example code below.</t>

 <t>Use of alphanumeric random sources is NOT RECOMMENDED due to the
 much greater difficulty in canonicalizing them in an independently
 repeatable fashion; however, if the administrator of the selection
 process chooses to ignore this advice and use an ASCII or similar
 Roman alphabet source or sources, all white space, punctuation,
 accents, and special characters should be removed, and all letters set
 to upper case.  This will leave only an unbroken sequence of letters
 A-Z and digits 0-9 which can be treated as a canonicalized single
 number above and suffixed with a "./".  The administrator MUST NOT
 use even more complex and harder to canonicalize quantities such as
 complex numbers or UNICODE international text.</t>

</section>

<section anchor="Extension">  <!-- 5. -->
  <name>Extended NomCom Selection</name>

 <t>There may be reasons why one or more of the selected members of
 the pool need to be eliminated and further selections made. This is
 particularly true for the IETF NomCom given the strong recommendation
 above that, in case of doubt or not-yet-resolved eligibility dispute,
 possible pool members should be left in the pool with the
 understanding that, in the event they are initially selected, they
 can be later eliminated should it be decided they are not
 eligible. For the IETF NomCom, there are two types of reasons for
 elimination as follows:</t>

 <dl>
   
   <dt>A.</dt><dd><t>Elimination due to simple rule enforcement by the
   administrator.  Examples would be someone that did not meet the
   eligibility requirements or whose inclusion would violate the rule
   limiting the number of voters with the same sponsor or all but one
   occurrence of someone included multiple times due to a name change
   or similar confusion. When there are such eliminations in the
   initial selectees, the administrator simply goes further down the
   ordered list produced with the initial randomness sources until
   there are the desired number of selectees who are not eliminated by
   such decisions.  The administrator SHOULD announce who has been
   eliminated and the reason for the administrator's decision to
   eliminate them.</t></dd>

   <dt>B.</dt><dd><t>Eliminations due to a selectee, that is,
   agreement from the selectee to serve cannot be obtained by the
   administrator before a deadline established by the administrator.
   For example, either the selectee declines to serve or, despite
   reasonable efforts, the selectee is not adequately contactable.</t>

   <t>(The elimination of someone due to non-contactability may work a
   hardship for that individual if it was due to no fault of their own
   and they wanted to serve. But there is no reasonable alternative if
   a NomCom voting membership of volunteers with a confirmed agreement
   to serve is to be finalized in a timely manner. Since someone so
   eliminated will, as provided below, be replaced by another randomly
   selected pool member, there is no problem from the point of view of
   NomCom composition.)</t></dd>

 </dl>

 <t>It will frequently be the case that, after the initial selection
 from the pool and the handling of any Type A eliminations as above,
 there will be a small number of Type B eliminations. If no further
 actions were taken, there will be an insufficient number of people
 selected and not eliminated. If selection were extended in this case
 by just going further down the ordered list, as with Type A
 eliminations, this would give initially selected persons the ability
 to, by declining to serve, in effect, transfer their voting NomCom
 membership to a known different person since the entire initial
 ordered list is, at that point, publicly known. Some perceive this as
 a problem, so it is resolved by the administrator iteratively using
 what is essentially a miniature version of the initial selection to
 re-randomize the remaining pool members as follows:</t>

 <ol>

   <li>The administrator, when or before the algorithm is announced,
   determines a secret random number R possibly using the techniques
   given in <xref target="SpecificAlg"/> using secret sources of
   randomness which MUST be different from those publicly announced
   for the initial selection. The administrator MUST record this
   secret random number and SHOULD record its randomness
   source(s). The administrator then calculates and records a hash
   chain using the SHA-256 <xref target="RFC6234"/> hash function,
   denoted as H, as follows: denote H(R) as H[1](R), H(H(R)) =
   H(H[1](R)) as H[2](R), H(H(H(R))) = H(H[2](R)) as H[3](R),
   ... H(H[N-1](R))) as H[N](R), where N is a number chosen by the
   administrator as the maximum number of times it might be necessary
   to extend selection due to Type B eliminations. It would always be
   safe to set N to the size of the pool minus the number of people to
   be selected but, as a practical matter for IETF NomCom selection,
   an N or 25 should be a very generous allowance.</li>
   
   <li>The new pool consists of the initial pool in the same order
   without any selectees who have agreed to serve and without any pool
   members eliminated by any earlier Type A or B eliminations.</li>

   <li>The new randomness is the next earlier value in the hash chain,
   that is H[N - 1](R).  This random source is treated as an
   additional source added to the initially announced list of random
   sources as the last source and is processed as specified resulting
   in it being suffixed to the seed produced by the initial randomness
   sources. (See worked example and the example code below.)</li>

   <li>The administrator publicly announces the selectees who were not
   eliminated, how many additional selections are needed, and H[N -
   1](R). Since H[N(R) was previously made public, anyone can check
   that the administrator has correctly announced H[N - 1](R) by
   calculating H(H[N - 1](R)) and comparing it with H[N](R). The
   administrator announces the extended selections and any further
   extension of the extended selections due to Type A eliminations as
   above.</li>

   <li>The administrator still needs to check for Type B eliminations
   among the new Extended Selection selectees. At this point in the
   process, the time constraints are likely to be very tight so
   contacting extensions selectees to be sure they are still willing
   to serve MUST be done urgently and with a very tight deadline.
   Since there may be further Type B eliminations among the extended
   selectees, more than one cycle of Extended Selection may be
   needed. If so, steps 2 through 5 are repeated with minor
   modifications as follows: For Step 2, those in the pool before the
   next extension are all those from the pool who have not been
   selected or been subject to Type A or Type B elimination so far. In
   particular, note that because they have been previous eliminated
   and to avoid various complex disputes and timing race conditions,
   someone who was uncontactable or declined to serve in an earlier
   round does NOT become eligible for later rounds even if they later
   become contactable or change their mind about declining. For Step
   3, the next earlier hash in the hash chain is used as the
   additional randomness; when multiple selection extensions have to
   be run, the additional randomness does not pile up making the
   pseudo-random seed longer and longer but rather each extension's
   additional randomness hash value is used with the initial random
   sources. In Step 4 the hash chain value announced is H[N-E](R)
   where this is the Eth Selection Extension.</li>
   
 </ol>

 <t>The use of a hash chain, as in step 1 above, is a well known
 technique that first appeared in <xref target="Lamport"/> and is used
 in <xref target="RFC1760"/>. Because the hash function H is assumed
 to be non-invertible, the public announcement of H[N](R) or any other
 value in the chain does not reveal any earlier values in the hash
 chain. While the administrator could try various values of R and
 could thus influence the value of H[N](R) or other H[*](R), this does
 not provide any control over the selections because the hash chain
 value is combined with the output of the pre-specified public
 randomness sources.</t>
 
 <t>Multiple extension cycles may be required so the
 selection administration should allow enough time for at least 5 or
 so of them. For example, in the selection of the 2022/2023 NomCom, 3
 extensions would have been required: The pool was, by historical
 standards, huge, with 267 members, the largest ever. In the initial
 selection, one of the 10 potential selectees was Type B eliminated
 because confirmation of their willingness to serve could not be
 obtained in a timely fashion. In the 1st Extended Selection, the 11th
 potential selectee was Type B eliminated because they declined to
 serve and the 12th was Type A eliminated because there were already
 two selectees with the same sponsor. In the 2nd Extended Selection,
 the 13th potential selected also declined to serve. In the 3rd
 Extended Selection, the 14th potential selectee became the final
 voting member of the Nomcom when they confirmed their willingness to
 serve.</t>

</section>

<section>  <!-- 6. -->
  <name>Handling Real World Problems</name>

 <t>In the real world, problems can arise in following the steps and
 flow outlined in the sections above. Some problems that have actually
 arisen are described below with recommendations for handling
 them.</t>

 <section>
   <name>Uncertainty as to the Pool</name>

 <t>Every reasonable effort should be made to see that the published
 pool, from which selection is made, is of certain and eligible
 persons.  However, especially with compressed schedules or perhaps
 someone whose claim that they volunteered and/or are eligible has not
 been resolved by the deadline, or a determination that someone is not
 eligible which occurs after the publication of the pool, or the like,
 there may still be uncertainties.</t>

 <t>The best way to handle this is to maintain the announced schedule
 in so far as possible, INCLUDE in the published pool all those whose
 eligibility is uncertain and to keep the published pool list
 numbering IMMUTABLE after it is frozen.  If one or more people in
 the pool are later selected by the algorithm and random input but it
 has been determined they are ineligible, they can be skipped and
 subsequently selected persons used.  (This is referred to above as a
 Type A elimination.) Thus, the uncertainty only effects one selection
 and in general no more than a maximum of U selections where there are
 U uncertain pool members.</t>

 <t>Other courses of action are far worse.  Actual insertion or
 deletion of entries in the pool after its publication changes the
 length of the list and scrambles who is selected. Even if done before
 the random numbers are known, such dinking with the list after its
 publication looks bad.  To avoid schedule slips, there MUST be clear
 fixed firm public deadlines and someone who challenges their absence
 from the pool after the published deadline MUST have their challenge
 automatically denied for tardiness even if their delay is not the
 fault of the challenger.</t>

 </section>

 <section>
  <name>Randomness Ambiguities</name>

 <t>The best good faith efforts have been made to specify precise and
 unambiguous sources of randomness.  These sources have been made
 public in advance and there has not been objection to them.  However,
 it has happened that when the time comes to actually get and use this
 randomness, the real world has thrown a curve ball and it isn't quite
 clear what data to use.  Problems have particularly arisen in
 connection with individual stock prices, volumes, and financial
 exchange rates or indices.  If volumes that were published in
 thousands are published in hundreds, you have a rounding problem.
 Prices that were quoted in fractions or decimals can change to the
 other.  If you take care of every contingency that has come up in the
 past, you might be hit with a new one.  When this sort of thing
 happens, it is generally too late to announce new sources, an action
 which could raise suspicions of its own as well as causing
 substantial delay.  About the only course of action is to make a
 reasonable choice within the ambiguity and depend on confidence in
 the good faith of the selection administrator.  With care, such cases
 should be extremely rare.</t>

 <t>Based on these experiences, it is again recommended that public
 lottery numbers or the like be used as the random inputs and
 financial volumes or prices avoided.</t>
 
 </section>
</section>  <!-- 6. -->

<section>  <!-- 7. -->
  <name>Fully Worked Example</name>

<t>&gt;&gt; EXAMPLE NEEDS TO ALSO COVER THE SECTION 5 EXTENSION
PROVISIONS. &lt;&lt;</t>

<ol>

 <li><t>Assume the eligible volunteers published in advance of selection
 are the numbered list of 31 past NomCom Chairs appearing below in
 Appendix A.</t></li>

 <li><t>Assume the following (fake example) ordered list of randomness
 sources:</t>

 <t>2.1 The Kingdom of Alphaland State Lottery daily number
 for 1 November 2025 treated as a single five-digit integer.</t>

 <t>2.2 (a) The People's Democratic Republic of Betastani State
 Lottery six winning numbers for 1 November 2025 and then (b) the
 seventh "extra number" for that day as if it was a separate random
 source.</t>
 </li>
 
</ol>

<t>Hypothetical randomness publicly produced:</t>
<t indent="2">Source 1:  29319</t>
<t indent="2">Source 2a:  9, 61, 26, 34, 42, 41</t>
<t indent="2">Source 2b:  55</t>

<t>Resulting seed string:</t>

<t indent="4">29319./9.26.34.41.42.61./55./</t>

<t>The table below gives the hex of the MD-5 of the above key string
bracketed with a two-byte string that is successively 0x0000, 0x0001,
0x0002, through 0x0010 (16 decimal).  The divisor for the number size
of the remaining pool at each stage is given and the index of the
selectee as per the original number of those in the pool.</t>

<table>
  
  <thead>
<tr><th>index</th><th align="center">Base64 value of
SHA-256</th><th>div</th><th>selected</th></tr>
  </thead>

  <tbody>
    <tr><td
    align="right">1</td><td>fgSNUcziqvUcd1j46xGZdpLQmgyW+OZzGfJAx2/EyS0=</td>
    <td>31</td><td>&gt; 4 &lt;</td></tr>
    <tr><td
    align="right">2</td><td>kMd2sgTSiCF1o11lM6Rs8yeQeRMLPnZo5k0wSFPMjHw=</td>
    <td>30</td><td>&gt; 30 &lt;</td></tr>
    <tr><td
    align="right">3</td><td>pwrk69jq8cUF5KrD0vg31SQMOvtf5117Y6Ox5cm38f0=</td>
    <td>29</td><td>&gt; 19 &lt;</td></tr>
    <tr><td
    align="right">4</td><td>KRXZEdXGiprKvqQ2aSnzYQpzaE0YwlfyDTBBI+R8kv8=</td>
    <td>28</td><td>&gt; 13 &lt;</td></tr>
    <tr><td
    align="right">5</td><td>K2qq2NImq28ESPaVB9uCVrI0tPT/NOYAtryUcjGpzt8=</td>
    <td>27</td><td>&gt; 7 &lt;</td></tr>
    <tr><td
    align="right">6</td><td>8PQ4tm652Kr8yV2D2OBKAYrKxWtkddxqtiMvIuknhgU=
    </td> <td>26</td><td>&gt; 22 &lt;</td></tr>
    <tr><td
    align="right">7</td><td>fJQRVYErqgAmJAs7a01/SoACdnCBNcqzrGbUsFticjM=</td>
    <td>25</td><td>&gt; 12 &lt;</td></tr>
    <tr><td
    align="right">8</td><td>wlfiQaw6S/bxcbT2u+7oshpAFxrsy6wIZyFD+uWle80=</td>
    <td>24</td><td>&gt; 28 &lt;</td></tr>
    <tr><td
    align="right">9</td><td>ekEoRHYTkT6p5m2fP3mn354kQSI1pz/B1RKC+Fa8YXA=</td>
    <td>23</td><td>&gt; 15 &lt;</td></tr>
    <tr><td
    align="right">10</td><td>ggmvds6SzOGPwr8vUwSPNHtk7WIsQLYiO2tl0V3yzZQ=</td>
    <td>22</td><td>&gt; 11 &lt;</td></tr>
    <tr><td
    align="right">11</td><td>ntjVm6AGBtydG6l9aiTSSojdcp6UcYhk55Rg71y0Z+s=</td>
    <td>21</td><td>&gt; 5 &lt;</td></tr>
    <tr><td
    align="right">12</td><td>CE14MeW+JUzb+D/gQ82dJF62NBapfROt7Ff2ngkT/XE=</td>
    <td>20</td><td>&gt; 27 &lt;</td></tr>
    <tr><td
    align="right">13</td><td>ZRYzTo0OZ0ASx5keWlh3YH1Di4o9p5jefz+MCWmWjFk=</td>
    <td>19</td><td>&gt; 23 &lt;</td></tr>
    <tr><td
    align="right">14</td><td>lvA2rjCw7sT0+SVNOZB29HZOVvIAiS3yA85wqE9ugPk=</td>
    <td>18</td><td>&gt; 6 &lt;</td></tr>
    <tr><td
    align="right">15</td><td>aQy+Eof9q4MbDZam/D+Sxc5yLixLYdArJ6kr1KmrbKA=</td>
    <td>17</td><td>&gt; 14 &lt;</td></tr>
  </tbody>
  
</table>

 <t>Resulting first ten selected, in order selected:</t>

 <table>
   <tbody>
<tr><td> 1.  G. Huston (4)</td><td> 6.  M. Richardson (22)</td></tr>
<tr><td> 2.  R. Salz (30)</td><td> 7.  D. McPherson (12)</td></tr>
<tr><td> 3.  S. Krishnan (19)</td><td> 8.  B. Stark (28)</td></tr>
<tr><td> 4.  R. Droms (13)</td><td> 9.  L. Dondet (15)</td></tr>
<tr><td> 5.  A. Doria (7)</td><td> 10.  R. Draves (11)</td></tr>
   </tbody>
 </table>

 <t>Should one of the above turn out to be ineligible or otherwise be
 eliminaged by a Type A reason, the next would be M. St.Johns, number
 5.</t>

</section>

<section>  <!-- 8. -->
  <name>Security Considerations</name>

 <t>Careful choice should be made of randomness inputs so that there
 is no reasonable likelihood that they are under the control of the
 administrator.  Guidelines given above to use a reasonably small
 number of inputs with a substantial amount of entropy from the last
 should be followed.  And equal care needs to be given that the
 algorithm selected is faithfully executed with the designated inputs
 values.</t>

 <t>Publication of the random inputs and results, including the hash
 chain seed R (<xref target="Extension"/>), and something like a
 one-week window for the community of interest to duplicate the
 calculations and protest if there is any discrepancy should give a
 reasonable assurance of faithful implementation and execution.</t>

</section>

<section anchor="IANA"> <!-- 9. -->
  <name>IANA Considerations</name>
  
  <t>This document requires no IANA actions.</t>
  
</section>

<section anchor="Source"> <!-- 10. -->
  <name>Source Code</name>

<t>The C source code below makes use of the SHA-256 reference code
from <xref target="RFC6234"/>.  The original code in <xref
target="RFC2777"/> was written by Donald Eastlake except for the code
dealing with multiple floating point number input which was written by
Matt Crawford. The <xref target="RFC2777"/> code could only handle
pools of up to 255 members and was extended to 2**16-1 by Erik
Nordmark for the code in <xref target="RFC3797"/>.  Both of these
earlier versions used MD-5 <xref target="RFC1321"/> rather than
SHA-256.</t>

<t>Python code by Rich Salz to implement the method in <xref
target="RFC3797"/> is available at
https://github.com/richsalz/ietf-rfc3797</t>

<t>The code below has been extracted from this document, compiled, and
tested.  While no flaws were found, it is possible that when used
with some compiler on some system under some circumstances some flaw
will manifest itself.</t>

<sourcecode type="C" markers="true">
  <![CDATA[
<< CODE HAS NOT YET BEEN UPDATED TO COVER EXTENDED SELECTION. >>

//*****************************************************************
/*  Example code for
 *      "Publicly Verifiable Random Selection"
 *          Donald E. Eastlake 3rd
 *              Original February 2004
 *              Updated August 2022 - June 2023
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, is permitted pursuant to, and subject
 * to the license terms contained in, the Revised BSD License
 * set forth in Section 4.c of the IETF Trust's Legal Provisions
 * Relating to IETF Documents
 * (http://trustee.ietf.org/license-info).                       */
//*****************************************************************

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <ctype.h>

//  SHA-256, RFC 6234
#include "sha.h"


// CONSTANTS
#define MAXLINE 256

//  Local prototypes in alphabetic order
//*****************************************************************
void     b64print ( uint8_t *p, int length );
void     b64toHex ( void );
int      b64v ( char );
long int getinteger ( char *prompt );
int      getNP ( void );
int      getSeed ( char *key );
void     hashChain ( void );
void     hexprint ( uint8_t *p, int length );
void     hexToB64 ( void );
int      longremainder ( unsigned int divisor,
                         uint8_t hash[SHA256HashSize] );
double   NPentropy ( void );
void     probe ( void );    // RFC3797 but with SHA-256
void     testSHA256 ( void );
void     xprintf ( char *message, int x );


//  Global Variables
//*****************************************************************
char    tin[MAXLINE+2];  // type in buffer
int     debug = 0; // debug level
int     keysize;
char    key[800];  // where key string is accumulated
unsigned int    N; // Number of items to be selected
unsigned int    P; // Size of pool
char    b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      "abcdefghijklmnopqrstuvwxyz0123456789+/";


//  Main driver/dispatch routine
//*****************************************************************
int main ( int argc, const char * argv[] ) {
char       *cherr;
int         i, ioerr;
char        ch;
    
nextcommand:
xprintf ( "How may I serve you? ", 101 );
cherr = fgets( tin, MAXLINE, stdin );   // get commeand
if ( cherr == NULL )
    exit ( 102 );
for ( i=0; i < MAXLINE; ++i ){
    ch = tin[i];
    if ( debug > 0 ) {
        ioerr = printf ( "%s%X%s",
            "Processing character 0X", ch, "\n");
        if ( ioerr <= 0 )
            exit ( 103 );
        }
    switch ( ch ) {
        case '?': // help
            xprintf ( " ? -> Help\n"
            " d -> set debug level\n"
            " e -> entropy needed\n"
            " h -> hash chain\n"
            " p -> select from pool\n"
                      " q -> quit\n", 104 );
            if ( debug )
                xprintf ( " t -> test SHA-256\n"
                " 8 -> hex to base64\n"
                        " 9 -> base64 to hex\n", 105
                    );  // falls through
        case 0: // "gets" string is zero terminated
            goto nextcommand;
        case ' ': case '\n': case '\t': // skip white space
        case'\v': case '\r': case '\f': case '\b': case 127:
            continue;  // try next character
        case 'd': case 'D': // set debug level
            debug = (int)getinteger ( "Set debug level" );
            goto nextcommand;
        case 'e': case 'E':  // calculate entropy needed
            if ( !getNP ( ) )
                NPentropy ( );
            goto nextcommand;
        case 'h': case 'H': // calculate hash chain
            if ( !getSeed ( key ) )
                hashChain ( );
            goto nextcommand;
        case 'p': case 'P':  // select from pool
            if ( !getNP ( ) && !getSeed ( key ) )
                probe ( );
            goto nextcommand;
        case 'q': case 'Q': case '\a':  // quit
            exit ( 0 );
        case 't': case 'T':
            testSHA256 ( );
            goto nextcommand;
        case '8':
            hexToB64 ( );
            goto nextcommand;
        case '9':
            b64toHex ( );
            goto nextcommand;
        default:
            ioerr = printf ( "%s%s%s",
                             "Undefined command: ",
                             tin, "\n");
            if ( ioerr <= 0 )
                exit ( 106 );
            goto nextcommand;
        }  // end switch
    }  // end for
}  // end main


//  print as base64
//*****************************************************************
void b64print ( uint8_t *p, int length ) {
uint8_t   nib;
int      ioerr;

while ( length > 0 ) {
    nib = p[0] >> 2;
    ioerr = printf ( "%c", b64[nib] ); // print 1st 6 bits
    if ( ioerr <= 0 )
      exit ( 1000 );
    nib = ( p[0] & 0x3 ) << 4; // get bottom 2 bits of 1st byte
    if ( --length ) {
      nib += ( p[1] >> 4 ); // get top 4 bits of 2nd byte
      ioerr = printf ( "%c", b64[nib] ); //print 2nd 6 bits
      if ( ioerr <= 0 )
        exit ( 1001 );
      nib = ( p[1] & 0xF ) << 2; // get bottom 4 bits of 2nd byte
      if ( --length ) {
        nib += ( p[2] >> 6 ); // get top 2 bits of 3rd byte
        ioerr = printf ( "%c%c", b64[nib], b64[ p[2] & 0x3F ] );
        if ( ioerr <= 0 )
          exit ( 1002 );
      }
      else { // length was 2, print rest of 2nd byte
        ioerr = printf ( "%c=", b64[nib] );
        if ( ioerr <= 0 )
          exit ( 1003 );
      }
    }
    else { // length was 1, print rest of 1st byte
      ioerr = printf ( "%c==", b64[nib] );
      if ( ioerr <= 0 )
        exit ( 1004 );
    }
    p += 3;
    --length;
} // while
} // end b64print


//  read base64, print as hex
//*****************************************************************
void b64toHex ( void ) {
char       clean[MAXLINE];
uint8_t    val64[((MAXLINE*3)/4)+2];
int        i, j, k, v;
int        equalsigns = 0;
char      *cherr;

xprintf ( "Type some Base64: ", 901 );
cherr = fgets ( tin, MAXLINE, stdin );
if ( cherr == NULL )
    exit ( 902 );
for ( i = 0, j = 0; i < MAXLINE; ++i ) {
    if ( ( tin[i] == '\n' ) || ( tin[i] == 0 ) )
        break;  // end of the line
    if ( isspace ( tin[i] ) )
        continue;  // skip white space
    if ( isalnum ( tin[i] ) ||
         ( tin[i] == '+' ) || ( tin[i] == '/') ) {
        if ( equalsigns ) {
            xprintf ( "Stuff after an equal sign.\n", 803 );
            return;
            }
        clean[j] = tin[i];
        ++j;
        continue;
        }
    if ( tin[i] == '=' ) {
        switch ( equalsigns ) {
            case 0:
                    v = j % 4;
                if ( ( v != 2 ) && ( v != 3 ) )
                    xprintf ( "Wrong length before '='.\n",
                                  904 );
                // fall through
            case 1:
                    ++equalsigns;
                    break; // out of switch equalsigns
            case 2:
                    xprintf ( "Too many equal signs.\n", 905 );
                return;
            } // switch equalsigns
        } // if equal sign
    } // for i
clean[j] = 0;
if ( debug ) {
    hexprint ( (uint8_t *)clean, j+1 );
    xprintf ( " ", 907 );
    }
v = j % 4;
if ( v == 1 )
    xprintf ( "Wrong length.\n", 906 );
for ( i = 0, k = 0; i < j; i += 4, k += 3 ) {
val64[k] = ( b64v ( clean[i] ) << 2 ) |
           ( ( b64v ( clean[i+1] ) >> 4 ) & 0xF );
if ( ( i + 2 ) < j ) {
    val64[k+1] = ( b64v ( clean[i+1] ) << 4 ) |
                 ( ( b64v ( clean[i+2] ) >> 2 ) &0xF );
    if ( ( i + 3 ) < j ) {
        val64[k+2] = ( b64v ( clean[i+2] ) << 6 ) |
                         b64v ( clean[i+3] );
        }
    }
} // for i
hexprint ( val64, ( (j*3)/4 ) );
xprintf ( "\n", 908 );
} // end b64toHex


//  convert a base64 char to int
//*****************************************************************
int b64v ( char ch ) {
int     i;

for ( i = 0; i < 64; ++i )
    if ( ch == b64[i] )
        return i;
exit ( 999 );
}


//  prompt for and get an integer input
//*****************************************************************
long int getinteger ( char *prompt ) {
long int    i;
char        *cherr;
int         j, ioerr;

nexttry:
ioerr = printf ( "%s", prompt );
if ( ioerr < 0 )
    exit ( 201 );
xprintf ( " (or 'quit' to exit) ", 202 );
cherr = fgets ( tin, MAXLINE, stdin  );
if ( cherr == NULL )
    exit ( 203 );
j = sscanf ( tin, "%ld", &i );
if ( ( j == EOF ) ||
     ( !j && ( ( tin[0] == 'q' ) ||
             ( tin[0] == 'Q' ) ) ) )
    exit ( j );
if ( j == 1 )
    return i;
goto nexttry;
} // end getinteger


//  get pool size and number of items to pick
//  returns zero for success, non-zero for failure
//****************************************************************
int getNP ( void ) {
    
P = (unsigned int)getinteger ( "Type size of pool:" );
if ( ( P > 65535 ) ||
     ( P <= 0 ) ) {
    xprintf ( "Pool zero, negative, or too big.\n", 301 );
    return ( 1 );
}
N = (unsigned int)getinteger (
        "Type number of items to be selected:" );
if ( N > P ){
    xprintf ( "Pool too small.\n", 302 );
    return ( 1 );
}
return ( 0 );  // got possibly reasonable values
} // end getNP


//  get the "random" inputs. echo back to user so the user may
//  be able to tell if truncation or other glitches occur.
//
//  Up to 16 inputs each of which can be either up to 16 integers
//      or up to 16 floating point numbers
//
//  output 1 for failure, 0 for success
//****************************************************************
int getSeed ( char *key ) {
long int    temp, array[16];
int         i, ioerr, j, k, k2;
char        sarray[16][256];
char        *cherr;
    
for ( i = 0, keysize = 0; i < 16; ++i ) {
    if ( keysize > 511 ) {
        xprintf ( "Too much input.\n", 400 );
        return ( 1 );
    }
    ioerr = printf (
        "Type #%d randomness or 'end' followed by new line.\n"
        "Up to 16 integers or the word 'float' followed by up\n"
        "to 16 x.y format reals.\n", i+1 );
    if ( ioerr <= 0 )
        exit ( 401 );
    cherr = fgets ( tin, MAXLINE, stdin );
    if ( cherr == NULL )
        exit ( 402 );
    j = sscanf ( tin,  // try to parse as "long int"s
                "%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld%ld",
                &array[0], &array[1], &array[2], &array[3],
                &array[4], &array[5], &array[6], &array[7],
                &array[8], &array[9], &array[10], &array[11],
                &array[12], &array[13], &array[14], &array[15] );
    if ( j == EOF )
        exit ( 403 );
    if ( !j ) {
        if ( ( tin[0] == 'e' ) || ( tin[0] == 'E' ) ) // "e"nd
            break; // break out of "for i"
        else {   // floating point code by Matt Crawford
            j = sscanf ( tin,
                    "float %ld.%[0-9]%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]"
                    "%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]"
                    "%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]"
                    "%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]%ld.%[0-9]",
                    &array[0], sarray[0], &array[1], sarray[1],
                    &array[2], sarray[2], &array[3], sarray[3],
                    &array[4], sarray[4], &array[5], sarray[5],
                    &array[6], sarray[6], &array[7], sarray[7],
                    &array[8], sarray[8], &array[9], sarray[9],
                    &array[10], sarray[10], &array[11], sarray[11],
                    &array[12], sarray[12], &array[13], sarray[13],
                    &array[14], sarray[14], &array[15], sarray[15] );
            if ( j == 0 || j & 1 ) {
                    xprintf ( "Bad format.", 404 );
                return ( 1 );
            }
            else {
                for ( k = 0, j /= 2; k < j; k++ )
                /* strip trailing zeros */
                    for ( k2 = (int)strlen(sarray[k]);
                        sarray[k][--k2]=='0'; )
                            sarray[k][k2] = '\0';
                    ioerr = printf ( "%ld.%s\n", array[k],
                                     sarray[k] );
                    if ( ioerr <= 0 )
                        exit ( 405 );
                    keysize += sprintf ( &key[keysize], "%ld.%s",
                                        array[k], sarray[k] );
                }
                keysize += sprintf ( &key[keysize], "/" );
            }
        }
        else
        { // sort integer values, not a very efficient algorithm
            for ( k2 = 0; k2 < j - 1; ++k2 )
                for ( k = 0; k < j - 1; ++k )
                    if ( array[k] > array[k+1] ) {
                        temp = array[k];
                        array[k] = array[k+1];
                        array[k+1] = temp;
                        }
            for ( k = 0; k < j; ++k ) {  // print for user check
                ioerr = printf ( "%ld ", array[k] );
                if ( ioerr <= 0 )
                    exit ( 406 );
                keysize += sprintf ( &key[keysize], "%ld.",
                                     array[k] );
            }
            keysize += sprintf ( &key[keysize], "/" );
        }
}    // end "for i"
if ( i == 0 ) {
    xprintf ( "No key input.\n", 407 );
    return ( 1 );
}
ioerr = printf ( "Key is:\n %s\n", key );
if ( ioerr <= 0 )
    exit ( 408 );
return ( 0 );
}  // end getSeed


//  print out a hash Chain based on key
//*****************************************************************
void hashChain ( void )
{
int            i, ioerr;
long int       j;
SHA256Context  context;
uint8_t        hash[SHA256HashSize];

j = getinteger ( "Length of chain to print:" );
if ( j > 99 ) {
    j = 99;
    xprintf ( "Chain length clipped at 99.\n", 500 );
    }
testSHA256 ( );
SHA256Reset ( &context );
SHA256Input ( &context, (uint8_t *)key, (int)strlen ( key ) );
SHA256Result ( &context, hash );
if ( debug ) {
    xprintf ( "Hex of SHA-256 of Key:\n", 501 );
    hexprint ( hash, SHA256HashSize );
    xprintf ( "\n", 502 );
    }
xprintf ( "00-", 505 );
b64print ( hash, SHA256HashSize );
    xprintf ( "\n", 506 );
for ( i = 1; i <= j; ++i ) {
    SHA256Reset ( &context );
    SHA256Input ( &context, hash, SHA256HashSize );
    SHA256Result ( &context, hash );
    ioerr = printf ( "%02d-", i );
    if ( ioerr <= 0 )
        exit ( 503 );
    b64print ( hash, SHA256HashSize );
    xprintf ( "\n", 504 );
} // for i
} // end hashChain


// print out a SHA-256 hash in hex
//****************************************************************
void hexprint ( uint8_t *p, int length ) {
int    i, ioerr;

for ( i = 0; i < length; ++i ) {
ioerr = printf ( "%02X", p[i] );
if ( ioerr <= 0 )
    exit ( 601 );
 } // for i
} // end hexprint


//  read hex, print as base64
//*****************************************************************
void hexToB64 ( void ) {
uint8_t   hexval[(MAXLINE/2)+2];
char      clean[MAXLINE];
char     *cherr;
int       i, j, v, ioerr;

xprintf ( "Type some bytes in hex: ", 1101 );
cherr = fgets ( tin, MAXLINE, stdin );
if ( cherr == NULL )
    exit ( 1102 );
for ( i = 0, j = 0; i < MAXLINE; ++i ) {
    if ( ( tin[i] == '\n' ) || ( tin[i] == 0 ) )
      break;  // end of the line
    if ( isspace ( tin[i] ) )
      continue;  // skip white space
    if ( isxdigit ( tin[i] ) ) {
      clean[j] = tolower ( tin[i] );
      ++j;
      continue;
    }
    ioerr = printf ( "Non-hex digit encountered: %02X\n", tin[i] );
    if ( ioerr <= 0 )
        exit ( 1103 );
    return;
} // for i
clean[j] = 0;
if ( j & 1 ) {
    ioerr = printf ( "Odd number of hex digits? %i\n", j );
    if ( ioerr <= 0 )
        exit ( 1104 );
    return;
}
for ( i = 0; i < j; ++i ) { // from clean to hexval
    if ( clean[i] >= 'a' && clean[i] <= 'f' )
        v = clean[i] - 'a' + 10;
    else
        v = clean[i] - '0';
    if ( i & 1 )
        hexval[i/2] += v;
    else
        hexval[i/2] = v << 4;
}
if ( debug ) {
    hexprint ( hexval, j/2 );
    xprintf ( "\n", 1105 );
}
b64print ( hexval, j/2 );
xprintf ( "\n", 1106 );
} // end hexToB64


// get remainder of dividing a SHA-256 hash
//   by a small positive number
//****************************************************************
int longremainder ( unsigned int divisor,
                    uint8_t hash[SHA256HashSize] ) {
long int     kruft;
int          i;

if ( divisor <= 0 )
    exit ( 1 );
for ( i = 0, kruft = 0; i < SHA256HashSize; ++i )
    {
    kruft = ( kruft << 8 ) + hash[i];
    kruft %= divisor;
    }
return (int)kruft;
}  // end longremainder


//  calculate how many bits of entropy it takes to select N from P
//      withour replacement. Print and return it.
//****************************************************************
/*               P!
    log  ( ----------------- )
       2    N! * ( P - N )!
*/
double NPentropy ( void )
{
long int    i;
double      result = 0.0;
int         ioerr;

if (    ( N < 1 )   // not selecting anything?
   ||   ( N >= P )  // selecting all of pool or more?
   )
   result = 0.0;    // degenerate case
else {
    for ( i = P; i > ( P - N ); --i )
        result += log ( i );
    for ( i = N; i > 1; --i )
        result -= log ( i );
    /* divide by [ log (base e) of 2 ] to convert to bits */
    result /= log ( 2 );
}
ioerr = printf ( "Approximately %.1f bits of entropy needed.\n",
                    result );
if ( ioerr <= 0 )
    exit ( 701 );
return result;
} // end NPentropy


//  Select N items from the pool of P items using the probe method
//****************************************************************
void probe ( void ) {
unsigned short     *selected;
SHA256Context      context;
uint8_t            hash[SHA256HashSize];
unsigned int       i, remaining, divisor;
int                j, k;
unsigned char      unch1, unch2;
    
selected =
  (unsigned short *)malloc ( P * sizeof ( unsigned short ) );
if ( !selected )
    xprintf ( "Out of memory.\n", 801 );
for ( i = 0; i < P; ++i )
    selected [i] = (unsigned short)(i + 1);
xprintf (
"index          base64 value of SHA-256          div selected\n",
    802 );
remaining = N;
divisor = P;
testSHA256 ( );
for ( i = 0; i < N; ++i, --remaining, --divisor ) {
    SHA256Reset ( &context );
    unch1 = i >> 8;
    unch2 = i & 0xFF;
    SHA256Input ( &context, &unch1, 1 );
    SHA256Input ( &context, &unch2, 1 );
    SHA256Input ( &context, (uint8_t *)key, keysize );
    SHA256Input ( &context, &unch1, 1 );
    SHA256Input ( &context, &unch2, 1 );
    SHA256Result ( &context, hash );
    k = longremainder ( divisor, hash );
    for ( j = 0; j < P; ++j) {
        if ( selected[j] )
            if ( --k < 0 ) {
                printf ( "%3d ", i + 1 );
                b64print ( hash, SHA256HashSize );
                printf ( " %3d  >%3d<\n", divisor, selected[j] );
                selected[j] = 0;
                break;  // for j
            }
    } // for j
} // for i
free ( (void *)selected );
} // end probe


//  Test that SHA-256 code seems to be working
//****************************************************************
void testSHA256 ( void ) {
SHA256Context  context;
char           test1[] = "abc";
uint8_t        correct[] = { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01,
    0xCF, 0xEA, 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
    0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, 0xB4, 0x10,
    0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD };
uint8_t        hash[SHA256HashSize];
int            i;

SHA256Reset ( &context );
SHA256Input ( &context, (uint8_t *)test1, 3 );
SHA256Result ( &context, hash );
for ( i = 0; i < SHA256HashSize; ++i ) {
if ( hash[i] == correct[i] )
    continue;
else
    xprintf ( "SHA256 not working.\n", 1201 );
}  // for
if ( debug )
    xprintf ( "SHA256 OK.\n", 1202 );
} // end testSHA256


//  printf a string and exit if io error occurs
//****************************************************************
void xprintf ( char *message, int x) {
int    ioerr;

ioerr = printf ( "%s", message );
if ( ioerr <= 0 )
    exit ( x );
}

<< CODE HAS NOT YET BEEN UPDATED TO COVER EXTENDED SELECTION. >>
  ]]>
</sourcecode>

</section>

</middle>

<!-- ____________________BACK_MATTER____________________ -->
<back>

<references>
  <name>Normative References</name>
        
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.0020.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.2119.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.4086.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.6234.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.8174.xml"/>
       
</references>
 
<references>
  <name>Informative References</name>

<reference anchor="Lamport">
  <front>
    <title>Password Authentication with Insecure Communication</title>
    <author initials="L." surname="Lamport"/>
    <date year="1981" month="11"/>
  </front>
  <seriesInfo name="Communications of the ACM" value="24.11"/>
  <seriesInfo name="pages" value="770-772"/>
</reference>
  
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.1321.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.1760.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.2777.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.3797.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.5890.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.8713.xml"/>
<xi:include
    href="https://www.rfc-editor.org/refs/bibxml/reference.RFC.9389.xml"/>

</references>

<section>
  <name>History of NomCom Voting Member Selection</name>

<t>For reference purposes, here is a list of the IETF Nominations
Committee member selection techniques and chairs so far:</t>

<table>
  <thead>
<tr><th>Num</th><th>YEAR</th><th>CHAIR</th><th>SELECTION METHOD</th></tr>
  </thead>
  <tbody>
    
    <tr><td align="right">1</td><td>1993/1994</td>
    <td>Jeff Case</td><td>Clergy</td></tr>
    
    <tr><td align="right">2</td><td>1994/1995</td>
    <td>Fred Baker</td><td>Clergy</td></tr>
    
    <tr><td align="right">3</td><td>1995/1996</td>
    <td>Guy Almes</td><td>Clergy</td></tr>
    
    <tr><td align="right">4</td><td>1996/1997</td>
    <td>Geoff Huston</td><td>Spouse</td></tr>
    
    <tr><td align="right">5</td><td>1997/1998</td>
    <td>Mike St.Johns</td><td>Algorithm</td></tr>
    
    <tr><td align="right">6</td><td>1998/1999</td>
    <td>Donald Eastlake 3rd</td><td>RFC 2777</td></tr>
    
    <tr><td align="right">7</td><td>1999/2000</td>
    <td>Avri Doria</td><td>RFC 2777</td></tr>
    
    <tr><td align="right">8</td><td>2000/2001</td>
    <td>Bernard Aboba</td><td>RFC 2777</td></tr>
    
    <tr><td align="right">9</td><td>2001/2002</td>
    <td>Theodore Ts'o</td><td>RFC 2777</td></tr>
    
    <tr><td align="right">10</td><td>2002/2003</td>
    <td>Phil Roberts</td><td>RFC 2777</td></tr>
    
    <tr><td align="right">11</td><td>2003/2004</td>
    <td>Rich Draves</td><td>RFC 2777</td></tr>
    
    <tr><td align="right">12</td><td>2004/2005</td>
    <td>Danny McPherson</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">13</td><td>2005/2006</td>
    <td>Ralph Droms</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">14</td><td>2006/2007</td>
    <td>Andrew Lange</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">15</td><td>2007/2008</td>
    <td>Lakshminath Dondeti</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">16</td><td>2008/2009</td>
    <td>Joel M. Halpern</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">17</td><td>2009/2010</td>
    <td>Mary Barnes</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">18</td><td>2010/2011</td>
    <td>Tom Walsh</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">19</td><td>2011/2012</td>
    <td>Suresh Krishnan</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">20</td><td>2012/2013</td>
    <td>Matt Lepinski</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">21</td><td>2013/2014</td>
    <td>Allison Mankin</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">22</td><td>2014/2015</td>
    <td>Michael Richardson</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">23</td><td>2015/2016</td>
    <td>Harald Alvestrand</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">24</td><td>2016/2017</td>
    <td>Lucy Lynch</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">25</td><td>2017/2018</td>
    <td>Peter Yee</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">26</td><td>2018/2019</td>
    <td>Scott Mansfield</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">27</td><td>2019/2020</td>
    <td>Victor Kuarsingh</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">28</td><td>2020/2021</td>
    <td>Barbara Stark</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">29</td><td>2021/2022</td>
    <td>Gabriel Montenegro</td><td>RFC 3797</td></tr>
    
    <tr><td align="right">30</td><td>2022/2023</td>
    <td>Rich Salz</td><td>RFC 3797</td></tr>

    <tr><td align="right">31</td><td>2023/2024</td> <td>Martin
    Thomson</td><td>RFC 3797 + hash chain extensions</td></tr>
    
  </tbody>
</table>

<t>Clergy = Names were written on pieces of paper, placed in a
receptacle, and a member of the clergy picked the NomCom members.</t>

<t>Spouse = Same as Clergy except chair's spouse made the
selection.</t>

<t>Algorithm = Algorithmic selection based on similar concepts to
those documented in <xref target="RFC2777"/> and <xref
target="RFC3797"/>. </t>

<t>RFC 2777 = Algorithmic selection using the algorithm and reference
code provided in <xref target="RFC2777"/> (but not the fake example
sources of randomness). </t>

<t>RFC 3797 = Algorithmic selection using the algorithm and reference
code provided in <xref target="RFC3797"/> (but not the fake example
sources of randomness).</t>

<t>RFC 3797 + hash chain extensions = As with <xref target="RFC3797"/>
but using a hash chain for Extended Selection as generally specified
in <xref target="Extension"/>.</t>

</section>

<section anchor="EqNumbers">
   <name>More Equations and Numbers</name>

 <t>You can skip this section unless you want to dig a little bit
 further into the statistical arguments.</t>
   
 <t>To illustrate the relatively minor effect in practice of less
 entropy than needed for complete randomization, assume you select N
 items from a pool of P things and that you do this T times where N
 &lt;&lt; P &lt;&lt; T. Obviously, the expected value of the number of
 times each thing would be selected is</t>
 
<artwork type="ascii-art" align="center">
  <![CDATA[
                   N * T
Expected Value = ---------
                     P
  ]]>
</artwork>

 <t>Although NomCom selection is done without replacement (since it
 makes no sense to select the same person more than once), given that
 N &lt;&lt; P we can approximate selection statistics assuming
 selection with replacement. Making the further approximation of the
 binomial distribution for the Gaussian distribution, the standard
 deviation of the number of times a thing would be selected is</t>

<artwork type="ascii-art" align="center">
  <![CDATA[
                                 ___________________
                              2 /     N          N
Standard Deviation of Value =  / T * --- * (1 - ---)
                              V       P          P
  ]]>
</artwork>

 <t>Assuming the specific case of selecting 10 items from a pool of
 200, typical of an IETF NomCom selection near the date of the
 document. The following table shows, for various powers of 2 number of
 item set selections, the expected number of times each item would be
 selected and the standard deviation in the expected number.</t>

 <table>
   <thead>
<tr><th align="center">Times Set of 10 Selected</th><th>Base 2
Log(Times)</th><th align="right">Expected Times Each Item
Selected</th><th align="right">Standard Deviation of Times Item
Selected</th><th>SD as a % of Expected</th></tr>
   </thead>
   <tbody>
<tr><td align="right">1,024</td><td
align="right">10</td><td
align="right">51.2</td><td
align="right">22.1</td><td>43.2%</td></tr>

<tr><td align="right">1,&zwsp;048,&zwsp;576</td><td
align="right">20</td><td
align="right">52,&zwsp;429</td><td
align="right">706</td><td>1.35%</td></tr>

<tr><td align="right">1,&zwsp;073,&zwsp;741,&zwsp;824</td><td
align="right">30</td><td
align="right">53,&zwsp;687,&zwsp;091</td><td
align="right">22,&zwsp;584</td><td>0.0421%</td></tr>

<tr><td
align="right">1,&zwsp;099,&zwsp;511,&zwsp;627,&zwsp;776</td><td
align="right">40</td><td
align="right">54,&zwsp;975,&zwsp;581,&zwsp;389</td><td
align="right">722,&zwsp;681</td><td>0.00131%</td></tr>
   </tbody>
 </table>

 <t>Thus, even if more bits are needed for perfect randomness, 40 bits
 of entropy will assure only an insignificant deviation from
 completely random selection for the difference in probability of
 selection of different pool members, the correlation between the
 selection of any pair of pool members, and the like for a small
 number of pool members.</t>
 
</section>

<section anchor="Changes3797">
  <name>Changes from RFC 3797</name>

 <t>The primary differences between this documenet and <xref
 target="RFC3797"/>, the previous version, are the following:</t>

 <ul>
   <li>Add Section 5: Extended Selection, using hash chain. </li>
   <li>Many editorial changes. Add IANA Considerations section.</li>
   <li>Use <xref target="RFC0020"/> as the reference for ASCII. </li>
   <li>Update Appendix A. </li>
   <li>Define "publicly verifiable" as "promotes public
   confidence" to avoid technical meanings of "verify".</li>
   <li>Change text and code to use SHA-256 instead of MD-5.</li>
   <li>Change "Fully Worked Example" and update code to generally
   improve it. Use new code for example.</li>

 </ul>

</section>

<section>
  <name>Versions Change History</name>

  <t>RFC EDITOR NOTE: Please remove this Appendix before
  publication</t>

  <section>
    <name>-00 to -01</name>
    <ul>
      <li>Add Extended NomCom Selection, Section 5, incrementing
      following section numbers.</li>
      <li>Add text emphasizing that no entries can be added after the
      volunteer list is frozen.</li>
      <li>Editorial improvements.</li>
    </ul>
  </section>
  <section>
    <name>-01 to -02</name>
    <ul>
      <li>Covert nroff source to IETF xml2rfc v3.</li>
      <li>Change pool formation reference to <xref
      target="RFC9389"/>.</li>
      <li>Increased use of all caps requirements language.</li>
      <li>Editorial improvements.</li>
    </ul>
  </section>
  <section>
    <name>-02 to -03</name>
    <ul>
      <li>Change over extension under <xref target="Extension"/> to
      use a hash chain as per
      https://mailarchive.ietf.org/arch/msg/eligibility-discuss/D0CQ9p6-RiPD3x77dna7IXkwcLQ/</li>
      <li>Define "verifiable" as "promoting
      confidence" to avoid technical meansings of "verify".</li>
      <li>Add Martin Thomson to Appendix A.</li>
      <li>Add Acknowledgements Section.</li>
      <li>Add <xref target="EqNumbers"/> on More Equations and
      Numbers.</li>
      <li>Add pointer to Rich Salz's implementation of the <xref
      target="RFC3797"/> method.</li>
      <li>Add this changes history Appendix.</li>
      <li>Change text and code to use SHA-256 instead of MD-5.</li>
      <li>Change "Fully Worked Example" and update code to generally
      improve it. Use new code for example.</li>
      <li>Change Table 1 on randomness required to cover a 250 person
      pool and to cover the case of selecting 1 item.</li>
      <li>Add "More Equations and Numbers" appendix.</li>
      <li>Editorial improvements.</li>
    </ul>
  </section>

</section>

<section anchor="Acknowledgements" numbered="false">
  <name>Acknowledgements</name>
  
 <t>The suggestions and comments on this document from the following
 persons are gratefully acknowledged: Paul Hoffman and Martin
 Thomson.</t>

 <t>Acknowledgements for RFC 3797: Matt Crawford and Erik Nordmark
 made major contributions to this document.  Comments by Bernard
 Aboba, Theodore Ts'o, Jim Galvin, Steve Bellovin, and others have
 been incorporated.</t>

</section>

</back>

</rfc>
