From 62b95f4d7453f1b0c788d877c793a84a420d2443 Mon Sep 17 00:00:00 2001 From: Kamron Batman Date: Thu, 9 Aug 2018 00:06:23 -0700 Subject: [PATCH] Adds IntelHW RDRand for Mac/Linux. --- Server/Random.cs | 148 +++++++++++++++++++++++++++++++++++++++++++++-- rdrand.so | Bin 0 -> 9708 bytes 2 files changed, 144 insertions(+), 4 deletions(-) create mode 100755 rdrand.so diff --git a/Server/Random.cs b/Server/Random.cs index 57b9070aa..a336b9787 100644 --- a/Server/Random.cs +++ b/Server/Random.cs @@ -21,11 +21,11 @@ namespace Server { private static readonly IRandomImpl _Random; static RandomImpl() { - if ( Core.Unix ) { - _Random = new CSPRandom(); + if (Core.Unix && File.Exists("rdrand.so")) { + _Random = new RDRandUnix(); } else if (Core.Is64Bit && File.Exists("rdrand64.dll")) { _Random = new RDRand64(); - } else if ( !Core.Is64Bit && File.Exists("rdrand32.dll") ) { + } else if (File.Exists("rdrand.dll")) { _Random = new RDRand32(); } else { _Random = new CSPRandom(); @@ -215,8 +215,148 @@ namespace Server { } } + public sealed class RDRandUnix : IRandomImpl, IHardwareRNG + { + internal class SafeNativeMethods + { + [DllImport("rdrand.so")] + internal static extern RDRandError rdrand_32(ref uint rand, bool retry); + + [DllImport("rdrand.so")] + internal static extern RDRandError rdrand_get_bytes(int n, byte[] buffer); + } + + private static int BUFFER_SIZE = 0x10000; + private static int LARGE_REQUEST = 0x40; + + private byte[] _Working = new byte[BUFFER_SIZE]; + private byte[] _Buffer = new byte[BUFFER_SIZE]; + + private int _Index = 0; + + private object _sync = new object(); + + private ManualResetEvent _filled = new ManualResetEvent(false); + + public RDRandUnix() + { + SafeNativeMethods.rdrand_get_bytes(BUFFER_SIZE, _Working); + ThreadPool.QueueUserWorkItem(new WaitCallback(Fill)); + } + + public bool IsSupported() + { + uint r = 0; + return SafeNativeMethods.rdrand_32(ref r, true) == RDRandError.Success; + } + + private void CheckSwap(int c) + { + if (_Index + c < BUFFER_SIZE) + return; + + _filled.WaitOne(); + + byte[] b = _Working; + _Working = _Buffer; + _Buffer = b; + _Index = 0; + + _filled.Reset(); + + ThreadPool.QueueUserWorkItem(new WaitCallback(Fill)); + } + + private void Fill(object o) + { + SafeNativeMethods.rdrand_get_bytes(BUFFER_SIZE, _Buffer); + _filled.Set(); + } + + private void _GetBytes(byte[] b) + { + int c = b.Length; + + lock (_sync) + { + CheckSwap(c); + Buffer.BlockCopy(_Working, _Index, b, 0, c); + _Index += c; + } + } + + private void _GetBytes(byte[] b, int offset, int count) + { + lock (_sync) + { + CheckSwap(count); + Buffer.BlockCopy(_Working, _Index, b, offset, count); + _Index += count; + } + } + + public int Next(int c) + { + return (int)(c * NextDouble()); + } + + public bool NextBool() + { + return (NextByte() & 1) == 1; + } + + private byte NextByte() + { + lock (_sync) + { + CheckSwap(1); + return _Working[_Index++]; + } + } + + public void NextBytes(byte[] b) + { + int c = b.Length; + + if (c >= LARGE_REQUEST) + { + SafeNativeMethods.rdrand_get_bytes(c, b); + return; + } + _GetBytes(b); + } + + public unsafe double NextDouble() + { + byte[] b = new byte[8]; + + if (BitConverter.IsLittleEndian) + { + b[7] = 0; + _GetBytes(b, 0, 7); + } + else + { + b[0] = 0; + _GetBytes(b, 1, 7); + } + + ulong r = 0; + fixed (byte* buf = b) + r = *(ulong*)(&buf[0]) >> 3; + + /* double: 53 bits of significand precision + * ulong.MaxValue >> 11 = 9007199254740991 + * 2^53 = 9007199254740992 + */ + + return (double)r / 9007199254740992; + } + } + public sealed class RDRand32 : IRandomImpl, IHardwareRNG { - internal class SafeNativeMethods { + internal class SafeNativeMethods + { [DllImport("rdrand32")] internal static extern RDRandError rdrand_32(ref uint rand, bool retry); diff --git a/rdrand.so b/rdrand.so new file mode 100755 index 0000000000000000000000000000000000000000..8205f7af2550643084945f1d1fac390bd12cf445 GIT binary patch literal 9708 zcmeHNZ){sv6~E7M8m}y~D@|3(R_cy+q-Z2@Q>wLmAa9G+XRV#OC1FKbcsQ}0M0M=c zeotE}3NDVpZzdw3A_NjrU`TvGNaLT>6$u=LZW%&bk&rqxA%d2+?wX}3g)C)V%K8~=WHwSh6Ijxn|gr4ePt%~+24pfR=$o!f5FIKm88^?&r>Up6?Rn?-;YouA?jOX`Q_Ro?dgfP-r7dOkS1B#c{^#1gk z$rQFR38cm^>Gu{x7_fZ~!uxl+El&bs&(pqXbG06Kk z<9(IK;}sKFgsg}SqpIqO=Y|szbvO}Anz(X3&hS7(JOE*53=x}ZTGza}uAOqXY-U9@;BnZB#W8SJPu7{mHmGs-=+U#_>cr+E(N*g!s3wi>eMLZQGvYso_r$M84_pA z&j;Y~7{?2As34S=oi{qS%_vO{dn%F&Cn7Cr+A|~%F_vi~#m^XV=t2D`Y9SqdE5k5vb}?4Oz#oBr6oq6rFZZBsL9z1(SRqaD=ToS#KLAAI?EAsF-<=!! zbneF!bywy$r&rM3x``S$<8s=}J}EG2l6z4ofAXbV-FxRjy~JAebgDHz+)t%zEUiUH zS{`eOi~*q&uuSrDPYHltTR+E*+)76eGA4SPm2e zuX%rD1m}#tdE-dQ=vg@Z{-J0>*IQ4YS{P15L;Ay~Pn8l{G_G$yiwlF9-CySpIyp=) zek^-gLg26Sz@G^&>Gv2*O7{0ny?ryKBHkPdjVIBVy>(lEfKn;N%jI%*MS6La>c23f zu@}vKfnxU7s`pHBW|BI|pQDU@#?6qiT4+4T{kN9doW48IboK+X!aH{vN#@@2j=zRF z=6!X^`|aTMm~3pyoVw1;8F+IuR?`jMbRRW&b3fbA`rQq!r#GUy@U4`i=VmM4u0N1(>gyF;ZFSg2DQS+4^?cZUt29ELm|P?)JDca zwNXEbpmtY%*l9TCG#qjo_B#!`VKBFlm8o>i%MFXB!AX_1f1bgKI~p?Hla1A2Zdq#% zycHAt{g#gYVWV97rL~!KUnu*kr##bn;AZM=^HgCodaxN~wQt6|!{YmH;ysRYi_K}q zbANa|xkv7%TcNpQ`IQFm_ylD&@nugadu2s7mgVg0E3&kD#P}ez=U+kNpYrrVot(Yg z;5`$(_}GN|5_+@4(h6?Av%%cE-th-9E5*=@%EYNzbB3iqTj_Xn@1yBuTq)(lJFj}j zZ^BV2^vo&~a#_w^YEZH(4e8FnvSM5~f4L(%EwrSMah@=qtu-`!#=mdtPgo6yu^YecjiQ|5Cfl(wj)Hvvfb{ZcA?_z24H> zNZ+JPzw>CmyB)c{;!zIVIETTQ{u89DJ){(l6cy=4=)J#+_03DlbjhQXr$goQ`aiC@ z0!1V|+xf!C#b9n;+l!rG%G!Ba+Yc{VhsT@y1Hy|v@pkHO=AHa~R#)-n{H~80)p| zdAZ(U+@yK(GAJ9F^@!cv+$%pT_gOo7vb_5jNRu|(_V1yRyUM!_)RRMGym}e?gx)k6 zyeAuq`siH883VM_B7{x=SA&O{TPH zgzc+iQ$Bo$F|`Fx2LtIxQ>Ogp4D9XNrA1hqgg5H_?$z?0P zHHCji={e?kln8I5 zYRQ3b0mtej_V>Btz0^)$p0waa{BGe9=(}u~+IOL3P)Gv|>GuaD-$cQ1YZ?B~fq&(|^c=qp1=2ye5%x2cpJ(d`3uHgZDnIBr z#6rbM6e>=pQ0Zh_N7imhsJ7nJC864UD(``c3(LHADlFC&R&{%|_N1e!bnEf(NGh4= z4{IagL~CdAxkNk}j-=_=0+Cc=@Kb@7wpPY}J2AlS-iNy+|JO`a&|vZ6AgYqfN~UNP GA^!o}bF%pW literal 0 HcmV?d00001