Skip to content
This repository has been archived by the owner on Oct 3, 2024. It is now read-only.

group.Order() now returns bytes, scalar.MinusOne() sets to order-1 #68

Merged
merged 3 commits into from
Oct 2, 2024
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
2 changes: 1 addition & 1 deletion .github/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ linters-settings:
threshold: 100
errcheck:
check-type-assertions: true
check-blank: true
check-blank: false
exclude-functions:
- (*crypto/Element).MarshalBinary
- (*crypto/Scalar).MarshalBinary
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
filippo.io/edwards25519 v1.1.0
filippo.io/nistec v0.0.3
github.com/bytemare/hash2curve v0.3.0
github.com/bytemare/secp256k1 v0.1.4
github.com/bytemare/secp256k1 v0.1.6
github.com/gtank/ristretto255 v0.1.2
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ github.com/bytemare/hash v0.3.0 h1:RqFMt3mqpF7UxLdjBrsOZm/2cz0cQiAOnYc9gDLopWE=
github.com/bytemare/hash v0.3.0/go.mod h1:YKOBchL0l8hRLFinVCL8YUKokGNIMhrWEHPHo3EV7/M=
github.com/bytemare/hash2curve v0.3.0 h1:41Npcbc+u/E252A5aCMtxDcz7JPkkX1QzShneTFm4eg=
github.com/bytemare/hash2curve v0.3.0/go.mod h1:itj45U8uqvCtWC0eCswIHVHswXcEHkpFui7gfJdPSfQ=
github.com/bytemare/secp256k1 v0.1.4 h1:6F1yP6RiUiWwH7AsGHsHktmHm24QcetdDcc39roBd2M=
github.com/bytemare/secp256k1 v0.1.4/go.mod h1:Pxb9miDs8PTt5mOktvvXiRflvLxI1wdxbXrc6IYsaho=
github.com/bytemare/secp256k1 v0.1.6 h1:5pOA84UBBTPTUmCkjtH6jHrbvZSh2kyxG0mW/OjSih0=
github.com/bytemare/secp256k1 v0.1.6/go.mod h1:Zr7o3YCog5jKx5JwgYbj984gRIqVioTDZMSDo1y0zgE=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
Expand Down
2 changes: 1 addition & 1 deletion groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ func (g Group) ElementLength() int {
}

// Order returns the order of the canonical group of scalars.
func (g Group) Order() string {
func (g Group) Order() []byte {
return g.get().Order()
}

Expand Down
5 changes: 3 additions & 2 deletions internal/edwards25519/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package edwards25519

import (
"crypto"
"slices"

ed "filippo.io/edwards25519"

Expand Down Expand Up @@ -87,6 +88,6 @@ func (g Group) ElementLength() int {
}

// Order returns the order of the canonical group of scalars.
func (g Group) Order() string {
return orderPrime
func (g Group) Order() []byte {
return slices.Clone(orderBytes)
}
47 changes: 25 additions & 22 deletions internal/edwards25519/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,17 @@ import (
const inputLength = 64

var (
scZero Scalar
scOne Scalar
order big.Int
scZero Scalar
scOne Scalar
order big.Int
scMinusOne = []byte{
236, 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,
}
orderBytes = []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,
}
)

func init() {
Expand Down Expand Up @@ -84,6 +92,12 @@ func (s *Scalar) One() internal.Scalar {
return s
}

// MinusOne sets the scalar to order-1, and returns it.
func (s *Scalar) MinusOne() internal.Scalar {
_ = s.decodeScalar(scMinusOne)
return s
}

// Random sets the current scalar to a new random scalar and returns it.
// The random source is crypto/rand, and this functions is guaranteed to return a non-zero scalar.
func (s *Scalar) Random() internal.Scalar {
Expand Down Expand Up @@ -278,14 +292,11 @@ func (s *Scalar) SetUInt64(i uint64) internal.Scalar {
encoded := make([]byte, canonicalEncodingLength)
binary.LittleEndian.PutUint64(encoded, i)

sc, err := decodeScalar(encoded)
if err != nil {
if err := s.decodeScalar(encoded); err != nil {
// This cannot happen, since any uint64 is smaller than the order.
panic(fmt.Sprintf("unexpected decoding of uint64 scalar: %s", err))
}

s.set(sc)

return s
}

Expand Down Expand Up @@ -320,33 +331,25 @@ func (s *Scalar) Encode() []byte {
return s.scalar.Bytes()
}

func decodeScalar(scalar []byte) (*ed.Scalar, error) {
func (s *Scalar) decodeScalar(scalar []byte) error {
if len(scalar) == 0 {
return nil, internal.ErrParamNilScalar
return internal.ErrParamNilScalar
}

if len(scalar) != canonicalEncodingLength {
return nil, internal.ErrParamScalarLength
return internal.ErrParamScalarLength
}

s := ed.NewScalar()
if _, err := s.SetCanonicalBytes(scalar); err != nil {
return nil, fmt.Errorf("%w", err)
if _, err := s.scalar.SetCanonicalBytes(scalar); err != nil {
return fmt.Errorf("%w", err)
}

return s, nil
return nil
}

// Decode sets the receiver to a decoding of the input data, and returns an error on failure.
func (s *Scalar) Decode(in []byte) error {
sc, err := decodeScalar(in)
if err != nil {
return err
}

s.scalar = *sc

return nil
return s.decodeScalar(in)
}

// Hex returns the fixed-sized hexadecimal encoding of s.
Expand Down
5 changes: 5 additions & 0 deletions internal/field/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ func (f Field) Order() *big.Int {
return f.order
}

// PMinusOne returns p-1, the greatest integer below the order.
func (f Field) PMinusOne() *big.Int {
return new(big.Int).Sub(f.order, big.NewInt(1))
}

// ByteLen returns the length of the field order in bytes.
func (f Field) ByteLen() int {
return f.byteLen
Expand Down
2 changes: 1 addition & 1 deletion internal/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ type Group interface {
ElementLength() int

// Order returns the order of the canonical group of scalars.
Order() string
Order() []byte
}
5 changes: 3 additions & 2 deletions internal/nist/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ func (g Group[P]) ElementLength() int {
}

// Order returns the order of the canonical group of scalars.
func (g Group[P]) Order() string {
return g.scalarField.Order().String()
func (g Group[P]) Order() []byte {
out := make([]byte, g.scalarField.ByteLen())
return g.scalarField.Order().FillBytes(out)
}

var (
Expand Down
6 changes: 6 additions & 0 deletions internal/nist/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ func (s *Scalar) One() internal.Scalar {
return s
}

// MinusOne sets the scalar to order-1, and returns it.
func (s *Scalar) MinusOne() internal.Scalar {
s.scalar.Set(s.field.PMinusOne())
return s
}

// Random sets s to a new random scalar and returns it.
// The random source is crypto/rand, and this functions is guaranteed to return a non-zero scalar.
func (s *Scalar) Random() internal.Scalar {
Expand Down
11 changes: 3 additions & 8 deletions internal/ristretto/ristretto.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package ristretto

import (
"crypto"
"slices"

"github.com/bytemare/hash2curve"
"github.com/gtank/ristretto255"
Expand All @@ -26,12 +27,6 @@ const (

// H2C represents the hash-to-curve string identifier.
H2C = "ristretto255_XMD:SHA-512_R255MAP_RO_"

// orderPrime represents curve25519's subgroup prime-order
// = 2^252 + 27742317777372353535851937790883648493
// = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
// cofactor h = 8.
orderPrime = "7237005577332262213973186563042994240857116359379907606001950938285454250989"
)

// Group represents the Ristretto255 group. It exposes a prime-order group API with hash-to-curve operations.
Expand Down Expand Up @@ -99,6 +94,6 @@ func (g Group) ElementLength() int {
}

// Order returns the order of the canonical group of scalars.
func (g Group) Order() string {
return orderPrime
func (g Group) Order() []byte {
return slices.Clone(orderBytes)
}
56 changes: 29 additions & 27 deletions internal/ristretto/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"encoding/binary"
"encoding/hex"
"fmt"
"math/big"

"github.com/gtank/ristretto255"

Expand All @@ -23,9 +22,21 @@ import (
const canonicalEncodingLength = 32

var (
scZero = &Scalar{*ristretto255.NewScalar()}
scOne Scalar
order big.Int
scZero = &Scalar{*ristretto255.NewScalar()}
scOne Scalar
scMinusOne = []byte{
236, 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,
}
// orderBytes represents curve25519's subgroup prime-order
// = 2^252 + 27742317777372353535851937790883648493
// = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed
// = 7237005577332262213973186563042994240857116359379907606001950938285454250989
// cofactor h = 8.
orderBytes = []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,
}
)

func init() {
Expand All @@ -36,10 +47,6 @@ func init() {
}); err != nil {
panic(err)
}

if _, ok := order.SetString(orderPrime, 10); !ok {
panic(internal.ErrBigIntConversion)
}
}

// Scalar implements the Scalar interface for Ristretto255 group scalars.
Expand Down Expand Up @@ -77,6 +84,12 @@ func (s *Scalar) One() internal.Scalar {
return s
}

// MinusOne sets the scalar to order-1, and returns it.
func (s *Scalar) MinusOne() internal.Scalar {
_ = s.decodeScalar(scMinusOne)
return s
}

// Random sets the current scalar to a new random scalar and returns it.
// The random source is crypto/rand, and this functions is guaranteed to return a non-zero scalar.
func (s *Scalar) Random() internal.Scalar {
Expand Down Expand Up @@ -270,14 +283,11 @@ func (s *Scalar) SetUInt64(i uint64) internal.Scalar {
encoded := make([]byte, canonicalEncodingLength)
binary.LittleEndian.PutUint64(encoded, i)

sc, err := decodeScalar(encoded)
if err != nil {
if err := s.decodeScalar(encoded); err != nil {
// This cannot happen, since any uint64 is smaller than the order.
panic(fmt.Sprintf("unexpected decoding of uint64 scalar: %s", err))
}

s.set(sc)

return s
}

Expand Down Expand Up @@ -312,33 +322,25 @@ func (s *Scalar) Encode() []byte {
return s.scalar.Encode(nil)
}

func decodeScalar(scalar []byte) (*ristretto255.Scalar, error) {
func (s *Scalar) decodeScalar(scalar []byte) error {
if len(scalar) == 0 {
return nil, internal.ErrParamNilScalar
return internal.ErrParamNilScalar
}

if len(scalar) != canonicalEncodingLength {
return nil, internal.ErrParamScalarLength
return internal.ErrParamScalarLength
}

s := ristretto255.NewScalar()
if err := s.Decode(scalar); err != nil {
return nil, fmt.Errorf("%w", err)
if err := s.scalar.Decode(scalar); err != nil {
return fmt.Errorf("%w", err)
}

return s, nil
return nil
}

// Decode sets the receiver to a decoding of the input data, and returns an error on failure.
func (s *Scalar) Decode(in []byte) error {
sc, err := decodeScalar(in)
if err != nil {
return err
}

s.scalar = *sc

return nil
return s.decodeScalar(in)
}

// Hex returns the fixed-sized hexadecimal encoding of s.
Expand Down
3 changes: 3 additions & 0 deletions internal/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type Scalar interface {
// One sets the scalar to 1, and returns it.
One() Scalar

// MinusOne sets the scalar to order-1, and returns it.
MinusOne() Scalar

// Random sets the current scalar to a new random scalar and returns it.
// The random source is crypto/rand, and this functions is guaranteed to return a non-zero scalar.
Random() Scalar
Expand Down
16 changes: 7 additions & 9 deletions internal/secp256k1/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,13 @@ const (
// E2CSECP256K1 represents the encode-to-curve string identifier for Secp256k1.
E2CSECP256K1 = "secp256k1_XMD:SHA-256_SSWU_NU_"

groupOrder = "115792089237316195423570985008687907852837564279074904382605163141518161494337"
scalarLength = 32
elementLength = 33
scalarLength = 32
)

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

// New returns a new instantiation of the Secp256k1 Group.
// New returns a new instantiation of the SECp256k1 Group.
func New() internal.Group {
return Group{}
}
Expand Down Expand Up @@ -85,15 +83,15 @@ func (g Group) Ciphersuite() string {

// ScalarLength returns the byte size of an encoded scalar.
func (g Group) ScalarLength() int {
return scalarLength
return secp256k1.ScalarLength()
}

// ElementLength returns the byte size of an encoded element.
func (g Group) ElementLength() int {
return elementLength
return secp256k1.ElementLength()
}

// Order returns the order of the canonical group of scalars.
func (g Group) Order() string {
return groupOrder
func (g Group) Order() []byte {
return secp256k1.Order()
}
6 changes: 6 additions & 0 deletions internal/secp256k1/scalar.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ func (s *Scalar) One() internal.Scalar {
return s
}

// MinusOne sets the scalar to order-1, and returns it.
func (s *Scalar) MinusOne() internal.Scalar {
s.scalar.MinusOne()
return s
}

// Random sets the current scalar to a new random scalar and returns it.
// The random source is crypto/rand, and this functions is guaranteed to return a non-zero scalar.
func (s *Scalar) Random() internal.Scalar {
Expand Down
Loading
Loading