diff --git a/internal/sm2ec/p256_asm_amd64.s b/internal/sm2ec/p256_asm_amd64.s index ef654f1..722cfe9 100644 --- a/internal/sm2ec/p256_asm_amd64.s +++ b/internal/sm2ec/p256_asm_amd64.s @@ -75,7 +75,7 @@ TEXT ·p256BigToLittle(SB),NOSPLIT,$0 RET /* ---------------------------------------*/ -// func p256MovCond(res, a, b *P256Point, cond int) +// func p256MovCond(res, a, b *SM2P256Point, cond int) TEXT ·p256MovCond(SB),NOSPLIT,$0 MOVQ res+0(FP), res_ptr MOVQ a+8(FP), x_ptr @@ -671,7 +671,7 @@ TEXT ·p256FromMont(SB),NOSPLIT,$0 RET /* ---------------------------------------*/ -// func p256Select(res *P256Point, table *p256Table, idx int) +// func p256Select(res *SM2P256Point, table *p256Table, idx int) TEXT ·p256Select(SB),NOSPLIT,$0 MOVQ idx+16(FP),AX MOVQ table+8(FP),DI @@ -1797,7 +1797,7 @@ TEXT sm2P256SqrInternal(SB),NOSPLIT,$8 #define sel_save (32*15 + 8)(SP) #define zero_save (32*15 + 8 + 4)(SP) -// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int) +// func p256PointAddAffineAsm(res, in1 *SM2P256Point, in2 *p256AffinePoint, sign, sel, zero int) TEXT ·p256PointAddAffineAsm(SB),0,$512-48 // Move input to stack in order to free registers MOVQ res+0(FP), AX @@ -2110,7 +2110,7 @@ TEXT sm2P256IsZero(SB),NOSPLIT,$0 #define rptr (32*20)(SP) #define points_eq (32*20+8)(SP) -//func p256PointAddAsm(res, in1, in2 *P256Point) int +//func p256PointAddAsm(res, in1, in2 *SM2P256Point) int TEXT ·p256PointAddAsm(SB),0,$680-32 // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl // Move input to stack in order to free registers @@ -2290,7 +2290,7 @@ TEXT ·p256PointAddAsm(SB),0,$680-32 #define tmp(off) (32*6 + off)(SP) #define rptr (32*7)(SP) -//func p256PointDoubleAsm(res, in *P256Point) +//func p256PointDoubleAsm(res, in *SM2P256Point) TEXT ·p256PointDoubleAsm(SB),NOSPLIT,$256-16 // Move input to stack in order to free registers MOVQ res+0(FP), AX diff --git a/internal/sm2ec/p256_asm_arm64.s b/internal/sm2ec/p256_asm_arm64.s index 8940812..2a1085a 100644 --- a/internal/sm2ec/p256_asm_arm64.s +++ b/internal/sm2ec/p256_asm_arm64.s @@ -92,7 +92,7 @@ TEXT ·p256BigToLittle(SB),NOSPLIT,$0 STP (acc1, acc0), 1*16(res_ptr) RET /* ---------------------------------------*/ -// func p256MovCond(res, a, b *P256Point, cond int) +// func p256MovCond(res, a, b *SM2P256Point, cond int) // If cond == 0 res=b, else res=a TEXT ·p256MovCond(SB),NOSPLIT,$0 MOVD res+0(FP), res_ptr @@ -291,7 +291,7 @@ TEXT ·p256FromMont(SB),NOSPLIT,$0 RET /* ---------------------------------------*/ -// func p256Select(res *P256Point, table *p256Table, idx int) +// func p256Select(res *SM2P256Point, table *p256Table, idx int) TEXT ·p256Select(SB),NOSPLIT,$0 MOVD idx+16(FP), const0 MOVD table+8(FP), b_ptr @@ -1159,7 +1159,7 @@ TEXT sm2P256MulInternal<>(SB),NOSPLIT,$0 #define u1(off) (32*10 + 8 + off)(RSP) #define u2(off) (32*11 + 8 + off)(RSP) -// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int) +// func p256PointAddAffineAsm(res, in1 *SM2P256Point, in2 *p256AffinePoint, sign, sel, zero int) TEXT ·p256PointAddAffineAsm(SB),0,$264-48 MOVD in1+8(FP), a_ptr MOVD in2+16(FP), b_ptr @@ -1355,7 +1355,7 @@ TEXT ·p256PointAddAffineAsm(SB),0,$264-48 #define zsqr(off) (32*2 + 8 + off)(RSP) #define tmp(off) (32*3 + 8 + off)(RSP) -//func p256PointDoubleAsm(res, in *P256Point) +//func p256PointDoubleAsm(res, in *SM2P256Point) TEXT ·p256PointDoubleAsm(SB),NOSPLIT,$136-16 MOVD res+0(FP), res_ptr MOVD in+8(FP), a_ptr @@ -1455,7 +1455,7 @@ TEXT ·p256PointDoubleAsm(SB),NOSPLIT,$136-16 #define x3out(off) (off)(b_ptr) #define y3out(off) (off + 32)(b_ptr) #define z3out(off) (off + 64)(b_ptr) -// func p256PointAddAsm(res, in1, in2 *P256Point) int +// func p256PointAddAsm(res, in1, in2 *SM2P256Point) int TEXT ·p256PointAddAsm(SB),0,$392-32 // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl // Move input to stack in order to free registers diff --git a/internal/sm2ec/p256_asm_table_test.go b/internal/sm2ec/p256_asm_table_test.go index 7be9373..ebfe3f0 100644 --- a/internal/sm2ec/p256_asm_table_test.go +++ b/internal/sm2ec/p256_asm_table_test.go @@ -9,7 +9,7 @@ import ( ) func TestP256PrecomputedTable(t *testing.T) { - base := NewP256Point().SetGenerator() + base := NewSM2P256Point().SetGenerator() for i := 0; i < 43; i++ { t.Run(fmt.Sprintf("table[%d]", i), func(t *testing.T) { @@ -22,8 +22,8 @@ func TestP256PrecomputedTable(t *testing.T) { } } -func testP256AffineTable(t *testing.T, base *P256Point, table *p256AffineTable) { - p := NewP256Point() +func testP256AffineTable(t *testing.T, base *SM2P256Point, table *p256AffineTable) { + p := NewSM2P256Point() zInv := new(p256Element) zInvSq := new(p256Element) diff --git a/internal/sm2ec/sm2p256_asm.go b/internal/sm2ec/sm2p256_asm.go index 15bd773..f572f20 100644 --- a/internal/sm2ec/sm2p256_asm.go +++ b/internal/sm2ec/sm2p256_asm.go @@ -34,21 +34,21 @@ var p256P = p256Element{0xffffffffffffffff, 0xffffffff00000000, // P256Point is a P-256 point. The zero value should not be assumed to be valid // (although it is in this implementation). -type P256Point struct { +type SM2P256Point struct { // (X:Y:Z) are Jacobian coordinates where x = X/Z² and y = Y/Z³. The point // at infinity can be represented by any set of coordinates with Z = 0. x, y, z p256Element } -// NewP256Point returns a new P256Point representing the point at infinity. -func NewP256Point() *P256Point { - return &P256Point{ +// NewSM2P256Point returns a new SM2P256Point representing the point at infinity. +func NewSM2P256Point() *SM2P256Point { + return &SM2P256Point{ x: p256One, y: p256One, z: p256Zero, } } // SetGenerator sets p to the canonical generator and returns p. -func (p *P256Point) SetGenerator() *P256Point { +func (p *SM2P256Point) SetGenerator() *SM2P256Point { p.x = p256Element{0x61328990f418029e, 0x3e7981eddca6c050, 0xd6a1ed99ac24c3c3, 0x91167a5ee1c13b05} p.y = p256Element{0xc1354e593c2d0ddd, 0xc1f5e5788d3295fa, @@ -58,7 +58,7 @@ func (p *P256Point) SetGenerator() *P256Point { } // Set sets p = q and returns p. -func (p *P256Point) Set(q *P256Point) *P256Point { +func (p *SM2P256Point) Set(q *SM2P256Point) *SM2P256Point { p.x, p.y, p.z = q.x, q.y, q.z return p } @@ -79,7 +79,7 @@ func toElementArray(b []byte) *[32]byte { // b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on // the curve, it returns nil and an error, and the receiver is unchanged. // Otherwise, it returns p. -func (p *P256Point) SetBytes(b []byte) (*P256Point, error) { +func (p *SM2P256Point) SetBytes(b []byte) (*SM2P256Point, error) { // p256Mul operates in the Montgomery domain with R = 2²⁵⁶ mod p. Thus rr // here is R in the Montgomery domain, or R×R mod p. See comment in // P256OrdInverse about how this is used. @@ -89,11 +89,11 @@ func (p *P256Point) SetBytes(b []byte) (*P256Point, error) { switch { // Point at infinity. case len(b) == 1 && b[0] == 0: - return p.Set(NewP256Point()), nil + return p.Set(NewSM2P256Point()), nil // Uncompressed form. case len(b) == p256UncompressedLength && b[0] == 4: - var r P256Point + var r SM2P256Point p256BigToLittle(&r.x, toElementArray(b[1:33])) p256BigToLittle(&r.y, toElementArray(b[33:65])) if p256LessThanP(&r.x) == 0 || p256LessThanP(&r.y) == 0 { @@ -109,7 +109,7 @@ func (p *P256Point) SetBytes(b []byte) (*P256Point, error) { // Compressed form. case len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3): - var r P256Point + var r SM2P256Point p256BigToLittle(&r.x, toElementArray(b[1:33])) if p256LessThanP(&r.x) == 0 { return nil, errors.New("invalid P256 element encoding") @@ -334,7 +334,7 @@ func p256NegCond(val *p256Element, cond int) // If cond is 0, sets res = b, otherwise sets res = a. // //go:noescape -func p256MovCond(res, a, b *P256Point, cond int) +func p256MovCond(res, a, b *SM2P256Point, cond int) //go:noescape func p256BigToLittle(res *p256Element, in *[32]byte) @@ -351,13 +351,13 @@ func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement) // p256Table is a table of the first 16 multiples of a point. Points are stored // at an index offset of -1 so [8]P is at index 7, P is at 0, and [16]P is at 15. // [0]P is the point at infinity and it's not stored. -type p256Table [16]P256Point +type p256Table [16]SM2P256Point // p256Select sets res to the point at index idx in the table. // idx must be in [0, 15]. It executes in constant time. // //go:noescape -func p256Select(res *P256Point, table *p256Table, idx int) +func p256Select(res *SM2P256Point, table *p256Table, idx int) // p256AffinePoint is a point in affine coordinates (x, y). x and y are still // Montgomery domain elements. The point can't be the point at infinity. @@ -397,27 +397,27 @@ func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int) // If sign is not 0, sets res = in1 + -in2. Otherwise, sets res = in1 + in2 // //go:noescape -func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int) +func p256PointAddAffineAsm(res, in1 *SM2P256Point, in2 *p256AffinePoint, sign, sel, zero int) // Point addition. Sets res = in1 + in2. Returns one if the two input points // were equal and zero otherwise. If in1 or in2 are the point at infinity, res // and the return value are undefined. // //go:noescape -func p256PointAddAsm(res, in1, in2 *P256Point) int +func p256PointAddAsm(res, in1, in2 *SM2P256Point) int // Point doubling. Sets res = in + in. in can be the point at infinity. // //go:noescape -func p256PointDoubleAsm(res, in *P256Point) +func p256PointDoubleAsm(res, in *SM2P256Point) // p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] in the // Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order. type p256OrdElement [4]uint64 // Add sets q = p1 + p2, and returns q. The points may overlap. -func (q *P256Point) Add(r1, r2 *P256Point) *P256Point { - var sum, double P256Point +func (q *SM2P256Point) Add(r1, r2 *SM2P256Point) *SM2P256Point { + var sum, double SM2P256Point r1IsInfinity := r1.isInfinity() r2IsInfinity := r2.isInfinity() pointsEqual := p256PointAddAsm(&sum, r1, r2) @@ -429,8 +429,8 @@ func (q *P256Point) Add(r1, r2 *P256Point) *P256Point { } // Double sets q = p + p, and returns q. The points may overlap. -func (q *P256Point) Double(p *P256Point) *P256Point { - var double P256Point +func (q *SM2P256Point) Double(p *SM2P256Point) *SM2P256Point { + var double SM2P256Point p256PointDoubleAsm(&double, p) return q.Set(&double) } @@ -438,7 +438,7 @@ func (q *P256Point) Double(p *P256Point) *P256Point { // ScalarBaseMult sets r = scalar * generator, where scalar is a 32-byte big // endian value, and returns r. If scalar is not 32 bytes long, ScalarBaseMult // returns an error and the receiver is unchanged. -func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) { +func (r *SM2P256Point) ScalarBaseMult(scalar []byte) (*SM2P256Point, error) { if len(scalar) != 32 { return nil, errors.New("invalid scalar length") } @@ -452,7 +452,7 @@ func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) { // ScalarMult sets r = scalar * q, where scalar is a 32-byte big endian value, // and returns r. If scalar is not 32 bytes long, ScalarBaseMult returns an // error and the receiver is unchanged. -func (r *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error) { +func (r *SM2P256Point) ScalarMult(q *SM2P256Point, scalar []byte) (*SM2P256Point, error) { if len(scalar) != 32 { return nil, errors.New("invalid scalar length") } @@ -485,21 +485,21 @@ func p256Equal(a, b *p256Element) int { } // isInfinity returns 1 if p is the point at infinity and 0 otherwise. -func (p *P256Point) isInfinity() int { +func (p *SM2P256Point) isInfinity() int { return p256Equal(&p.z, &p256Zero) } // Bytes returns the uncompressed or infinity encoding of p, as specified in // SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at // infinity is shorter than all other encodings. -func (p *P256Point) Bytes() []byte { +func (p *SM2P256Point) Bytes() []byte { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. var out [p256UncompressedLength]byte return p.bytes(&out) } -func (p *P256Point) bytes(out *[p256UncompressedLength]byte) []byte { +func (p *SM2P256Point) bytes(out *[p256UncompressedLength]byte) []byte { // The proper representation of the point at infinity is a single zero byte. if p.isInfinity() == 1 { return append(out[:0], 0) @@ -517,7 +517,7 @@ func (p *P256Point) bytes(out *[p256UncompressedLength]byte) []byte { // affineFromMont sets (x, y) to the affine coordinates of p, converted out of the // Montgomery domain. -func (p *P256Point) affineFromMont(x, y *p256Element) { +func (p *SM2P256Point) affineFromMont(x, y *p256Element) { p256Inverse(y, &p.z) p256Sqr(x, y, 1) p256Mul(y, y, x) @@ -529,17 +529,41 @@ func (p *P256Point) affineFromMont(x, y *p256Element) { p256FromMont(y, y) } +// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1, +// Version 2.0, Section 2.3.5, or an error if p is the point at infinity. +func (p *SM2P256Point) BytesX() ([]byte, error) { + // This function is outlined to make the allocations inline in the caller + // rather than happen on the heap. + var out [p256ElementLength]byte + return p.bytesX(&out) +} + +func (p *SM2P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) { + if p.isInfinity() == 1 { + return nil, errors.New("SM2 point is the point at infinity") + } + + x := new(p256Element) + p256Inverse(x, &p.z) + p256Sqr(x, x, 1) + p256Mul(x, &p.x, x) + p256FromMont(x, x) + p256LittleToBig(toElementArray(out[:]), x) + + return out[:], nil +} + // BytesCompressed returns the compressed or infinity encoding of p, as // specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the // point at infinity is shorter than all other encodings. -func (p *P256Point) BytesCompressed() []byte { +func (p *SM2P256Point) BytesCompressed() []byte { // This function is outlined to make the allocations inline in the caller // rather than happen on the heap. var out [p256CompressedLength]byte return p.bytesCompressed(&out) } -func (p *P256Point) bytesCompressed(out *[p256CompressedLength]byte) []byte { +func (p *SM2P256Point) bytesCompressed(out *[p256CompressedLength]byte) []byte { if p.isInfinity() == 1 { return append(out[:0], 0) } @@ -554,7 +578,7 @@ func (p *P256Point) bytesCompressed(out *[p256CompressedLength]byte) []byte { } // Select sets q to p1 if cond == 1, and to p2 if cond == 0. -func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point { +func (q *SM2P256Point) Select(p1, p2 *SM2P256Point, cond int) *SM2P256Point { p256MovCond(q, p1, p2, cond) return q } @@ -757,7 +781,7 @@ func boothW6(in uint) (int, int) { return int(d), int(s & 1) } -func (p *P256Point) p256BaseMult(scalar *p256OrdElement) { +func (p *SM2P256Point) p256BaseMult(scalar *p256OrdElement) { var t0 p256AffinePoint wvalue := (scalar[0] << 1) & 0x7f @@ -783,14 +807,14 @@ func (p *P256Point) p256BaseMult(scalar *p256OrdElement) { } // If the whole scalar was zero, set to the point at infinity. - p256MovCond(p, p, NewP256Point(), zero) + p256MovCond(p, p, NewSM2P256Point(), zero) } -func (p *P256Point) p256ScalarMult(scalar *p256OrdElement) { +func (p *SM2P256Point) p256ScalarMult(scalar *p256OrdElement) { // precomp is a table of precomputed points that stores powers of p // from p^1 to p^16. var precomp p256Table - var t0, t1, t2, t3 P256Point + var t0, t1, t2, t3 SM2P256Point // Prepare the table precomp[0] = *p // 1 diff --git a/sm2/sm2ec/sm2p256_asm_ec.go b/sm2/sm2ec/sm2ec.go similarity index 92% rename from sm2/sm2ec/sm2p256_asm_ec.go rename to sm2/sm2ec/sm2ec.go index 9648b01..dd99624 100644 --- a/sm2/sm2ec/sm2p256_asm_ec.go +++ b/sm2/sm2ec/sm2ec.go @@ -1,6 +1,3 @@ -//go:build (amd64 && !generic) || (arm64 && !generic) -// +build amd64,!generic arm64,!generic - package sm2ec import ( @@ -13,11 +10,11 @@ import ( // TODO: will merge it with sm2p256_generic.go from golang 1.18 with generic support. type sm2Curve struct { - newPoint func() *_sm2ec.P256Point + newPoint func() *_sm2ec.SM2P256Point params *elliptic.CurveParams } -var sm2p256 = &sm2Curve{newPoint: _sm2ec.NewP256Point} +var sm2p256 = &sm2Curve{newPoint: _sm2ec.NewSM2P256Point} func initSM2P256() { sm2p256.params = sm2Params @@ -37,7 +34,7 @@ func (curve *sm2Curve) IsOnCurve(x, y *big.Int) bool { return err == nil } -func (curve *sm2Curve) pointFromAffine(x, y *big.Int) (p *_sm2ec.P256Point, err error) { +func (curve *sm2Curve) pointFromAffine(x, y *big.Int) (p *_sm2ec.SM2P256Point, err error) { p = curve.newPoint() // (0, 0) is by convention the point at infinity, which can't be represented // in affine coordinates. See Issue 37294. @@ -60,7 +57,7 @@ func (curve *sm2Curve) pointFromAffine(x, y *big.Int) (p *_sm2ec.P256Point, err return p.SetBytes(buf) } -func (curve *sm2Curve) pointToAffine(p *_sm2ec.P256Point) (x, y *big.Int) { +func (curve *sm2Curve) pointToAffine(p *_sm2ec.SM2P256Point) (x, y *big.Int) { out := p.Bytes() if len(out) == 1 && out[0] == 0 { // This is the encoding of the point at infinity, which the affine diff --git a/sm2/sm2ec/sm2p256_test.go b/sm2/sm2ec/sm2ec_test.go similarity index 100% rename from sm2/sm2ec/sm2p256_test.go rename to sm2/sm2ec/sm2ec_test.go diff --git a/sm2/sm2ec/sm2p256_generic.go b/sm2/sm2ec/sm2p256_generic.go deleted file mode 100644 index 22be415..0000000 --- a/sm2/sm2ec/sm2p256_generic.go +++ /dev/null @@ -1,180 +0,0 @@ -//go:build !amd64 && !arm64 || generic -// +build !amd64,!arm64 generic - -package sm2ec - -import ( - "crypto/elliptic" - "errors" - "math/big" - - _sm2ec "github.com/emmansun/gmsm/internal/sm2ec" -) - -// TODO: will merge it with sm2p256_asm_ec.go from golang 1.18 with generic support. -type sm2Curve struct { - newPoint func() *_sm2ec.SM2P256Point - params *elliptic.CurveParams -} - -var sm2p256 = &sm2Curve{newPoint: _sm2ec.NewSM2P256Point} - -func initSM2P256() { - sm2p256.params = sm2Params -} - -func (curve *sm2Curve) Params() *elliptic.CurveParams { - return curve.params -} - -func (curve *sm2Curve) IsOnCurve(x, y *big.Int) bool { - // IsOnCurve is documented to reject (0, 0), the conventional point at - // infinity, which however is accepted by pointFromAffine. - if x.Sign() == 0 && y.Sign() == 0 { - return false - } - _, err := curve.pointFromAffine(x, y) - return err == nil -} - -func (curve *sm2Curve) pointFromAffine(x, y *big.Int) (p *_sm2ec.SM2P256Point, err error) { - p = curve.newPoint() - // (0, 0) is by convention the point at infinity, which can't be represented - // in affine coordinates. See Issue 37294. - if x.Sign() == 0 && y.Sign() == 0 { - return p, nil - } - // Reject values that would not get correctly encoded. - if x.Sign() < 0 || y.Sign() < 0 { - return p, errors.New("negative coordinate") - } - if x.BitLen() > curve.params.BitSize || y.BitLen() > curve.params.BitSize { - return p, errors.New("overflowing coordinate") - } - // Encode the coordinates and let SetBytes reject invalid points. - byteLen := (curve.params.BitSize + 7) / 8 - buf := make([]byte, 1+2*byteLen) - buf[0] = 4 // uncompressed point - x.FillBytes(buf[1 : 1+byteLen]) - y.FillBytes(buf[1+byteLen : 1+2*byteLen]) - return p.SetBytes(buf) -} - -func (curve *sm2Curve) pointToAffine(p *_sm2ec.SM2P256Point) (x, y *big.Int) { - out := p.Bytes() - if len(out) == 1 && out[0] == 0 { - // This is the encoding of the point at infinity, which the affine - // coordinates API represents as (0, 0) by convention. - return new(big.Int), new(big.Int) - } - byteLen := (curve.params.BitSize + 7) / 8 - x = new(big.Int).SetBytes(out[1 : 1+byteLen]) - y = new(big.Int).SetBytes(out[1+byteLen:]) - return x, y -} - -func (curve *sm2Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { - p1, err := curve.pointFromAffine(x1, y1) - if err != nil { - panic("sm2/elliptic: Add was called on an invalid point") - } - p2, err := curve.pointFromAffine(x2, y2) - if err != nil { - panic("sm2/elliptic: Add was called on an invalid point") - } - return curve.pointToAffine(p1.Add(p1, p2)) -} - -func (curve *sm2Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { - p, err := curve.pointFromAffine(x1, y1) - if err != nil { - panic("sm2/elliptic: Double was called on an invalid point") - } - return curve.pointToAffine(p.Double(p)) -} - -// normalizeScalar brings the scalar within the byte size of the order of the -// curve, as expected by the nistec scalar multiplication functions. -func (curve *sm2Curve) normalizeScalar(scalar []byte) []byte { - byteSize := (curve.params.N.BitLen() + 7) / 8 - if len(scalar) == byteSize { - return scalar - } - s := new(big.Int).SetBytes(scalar) - if len(scalar) > byteSize { - s.Mod(s, curve.params.N) - } - out := make([]byte, byteSize) - return s.FillBytes(out) -} - -func (curve *sm2Curve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) { - p, err := curve.pointFromAffine(Bx, By) - if err != nil { - panic("sm2/elliptic: ScalarMult was called on an invalid point") - } - scalar = curve.normalizeScalar(scalar) - p, err = p.ScalarMult(p, scalar) - if err != nil { - panic("sm2/elliptic: sm2 rejected normalized scalar") - } - return curve.pointToAffine(p) -} - -func (curve *sm2Curve) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) { - scalar = curve.normalizeScalar(scalar) - p, err := curve.newPoint().ScalarBaseMult(scalar) - if err != nil { - panic("sm2/elliptic: sm2 rejected normalized scalar") - } - return curve.pointToAffine(p) -} - -// CombinedMult returns [s1]G + [s2]P where G is the generator. It's used -// through an interface upgrade in crypto/ecdsa. -func (curve *sm2Curve) CombinedMult(Px, Py *big.Int, s1, s2 []byte) (x, y *big.Int) { - s1 = curve.normalizeScalar(s1) - q, err := curve.newPoint().ScalarBaseMult(s1) - if err != nil { - panic("sm2/elliptic: sm2 rejected normalized scalar") - } - p, err := curve.pointFromAffine(Px, Py) - if err != nil { - panic("sm2/elliptic: CombinedMult was called on an invalid point") - } - s2 = curve.normalizeScalar(s2) - p, err = p.ScalarMult(p, s2) - if err != nil { - panic("sm2/elliptic: sm2 rejected normalized scalar") - } - return curve.pointToAffine(p.Add(p, q)) -} - -func (curve *sm2Curve) Unmarshal(data []byte) (x, y *big.Int) { - if len(data) == 0 || data[0] != 4 { - return nil, nil - } - // Use SetBytes to check that data encodes a valid point. - _, err := curve.newPoint().SetBytes(data) - if err != nil { - return nil, nil - } - // We don't use pointToAffine because it involves an expensive field - // inversion to convert from Jacobian to affine coordinates, which we - // already have. - byteLen := (curve.params.BitSize + 7) / 8 - x = new(big.Int).SetBytes(data[1 : 1+byteLen]) - y = new(big.Int).SetBytes(data[1+byteLen:]) - return x, y -} - -func (curve *sm2Curve) UnmarshalCompressed(data []byte) (x, y *big.Int) { - if len(data) == 0 || (data[0] != 2 && data[0] != 3) { - return nil, nil - } - p, err := curve.newPoint().SetBytes(data) - if err != nil { - return nil, nil - } - return curve.pointToAffine(p) -}