<div><div><div dir="auto">On Wed, Oct 4, 2017 at 21:01 Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:</div></div><div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="gmail_quote"><div dir="auto">On Wed, Oct 4, 2017 at 20:49 Greg Parker via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><br><div><blockquote type="cite"><div>On Oct 3, 2017, at 11:44 PM, Jonathan Hull via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><br class="m_5653898744427273581m_6382907976278284216m_7560581448019464507Apple-interchange-newline"><div><div style="word-wrap:break-word">I like the idea of splitting it into 2 separate “Random” proposals.<div><br></div><div>The first would have Xiaodi’s built-in CSPRNG which only has the interface:</div><div><br></div><div>On FixedWidthInteger:</div><div><span class="m_5653898744427273581m_6382907976278284216m_7560581448019464507Apple-tab-span" style="white-space:pre-wrap">        </span>static func random()throws -&gt; Self</div><div><span class="m_5653898744427273581m_6382907976278284216m_7560581448019464507Apple-tab-span" style="white-space:pre-wrap">        </span>static func random(in range: ClosedRange&lt;Self&gt;)throws -&gt; Self<br><div><br></div><div>On Double:</div><div><span class="m_5653898744427273581m_6382907976278284216m_7560581448019464507Apple-tab-span" style="white-space:pre-wrap">        </span>static func random()throws -&gt; Double</div><div><span class="m_5653898744427273581m_6382907976278284216m_7560581448019464507Apple-tab-span" style="white-space:pre-wrap">        </span>static func random(in range: ClosedRange&lt;Double&gt;)throws -&gt; Double</div><div><br></div><div>(Everything else we want, like shuffled(), could be built in later proposals by calling those functions)</div><div><br></div><div>The other option would be to remove the ‘throws’ from the above functions (perhaps fatalError-ing), and provide an additional function which can be used to check that there is enough entropy (so as to avoid the crash or fall back to a worse source when the CSPRNG is unavailable).</div></div></div></div></blockquote></div><div><blockquote type="cite"><br></blockquote></div><div><blockquote type="cite"><div><div style="word-wrap:break-word"><div><div>Then a second proposal would bring in the concept of RandomSources (whatever we call them), which can return however many random bytes you ask for… and a protocol for types which know how to initialize themselves from those bytes.  That might be spelled like &#39;static func random(using: RandomSource)-&gt;Self&#39;.  As a convenience, the source would also be able to create FixedWidthIntegers and Doubles (both with and without a range), and would also have the coinFlip() and oneIn(UInt)-&gt;Bool functions. Most types should be able to build themselves off of that.  There would be a default source which is built from the first protocol.</div><div><br></div><div>I also really think we should have a concept of Repeatably-Random as a subprotocol for the second proposal.  I see far too many shipping apps which have bugs due to using arc4Random when they really needed a repeatable source (e.g. patterns and lines jump around when you resize things). If it was an easy option, people would use it when appropriate. This would just mean a sub-protocol which has an initializer which takes a seed, and the ability to save/restore state (similar to CGContexts).</div></div></div></div></blockquote></div><div><br></div></div><div style="word-wrap:break-word;line-break:after-white-space"><div>I like this kind of layering of functionality and proposals. I would additionally separate the fundamental CSPRNG interface from the fool-proof easy functions that naive users will find on Stack Overflow.</div><div><div><br></div><div>The &quot;easy&quot; functions should:</div><div><br></div></div><div>* Trap on any error without throwing. Sophisticated users may be able to do something about entropy failure, so the fundamental CSPRNG interface needs to provide errors, but the easy function should either degrade somewhat (if entropy is present but insufficient) or just die (if entropy is wholly absent or nearly so).</div><div><br></div><div>* Remove the range-less function. Naive users often write things like `Int.random() % 100`, which unbeknownst to them is biased. Providing only the ranged interface nudges naive users toward correct usage. </div><div><br></div><div>* Provide an &quot;easy&quot; way to get some random bytes instead of a random number. Perhaps a Data initializer that returns random-filled bytes of the requested length. This helps make up for the lack of a range-less function on FixedWidthInteger.</div><div><br></div><div>The &quot;easy&quot; functions should get the best names: Int.random(in:), Data.random(length:), etc. The fundamental CSPRNG interface should have an interface that is less friendly and less discoverable.</div></div><div style="word-wrap:break-word;line-break:after-white-space"><div></div></div></blockquote><div dir="auto"><br></div></div></div><div><div class="gmail_quote"><div dir="auto">Agree, this is a very tractable set of functions for an initial implementation. In fact, with these primitives and maybe some shuffling and choosing conveniences in the stdlib, I see the remainder as useful-to-haves that may or may not be critical for inclusion in the stdlib vs more appropriate for a dedicated math library (more to follow on that thought in a little while).</div></div></div></blockquote><div dir="auto"><br></div></div></div></div><div><div><div class="gmail_quote"><div dir="auto">To sum up my thoughts so far in code, building on previous comments from others, this would be a nice set of random APIs, IMO:</div><div dir="auto"><br></div><div dir="auto">```</div><div dir="auto">extension Int {</div><div dir="auto">  static func random(in range: Countable{Closed}Range&lt;Int&gt;) -&gt; Int</div><div dir="auto">}</div><div dir="auto">// And similar for other concrete built-in integer types.</div><div dir="auto">//</div><div dir="auto">// Since fixed-width integers could exceed the maximum size supported by getrandom()</div><div dir="auto">// and other such functions, we do not provide a default implementation.</div><div dir="auto">//</div><div dir="auto">// The return value may not be cryptographically secure if there is insufficient entropy.</div><div dir="auto"><br></div><div dir="auto">extension Float {</div><div dir="auto">  static func random(in range: {Closed}Range&lt;Float&gt;) -&gt; Float</div><div dir="auto">}</div><div dir="auto"><br></div><div dir="auto">extension Double {</div><div dir="auto">  static func random(in range: {Closed}Range&lt;Double&gt;) -&gt; Double</div><div dir="auto">}</div><div dir="auto"><br></div><div dir="auto">extension Float80 {</div><div dir="auto">  // Ditto.</div><div dir="auto">}</div><div dir="auto"><br></div><div dir="auto">extension Data {</div><div dir="auto">  static func random(byteCount: Int) -&gt; Data</div><div dir="auto">}</div><div dir="auto"><br></div><div dir="auto">extension UnsafeMutableRawPointer {</div><div dir="auto">  func copyRandomBytes(count: Int) throws</div><div dir="auto">}</div><div dir="auto">// This function is to be the most primitive of the random APIs, and will throw if there is insufficient entropy.</div><div dir="auto"><br></div><div dir="auto">extension UnsafeMutableRawBufferPointer {</div><div dir="auto">  func copyRandomBytes() throws</div><div dir="auto">}</div><div dir="auto">// Just as UMRBP.copyBytes(from:) parallels UMRP.copyBytes(from:count:), we offer this convenience here.</div><div dir="auto">```</div></div></div></div><div><div><div class="gmail_quote"><div dir="auto"><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="gmail_quote"><div dir="auto"></div></div></div><div><div class="gmail_quote"><div dir="auto"><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div><br></div><div><br></div><div>-- </div><div>Greg Parker     <a href="mailto:gparker@apple.com" target="_blank">gparker@apple.com</a>     Runtime Wrangler</div><div><br></div><div><br></div></div>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div></blockquote></div></div></div>