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

[WIP] VXEdDSA #167

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
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
140 changes: 111 additions & 29 deletions crypto/internal/ed25519/edwards25519/edwards25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
// http://ed25519.cr.yp.to/.
package edwards25519

import "math"

// This code is a port of the public domain, "ref10" implementation of ed25519
// from SUPERCOP.

Expand Down Expand Up @@ -861,6 +859,22 @@ func FeSquare2(h, f *FieldElement) {
h[9] = int32(h9)
}

func FeSqrt(out, a *FieldElement) {
var exp, b, b2, bi, i FieldElement

i = SqrtM1
FePow22523(&exp, a) /* b = a^(q-5)/8 */
FeMul(&b, a, &exp) /* b = a * a^(q-5)/8 */
FeSquare(&b2, &b) /* b^2 = a * a^(q-1)/4 */

/* note b^4 == a^2, so b^2 == a or -a
* if b^2 != a, multiply it by sqrt(-1) */
FeMul(&bi, &b, &i)
FeCMove(&b, &bi, int32(1^FeIsequal(b2, *a)))

FeCopy(out, &b)
}

func FeInvert(out, z *FieldElement) {
var t0, t1, t2, t3 FieldElement
var i int
Expand Down Expand Up @@ -916,7 +930,7 @@ func FeInvert(out, z *FieldElement) {
FeMul(out, &t1, &t0) // 254..5,3,1,0
}

func fePow22523(out, z *FieldElement) {
func FePow22523(out, z *FieldElement) {
var t0, t1, t2 FieldElement
var i int

Expand Down Expand Up @@ -977,6 +991,28 @@ func fePow22523(out, z *FieldElement) {
FeMul(out, &t0, z)
}

func FeIsequal(f, g FieldElement) int {
var h FieldElement
FeSub(&h, &f, &g)
return 1 ^ (1 & (feIsNonzero(h) >> 8))
}

func feIsNonzero(f FieldElement) int {
var s [32]byte
FeToBytes(&s, &f)
var zero [32]byte

return FeCompare(s, zero)
}

func FeCompare(x, y [32]byte) int {
d := 0
for i := 0; i < 32; i++ {
d |= int(x[i]) ^ int(y[i])
}
return (1 & ((d - 1) >> 8)) - 1
}

// Group elements are members of the elliptic curve -x^2 + y^2 = 1 + d * x^2 *
// y^2 where d = -121665/121666.
//
Expand Down Expand Up @@ -1055,6 +1091,13 @@ func (p *ExtendedGroupElement) Double(r *CompletedGroupElement) {
q.Double(r)
}

func GeNeg(r *ExtendedGroupElement, p ExtendedGroupElement) {
FeNeg(&r.X, &p.X)
FeCopy(&r.Y, &p.Y)
FeCopy(&r.Z, &p.Z)
FeNeg(&r.T, &p.T)
}

func GeDouble(r, p *ExtendedGroupElement) {
var q ProjectiveGroupElement
p.ToProjective(&q)
Expand Down Expand Up @@ -1128,10 +1171,11 @@ func (p *ExtendedGroupElement) FromBytesBaseGroup(s *[32]byte) bool {

func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool {
FeFromBytes(&p.Y, s)
return p.FromParityAndY(s[31]>>7, &p.Y)
return p.FromParityAndY((s[31] >> 7), &p.Y)
}

func (p *ExtendedGroupElement) FromParityAndY(bit byte, y *FieldElement) bool {
// compare to ge_frombytes_negate_vartime
var u, v, v3, vxx, check FieldElement

FeCopy(&p.Y, y)
Expand All @@ -1147,7 +1191,7 @@ func (p *ExtendedGroupElement) FromParityAndY(bit byte, y *FieldElement) bool {
FeMul(&p.X, &p.X, &v)
FeMul(&p.X, &p.X, &u) // x = uv^7

fePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8)
FePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8)
FeMul(&p.X, &p.X, &v3)
FeMul(&p.X, &p.X, &u) // x = uv^3(uv^7)^((q-5)/8)

Expand All @@ -1168,7 +1212,6 @@ func (p *ExtendedGroupElement) FromParityAndY(bit byte, y *FieldElement) bool {
tmp2[31-i] = v
}
}

if FeIsNegative(&p.X) != bit {
FeNeg(&p.X, &p.X)
}
Expand Down Expand Up @@ -1327,6 +1370,16 @@ func GeScalarMult(r *ExtendedGroupElement, a *[32]byte, A *ExtendedGroupElement)
ExtendedGroupElementCopy(r, &q)
}

// GeIsNeutral
// returns 1 if p is the neutral point
// returns 0 otherwise
func GeIsNeutral(p *ExtendedGroupElement) bool {
var zero FieldElement
FeZero(&zero)
// Check if p == neutral element == (0, 1)
return FeIsequal(p.X, zero)&FeIsequal(p.Y, p.Z) == 1
}

// GeDoubleScalarMultVartime sets r = a*A + b*B
// where a = a[0]+256*a[1]+...+256^31 a[31].
// and b = b[0]+256*b[1]+...+256^31 b[31].
Expand Down Expand Up @@ -1382,6 +1435,23 @@ func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *[32]byte, A *Extend
}
}

func GeToMontX(u *FieldElement, ed *ExtendedGroupElement) {
/*
u = (y + 1) / (1 - y)
or
u = (y + z) / (z - y)

NOTE: y=1 is converted to u=0 since fe_invert is mod-exp
*/
var yPlusOne, oneMinusY, invOneMinusY FieldElement

FeAdd(&yPlusOne, &ed.Y, &ed.Z)
FeSub(&oneMinusY, &ed.Z, &ed.Y)
FeInvert(&invOneMinusY, &oneMinusY)
FeMul(u, &yPlusOne, &invOneMinusY)

}

// equal returns 1 if b == c and 0 otherwise.
func equal(b, c int32) int32 {
x := uint32(b ^ c)
Expand Down Expand Up @@ -1902,29 +1972,17 @@ func ScMulAdd(s, a, b, c *[32]byte) {
s[31] = byte(s11 >> 17)
}

// Input:
// s[0]+256*s[1]+...+256^63*s[63] = s
// s <= l
//
// Output:
// s[0]+256*s[1]+...+256^31*s[31] = l - s
// where l = 2^252 + 27742317777372353535851937790883648493.
func ScNeg(r, s *[32]byte) {
l := [32]byte{237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}
var carry int32
for i := 0; i < 32; i++ {
carry = carry + int32(l[i]) - int32(s[i])
negative := carry & math.MinInt32 // extract the sign bit (min=0b100...)
negative |= negative >> 16
negative |= negative >> 8
negative |= negative >> 4
negative |= negative >> 2
negative |= negative >> 1
carry += negative & 256 // +=256 if negative, unmodified otherwise
r[i] = byte(carry)
// carry for next iteration
carry = negative & (-1) // -1 if negative, 0 otherwise
}
var lMinus1 = [32]byte{0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}

// ScNeg computes:
// b = -a (mod l)
// where l = 2^252 + 27742317777372353535851937790883648493.
func ScNeg(b, a *[32]byte) {
var zero [32]byte
ScMulAdd(b, &lMinus1, a, &zero)
}

// Input:
Expand Down Expand Up @@ -2250,3 +2308,27 @@ func ScReduce(out *[32]byte, s *[64]byte) {
out[30] = byte(s11 >> 9)
out[31] = byte(s11 >> 17)
}

// ScCMove is equivalent to FeCMove but operates directly on the [32]byte
// representation instead on the FieldElement. Can be used to spare a
// FieldElement.FromBytes operation.
func ScCMove(f, g *[32]byte, b int32) {
var x [32]byte
for i := range x {
x[i] = (f[i] ^ g[i])
}
b = -b
for i := range x {
x[i] &= byte(b)
}
for i := range f {
f[i] ^= x[i]
}
}

// ScClamp Sets and clears bits to make a random 32 bytes into a private key
func ScClamp(a *[32]byte) {
a[0] &= 248
a[31] &= 127
a[31] |= 64
}
122 changes: 120 additions & 2 deletions crypto/internal/ed25519/extra25519/extra25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,44 @@ func representativeToMontgomeryX(v, rr2 *edwards25519.FieldElement) {
edwards25519.FeSub(v, v, &v2)
}

func montgomeryXToEdwardsY(out, x *edwards25519.FieldElement) {
func FeMontRhs(v2, u *edwards25519.FieldElement) {
var u2, Au, inner edwards25519.FieldElement
var one edwards25519.FieldElement
edwards25519.FeOne(&one)

edwards25519.FeSquare(&u2, u) /* u^2 */
edwards25519.FeMul(&Au, &edwards25519.A, u) /* Au */
edwards25519.FeAdd(&inner, &u2, &Au) /* u^2 + Au */
edwards25519.FeAdd(&inner, &inner, &one) /* u^2 + Au + 1 */
edwards25519.FeMul(v2, u, &inner) /* u(u^2 + Au + 1) */
}

func legendreIsNonsquare(in edwards25519.FieldElement) int32 {
var temp edwards25519.FieldElement
edwards25519.FePow22523(&temp, &in) /* temp = in^((q-5)/8) */
edwards25519.FeSquare(&temp, &temp) /* in^((q-5)/4) */
edwards25519.FeSquare(&temp, &temp) /* in^((q-5)/2) */
edwards25519.FeMul(&temp, &temp, &in) /* in^((q-3)/2) */
edwards25519.FeMul(&temp, &temp, &in) /* in^((q-1)/2) */

/* temp is now the Legendre symbol:
* 1 = square
* 0 = input is zero
* -1 = nonsquare
*/
var b [32]byte
edwards25519.FeToBytes(&b, &temp)
//fmt.Println(hex.Dump(b[:]))
return int32(1 & b[31])
}

// compare to fe_montx_to_edy
func FeMontgomeryXToEdwardsY(out, x *edwards25519.FieldElement) {
/*
y = (u - 1) / (u + 1)

NOTE: u=-1 is converted to y=0 since fe_invert is mod-exp
*/
var t, tt edwards25519.FieldElement
edwards25519.FeOne(&t)
edwards25519.FeAdd(&tt, x, &t) // u+1
Expand All @@ -356,6 +393,38 @@ func montgomeryXToEdwardsY(out, x *edwards25519.FieldElement) {
edwards25519.FeMul(out, &tt, &t) // (u-1)/(u+1)
}

func elligator(u *edwards25519.FieldElement, r edwards25519.FieldElement) {
/* r = input
* x = -A/(1+2r^2) # 2 is nonsquare
* e = (x^3 + Ax^2 + x)^((q-1)/2) # legendre symbol
* if e == 1 (square) or e == 0 (because x == 0 and 2r^2 + 1 == 0)
* u = x
* if e == -1 (nonsquare)
* u = -x - A
*/
var A, one, twor2, twor2plus1, twor2plus1inv edwards25519.FieldElement
var x, e, Atemp, uneg edwards25519.FieldElement
A = edwards25519.A /* A = 486662 */
edwards25519.FeOne(&one)

edwards25519.FeSquare2(&twor2, &r) /* 2r^2 */
edwards25519.FeAdd(&twor2plus1, &twor2, &one) /* 1+2r^2 */
edwards25519.FeInvert(&twor2plus1inv, &twor2plus1) /* 1/(1+2r^2) */
edwards25519.FeMul(&x, &twor2plus1inv, &A) /* A/(1+2r^2) */
edwards25519.FeNeg(&x, &x) /* x = -A/(1+2r^2) */

FeMontRhs(&e, &x) /* e = x^3 + Ax^2 + x */

nonsquare := legendreIsNonsquare(e)

edwards25519.FeZero(&Atemp)

edwards25519.FeCMove(&Atemp, &A, nonsquare) /* 0, or A if nonsquare */
edwards25519.FeAdd(u, &x, &Atemp) /* x, or x+A if nonsquare */
edwards25519.FeNeg(&uneg, u) /* -x, or -x-A if nonsquare */
edwards25519.FeCMove(u, &uneg, nonsquare) /* x, or -x-A if nonsquare */
}

// HashToEdwards converts a 256-bit hash output into a point on the Edwards
// curve isomorphic to Curve25519 in a manner that preserves
// collision-resistance. The returned curve points are NOT indistinguishable
Expand All @@ -369,8 +438,57 @@ func HashToEdwards(out *edwards25519.ExtendedGroupElement, h *[32]byte) {
hh[31] &= 127
edwards25519.FeFromBytes(&out.Y, &hh)
representativeToMontgomeryX(&out.X, &out.Y)
montgomeryXToEdwardsY(&out.Y, &out.X)
FeMontgomeryXToEdwardsY(&out.Y, &out.X)
if ok := out.FromParityAndY(bit, &out.Y); !ok {
panic("HashToEdwards: point not on curve")
}
}

func HashToPoint(m []byte) *edwards25519.ExtendedGroupElement {
// H(n) = (f(h(n))^8)
var hmb [32]byte
h64 := sha512.Sum512(m)
copy(hmb[:], h64[:32])
var hm edwards25519.ExtendedGroupElement
HashToEdwards(&hm, &hmb)
edwards25519.GeDouble(&hm, &hm)
edwards25519.GeDouble(&hm, &hm)
edwards25519.GeDouble(&hm, &hm)
return &hm
}

/* sqrt(-(A+2)) */
var a_bytes = [32]byte{
0x06, 0x7e, 0x45, 0xff, 0xaa, 0x04, 0x6e, 0xcc,
0x82, 0x1a, 0x7d, 0x4b, 0xd1, 0xd3, 0xa1, 0xc5,
0x7e, 0x4f, 0xfc, 0x03, 0xdc, 0x08, 0x7b, 0xd2,
0xbb, 0x06, 0xa0, 0x60, 0xf4, 0xed, 0x26, 0x0f,
}

func GeMontXtoExtendedGroupElement(p *edwards25519.ExtendedGroupElement, u edwards25519.FieldElement, edSignBit byte) {
var x, y, v, A, v2, iv, nx edwards25519.FieldElement

edwards25519.FeFromBytes(&A, &a_bytes)

/* given u, recover edwards y */
/* given u, recover v */
/* given u and v, recover edwards x */

FeMontgomeryXToEdwardsY(&y, &u) /* y = (u - 1) / (u + 1) */

FeMontRhs(&v2, &u) /* v^2 = u(u^2 + Au + 1) */

edwards25519.FeSqrt(&v, &v2) /* v = sqrt(v^2) */

edwards25519.FeMul(&x, &u, &A) /* x = u * sqrt(-(A+2)) */
edwards25519.FeInvert(&iv, &v) /* 1/v */
edwards25519.FeMul(&x, &x, &iv) /* x = (u/v) * sqrt(-(A+2)) */

edwards25519.FeNeg(&nx, &x) /* negate x to match sign bit */
edwards25519.FeCMove(&x, &nx, int32(edwards25519.FeIsNegative(&x)^edSignBit))

edwards25519.FeCopy(&(p.X), &x)
edwards25519.FeCopy(&(p.Y), &y)
edwards25519.FeOne(&(p.Z))
edwards25519.FeMul(&(p.T), &(p.X), &(p.Y))
}
Loading