github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/flip/prng_test.go (about) 1 package flip 2 3 import ( 4 "github.com/stretchr/testify/require" 5 "math/big" 6 "testing" 7 ) 8 9 func TestPRNG(t *testing.T) { 10 var secret Secret 11 secret[0] = 1 12 prng := NewPRNG(secret) 13 expected := []int{13, 59, 52, 48, 40, 15, 11, 21, 64, 31, 53, 61, 20, 28, 52, 41, 53, 45, 14 54, 54, 23, 32, 19, 5, 53, 45, 18, 21, 13, 50, 57, 61, 26, 51, 62, 8, 62, 52, 10, 2, 64, 17, 15 53, 35, 35, 9, 30, 0, 49, 47, 10, 8, 39, 37, 14, 18, 17, 48, 23, 32, 11, 45, 40, 24, 40, 11, 46, 40, 16 46, 41, 3, 25, 16, 55, 16, 21, 8, 64, 22, 6, 9, 25, 49, 24, 12, 26, 48, 48, 28, 31, 34, 58, 21, 17 28, 52, 60, 28, 50, 49, 8} 18 19 for _, a := range expected { 20 b := prng.Int(65) 21 require.Equal(t, a, int(b)) 22 } 23 24 n := "919209803230948230498223094203977777434098123" 25 var ni big.Int 26 ni.SetString(n, 10) 27 bigExpected := []string{ 28 "614222739125617243553633697417534086505324514", 29 "355554091485763233176715002468010576256365854", 30 "445884861910366431685301365477451900735701042", 31 "117678505521424886688566746877893336950051289", 32 "246188573796042435697035169087245506434824132", 33 "684500989680877379218341481720344136659405599", 34 "26111147325353218353310266097685298806908568", 35 "824789626433629860440209186185356370803493878", 36 "831846934379293857466321253950305266684136426", 37 "733199753439315108451154616131739206730983101", 38 } 39 40 for _, a := range bigExpected { 41 b := prng.Big(&ni) 42 var ai big.Int 43 ai.SetString(a, 10) 44 require.Equal(t, b.Cmp(&ai), 0) 45 } 46 47 coinsExpected := []bool{ 48 true, false, false, true, true, false, true, false, false, true, false, true, true, true, false, false, 49 false, true, true, false, 50 } 51 52 for _, b := range coinsExpected { 53 require.Equal(t, prng.Bool(), b) 54 } 55 56 expectedNegatives := []int{ 57 -210, -25, -224, -221, -64, -49, -64, -246, -76, -32, -159, -200, -49, -166, -23, -120, -164, -174, -205, -25, -26, 58 -4, -31, -198, -176, -51, -244, -16, -81, -184, -141, -233, -197, -106, -101, -150, -191, -95, -147, -185, -249, 59 -3, -132, -76, -212, -106, -224, -71, -217, -190, -11, -29, -176, -158, -163, -54, -234, -254, -164, -152, -48, 60 -118, -53, -78, -116, -200, -141, -182, -156, -120, -45, -181, -191, -107, -246, -114, -244, -161, -33, -153, 61 -182, -206, -213, -22, -230, -35, -38, -204, -29, -220, -196, -65, -52, -39, -122, -205, -181, -178, -60, 62 -21, -120, -89, -129, -225, -34, -204, -134, -185, -50, -114, -55, -151, -239, -175, -43, -159, -64, -31, 63 -74, -234, -100, -86, -175, -175, -82, -21, -26, -151, -63, -142, -116, -40, -87, -161, -143, -182, -18, 64 -158, -59, -71, -216, -40, -65, -79, -243, -95, -12, -160, -63, -231, -56, -220, -70, -102, -61, -235, 65 -21, -163, -174, -65, -45, -130, -113, -45, -156, -138, -158, -52, -150, -35, -17, -228, -22, -112, -199, 66 -77, -168, -166, -16, -248, -39, -245, -110, -214, -28, -235, -54, -235, -160, -218, -133, -212, -139, -4, 67 -64, -132, -233, -222, -194, -237, -149, -207, -161, -100, -36, -241, -70, -167, -252, -54, -42, 68 -189, -234, -34, -192, -212, -49, -155, -189, -70, -62, -15, -114, -89, -234, -236, -21, -241, -217, -205, 69 -155, -182, -103, -220, -143, -123, -82, -35, -15, -130, -140, -224, -158, -119, -2, -201, -195, -41, -246, 70 -155, -156, -109, -41, -170, -142, -68, -28, -102, -176, -100, -213, -24, -46, -134, -191, -147, -178, -220, 71 -116, -45, -53, -248, -177, -6, -168, -139, -52, -129, -95, -135, -116, -250, -32, -242, -127, -127, -234, 72 -235, -92, -214, -243, -90, -11, -242, -150, -179, -218, -119, -156, -205, -204, -251, -143, -55, -15, -58, 73 -78, -110, -241, -142, -1, -35, -81, -102, -107, -90, -53, -134, -246, -14, -249, -82, -217, -3, -197, 74 -208, -64, -255, -202, -241, -70, -146, -20, -171, -182, -9, -213, -243, -221, -116, -171, -174, -121, 75 -19, -148, -23, -137, -43, -144, -210, -112, -192, -171, -251, -134, -178, -63, 0, -180, -94, -52, -137} 76 77 for _, a := range expectedNegatives { 78 b := prng.Int(-256) 79 require.Equal(t, a, int(b)) 80 } 81 } 82 83 func TestPRNGRanges(t *testing.T) { 84 85 test := func(n int64) { 86 var secret Secret 87 secret[0] = 3 88 found0 := false 89 foundMax := false 90 prng := NewPRNG(secret) 91 max := n 92 if max > 0 { 93 max-- 94 } else { 95 max++ 96 } 97 98 for i := 0; i < 1000 && (!found0 || !foundMax); i++ { 99 val := prng.Int(n) 100 if val == 0 { 101 found0 = true 102 } 103 if val == max { 104 foundMax = true 105 } 106 } 107 require.True(t, found0) 108 require.True(t, foundMax) 109 } 110 111 for _, n := range []int{2, 4, 5, 16, 17, 32, 33, 64, 127, 128, 129, -2, -3, -4, -5, -8, -10, -15, -16, -17, -31, -32, -33} { 112 test(int64(n)) 113 } 114 } 115 116 func TestPRNGCornerCases(t *testing.T) { 117 var secret Secret 118 secret[0] = 1 119 prng := NewPRNG(secret) 120 121 // By convention, we're returning 0 for 0 moduli, but it's 122 // a corner case. 123 m := big.NewInt(0) 124 r := prng.Big(m) 125 require.Equal(t, 0, m.Cmp(r)) 126 127 // The caase of the 1 modulus is handled normally but let's test 128 // that it works. 129 m = big.NewInt(1) 130 r = prng.Big(m) 131 require.Equal(t, 0, r.Cmp(big.NewInt(0))) 132 133 // We had an earlier bug in our shuffle, a classic off-by-one, in which 0,1 134 // would always be shuffled 1,0. So, if we run 40 times in a row, we better 135 // get some number of (1,0) results that are >0 and <40. This test indeed 136 // failed when I went back and rebroke the shuffle function. 137 flips := 0 138 n := 40 139 for i := 0; i < n; i++ { 140 res := prng.Permutation(2) 141 if res[0] == 1 { 142 flips++ 143 } 144 } 145 require.NotEqual(t, 0, flips) 146 require.NotEqual(t, n, flips) 147 }