~edwargix/tallyard

bde2442514d08f1aa4299f52886eb0ad3cfd7f9f — David Florness 5 years ago 0945ec7
Polynomials
1 files changed, 69 insertions(+), 0 deletions(-)

A poly.go
A poly.go => poly.go +69 -0
@@ 0,0 1,69 @@
package main

import (
	"crypto/rand"
	"math"
	"math/big"
)

type Poly struct {
	constant *big.Int
	coefs    []*big.Int
}

func RandomBigInt(numBytes uint, allowAllZeros bool) (*big.Int, error) {
	randBytes := make([]byte, numBytes)
	_, err := rand.Read(randBytes)
	if err != nil {
		return nil, err
	}
	bi := big.Int{}
	bi.SetBytes(randBytes)
	if bi.Cmp(big.NewInt(0)) == 0 {
		return RandomBigInt(numBytes, allowAllZeros)
	}
	return bi.SetBytes(randBytes), nil
}

// creates a random polynomial of the given degree, uses at least `entropy' bits
// of entropy for the random coefficients, and assigns the ballot to the
// constant term
func NewRandomPoly(degree uint, entropy uint, ballot []byte) *Poly {
	constant := &big.Int{}
	constant.SetBytes(ballot)
	p := &Poly{constant, make([]*big.Int, degree)}

	// number of bits per coefficient
	numBits := uint(math.Ceil(float64(entropy)/float64(degree)))

	// number of bytes per coefficient
	numBytes := numBits / 8
	if numBits % 8 > 0 {
		numBytes += 1
	}

	var err error
	for i := range p.coefs {
		p.coefs[i], err = RandomBigInt(numBytes, false)
		if err != nil {
			panic(err)
		}
	}

	return p
}

func (p *Poly) Eval(input *big.Int) *big.Int {
	res := &big.Int{}
	res.Set(p.constant)

	for i, coef := range p.coefs {
		degree := big.NewInt(int64(i+1))
		term := &big.Int{}
		term.Exp(input, degree, nil)
		term.Mul(term, coef)
		res.Add(res, term)
	}

	return res
}