Skip to content
This repository was archived by the owner on Jan 5, 2022. It is now read-only.

Commit

Permalink
Impl sqrt for fq & fq2 with their test
Browse files Browse the repository at this point in the history
  • Loading branch information
saitima committed Mar 30, 2020
1 parent 5d91d38 commit 6e85493
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 1 deletion.
77 changes: 77 additions & 0 deletions field_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type field interface {
square(c, a fieldElement)
exp(c, a fieldElement, e *big.Int)
inverse(c, a fieldElement) bool
sqrt(c, a fieldElement) bool
}

type fqTest struct {
Expand Down Expand Up @@ -127,6 +128,10 @@ func (t fqTest) inverse(c, a fieldElement) bool {
return t.fq.inverse(c.(fe), a.(fe))
}

func (t fqTest) sqrt(c, a fieldElement) bool {
return t.fq.sqrt(c.(fe), a.(fe))
}

type fq2Test struct {
*fq2
}
Expand Down Expand Up @@ -223,6 +228,10 @@ func (t fq2Test) mulByFq(c, a fieldElement, b fieldElement) {
t.fq2.mulByFq(c.(*fe2), a.(*fe2), b.(fe))
}

func (t fq2Test) sqrt(c, a fieldElement) bool {
return t.fq2.sqrt(c.(*fe2), a.(*fe2))
}

type fq3Test struct {
*fq3
}
Expand Down Expand Up @@ -319,6 +328,11 @@ func (t fq3Test) mulByFq(c, a fieldElement, b fieldElement) {
t.fq3.mulByFq(c.(*fe3), a.(*fe3), b.(fe))
}

func (t fq3Test) sqrt(c, a fieldElement) bool {
// return t.fq.sqrt(c.(*fe3), a.(*fe3))
return true
}

type fq4Test struct {
*fq4
}
Expand Down Expand Up @@ -411,6 +425,11 @@ func (t fq4Test) inverse(c, a fieldElement) bool {
return t.fq4.inverse(c.(*fe4), a.(*fe4))
}

func (t fq4Test) sqrt(c, a fieldElement) bool {
// return t.fq.sqrt(c.(*fe4), a.(*fe4))
return true
}

type fq6CTest struct {
*fq6C
}
Expand Down Expand Up @@ -503,6 +522,11 @@ func (t fq6CTest) inverse(c, a fieldElement) bool {
return t.fq6C.inverse(c.(*fe6C), a.(*fe6C))
}

func (t fq6CTest) sqrt(c, a fieldElement) bool {
// return t.fq.sqrt(c.(*fe6C), a.(*fe6C))
return true
}

type fq6QTest struct {
*fq6Q
}
Expand Down Expand Up @@ -595,6 +619,11 @@ func (t fq6QTest) inverse(c, a fieldElement) bool {
return t.fq6Q.inverse(c.(*fe6Q), a.(*fe6Q))
}

func (t fq6QTest) sqrt(c, a fieldElement) bool {
// return t.fq.sqrt(c.(*fe6Q), a.(*fe6Q))
return true
}

type fq12Test struct {
*fq12
}
Expand Down Expand Up @@ -687,6 +716,11 @@ func (t fq12Test) inverse(c, a fieldElement) bool {
return t.fq12.inverse(c.(*fe12), a.(*fe12))
}

func (t fq12Test) sqrt(c, a fieldElement) bool {
// return t.fq.sqrt(c.(*fe12), a.(*fe12))
return true
}

func randFq(limbSize int) *fq {
var offset int
t, err := rand.Int(rand.Reader, new(big.Int).SetUint64(64))
Expand Down Expand Up @@ -1003,6 +1037,7 @@ func randFq2(limbSize int) *fq2 {
break
}
}
fq2.calculateFrobeniusCoeffs()
return fq2
}

Expand Down Expand Up @@ -1383,3 +1418,45 @@ func TestFqInversion(t *testing.T) {
}
}
}

func TestFqSquareRoot(t *testing.T) {
fields = []string{"FQ"}
for _, ext := range fields {
for limbSize := from; limbSize < 4; limbSize++ {
// for limbSize := from; limbSize < to+1; limbSize++ {
t.Run(fmt.Sprintf("%d_%s", limbSize*64, ext), func(t *testing.T) {
for i := 0; i < fuz; i++ {
field := randField(ext, limbSize)
u := field.new()
zero := field.zero()
one := field.one()
field.sqrt(u, zero)
if !field.equal(u, zero) {
t.Errorf("(0^(1/2)) == 0)")
}
field.sqrt(u, one)
if !field.equal(u, one) {
t.Errorf("(1^(1/2)) == 1)")
}
v, w, negA := field.new(), field.new(), field.new()
a := field.rand(rand.Reader)
field.neg(negA, a)
field.square(u, a)
field.square(w, negA)
if !field.equal(w, u) {
t.Errorf("square of r and -r is not same")
}
if hasRoot := field.sqrt(v, u); !hasRoot {
t.Errorf("elem has no square-root")
}
if !field.equal(a, v) && !field.equal(negA, v) {
field.debugElement(a)
field.debugElement(negA)
field.debugElement(v)
t.Errorf("((r)^2)^(1/2) == r)")
}
}
})
}
}
}
31 changes: 30 additions & 1 deletion fq.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,35 @@ func (f *fq) exp(c, a fe, e *big.Int) {
f.copy(c, z)
}

func (f *fq) sqrt(c, a fe) bool {
negOne, tmp, b := f.new(), f.new(), f.new()
f.neg(negOne, f.one)

// power = (p-3)/4
power := new(big.Int).Rsh(f.pbig, 2)
// b = a^((p-3)/4)
f.exp(b, a, power)
// tmp = b^2 = a^(p-3/2) = a^-1 * a^(p-1/2)
// if a is a square then a^(p-1/2) is 1 else -1
// so tmp = a^-1 or -a^-1
f.square(tmp, b)
// check that a*a^-1 is -1
f.mul(tmp, tmp, a)
if f.equal(tmp, negOne) {
f.copy(c, f.zero)
return false
}
// c = a^(p-3/4) * a = a^(p+1/4)
f.mul(c, b, a)
return true
}

func (f *fq) sign(fe fe) int8 {
neg := f.new()
f.neg(neg, fe)
return f.cmp(fe, neg)
}

func (f *fq) isOne(fe fe) bool {
return f.equal(fe, f.one)
}
Expand Down Expand Up @@ -492,7 +521,7 @@ func (f *fq) fromBytes(in []byte) (fe, error) {
func (f *fq) fromString(hexStr string) (fe, error) {
str := hexStr
if len(str) > 1 && str[:2] == "0x" {
str = hexStr[:2]
str = hexStr[2:]
}
in, err := hex.DecodeString(str)
if err != nil {
Expand Down
51 changes: 51 additions & 0 deletions fq2.go
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,57 @@ func (f *fq2) exp(c, a *fe2, e *big.Int) {
f.copy(c, z)
}

func (f *fq2) sqrt(c, a *fe2) bool {
// if p = 3 mod 4 then we can simply use righ-shift
// for division by multiples of two in order to get (p-3/4)

negOne, tmp, b := f.new(), f.new(), f.new()

pMinusThreeByFour := new(big.Int).Rsh(f.f.pbig, 2)
f.exp(b, a, pMinusThreeByFour)

f.square(tmp, b)
f.mul(tmp, tmp, a)
a0 := f.new()
f.frobeniusMap(a0, tmp, 1)
f.mul(a0, a0, tmp)

f.neg(negOne, f.one())
if f.equal(a0, negOne) {
f.copy(c, f.zero())
return false
}

f.mul(b, b, a)
if f.equal(tmp, negOne) {
zeroOne := f.new()
f.f.copy(zeroOne[0], f.f.zero)
f.f.copy(zeroOne[1], f.f.one)
f.mul(c, b, zeroOne)
} else {
f.add(tmp, tmp, f.one())
pMinusOneByTwo := new(big.Int).Rsh(f.f.pbig, 1)
f.exp(tmp, tmp, pMinusOneByTwo)
f.mul(c, b, tmp)
}
return true
}

func (f *fq2) sign(fe *fe2) int8 {
neg := f.new()
f.neg(neg, fe)

return f.cmp(fe, neg)
}

func (f *fq2) cmp(a, b *fe2) int8 {
cmp := f.f.cmp(a[1], b[1])
if cmp == 0 {
return f.f.cmp(a[0], b[0])
}
return cmp
}

func (f *fq2) mulByFq(c, a *fe2, b fe) {
fq := f.fq()
fq.mul(c[0], a[0], b)
Expand Down

0 comments on commit 6e85493

Please sign in to comment.