Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows to compile p384 with arch others than arm64 and amd64. #194

Merged
merged 1 commit into from
Nov 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 0 additions & 56 deletions ecc/p384/api_test.go

This file was deleted.

2 changes: 1 addition & 1 deletion ecc/p384/arith.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build arm64 amd64
// +build !noasm,arm64 !noasm,amd64

package p384

Expand Down
2 changes: 1 addition & 1 deletion ecc/p384/arith_amd64.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build amd64
// +build amd64,!noasm

package p384

Expand Down
2 changes: 1 addition & 1 deletion ecc/p384/arith_amd64.s
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build amd64
// +build amd64,!noasm

#include "textflag.h"

Expand Down
2 changes: 1 addition & 1 deletion ecc/p384/arith_arm64.s
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build arm64
// +build arm64,!noasm

#include "textflag.h"

Expand Down
2 changes: 1 addition & 1 deletion ecc/p384/arith_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// +build arm64 amd64
// +build !noasm,arm64 !noasm,amd64

package p384

Expand Down
78 changes: 78 additions & 0 deletions ecc/p384/opt_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// +build !noasm,arm64 !noasm,amd64

package p384

import (
"crypto/elliptic"
"math/big"
"testing"

"github.com/cloudflare/circl/internal/test"
)

func TestInternals(t *testing.T) {
t.Run("absolute", func(t *testing.T) {
cases := []int32{-2, -1, 0, 1, 2}
expected := []int32{2, 1, 0, 1, 2}
for i := range cases {
got := absolute(cases[i])
want := expected[i]
if got != want {
test.ReportError(t, got, want, cases[i])
}
}
})

t.Run("toOdd", func(t *testing.T) {
var c curve
k := []byte{0xF0}
oddK, _ := c.toOdd(k)
got := len(oddK)
want := 48
if got != want {
test.ReportError(t, got, want)
}

oddK[sizeFp-1] = 0x0
smallOddK, _ := c.toOdd(oddK)
got = len(smallOddK)
want = 48
if got != want {
test.ReportError(t, got, want)
}
})

t.Run("special k", func(t *testing.T) {
cases := []struct { // known cases that require complete addition
w uint
k int
}{
{w: 2, k: 2},
{w: 5, k: 6},
{w: 6, k: 38},
{w: 7, k: 102},
{w: 9, k: 230},
{w: 12, k: 742},
{w: 14, k: 4838},
{w: 17, k: 21222},
{w: 19, k: 152294},
}

var c curve

StdCurve := elliptic.P384()
params := StdCurve.Params()
for _, caseI := range cases {
k := big.NewInt(int64(caseI.k)).Bytes()
gotX, gotY := c.scalarMultOmega(params.Gx, params.Gy, k, caseI.w)
wantX, wantY := StdCurve.ScalarMult(params.Gx, params.Gy, k)

if gotX.Cmp(wantX) != 0 {
test.ReportError(t, gotX, wantX, caseI)
}
if gotY.Cmp(wantY) != 0 {
test.ReportError(t, gotY, wantY, caseI)
}
}
})
}
182 changes: 0 additions & 182 deletions ecc/p384/p384.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
// +build arm64 amd64

package p384

import (
"crypto/elliptic"
"crypto/subtle"
"math/big"

"github.com/cloudflare/circl/math"
)

// Curve is used to provide the extended functionality and performance of
Expand All @@ -22,11 +17,6 @@ type Curve interface {
CombinedMult(Qx, Qy *big.Int, m, n []byte) (Px, Py *big.Int)
}

type curve struct{}

// P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4).
func P384() Curve { return curve{} }

// Params returns the parameters for the curve. Note: The value returned by
// this function fallbacks to the stdlib implementation of elliptic curve
// operations. Use this method to only recover elliptic curve parameters.
Expand All @@ -36,175 +26,3 @@ func (c curve) Params() *elliptic.CurveParams { return elliptic.P384().Params()
func (c curve) IsAtInfinity(x, y *big.Int) bool {
return x.Sign() == 0 && y.Sign() == 0
}

// IsOnCurve reports whether the given (x,y) lies on the curve.
func (c curve) IsOnCurve(x, y *big.Int) bool {
x1, y1 := &fp384{}, &fp384{}
x1.SetBigInt(x)
y1.SetBigInt(y)
montEncode(x1, x1)
montEncode(y1, y1)

y2, x3 := &fp384{}, &fp384{}
fp384Sqr(y2, y1)
fp384Sqr(x3, x1)
fp384Mul(x3, x3, x1)

threeX := &fp384{}
fp384Add(threeX, x1, x1)
fp384Add(threeX, threeX, x1)

fp384Sub(x3, x3, threeX)
fp384Add(x3, x3, &bb)

return *y2 == *x3
}

// Add returns the sum of (x1,y1) and (x2,y2).
func (c curve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) {
P := newAffinePoint(x1, y1).toJacobian()
P.mixadd(P, newAffinePoint(x2, y2))
return P.toAffine().toInt()
}

// Double returns 2*(x,y).
func (c curve) Double(x1, y1 *big.Int) (x, y *big.Int) {
P := newAffinePoint(x1, y1).toJacobian()
P.double()
return P.toAffine().toInt()
}

// reduceScalar shorten a scalar modulo the order of the curve.
func (c curve) reduceScalar(k []byte) []byte {
const max = sizeFp
if len(k) > max {
bigK := new(big.Int).SetBytes(k)
bigK.Mod(bigK, c.Params().N)
k = bigK.Bytes()
}
if len(k) < max {
k = append(make([]byte, max-len(k)), k...)
}
return k
}

// toOdd performs k = (-k mod N) if k is even.
func (c curve) toOdd(k []byte) ([]byte, int) {
var X, Y big.Int
X.SetBytes(k)
Y.Neg(&X).Mod(&Y, c.Params().N)
isEven := 1 - int(X.Bit(0))
x := X.Bytes()
y := Y.Bytes()

if len(x) < len(y) {
x = append(make([]byte, len(y)-len(x)), x...)
} else if len(x) > len(y) {
y = append(make([]byte, len(x)-len(y)), y...)
}
subtle.ConstantTimeCopy(isEven, x, y)
return x, isEven
}

// ScalarMult returns (Qx,Qy)=k*(Px,Py) where k is a number in big-endian form.
func (c curve) ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int) {
return c.scalarMultOmega(x1, y1, k, 5)
}

func (c curve) scalarMultOmega(x1, y1 *big.Int, k []byte, omega uint) (x, y *big.Int) {
k = c.reduceScalar(k)
oddK, isEvenK := c.toOdd(k)

var scalar big.Int
scalar.SetBytes(oddK)
if scalar.Sign() == 0 {
return new(big.Int), new(big.Int)
}
const bitsN = uint(384)
L := math.SignedDigit(&scalar, omega, bitsN)

var R jacobianPoint
Q := zeroPoint().toJacobian()
TabP := newAffinePoint(x1, y1).oddMultiples(omega)
for i := len(L) - 1; i > 0; i-- {
for j := uint(0); j < omega-1; j++ {
Q.double()
}
idx := absolute(L[i]) >> 1
for j := range TabP {
R.cmov(&TabP[j], subtle.ConstantTimeEq(int32(j), idx))
}
R.cneg(int(L[i]>>31) & 1)
Q.add(Q, &R)
}
// Calculate the last iteration using complete addition formula.
for j := uint(0); j < omega-1; j++ {
Q.double()
}
idx := absolute(L[0]) >> 1
for j := range TabP {
R.cmov(&TabP[j], subtle.ConstantTimeEq(int32(j), idx))
}
R.cneg(int(L[0]>>31) & 1)
QQ := Q.toProjective()
QQ.completeAdd(QQ, R.toProjective())
QQ.cneg(isEvenK)
return QQ.toAffine().toInt()
}

// ScalarBaseMult returns k*G, where G is the base point of the group
// and k is an integer in big-endian form.
func (c curve) ScalarBaseMult(k []byte) (x, y *big.Int) {
params := c.Params()
return c.ScalarMult(params.Gx, params.Gy, k)
}

// CombinedMult calculates P=mG+nQ, where G is the generator and Q=(x,y,z).
// The scalars m and n are integers in big-endian form. Non-constant time.
func (c curve) CombinedMult(xQ, yQ *big.Int, m, n []byte) (xP, yP *big.Int) {
const nOmega = uint(5)
var k big.Int
k.SetBytes(m)
nafM := math.OmegaNAF(&k, baseOmega)
k.SetBytes(n)
nafN := math.OmegaNAF(&k, nOmega)

if len(nafM) > len(nafN) {
nafN = append(nafN, make([]int32, len(nafM)-len(nafN))...)
} else if len(nafM) < len(nafN) {
nafM = append(nafM, make([]int32, len(nafN)-len(nafM))...)
}

TabQ := newAffinePoint(xQ, yQ).oddMultiples(nOmega)
var jR jacobianPoint
var aR affinePoint
P := zeroPoint().toJacobian()
for i := len(nafN) - 1; i >= 0; i-- {
P.double()
// Generator point
if nafM[i] != 0 {
idxM := absolute(nafM[i]) >> 1
aR = baseOddMultiples[idxM]
if nafM[i] < 0 {
aR.neg()
}
P.mixadd(P, &aR)
}
// Input point
if nafN[i] != 0 {
idxN := absolute(nafN[i]) >> 1
jR = TabQ[idxN]
if nafN[i] < 0 {
jR.neg()
}
P.add(P, &jR)
}
}
return P.toAffine().toInt()
}

// absolute returns always a positive value.
func absolute(x int32) int32 {
mask := x >> 31
return (x + mask) ^ mask
}
20 changes: 20 additions & 0 deletions ecc/p384/p384_generic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// +build noasm !amd64,!arm64

package p384

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

type curve struct{ elliptic.Curve }

func P384() Curve { return curve{elliptic.P384()} }

// CombinedMult calculates P=mG+nQ, where G is the generator and Q=(x,y,z).
// The scalars m and n are integers in big-endian form. Non-constant time.
func (c curve) CombinedMult(xQ, yQ *big.Int, m, n []byte) (xP, yP *big.Int) {
x1, y1 := c.ScalarBaseMult(m)
x2, y2 := c.ScalarMult(xQ, yQ, n)
return c.Add(x1, y1, x2, y2)
}
Loading