github.com/ahenzinger/simplepir@v0.0.0-20230113230609-e9020b03bf28/pir/pir_test.go (about)

     1  package pir
     2  
     3  import (
     4  	"encoding/csv"
     5  	"fmt"
     6  	"math"
     7  	"os"
     8  	"strconv"
     9  	"testing"
    10  	"strings"
    11  )
    12  
    13  const LOGQ = uint64(32)
    14  const SEC_PARAM = uint64(1 << 10)
    15  
    16  // Test that DB packing methods are correct, when each database entry is ~ 1 Z_p elem.
    17  func TestDBMediumEntries(t *testing.T) {
    18  	N := uint64(4)
    19  	d := uint64(9)
    20  	pir := SimplePIR{}
    21  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
    22  
    23  	vals := []uint64{1, 2, 3, 4}
    24  	DB := MakeDB(N, d, &p, vals)
    25  	if DB.Info.Packing != 1 || DB.Info.Ne != 1 {
    26  		panic("Should not happen.")
    27  	}
    28  
    29  	for i := uint64(0); i < N; i++ {
    30  		if DB.GetElem(i) != (i + 1) {
    31  			panic("Failure")
    32  		}
    33  	}
    34  }
    35  
    36  // Test that DB packing methods are correct, when multiple database entries fit in 1 Z_p elem.
    37  func TestDBSmallEntries(t *testing.T) {
    38  	N := uint64(4)
    39  	d := uint64(3)
    40  	pir := SimplePIR{}
    41  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
    42  
    43  	vals := []uint64{1, 2, 3, 4}
    44  	DB := MakeDB(N, d, &p, vals)
    45  	if DB.Info.Packing <= 1 || DB.Info.Ne != 1 {
    46  		panic("Should not happen.")
    47  	}
    48  
    49  	for i := uint64(0); i < N; i++ {
    50  		if DB.GetElem(i) != (i + 1) {
    51  			panic("Failure")
    52  		}
    53  	}
    54  }
    55  
    56  // Test that DB packing methods are correct, when each database entry requires multiple Z_p elems.
    57  func TestDBLargeEntries(t *testing.T) {
    58  	N := uint64(4)
    59  	d := uint64(12)
    60  	pir := SimplePIR{}
    61  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
    62  
    63  	vals := []uint64{1, 2, 3, 4}
    64  	DB := MakeDB(N, d, &p, vals)
    65  	if DB.Info.Packing != 0 || DB.Info.Ne <= 1 {
    66  		panic("Should not happen.")
    67  	}
    68  
    69  	for i := uint64(0); i < N; i++ {
    70  		if DB.GetElem(i) != (i + 1) {
    71  			panic("Failure")
    72  		}
    73  	}
    74  }
    75  
    76  func TestDBInterleaving(t *testing.T) {
    77  	N := uint64(16)
    78  	d := uint64(8)
    79  	numBytes := uint64(len([]byte("string 16")))
    80  
    81  	DBs := make([]*Database, numBytes)
    82  	pir := SimplePIR{}
    83  	p := pir.PickParams(N, d, uint64(1 << 10) /* n */, uint64(32) /* log q */)
    84  
    85  	for n:=uint64(0); n<numBytes; n++ {
    86  		val := make([]uint64, N)
    87  		for i:=uint64(0); i<N; i++ {
    88  			arr := []byte("string "+fmt.Sprint(i))
    89  			if uint64(len(arr)) > n {
    90  				val[i] = uint64(arr[n])
    91  			} else {
    92  				val[i] = 0
    93  			}
    94  		}
    95  		DBs[n] = MakeDB(N, d, &p, val) 
    96  	}
    97  
    98  	D := pir.ConcatDBs(DBs, &p)
    99  
   100  	for i:=uint64(0); i<N; i++ {
   101  		val := make([]byte, numBytes)
   102  		for n:=uint64(0); n<numBytes; n++ {
   103  			val[n] = byte(D.GetElem(i + N*n))
   104  		}
   105  		fmt.Printf("Got '%s' instead of '%s'\n", string(val), "string " + fmt.Sprint(i))
   106  		if strings.TrimRight(string(val), "\x00") != "string " + fmt.Sprint(i) {
   107  			panic("Failure")
   108  		}
   109  	}
   110  }
   111  
   112  // Print the BW used by SimplePIR
   113  func TestSimplePirBW(t *testing.T) {
   114  	N := uint64(1 << 20)
   115  	d := uint64(2048)
   116  
   117  	log_N, _ := strconv.Atoi(os.Getenv("LOG_N"))
   118  	D, _ := strconv.Atoi(os.Getenv("D"))
   119  	if log_N != 0 {
   120  		N = uint64(1 << log_N)
   121  	}
   122  	if D != 0 {
   123  		d = uint64(D)
   124  	}
   125  
   126  	pir := SimplePIR{}
   127  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   128  	DB := SetupDB(N, d, &p)
   129  
   130  	fmt.Printf("Executing with entries consisting of %d (>= 1) bits; p is %d; packing factor is %d; number of DB elems per entry is %d.\n",
   131  		d, p.P, DB.Info.Packing, DB.Info.Ne)
   132  
   133  	pir.GetBW(DB.Info, p)
   134  }
   135  
   136  // Print the BW used by DoublePIR
   137  func TestDoublePirBW(t *testing.T) {
   138  	N := uint64(1 << 20)
   139  	d := uint64(2048)
   140  
   141  	log_N, _ := strconv.Atoi(os.Getenv("LOG_N"))
   142  	D, _ := strconv.Atoi(os.Getenv("D"))
   143  	if log_N != 0 {
   144  		N = uint64(1 << log_N)
   145  	}
   146  	if D != 0 {
   147  		d = uint64(D)
   148  	}
   149  
   150  	pir := DoublePIR{}
   151  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   152  	DB := SetupDB(N, d, &p)
   153  
   154  	fmt.Printf("Executing with entries consisting of %d (>= 1) bits; p is %d; packing factor is %d; number of DB elems per entry is %d.\n",
   155  		d, p.P, DB.Info.Packing, DB.Info.Ne)
   156  
   157  	pir.GetBW(DB.Info, p)
   158  }
   159  
   160  // Test SimplePIR correctness on DB with short entries.
   161  func TestSimplePir(t *testing.T) {
   162  	N := uint64(1 << 20)
   163  	d := uint64(8)
   164  	pir := SimplePIR{}
   165  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   166  
   167  	DB := MakeRandomDB(N, d, &p)
   168  	RunPIR(&pir, DB, p, []uint64{262144})
   169  }
   170  
   171  func TestSimplePirCompressed(t *testing.T) {
   172          N := uint64(1 << 20)
   173          d := uint64(8)
   174          pir := SimplePIR{}
   175          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   176  
   177          DB := MakeRandomDB(N, d, &p)
   178          RunPIRCompressed(&pir, DB, p, []uint64{262144})
   179  }
   180  
   181  // Test SimplePIR correctness on DB with long entries
   182  func TestSimplePirLongRow(t *testing.T) {
   183  	N := uint64(1 << 20)
   184  	d := uint64(32)
   185  	pir := SimplePIR{}
   186  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   187  
   188  	DB := MakeRandomDB(N, d, &p)
   189  	RunPIR(&pir, DB, p, []uint64{1})
   190  }
   191  
   192  func TestSimplePirLongRowCompressed(t *testing.T) {
   193          N := uint64(1 << 20)
   194          d := uint64(32)
   195          pir := SimplePIR{}
   196          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   197  
   198          DB := MakeRandomDB(N, d, &p)
   199          RunPIRCompressed(&pir, DB, p, []uint64{1})
   200  }
   201  
   202  // Test SimplePIR correctness on big DB
   203  func TestSimplePirBigDB(t *testing.T) {
   204  	N := uint64(1 << 25)
   205  	d := uint64(7)
   206  	pir := SimplePIR{}
   207  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   208  
   209  	DB := MakeRandomDB(N, d, &p)
   210  	RunPIR(&pir, DB, p, []uint64{0})
   211  }
   212  
   213  func TestSimplePirBigDBCompressed(t *testing.T) {
   214          N := uint64(1 << 25)
   215          d := uint64(7)
   216          pir := SimplePIR{}
   217          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   218  
   219          DB := MakeRandomDB(N, d, &p)
   220          RunPIRCompressed(&pir, DB, p, []uint64{0})
   221  }
   222  
   223  // Test SimplePIR correctness on DB with short entries, and batching.
   224  func TestSimplePirBatch(t *testing.T) {
   225  	N := uint64(1 << 20)
   226  	d := uint64(8)
   227  	pir := SimplePIR{}
   228  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   229  
   230  	DB := MakeRandomDB(N, d, &p)
   231  	RunPIR(&pir, DB, p, []uint64{0, 0, 0, 0})
   232  }
   233  
   234  func TestSimplePirBatchCompressed(t *testing.T) {
   235          N := uint64(1 << 20)
   236          d := uint64(8)
   237          pir := SimplePIR{}
   238          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   239  
   240          DB := MakeRandomDB(N, d, &p)
   241          RunPIRCompressed(&pir, DB, p, []uint64{0, 0, 0, 0})
   242  }
   243  
   244  // Test SimplePIR correctness on DB with long entries, and batching.
   245  func TestSimplePirLongRowBatch(t *testing.T) {
   246  	N := uint64(1 << 20)
   247  	d := uint64(32)
   248  	pir := SimplePIR{}
   249  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   250  
   251  	DB := MakeRandomDB(N, d, &p)
   252  	RunPIR(&pir, DB, p, []uint64{0, 0, 0, 0})
   253  }
   254  
   255  func TestSimplePirLongRowBatchCompressed(t *testing.T) {
   256          N := uint64(1 << 20)
   257          d := uint64(32)
   258          pir := SimplePIR{}
   259          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   260  
   261          DB := MakeRandomDB(N, d, &p)
   262          RunPIRCompressed(&pir, DB, p, []uint64{0, 0, 0, 0})
   263  }
   264  
   265  // Test DoublePIR correctness on DB with short entries.
   266  func TestDoublePir(t *testing.T) {
   267  	N := uint64(1 << 28)
   268  	d := uint64(3)
   269  	pir := DoublePIR{}
   270  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   271  
   272  	DB := MakeRandomDB(N, d, &p)
   273  	RunPIR(&pir, DB, p, []uint64{0})
   274  }
   275  
   276  func TestDoublePirCompressed(t *testing.T) {
   277          N := uint64(1 << 22)
   278          d := uint64(3)
   279          pir := DoublePIR{}
   280          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   281  
   282          DB := MakeRandomDB(N, d, &p)
   283          RunPIRCompressed(&pir, DB, p, []uint64{0})
   284  }
   285  
   286  // Test DoublePIR correctness on DB with long entries.
   287  func TestDoublePirLongRow(t *testing.T) {
   288  	N := uint64(1 << 20)
   289  	d := uint64(32)
   290  	pir := DoublePIR{}
   291  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   292  
   293  	DB := MakeRandomDB(N, d, &p)
   294  
   295  	fmt.Printf("Executing with entries consisting of %d (>= 1) bits; p is %d; packing factor is %d; number of DB elems per entry is %d.\n",
   296  		d, p.P, DB.Info.Packing, DB.Info.Ne)
   297  
   298  	RunPIR(&pir, DB, p, []uint64{1 << 19})
   299  }
   300  
   301  func TestDoublePirLongRowCompressed(t *testing.T) {
   302          N := uint64(1 << 20)
   303          d := uint64(32)
   304          pir := DoublePIR{}
   305          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   306  
   307          DB := MakeRandomDB(N, d, &p)
   308  
   309          fmt.Printf("Executing with entries consisting of %d (>= 1) bits; p is %d; packing factor is %d; number of DB elems per entry is %d.\n",
   310                  d, p.P, DB.Info.Packing, DB.Info.Ne)
   311  
   312          RunPIRCompressed(&pir, DB, p, []uint64{1 << 19})
   313  }
   314  
   315  // Test DoublePIR correctness on big DB
   316  func TestDoublePirBigDB(t *testing.T) {
   317  	N := uint64(1 << 25)
   318  	d := uint64(7)
   319  	pir := DoublePIR{}
   320  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   321  
   322  	DB := MakeRandomDB(N, d, &p)
   323  	RunPIR(&pir, DB, p, []uint64{0})
   324  }
   325  
   326  func TestDoublePirBigDBCompressed(t *testing.T) {
   327          N := uint64(1 << 23)
   328          d := uint64(7)
   329          pir := DoublePIR{}
   330          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   331  
   332          DB := MakeRandomDB(N, d, &p)
   333          RunPIRCompressed(&pir, DB, p, []uint64{0})
   334  }
   335  
   336  // Test DoublePIR correctness on DB with short entries, and batching.
   337  func TestDoublePirBatch(t *testing.T) {
   338  	N := uint64(1 << 20)
   339  	d := uint64(8)
   340  	pir := DoublePIR{}
   341  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   342  
   343  	DB := MakeRandomDB(N, d, &p)
   344  	RunPIR(&pir, DB, p, []uint64{0, 0, 0, 0})
   345  }
   346  
   347  func TestDoublePirBatchCompressed(t *testing.T) {
   348          N := uint64(1 << 20)
   349          d := uint64(8)
   350          pir := DoublePIR{}
   351          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   352  
   353          DB := MakeRandomDB(N, d, &p)
   354          RunPIRCompressed(&pir, DB, p, []uint64{0, 0, 0, 0})
   355  }
   356  
   357  // Test DoublePIR correctness on DB with long entries, and batching.
   358  func TestDoublePirLongRowBatch(t *testing.T) {
   359  	N := uint64(1 << 20)
   360  	d := uint64(32)
   361  	pir := DoublePIR{}
   362  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   363  
   364  	DB := MakeRandomDB(N, d, &p)
   365  	RunPIR(&pir, DB, p, []uint64{0, 0, 0, 0})
   366  }
   367  
   368  func TestDoublePirLongRowBatchCompressed(t *testing.T) {
   369          N := uint64(1 << 20)
   370          d := uint64(32)
   371          pir := DoublePIR{}
   372          p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   373  
   374          DB := MakeRandomDB(N, d, &p)
   375          RunPIRCompressed(&pir, DB, p, []uint64{0, 0, 0, 0})
   376  }
   377  
   378  // Benchmark SimplePIR performance.
   379  func BenchmarkSimplePirSingle(b *testing.B) {
   380  	f, err := os.Create("simple-cpu.out")
   381  	if err != nil {
   382  		panic("Error creating file")
   383  	}
   384  
   385  	N := uint64(1 << 20)
   386  	d := uint64(2048)
   387  
   388  	log_N, _ := strconv.Atoi(os.Getenv("LOG_N"))
   389  	D, _ := strconv.Atoi(os.Getenv("D"))
   390  	if log_N != 0 {
   391  		N = uint64(1 << log_N)
   392  	}
   393  	if D != 0 {
   394  		d = uint64(D)
   395  	}
   396  
   397  	pir := SimplePIR{}
   398  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   399  
   400  	i := uint64(0) // index to query
   401  	if i >= p.L*p.M {
   402  		panic("Index out of dimensions")
   403  	}
   404  
   405  	DB := MakeRandomDB(N, d, &p)
   406  	var tputs []float64
   407  	for j := 0; j < 5; j++ {
   408  		tput, _, _, _ := RunFakePIR(&pir, DB, p, []uint64{i}, f, false)
   409  		tputs = append(tputs, tput)
   410  	}
   411  	fmt.Printf("Avg SimplePIR tput, except for first run: %f MB/s\n", avg(tputs))
   412  	fmt.Printf("Std dev of SimplePIR tput, except for first run: %f MB/s\n", stddev(tputs))
   413  }
   414  
   415  // Benchmark DoublePIR performance.
   416  func BenchmarkDoublePirSingle(b *testing.B) {
   417  	f, err := os.Create("double-cpu.out")
   418  	if err != nil {
   419  		panic("Error creating file")
   420  	}
   421  
   422  	N := uint64(1 << 20)
   423  	d := uint64(2048)
   424  
   425  	log_N, _ := strconv.Atoi(os.Getenv("LOG_N"))
   426  	D, _ := strconv.Atoi(os.Getenv("D"))
   427  	if log_N != 0 {
   428  		N = uint64(1 << log_N)
   429  	}
   430  	if D != 0 {
   431  		d = uint64(D)
   432  	}
   433  
   434  	pir := DoublePIR{}
   435  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   436  
   437  	i := uint64(0) // index to query
   438  	if i >= p.L*p.M {
   439  		panic("Index out of dimensions")
   440  	}
   441  
   442  	DB := MakeRandomDB(N, d, &p)
   443  	var tputs []float64
   444  	for j := 0; j < 5; j++ {
   445  		tput, _, _, _ := RunFakePIR(&pir, DB, p, []uint64{i}, f, false)
   446  		tputs = append(tputs, tput)
   447  	}
   448  	fmt.Printf("Avg DoublePIR tput, except for first run: %f MB/s\n", avg(tputs))
   449  	fmt.Printf("Std dev of DoublePIR tput, except for first run: %f MB/s\n", stddev(tputs))
   450  }
   451  
   452  // Benchmark SimplePIR performance, on 1GB databases with increasing row length.
   453  func BenchmarkSimplePirVaryingDB(b *testing.B) {
   454  	flog, err := os.OpenFile("simple-comm.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
   455  	if err != nil {
   456  		panic("Error creating log file")
   457  	}
   458  	defer flog.Close()
   459  
   460  	writer := csv.NewWriter(flog)
   461  	defer writer.Flush()
   462  
   463  	records := []string{"N", "d", "tput", "tput_stddev", "offline_comm", "online_comm"}
   464  	writer.Write(records)
   465  
   466  	pir := SimplePIR{}
   467  
   468  	// Set N, D
   469  	total_sz := 33
   470  
   471  	for d := uint64(1); d <= 32768; d *= 2 {
   472  		N := uint64(1<<total_sz) / d
   473  		p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   474  
   475  		i := uint64(0) // index to query
   476  		if i >= p.L*p.M {
   477  			panic("Index out of dimensions")
   478  		}
   479  
   480  		DB := MakeRandomDB(N, d, &p)
   481  		var tputs []float64
   482  		var offline_cs []float64
   483  		var online_cs []float64
   484  
   485  		for j := 0; j < 5; j++ {
   486  			tput, _, offline_c, online_c := RunFakePIR(&pir, DB, p, []uint64{i}, nil, false)
   487  			tputs = append(tputs, tput)
   488  			offline_cs = append(offline_cs, offline_c)
   489  			online_cs = append(online_cs, online_c)
   490  		}
   491  		fmt.Printf("Avg SimplePIR tput (%d, %d), except for first run: %f MB/s\n", N, d, avg(tputs))
   492  		fmt.Printf("Std dev of SimplePIR tput (%d, %d), except for first run: %f MB/s\n", N, d, stddev(tputs))
   493  		if (stddev(offline_cs) != 0) || (stddev(online_cs) != 0) {
   494  			fmt.Printf("%f %f SHOULD NOT HAPPEN\n", stddev(offline_cs), stddev(online_cs))
   495  			//panic("Should not happen!")
   496  		}
   497  		writer.Write([]string{strconv.FormatUint(N, 10),
   498  			strconv.FormatUint(d, 10),
   499  			strconv.FormatFloat(avg(tputs), 'f', 4, 64),
   500  			strconv.FormatFloat(stddev(tputs), 'f', 4, 64),
   501  			strconv.FormatFloat(avg(offline_cs), 'f', 4, 64),
   502  			strconv.FormatFloat(avg(online_cs), 'f', 4, 64)})
   503  	}
   504  }
   505  
   506  // Benchmark DoublePIR performance, on 1 GB databases with increasing row length.
   507  func BenchmarkDoublePirVaryingDB(b *testing.B) {
   508  	flog, err := os.OpenFile("double-comm.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
   509  	if err != nil {
   510  		panic("Error creating log file")
   511  	}
   512  	defer flog.Close()
   513  
   514  	writer := csv.NewWriter(flog)
   515  	defer writer.Flush()
   516  
   517  	records := []string{"N", "d", "tput", "tput_stddev", "offline_comm", "online_comm"}
   518  	writer.Write(records)
   519  
   520  	pir := DoublePIR{}
   521  
   522  	// Set N, D
   523  	total_sz := 33
   524  	for d := uint64(1); d <= 32768; d *= 2 {
   525  		N := uint64(1<<total_sz) / d
   526  		p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   527  
   528  		i := uint64(0) // index to query
   529  		if i >= p.L*p.M {
   530  			panic("Index out of dimensions")
   531  		}
   532  
   533  		DB := MakeRandomDB(N, d, &p)
   534  		var tputs []float64
   535  		var offline_cs []float64
   536  		var online_cs []float64
   537  
   538  		for j := 0; j < 5; j++ {
   539  			tput, _, offline_c, online_c := RunFakePIR(&pir, DB, p, []uint64{i}, nil, false)
   540  			tputs = append(tputs, tput)
   541  			offline_cs = append(offline_cs, offline_c)
   542  			online_cs = append(online_cs, online_c)
   543  		}
   544  		fmt.Printf("Avg SimplePIR tput (%d, %d), except for first run: %f MB/s\n", N, d, avg(tputs))
   545  		fmt.Printf("Std dev of SimplePIR tput (%d, %d), except for first run: %f MB/s\n", N, d, stddev(tputs))
   546  		if (stddev(offline_cs) != 0) || (stddev(online_cs) != 0) {
   547  			fmt.Printf("%f %f SHOULD NOT HAPPEN\n", stddev(offline_cs), stddev(online_cs))
   548  			//panic("Should not happen!")
   549  		}
   550  		writer.Write([]string{strconv.FormatUint(N, 10),
   551  			strconv.FormatUint(d, 10),
   552  			strconv.FormatFloat(avg(tputs), 'f', 4, 64),
   553  			strconv.FormatFloat(stddev(tputs), 'f', 4, 64),
   554  			strconv.FormatFloat(avg(offline_cs), 'f', 4, 64),
   555  			strconv.FormatFloat(avg(online_cs), 'f', 4, 64)})
   556  	}
   557  }
   558  
   559  // Benchmark SimplePIR performance with batches of increasing size.
   560  func BenchmarkSimplePirBatchLarge(b *testing.B) {
   561  	f, err := os.Create("simple-cpu-batch.out")
   562  	if err != nil {
   563  		panic("Error creating file")
   564  	}
   565  
   566  	flog, err := os.Create("simple-batch.log")
   567  	if err != nil {
   568  		panic("Error creating log file")
   569  	}
   570  	defer flog.Close()
   571  
   572  	N := uint64(1 << 33)
   573  	d := uint64(1)
   574  
   575  	log_N, _ := strconv.Atoi(os.Getenv("LOG_N"))
   576  	D, _ := strconv.Atoi(os.Getenv("D"))
   577  	if log_N != 0 {
   578  		N = uint64(1 << log_N)
   579  	}
   580  	if D != 0 {
   581  		d = uint64(D)
   582  	}
   583  
   584  	pir := SimplePIR{}
   585  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   586  
   587  	i := uint64(0) // index to query
   588  	if i >= p.L*p.M {
   589  		panic("Index out of dimensions")
   590  	}
   591  
   592  	DB := MakeRandomDB(N, d, &p)
   593  
   594  	writer := csv.NewWriter(flog)
   595  	defer writer.Flush()
   596  
   597  	records := []string{"Batch_sz", "Good_tput", "Good_std_dev", "Num_successful_queries", "Tput"}
   598  	writer.Write(records)
   599  
   600  	for trial := 0; trial <= 10; trial += 1 {
   601  		batch_sz := (1 << trial)
   602  		var query []uint64
   603  		for j := 0; j < batch_sz; j++ {
   604  			query = append(query, i)
   605  		}
   606  		var tputs []float64
   607  		for iter := 0; iter < 5; iter++ {
   608  			tput, _, _, _ := RunFakePIR(&pir, DB, p, query, f, false)
   609  			tputs = append(tputs, tput)
   610  		}
   611  
   612  		expected_num_empty_buckets := math.Pow(float64(batch_sz-1)/float64(batch_sz), float64(batch_sz)) * float64(batch_sz)
   613  		expected_num_successful_queries := float64(batch_sz) - expected_num_empty_buckets
   614  		good_tput := avg(tputs) / float64(batch_sz) * expected_num_successful_queries
   615  		dev := stddev(tputs) / float64(batch_sz) * expected_num_successful_queries
   616  
   617  		writer.Write([]string{strconv.Itoa(batch_sz),
   618  			strconv.FormatFloat(good_tput, 'f', 4, 64),
   619  			strconv.FormatFloat(dev, 'f', 4, 64),
   620  			strconv.FormatFloat(expected_num_successful_queries, 'f', 4, 64),
   621  			strconv.FormatFloat(avg(tputs), 'f', 4, 64)})
   622  	}
   623  }
   624  
   625  // Benchmark DoublePIR performance with batches of increasing size.
   626  func BenchmarkDoublePirBatchLarge(b *testing.B) {
   627  	f, err := os.Create("double-cpu-batch.out")
   628  	if err != nil {
   629  		panic("Error creating file")
   630  	}
   631  
   632  	flog, err := os.Create("double-batch.log")
   633  	if err != nil {
   634  		panic("Error creating log file")
   635  	}
   636  	defer flog.Close()
   637  
   638  	N := uint64(1 << 33)
   639  	d := uint64(1)
   640  
   641  	log_N, _ := strconv.Atoi(os.Getenv("LOG_N"))
   642  	D, _ := strconv.Atoi(os.Getenv("D"))
   643  	if log_N != 0 {
   644  		N = uint64(1 << log_N)
   645  	}
   646  	if D != 0 {
   647  		d = uint64(D)
   648  	}
   649  
   650  	pir := DoublePIR{}
   651  	p := pir.PickParams(N, d, SEC_PARAM, LOGQ)
   652  
   653  	i := uint64(0) // index to query
   654  	if i >= p.L*p.M {
   655  		panic("Index out of dimensions")
   656  	}
   657  
   658  	DB := MakeRandomDB(N, d, &p)
   659  
   660  	writer := csv.NewWriter(flog)
   661  	defer writer.Flush()
   662  
   663  	records := []string{"Batch_sz", "Good_tput", "Good_std_dev", "Num_successful_queries", "Tput"}
   664  	writer.Write(records)
   665  
   666  	for trial := 0; trial <= 10; trial += 1 {
   667  		batch_sz := (1 << trial)
   668  		var query []uint64
   669  		for j := 0; j < batch_sz; j++ {
   670  			query = append(query, i)
   671  		}
   672  		var tputs []float64
   673  		for iter := 0; iter < 5; iter++ {
   674  			tput, _, _, _ := RunFakePIR(&pir, DB, p, query, f, false)
   675  			tputs = append(tputs, tput)
   676  		}
   677  		expected_num_empty_buckets := math.Pow(float64(batch_sz-1)/float64(batch_sz), float64(batch_sz)) * float64(batch_sz)
   678  		expected_num_successful_queries := float64(batch_sz) - expected_num_empty_buckets
   679  		good_tput := avg(tputs) / float64(batch_sz) * expected_num_successful_queries
   680  		dev := stddev(tputs) / float64(batch_sz) * expected_num_successful_queries
   681  
   682  		writer.Write([]string{strconv.Itoa(batch_sz),
   683  			strconv.FormatFloat(good_tput, 'f', 4, 64),
   684  			strconv.FormatFloat(dev, 'f', 4, 64),
   685  			strconv.FormatFloat(expected_num_successful_queries, 'f', 4, 64),
   686  			strconv.FormatFloat(avg(tputs), 'f', 4, 64)})
   687  	}
   688  }