-
Notifications
You must be signed in to change notification settings - Fork 0
/
groups.go
183 lines (149 loc) · 5.03 KB
/
groups.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// SPDX-License-Group: MIT
//
// Copyright (C) 2020-2024 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 ecc exposes a prime-order elliptic curve groups with additional hash-to-curve operations.
//
// It implements the latest hash-to-curve specification to date
// (https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/).
package ecc
import (
"crypto"
"errors"
"fmt"
"sync"
"github.com/bytemare/ecc/internal"
"github.com/bytemare/ecc/internal/edwards25519"
"github.com/bytemare/ecc/internal/nist"
"github.com/bytemare/ecc/internal/ristretto"
"github.com/bytemare/ecc/internal/secp256k1"
)
// Group identifies prime-order groups over elliptic curves with hash-to-group operations.
type Group byte
const (
// Ristretto255Sha512 identifies the Ristretto255 group with SHA2-512 hash-to-group hashing.
Ristretto255Sha512 Group = 1 + iota
// decaf448Shake256 is not implemented.
decaf448Shake256
// P256Sha256 identifies a group over P256 with SHA2-256 hash-to-group hashing.
P256Sha256
// P384Sha384 identifies a group over P384 with SHA2-384 hash-to-group hashing.
P384Sha384
// 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
// Secp256k1Sha256 identifies the SECp256k1 group with SHA2-256 hash-to-group hashing.
Secp256k1Sha256
maxID
dstfmt = "%s-V%02d-CS%02d-%s"
minLength = 0
recommendedMinLength = 16
)
var (
once [maxID - 1]sync.Once
groups [maxID - 1]internal.Group
errZeroLenDST = errors.New("zero-length DST")
)
// Available reports whether the given Group is linked into the binary.
func (g Group) Available() bool {
return 0 < g && g < maxID && g != decaf448Shake256
}
func (g Group) get() internal.Group {
if !g.Available() {
panic(internal.ErrInvalidGroup)
}
once[g-1].Do(g.init)
return groups[g-1]
}
// MakeDST builds a domain separation tag in the form of <app>-V<version>-CS<id>-<hash-to-curve-ID>,
// and returns no error.
func (g Group) MakeDST(app string, version uint8) []byte {
p := g.get()
return []byte(fmt.Sprintf(dstfmt, app, version, g, p.Ciphersuite()))
}
// String returns the hash-to-curve string identifier of the ciphersuite.
func (g Group) String() string {
return g.get().Ciphersuite()
}
// NewScalar returns a new scalar set to 0.
func (g Group) NewScalar() *Scalar {
return newScalar(g.get().NewScalar())
}
// NewElement returns the identity element (point at infinity).
func (g Group) NewElement() *Element {
return newPoint(g.get().NewElement())
}
// Base returns the group's base point a.k.a. canonical generator.
func (g Group) Base() *Element {
return newPoint(g.get().Base())
}
func checkDST(dst []byte) {
if len(dst) < recommendedMinLength {
if len(dst) == minLength {
panic(errZeroLenDST)
}
}
}
// 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 {
checkDST(dst)
return newScalar(g.get().HashToScalar(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) *Element {
checkDST(dst)
return newPoint(g.get().HashToGroup(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) *Element {
checkDST(dst)
return newPoint(g.get().EncodeToGroup(input, dst))
}
// ScalarLength returns the byte size of an encoded scalar.
func (g Group) ScalarLength() int {
return g.get().ScalarLength()
}
// ElementLength returns the byte size of an encoded element.
func (g Group) ElementLength() int {
return g.get().ElementLength()
}
// Order returns the order of the canonical group of scalars.
func (g Group) Order() []byte {
return g.get().Order()
}
func (g Group) initGroup(get func() internal.Group) {
groups[g-1] = get()
}
func (g Group) init() {
switch g {
case Ristretto255Sha512:
g.initGroup(ristretto.New)
case P256Sha256:
g.initGroup(nist.P256)
case P384Sha384:
g.initGroup(nist.P384)
case P521Sha512:
g.initGroup(nist.P521)
case Edwards25519Sha512:
g.initGroup(edwards25519.New)
case Secp256k1Sha256:
g.initGroup(secp256k1.New)
default:
panic("group not recognized")
}
}
// disallowEqual is an incomparable type.
// If you place it first in your struct, you prevent == from
// working on your struct without growing its size.
type disallowEqual [0]func()