diff --git a/README.md b/README.md index c51b7c1..fed793f 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ type Group interface { NewScalar() Scalar NewElement() Element Base() Element + HashFunc() crypto.Hash HashToScalar(input, dst []byte) Scalar HashToGroup(input, dst []byte) Element EncodeToGroup(input, dst []byte) Element diff --git a/groups.go b/groups.go index 889788c..ec26b3f 100644 --- a/groups.go +++ b/groups.go @@ -13,6 +13,7 @@ package crypto import ( + "crypto" "errors" "fmt" "sync" @@ -113,6 +114,11 @@ func checkDST(dst []byte) { } } +// HashFunc returns the RFC9380 associated hash function of the group. +func (g Group) HashFunc() crypto.Hash { + return g.get().HashFunc() +} + // 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) *Scalar { diff --git a/internal/edwards25519/group.go b/internal/edwards25519/group.go index 9a4a27d..712a59d 100644 --- a/internal/edwards25519/group.go +++ b/internal/edwards25519/group.go @@ -10,6 +10,8 @@ package edwards25519 import ( + "crypto" + ed "filippo.io/edwards25519" "github.com/bytemare/crypto/internal" @@ -43,6 +45,11 @@ func (g Group) Base() internal.Element { return &Element{*ed.NewGeneratorPoint()} } +// HashFunc returns the RFC9380 associated hash function of the group. +func (g Group) HashFunc() crypto.Hash { + return crypto.SHA512 +} + // 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 { diff --git a/internal/group.go b/internal/group.go index ee42ccb..a0949ff 100644 --- a/internal/group.go +++ b/internal/group.go @@ -9,6 +9,8 @@ // Package internal defines simple and abstract APIs to group Elements and Scalars. package internal +import "crypto" + // Group abstracts operations in a prime-order group. type Group interface { // NewScalar returns a new scalar set to 0. @@ -20,6 +22,9 @@ type Group interface { // Base returns the group's base point a.k.a. canonical generator. Base() Element + // HashFunc returns the RFC9380 associated hash function of the group. + HashFunc() crypto.Hash + // 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. HashToScalar(input, dst []byte) Scalar diff --git a/internal/nist/group.go b/internal/nist/group.go index f9955f4..de5a803 100644 --- a/internal/nist/group.go +++ b/internal/nist/group.go @@ -95,6 +95,11 @@ func (g Group[P]) newPoint(p P) *Element[P] { } } +// HashFunc returns the RFC9380 associated hash function of the group. +func (g Group[P]) HashFunc() crypto.Hash { + return g.curve.hash +} + // 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[P]) HashToScalar(input, dst []byte) internal.Scalar { diff --git a/internal/ristretto/ristretto.go b/internal/ristretto/ristretto.go index 3859282..c1fdfeb 100644 --- a/internal/ristretto/ristretto.go +++ b/internal/ristretto/ristretto.go @@ -54,6 +54,11 @@ func (g Group) Base() internal.Element { return &Element{*ristretto255.NewElement().Base()} } +// HashFunc returns the RFC9380 associated hash function of the group. +func (g Group) HashFunc() crypto.Hash { + return crypto.SHA512 +} + // 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 { diff --git a/internal/secp256k1/group.go b/internal/secp256k1/group.go index abe2b58..c9f52f8 100644 --- a/internal/secp256k1/group.go +++ b/internal/secp256k1/group.go @@ -10,6 +10,8 @@ package secp256k1 import ( + "crypto" + "github.com/bytemare/secp256k1" "github.com/bytemare/crypto/internal" @@ -50,6 +52,11 @@ func (g Group) Base() internal.Element { return newElement().Base() } +// HashFunc returns the RFC9380 associated hash function of the group. +func (g Group) HashFunc() crypto.Hash { + return crypto.SHA256 +} + // 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 { diff --git a/tests/groups_test.go b/tests/groups_test.go index cc46430..468a7f2 100644 --- a/tests/groups_test.go +++ b/tests/groups_test.go @@ -141,6 +141,14 @@ func TestGroup_ElementLength(t *testing.T) { }) } +func TestHashFunc(t *testing.T) { + testAll(t, func(group *testGroup) { + if group.group.HashFunc() != group.hash { + t.Error(errExpectedEquality) + } + }) +} + func TestHashToScalar(t *testing.T) { testAll(t, func(group *testGroup) { sv := decodeScalar(t, group.group, group.hashToCurve.hashToScalar) diff --git a/tests/table_test.go b/tests/table_test.go index 7834696..36fad50 100644 --- a/tests/table_test.go +++ b/tests/table_test.go @@ -9,9 +9,10 @@ package group_test import ( + "crypto" "testing" - "github.com/bytemare/crypto" + group "github.com/bytemare/crypto" ) func testAll(t *testing.T, f func(*testGroup)) { @@ -47,7 +48,8 @@ type testGroup struct { hashToCurve testHashToCurve elementLength int scalarLength int - group crypto.Group + group group.Group + hash crypto.Hash } var testTable = []*testGroup{ @@ -85,6 +87,7 @@ var testTable = []*testGroup{ 32, 32, 1, + crypto.SHA512, }, { [15]string{ @@ -120,6 +123,7 @@ var testTable = []*testGroup{ 33, 32, 3, + crypto.SHA256, }, { [15]string{ @@ -155,6 +159,7 @@ var testTable = []*testGroup{ 49, 48, 4, + crypto.SHA384, }, { [15]string{ @@ -190,6 +195,7 @@ var testTable = []*testGroup{ 67, 66, 5, + crypto.SHA512, }, { [15]string{ @@ -225,6 +231,7 @@ var testTable = []*testGroup{ 32, 32, 6, + crypto.SHA512, }, { [15]string{ @@ -260,5 +267,6 @@ var testTable = []*testGroup{ 33, 32, 7, + crypto.SHA256, }, } diff --git a/tests/utils_test.go b/tests/utils_test.go index b669018..f334ba6 100644 --- a/tests/utils_test.go +++ b/tests/utils_test.go @@ -14,6 +14,7 @@ import ( "encoding/hex" "errors" "fmt" + "strings" "testing" "github.com/bytemare/crypto" @@ -166,8 +167,8 @@ func testDecodingHexFails(t *testing.T, thing1, thing2 serde) { if err := thing2.DecodeHex(string(malformed)); err == nil { t.Fatal("expected error on malformed string") - } else { - t.Log(err) + } else if !strings.HasSuffix(err.Error(), "DecodeHex: encoding/hex: invalid byte: U+005F '_'") { + t.Fatalf("unexpected error: %q", err) } }