blob: 3ed1d04da770476554a080850fd5c6ad2d3427eb [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package amcl
//import "fmt"
/* Elliptic Curve Point Structure */
type ECP struct {
x *FP
y *FP
z *FP
INF bool
}
/* Constructors */
func NewECP() *ECP {
E := new(ECP)
E.x = NewFPint(0)
E.y = NewFPint(0)
E.z = NewFPint(0)
E.INF = true
return E
}
/* set (x,y) from two BIGs */
func NewECPbigs(ix *BIG, iy *BIG) *ECP {
E := new(ECP)
E.x = NewFPbig(ix)
E.y = NewFPbig(iy)
E.z = NewFPint(1)
rhs := RHS(E.x)
if CURVETYPE == MONTGOMERY {
if rhs.jacobi() == 1 {
E.INF = false
} else {
E.inf()
}
} else {
y2 := NewFPcopy(E.y)
y2.sqr()
if y2.equals(rhs) {
E.INF = false
} else {
E.inf()
}
}
return E
}
/* set (x,y) from BIG and a bit */
func NewECPbigint(ix *BIG, s int) *ECP {
E := new(ECP)
E.x = NewFPbig(ix)
E.y = NewFPint(0)
rhs := RHS(E.x)
E.z = NewFPint(1)
if rhs.jacobi() == 1 {
ny := rhs.sqrt()
if ny.redc().parity() != s {
ny.neg()
}
E.y.copy(ny)
E.INF = false
} else {
E.inf()
}
return E
}
/* set from x - calculate y from curve equation */
func NewECPbig(ix *BIG) *ECP {
E := new(ECP)
E.x = NewFPbig(ix)
E.y = NewFPint(0)
rhs := RHS(E.x)
E.z = NewFPint(1)
if rhs.jacobi() == 1 {
if CURVETYPE != MONTGOMERY {
E.y.copy(rhs.sqrt())
}
E.INF = false
} else {
E.INF = true
}
return E
}
/* test for O point-at-infinity */
func (E *ECP) is_infinity() bool {
if CURVETYPE == EDWARDS {
E.x.reduce()
E.y.reduce()
E.z.reduce()
return (E.x.iszilch() && E.y.equals(E.z))
} else {
return E.INF
}
}
/* Conditional swap of P and Q dependant on d */
func (E *ECP) cswap(Q *ECP, d int32) {
E.x.cswap(Q.x, d)
if CURVETYPE != MONTGOMERY {
E.y.cswap(Q.y, d)
}
E.z.cswap(Q.z, d)
if CURVETYPE != EDWARDS {
bd := true
if d == 0 {
bd = false
}
bd = bd && (E.INF != Q.INF)
E.INF = (bd != E.INF)
Q.INF = (bd != Q.INF)
}
}
/* Conditional move of Q to P dependant on d */
func (E *ECP) cmove(Q *ECP, d int32) {
E.x.cmove(Q.x, d)
if CURVETYPE != MONTGOMERY {
E.y.cmove(Q.y, d)
}
E.z.cmove(Q.z, d)
if CURVETYPE != EDWARDS {
bd := true
if d == 0 {
bd = false
}
E.INF = (E.INF != ((E.INF != Q.INF) && bd))
}
}
/* return 1 if b==c, no branching */
func teq(b int32, c int32) int32 {
x := b ^ c
x -= 1 // if x=0, x now -1
return ((x >> 31) & 1)
}
/* this=P */
func (E *ECP) copy(P *ECP) {
E.x.copy(P.x)
if CURVETYPE != MONTGOMERY {
E.y.copy(P.y)
}
E.z.copy(P.z)
E.INF = P.INF
}
/* this=-this */
func (E *ECP) neg() {
if E.is_infinity() {
return
}
if CURVETYPE == WEIERSTRASS {
E.y.neg()
E.y.reduce()
}
if CURVETYPE == EDWARDS {
E.x.neg()
E.x.reduce()
}
return
}
/* Constant time select from pre-computed table */
func (E *ECP) selector(W []*ECP, b int32) {
MP := NewECP()
m := b >> 31
babs := (b ^ m) - m
babs = (babs - 1) / 2
E.cmove(W[0], teq(babs, 0)) // conditional move
E.cmove(W[1], teq(babs, 1))
E.cmove(W[2], teq(babs, 2))
E.cmove(W[3], teq(babs, 3))
E.cmove(W[4], teq(babs, 4))
E.cmove(W[5], teq(babs, 5))
E.cmove(W[6], teq(babs, 6))
E.cmove(W[7], teq(babs, 7))
MP.copy(E)
MP.neg()
E.cmove(MP, (m & 1))
}
/* set this=O */
func (E *ECP) inf() {
E.INF = true
E.x.zero()
E.y.one()
E.z.one()
}
/* Test P == Q */
func (E *ECP) equals(Q *ECP) bool {
if E.is_infinity() && Q.is_infinity() {
return true
}
if E.is_infinity() || Q.is_infinity() {
return false
}
if CURVETYPE == WEIERSTRASS {
zs2 := NewFPcopy(E.z)
zs2.sqr()
zo2 := NewFPcopy(Q.z)
zo2.sqr()
zs3 := NewFPcopy(zs2)
zs3.mul(E.z)
zo3 := NewFPcopy(zo2)
zo3.mul(Q.z)
zs2.mul(Q.x)
zo2.mul(E.x)
if !zs2.equals(zo2) {
return false
}
zs3.mul(Q.y)
zo3.mul(E.y)
if !zs3.equals(zo3) {
return false
}
} else {
a := NewFPint(0)
b := NewFPint(0)
a.copy(E.x)
a.mul(Q.z)
a.reduce()
b.copy(Q.x)
b.mul(E.z)
b.reduce()
if !a.equals(b) {
return false
}
if CURVETYPE == EDWARDS {
a.copy(E.y)
a.mul(Q.z)
a.reduce()
b.copy(Q.y)
b.mul(E.z)
b.reduce()
if !a.equals(b) {
return false
}
}
}
return true
}
/* Calculate RHS of curve equation */
func RHS(x *FP) *FP {
x.norm()
r := NewFPcopy(x)
r.sqr()
if CURVETYPE == WEIERSTRASS { // x^3+Ax+B
b := NewFPbig(NewBIGints(CURVE_B))
r.mul(x)
if CURVE_A == -3 {
cx := NewFPcopy(x)
cx.imul(3)
cx.neg()
cx.norm()
r.add(cx)
}
r.add(b)
}
if CURVETYPE == EDWARDS { // (Ax^2-1)/(Bx^2-1)
b := NewFPbig(NewBIGints(CURVE_B))
one := NewFPint(1)
b.mul(r)
b.sub(one)
if CURVE_A == -1 {
r.neg()
}
r.sub(one)
b.inverse()
r.mul(b)
}
if CURVETYPE == MONTGOMERY { // x^3+Ax^2+x
x3 := NewFPint(0)
x3.copy(r)
x3.mul(x)
r.imul(CURVE_A)
r.add(x3)
r.add(x)
}
r.reduce()
return r
}
/* set to affine - from (x,y,z) to (x,y) */
func (E *ECP) affine() {
if E.is_infinity() {
return
}
one := NewFPint(1)
if E.z.equals(one) {
return
}
E.z.inverse()
if CURVETYPE == WEIERSTRASS {
z2 := NewFPcopy(E.z)
z2.sqr()
E.x.mul(z2)
E.x.reduce()
E.y.mul(z2)
E.y.mul(E.z)
E.y.reduce()
}
if CURVETYPE == EDWARDS {
E.x.mul(E.z)
E.x.reduce()
E.y.mul(E.z)
E.y.reduce()
}
if CURVETYPE == MONTGOMERY {
E.x.mul(E.z)
E.x.reduce()
}
E.z.one()
}
/* extract x as a BIG */
func (E *ECP) getX() *BIG {
E.affine()
return E.x.redc()
}
/* extract y as a BIG */
func (E *ECP) getY() *BIG {
E.affine()
return E.y.redc()
}
/* get sign of Y */
func (E *ECP) getS() int {
E.affine()
y := E.getY()
return y.parity()
}
/* extract x as an FP */
func (E *ECP) getx() *FP {
return E.x
}
/* extract y as an FP */
func (E *ECP) gety() *FP {
return E.y
}
/* extract z as an FP */
func (E *ECP) getz() *FP {
return E.z
}
/* convert to byte array */
func (E *ECP) toBytes(b []byte) {
var t [int(MODBYTES)]byte
MB := int(MODBYTES)
if CURVETYPE != MONTGOMERY {
b[0] = 0x04
} else {
b[0] = 0x02
}
E.affine()
E.x.redc().toBytes(t[:])
for i := 0; i < MB; i++ {
b[i+1] = t[i]
}
if CURVETYPE != MONTGOMERY {
E.y.redc().toBytes(t[:])
for i := 0; i < MB; i++ {
b[i+MB+1] = t[i]
}
}
}
/* convert from byte array to point */
func ECP_fromBytes(b []byte) *ECP {
var t [int(MODBYTES)]byte
MB := int(MODBYTES)
p := NewBIGints(Modulus)
for i := 0; i < MB; i++ {
t[i] = b[i+1]
}
px := fromBytes(t[:])
if comp(px, p) >= 0 {
return NewECP()
}
if b[0] == 0x04 {
for i := 0; i < MB; i++ {
t[i] = b[i+MB+1]
}
py := fromBytes(t[:])
if comp(py, p) >= 0 {
return NewECP()
}
return NewECPbigs(px, py)
} else {
return NewECPbig(px)
}
}
/* convert to hex string */
func (E *ECP) toString() string {
if E.is_infinity() {
return "infinity"
}
E.affine()
if CURVETYPE == MONTGOMERY {
return "(" + E.x.redc().toString() + ")"
} else {
return "(" + E.x.redc().toString() + "," + E.y.redc().toString() + ")"
}
}
/* this*=2 */
func (E *ECP) dbl() {
if CURVETYPE == WEIERSTRASS {
if E.INF {
return
}
if E.y.iszilch() {
E.inf()
return
}
w1 := NewFPcopy(E.x)
w6 := NewFPcopy(E.z)
w2 := NewFPint(0)
w3 := NewFPcopy(E.x)
w8 := NewFPcopy(E.x)
if CURVE_A == -3 {
w6.sqr()
w1.copy(w6)
w1.neg()
w3.add(w1)
w8.add(w6)
w3.mul(w8)
w8.copy(w3)
w8.imul(3)
} else {
w1.sqr()
w8.copy(w1)
w8.imul(3)
}
w2.copy(E.y)
w2.sqr()
w3.copy(E.x)
w3.mul(w2)
w3.imul(4)
w1.copy(w3)
w1.neg()
// w1.norm();
E.x.copy(w8)
E.x.sqr()
E.x.add(w1)
E.x.add(w1)
// x.reduce();
E.x.norm()
E.z.mul(E.y)
E.z.add(E.z)
w2.add(w2)
w2.sqr()
w2.add(w2)
w3.sub(E.x)
E.y.copy(w8)
E.y.mul(w3)
// w2.norm();
E.y.sub(w2)
// y.reduce();
// z.reduce();
E.y.norm()
E.z.norm()
}
if CURVETYPE == EDWARDS {
C := NewFPcopy(E.x)
D := NewFPcopy(E.y)
H := NewFPcopy(E.z)
J := NewFPint(0)
E.x.mul(E.y)
E.x.add(E.x)
C.sqr()
D.sqr()
if CURVE_A == -1 {
C.neg()
}
E.y.copy(C)
E.y.add(D)
// y.norm();
H.sqr()
H.add(H)
E.z.copy(E.y)
J.copy(E.y)
J.sub(H)
E.x.mul(J)
C.sub(D)
E.y.mul(C)
E.z.mul(J)
E.x.norm()
E.y.norm()
E.z.norm()
}
if CURVETYPE == MONTGOMERY {
A := NewFPcopy(E.x)
B := NewFPcopy(E.x)
AA := NewFPint(0)
BB := NewFPint(0)
C := NewFPint(0)
if E.INF {
return
}
A.add(E.z)
AA.copy(A)
AA.sqr()
B.sub(E.z)
BB.copy(B)
BB.sqr()
C.copy(AA)
C.sub(BB)
// C.norm();
E.x.copy(AA)
E.x.mul(BB)
A.copy(C)
A.imul((CURVE_A + 2) / 4)
BB.add(A)
E.z.copy(BB)
E.z.mul(C)
// x.reduce();
// z.reduce();
E.x.norm()
E.z.norm()
}
return
}
/* this+=Q */
func (E *ECP) add(Q *ECP) {
if CURVETYPE == WEIERSTRASS {
if E.INF {
E.copy(Q)
return
}
if Q.INF {
return
}
aff := false
one := NewFPint(1)
if Q.z.equals(one) {
aff = true
}
var A, C *FP
B := NewFPcopy(E.z)
D := NewFPcopy(E.z)
if !aff {
A = NewFPcopy(Q.z)
C = NewFPcopy(Q.z)
A.sqr()
B.sqr()
C.mul(A)
D.mul(B)
A.mul(E.x)
C.mul(E.y)
} else {
A = NewFPcopy(E.x)
C = NewFPcopy(E.y)
B.sqr()
D.mul(B)
}
B.mul(Q.x)
B.sub(A)
D.mul(Q.y)
D.sub(C)
if B.iszilch() {
if D.iszilch() {
E.dbl()
return
} else {
E.INF = true
return
}
}
if !aff {
E.z.mul(Q.z)
}
E.z.mul(B)
e := NewFPcopy(B)
e.sqr()
B.mul(e)
A.mul(e)
e.copy(A)
e.add(A)
e.add(B)
E.x.copy(D)
E.x.sqr()
E.x.sub(e)
A.sub(E.x)
E.y.copy(A)
E.y.mul(D)
C.mul(B)
E.y.sub(C)
// x.reduce();
// y.reduce();
// z.reduce();
E.x.norm()
E.y.norm()
E.z.norm()
}
if CURVETYPE == EDWARDS {
b := NewFPbig(NewBIGints(CURVE_B))
A := NewFPcopy(E.z)
B := NewFPint(0)
C := NewFPcopy(E.x)
D := NewFPcopy(E.y)
EE := NewFPint(0)
F := NewFPint(0)
G := NewFPint(0)
//H:=NewFPint(0)
//I:=NewFPint(0)
A.mul(Q.z)
B.copy(A)
B.sqr()
C.mul(Q.x)
D.mul(Q.y)
EE.copy(C)
EE.mul(D)
EE.mul(b)
F.copy(B)
F.sub(EE)
G.copy(B)
G.add(EE)
C.add(D)
if CURVE_A == 1 {
EE.copy(D)
D.sub(C)
}
B.copy(E.x)
B.add(E.y)
D.copy(Q.x)
D.add(Q.y)
B.mul(D)
B.sub(C)
B.mul(F)
E.x.copy(A)
E.x.mul(B)
if CURVE_A == 1 {
C.copy(EE)
C.mul(G)
}
if CURVE_A == -1 {
C.mul(G)
}
E.y.copy(A)
E.y.mul(C)
E.z.copy(F)
E.z.mul(G)
// x.reduce(); y.reduce(); z.reduce();
E.x.norm()
E.y.norm()
E.z.norm()
}
return
}
/* Differential Add for Montgomery curves. this+=Q where W is this-Q and is affine. */
func (E *ECP) dadd(Q *ECP, W *ECP) {
A := NewFPcopy(E.x)
B := NewFPcopy(E.x)
C := NewFPcopy(Q.x)
D := NewFPcopy(Q.x)
DA := NewFPint(0)
CB := NewFPint(0)
A.add(E.z)
B.sub(E.z)
C.add(Q.z)
D.sub(Q.z)
DA.copy(D)
DA.mul(A)
CB.copy(C)
CB.mul(B)
A.copy(DA)
A.add(CB)
A.sqr()
B.copy(DA)
B.sub(CB)
B.sqr()
E.x.copy(A)
E.z.copy(W.x)
E.z.mul(B)
if E.z.iszilch() {
E.inf()
} else {
E.INF = false
}
// x.reduce();
E.x.norm()
}
/* this-=Q */
func (E *ECP) sub(Q *ECP) {
Q.neg()
E.add(Q)
Q.neg()
}
func multiaffine(m int, P []*ECP) {
t1 := NewFPint(0)
t2 := NewFPint(0)
var work []*FP
for i := 0; i < m; i++ {
work = append(work, NewFPint(0))
}
work[0].one()
work[1].copy(P[0].z)
for i := 2; i < m; i++ {
work[i].copy(work[i-1])
work[i].mul(P[i-1].z)
}
t1.copy(work[m-1])
t1.mul(P[m-1].z)
t1.inverse()
t2.copy(P[m-1].z)
work[m-1].mul(t1)
for i := m - 2; ; i-- {
if i == 0 {
work[0].copy(t1)
work[0].mul(t2)
break
}
work[i].mul(t2)
work[i].mul(t1)
t2.mul(P[i].z)
}
/* now work[] contains inverses of all Z coordinates */
for i := 0; i < m; i++ {
P[i].z.one()
t1.copy(work[i])
t1.sqr()
P[i].x.mul(t1)
t1.mul(work[i])
P[i].y.mul(t1)
}
}
/* constant time multiply by small integer of length bts - use ladder */
func (E *ECP) pinmul(e int32, bts int32) *ECP {
if CURVETYPE == MONTGOMERY {
return E.mul(NewBIGint(int(e)))
} else {
P := NewECP()
R0 := NewECP()
R1 := NewECP()
R1.copy(E)
for i := bts - 1; i >= 0; i-- {
b := (e >> uint32(i)) & 1
P.copy(R1)
P.add(R0)
R0.cswap(R1, b)
R1.copy(P)
R0.dbl()
R0.cswap(R1, b)
}
P.copy(R0)
P.affine()
return P
}
}
/* return e.this */
func (E *ECP) mul(e *BIG) *ECP {
if e.iszilch() || E.is_infinity() {
return NewECP()
}
P := NewECP()
if CURVETYPE == MONTGOMERY {
/* use Ladder */
D := NewECP()
R0 := NewECP()
R0.copy(E)
R1 := NewECP()
R1.copy(E)
R1.dbl()
D.copy(E)
D.affine()
nb := e.nbits()
for i := nb - 2; i >= 0; i-- {
b := int32(e.bit(i))
P.copy(R1)
P.dadd(R0, D)
R0.cswap(R1, b)
R1.copy(P)
R0.dbl()
R0.cswap(R1, b)
}
P.copy(R0)
} else {
// fixed size windows
mt := NewBIG()
t := NewBIG()
Q := NewECP()
C := NewECP()
var W []*ECP
var w [1 + (NLEN*int(BASEBITS)+3)/4]int8
E.affine()
Q.copy(E)
Q.dbl()
W = append(W, NewECP())
W[0].copy(E)
for i := 1; i < 8; i++ {
W = append(W, NewECP())
W[i].copy(W[i-1])
W[i].add(Q)
}
// convert the table to affine
if CURVETYPE == WEIERSTRASS {
multiaffine(8, W[:])
}
// make exponent odd - add 2P if even, P if odd
t.copy(e)
s := int32(t.parity())
t.inc(1)
t.norm()
ns := int32(t.parity())
mt.copy(t)
mt.inc(1)
mt.norm()
t.cmove(mt, s)
Q.cmove(E, ns)
C.copy(Q)
nb := 1 + (t.nbits()+3)/4
// convert exponent to signed 4-bit window
for i := 0; i < nb; i++ {
w[i] = int8(t.lastbits(5) - 16)
t.dec(int(w[i]))
t.norm()
t.fshr(4)
}
w[nb] = int8(t.lastbits(5))
P.copy(W[(int(w[nb])-1)/2])
for i := nb - 1; i >= 0; i-- {
Q.selector(W, int32(w[i]))
P.dbl()
P.dbl()
P.dbl()
P.dbl()
P.add(Q)
}
P.sub(C) /* apply correction */
}
P.affine()
return P
}
/* Return e.this+f.Q */
func (E *ECP) mul2(e *BIG, Q *ECP, f *BIG) *ECP {
te := NewBIG()
tf := NewBIG()
mt := NewBIG()
S := NewECP()
T := NewECP()
C := NewECP()
var W []*ECP
//ECP[] W=new ECP[8];
var w [1 + (NLEN*int(BASEBITS)+1)/2]int8
E.affine()
Q.affine()
te.copy(e)
tf.copy(f)
// precompute table
for i := 0; i < 8; i++ {
W = append(W, NewECP())
}
W[1].copy(E)
W[1].sub(Q)
W[2].copy(E)
W[2].add(Q)
S.copy(Q)
S.dbl()
W[0].copy(W[1])
W[0].sub(S)
W[3].copy(W[2])
W[3].add(S)
T.copy(E)
T.dbl()
W[5].copy(W[1])
W[5].add(T)
W[6].copy(W[2])
W[6].add(T)
W[4].copy(W[5])
W[4].sub(S)
W[7].copy(W[6])
W[7].add(S)
// convert the table to affine
if CURVETYPE == WEIERSTRASS {
multiaffine(8, W)
}
// if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction
s := int32(te.parity())
te.inc(1)
te.norm()
ns := int32(te.parity())
mt.copy(te)
mt.inc(1)
mt.norm()
te.cmove(mt, s)
T.cmove(E, ns)
C.copy(T)
s = int32(tf.parity())
tf.inc(1)
tf.norm()
ns = int32(tf.parity())
mt.copy(tf)
mt.inc(1)
mt.norm()
tf.cmove(mt, s)
S.cmove(Q, ns)
C.add(S)
mt.copy(te)
mt.add(tf)
mt.norm()
nb := 1 + (mt.nbits()+1)/2
// convert exponent to signed 2-bit window
for i := 0; i < nb; i++ {
a := (te.lastbits(3) - 4)
te.dec(int(a))
te.norm()
te.fshr(2)
b := (tf.lastbits(3) - 4)
tf.dec(int(b))
tf.norm()
tf.fshr(2)
w[i] = int8(4*a + b)
}
w[nb] = int8(4*te.lastbits(3) + tf.lastbits(3))
S.copy(W[(w[nb]-1)/2])
for i := nb - 1; i >= 0; i-- {
T.selector(W, int32(w[i]))
S.dbl()
S.dbl()
S.add(T)
}
S.sub(C) /* apply correction */
S.affine()
return S
}
/*
func main() {
Gx:=NewBIGints(CURVE_Gx);
var Gy *BIG
var P *ECP
if CURVETYPE!=MONTGOMERY {Gy=NewBIGints(CURVE_Gy)}
r:=NewBIGints(CURVE_Order)
//r.dec(7);
fmt.Printf("Gx= "+Gx.toString())
fmt.Printf("\n")
if CURVETYPE!=MONTGOMERY {
fmt.Printf("Gy= "+Gy.toString())
fmt.Printf("\n")
}
if CURVETYPE!=MONTGOMERY {
P=NewECPbigs(Gx,Gy)
} else {P=NewECPbig(Gx)}
fmt.Printf("P= "+P.toString());
fmt.Printf("\n")
R:=P.mul(r);
//for (int i=0;i<10000;i++)
// R=P.mul(r);
fmt.Printf("R= "+R.toString())
fmt.Printf("\n")
}
*/