// Implementation of a MultiplicateCurve, using filippo.io/edwards25519. // Note that the implementation in edwards25519 uses addition for the group operation, // while we are exposing a multiplicative version of it. package curve import ( "crypto/rand" "encoding/base64" "io" ed "filippo.io/edwards25519" ) type c25519 struct{} type scalar ed.Scalar type point ed.Point type Curve25519Scalar = scalar type Curve25519Point = point var Curve25519 = &c25519{} var _ SomeScalar[*scalar] = (*scalar)(nil) var _ SomePoint[*scalar, *scalar, *point] = (*point)(nil) var _ SomeCurve[*scalar, *scalar, *point, *point] = Curve25519 var b64 = base64.StdEncoding.WithPadding(base64.NoPadding) func (s *scalar) Bytes() []byte { return ((*ed.Scalar)(s)).Bytes() } func (s *scalar) Equal(t *scalar) bool { return ((*ed.Scalar)(s)).Equal((*ed.Scalar)(t)) == 1 } func (s *scalar) String() string { return b64.EncodeToString(s.Bytes()) } func (s *scalar) Add(t *scalar) *scalar { return (*scalar)(new(ed.Scalar).Add((*ed.Scalar)(s), (*ed.Scalar)(t))) } func (s *scalar) Sub(t *scalar) *scalar { return (*scalar)(new(ed.Scalar).Subtract((*ed.Scalar)(s), (*ed.Scalar)(t))) } func (s *scalar) Mul(t *scalar) *scalar { return (*scalar)(new(ed.Scalar).Multiply((*ed.Scalar)(s), (*ed.Scalar)(t))) } func (c *c25519) ScalarFromReader(random io.Reader) (*scalar, error) { var buf [64]byte if random == nil { random = rand.Reader } random.Read(buf[:]) return c.ScalarFromBytes(buf[:]) } func (c *c25519) RandomScalar() *scalar { for i := 0; i < 3; i++ { if s, e := c.ScalarFromReader(nil); e == nil { return s } } panic("couldn't generate scalar") } func (c *c25519) ScalarFromBytes(b []byte) (*scalar, error) { s, e := new(ed.Scalar).SetUniformBytes(b) return (*scalar)(s), e } func (c *c25519) ScalarOne() *scalar { b := [64]byte{1} one, e := c.ScalarFromBytes(b[:]) if e != nil { panic(e) } return one } func (c *c25519) Exp(s *scalar) *point { p := new(ed.Point).ScalarBaseMult((*ed.Scalar)(s)) return (*point)(p) } func (c *c25519) Identity() *point { return (*point)(ed.NewIdentityPoint()) } func (c *c25519) Generator() *point { return (*point)(ed.NewGeneratorPoint()) } func (c *c25519) Product(pts []*point) (product *point) { product = c.Identity() for _, p := range pts { product = product.Mul(p) } return product } // Return P^n , for n Sc, and P Pt func (p *point) Exp(s *scalar) *point { r := new(ed.Point).ScalarMult((*ed.Scalar)(s), (*ed.Point)(p)) return (*point)(r) } func (p *point) Bytes() []byte { return ((*ed.Point)(p)).Bytes() } // Return p (*) q in group func (p *point) Mul(q *point) *point { r := new(ed.Point).Add((*ed.Point)(p), (*ed.Point)(q)) return (*point)(r) } // Return p (/) q in group func (p *point) Div(q *point) *point { r := new(ed.Point).Subtract((*ed.Point)(p), (*ed.Point)(q)) return (*point)(r) } // Return p^(-1) func (p *point) Inv() *point { n := new(ed.Point).Negate((*ed.Point)(p)) return (*point)(n) } func (p *point) Equal(q *point) bool { return ((*ed.Point)(p)).Equal((*ed.Point)(q)) == 1 } func (p *point) String() string { return b64.EncodeToString(p.Bytes()) }