mirror of https://github.com/gtank/ristretto255
ristretto255: implement Encode and Decode
This commit is contained in:
parent
88aa823cd0
commit
b6eb459f56
18
fe.go
18
fe.go
|
@ -109,3 +109,21 @@ func fieldElementFromDecimal(s string) *radix51.FieldElement {
|
|||
}
|
||||
return new(radix51.FieldElement).FromBig(n)
|
||||
}
|
||||
|
||||
// The order of the field, 2^255 - 19, in 51-bit little endian form.
|
||||
var fieldOrder = [5]uint64{0x7ffffffffffed, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff, 0x7ffffffffffff}
|
||||
|
||||
// feMinimal returns true if the given field element is less than the order of the field.
|
||||
func feMinimal(fe *radix51.FieldElement) bool {
|
||||
for i := 4; ; i-- {
|
||||
v := fe[i]
|
||||
if v > fieldOrder[i] {
|
||||
return false
|
||||
} else if v < fieldOrder[i] {
|
||||
break
|
||||
} else if i == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
134
ristretto255.go
134
ristretto255.go
|
@ -8,6 +8,9 @@
|
|||
package ristretto255
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"github.com/gtank/ristretto255/internal/edwards25519"
|
||||
"github.com/gtank/ristretto255/internal/radix51"
|
||||
)
|
||||
|
@ -23,6 +26,13 @@ var (
|
|||
"1159843021668779879193775521855586647937357759715417654439879720876111806838")
|
||||
dMinusOneSQ = fieldElementFromDecimal(
|
||||
"40440834346308536858101042469323190826248399146238708352240133220865137265952")
|
||||
|
||||
// The encoding of the Ristretto element that can be represented internally
|
||||
// by the Curve25519 base point.
|
||||
encodedBasepoint, _ = hex.DecodeString(
|
||||
"e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76")
|
||||
|
||||
errInvalidEncoding = errors.New("invalid Ristretto encoding")
|
||||
)
|
||||
|
||||
// Element is an element of the ristretto255 prime-order group.
|
||||
|
@ -127,3 +137,127 @@ func mapToPoint(out *edwards25519.ExtendedGroupElement, t *radix51.FieldElement)
|
|||
out.Z.Mul(w1, w3)
|
||||
out.T.Mul(w0, w2)
|
||||
}
|
||||
|
||||
// Encode encodes a Ristretto group element to its canonical bytestring.
|
||||
func (e *Element) Encode(ee *Element) []byte {
|
||||
tmp := &radix51.FieldElement{}
|
||||
|
||||
// u1 = (z0 + y0) * (z0 - y0)
|
||||
u1 := &radix51.FieldElement{}
|
||||
u1.Add(&ee.r.Z, &ee.r.Y).Mul(u1, tmp.Sub(&ee.r.Z, &ee.r.Y))
|
||||
|
||||
// u2 = x0 * y0
|
||||
u2 := &radix51.FieldElement{}
|
||||
u2.Mul(&ee.r.X, &ee.r.Y)
|
||||
|
||||
// Ignore was_square since this is always square
|
||||
// (_, invsqrt) = SQRT_RATIO_M1(1, u1 * u2^2)
|
||||
invSqrt := &radix51.FieldElement{}
|
||||
_ = feSqrtRatio(invSqrt, u1, tmp.Square(u2))
|
||||
|
||||
// den1 = invsqrt * u1
|
||||
// den2 = invsqrt * u2
|
||||
// z_inv = den1 * den2 * t0
|
||||
den1, den2 := &radix51.FieldElement{}, &radix51.FieldElement{}
|
||||
zInv := &radix51.FieldElement{}
|
||||
den1.Mul(invSqrt, u1)
|
||||
den2.Mul(invSqrt, u2)
|
||||
zInv.Mul(den1, den2).Mul(zInv, &ee.r.T)
|
||||
|
||||
// ix0 = x0 * SQRT_M1
|
||||
// iy0 = y0 * SQRT_M1
|
||||
// enchanted_denominator = den1 * INVSQRT_A_MINUS_D
|
||||
ix0, iy0 := &radix51.FieldElement{}, &radix51.FieldElement{}
|
||||
enchantedDenominator := &radix51.FieldElement{}
|
||||
ix0.Mul(&ee.r.X, sqrtM1)
|
||||
iy0.Mul(&ee.r.Y, sqrtM1)
|
||||
enchantedDenominator.Mul(den1, invSqrtAMinusD)
|
||||
|
||||
// rotate = IS_NEGATIVE(t0 * z_inv)
|
||||
rotate := tmp.Mul(&ee.r.T, zInv).IsNegative()
|
||||
|
||||
// x = CT_SELECT(iy0 IF rotate ELSE x0)
|
||||
// y = CT_SELECT(ix0 IF rotate ELSE y0)
|
||||
// z = z0
|
||||
// den_inv = CT_SELECT(enchanted_denominator IF rotate ELSE den2)
|
||||
x, y := &radix51.FieldElement{}, &radix51.FieldElement{}
|
||||
denInv := &radix51.FieldElement{}
|
||||
x.Select(iy0, &ee.r.X, rotate)
|
||||
y.Select(ix0, &ee.r.Y, rotate)
|
||||
z := &ee.r.Z
|
||||
denInv.Select(enchantedDenominator, den2, rotate)
|
||||
|
||||
// y = CT_NEG(y, IS_NEGATIVE(x * z_inv))
|
||||
y.CondNeg(y, tmp.Mul(x, zInv).IsNegative())
|
||||
|
||||
// s = CT_ABS(den_inv * (z - y))
|
||||
s := tmp.Mul(denInv, tmp.Sub(z, y)).Abs(tmp)
|
||||
|
||||
// Return the canonical little-endian encoding of s.
|
||||
return s.Bytes(nil)
|
||||
}
|
||||
|
||||
// Decode decodes the canonical bytestring encoding of an element into a Ristretto element.
|
||||
// Returns nil on success.
|
||||
func (e *Element) Decode(in []byte) error {
|
||||
if len(in) != 32 {
|
||||
return errInvalidEncoding
|
||||
}
|
||||
|
||||
// First, interpret the string as an integer s in little-endian representation.
|
||||
s := &radix51.FieldElement{}
|
||||
s.FromBytes(in)
|
||||
|
||||
// If the resulting value is >= p, decoding fails.
|
||||
// If IS_NEGATIVE(s) returns TRUE, decoding fails.
|
||||
if !feMinimal(s) || s.IsNegative() == 1 {
|
||||
return errInvalidEncoding
|
||||
}
|
||||
|
||||
// ss = s^2
|
||||
sSqr := &radix51.FieldElement{}
|
||||
sSqr.Square(s)
|
||||
|
||||
// u1 = 1 - ss
|
||||
u1 := &radix51.FieldElement{}
|
||||
u1.Sub(radix51.One, sSqr)
|
||||
|
||||
// u2 = 1 + ss
|
||||
u2 := &radix51.FieldElement{}
|
||||
u2.Add(radix51.One, sSqr)
|
||||
|
||||
// u2_sqr = u2^2
|
||||
u2Sqr := &radix51.FieldElement{}
|
||||
u2Sqr.Square(u2)
|
||||
|
||||
// v = -(D * u1^2) - u2_sqr
|
||||
v := &radix51.FieldElement{}
|
||||
v.Square(u1).Mul(v, edwards25519.D).Neg(v).Sub(v, u2Sqr)
|
||||
|
||||
// (was_square, invsqrt) = SQRT_RATIO_M1(1, v * u2_sqr)
|
||||
invSqrt, tmp := &radix51.FieldElement{}, &radix51.FieldElement{}
|
||||
wasSquare := feSqrtRatio(invSqrt, radix51.One, tmp.Mul(v, u2Sqr))
|
||||
|
||||
// den_x = invsqrt * u2
|
||||
// den_y = invsqrt * den_x * v
|
||||
denX, denY := &radix51.FieldElement{}, &radix51.FieldElement{}
|
||||
denX.Mul(invSqrt, u2)
|
||||
denY.Mul(invSqrt, denX).Mul(denY, v)
|
||||
|
||||
// x = CT_ABS(2 * s * den_x)
|
||||
// y = u1 * den_y
|
||||
// t = x * y
|
||||
out := &e.r
|
||||
out.X.Mul(radix51.Two, s).Mul(&out.X, denX).Abs(&out.X)
|
||||
out.Y.Mul(u1, denY)
|
||||
out.Z.One()
|
||||
out.T.Mul(&out.X, &out.Y)
|
||||
|
||||
// If was_square is FALSE, or IS_NEGATIVE(t) returns TRUE, or y = 0, decoding fails.
|
||||
if wasSquare == 0 || out.T.IsNegative() == 1 || out.Y.Equal(radix51.Zero) == 1 {
|
||||
return errInvalidEncoding
|
||||
}
|
||||
|
||||
// Otherwise, return the internal representation in extended coordinates (x, y, 1, t).
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package ristretto255
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRistrettoBasepointDecode(t *testing.T) {
|
||||
extendedBasepoint := &Element{}
|
||||
err := extendedBasepoint.Decode(encodedBasepoint)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue