예제 #1
0
// Tests if the encoding process correctly decodes the id back to the original.
func TestEncoding(t *testing.T) {
	for i := 0; i < 15; i++ { //How many times we want to run GenerateSeed()
		o, _, _ := GenerateSeed(nil)

		c := 10
		h := 100 //How many random numbers to select in between 0-c and (MAX_INT-c) - MAX-INT

		var y []uint64 //Stores all the values we want to run encoding tests on

		for t := 0; t < c; t++ {
			y = append(y, uint64(t))
		}

		//Generate Random numbers
		for t := 0; t < h; t++ {
			upper := *big.NewInt(int64(MAX_INT - 2*c))
			rand, _ := rand.Int(rand.Reader, &upper)
			randomNumber := rand.Uint64() + uint64(c)

			y = append(y, randomNumber)
		}

		for t := MAX_INT; t >= MAX_INT-c; t-- {
			y = append(y, uint64(t))
		}

		t.Logf("Prime: %d ModInverse: %d Random: %d", o.Prime(), o.ModInverse(), o.Random())
		for _, value := range y {
			orig := value
			hashed := o.Encode(value)
			unhashed := o.Decode(hashed)

			if orig != unhashed {
				t.Errorf("%d: %d -> %d - FAILED", orig, hashed, unhashed)
			} else {
				t.Logf("%d: %d -> %d - PASSED", orig, hashed, unhashed)
				// log.Printf("%d: %d -> %d - PASSED", orig, hashed, unhashed)
			}
		}

	}
}
예제 #2
0
// Generates a valid Optimus struct using a randomly selected prime
// number from this site: http://primes.utm.edu/lists/small/millions/
// The first 50 million prime numbers are distributed evenly in 50 files.
// Parameter req should be nil if not using Google App Engine.
// This Function is Time, Memory and CPU intensive. Run it once to generate the
// required seeds.
// WARNING: Potentially Insecure. Double check that the prime number returned
// is actually prime number using an independent source.
// The largest Prime has 9 digits. The smallest has 1 digit.
// The final return value is the website zip file identifier that was used to obtain the prime number
func GenerateSeed(req *http.Request) (*Optimus, error, uint8) {
	log.Printf("\x1b[31mWARNING: Optimus generates a random number via this site: http://primes.utm.edu/lists/small/millions/. This is potentially insecure!\x1b[39;49m")

	baseURL := "http://primes.utm.edu/lists/small/millions/primes%d.zip"

	//Generate Random number between 1-50
	b_49 := *big.NewInt(49)
	n, _ := rand.Int(rand.Reader, &b_49)
	i_n := n.Uint64() + 1

	//Download zip file
	finalUrl := fmt.Sprintf(baseURL, i_n)
	log.Printf("Using file: %s", finalUrl)

	resp, err := client(req).Get(finalUrl)
	if err != nil {
		return nil, jsonerror.New(1, "Could not generate seed", err.Error()), uint8(i_n)
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, jsonerror.New(1, "Could not generate seed", err.Error()), uint8(i_n)
	}

	r, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength)
	if err != nil {
		return nil, jsonerror.New(1, "Could not generate seed", err.Error()), uint8(i_n)
	}

	zippedFile := r.File[0]

	src, err := zippedFile.Open() //src contains ReaderCloser
	if err != nil {
		return nil, jsonerror.New(1, "Could not generate seed", err.Error()), uint8(i_n)
	}
	defer src.Close()

	//Create a Byte Slice
	buf := new(bytes.Buffer)
	noOfBytes, _ := buf.ReadFrom(src)
	b := buf.Bytes() //Byte Slice

	//Randomly pick a character position
	start := 67 // Each zip file has an introductory header which is not relevant until the 67th character
	end := noOfBytes

	b_end := *big.NewInt(int64(end) - int64(start))
	n, _ = rand.Int(rand.Reader, &b_end)
	randomPosition := n.Uint64() + uint64(start)

	min := randomPosition - 9
	max := randomPosition + 9

	if min < uint64(start) {
		min = uint64(start)
	}

	if max > uint64(end) {
		max = uint64(end)
	}

	scanner := bufio.NewScanner(strings.NewReader(string(b[min:max]))) //Input
	scanner.Split(bufio.ScanWords)

	var selectedNumbers []uint64
	for scanner.Scan() {
		p, _ := strconv.ParseUint(scanner.Text(), 10, 64)
		selectedNumbers = append(selectedNumbers, p)
	}

	//Not perfect but good enough

	var selectedPrime uint64
	length := len(selectedNumbers)
	if length > 2 {
		//Pick middle number

		//Check if length is even number
		//Check if round is odd or even
		var odd bool
		if length&1 != 0 {
			odd = true //odd
		} else {
			odd = false //even
		}

		if odd {
			selectedPrime = selectedNumbers[length/2]
		} else {

			r := *big.NewInt(1)
			rn, _ := rand.Int(rand.Reader, &r)
			if rn.Uint64() == 0 {
				selectedPrime = selectedNumbers[length/2]
			} else {
				selectedPrime = selectedNumbers[length/2-1]
			}
		}
	} else {
		//Pick largest number
		largest := selectedNumbers[0]

		for _, value := range selectedNumbers {
			if value > largest {
				largest = value
			}
		}

		selectedPrime = largest
	}

	//Calculate Mod Inverse for selectedPrime
	modInverse := ModInverse(selectedPrime)

	//Generate Random Integer less than MAX_INT
	upper := *big.NewInt(MAX_INT - 2)
	rand, _ := rand.Int(rand.Reader, &upper)
	randomNumber := rand.Uint64() + 1

	return &Optimus{selectedPrime, modInverse, randomNumber}, nil, uint8(i_n)
}