Skip to content

Commit

Permalink
Add Edwards25519 and use always-square-and-multiply for pow, and fix …
Browse files Browse the repository at this point in the history
…ristretto pow (#26)

Signed-off-by: bytemare <3641580+bytemare@users.noreply.github.com>
  • Loading branch information
bytemare committed Jan 20, 2023
1 parent 1c5ea5a commit 557b5a3
Show file tree
Hide file tree
Showing 18 changed files with 1,335 additions and 87 deletions.
2 changes: 1 addition & 1 deletion .github/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ linters-settings:
# Default: false
custom-order: true
gocognit:
min-complexity: 15
min-complexity: 17
goconst:
min-len: 2
min-occurrences: 2
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/bytemare/crypto
go 1.19

require (
filippo.io/edwards25519 v1.0.0
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c
github.com/bytemare/hash2curve v0.1.2
github.com/gtank/ristretto255 v0.1.2
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c h1:x4epP2lA8b5UYoIFjcVpN+MfJQeX5M5Yilmc1VH0YDw=
filippo.io/nistec v0.0.0-20220513155737-c4b6d02e738c/go.mod h1:84fxC9mi+MhC2AERXI4LSa8cmSVOzrFikg6hZ4IfCyw=
github.com/bytemare/hash v0.1.3 h1:E2v/+gqvLTjaR8W2JdhqaB2L9161yFBlSXDnYEyMt94=
Expand Down
6 changes: 6 additions & 0 deletions groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"sync"

"github.com/bytemare/crypto/internal"
"github.com/bytemare/crypto/internal/edwards25519"
"github.com/bytemare/crypto/internal/nist"
"github.com/bytemare/crypto/internal/ristretto"
)
Expand All @@ -41,6 +42,9 @@ const (
// P521Sha512 identifies a group over P521 with SHA2-512 hash-to-group hashing.
P521Sha512

// Edwards25519Sha512 identifies the Edwards25519 group with SHA2-512 hash-to-group hashing.
Edwards25519Sha512

maxID

dstfmt = "%s-V%02d-CS%02d-%s"
Expand Down Expand Up @@ -157,6 +161,8 @@ func (g Group) init() {
g.initGroup(nist.P384)
case P521Sha512:
g.initGroup(nist.P521)
case Edwards25519Sha512:
g.initGroup(edwards25519.New)
case maxID:
fallthrough
default:
Expand Down
173 changes: 173 additions & 0 deletions internal/edwards25519/element.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

package edwards25519

import (
"fmt"

ed "filippo.io/edwards25519"

"github.com/bytemare/crypto/internal"
)

// Element implements the Element interface for the Ristretto255 group element.
type Element struct {
element ed.Point
}

func checkElement(element internal.Element) *Element {
if element == nil {
panic(internal.ErrParamNilPoint)
}

ec, ok := element.(*Element)
if !ok {
panic(internal.ErrCastElement)
}

return ec
}

// Base sets the element to the group's base point a.k.a. canonical generator.
func (e *Element) Base() internal.Element {
e.element.Set(ed.NewGeneratorPoint())
return e
}

// Identity sets the element to the point at infinity of the Group's underlying curve.
func (e *Element) Identity() internal.Element {
e.element.Set(ed.NewIdentityPoint())
return e
}

// Add sets the receiver to the sum of the input and the receiver, and returns the receiver.
func (e *Element) Add(element internal.Element) internal.Element {
ec := checkElement(element)
e.element.Add(&e.element, &ec.element)

return e
}

// Double sets the receiver to its double, and returns it.
func (e *Element) Double() internal.Element {
e.element.Add(&e.element, &e.element)
return e
}

// Negate sets the receiver to its negation, and returns it.
func (e *Element) Negate() internal.Element {
e.element.Negate(&e.element)
return e
}

// Subtract subtracts the input from the receiver, and returns the receiver.
func (e *Element) Subtract(element internal.Element) internal.Element {
ec := checkElement(element)
e.element.Subtract(&e.element, &ec.element)

return e
}

// Multiply sets the receiver to the scalar multiplication of the receiver with the given Scalar, and returns it.
func (e *Element) Multiply(scalar internal.Scalar) internal.Element {
if scalar == nil {
e.Identity()
return e
}

sc := assert(scalar)
e.element.ScalarMult(&sc.scalar, &e.element)

return e
}

// Equal returns 1 if the elements are equivalent, and 0 otherwise.
func (e *Element) Equal(element internal.Element) int {
ec := checkElement(element)
return e.element.Equal(&ec.element)
}

// IsIdentity returns whether the Element is the point at infinity of the Group's underlying curve.
func (e *Element) IsIdentity() bool {
return e.element.Equal(ed.NewIdentityPoint()) == 1
}

func (e *Element) set(element *Element) *Element {
*e = *element
return e
}

// Set sets the receiver to the value of the argument, and returns the receiver.
func (e *Element) Set(element internal.Element) internal.Element {
if element == nil {
return e.set(nil)
}

ec, ok := element.(*Element)
if !ok {
panic(internal.ErrCastElement)
}

return e.set(ec)
}

// Copy returns a copy of the receiver.
func (e *Element) Copy() internal.Element {
return &Element{*ed.NewIdentityPoint().Set(&e.element)}
}

// Encode returns the compressed byte encoding of the element.
func (e *Element) Encode() []byte {
return e.element.Bytes()
}

// XCoordinate returns the encoded x coordinate of the element, which is the same as Encode().
func (e *Element) XCoordinate() []byte {
return e.element.BytesMontgomery()
}

func decodeElement(element []byte) (*ed.Point, error) {
if len(element) == 0 {
return nil, internal.ErrParamNilPoint
}

e := ed.NewIdentityPoint()
if _, err := e.SetBytes(element); err != nil {
return nil, fmt.Errorf("edwards25519 element Decode: %w", err)
}

return e, nil
}

// Decode sets the receiver to a decoding of the input data, and returns an error on failure.
func (e *Element) Decode(data []byte) error {
element, err := decodeElement(data)
if err != nil {
return err
}

// superfluous identity check
if element.Equal(ed.NewIdentityPoint()) == 1 {
return internal.ErrIdentity
}

e.element = *element

return nil
}

// MarshalBinary returns the compressed byte encoding of the element.
func (e *Element) MarshalBinary() (data []byte, err error) {
return e.Encode(), nil
}

// UnmarshalBinary sets e to the decoding of the byte encoded element.
func (e *Element) UnmarshalBinary(data []byte) error {
return e.Decode(data)
}
82 changes: 82 additions & 0 deletions internal/edwards25519/group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: MIT
//
// Copyright (C) 2021 Daniel Bourdrez. All Rights Reserved.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree or at
// https://spdx.org/licenses/MIT.html

// Package edwards25519 allows simple and abstracted operations in the Edwards25519 group.
package edwards25519

import (
ed "filippo.io/edwards25519"

"github.com/bytemare/crypto/internal"
)

const (
canonicalEncodingLength = 32
orderPrime = "7237005577332262213973186563042994240857116359379907606001950938285454250989"
)

// Group represents the Edwards25519 group. It exposes a prime-order group API with hash-to-curve operations.
type Group struct{}

// New returns a new instantiation of the Edwards25519 Group.
func New() internal.Group {
return Group{}
}

// NewScalar returns a new, empty, scalar.
func (g Group) NewScalar() internal.Scalar {
return &Scalar{*ed.NewScalar()}
}

// NewElement returns the identity element (point at infinity).
func (g Group) NewElement() internal.Element {
return &Element{*ed.NewIdentityPoint()}
}

// Base returns group's base point a.k.a. canonical generator.
func (g Group) Base() internal.Element {
return &Element{*ed.NewGeneratorPoint()}
}

// HashToScalar returns a safe mapping of the arbitrary input to a Scalar.
// The DST must not be empty or nil, and is recommended to be longer than 16 bytes.
func (g Group) HashToScalar(input, dst []byte) internal.Scalar {
return &Scalar{*HashToEdwards25519Field(input, dst)}
}

// HashToGroup returns a safe mapping of the arbitrary input to an Element in the Group.
// The DST must not be empty or nil, and is recommended to be longer than 16 bytes.
func (g Group) HashToGroup(input, dst []byte) internal.Element {
return &Element{*HashToEdwards25519(input, dst)}
}

// EncodeToGroup returns a non-uniform mapping of the arbitrary input to an Element in the Group.
// The DST must not be empty or nil, and is recommended to be longer than 16 bytes.
func (g Group) EncodeToGroup(input, dst []byte) internal.Element {
return &Element{*EncodeToEdwards25519(input, dst)}
}

// Ciphersuite returns the hash-to-curve ciphersuite identifier.
func (g Group) Ciphersuite() string {
return H2C
}

// ScalarLength returns the byte size of an encoded element.
func (g Group) ScalarLength() uint {
return canonicalEncodingLength
}

// ElementLength returns the byte size of an encoded element.
func (g Group) ElementLength() uint {
return canonicalEncodingLength
}

// Order returns the order of the canonical group of scalars.
func (g Group) Order() string {
return orderPrime
}

0 comments on commit 557b5a3

Please sign in to comment.