mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-27 04:36:19 +08:00
sm2: support ecdh mqv
This commit is contained in:
parent
6a556b26d3
commit
8f7a7626ba
@ -23,7 +23,10 @@ type Curve interface {
|
|||||||
ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error)
|
ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error)
|
||||||
|
|
||||||
// SM2MQV performs a SM2 specific style ECMQV exchange and return the shared secret.
|
// SM2MQV performs a SM2 specific style ECMQV exchange and return the shared secret.
|
||||||
//SM2MQV(sLocal, eLocal *PrivateKey, sRemote, eRemote *PublicKey) (*PublicKey, error)
|
SM2MQV(sLocal, eLocal *PrivateKey, sRemote, eRemote *PublicKey) (*PublicKey, error)
|
||||||
|
|
||||||
|
// SM2SharedKey performs SM2 key derivation to generate shared keying data, the uv was generated by SM2MQV.
|
||||||
|
SM2SharedKey(isResponder bool, kenLen int, uv, sPub, sRemote *PublicKey, uid []byte, remoteUID []byte) ([]byte, error)
|
||||||
|
|
||||||
// GenerateKey generates a new PrivateKey from rand.
|
// GenerateKey generates a new PrivateKey from rand.
|
||||||
GenerateKey(rand io.Reader) (*PrivateKey, error)
|
GenerateKey(rand io.Reader) (*PrivateKey, error)
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"crypto"
|
"crypto"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
@ -23,6 +24,14 @@ var _ interface {
|
|||||||
Equal(x crypto.PrivateKey) bool
|
Equal(x crypto.PrivateKey) bool
|
||||||
} = &ecdh.PrivateKey{}
|
} = &ecdh.PrivateKey{}
|
||||||
|
|
||||||
|
func hexDecode(t *testing.T, s string) []byte {
|
||||||
|
b, err := hex.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("invalid hex string:", s)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func TestECDH(t *testing.T) {
|
func TestECDH(t *testing.T) {
|
||||||
aliceKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
aliceKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -69,6 +78,180 @@ func TestECDH(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSM2MQV(t *testing.T) {
|
||||||
|
aliceSKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
aliceEKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobSKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
bobEKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobSecret, err := ecdh.P256().SM2MQV(bobSKey, bobEKey, aliceSKey.PublicKey(), aliceEKey.PublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aliceSecret, err := ecdh.P256().SM2MQV(aliceSKey, aliceEKey, bobSKey.PublicKey(), bobEKey.PublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !aliceSecret.Equal(bobSecret) {
|
||||||
|
t.Error("two SM2MQV computations came out different")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSM2SharedKey(t *testing.T) {
|
||||||
|
aliceSKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
aliceEKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobSKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
bobEKey, err := ecdh.P256().GenerateKey(rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobSecret, err := ecdh.P256().SM2MQV(bobSKey, bobEKey, aliceSKey.PublicKey(), aliceEKey.PublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aliceSecret, err := ecdh.P256().SM2MQV(aliceSKey, aliceEKey, bobSKey.PublicKey(), bobEKey.PublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !aliceSecret.Equal(bobSecret) {
|
||||||
|
t.Error("two SM2MQV computations came out different")
|
||||||
|
}
|
||||||
|
|
||||||
|
bobKey, err := ecdh.P256().SM2SharedKey(true, 48, bobSecret, bobSKey.PublicKey(), aliceSKey.PublicKey(), []byte("Bob"), []byte("Alice"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aliceKey, err := ecdh.P256().SM2SharedKey(false, 48, aliceSecret, aliceSKey.PublicKey(), bobSKey.PublicKey(), []byte("Alice"), []byte("Bob"))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(bobKey, aliceKey) {
|
||||||
|
t.Error("two SM2SharedKey computations came out different")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var vectors = []struct {
|
||||||
|
LocalStaticPriv, LocalEphemeralPriv string
|
||||||
|
RemoteStaticPriv, RemoteEphemeralPriv string
|
||||||
|
SharedSecret, Key string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"e04c3fd77408b56a648ad439f673511a2ae248def3bab26bdfc9cdbd0ae9607e",
|
||||||
|
"6fe0bac5b09d3ab10f724638811c34464790520e4604e71e6cb0e5310623b5b1",
|
||||||
|
"7a1136f60d2c5531447e5a3093078c2a505abf74f33aefed927ac0a5b27e7dd7",
|
||||||
|
"d0233bdbb0b8a7bfe1aab66132ef06fc4efaedd5d5000692bc21185242a31f6f",
|
||||||
|
"046ab5c9709277837cedc515730d04751ef81c71e81e0e52357a98cf41796ab560508da6e858b40c6264f17943037434174284a847f32c4f54104a98af5148d89f",
|
||||||
|
"1ad809ebc56ddda532020c352e1e60b121ebeb7b4e632db4dd90a362cf844f8bba85140e30984ddb581199bf5a9dda22",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cb5ac204b38d0e5c9fc38a467075986754018f7dbb7cbbc5b4c78d56a88a8ad8",
|
||||||
|
"1681a66c02b67fdadfc53cba9b417b9499d0159435c86bb8760c3a03ae157539",
|
||||||
|
"4f54b10e0d8e9e2fe5cc79893e37fd0fd990762d1372197ed92dde464b2773ef",
|
||||||
|
"a2fe43dea141e9acc88226eaba8908ad17e81376c92102cb8186e8fef61a8700",
|
||||||
|
"04677d055355a1dcc9de4df00d3a80b6daa76bdf54ff7e0a3a6359fcd0c6f1e4b4697fffc41bbbcc3a28ea3aa1c6c380d1e92f142233afa4b430d02ab4cebc43b2",
|
||||||
|
"7a103ae61a30ed9df573a5febb35a9609cbed5681bcb98a8545351bf7d6824cc4635df5203712ea506e2e3c4ec9b12e7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ee690a34a779ab48227a2f68b062a80f92e26d82835608dd01b7452f1e4fb296",
|
||||||
|
"2046c6cee085665e9f3abeba41fd38e17a26c08f2f5e8f0e1007afc0bf6a2a5d",
|
||||||
|
"8ef49ea427b13cc31151e1c96ae8a48cb7919063f2d342560fb7eaaffb93d8fe",
|
||||||
|
"9baf8d602e43fbae83fedb7368f98c969d378b8a647318f8cafb265296ae37de",
|
||||||
|
"04f7e9f1447968b284ff43548fcec3752063ea386b48bfabb9baf2f9c1caa05c2fb12c2cca37326ce27e68f8cc6414c2554895519c28da1ca21e61890d0bc525c4",
|
||||||
|
"b18e78e5072f301399dc1f4baf2956c0ed2d5f52f19abb1705131b0865b079031259ee6c629b4faed528bcfa1c5d2cbc",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSM2SharedKeyVectors(t *testing.T) {
|
||||||
|
initiator := []byte("Alice")
|
||||||
|
responder := []byte("Bob")
|
||||||
|
kenLen := 48
|
||||||
|
|
||||||
|
for i, v := range vectors {
|
||||||
|
aliceSKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.LocalStaticPriv))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
aliceEKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.LocalEphemeralPriv))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
bobSKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.RemoteStaticPriv))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
bobEKey, err := ecdh.P256().NewPrivateKey(hexDecode(t, v.RemoteEphemeralPriv))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobSecret, err := ecdh.P256().SM2MQV(bobSKey, bobEKey, aliceSKey.PublicKey(), aliceEKey.PublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aliceSecret, err := ecdh.P256().SM2MQV(aliceSKey, aliceEKey, bobSKey.PublicKey(), bobEKey.PublicKey())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !aliceSecret.Equal(bobSecret) {
|
||||||
|
t.Error("two SM2MQV computations came out different")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(aliceSecret.Bytes(), hexDecode(t, v.SharedSecret)) {
|
||||||
|
t.Errorf("%v shared secret is not expected.", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
bobKey, err := ecdh.P256().SM2SharedKey(true, kenLen, bobSecret, bobSKey.PublicKey(), aliceSKey.PublicKey(), responder, initiator)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
aliceKey, err := ecdh.P256().SM2SharedKey(false, kenLen, aliceSecret, aliceSKey.PublicKey(), bobSKey.PublicKey(), initiator, responder)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(bobKey, aliceKey) {
|
||||||
|
t.Error("two SM2SharedKey computations came out different")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(bobKey, hexDecode(t, v.Key)) {
|
||||||
|
t.Errorf("%v keying data is not expected.", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type countingReader struct {
|
type countingReader struct {
|
||||||
r io.Reader
|
r io.Reader
|
||||||
n int
|
n int
|
||||||
|
@ -3,18 +3,24 @@ package ecdh
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
|
|
||||||
"github.com/emmansun/gmsm/internal/randutil"
|
"github.com/emmansun/gmsm/internal/randutil"
|
||||||
sm2ec "github.com/emmansun/gmsm/internal/sm2ec"
|
sm2ec "github.com/emmansun/gmsm/internal/sm2ec"
|
||||||
"github.com/emmansun/gmsm/internal/subtle"
|
"github.com/emmansun/gmsm/internal/subtle"
|
||||||
|
"github.com/emmansun/gmsm/kdf"
|
||||||
|
"github.com/emmansun/gmsm/sm3"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sm2Curve struct {
|
type sm2Curve struct {
|
||||||
name string
|
name string
|
||||||
newPoint func() *sm2ec.SM2P256Point
|
newPoint func() *sm2ec.SM2P256Point
|
||||||
scalarOrder []byte
|
scalarOrder []byte
|
||||||
|
constantA []byte
|
||||||
|
constantB []byte
|
||||||
|
generator []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sm2Curve) String() string {
|
func (c *sm2Curve) String() string {
|
||||||
@ -107,6 +113,91 @@ func (c *sm2Curve) ECDH(local *PrivateKey, remote *PublicKey) ([]byte, error) {
|
|||||||
return p.BytesX()
|
return p.BytesX()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *sm2Curve) sm2avf(secret *PublicKey) []byte {
|
||||||
|
bytes := secret.publicKey[1:33]
|
||||||
|
var result [32]byte
|
||||||
|
copy(result[16:], bytes[16:])
|
||||||
|
result[16] = (result[16] & 0x7f) | 0x80
|
||||||
|
|
||||||
|
return result[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *sm2Curve) SM2MQV(sLocal, eLocal *PrivateKey, sRemote, eRemote *PublicKey) (*PublicKey, error) {
|
||||||
|
// implicitSig: (sLocal + avf(eLocal.Pub) * ePriv) mod N
|
||||||
|
x2 := c.sm2avf(eLocal.PublicKey())
|
||||||
|
t, err := sm2ec.ImplicitSig(sLocal.privateKey, eLocal.privateKey, x2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// new base point: peerPub + [x1](peerSecret)
|
||||||
|
x1 := c.sm2avf(eRemote)
|
||||||
|
p2, err := c.newPoint().SetBytes(eRemote.publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := p2.ScalarMult(p2, x1); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p1, err := c.newPoint().SetBytes(sRemote.publicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p2.Add(p1, p2)
|
||||||
|
|
||||||
|
if _, err := p2.ScalarMult(p2, t); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.NewPublicKey(p2.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *sm2Curve) SM2SharedKey(isResponder bool, kenLen int, uv, sPub, sRemote *PublicKey, uid []byte, remoteUID []byte) ([]byte, error) {
|
||||||
|
var buffer [128]byte
|
||||||
|
copy(buffer[:], uv.publicKey[1:])
|
||||||
|
peerZ, err := c.sm2za(sm3.New(), sRemote, remoteUID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
z, err := c.sm2za(sm3.New(), sPub, uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isResponder {
|
||||||
|
copy(buffer[64:], peerZ)
|
||||||
|
copy(buffer[96:], z)
|
||||||
|
} else {
|
||||||
|
copy(buffer[64:], z)
|
||||||
|
copy(buffer[96:], peerZ)
|
||||||
|
}
|
||||||
|
|
||||||
|
return kdf.Kdf(sm3.New(), buffer[:], kenLen), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultUID = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
|
||||||
|
|
||||||
|
// CalculateZA ZA = H256(ENTLA || IDA || a || b || xG || yG || xA || yA).
|
||||||
|
// Compliance with GB/T 32918.2-2016 5.5
|
||||||
|
func (c *sm2Curve) sm2za(md hash.Hash, pub *PublicKey, uid []byte) ([]byte, error) {
|
||||||
|
if len(uid) == 0 {
|
||||||
|
uid = defaultUID
|
||||||
|
}
|
||||||
|
uidLen := len(uid)
|
||||||
|
if uidLen >= 0x2000 {
|
||||||
|
return nil, errors.New("ecdh: the uid is too long")
|
||||||
|
}
|
||||||
|
entla := uint16(uidLen) << 3
|
||||||
|
md.Write([]byte{byte(entla >> 8), byte(entla)})
|
||||||
|
if uidLen > 0 {
|
||||||
|
md.Write(uid)
|
||||||
|
}
|
||||||
|
md.Write(c.constantA)
|
||||||
|
md.Write(c.constantB)
|
||||||
|
md.Write(c.generator)
|
||||||
|
md.Write(pub.publicKey[1:])
|
||||||
|
|
||||||
|
return md.Sum(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
// P256 returns a Curve which implements SM2, also known as sm2p256v1
|
// P256 returns a Curve which implements SM2, also known as sm2p256v1
|
||||||
//
|
//
|
||||||
// Multiple invocations of this function will return the same value, so it can
|
// Multiple invocations of this function will return the same value, so it can
|
||||||
@ -117,9 +208,15 @@ var sm2P256 = &sm2Curve{
|
|||||||
name: "sm2p256v1",
|
name: "sm2p256v1",
|
||||||
newPoint: sm2ec.NewSM2P256Point,
|
newPoint: sm2ec.NewSM2P256Point,
|
||||||
scalarOrder: sm2P256Order,
|
scalarOrder: sm2P256Order,
|
||||||
|
generator: sm2Generator,
|
||||||
|
constantA: sm2ConstantA,
|
||||||
|
constantB: sm2ConstantB,
|
||||||
}
|
}
|
||||||
|
|
||||||
var sm2P256Order = []byte{0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b, 0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x23}
|
var sm2P256Order = []byte{0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b, 0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x23}
|
||||||
|
var sm2Generator = []byte{0x32, 0xc4, 0xae, 0x2c, 0x1f, 0x19, 0x81, 0x19, 0x5f, 0x99, 0x4, 0x46, 0x6a, 0x39, 0xc9, 0x94, 0x8f, 0xe3, 0xb, 0xbf, 0xf2, 0x66, 0xb, 0xe1, 0x71, 0x5a, 0x45, 0x89, 0x33, 0x4c, 0x74, 0xc7, 0xbc, 0x37, 0x36, 0xa2, 0xf4, 0xf6, 0x77, 0x9c, 0x59, 0xbd, 0xce, 0xe3, 0x6b, 0x69, 0x21, 0x53, 0xd0, 0xa9, 0x87, 0x7c, 0xc6, 0x2a, 0x47, 0x40, 0x2, 0xdf, 0x32, 0xe5, 0x21, 0x39, 0xf0, 0xa0}
|
||||||
|
var sm2ConstantA = []byte{0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}
|
||||||
|
var sm2ConstantB = []byte{0x28, 0xe9, 0xfa, 0x9e, 0x9d, 0x9f, 0x5e, 0x34, 0x4d, 0x5a, 0x9e, 0x4b, 0xcf, 0x65, 0x09, 0xa7, 0xf3, 0x97, 0x89, 0xf5, 0x15, 0xab, 0x8f, 0x92, 0xdd, 0xbc, 0xbd, 0x41, 0x4d, 0x94, 0x0e, 0x93}
|
||||||
|
|
||||||
// isLess returns whether a < b, where a and b are big-endian buffers of the
|
// isLess returns whether a < b, where a and b are big-endian buffers of the
|
||||||
// same length and shorter than 72 bytes.
|
// same length and shorter than 72 bytes.
|
||||||
|
4
go.mod
4
go.mod
@ -3,6 +3,6 @@ module github.com/emmansun/gmsm
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10
|
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
|
||||||
)
|
)
|
||||||
|
8
go.sum
8
go.sum
@ -1,11 +1,11 @@
|
|||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
1299
internal/sm2ec/fiat/sm2p256_order.go
Normal file
1299
internal/sm2ec/fiat/sm2p256_order.go
Normal file
File diff suppressed because it is too large
Load Diff
136
internal/sm2ec/fiat/sm2p256_order_test.go
Normal file
136
internal/sm2ec/fiat/sm2p256_order_test.go
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package fiat_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/internal/sm2ec/fiat"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ordN *big.Int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// n=115792089210356248756420345214020892766061623724957744567843809356293439045923
|
||||||
|
// p-n=188730266966446886577384576996245946076
|
||||||
|
ordN, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
|
||||||
|
}
|
||||||
|
|
||||||
|
var testValues = [20]string{
|
||||||
|
"e576e1aefe41c42a634a6937982dd8ea60654c4d406ef141018072b8a8ee10ff",
|
||||||
|
"374bf8d3ed1a35a109ccc73276e4fa3697d942eafcd514a82a985d0820f02645",
|
||||||
|
"d62fd995bdc9ed6d405cad6a5cd48e0b92b465c2c8fbb7b14cc86e16e6dba6e8",
|
||||||
|
"a8c28fe4b2c4abad3759ac3cb97c23eb0440273277f8d8be794eea0a2561357d",
|
||||||
|
"f3bcfff783d0eb4de34bffd0c6290f75381bf715a1bc2b02ffbb58cc794ef1b7",
|
||||||
|
"a08b119bb9bf49b2cda951de57df6e95f413a609aefa51eefa554a4906963942",
|
||||||
|
"1b767aabebdf28a447de4c37b18d8c86e431c70acbb6d05eab459180e3731075",
|
||||||
|
"40616625f9dd4e7c396106e539ed7891636acfb3ba7f80e72dc305b8cb2955d8",
|
||||||
|
"3246e27330be55dc574e97a9e0c5ab6a476bb2b5422e8c47b2248a40504fc8a0",
|
||||||
|
"aa54dec0a14ee69417186ff2711e59282d5badc3faa1528c4171e14baa525865",
|
||||||
|
"408817dd964bd439aec08c3ebda707dc8ff969d25aef0ec0ba6085bc8da6996f",
|
||||||
|
"99ed1792abdda9f0e43fd50c59a57b7f9c3c60d69c8046c71b67a1a71d9f7d55",
|
||||||
|
"455705f9823bd5ba6f58c2a4dbdf6f10a0de1947a82c2653b00833ea39e26b5d",
|
||||||
|
"b43fdba6043be8524bcc4cd6ab7d71534fcaf42869ab838e98608d5e9d801cf9",
|
||||||
|
"c97498821b3b4db41239d1a3d47d49754e5e6b7bb7ae21d4eb0826bd5c0aeed6",
|
||||||
|
"c0213f02d06c935b798594c9c3b4feaebea881205733a21484a48df4643fbde7",
|
||||||
|
"313c9f7129eb1a09c385dc755aab9d88fcab79a7e4deaca68dd08d93fd68d252",
|
||||||
|
"eb7b96f239402bd494dc258672cd4a1643ae9fe092ddaaca54f9e909548eaa90",
|
||||||
|
"24567a167761a040aed80ea4655616b5aae5a0548b2a2a39a99bd4a6d7791610",
|
||||||
|
"c79886c5cd9de1f2a0deee1c76cd8c38da7dcd401f59ec4bebbaf815006f2f71",
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateValues(t *testing.T) {
|
||||||
|
p, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
k, _ := rand.Int(rand.Reader, p)
|
||||||
|
if k.Sign() > 0 {
|
||||||
|
fmt.Printf("%v\n", hex.EncodeToString(k.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func p256OrderMulTest(t *testing.T, x, y, n *big.Int) {
|
||||||
|
var scalar1 [32]byte
|
||||||
|
var scalar2 [32]byte
|
||||||
|
var scalar [32]byte
|
||||||
|
x1 := new(big.Int).Mod(x, n)
|
||||||
|
y1 := new(big.Int).Mod(y, n)
|
||||||
|
ax := new(fiat.SM2P256OrderElement)
|
||||||
|
ay := new(fiat.SM2P256OrderElement)
|
||||||
|
res := new(fiat.SM2P256OrderElement)
|
||||||
|
x1.FillBytes(scalar1[:])
|
||||||
|
y1.FillBytes(scalar2[:])
|
||||||
|
_, err := ax.SetBytes(scalar1[:])
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(scalar1[:], ax.Bytes()) {
|
||||||
|
t.Errorf("x SetBytes/Bytes error, expected %v, got %v\n", hex.EncodeToString(scalar1[:]), hex.EncodeToString(ax.Bytes()))
|
||||||
|
}
|
||||||
|
_, err = ay.SetBytes(scalar2[:])
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(scalar2[:], ay.Bytes()) {
|
||||||
|
t.Errorf("y SetBytes/Bytes error, expected %v, got %v\n", hex.EncodeToString(scalar2[:]), hex.EncodeToString(ay.Bytes()))
|
||||||
|
}
|
||||||
|
res = res.Mul(ax, ay)
|
||||||
|
expected := new(big.Int).Mul(x1, y1)
|
||||||
|
expected = expected.Mod(expected, n)
|
||||||
|
expected.FillBytes(scalar[:])
|
||||||
|
if !bytes.Equal(res.Bytes(), scalar[:]) {
|
||||||
|
t.Errorf("expected %v, got %v\n", hex.EncodeToString(scalar[:]), hex.EncodeToString(res.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP256Mul(t *testing.T) {
|
||||||
|
for i := 0; i < 20; i += 2 {
|
||||||
|
x, _ := new(big.Int).SetString(testValues[i], 16)
|
||||||
|
y, _ := new(big.Int).SetString(testValues[i+1], 16)
|
||||||
|
p256OrderMulTest(t, x, y, ordN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP256Square(t *testing.T) {
|
||||||
|
var scalar [32]byte
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
x, _ := new(big.Int).SetString(testValues[i], 16)
|
||||||
|
ax := new(fiat.SM2P256OrderElement)
|
||||||
|
ax.SetBytes(x.Bytes())
|
||||||
|
res := new(fiat.SM2P256OrderElement)
|
||||||
|
res.Square(ax)
|
||||||
|
expected := new(big.Int).Mul(x, x)
|
||||||
|
expected = expected.Mod(expected, ordN)
|
||||||
|
expected.FillBytes(scalar[:])
|
||||||
|
if !bytes.Equal(res.Bytes(), scalar[:]) {
|
||||||
|
t.Errorf("expected %v, got %v\n", hex.EncodeToString(scalar[:]), hex.EncodeToString(res.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestP256Add(t *testing.T) {
|
||||||
|
var scalar [32]byte
|
||||||
|
for i := 0; i < 20; i += 2 {
|
||||||
|
x, _ := new(big.Int).SetString(testValues[i], 16)
|
||||||
|
y, _ := new(big.Int).SetString(testValues[i+1], 16)
|
||||||
|
expected := new(big.Int).Add(x, y)
|
||||||
|
expected = expected.Mod(expected, ordN)
|
||||||
|
expected.FillBytes(scalar[:])
|
||||||
|
|
||||||
|
ax := new(fiat.SM2P256OrderElement)
|
||||||
|
ax.SetBytes(x.Bytes())
|
||||||
|
|
||||||
|
ay := new(fiat.SM2P256OrderElement)
|
||||||
|
ay.SetBytes(y.Bytes())
|
||||||
|
|
||||||
|
res := new(fiat.SM2P256OrderElement)
|
||||||
|
res.Add(ax, ay)
|
||||||
|
|
||||||
|
if !bytes.Equal(res.Bytes(), scalar[:]) {
|
||||||
|
t.Errorf("expected %v, got %v\n", hex.EncodeToString(scalar[:]), hex.EncodeToString(res.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,13 @@ func p256OrdMul(res, in1, in2 *p256OrdElement)
|
|||||||
//go:noescape
|
//go:noescape
|
||||||
func p256OrdSqr(res, in *p256OrdElement, n int)
|
func p256OrdSqr(res, in *p256OrdElement, n int)
|
||||||
|
|
||||||
|
// This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is
|
||||||
|
// the order of the scalar field. Elements in the Montgomery domain take the
|
||||||
|
// form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the
|
||||||
|
// domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x
|
||||||
|
// into the Montgomery domain.
|
||||||
|
var RR = &p256OrdElement{0x901192af7c114f20, 0x3464504ade6fa2fa, 0x620fc84c3affe0d4, 0x1eb5e412a22b3d3b}
|
||||||
|
|
||||||
// P256OrdInverse, sets out to in⁻¹ mod org(G). If in is zero, out will be zero.
|
// P256OrdInverse, sets out to in⁻¹ mod org(G). If in is zero, out will be zero.
|
||||||
// n-2 =
|
// n-2 =
|
||||||
// 1111111111111111111111111111111011111111111111111111111111111111
|
// 1111111111111111111111111111111011111111111111111111111111111111
|
||||||
@ -43,13 +50,6 @@ func P256OrdInverse(k []byte) ([]byte, error) {
|
|||||||
t := new(p256OrdElement)
|
t := new(p256OrdElement)
|
||||||
m := new(p256OrdElement)
|
m := new(p256OrdElement)
|
||||||
|
|
||||||
// This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is
|
|
||||||
// the order of the scalar field. Elements in the Montgomery domain take the
|
|
||||||
// form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the
|
|
||||||
// domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x
|
|
||||||
// into the Montgomery domain.
|
|
||||||
RR := &p256OrdElement{0x901192af7c114f20, 0x3464504ade6fa2fa, 0x620fc84c3affe0d4, 0x1eb5e412a22b3d3b}
|
|
||||||
|
|
||||||
p256OrdMul(_1, x, RR) // _1 , 2^0
|
p256OrdMul(_1, x, RR) // _1 , 2^0
|
||||||
p256OrdSqr(m, _1, 1) // _10, 2^1
|
p256OrdSqr(m, _1, 1) // _10, 2^1
|
||||||
p256OrdMul(_11, m, _1) // _11, 2^1 + 2^0
|
p256OrdMul(_11, m, _1) // _11, 2^1 + 2^0
|
||||||
@ -98,12 +98,35 @@ func P256OrdInverse(k []byte) ([]byte, error) {
|
|||||||
p256OrdSqr(x, x, int(s))
|
p256OrdSqr(x, x, int(s))
|
||||||
p256OrdMul(x, x, muls[i])
|
p256OrdMul(x, x, muls[i])
|
||||||
}
|
}
|
||||||
|
return p256OrderFromMont(x), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// P256OrdMul multiplication modulo org(G).
|
||||||
|
func P256OrdMul(in1, in2 []byte) ([]byte, error) {
|
||||||
|
if len(in1) != 32 || len(in2) != 32 {
|
||||||
|
return nil, errors.New("invalid scalar length")
|
||||||
|
}
|
||||||
|
x1 := new(p256OrdElement)
|
||||||
|
p256OrdBigToLittle(x1, toElementArray(in1))
|
||||||
|
p256OrdMul(x1, x1, RR)
|
||||||
|
|
||||||
|
x2 := new(p256OrdElement)
|
||||||
|
p256OrdBigToLittle(x2, toElementArray(in2))
|
||||||
|
p256OrdMul(x2, x2, RR)
|
||||||
|
|
||||||
|
res := new(p256OrdElement)
|
||||||
|
p256OrdMul(res, x1, x2)
|
||||||
|
|
||||||
|
return p256OrderFromMont(res), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func p256OrderFromMont(in *p256OrdElement) []byte {
|
||||||
// Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1,
|
// Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1,
|
||||||
// converts a Montgomery value out of the domain.
|
// converts a Montgomery value out of the domain.
|
||||||
one := &p256OrdElement{1}
|
one := &p256OrdElement{1}
|
||||||
p256OrdMul(x, x, one)
|
p256OrdMul(in, in, one)
|
||||||
|
|
||||||
var xOut [32]byte
|
var xOut [32]byte
|
||||||
p256OrdLittleToBig(&xOut, x)
|
p256OrdLittleToBig(&xOut, in)
|
||||||
return xOut[:], nil
|
return xOut[:]
|
||||||
}
|
}
|
@ -1,6 +1,3 @@
|
|||||||
//go:build (amd64 && !generic) || (arm64 && !generic)
|
|
||||||
// +build amd64,!generic arm64,!generic
|
|
||||||
|
|
||||||
package sm2ec_test
|
package sm2ec_test
|
||||||
|
|
||||||
import (
|
import (
|
@ -74,6 +74,10 @@ func TestSM2P256MontgomeryDomainN(t *testing.T) {
|
|||||||
in string
|
in string
|
||||||
out string
|
out string
|
||||||
}{
|
}{
|
||||||
|
{ // One
|
||||||
|
"01",
|
||||||
|
"010000000000000000000000008dfc2094de39fad4ac440bf6c62abedd",
|
||||||
|
},
|
||||||
{ // R
|
{ // R
|
||||||
"010000000000000000000000000000000000000000000000000000000000000000",
|
"010000000000000000000000000000000000000000000000000000000000000000",
|
||||||
"1eb5e412a22b3d3b620fc84c3affe0d43464504ade6fa2fa901192af7c114f20",
|
"1eb5e412a22b3d3b620fc84c3affe0d43464504ade6fa2fa901192af7c114f20",
|
||||||
|
78
internal/sm2ec/sm2p256_mqv.go
Normal file
78
internal/sm2ec/sm2p256_mqv.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package sm2ec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"math/bits"
|
||||||
|
)
|
||||||
|
|
||||||
|
var p256Order = [4]uint64{0x53bbf40939d54123, 0x7203df6b21c6052b,
|
||||||
|
0xffffffffffffffff, 0xfffffffeffffffff}
|
||||||
|
|
||||||
|
func fromBytes(bytes []byte) (*[4]uint64, error) {
|
||||||
|
if len(bytes) != 32 {
|
||||||
|
return nil, errors.New("invalid scalar length")
|
||||||
|
}
|
||||||
|
var t [4]uint64
|
||||||
|
t[0] = binary.BigEndian.Uint64(bytes[24:])
|
||||||
|
t[1] = binary.BigEndian.Uint64(bytes[16:])
|
||||||
|
t[2] = binary.BigEndian.Uint64(bytes[8:])
|
||||||
|
t[3] = binary.BigEndian.Uint64(bytes)
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBytes(t *[4]uint64) []byte {
|
||||||
|
var bytes [32]byte
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint64(bytes[:], t[3])
|
||||||
|
binary.BigEndian.PutUint64(bytes[8:], t[2])
|
||||||
|
binary.BigEndian.PutUint64(bytes[16:], t[1])
|
||||||
|
binary.BigEndian.PutUint64(bytes[24:], t[0])
|
||||||
|
|
||||||
|
return bytes[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// p256OrdAdd sets res = x + y.
|
||||||
|
func p256OrdAdd(res, x, y *[4]uint64) {
|
||||||
|
var c, b uint64
|
||||||
|
t1 := make([]uint64, 4)
|
||||||
|
t1[0], c = bits.Add64(x[0], y[0], 0)
|
||||||
|
t1[1], c = bits.Add64(x[1], y[1], c)
|
||||||
|
t1[2], c = bits.Add64(x[2], y[2], c)
|
||||||
|
t1[3], c = bits.Add64(x[3], y[3], c)
|
||||||
|
t2 := make([]uint64, 4)
|
||||||
|
t2[0], b = bits.Sub64(t1[0], p256Order[0], 0)
|
||||||
|
t2[1], b = bits.Sub64(t1[1], p256Order[1], b)
|
||||||
|
t2[2], b = bits.Sub64(t1[2], p256Order[2], b)
|
||||||
|
t2[3], b = bits.Sub64(t1[3], p256Order[3], b)
|
||||||
|
// Three options:
|
||||||
|
// - a+b < p
|
||||||
|
// then c is 0, b is 1, and t1 is correct
|
||||||
|
// - p <= a+b < 2^256
|
||||||
|
// then c is 0, b is 0, and t2 is correct
|
||||||
|
// - 2^256 <= a+b
|
||||||
|
// then c is 1, b is 1, and t2 is correct
|
||||||
|
t2Mask := (c ^ b) - 1
|
||||||
|
res[0] = (t1[0] & ^t2Mask) | (t2[0] & t2Mask)
|
||||||
|
res[1] = (t1[1] & ^t2Mask) | (t2[1] & t2Mask)
|
||||||
|
res[2] = (t1[2] & ^t2Mask) | (t2[2] & t2Mask)
|
||||||
|
res[3] = (t1[3] & ^t2Mask) | (t2[3] & t2Mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImplicitSig(sPriv, ePriv, t []byte) ([]byte, error) {
|
||||||
|
mulRes, err := P256OrdMul(ePriv, t)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
t1, err := fromBytes(mulRes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
t2, err := fromBytes(sPriv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var t3 [4]uint64
|
||||||
|
p256OrdAdd(&t3, t1, t2)
|
||||||
|
return toBytes(&t3), nil
|
||||||
|
}
|
48
internal/sm2ec/sm2p256_mqv_test.go
Normal file
48
internal/sm2ec/sm2p256_mqv_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package sm2ec_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/internal/sm2ec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func randomK(r io.Reader, ord *big.Int) (k *big.Int, err error) {
|
||||||
|
for {
|
||||||
|
k, err = rand.Int(r, ord)
|
||||||
|
if k.Sign() > 0 || err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImplicitSig(t *testing.T) {
|
||||||
|
n, _ := new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
|
||||||
|
sPriv, err := randomK(rand.Reader, n)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ePriv, err := randomK(rand.Reader, n)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
k, err := randomK(rand.Reader, n)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
res1, err := sm2ec.ImplicitSig(sPriv.Bytes(), ePriv.Bytes(), k.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
res2 := new(big.Int)
|
||||||
|
res2.Mul(ePriv, k)
|
||||||
|
res2.Add(res2, sPriv)
|
||||||
|
res2.Mod(res2, n)
|
||||||
|
if !bytes.Equal(res1, res2.Bytes()) {
|
||||||
|
t.Errorf("expected %s, got %s", hex.EncodeToString(res1), hex.EncodeToString(res2.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
128
internal/sm2ec/sm2p256_ord.go
Normal file
128
internal/sm2ec/sm2p256_ord.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
//go:build (!amd64 && !arm64) || generic
|
||||||
|
// +build !amd64,!arm64 generic
|
||||||
|
|
||||||
|
package sm2ec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/emmansun/gmsm/internal/sm2ec/fiat"
|
||||||
|
)
|
||||||
|
|
||||||
|
// P256OrdInverse, sets out to in⁻¹ mod org(G). If in is zero, out will be zero.
|
||||||
|
// n-2 =
|
||||||
|
// 1111111111111111111111111111111011111111111111111111111111111111
|
||||||
|
// 1111111111111111111111111111111111111111111111111111111111111111
|
||||||
|
// 0111001000000011110111110110101100100001110001100000010100101011
|
||||||
|
// 0101001110111011111101000000100100111001110101010100000100100001
|
||||||
|
//
|
||||||
|
func P256OrdInverse(k []byte) ([]byte, error) {
|
||||||
|
if len(k) != 32 {
|
||||||
|
return nil, errors.New("invalid scalar length")
|
||||||
|
}
|
||||||
|
x := new(fiat.SM2P256OrderElement)
|
||||||
|
_1 := new(fiat.SM2P256OrderElement)
|
||||||
|
_, err := _1.SetBytes(k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_11 := new(fiat.SM2P256OrderElement)
|
||||||
|
_101 := new(fiat.SM2P256OrderElement)
|
||||||
|
_111 := new(fiat.SM2P256OrderElement)
|
||||||
|
_1111 := new(fiat.SM2P256OrderElement)
|
||||||
|
_10101 := new(fiat.SM2P256OrderElement)
|
||||||
|
_101111 := new(fiat.SM2P256OrderElement)
|
||||||
|
t := new(fiat.SM2P256OrderElement)
|
||||||
|
m := new(fiat.SM2P256OrderElement)
|
||||||
|
|
||||||
|
m.Square(_1)
|
||||||
|
_11.Mul(m, _1)
|
||||||
|
_101.Mul(m, _11)
|
||||||
|
_111.Mul(m, _101)
|
||||||
|
x.Square(_101)
|
||||||
|
_1111.Mul(_101, x)
|
||||||
|
|
||||||
|
t.Square(x)
|
||||||
|
_10101.Mul(t, _1)
|
||||||
|
x.Square(_10101)
|
||||||
|
_101111.Mul(x, _101)
|
||||||
|
x.Mul(_10101, x)
|
||||||
|
t.Square(x)
|
||||||
|
t.Square(t)
|
||||||
|
|
||||||
|
m.Mul(t, m)
|
||||||
|
t.Mul(t, _11)
|
||||||
|
x.Square(t)
|
||||||
|
for i := 1; i < 8; i++ {
|
||||||
|
x.Square(x)
|
||||||
|
}
|
||||||
|
m.Mul(x, m)
|
||||||
|
x.Mul(x, t)
|
||||||
|
|
||||||
|
t.Square(x)
|
||||||
|
for i := 1; i < 16; i++ {
|
||||||
|
t.Square(t)
|
||||||
|
}
|
||||||
|
m.Mul(t, m)
|
||||||
|
t.Mul(t, x)
|
||||||
|
|
||||||
|
x.Square(m)
|
||||||
|
for i := 1; i < 32; i++ {
|
||||||
|
x.Square(x)
|
||||||
|
}
|
||||||
|
x.Mul(x, t)
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
x.Square(x)
|
||||||
|
}
|
||||||
|
x.Mul(x, t)
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
x.Square(x)
|
||||||
|
}
|
||||||
|
x.Mul(x, t)
|
||||||
|
|
||||||
|
sqrs := []uint8{
|
||||||
|
4, 3, 11, 5, 3, 5, 1,
|
||||||
|
3, 7, 5, 9, 7, 5, 5,
|
||||||
|
4, 5, 2, 2, 7, 3, 5,
|
||||||
|
5, 6, 2, 6, 3, 5,
|
||||||
|
}
|
||||||
|
muls := []*fiat.SM2P256OrderElement{
|
||||||
|
_111, _1, _1111, _1111, _101, _10101, _1,
|
||||||
|
_1, _111, _11, _101, _10101, _10101, _111,
|
||||||
|
_111, _1111, _11, _1, _1, _1, _111,
|
||||||
|
_111, _10101, _1, _1, _1, _1}
|
||||||
|
|
||||||
|
for i, s := range sqrs {
|
||||||
|
for j := 0; j < int(s); j++ {
|
||||||
|
x.Square(x)
|
||||||
|
}
|
||||||
|
x.Mul(x, muls[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return x.Bytes(), nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// P256OrdMul multiplication modulo org(G).
|
||||||
|
func P256OrdMul(in1, in2 []byte) ([]byte, error) {
|
||||||
|
if len(in1) != 32 || len(in2) != 32 {
|
||||||
|
return nil, errors.New("invalid scalar length")
|
||||||
|
}
|
||||||
|
ax := new(fiat.SM2P256OrderElement)
|
||||||
|
ay := new(fiat.SM2P256OrderElement)
|
||||||
|
res := new(fiat.SM2P256OrderElement)
|
||||||
|
|
||||||
|
_, err := ax.SetBytes(in1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = ay.SetBytes(in2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res = res.Mul(ax, ay)
|
||||||
|
return res.Bytes(), nil
|
||||||
|
}
|
@ -214,7 +214,14 @@ func (ke *KeyExchange) mqv() {
|
|||||||
ke.v.X, ke.v.Y = ke.privateKey.ScalarMult(x, y, t.Bytes())
|
ke.v.X, ke.v.Y = ke.privateKey.ScalarMult(x, y, t.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func respondKeyExchange(ke *KeyExchange, r *big.Int) (*ecdsa.PublicKey, []byte, error) {
|
func respondKeyExchange(ke *KeyExchange, rA *ecdsa.PublicKey, r *big.Int) (*ecdsa.PublicKey, []byte, error) {
|
||||||
|
if ke.peerPub == nil {
|
||||||
|
return nil, nil, errors.New("sm2: no peer public key given")
|
||||||
|
}
|
||||||
|
if !ke.privateKey.IsOnCurve(rA.X, rA.Y) {
|
||||||
|
return nil, nil, errors.New("sm2: invalid initiator's ephemeral public key")
|
||||||
|
}
|
||||||
|
ke.peerSecret = rA
|
||||||
// secret = RB = [r]G
|
// secret = RB = [r]G
|
||||||
ke.secret.X, ke.secret.Y = ke.privateKey.ScalarBaseMult(r.Bytes())
|
ke.secret.X, ke.secret.Y = ke.privateKey.ScalarBaseMult(r.Bytes())
|
||||||
ke.r = r
|
ke.r = r
|
||||||
@ -236,18 +243,11 @@ func respondKeyExchange(ke *KeyExchange, r *big.Int) (*ecdsa.PublicKey, []byte,
|
|||||||
//
|
//
|
||||||
// It will check if there are peer's public key and validate the peer's Ephemeral Public Key.
|
// It will check if there are peer's public key and validate the peer's Ephemeral Public Key.
|
||||||
func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*ecdsa.PublicKey, []byte, error) {
|
func (ke *KeyExchange) RepondKeyExchange(rand io.Reader, rA *ecdsa.PublicKey) (*ecdsa.PublicKey, []byte, error) {
|
||||||
if ke.peerPub == nil {
|
|
||||||
return nil, nil, errors.New("sm2: no peer public key given")
|
|
||||||
}
|
|
||||||
if !ke.privateKey.IsOnCurve(rA.X, rA.Y) {
|
|
||||||
return nil, nil, errors.New("sm2: invalid initiator's ephemeral public key")
|
|
||||||
}
|
|
||||||
ke.peerSecret = rA
|
|
||||||
r, err := randFieldElement(ke.privateKey, rand)
|
r, err := randFieldElement(ke.privateKey, rand)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return respondKeyExchange(ke, r)
|
return respondKeyExchange(ke, rA, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConfirmResponder for initiator's step A4-A10, returns keying data and optional signature.
|
// ConfirmResponder for initiator's step A4-A10, returns keying data and optional signature.
|
||||||
|
@ -1,22 +1,118 @@
|
|||||||
package sm2
|
package sm2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var vectors = []struct {
|
||||||
|
LocalStaticPriv, LocalEphemeralPriv string
|
||||||
|
RemoteStaticPriv, RemoteEphemeralPriv string
|
||||||
|
SharedSecret, Key string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
"e04c3fd77408b56a648ad439f673511a2ae248def3bab26bdfc9cdbd0ae9607e",
|
||||||
|
"6fe0bac5b09d3ab10f724638811c34464790520e4604e71e6cb0e5310623b5b1",
|
||||||
|
"7a1136f60d2c5531447e5a3093078c2a505abf74f33aefed927ac0a5b27e7dd7",
|
||||||
|
"d0233bdbb0b8a7bfe1aab66132ef06fc4efaedd5d5000692bc21185242a31f6f",
|
||||||
|
"046ab5c9709277837cedc515730d04751ef81c71e81e0e52357a98cf41796ab560508da6e858b40c6264f17943037434174284a847f32c4f54104a98af5148d89f",
|
||||||
|
"1ad809ebc56ddda532020c352e1e60b121ebeb7b4e632db4dd90a362cf844f8bba85140e30984ddb581199bf5a9dda22",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cb5ac204b38d0e5c9fc38a467075986754018f7dbb7cbbc5b4c78d56a88a8ad8",
|
||||||
|
"1681a66c02b67fdadfc53cba9b417b9499d0159435c86bb8760c3a03ae157539",
|
||||||
|
"4f54b10e0d8e9e2fe5cc79893e37fd0fd990762d1372197ed92dde464b2773ef",
|
||||||
|
"a2fe43dea141e9acc88226eaba8908ad17e81376c92102cb8186e8fef61a8700",
|
||||||
|
"04677d055355a1dcc9de4df00d3a80b6daa76bdf54ff7e0a3a6359fcd0c6f1e4b4697fffc41bbbcc3a28ea3aa1c6c380d1e92f142233afa4b430d02ab4cebc43b2",
|
||||||
|
"7a103ae61a30ed9df573a5febb35a9609cbed5681bcb98a8545351bf7d6824cc4635df5203712ea506e2e3c4ec9b12e7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ee690a34a779ab48227a2f68b062a80f92e26d82835608dd01b7452f1e4fb296",
|
||||||
|
"2046c6cee085665e9f3abeba41fd38e17a26c08f2f5e8f0e1007afc0bf6a2a5d",
|
||||||
|
"8ef49ea427b13cc31151e1c96ae8a48cb7919063f2d342560fb7eaaffb93d8fe",
|
||||||
|
"9baf8d602e43fbae83fedb7368f98c969d378b8a647318f8cafb265296ae37de",
|
||||||
|
"04f7e9f1447968b284ff43548fcec3752063ea386b48bfabb9baf2f9c1caa05c2fb12c2cca37326ce27e68f8cc6414c2554895519c28da1ca21e61890d0bc525c4",
|
||||||
|
"b18e78e5072f301399dc1f4baf2956c0ed2d5f52f19abb1705131b0865b079031259ee6c629b4faed528bcfa1c5d2cbc",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func hexDecode(t *testing.T, s string) []byte {
|
||||||
|
b, err := hex.DecodeString(s)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("invalid hex string:", s)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
func TestKeyExchangeSample(t *testing.T) {
|
func TestKeyExchangeSample(t *testing.T) {
|
||||||
priv1, _ := GenerateKey(rand.Reader)
|
initiatorUID := []byte("Alice")
|
||||||
priv2, _ := GenerateKey(rand.Reader)
|
responderUID := []byte("Bob")
|
||||||
initiator, err := NewKeyExchange(priv1, &priv2.PublicKey, []byte("Alice"), []byte("Bob"), 32, true)
|
kenLen := 48
|
||||||
|
|
||||||
|
for i, v := range vectors {
|
||||||
|
priv1 := new(PrivateKey)
|
||||||
|
priv1.D, _ = new(big.Int).SetString(v.LocalStaticPriv, 16)
|
||||||
|
priv1.Curve = P256()
|
||||||
|
priv1.X, priv1.Y = priv1.Curve.ScalarBaseMult(priv1.D.Bytes())
|
||||||
|
|
||||||
|
priv2 := new(PrivateKey)
|
||||||
|
priv2.D, _ = new(big.Int).SetString(v.RemoteStaticPriv, 16)
|
||||||
|
priv2.Curve = P256()
|
||||||
|
priv2.X, priv2.Y = priv1.Curve.ScalarBaseMult(priv2.D.Bytes())
|
||||||
|
|
||||||
|
initiator, err := NewKeyExchange(priv1, &priv2.PublicKey, initiatorUID, responderUID, kenLen, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
responder, err := NewKeyExchange(priv2, &priv1.PublicKey, []byte("Bob"), []byte("Alice"), 32, true)
|
responder, err := NewKeyExchange(priv2, &priv1.PublicKey, responderUID, initiatorUID, 48, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
initiator.Destroy()
|
||||||
|
responder.Destroy()
|
||||||
|
}()
|
||||||
|
rA, _ := new(big.Int).SetString(v.LocalEphemeralPriv, 16)
|
||||||
|
initKeyExchange(initiator, rA)
|
||||||
|
|
||||||
|
rB, _ := new(big.Int).SetString(v.RemoteEphemeralPriv, 16)
|
||||||
|
RB, s2, _ := respondKeyExchange(responder, initiator.secret, rB)
|
||||||
|
|
||||||
|
key1, s1, err := initiator.ConfirmResponder(RB, s2)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
key2, err := responder.ConfirmInitiator(s1)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(key1, key2) {
|
||||||
|
t.Errorf("got different key")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(key1, hexDecode(t, v.Key)) {
|
||||||
|
t.Errorf("case %v got unexpected keying data", i)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(elliptic.Marshal(initiator.v.Curve, initiator.v.X, initiator.v.Y), hexDecode(t, v.SharedSecret)) {
|
||||||
|
t.Errorf("case %v got unexpected shared key", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeyExchange(t *testing.T) {
|
||||||
|
priv1, _ := GenerateKey(rand.Reader)
|
||||||
|
priv2, _ := GenerateKey(rand.Reader)
|
||||||
|
initiator, err := NewKeyExchange(priv1, &priv2.PublicKey, []byte("Alice"), []byte("Bob"), 48, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
responder, err := NewKeyExchange(priv2, &priv1.PublicKey, []byte("Bob"), []byte("Alice"), 48, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -174,3 +174,21 @@ func (curve *sm2Curve) UnmarshalCompressed(data []byte) (x, y *big.Int) {
|
|||||||
}
|
}
|
||||||
return curve.pointToAffine(p)
|
return curve.pointToAffine(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Inverse, implements invertible interface, used by Sign()
|
||||||
|
func (curve *sm2Curve) Inverse(k *big.Int) *big.Int {
|
||||||
|
if k.Sign() < 0 {
|
||||||
|
// This should never happen.
|
||||||
|
k = new(big.Int).Neg(k)
|
||||||
|
}
|
||||||
|
if k.Cmp(curve.params.N) >= 0 {
|
||||||
|
// This should never happen.
|
||||||
|
k = new(big.Int).Mod(k, curve.params.N)
|
||||||
|
}
|
||||||
|
scalar := k.FillBytes(make([]byte, 32))
|
||||||
|
inverse, err := _sm2ec.P256OrdInverse(scalar)
|
||||||
|
if err != nil {
|
||||||
|
panic("sm2/elliptic: sm2 rejected normalized scalar")
|
||||||
|
}
|
||||||
|
return new(big.Int).SetBytes(inverse)
|
||||||
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
//go:build (amd64 && !generic) || (arm64 && !generic)
|
|
||||||
// +build amd64,!generic arm64,!generic
|
|
||||||
|
|
||||||
package sm2ec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
_sm2ec "github.com/emmansun/gmsm/internal/sm2ec"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Inverse, implements invertible interface, used by Sign()
|
|
||||||
func (curve *sm2Curve) Inverse(k *big.Int) *big.Int {
|
|
||||||
if k.Sign() < 0 {
|
|
||||||
// This should never happen.
|
|
||||||
k = new(big.Int).Neg(k)
|
|
||||||
}
|
|
||||||
if k.Cmp(curve.params.N) >= 0 {
|
|
||||||
// This should never happen.
|
|
||||||
k = new(big.Int).Mod(k, curve.params.N)
|
|
||||||
}
|
|
||||||
scalar := k.FillBytes(make([]byte, 32))
|
|
||||||
inverse, err := _sm2ec.P256OrdInverse(scalar)
|
|
||||||
if err != nil {
|
|
||||||
panic("sm2/elliptic: sm2 rejected normalized scalar")
|
|
||||||
}
|
|
||||||
return new(big.Int).SetBytes(inverse)
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user