arnaucube
arnaucube/go-circom-prover-verifierPublic Self-hosted repository
go-circom-prover-verifier/prover/ifft.go
prover/ifft.goRaw
  1package prover
  2
  3import (
  4	"math"
  5	"math/big"
  6
  7	"github.com/iden3/go-circom-prover-verifier/types"
  8	"github.com/iden3/go-iden3-crypto/ff"
  9)
 10
 11type rootsT struct {
 12	roots [][]*ff.Element
 13	w     []*ff.Element
 14}
 15
 16func newRootsT() rootsT {
 17	var roots rootsT
 18
 19	rem := new(big.Int).Sub(types.R, big.NewInt(1))
 20	s := 0
 21	for rem.Bit(0) == 0 { // rem.Bit==0 when even
 22		s++
 23		rem = new(big.Int).Rsh(rem, 1)
 24	}
 25	roots.w = make([]*ff.Element, s+1)
 26	roots.w[s] = ff.NewElement().SetBigInt(fExp(big.NewInt(5), rem))
 27
 28	n := s - 1
 29	for n >= 0 {
 30		roots.w[n] = ff.NewElement().Mul(roots.w[n+1], roots.w[n+1])
 31		n--
 32	}
 33	roots.roots = make([][]*ff.Element, 50) // TODO WIP
 34
 35	roots.setRoots(15)
 36	return roots
 37}
 38
 39func (roots rootsT) setRoots(n int) {
 40	for i := n; i >= 0 && nil == roots.roots[i]; i-- { // TODO tmp i<=len(r)
 41		r := ff.NewElement().SetBigInt(big.NewInt(1))
 42		nroots := 1 << i
 43		var rootsi []*ff.Element
 44		for j := 0; j < nroots; j++ {
 45			rootsi = append(rootsi, r)
 46			r = ff.NewElement().Mul(r, roots.w[i])
 47		}
 48		roots.roots[i] = rootsi
 49	}
 50}
 51
 52func fftroots(roots rootsT, pall []*ff.Element, bits, offset, step int) []*ff.Element {
 53	n := 1 << bits
 54	if n == 1 {
 55		return []*ff.Element{pall[offset]}
 56	} else if n == 2 {
 57		return []*ff.Element{
 58			ff.NewElement().Add(pall[offset], pall[offset+step]), // TODO tmp
 59			ff.NewElement().Sub(pall[offset], pall[offset+step]),
 60		}
 61	}
 62
 63	ndiv2 := n >> 1
 64	p1 := fftroots(roots, pall, bits-1, offset, step*2)
 65	p2 := fftroots(roots, pall, bits-1, offset+step, step*2)
 66
 67	out := make([]*ff.Element, n)
 68	for i := 0; i < ndiv2; i++ {
 69		out[i] = ff.NewElement().Add(p1[i], ff.NewElement().Mul(roots.roots[bits][i], p2[i]))
 70		out[i+ndiv2] = ff.NewElement().Sub(p1[i], ff.NewElement().Mul(roots.roots[bits][i], p2[i]))
 71	}
 72	return out
 73}
 74
 75func fft(p []*ff.Element) []*ff.Element {
 76	if len(p) <= 1 {
 77		return p
 78	}
 79	bits := math.Log2(float64(len(p)-1)) + 1
 80	roots := newRootsT()
 81	roots.setRoots(int(bits))
 82	m := 1 << int(bits)
 83	ep := extend(p, m)
 84	res := fftroots(roots, ep, int(bits), 0, 1)
 85	return res
 86}
 87
 88func ifft(p []*ff.Element) []*ff.Element {
 89	res := fft(p)
 90	bits := math.Log2(float64(len(p)-1)) + 1
 91	m := 1 << int(bits)
 92
 93	twoinvm := ff.NewElement().SetBigInt(fInv(fMul(big.NewInt(1), big.NewInt(int64(m)))))
 94
 95	var resn []*ff.Element
 96	for i := 0; i < m; i++ {
 97		resn = append(resn, ff.NewElement().Mul(res[(m-i)%m], twoinvm))
 98	}
 99
100	return resn
101}
102
103func extend(p []*ff.Element, e int) []*ff.Element {
104	if e == len(p) {
105		return p
106	}
107	z := arrayOfZeroesE(e - len(p))
108	return append(p, z...)
109}