Skip to content

Commit 170cfd4

Browse files
committed
fixed
1 parent 497dc71 commit 170cfd4

File tree

11 files changed

+1259
-11
lines changed

11 files changed

+1259
-11
lines changed

elliptic/e521/e521.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package e521
2+
3+
import (
4+
"sync"
5+
"encoding/asn1"
6+
)
7+
8+
// Implements support for ECC over Curve E-521 as specified in the
9+
// Brazilian national cryptographic standards defined in:
10+
//
11+
// ITI DOC-ICP-01.01 — Brazilian Cryptographic Standards for Public-Key Algorithms
12+
//
13+
// This standard is maintained under the ICP-Brasil framework by the
14+
// Instituto Nacional de Tecnologia da Informação (ITI) and mandates the
15+
// use of secure, internationally reviewed algorithms for digital
16+
// certificates and electronic signatures.
17+
//
18+
// Curve E-521 is a high-security elliptic curve consistent with 512-bit
19+
// security strength and is considered future-safe for use in digital
20+
// signatures and key agreement protocols.
21+
//
22+
// Officially approved via:
23+
// - Instrução Normativa ITI nº 22, de 23 de março de 2022
24+
//
25+
// References:
26+
// - ICP-Brasil – DOC-ICP-01.01, v5.0 (2022)
27+
// https://www.gov.br/iti/pt-br/assuntos/legislacao/documentos-principais/IN2022_22_DOC_ICP_01.01_assinado.pdf
28+
// - Instrução Normativa ITI nº 22/2022 – Instituto Nacional de Tecnologia da Informação
29+
// - Diego F. Aranha, Paulo S. L. M. Barreto, Geovandro C. C. F. Pereira, Jefferson Ricardini,
30+
// "A note on high-security general-purpose elliptic curves", 2013.
31+
// https://eprint.iacr.org/2013/647
32+
//
33+
// This code implements PureEdDSA using SHAKE256 over the E-521 Edwards curve,
34+
// compliant with the above specifications.
35+
36+
var (
37+
// E-521 EdDSA curve oid
38+
OIDE521 = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 44588, 2, 1}
39+
)
40+
41+
var once sync.Once
42+
43+
func E521() *E521Curve {
44+
once.Do(initAll)
45+
return e521
46+
}

elliptic/e521/e521_curves.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package e521
2+
3+
import (
4+
"math/big"
5+
)
6+
7+
var e521 *E521Curve
8+
9+
func initAll() {
10+
initE521()
11+
}
12+
13+
func initE521() {
14+
// h = "04"
15+
e521 = &E521Curve{
16+
Name: "E-521",
17+
P: bigFromHex("1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
18+
N: bigFromHex("7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd15b6c64746fc85f736b8af5e7ec53f04fbd8c4569a8f1f4540ea2435f5180d6b"),
19+
D: bigFromHex("1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa4331"),
20+
Gx: bigFromHex("752cb45c48648b189df90cb2296b2878a3bfd9f42fc6c818ec8bf3c9c0c6203913f6ecc5ccc72434b1ae949d568fc99c6059d0fb13364838aa302a940a2f19ba6c"),
21+
Gy: bigFromHex("0c"),
22+
BitSize: 521,
23+
}
24+
}
25+
26+
func bigFromHex(s string) (i *big.Int) {
27+
i = new(big.Int)
28+
i.SetString(s, 16)
29+
30+
return
31+
}

elliptic/e521/e521_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package e521
2+
3+
import (
4+
"testing"
5+
"crypto/elliptic"
6+
)
7+
8+
func Test_Interface(t *testing.T) {
9+
var _ elliptic.Curve = (*E521Curve)(nil)
10+
}

elliptic/e521/params.go

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
package e521
2+
3+
import (
4+
"math/big"
5+
"crypto/elliptic"
6+
)
7+
8+
type E521Curve struct {
9+
Name string
10+
P *big.Int
11+
N *big.Int
12+
D *big.Int
13+
Gx, Gy *big.Int
14+
BitSize int
15+
}
16+
17+
func (curve *E521Curve) Params() *elliptic.CurveParams {
18+
cp := new(elliptic.CurveParams)
19+
cp.Name = curve.Name
20+
cp.P = curve.P
21+
cp.N = curve.N
22+
cp.Gx = curve.Gx
23+
cp.Gy = curve.Gy
24+
cp.BitSize = curve.BitSize
25+
return cp
26+
}
27+
28+
// polynomial returns (1 - y²) / (1 - d*y²).
29+
func (curve *E521Curve) polynomial(y *big.Int) *big.Int {
30+
// Solve for x using Edwards curve equation: x² + y² = 1 + d*x²*y²
31+
// Rearranged to: x² = (1 - y²) / (1 - d*y²)
32+
y2 := new(big.Int).Mul(y, y)
33+
y2.Mod(y2, curve.P)
34+
35+
// numerator = 1 - y²
36+
numerator := new(big.Int).Sub(big.NewInt(1), y2)
37+
numerator.Mod(numerator, curve.P)
38+
39+
// denominator = 1 - d*y²
40+
dy2 := new(big.Int).Mul(y2, curve.D)
41+
dy2.Mod(dy2, curve.P)
42+
denominator := new(big.Int).Sub(big.NewInt(1), dy2)
43+
denominator.Mod(denominator, curve.P)
44+
45+
// x² = numerator / denominator
46+
invDenom := new(big.Int).ModInverse(denominator, curve.P)
47+
if invDenom == nil {
48+
return new(big.Int)
49+
}
50+
51+
x2 := new(big.Int).Mul(numerator, invDenom)
52+
x2.Mod(x2, curve.P)
53+
54+
return x2
55+
}
56+
57+
// check equation: x² + y² ≡ 1 + d*x²*y² (mod p),
58+
// so we can check equation: x² = (1 - y²) / (1 - d*y²).
59+
func (curve *E521Curve) IsOnCurve(x, y *big.Int) bool {
60+
if x.Sign() == 0 && y.Sign() == 0 {
61+
return true
62+
}
63+
64+
x2 := new(big.Int).Mul(x, x)
65+
x2.Mod(x2, curve.P)
66+
67+
return curve.polynomial(y).Cmp(x2) == 0
68+
}
69+
70+
func (curve *E521Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
71+
if x1.Sign() == 0 && y1.Sign() == 0 {
72+
return x2, y2
73+
}
74+
if x2.Sign() == 0 && y2.Sign() == 0 {
75+
return x1, y1
76+
}
77+
78+
// x3 = (x1*y2 + y1*x2) / (1 + d*x1*x2*y1*y2)
79+
// y3 = (y1*y2 - x1*x2) / (1 - d*x1*x2*y1*y2)
80+
81+
x1y2 := new(big.Int).Mul(x1, y2)
82+
y1x2 := new(big.Int).Mul(y1, x2)
83+
numeratorX := new(big.Int).Add(x1y2, y1x2)
84+
85+
y1y2 := new(big.Int).Mul(y1, y2)
86+
x1x2 := new(big.Int).Mul(x1, x2)
87+
numeratorY := new(big.Int).Sub(y1y2, x1x2)
88+
89+
dx1x2y1y2 := new(big.Int).Mul(x1x2, y1y2)
90+
dx1x2y1y2.Mul(dx1x2y1y2, curve.D)
91+
dx1x2y1y2.Mod(dx1x2y1y2, curve.P)
92+
93+
denominatorX := new(big.Int).Add(big.NewInt(1), dx1x2y1y2)
94+
denominatorY := new(big.Int).Sub(big.NewInt(1), dx1x2y1y2)
95+
96+
// Encontrar inversos modulares
97+
invDenomX := new(big.Int).ModInverse(denominatorX, curve.P)
98+
invDenomY := new(big.Int).ModInverse(denominatorY, curve.P)
99+
100+
x3 := new(big.Int).Mul(numeratorX, invDenomX)
101+
x3.Mod(x3, curve.P)
102+
103+
y3 := new(big.Int).Mul(numeratorY, invDenomY)
104+
y3.Mod(y3, curve.P)
105+
106+
return x3, y3
107+
}
108+
109+
// Double dobra um ponto na curva Edwards
110+
func (curve *E521Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
111+
return curve.Add(x1, y1, x1, y1)
112+
}
113+
114+
func (curve *E521Curve) ScalarMult(x, y *big.Int, k []byte) (*big.Int, *big.Int) {
115+
scalar := bytesToLittleInt(k)
116+
scalar.Mod(scalar, curve.N)
117+
118+
resultX := big.NewInt(0)
119+
resultY := big.NewInt(1)
120+
121+
tempX := new(big.Int).Set(x)
122+
tempY := new(big.Int).Set(y)
123+
124+
for scalar.BitLen() > 0 {
125+
if scalar.Bit(0) == 1 {
126+
resultX, resultY = curve.Add(resultX, resultY, tempX, tempY)
127+
}
128+
129+
tempX, tempY = curve.Double(tempX, tempY)
130+
scalar.Rsh(scalar, 1)
131+
}
132+
133+
return resultX, resultY
134+
}
135+
136+
func (curve *E521Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
137+
return curve.ScalarMult(curve.Gx, curve.Gy, k)
138+
}
139+
140+
func (curve *E521Curve) Marshal(x, y *big.Int) []byte {
141+
return Marshal(curve, x, y)
142+
}
143+
144+
// MarshalCompressed compresses Edwards point according to RFC 8032: store sign bit of x
145+
func (curve *E521Curve) MarshalCompressed(x, y *big.Int) []byte {
146+
return MarshalCompressed(curve, x, y)
147+
}
148+
149+
func (curve *E521Curve) Unmarshal(data []byte) (*big.Int, *big.Int) {
150+
if len(data) == 0 {
151+
return nil, nil
152+
}
153+
154+
byteLen := (curve.BitSize + 7) / 8
155+
if len(data) != 1+2*byteLen {
156+
return nil, nil
157+
}
158+
159+
if data[0] != 4 {
160+
return nil, nil
161+
}
162+
163+
x := bytesToLittleInt(data[1 : 1+byteLen])
164+
y := bytesToLittleInt(data[1+byteLen:])
165+
166+
if !curve.IsOnCurve(x, y) {
167+
return nil, nil
168+
}
169+
170+
return x, y
171+
}
172+
173+
// UnmarshalCompressed decompresses a compressed point according to RFC 8032
174+
func (curve *E521Curve) UnmarshalCompressed(data []byte) (*big.Int, *big.Int) {
175+
byteLen := (curve.BitSize + 7) / 8
176+
if len(data) != byteLen {
177+
return nil, nil
178+
}
179+
180+
// Extract sign bit from MSB of last byte
181+
signBit := (data[byteLen-1] >> 7) & 1
182+
183+
// Clear the sign bit from y data
184+
yBytes := make([]byte, byteLen)
185+
copy(yBytes, data)
186+
yBytes[byteLen-1] &= 0x7F // Clear MSB
187+
188+
y := bytesToLittleInt(yBytes)
189+
190+
// Solve for x using Edwards curve equation: x² + y² = 1 + d*x²*y²
191+
x2 := curve.polynomial(y)
192+
193+
// Calculate square root
194+
x := new(big.Int).ModSqrt(x2, curve.P)
195+
if x == nil {
196+
return nil, nil
197+
}
198+
199+
// Choose correct x based on sign bit (RFC 8032 uses sign of x)
200+
xBytes := littleIntToBytes(x, byteLen)
201+
if (xBytes[0] & 1) != signBit {
202+
x.Sub(curve.P, x)
203+
x.Mod(x, curve.P)
204+
}
205+
206+
return x, y
207+
}
208+
209+
func Marshal(curve elliptic.Curve, x, y *big.Int) []byte {
210+
panicIfNotOnCurve(curve, x, y)
211+
212+
byteLen := (curve.Params().BitSize + 7) / 8
213+
ret := make([]byte, 1+2*byteLen)
214+
ret[0] = 4 // uncompressed point
215+
216+
xBytes := littleIntToBytes(x, byteLen)
217+
yBytes := littleIntToBytes(y, byteLen)
218+
219+
copy(ret[1:1+byteLen], xBytes)
220+
copy(ret[1+byteLen:], yBytes)
221+
222+
return ret
223+
}
224+
225+
func MarshalCompressed(curve elliptic.Curve, x, y *big.Int) []byte {
226+
panicIfNotOnCurve(curve, x, y)
227+
228+
byteLen := (curve.Params().BitSize + 7) / 8
229+
yBytes := littleIntToBytes(y, byteLen)
230+
231+
// Get the sign bit from x (LSB in little-endian representation)
232+
xBytes := littleIntToBytes(x, byteLen)
233+
signBit := xBytes[0] & 1
234+
235+
// Store sign bit in the LSB of the last byte of yBytes (RFC 8032)
236+
compressed := make([]byte, byteLen)
237+
copy(compressed, yBytes)
238+
compressed[byteLen-1] |= signBit << 7
239+
240+
return compressed
241+
}
242+
243+
func Unmarshal(curve elliptic.Curve, data []byte) (*big.Int, *big.Int) {
244+
if c, ok := curve.(*E521Curve); ok {
245+
return c.Unmarshal(data)
246+
}
247+
248+
return nil, nil
249+
}
250+
251+
func UnmarshalCompressed(curve elliptic.Curve, data []byte) (*big.Int, *big.Int) {
252+
if c, ok := curve.(*E521Curve); ok {
253+
return c.UnmarshalCompressed(data)
254+
}
255+
256+
return nil, nil
257+
}
258+
259+
func panicIfNotOnCurve(curve elliptic.Curve, x, y *big.Int) {
260+
// (0, 0) is the point at infinity by convention. It's ok to operate on it,
261+
// although IsOnCurve is documented to return false for it. See Issue 37294.
262+
if x.Sign() == 0 && y.Sign() == 0 {
263+
return
264+
}
265+
266+
if !curve.IsOnCurve(x, y) {
267+
panic("go-cryptobin/kg: attempted operation on invalid point")
268+
}
269+
}
270+
271+
// bytesToLittleInt converte bytes little-endian to big.Int
272+
func bytesToLittleInt(b []byte) *big.Int {
273+
reversed := make([]byte, len(b))
274+
for i := 0; i < len(b); i++ {
275+
reversed[i] = b[len(b)-1-i]
276+
}
277+
278+
return new(big.Int).SetBytes(reversed)
279+
}
280+
281+
// littleIntToBytes converte big.Int to bytes little-endian
282+
func littleIntToBytes(n *big.Int, length int) []byte {
283+
bytes := n.Bytes()
284+
285+
if len(bytes) < length {
286+
padding := make([]byte, length-len(bytes))
287+
bytes = append(padding, bytes...)
288+
}
289+
290+
reversed := make([]byte, length)
291+
for i := 0; i < length; i++ {
292+
reversed[i] = bytes[length-1-i]
293+
}
294+
295+
return reversed
296+
}

0 commit comments

Comments
 (0)