init: v1.0.0
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
package sm2
|
||||
|
||||
// asn1.go implements the ASN.1 encoding of SM2 types in GB/T 35276-2017 信息安全技术 SM2密码算法使用规范.
|
||||
// For each type, use *.MarshalASN1 and *.UnmarshalASN1 to encode/decode.
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
|
||||
"xdx.jelly/xgcl/internal/tags"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 如果编译时指定了 -tags "gmt0028",则执行算法正确性检测。
|
||||
if tags.Gmt0028 {
|
||||
if !(Auditor{}).Correctness() {
|
||||
panic("SM2 Correctness check failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auditor 算法正确性检测
|
||||
type Auditor struct{}
|
||||
|
||||
func (a Auditor) Correctness() bool {
|
||||
return a.CheckSign() && a.CheckEnc() && a.CheckKeyExchange()
|
||||
}
|
||||
|
||||
func (a Auditor) CheckSign() bool {
|
||||
var signData = struct {
|
||||
e string
|
||||
d string
|
||||
pk string
|
||||
sig string
|
||||
k string
|
||||
}{
|
||||
"F0B43E94BA45ACCAACE692ED534382EB17E6AB5A19CE7B31F4486FDFC0D28640",
|
||||
"3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8",
|
||||
"09F9DF311E5421A150DD7D161E4BC5C672179FAD1833FC076BB08FF356F35020CCEA490CE26775A52DC6EA718CC1AA600AED05FBF35E084A6632F6072DA9AD13",
|
||||
"f5a03b0648d2c4630eeac513e1bb81a15944da3827d5b74143ac7eaceee720b3b1b6aa29df212fd8763182bc0d421ca1bb9038fd1f7f42d4840b69c485bbc1aa",
|
||||
"59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21",
|
||||
}
|
||||
|
||||
b, err := hex.DecodeString(signData.d)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
d := NewPrivateKey()
|
||||
d.SetBytes(b)
|
||||
|
||||
pk := NewPublicKey()
|
||||
b, err = hex.DecodeString(signData.pk)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
pk.SetBytes(b)
|
||||
|
||||
e, err := hex.DecodeString(signData.e)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
k, err := hex.DecodeString(signData.k)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
var sig *Signature
|
||||
if sig, err = Sign(e, k, d); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if b, err = hex.DecodeString(signData.sig); err != nil || bytes.Compare(sig.Bytes(), b) != 0 {
|
||||
return false
|
||||
}
|
||||
return Verify(e, pk, sig)
|
||||
}
|
||||
|
||||
func (a Auditor) CheckEnc() bool {
|
||||
var encData = struct {
|
||||
d string
|
||||
pk string
|
||||
k string
|
||||
cipher string
|
||||
msg string
|
||||
}{
|
||||
"81987CC90CF5057C2DCAA75D1FDDCA84B24862F0CAD73C7F67349AE699B92983",
|
||||
"A2C0BFFCC4B36A6064F88600C7171A67B293A03E9BBFA3C28EA2DD496D1A6EC701D29EA7C8D2AB9DC85CAA7F9E24A730CAEA8FF3670FAFD6B28D10F9531ECF50",
|
||||
"26D6163FA18603EE2F3DE8936544D5DF1255A2DBEBA63AFC0D833EC449D2CB45",
|
||||
"BF6CFCB8E6295DC22777376F8385C5D6AADD5E430D11E004246D6BEBF99EC5249CB9AB2F9AF688C77A1BDF9F3B0816A4EAB7F5DA22E5DACDC1C8F6E45499874E1FC32E35744161AA0FFA6C70FC811D3B66D4CACDA3C0996B54768C603C6B24E0C85CDDE8AD71A258B89DDB42DA900BCF4F18AB52D7841134CAC581D3CF7F58F7",
|
||||
"C353C68EF05C4B342B377DA055D909FB1FAA4255662F3BAB8DDB3535E40BC93B",
|
||||
}
|
||||
|
||||
b, err := hex.DecodeString(encData.d)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
d := NewPrivateKey()
|
||||
d.SetBytes(b)
|
||||
|
||||
pk := NewPublicKey()
|
||||
b, err = hex.DecodeString(encData.pk)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
pk.SetBytes(b)
|
||||
|
||||
msg, err := hex.DecodeString(encData.msg)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
k, err := hex.DecodeString(encData.k)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
var cipher *Cipher
|
||||
b, err = hex.DecodeString(encData.cipher)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if cipher, err = Encrypt(pk, msg, k); err != nil || bytes.Compare(b, cipher.Bytes()) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if b, err = Decrypt(d, cipher); err != nil || bytes.Compare(b, msg) != 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (a Auditor) CheckKeyExchange() bool {
|
||||
var keyExchangeData = struct {
|
||||
// d string
|
||||
// pk string
|
||||
// k string
|
||||
// cipher string
|
||||
// msg string
|
||||
}{
|
||||
// "81987CC90CF5057C2DCAA75D1FDDCA84B24862F0CAD73C7F67349AE699B92983",
|
||||
// "A2C0BFFCC4B36A6064F88600C7171A67B293A03E9BBFA3C28EA2DD496D1A6EC701D29EA7C8D2AB9DC85CAA7F9E24A730CAEA8FF3670FAFD6B28D10F9531ECF50",
|
||||
// "26D6163FA18603EE2F3DE8936544D5DF1255A2DBEBA63AFC0D833EC449D2CB45",
|
||||
// "BF6CFCB8E6295DC22777376F8385C5D6AADD5E430D11E004246D6BEBF99EC5249CB9AB2F9AF688C77A1BDF9F3B0816A4EAB7F5DA22E5DACDC1C8F6E45499874E1FC32E35744161AA0FFA6C70FC811D3B66D4CACDA3C0996B54768C603C6B24E0C85CDDE8AD71A258B89DDB42DA900BCF4F18AB52D7841134CAC581D3CF7F58F7",
|
||||
// "C353C68EF05C4B342B377DA055D909FB1FAA4255662F3BAB8DDB3535E40BC93B",
|
||||
}
|
||||
|
||||
_ = keyExchangeData
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 xdx. All Rights Reserved.
|
||||
// Created by xdx <xdx@xdx.jelly>.
|
||||
|
||||
// Package sm2 implements the GM/T 0003
|
||||
package sm2
|
||||
|
||||
// Package ec256 实现SM2里的需要用到的curve接口。
|
||||
// 可选tags
|
||||
// generic64 pure go code, 64bits
|
||||
// generic32 pure go code, 32bits
|
||||
// generic =generic64
|
||||
// amd64 with assamble code, in amd64 platform
|
||||
// arm64 with assamble code, in arm64 platform, for android and iphone
|
||||
|
||||
/************************************************************
|
||||
1、对公私钥、签名、密文等数据结构均使用MarshalBinary和UnmarshalBinary
|
||||
来和字节序列转化,格式满足GMT0018。
|
||||
MarshalBinary implements the encoding.BinaryMarshaler interface
|
||||
UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
if o.UnmarshalBinary return error, then o is unchanged
|
||||
*************************************************************/
|
||||
|
||||
// FIXME sm2曲线名改为 sm2p256v1
|
||||
@@ -0,0 +1,5 @@
|
||||
# go assemble vs. arm
|
||||
## CSEL
|
||||
iff cond, dst = r1, else dst = r2
|
||||
go: CSEL cond, r1, r2, dst
|
||||
arm: CSEL dst, r1, r2, cond
|
||||
@@ -0,0 +1,54 @@
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/internal"
|
||||
)
|
||||
|
||||
const debug = false
|
||||
|
||||
func printFuncName() {
|
||||
if debug {
|
||||
fmt.Println("Calling " + internal.GetFuncName())
|
||||
}
|
||||
}
|
||||
|
||||
var _ elliptic.Curve = SM2CurveParam{}
|
||||
|
||||
// SM2CurveParam CurveParams已经实现了crypto.Curve接口,增加一层把点乘等函数覆盖了。
|
||||
type SM2CurveParam struct {
|
||||
*elliptic.CurveParams
|
||||
}
|
||||
|
||||
type combinedMulter interface {
|
||||
CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
|
||||
}
|
||||
|
||||
// p = 2^256 - 2^224 - 2^96 + 2^64 -1
|
||||
var c256 = SM2CurveParam{CurveParams: &elliptic.CurveParams{
|
||||
Name: "Curve SM2",
|
||||
P: bigFromBase16("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"),
|
||||
N: bigFromBase16("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"),
|
||||
B: bigFromBase16("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"),
|
||||
Gx: bigFromBase16("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7"),
|
||||
Gy: bigFromBase16("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"),
|
||||
BitSize: 256},
|
||||
}
|
||||
|
||||
var Curve256 = c256
|
||||
|
||||
// EC256 returns the sm2-curve
|
||||
func EC256() elliptic.Curve {
|
||||
return c256
|
||||
}
|
||||
|
||||
func CurveSM2() elliptic.Curve {
|
||||
return c256
|
||||
}
|
||||
|
||||
func (SM2CurveParam) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
|
||||
return CombinedMult(bigX, bigY, baseScalar, scalar)
|
||||
}
|
||||
@@ -0,0 +1,814 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file contains the Go wrapper for the constant-time, 64-bit assembly
|
||||
// implementation of P256. The optimizations performed here are described in
|
||||
// detail in:
|
||||
// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
|
||||
// 256-bit primes"
|
||||
// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x
|
||||
// https://eprint.iacr.org/2013/816.pdf
|
||||
|
||||
//go:build (arm64 || amd64) && !generic && !generic32 && !generic64
|
||||
// +build arm64 amd64
|
||||
// +build !generic
|
||||
// +build !generic32
|
||||
// +build !generic64
|
||||
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
const (
|
||||
// montgomery of one: 1*R mod p
|
||||
montOne0 = 0x0000000000000001
|
||||
montOne1 = 0x00000000ffffffff
|
||||
montOne2 = 0x0000000000000000
|
||||
montOne3 = 0x0000000100000000
|
||||
|
||||
// montgomery of base point:
|
||||
montBaseX0 = 0x61328990f418029e
|
||||
montBaseX1 = 0x3e7981eddca6c050
|
||||
montBaseX2 = 0xd6a1ed99ac24c3c3
|
||||
montBaseX3 = 0x91167a5ee1c13b05
|
||||
|
||||
montBaseY0 = 0xc1354e593c2d0ddd
|
||||
montBaseY1 = 0xc1f5e5788d3295fa
|
||||
montBaseY2 = 0x8d4cfb066e2a48f8
|
||||
montBaseY3 = 0x63cd65d481d735bd
|
||||
|
||||
// R*R mod n
|
||||
rrModN0 = 0x901192af7c114f20
|
||||
rrModN1 = 0x3464504ade6fa2fa
|
||||
rrModN2 = 0x620fc84c3affe0d4
|
||||
rrModN3 = 0x1eb5e412a22b3d3b
|
||||
|
||||
// R*R mod p
|
||||
rrModP0 = 0x0000000200000003
|
||||
rrModP1 = 0x00000002ffffffff
|
||||
rrModP2 = 0x0000000100000001
|
||||
rrModP3 = 0x0000000400000002
|
||||
)
|
||||
|
||||
// c256Point Jacobian represent of a point with x,y,z in Montgomery domain
|
||||
type c256Point struct {
|
||||
xyz [12]uint64
|
||||
}
|
||||
|
||||
var (
|
||||
c256Precomputed *[43][32 * 8]uint64
|
||||
)
|
||||
|
||||
func init() {
|
||||
initTable()
|
||||
}
|
||||
|
||||
func (curve SM2CurveParam) Params() *elliptic.CurveParams {
|
||||
return curve.CurveParams
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
// func c256Add(res, in1, in2 []uint64)
|
||||
|
||||
// Functions implemented in c256_asm_*64.s
|
||||
// Montgomery multiplication modulo P256
|
||||
//
|
||||
//go:noescape
|
||||
func c256Mul(res, in1, in2 []uint64)
|
||||
|
||||
// Montgomery square modulo P256, repeated n times (n >= 1)
|
||||
//
|
||||
//go:noescape
|
||||
func c256Sqr(res, in []uint64, n int)
|
||||
|
||||
// Montgomery multiplication by 1, montMul(in, 1)
|
||||
//
|
||||
//go:noescape
|
||||
func c256FromMont(res, in []uint64)
|
||||
|
||||
// iff cond != 0 val <- -val
|
||||
//
|
||||
//go:noescape
|
||||
func c256NegCond(val []uint64, cond int)
|
||||
|
||||
// if cond == 0 res <- b; else res <- a
|
||||
//
|
||||
//go:noescape
|
||||
func c256MovCond(res, a, b []uint64, cond int)
|
||||
|
||||
// Endianness swap, 大端表示的32字节转4个小端表示的uint64
|
||||
//
|
||||
//go:noescape
|
||||
func c256BigToLittle(res []uint64, in []byte)
|
||||
|
||||
//go:noescape
|
||||
func c256LittleToBig(res []byte, in []uint64)
|
||||
|
||||
// Constant time table access
|
||||
// idx = 0, returns infinity. idx = i > 0, returns table[i-1].
|
||||
//
|
||||
//go:noescape
|
||||
func c256Select(point, table []uint64, idx int)
|
||||
|
||||
//go:noescape
|
||||
func c256SelectBase(point, table []uint64, idx int)
|
||||
|
||||
// Montgomery multiplication modulo Ord(G)
|
||||
//
|
||||
//go:noescape
|
||||
func c256OrdMul(res, in1, in2 []uint64)
|
||||
|
||||
// Montgomery square modulo Ord(G), repeated n times
|
||||
//
|
||||
//go:noescape
|
||||
func c256OrdSqr(res, in []uint64, n int)
|
||||
|
||||
// Point add with in2 being affine point
|
||||
// If sign == 1 -> in2 = -in2
|
||||
// If sel == 0 -> res = in1
|
||||
// if zero == 0 -> res = in2
|
||||
//
|
||||
//go:noescape
|
||||
func c256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int)
|
||||
|
||||
// Point add. Returns one if the two input points were equal and zero
|
||||
// otherwise. (Note that, due to the way that the equations work out, some
|
||||
// representations of ∞ are considered equal to everything by this function.)
|
||||
//
|
||||
//go:noescape
|
||||
func c256PointAddAsm(res, in1, in2 []uint64) int
|
||||
|
||||
// Point double
|
||||
//
|
||||
//go:noescape
|
||||
func c256PointDoubleAsm(res, in []uint64)
|
||||
|
||||
func c256ToMont(res, in []uint64) {
|
||||
c256Mul(res, in, rr)
|
||||
}
|
||||
|
||||
// in: k = k0 mod N
|
||||
// out: k0^{-1} mod N
|
||||
// use montgomery power: k -> k*R -> k^{N-2}*R -> k^{N-2}
|
||||
// Done - FIXME, need improve
|
||||
func (curve SM2CurveParam) Inverse(k *big.Int) *big.Int {
|
||||
|
||||
if k.Sign() < 0 {
|
||||
// This should never happen.
|
||||
k = new(big.Int).Neg(k)
|
||||
}
|
||||
|
||||
if k.Cmp(c256.N) >= 0 {
|
||||
// This should never happen.
|
||||
k = new(big.Int).Mod(k, c256.N)
|
||||
}
|
||||
|
||||
// table will store precomputed powers of x.
|
||||
var table [4 * 10]uint64
|
||||
var (
|
||||
_1 = table[4*0 : 4*1] // 1
|
||||
_11 = table[4*1 : 4*2] // 3
|
||||
_101 = table[4*2 : 4*3] // 5
|
||||
_111 = table[4*3 : 4*4] // 7
|
||||
_1111 = table[4*4 : 4*5] // 15
|
||||
_10101 = table[4*5 : 4*6] // 21
|
||||
_101111 = table[4*6 : 4*7] // 47
|
||||
x = table[4*7 : 4*8]
|
||||
t = table[4*8 : 4*9]
|
||||
s = table[4*9 : 4*10]
|
||||
)
|
||||
|
||||
fromBig(x[:], k)
|
||||
// This code operates in the Montgomery domain where R = 2^256 mod n
|
||||
// and n is the order of the scalar field. (See initP256 for the
|
||||
// value.) Elements in the Montgomery domain take the form a×R and
|
||||
// multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
|
||||
// is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
|
||||
// i.e. converts x into the Montgomery domain.
|
||||
// Window values borrowed from https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion
|
||||
RR := []uint64{rrModN0, rrModN1, rrModN2, rrModN3} // sm2-p256
|
||||
|
||||
// FIXME: the ladder need improve
|
||||
// SM2-p256:
|
||||
// N-2 = 0xfffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54121
|
||||
c256OrdMul(_1, x, RR) // _1
|
||||
c256OrdSqr(x, _1, 1) // _10 x=10
|
||||
c256OrdMul(_11, x, _1) // _11
|
||||
c256OrdMul(_101, x, _11) // _101
|
||||
c256OrdMul(_111, x, _101) // _111
|
||||
c256OrdSqr(x, _101, 1) // _1010 -- x = _1010
|
||||
c256OrdMul(_1111, _101, x) // _1111
|
||||
|
||||
c256OrdSqr(t, x, 1) // _10100 -- t=_10100
|
||||
c256OrdMul(_10101, t, _1) // _10101
|
||||
c256OrdSqr(x, _10101, 1) // _101010 -- x=_101010
|
||||
c256OrdMul(_101111, _101, x) // _101111
|
||||
c256OrdMul(x, _10101, x) // _111111 = x6 -- x=x6
|
||||
c256OrdSqr(s, x, 1) // x = _1111110
|
||||
c256OrdMul(s, s, _1) // x = x7
|
||||
c256OrdSqr(x, s, 1) // x = _11111110 = 0xfe
|
||||
c256OrdMul(s, x, _1) // s = x8 = 0xff
|
||||
c256OrdSqr(t, s, 8) // t=_ff00
|
||||
c256OrdMul(x, t, x) // x = fffe
|
||||
c256OrdMul(s, t, s) // s = _ffff
|
||||
c256OrdSqr(t, s, 16) // t=_ffff0000
|
||||
c256OrdMul(x, t, x) // x = fffffffe
|
||||
c256OrdMul(t, x, _1) // t = ffffffff
|
||||
|
||||
c256OrdSqr(x, x, 32) // x=_fffffffe00000000
|
||||
c256OrdMul(x, x, t) // x=_fffffffeffffffff
|
||||
c256OrdSqr(x, x, 32) // x = _fffffffeffffffff00000000
|
||||
c256OrdMul(x, x, t) // x= _fffffffeffffffffffffffff
|
||||
c256OrdSqr(x, x, 32) // x = _fffffffeffffffffffffffff00000000
|
||||
c256OrdMul(x, x, t) // x = _fffffffeffffffffffffffffffffffff
|
||||
|
||||
// 7203df6b21c6052b53bbf40939d54121 =
|
||||
// 01110010000000111101111101101011001000011100011000000101001010110101001110111011111101000000100100111001110101010100000100100001 =
|
||||
// 0111 001 00000001111 01111 101
|
||||
// 101 011 001 0000111 00011
|
||||
// 000000101 0010101 10101 00111 0111
|
||||
// 011 1111 01 0000001 001
|
||||
// 00111 00111 010101 01 000001
|
||||
// 001 00001
|
||||
|
||||
sqrs := []uint8{
|
||||
4, 3, 11, 5, 3,
|
||||
3, 3, 3, 7, 5,
|
||||
9, 7, 5, 5, 4,
|
||||
3, 4, 2, 7, 3,
|
||||
5, 5, 6, 2, 6,
|
||||
3, 5,
|
||||
}
|
||||
muls := [][]uint64{
|
||||
_111, _1, _1111, _1111, _101,
|
||||
_101, _11, _1, _111, _11,
|
||||
_101, _10101, _10101, _111, _111,
|
||||
_11, _1111, _1, _1, _1,
|
||||
_111, _111, _10101, _1, _1,
|
||||
_1, _1,
|
||||
}
|
||||
|
||||
for i, s := range sqrs {
|
||||
c256OrdSqr(x, x, int(s))
|
||||
c256OrdMul(x, x, muls[i])
|
||||
}
|
||||
|
||||
// Multiplying by one in the Montgomery domain converts a Montgomery
|
||||
// value out of the domain.
|
||||
one := []uint64{1, 0, 0, 0}
|
||||
c256OrdMul(x, x, one)
|
||||
|
||||
xOut := make([]byte, 32)
|
||||
c256LittleToBig(xOut, x)
|
||||
return new(big.Int).SetBytes(xOut)
|
||||
}
|
||||
|
||||
// fromBig converts a *big.Int into a format used by this code.
|
||||
func fromBig(out []uint64, big *big.Int) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
|
||||
for i, v := range big.Bits() {
|
||||
out[i] = uint64(v)
|
||||
}
|
||||
}
|
||||
|
||||
// c256GetScalar endian-swaps the big-endian scalar value from in and writes it
|
||||
// to out. If the scalar is equal or greater than the order of the group, it's
|
||||
// reduced modulo that order.
|
||||
func c256GetScalar(out []uint64, in []byte) {
|
||||
n := new(big.Int).SetBytes(in)
|
||||
|
||||
if n.Cmp(c256.N) >= 0 {
|
||||
n.Mod(n, c256.N)
|
||||
}
|
||||
fromBig(out, n)
|
||||
}
|
||||
|
||||
// c256Mul operates in a Montgomery domain with R = 2^256 mod p, where p is the
|
||||
// underlying field of the curve. (See initP256 for the value.) Thus rr here is
|
||||
// R×R mod p. See comment in Inverse about how this is used.
|
||||
var rr = []uint64{rrModP0, rrModP1, rrModP2, rrModP3} //// changed to sm2
|
||||
|
||||
// Note: for most time, in < p
|
||||
func maybeReduceModP(in *big.Int) *big.Int {
|
||||
if in.Cmp(c256.P) < 0 {
|
||||
return in
|
||||
}
|
||||
return new(big.Int).Mod(in, c256.P)
|
||||
}
|
||||
|
||||
func CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
|
||||
scalarReversed := make([]uint64, 4)
|
||||
var r1, r2 c256Point
|
||||
c256GetScalar(scalarReversed, baseScalar)
|
||||
r1IsInfinity := scalarIsZero(scalarReversed)
|
||||
r1.c256BaseMult(scalarReversed)
|
||||
|
||||
c256GetScalar(scalarReversed, scalar)
|
||||
r2IsInfinity := scalarIsZero(scalarReversed)
|
||||
r2.c256PointFromAffine(bigX, bigY)
|
||||
r2.c256ScalarMult(scalarReversed)
|
||||
|
||||
var sum, double c256Point
|
||||
pointsEqual := c256PointAddAsm(sum.xyz[:], r1.xyz[:], r2.xyz[:])
|
||||
c256PointDoubleAsm(double.xyz[:], r1.xyz[:])
|
||||
sum.CopyConditional(&double, pointsEqual)
|
||||
sum.CopyConditional(&r1, r2IsInfinity)
|
||||
sum.CopyConditional(&r2, r1IsInfinity)
|
||||
return sum.c256PointToAffine()
|
||||
}
|
||||
|
||||
func (curve SM2CurveParam) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
|
||||
// return curve.ScalarMult(curve.Gx, curve.Gy, scalar)
|
||||
scalarReversed := make([]uint64, 4)
|
||||
c256GetScalar(scalarReversed, scalar)
|
||||
|
||||
var r c256Point
|
||||
r.c256BaseMult(scalarReversed)
|
||||
return r.c256PointToAffine()
|
||||
}
|
||||
|
||||
func (curve SM2CurveParam) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
|
||||
scalarReversed := make([]uint64, 4)
|
||||
c256GetScalar(scalarReversed, scalar)
|
||||
|
||||
var r c256Point
|
||||
fromBig(r.xyz[0:4], maybeReduceModP(bigX))
|
||||
fromBig(r.xyz[4:8], maybeReduceModP(bigY))
|
||||
c256Mul(r.xyz[0:4], r.xyz[0:4], rr[:])
|
||||
c256Mul(r.xyz[4:8], r.xyz[4:8], rr[:])
|
||||
// This sets r2's Z value to 1, in the Montgomery domain.
|
||||
r.xyz[8] = montOne0
|
||||
r.xyz[9] = montOne1
|
||||
r.xyz[10] = montOne2
|
||||
r.xyz[11] = montOne3
|
||||
|
||||
r.c256ScalarMult(scalarReversed)
|
||||
return r.c256PointToAffine()
|
||||
}
|
||||
|
||||
func (curve SM2CurveParam) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) {
|
||||
var r1, r2 c256Point
|
||||
r1.c256PointFromAffine(x1, y1)
|
||||
r2.c256PointFromAffine(x2, y2)
|
||||
if true {
|
||||
// in most cases, the input two points are not equal.
|
||||
// omit the time-attack risk.
|
||||
if c256PointAddAsm(r1.xyz[:], r1.xyz[:], r2.xyz[:]) == 1 {
|
||||
c256PointDoubleAsm(r1.xyz[:], r2.xyz[:])
|
||||
}
|
||||
return r1.c256PointToAffine()
|
||||
} else {
|
||||
var res, double c256Point
|
||||
pointEqual := c256PointAddAsm(res.xyz[:], r1.xyz[:], r2.xyz[:])
|
||||
c256PointDoubleAsm(double.xyz[:], r1.xyz[:])
|
||||
c256MovCond(res.xyz[:], res.xyz[:], double.xyz[:], pointEqual)
|
||||
return res.c256PointToAffine()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (curve SM2CurveParam) Double(x1, y1 *big.Int) (x, y *big.Int) {
|
||||
var r c256Point
|
||||
r.c256PointFromAffine(x1, y1)
|
||||
c256PointDoubleAsm(r.xyz[:], r.xyz[:])
|
||||
return r.c256PointToAffine()
|
||||
}
|
||||
|
||||
// uint64IsZero returns 1 if x is zero and zero otherwise.
|
||||
func uint64IsZero(x uint64) int {
|
||||
x = ^x
|
||||
x &= x >> 32
|
||||
x &= x >> 16
|
||||
x &= x >> 8
|
||||
x &= x >> 4
|
||||
x &= x >> 2
|
||||
x &= x >> 1
|
||||
return int(x & 1)
|
||||
}
|
||||
|
||||
// scalarIsZero returns 1 if scalar represents the zero value, and zero
|
||||
// otherwise.
|
||||
func scalarIsZero(scalar []uint64) int {
|
||||
return uint64IsZero(scalar[0] | scalar[1] | scalar[2] | scalar[3])
|
||||
}
|
||||
|
||||
// c256PointFromAffine change affine point (x,y) to Montgemery domain
|
||||
// Jacobian point p
|
||||
func (p *c256Point) c256PointFromAffine(x, y *big.Int) {
|
||||
xyz := p.xyz[:]
|
||||
fromBig(xyz[0:4], maybeReduceModP(x))
|
||||
fromBig(xyz[4:8], maybeReduceModP(y))
|
||||
c256Mul(xyz[0:4], xyz[0:4], rr[:])
|
||||
c256Mul(xyz[4:8], xyz[4:8], rr[:])
|
||||
xyz[8] = montOne0
|
||||
xyz[9] = montOne1
|
||||
xyz[10] = montOne2
|
||||
xyz[11] = montOne3
|
||||
}
|
||||
|
||||
func (p *c256Point) c256PointToAffine() (x, y *big.Int) {
|
||||
zInv := make([]uint64, 4)
|
||||
zInvSq := make([]uint64, 4)
|
||||
c256Inverse(zInv, p.xyz[8:12])
|
||||
c256Sqr(zInvSq, zInv, 1)
|
||||
c256Mul(zInv, zInv, zInvSq)
|
||||
|
||||
c256Mul(zInvSq, p.xyz[0:4], zInvSq)
|
||||
c256Mul(zInv, p.xyz[4:8], zInv)
|
||||
|
||||
c256FromMont(zInvSq, zInvSq)
|
||||
c256FromMont(zInv, zInv)
|
||||
|
||||
xOut := make([]byte, 32)
|
||||
yOut := make([]byte, 32)
|
||||
c256LittleToBig(xOut, zInvSq)
|
||||
c256LittleToBig(yOut, zInv)
|
||||
|
||||
return new(big.Int).SetBytes(xOut), new(big.Int).SetBytes(yOut)
|
||||
}
|
||||
|
||||
// CopyConditional copies overwrites p with src if v == 1, and leaves p
|
||||
// unchanged if v == 0.
|
||||
func (p *c256Point) CopyConditional(src *c256Point, v int) {
|
||||
pMask := uint64(v) - 1
|
||||
srcMask := ^pMask
|
||||
|
||||
for i, n := range p.xyz {
|
||||
p.xyz[i] = (n & pMask) | (src.xyz[i] & srcMask)
|
||||
}
|
||||
}
|
||||
|
||||
// c256Inverse sets out to in^-1 mod p.
|
||||
// in*R => in^{-1} * R = mont_power(in*R, p-2)
|
||||
// Tested Done
|
||||
func c256Inverse(out, in []uint64) {
|
||||
if false {
|
||||
var stack [8 * 4]uint64
|
||||
p2 := stack[4*0 : 4*0+4]
|
||||
p4 := stack[4*1 : 4*1+4]
|
||||
p8 := stack[4*2 : 4*2+4]
|
||||
p16 := stack[4*3 : 4*3+4]
|
||||
p32 := stack[4*4 : 4*4+4]
|
||||
p28e := stack[4*5 : 4*6] // fffffffe
|
||||
p28c := stack[4*6 : 4*7] // fffffffc
|
||||
t := stack[4*7 : 4*8]
|
||||
|
||||
// 0xfffffffe ffffffff ffffffff ffffffff ffffffff 00000000 ffffffff fffffffd
|
||||
c256Sqr(p28e, in, 1) // 10*p
|
||||
c256Mul(p2, p28e, in) // 11*p
|
||||
|
||||
c256Sqr(t, p2, 2) //1100*p
|
||||
c256Mul(p4, t, p2) // f*p
|
||||
|
||||
c256Sqr(t, p4, 4) // f0*p
|
||||
c256Mul(p8, t, p4) // ff*p
|
||||
|
||||
c256Sqr(t, p8, 8) // ff00*p
|
||||
c256Mul(p16, t, p8) // ffff*p
|
||||
|
||||
c256Sqr(t, p16, 8) // ffff00*p
|
||||
c256Mul(t, t, p8) // ffffff*p
|
||||
c256Sqr(t, t, 4) // ffffff0*p
|
||||
c256Mul(t, t, p4) // fffffff*p
|
||||
c256Sqr(t, t, 2) // fffffff_(00)*p
|
||||
c256Mul(t, t, p2) // fffffff_(11)*p
|
||||
c256Sqr(p28c, t, 2) // fffffffc*p
|
||||
c256Mul(p28e, p28e, p28c) // fffffffe*p
|
||||
c256Mul(p32, p28e, in) // ffffffff*p
|
||||
|
||||
c256Sqr(t, p28e, 32)
|
||||
c256Mul(t, t, p32) // fffffffe ffffffff
|
||||
|
||||
c256Sqr(t, t, 32)
|
||||
c256Mul(t, t, p32) // fffffffe ffffffff ffffffff
|
||||
|
||||
c256Sqr(t, t, 32)
|
||||
c256Mul(t, t, p32) // fffffffe ffffffff ffffffff ffffffff
|
||||
|
||||
c256Sqr(t, t, 32)
|
||||
c256Mul(t, t, p32) // fffffffe ffffffff ffffffff ffffffff ffffffff
|
||||
|
||||
c256Sqr(t, t, 64)
|
||||
c256Mul(t, t, p32) // fffffffe ffffffff ffffffff ffffffff ffffffff 00000000 ffffffff
|
||||
|
||||
c256Sqr(t, t, 32)
|
||||
c256Mul(t, t, p28c) // fffffffe ffffffff ffffffff ffffffff ffffffff 00000000 fffffffe
|
||||
c256Mul(out, t, in) // fffffffe ffffffff ffffffff ffffffff ffffffff 00000000 fffffffd
|
||||
|
||||
// total 255 sqr + 16 mul
|
||||
} else {
|
||||
var stack [17 * 4]uint64
|
||||
_10 := stack[4*0 : 4*0+4]
|
||||
_11 := stack[4*1 : 4*1+4]
|
||||
_110 := stack[4*2 : 4*2+4]
|
||||
_111 := stack[4*3 : 4*3+4]
|
||||
_111000 := stack[4*4 : 4*4+4]
|
||||
_111111 := stack[4*5 : 4*6] // fffffffe
|
||||
_1111110 := stack[4*6 : 4*7] // fffffffc
|
||||
_1111111 := stack[4*7 : 4*8]
|
||||
x12 := stack[4*8 : 4*9] // _111111111111
|
||||
x24 := stack[4*9 : 4*10]
|
||||
x31 := stack[4*10 : 4*11]
|
||||
i39 := stack[4*11 : 4*12]
|
||||
i68 := stack[4*12 : 4*13]
|
||||
x62 := stack[4*13 : 4*14]
|
||||
i71 := stack[4*14 : 4*15]
|
||||
x64 := stack[4*15 : 4*16]
|
||||
i265 := stack[4*16 : 4*17]
|
||||
|
||||
c256Sqr(_10, in, 1) // _10 = 2 * 1
|
||||
c256Mul(_11, _10, in) // _11 = 1 + _10
|
||||
c256Sqr(_110, _11, 1) // _110 = 2 * _11
|
||||
c256Mul(_111, _110, in) // _111 = 1 + _110
|
||||
c256Sqr(_111000, _111, 3) // _111000 = _111 << 3
|
||||
c256Mul(_111111, _111, _111000) // _111111 = _111 + _111000
|
||||
c256Sqr(_1111110, _111111, 1) // _1111110 = 2 * _111111
|
||||
c256Mul(_1111111, _1111110, in) // _1111111 = 1 + _1111110
|
||||
c256Sqr(x12, _1111110, 5) // x12 = _1111110<<5 + _111111
|
||||
c256Mul(x12, x12, _111111)
|
||||
|
||||
c256Sqr(x24, x12, 12) // x24 = x12<<12 + x12
|
||||
c256Mul(x24, x24, x12)
|
||||
|
||||
c256Sqr(x31, x24, 7) // x31 = x24<<7 + _1111111
|
||||
c256Mul(x31, x31, _1111111)
|
||||
|
||||
c256Sqr(i39, x31, 2) // i39 = x31 << 2
|
||||
c256Sqr(i68, i39, 29) // i68 = i39 << 29
|
||||
c256Mul(x62, x31, i68) // x62 = x31 + i68
|
||||
c256Sqr(i71, i68, 2) // i71 = i68 << 2
|
||||
c256Mul(x64, i39, i71) // x64 = i39 + i71 + _11
|
||||
c256Mul(x64, x64, _11)
|
||||
c256Sqr(i265, i71, 32) // i265 = ((i71<<32+x64)<<64 + x64) << 94
|
||||
c256Mul(i265, i265, x64)
|
||||
c256Sqr(i265, i265, 64)
|
||||
c256Mul(i265, i265, x64)
|
||||
c256Sqr(i265, i265, 94)
|
||||
|
||||
c256Mul(i265, i265, x62) // return (x62+i265)<<2 + 1
|
||||
c256Sqr(i265, i265, 2)
|
||||
c256Mul(out, i265, in)
|
||||
|
||||
// 255 sqr + 14 mul
|
||||
}
|
||||
}
|
||||
|
||||
func (p *c256Point) c256StorePoint(r *[16 * 4 * 3]uint64, index int) {
|
||||
copy(r[index*12:], p.xyz[:])
|
||||
}
|
||||
|
||||
func boothW5(in uint) (int, int) {
|
||||
var s uint = ^((in >> 5) - 1)
|
||||
var d uint = (1 << 6) - in - 1
|
||||
d = (d & s) | (in & (^s))
|
||||
d = (d >> 1) + (d & 1)
|
||||
return int(d), int(s & 1)
|
||||
}
|
||||
|
||||
/*
|
||||
输入in 低7位有效 i0,i1,i2,...,i6
|
||||
*/
|
||||
func boothW6(in uint) (int, int) {
|
||||
if true {
|
||||
var s uint = ^((in >> 6) - 1)
|
||||
var d uint = (1 << 7) - in - 1
|
||||
d = (d & s) | (in & (^s))
|
||||
d = (d >> 1) + (d & 1)
|
||||
return int(d), int(s & 1)
|
||||
} else {
|
||||
//
|
||||
var sel, sign uint = 0, 0
|
||||
in = in & 0x7f // 只取低7位。其中最低位是前一窗口的最高位。
|
||||
|
||||
// sign 是第7位
|
||||
if (in >> 6) == 1 {
|
||||
sign = 1
|
||||
} else {
|
||||
sign = 0
|
||||
}
|
||||
|
||||
if sign == 1 {
|
||||
sel = in >> 1
|
||||
sel = (^sel) & 0x3f
|
||||
sel++
|
||||
if in&1 == 1 {
|
||||
sel--
|
||||
}
|
||||
} else {
|
||||
sel = (in + 1) >> 1
|
||||
}
|
||||
|
||||
return int(sel), int(sign)
|
||||
}
|
||||
}
|
||||
|
||||
func initTable() {
|
||||
/*
|
||||
c256Precomputed[i][j] = 2^{6i}*(jG) =
|
||||
0 1 2 31
|
||||
0 G [2]G [3]G [32]G
|
||||
1 [2^{6*1}]G [2^{6*1}][2]G
|
||||
2 [2^{6*2}]G [2^{6*2}][2]G
|
||||
·························
|
||||
42 [2^{6*42}]G
|
||||
|
||||
===========================================
|
||||
|
||||
1 2 3 ... 32
|
||||
64 64*2 64*3 64*32
|
||||
64*64 64*64*2 ...
|
||||
|
||||
43*32 =
|
||||
*/
|
||||
c256Precomputed = new([43][32 * 8]uint64)
|
||||
|
||||
basePoint := []uint64{
|
||||
montBaseX0, montBaseX1, montBaseX2, montBaseX3,
|
||||
montBaseY0, montBaseY1, montBaseY2, montBaseY3,
|
||||
montOne0, montOne1, montOne2, montOne3,
|
||||
}
|
||||
t1 := make([]uint64, 12)
|
||||
t2 := make([]uint64, 12)
|
||||
copy(t2, basePoint)
|
||||
|
||||
zInv := make([]uint64, 4)
|
||||
zInvSq := make([]uint64, 4)
|
||||
for j := 0; j < 32; j++ {
|
||||
copy(t1, t2)
|
||||
for i := 0; i < 43; i++ {
|
||||
// The window size is 6 so we need to double 6 times.
|
||||
if i != 0 {
|
||||
for k := 0; k < 6; k++ {
|
||||
c256PointDoubleAsm(t1, t1)
|
||||
}
|
||||
}
|
||||
// Convert the point to affine form. (Its values are
|
||||
// still in Montgomery form however.)
|
||||
c256Inverse(zInv, t1[8:12])
|
||||
c256Sqr(zInvSq, zInv, 1)
|
||||
c256Mul(zInv, zInv, zInvSq)
|
||||
|
||||
c256Mul(t1[:4], t1[:4], zInvSq)
|
||||
c256Mul(t1[4:8], t1[4:8], zInv)
|
||||
|
||||
copy(t1[8:12], basePoint[8:12])
|
||||
// Update the table entry
|
||||
copy(c256Precomputed[i][j*8:], t1[:8])
|
||||
}
|
||||
if j == 0 {
|
||||
c256PointDoubleAsm(t2, basePoint)
|
||||
} else {
|
||||
c256PointAddAsm(t2, t2, basePoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func c256SelectBaseOfGo(point, table []uint64, idx int) {
|
||||
if false {
|
||||
c256SelectBase(point, table, idx)
|
||||
return
|
||||
} else {
|
||||
if idx == 0 {
|
||||
return
|
||||
}
|
||||
copy(point[:8], table[8*(idx-1):])
|
||||
}
|
||||
}
|
||||
func (p *c256Point) c256BaseMult(scalar []uint64) {
|
||||
wvalue := (scalar[0] << 1) & 0x7f
|
||||
sel, sign := boothW6(uint(wvalue))
|
||||
c256SelectBase(p.xyz[0:8], c256Precomputed[0][0:], sel)
|
||||
c256NegCond(p.xyz[4:8], sign)
|
||||
|
||||
// (This is one, in the Montgomery domain.)
|
||||
p.xyz[8] = montOne0
|
||||
p.xyz[9] = montOne1
|
||||
p.xyz[10] = montOne2
|
||||
p.xyz[11] = montOne3
|
||||
|
||||
var t0 c256Point
|
||||
// (This is one, in the Montgomery domain.)
|
||||
t0.xyz[8] = montOne0
|
||||
t0.xyz[9] = montOne1
|
||||
t0.xyz[10] = montOne2
|
||||
t0.xyz[11] = montOne3
|
||||
|
||||
// 191 = 6*31 + 5
|
||||
index := uint(5)
|
||||
zero := sel
|
||||
|
||||
for i := 1; i < 43; i++ {
|
||||
if index < 192 {
|
||||
wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x7f
|
||||
} else {
|
||||
wvalue = (scalar[index/64] >> (index % 64)) & 0x7f
|
||||
}
|
||||
index += 6
|
||||
sel, sign = boothW6(uint(wvalue))
|
||||
c256SelectBase(t0.xyz[0:8], c256Precomputed[i][0:], sel)
|
||||
c256PointAddAffineAsm(p.xyz[0:12], p.xyz[0:12], t0.xyz[0:8], sign, sel, zero)
|
||||
zero |= sel
|
||||
}
|
||||
}
|
||||
|
||||
func (p *c256Point) c256ScalarMult(scalar []uint64) {
|
||||
// precomp is a table of precomputed points that stores powers of p
|
||||
// from p^1 to p^16.
|
||||
var precomp [16 * 4 * 3]uint64
|
||||
var t0, t1, t2, t3 c256Point
|
||||
|
||||
// Prepare the table
|
||||
p.c256StorePoint(&precomp, 0) // 1
|
||||
|
||||
c256PointDoubleAsm(t0.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(t1.xyz[:], t0.xyz[:])
|
||||
c256PointDoubleAsm(t2.xyz[:], t1.xyz[:])
|
||||
c256PointDoubleAsm(t3.xyz[:], t2.xyz[:])
|
||||
t0.c256StorePoint(&precomp, 1) // 2
|
||||
t1.c256StorePoint(&precomp, 3) // 4
|
||||
t2.c256StorePoint(&precomp, 7) // 8
|
||||
t3.c256StorePoint(&precomp, 15) // 16
|
||||
|
||||
c256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
|
||||
c256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
|
||||
c256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
|
||||
t0.c256StorePoint(&precomp, 2) // 3
|
||||
t1.c256StorePoint(&precomp, 4) // 5
|
||||
t2.c256StorePoint(&precomp, 8) // 9
|
||||
|
||||
c256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
|
||||
c256PointDoubleAsm(t1.xyz[:], t1.xyz[:])
|
||||
t0.c256StorePoint(&precomp, 5) // 6
|
||||
t1.c256StorePoint(&precomp, 9) // 10
|
||||
|
||||
c256PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:])
|
||||
c256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
|
||||
t2.c256StorePoint(&precomp, 6) // 7
|
||||
t1.c256StorePoint(&precomp, 10) // 11
|
||||
|
||||
c256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
|
||||
c256PointDoubleAsm(t2.xyz[:], t2.xyz[:])
|
||||
t0.c256StorePoint(&precomp, 11) // 12
|
||||
t2.c256StorePoint(&precomp, 13) // 14
|
||||
|
||||
c256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
|
||||
c256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
|
||||
t0.c256StorePoint(&precomp, 12) // 13
|
||||
t2.c256StorePoint(&precomp, 14) // 15
|
||||
|
||||
// Start scanning the window from top bit
|
||||
index := uint(254)
|
||||
var sel, sign int
|
||||
|
||||
wvalue := (scalar[index/64] >> (index % 64)) & 0x3f
|
||||
sel, _ = boothW5(uint(wvalue))
|
||||
|
||||
c256Select(p.xyz[0:12], precomp[0:], sel)
|
||||
zero := sel
|
||||
|
||||
for index > 4 {
|
||||
index -= 5
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
|
||||
if index < 192 {
|
||||
wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f
|
||||
} else {
|
||||
wvalue = (scalar[index/64] >> (index % 64)) & 0x3f
|
||||
}
|
||||
|
||||
sel, sign = boothW5(uint(wvalue))
|
||||
|
||||
c256Select(t0.xyz[0:], precomp[0:], sel)
|
||||
c256NegCond(t0.xyz[4:8], sign)
|
||||
c256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
|
||||
c256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
|
||||
c256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
|
||||
zero |= sel
|
||||
}
|
||||
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
c256PointDoubleAsm(p.xyz[:], p.xyz[:])
|
||||
|
||||
wvalue = (scalar[0] << 1) & 0x3f
|
||||
sel, sign = boothW5(uint(wvalue))
|
||||
|
||||
c256Select(t0.xyz[0:], precomp[0:], sel)
|
||||
c256NegCond(t0.xyz[4:8], sign)
|
||||
c256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
|
||||
c256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
|
||||
c256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,112 @@
|
||||
//go:build (amd64 || arm64) && !generic && !generic32 && !generic64
|
||||
// +build amd64 arm64
|
||||
// +build !generic
|
||||
// +build !generic32
|
||||
// +build !generic64
|
||||
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func pointFromBig(x, y *big.Int) []uint64 {
|
||||
xyz := make([]uint64, 12)
|
||||
fromBig(xyz[0:4], maybeReduceModP(x))
|
||||
fromBig(xyz[4:8], maybeReduceModP(y))
|
||||
c256Mul(xyz[0:4], xyz[0:4], rr[:])
|
||||
c256Mul(xyz[4:8], xyz[4:8], rr[:])
|
||||
xyz[8] = montOne0
|
||||
xyz[9] = montOne1
|
||||
xyz[10] = montOne2
|
||||
xyz[11] = montOne3
|
||||
return xyz
|
||||
}
|
||||
|
||||
// func TestC256AddSpeed(t *testing.T) {
|
||||
// a := []uint64{0x715A4589334C74C7, 0x8FE30BBFF2660BE1, 0x5F9904466A39C994, 0x32C4AE2C1F198119}
|
||||
// b := []uint64{0x715A4589334C74C7, 0x8FE30BBFF2660BE1, 0x5F9904466A39C994, 0x32C4AE2C1F198119}
|
||||
// res := make([]uint64, 4)
|
||||
// begin := time.Now()
|
||||
// total := 1000000000
|
||||
// for i := 0; i < total; i++ {
|
||||
// c256Add(res, a, b)
|
||||
// }
|
||||
// elaspe := time.Since(begin)
|
||||
// fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
// fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
|
||||
// }
|
||||
|
||||
func TestC256SqrSpeed(t *testing.T) {
|
||||
a := []uint64{0x715A4589334C74C7, 0x8FE30BBFF2660BE1, 0x5F9904466A39C994, 0x32C4AE2C1F198119}
|
||||
res := make([]uint64, 4)
|
||||
begin := time.Now()
|
||||
total := 100000000
|
||||
for i := 0; i < total; i++ {
|
||||
c256Sqr(res, a, 1)
|
||||
// c256Sqr(res, res, 1)
|
||||
// c256Sqr(res, res, 1)
|
||||
// c256Sqr(res, res, 1)
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
|
||||
}
|
||||
|
||||
func TestC256MulSpeed(t *testing.T) {
|
||||
a := []uint64{0x715A4589334C74C7, 0x8FE30BBFF2660BE1, 0x5F9904466A39C994, 0x32C4AE2C1F198119}
|
||||
b := []uint64{0x715A4589334C74C6, 0x8FE30BBFF2660BE1, 0x5F9904466A39C994, 0x32C4AE2C1F198119}
|
||||
res := make([]uint64, 4)
|
||||
total := 100000000
|
||||
begin := time.Now()
|
||||
for i := 0; i < total; i++ {
|
||||
c256Mul(res, a, b)
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
|
||||
}
|
||||
|
||||
func TestC256PointAddAsmSpeed(t *testing.T) {
|
||||
p1 := pointFromBig(c256.Gx, c256.Gy)
|
||||
x2, y2 := c256.ScalarMult(c256.Gx, c256.Gy, (new(big.Int).SetInt64(2)).Bytes())
|
||||
p2 := pointFromBig(x2, y2)
|
||||
var res [12]uint64
|
||||
begin := time.Now()
|
||||
total := 10000000
|
||||
for i := 0; i < total; i++ {
|
||||
c256PointAddAsm(res[:], p1, p2)
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
|
||||
}
|
||||
|
||||
func TestC256PointDoubleAsmSpeed(t *testing.T) {
|
||||
p1 := pointFromBig(c256.Gx, c256.Gy)
|
||||
var res [12]uint64
|
||||
begin := time.Now()
|
||||
total := 10000000
|
||||
for i := 0; i < total; i++ {
|
||||
c256PointDoubleAsm(res[:], p1)
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(int(float64(total) / float64(elaspe.Milliseconds()) * 1000))
|
||||
}
|
||||
|
||||
func TestC256InvSpeed(t *testing.T) {
|
||||
in := []uint64{34235, 23341, 3444, 55555}
|
||||
out := make([]uint64, 4)
|
||||
begin := time.Now()
|
||||
total := 1000000
|
||||
for i := 0; i < total; i++ {
|
||||
c256Inverse(out, in)
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
|
||||
}
|
||||
@@ -0,0 +1,941 @@
|
||||
//go:build (amd64 || arm64) && !generic && !generic32 && !generic64
|
||||
// +build amd64 arm64
|
||||
// +build !generic
|
||||
// +build !generic32
|
||||
// +build !generic64
|
||||
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// r^{-1} mod p
|
||||
var rModInverseP *big.Int
|
||||
var rModInverseN *big.Int
|
||||
var p *big.Int
|
||||
var n *big.Int
|
||||
|
||||
func init() {
|
||||
rModInverseP = new(big.Int)
|
||||
rModInverseP.SetInt64(1)
|
||||
rModInverseP.Lsh(rModInverseP, 256)
|
||||
rModInverseP.ModInverse(rModInverseP, c256.P)
|
||||
|
||||
rModInverseN = new(big.Int)
|
||||
rModInverseN.SetInt64(1)
|
||||
rModInverseN.Lsh(rModInverseN, 256)
|
||||
rModInverseN.ModInverse(rModInverseN, c256.N)
|
||||
|
||||
p = new(big.Int)
|
||||
p.Set(c256.P)
|
||||
n = new(big.Int)
|
||||
n.Set(c256.N)
|
||||
}
|
||||
|
||||
func randUint64(a []uint64) {
|
||||
buf := make([]byte, 8)
|
||||
for i := range a {
|
||||
rand.Read(buf)
|
||||
a[i] = binary.LittleEndian.Uint64(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func assertEqual(a, b interface{}) {
|
||||
switch a.(type) {
|
||||
case *big.Int:
|
||||
if a.(*big.Int).Cmp(b.(*big.Int)) != 0 {
|
||||
panic("assert equal failed")
|
||||
}
|
||||
case []uint64:
|
||||
aa := a.([]uint64)
|
||||
bb := b.([]uint64)
|
||||
for i := 0; i < len(aa); i++ {
|
||||
if aa[i] != bb[i] {
|
||||
panic("assert equal failed")
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("unknown type")
|
||||
}
|
||||
}
|
||||
|
||||
func print(a []uint64) {
|
||||
for _, x := range a {
|
||||
fmt.Printf("%016x ", x)
|
||||
}
|
||||
fmt.Println("")
|
||||
}
|
||||
|
||||
func toBig(in []uint64) *big.Int {
|
||||
out := new(big.Int)
|
||||
for i := len(in) - 1; i >= 0; i-- {
|
||||
out.Lsh(out, 64)
|
||||
out.Add(out, new(big.Int).SetUint64(in[i]))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Functions implemented in c256_asm_*64.s
|
||||
// Montgomery multiplication modulo P256
|
||||
func c256MulOfGo(res, in1, in2 []uint64) {
|
||||
int1 := toBig(in1)
|
||||
int2 := toBig(in2)
|
||||
int1.Mul(int1, int2)
|
||||
int1.Mul(int1, rModInverseP)
|
||||
int1.Mod(int1, p)
|
||||
fromBig(res, int1)
|
||||
}
|
||||
|
||||
// Montgomery square modulo P256, repeated n times (n >= 1)
|
||||
func c256SqrOfGo(res, in []uint64, n int) {
|
||||
copy(res, in)
|
||||
for i := 0; i < n; i++ {
|
||||
c256MulOfGo(res, res, res)
|
||||
}
|
||||
}
|
||||
|
||||
// Montgomery multiplication by 1
|
||||
func c256FromMontOfGo(res, in []uint64) {
|
||||
int1 := toBig(in)
|
||||
int1.Mul(int1, rModInverseP)
|
||||
int1.Mod(int1, p)
|
||||
fromBig(res, int1)
|
||||
}
|
||||
|
||||
// iff cond == 1 val <- -val
|
||||
func c256NegCondOfGo(val []uint64, cond int) {
|
||||
if cond == 1 {
|
||||
int1 := toBig(val)
|
||||
int1.Sub(p, int1)
|
||||
|
||||
int1.Mod(int1, p)
|
||||
fromBig(val, int1)
|
||||
}
|
||||
}
|
||||
|
||||
// Montgomery multiplication modulo Ord(G)
|
||||
func c256OrdMulOfGo(res, in1, in2 []uint64) {
|
||||
int1 := toBig(in1)
|
||||
int2 := toBig(in2)
|
||||
int1.Mul(int1, int2)
|
||||
int1.Mul(int1, rModInverseN)
|
||||
int1.Mod(int1, n)
|
||||
fromBig(res, int1)
|
||||
}
|
||||
|
||||
// Montgomery square modulo Ord(G), repeated n times
|
||||
func c256OrdSqrOfGo(res, in []uint64, n int) {
|
||||
copy(res, in)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
c256OrdMulOfGo(res, res, res)
|
||||
}
|
||||
}
|
||||
|
||||
// the key step of mont-mul, res = in + p * in[0]
|
||||
// res:5, in:4
|
||||
func c256MulPOfGo(res, in []uint64) {
|
||||
int1 := toBig(in)
|
||||
r := new(big.Int)
|
||||
r.Mul(new(big.Int).SetUint64(in[0]), p)
|
||||
r.Add(r, int1)
|
||||
fromBig(res, r)
|
||||
}
|
||||
|
||||
func montReduceOfGo(res, a []uint64) {
|
||||
res1 := new(big.Int)
|
||||
a1 := toBig(a)
|
||||
res1.Mul(new(big.Int).SetUint64(a[0]), p)
|
||||
res1.Add(res1, a1)
|
||||
res1.Rsh(res1, 64)
|
||||
fromBig(res, res1)
|
||||
}
|
||||
|
||||
func randomPoint() (*big.Int, *big.Int) {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
return c256.ScalarMult(c256.Gx, c256.Gy, k.Bytes())
|
||||
}
|
||||
|
||||
// func TestMontReduceOfGo(t *testing.T) {
|
||||
// res1, res2, in1 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
// _ = res1
|
||||
// for i := 0; i < 100000000; i++ {
|
||||
// randUint64(in1)
|
||||
// // in1 = []uint64{1, 1, 1, 1}
|
||||
// montReduceOfGo(res1, in1)
|
||||
// // montReduce(res2, in1)
|
||||
// // print(res1)
|
||||
// // print(res2)
|
||||
// // assertEqualUint(res1, res2, "")
|
||||
// }
|
||||
// }
|
||||
|
||||
func BenchmarkUint64IsZero(b *testing.B) {
|
||||
scalar := []uint64{1, 2, 3, 4}
|
||||
for i := 0; i < b.N; i++ {
|
||||
scalarIsZero(scalar)
|
||||
}
|
||||
}
|
||||
func TestC256Mul(t *testing.T) {
|
||||
for i := 0; i < 1000000; i++ {
|
||||
// for {
|
||||
res1, res2, in1, in2 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
randUint64(in2)
|
||||
|
||||
c256MulOfGo(res1, in1, in2)
|
||||
c256Mul(res2, in1, in2)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用p256:
|
||||
// BenchmarkC256Mul-10 82318298 14.51 ns/op 0 B/op 0 allocs/op
|
||||
// 修改不用nist p256:
|
||||
// BenchmarkC256Mul-10 87902702 13.60 ns/op 0 B/op 0 allocs/op
|
||||
func BenchmarkC256Mul(b *testing.B) {
|
||||
res, in1, in2 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
randUint64(in2)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c256Mul(res, in1, in2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestC256SqrBasic(t *testing.T) {
|
||||
res, zero, in := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
c256Sqr(res, in, 1)
|
||||
assertEqual(res, zero)
|
||||
|
||||
pplus1 := new(big.Int).Add(p, big.NewInt(1))
|
||||
fromBig(in, pplus1)
|
||||
c256Sqr(res, in, 1)
|
||||
rInv := toBig(res)
|
||||
assertEqual(rInv, rModInverseP)
|
||||
|
||||
f32 := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
|
||||
fromBig(in, f32)
|
||||
c256Sqr(res, in, 1)
|
||||
f32.Mul(f32, f32)
|
||||
f32.Mul(f32, rModInverseP)
|
||||
f32.Mod(f32, p)
|
||||
res2 := make([]uint64, 4)
|
||||
fromBig(res2, f32)
|
||||
assertEqual(res, res2)
|
||||
}
|
||||
|
||||
func TestC256Sqr(t *testing.T) {
|
||||
for n := 1; n < 10; n++ {
|
||||
for i := 0; i < 100000; i++ {
|
||||
res1, res2, in := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in)
|
||||
c256SqrOfGo(res1, in, n)
|
||||
c256Sqr(res2, in, n)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用p256:
|
||||
// BenchmarkC256Sqr-10 93287706 12.84 ns/op 0 B/op 0 allocs/op
|
||||
// 修改不用nist p256:
|
||||
// BenchmarkC256Sqr-10 87514056 11.72 ns/op 0 B/op 0 allocs/op
|
||||
func BenchmarkC256Sqr(b *testing.B) {
|
||||
res, in := make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c256Sqr(res, in, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegCond(t *testing.T) {
|
||||
res1, res2, in1 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
copy(res1, in1)
|
||||
copy(res2, in1)
|
||||
|
||||
c256NegCondOfGo(res1, 1)
|
||||
c256NegCond(res2, 1)
|
||||
assertEqual(res1, res2)
|
||||
c256NegCondOfGo(res1, 0)
|
||||
c256NegCond(res2, 0)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
|
||||
func TestMovCond(t *testing.T) {
|
||||
res, in1, in2 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
randUint64(in2)
|
||||
|
||||
c256MovCond(res, in1, in2, 1)
|
||||
assertEqual(res, in1)
|
||||
|
||||
c256MovCond(res, in1, in2, 0)
|
||||
assertEqual(res, in2)
|
||||
|
||||
c256MovCond(res, in1, in2, 12345)
|
||||
assertEqual(res, in1)
|
||||
}
|
||||
|
||||
func TestFromMont(t *testing.T) {
|
||||
for i := 0; i < 1000000; i++ {
|
||||
res1, res2, in1 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
c256FromMontOfGo(res1, in1)
|
||||
c256FromMont(res2, in1)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrdMul(t *testing.T) {
|
||||
for i := 0; i < 100000; i++ {
|
||||
res1, res2, in1, in2 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
randUint64(in2)
|
||||
|
||||
c256OrdMulOfGo(res1, in1, in2)
|
||||
c256OrdMul(res2, in1, in2)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestOrdSqr(t *testing.T) {
|
||||
for k := 1; k < 10; k++ {
|
||||
for i := 0; i < 10000; i++ {
|
||||
res1, res2, in1, in2 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
randUint64(in2)
|
||||
|
||||
c256OrdSqrOfGo(res1, in1, k)
|
||||
c256OrdSqr(res2, in1, k)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOrdInverse(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
res1 := c256.Inverse(k)
|
||||
res2 := new(big.Int)
|
||||
res2.ModInverse(k, c256.N)
|
||||
|
||||
res1.Mul(res1, k)
|
||||
res1.Mod(res1, c256.N)
|
||||
res2.Mul(res2, k)
|
||||
res2.Mod(res2, c256.N)
|
||||
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestC256Inverse(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
res1, res2, in1, in2 := make([]uint64, 4), make([]uint64, 4), make([]uint64, 4), make([]uint64, 4)
|
||||
randUint64(in1)
|
||||
copy(in2, in1)
|
||||
|
||||
int1 := toBig(in1)
|
||||
|
||||
int1.ModInverse(int1, c256.P)
|
||||
int1.Lsh(int1, 256*2)
|
||||
int1.Mod(int1, c256.P)
|
||||
fromBig(res1, int1)
|
||||
|
||||
c256Inverse(res2, in2)
|
||||
assertEqual(res1, res2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointAddAffineAsmG(t *testing.T) {
|
||||
var g1, g2, g3, g c256Point
|
||||
x1 := new(big.Int).Set(c256.Gx)
|
||||
y1 := new(big.Int).Set(c256.Gy)
|
||||
x2, y2 := c256.CurveParams.Add(x1, y1, x1, y1)
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
|
||||
g1.c256PointFromAffine(c256.Gx, c256.Gy)
|
||||
g2.c256PointFromAffine(x2, y2)
|
||||
g3.c256PointFromAffine(x3, y3)
|
||||
|
||||
c256PointAddAffineAsm(g.xyz[:], g1.xyz[:], g2.xyz[:], 0, 1, 1)
|
||||
x, y := g3.c256PointToAffine()
|
||||
assertEqual(x3, x)
|
||||
assertEqual(y3, y)
|
||||
}
|
||||
|
||||
func TestPointAddAffineAsm(t *testing.T) {
|
||||
var p1, p2 c256Point
|
||||
{
|
||||
x1, y1 := randomPoint()
|
||||
x2 := bigFromBase16("4071bba1f6624b6e9ac69b7109db9cac04e5bba76fdc954ebe375dfb2af6df2a")
|
||||
y2 := bigFromBase16("fffffffb00000005fffffffc00000002fffffffd00000006fffffff900000004")
|
||||
y2.Sub(p, y2)
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
|
||||
y2.Sub(p, y2)
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
// p2.y = 1, set to p+1
|
||||
p2.xyz[4] = 0
|
||||
p2.xyz[5] = 0xffffffff00000001
|
||||
p2.xyz[6] = 0xffffffffffffffff
|
||||
p2.xyz[7] = 0xfffffffeffffffff
|
||||
|
||||
c256PointAddAffineAsm(p1.xyz[:], p1.xyz[:], p2.xyz[:], 1, 1, 1)
|
||||
x4, y4 := p1.c256PointToAffine()
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
}
|
||||
|
||||
{
|
||||
x1, y1 := randomPoint()
|
||||
x2 := bigFromBase16("4071bba1f6624b6e9ac69b7109db9cac04e5bba76fdc954ebe375dfb2af6df2a")
|
||||
y2 := bigFromBase16("fffffffb00000005fffffffc00000002fffffffd00000006fffffff900000004")
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
y2.Sub(p, y2)
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
|
||||
c256PointAddAffineAsm(p1.xyz[:], p1.xyz[:], p2.xyz[:], 1, 1, 1)
|
||||
x4, y4 := p1.c256PointToAffine()
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
}
|
||||
|
||||
for i := 0; i < 10000; i++ {
|
||||
x1, y1 := randomPoint()
|
||||
x2, y2 := randomPoint()
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
|
||||
c256PointAddAffineAsm(p1.xyz[:], p1.xyz[:], p2.xyz[:], 0, 1, 1)
|
||||
x4, y4 := p1.c256PointToAffine()
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
|
||||
y2.Sub(p, y2)
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
|
||||
c256PointAddAffineAsm(p1.xyz[:], p1.xyz[:], p2.xyz[:], 1, 1, 1)
|
||||
x4, y4 = p1.c256PointToAffine()
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkPointAddAffineAsm(b *testing.B) {
|
||||
var res, p1, p2 c256Point
|
||||
x1, y1 := randomPoint()
|
||||
x2, y2 := randomPoint()
|
||||
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c256PointAddAffineAsm(res.xyz[:], p1.xyz[:], p2.xyz[:], 1, 1, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointAddAffineAsmSpeed(t *testing.T) {
|
||||
var res, p1, p2 c256Point
|
||||
x1, y1 := randomPoint()
|
||||
x2, y2 := randomPoint()
|
||||
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
total := 100000
|
||||
begin := time.Now()
|
||||
for i := 0; i < total; i++ {
|
||||
c256PointAddAffineAsm(res.xyz[:], p1.xyz[:], p2.xyz[:], 1, 1, 1)
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
|
||||
}
|
||||
|
||||
func TestPointAddAsm(t *testing.T) {
|
||||
var res, p1, p2 c256Point
|
||||
x1, y1 := randomPoint()
|
||||
x2 := new(big.Int).Set(x1)
|
||||
y2 := new(big.Int).Set(y1)
|
||||
y2.Sub(p, y2)
|
||||
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
c256PointAddAsm(res.xyz[:], p1.xyz[:], p2.xyz[:])
|
||||
x, y := res.c256PointToAffine()
|
||||
assertEqual(x, big.NewInt(0))
|
||||
assertEqual(y, big.NewInt(0))
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
|
||||
k1, _ := rand.Int(rand.Reader, c256.N)
|
||||
k2, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
x1, y1 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k1.Bytes())
|
||||
x2, y2 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k2.Bytes())
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
p2.c256PointFromAffine(x2, y2)
|
||||
c256PointAddAsm(res.xyz[:], p1.xyz[:], p2.xyz[:])
|
||||
|
||||
x4, y4 := res.c256PointToAffine()
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointDoubleAsm(t *testing.T) {
|
||||
for i := 0; i < 1000; i++ {
|
||||
var res1, res2, p1 c256Point
|
||||
k1, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
x1, y1 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k1.Bytes())
|
||||
x3, y3 := c256.CurveParams.Double(x1, y1)
|
||||
res2.c256PointFromAffine(x3, y3)
|
||||
|
||||
p1.c256PointFromAffine(x1, y1)
|
||||
c256PointDoubleAsm(res1.xyz[:], p1.xyz[:])
|
||||
|
||||
x4, y4 := res1.c256PointToAffine()
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
}
|
||||
}
|
||||
|
||||
// / test for Curve interface
|
||||
func TestIsOnCurve(t *testing.T) {
|
||||
if !c256.IsOnCurve(c256.Gx, c256.Gy) {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointAdd(t *testing.T) {
|
||||
x1, y1 := randomPoint()
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x1, y1)
|
||||
x4, y4 := c256.Add(x1, y1, x1, y1)
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
|
||||
x2 := new(big.Int).Set(x1)
|
||||
y2 := new(big.Int).Set(y1)
|
||||
y2.Sub(p, y2)
|
||||
x3, y3 = c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
x4, y4 = c256.Add(x1, y1, x2, y2)
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
k1, _ := rand.Int(rand.Reader, c256.N)
|
||||
k2, _ := rand.Int(rand.Reader, c256.N)
|
||||
x1, y1 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k1.Bytes())
|
||||
x2, y2 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k2.Bytes())
|
||||
x3, y3 := c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
x4, y4 := c256.Add(x1, y1, x2, y2)
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPointDouble(b *testing.B) {
|
||||
x, y := randomPoint()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// BenchmarkPointDouble-8 278118 4096 ns/op 192 B/op 4 allocs/op
|
||||
c256.Double(x, y)
|
||||
|
||||
// BenchmarkPointDouble-8 186952 6471 ns/op 3961 B/op 52 allocs/op
|
||||
// c256.CurveParams.Double(x, y)
|
||||
}
|
||||
}
|
||||
func BenchmarkPointAdd(b *testing.B) {
|
||||
x1, y1 := randomPoint()
|
||||
x2, y2 := randomPoint()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
//BenchmarkPointAdd-8 273103 4229 ns/op 192 B/op 4 allocs/op
|
||||
c256.Add(x1, y1, x2, y2)
|
||||
// c256.Add(x1, y1, x1, y1)
|
||||
|
||||
// BenchmarkPointAdd-8 175370 7210 ns/op 4881 B/op 65 allocs/op
|
||||
// c256.CurveParams.Add(x1, y1, x2, y2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPointDouble(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
k1, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
x1, y1 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k1.Bytes())
|
||||
|
||||
x3, y3 := c256.CurveParams.Double(x1, y1)
|
||||
x4, y4 := c256.Double(x1, y1)
|
||||
|
||||
assertEqual(x3, x4)
|
||||
assertEqual(y3, y4)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMult(t *testing.T) {
|
||||
k := new(big.Int).Set(c256.N)
|
||||
x, y := c256.ScalarMult(c256.Gx, c256.Gy, k.Bytes())
|
||||
zero := big.NewInt(0)
|
||||
assertEqual(x, zero)
|
||||
assertEqual(y, zero)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
x1, y1 := c256.ScalarMult(c256.Gx, c256.Gy, k.Bytes())
|
||||
x2, y2 := c256.CurveParams.ScalarMult(c256.Gx, c256.Gy, k.Bytes())
|
||||
|
||||
assertEqual(x1, x2)
|
||||
assertEqual(y1, y2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarBaseMult(t *testing.T) {
|
||||
k := new(big.Int).Add(c256.N, big.NewInt(1))
|
||||
x1, y1 := c256.ScalarBaseMult(k.Bytes())
|
||||
assertEqual(x1, c256.Gx)
|
||||
assertEqual(y1, c256.Gy)
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
x1, y1 := c256.ScalarBaseMult(k.Bytes())
|
||||
x2, y2 := c256.CurveParams.ScalarBaseMult(k.Bytes())
|
||||
|
||||
assertEqual(x1, x2)
|
||||
assertEqual(y1, y2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMultSpeed(t *testing.T) {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
x1, y1 := c256.ScalarMult(c256.Gx, c256.Gy, k.Bytes())
|
||||
|
||||
begin := time.Now()
|
||||
total := 100000
|
||||
for i := 0; i < total; i++ {
|
||||
c256.ScalarMult(x1, y1, k.Bytes())
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
|
||||
}
|
||||
|
||||
func BenchmarkScalarMultSpeed(b *testing.B) {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
x1, y1 := c256.ScalarMult(c256.Gx, c256.Gy, k.Bytes())
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c256.ScalarMult(x1, y1, k.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarBaseMultSpeed(t *testing.T) {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
|
||||
begin := time.Now()
|
||||
total := 100000
|
||||
for i := 0; i < total; i++ {
|
||||
c256.ScalarBaseMult(k.Bytes())
|
||||
}
|
||||
elaspe := time.Since(begin)
|
||||
fmt.Println("time: ", elaspe.Milliseconds(), "ms")
|
||||
fmt.Println(float64(total) / float64(elaspe.Milliseconds()) * 1000)
|
||||
}
|
||||
|
||||
func BenchmarkScalarBaseMultSpeed(b *testing.B) {
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c256.ScalarBaseMult(k.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkCombineMult-8 17679 64513 ns/op 320 B/op 6 allocs/op
|
||||
func BenchmarkCombineMult(b *testing.B) {
|
||||
x, y := randomPoint()
|
||||
k, _ := rand.Int(rand.Reader, c256.N)
|
||||
baseScalar := k.Bytes()
|
||||
k, _ = rand.Int(rand.Reader, c256.N)
|
||||
scalar := k.Bytes()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
CombinedMult(x, y, baseScalar, scalar)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoothW5(t *testing.T) {
|
||||
for i := uint(0); i < 64; i++ {
|
||||
sel, sign := boothW5(i)
|
||||
fmt.Println(i, "\t", sel, "\t", sign)
|
||||
_, _ = sel, sign
|
||||
}
|
||||
}
|
||||
|
||||
func TestBoothW6(t *testing.T) {
|
||||
for i := uint(0); i < 128; i++ {
|
||||
sel, sign := boothW6(i)
|
||||
// fmt.Println(i, "\t", sel, "\t", sign)
|
||||
_, _ = sel, sign
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectBase(t *testing.T) {
|
||||
var t0 c256Point
|
||||
c256SelectBase(t0.xyz[0:8], c256Precomputed[0][0:], 1)
|
||||
|
||||
}
|
||||
|
||||
func TestSelect(t *testing.T) {
|
||||
var t0 c256Point
|
||||
var precomp [16 * 4 * 3]uint64
|
||||
var p = c256Point{
|
||||
xyz: [12]uint64{0x715A4589334C74C7,
|
||||
0x8FE30BBFF2660BE1,
|
||||
0x5F9904466A39C994,
|
||||
0x32C4AE2C1F198119,
|
||||
0x02DF32E52139F0A0,
|
||||
0xD0A9877CC62A4740,
|
||||
0x59BDCEE36B692153,
|
||||
0xBC3736A2F4F6779C,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0},
|
||||
}
|
||||
c256ToMont(p.xyz[:], p.xyz[:])
|
||||
c256Select(t0.xyz[:], precomp[:], 0)
|
||||
assertEqual(t0.xyz[:], make([]uint64, 12))
|
||||
equal := c256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
|
||||
assert.Equal(t, equal, 1)
|
||||
}
|
||||
|
||||
/*
|
||||
TestBoothW5
|
||||
0 0 0
|
||||
1 1 0
|
||||
2 1 0
|
||||
3 2 0
|
||||
4 2 0
|
||||
5 3 0
|
||||
6 3 0
|
||||
7 4 0
|
||||
8 4 0
|
||||
9 5 0
|
||||
10 5 0
|
||||
11 6 0
|
||||
12 6 0
|
||||
13 7 0
|
||||
14 7 0
|
||||
15 8 0
|
||||
16 8 0
|
||||
17 9 0
|
||||
18 9 0
|
||||
19 10 0
|
||||
20 10 0
|
||||
21 11 0
|
||||
22 11 0
|
||||
23 12 0
|
||||
24 12 0
|
||||
25 13 0
|
||||
26 13 0
|
||||
27 14 0
|
||||
28 14 0
|
||||
29 15 0
|
||||
30 15 0
|
||||
31 16 0
|
||||
32 16 1
|
||||
33 15 1
|
||||
34 15 1
|
||||
35 14 1
|
||||
36 14 1
|
||||
37 13 1
|
||||
38 13 1
|
||||
39 12 1
|
||||
40 12 1
|
||||
41 11 1
|
||||
42 11 1
|
||||
43 10 1
|
||||
44 10 1
|
||||
45 9 1
|
||||
46 9 1
|
||||
47 8 1
|
||||
48 8 1
|
||||
49 7 1
|
||||
50 7 1
|
||||
51 6 1
|
||||
52 6 1
|
||||
53 5 1
|
||||
54 5 1
|
||||
55 4 1
|
||||
56 4 1
|
||||
57 3 1
|
||||
58 3 1
|
||||
59 2 1
|
||||
60 2 1
|
||||
61 1 1
|
||||
62 1 1
|
||||
63 0 1
|
||||
|
||||
*/
|
||||
|
||||
func TestPrintBaseMult(t *testing.T) {
|
||||
if false {
|
||||
for i, table := range c256Precomputed {
|
||||
for j := 0; j < 32; j++ {
|
||||
fmt.Printf("\t// [64^%d * %2d]G\n", i, j+1)
|
||||
fmt.Print("\t")
|
||||
for k := 0; k < 4; k++ {
|
||||
fmt.Printf("0x%016x", table[8*j+k])
|
||||
if k < 3 {
|
||||
fmt.Print(", ")
|
||||
} else {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
fmt.Print("\t")
|
||||
for k := 4; k < 8; k++ {
|
||||
fmt.Printf("0x%016x", table[8*j+k])
|
||||
if k < 7 {
|
||||
fmt.Print(", ")
|
||||
} else {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println("\t//")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func writePoint(sb *strings.Builder, p c256Point) {
|
||||
x, y := p.c256PointToAffine()
|
||||
p.c256PointFromAffine(x, y)
|
||||
for k := 0; k < 8; k++ {
|
||||
sb.WriteString(fmt.Sprintf("0x%016x, ", p.xyz[k]))
|
||||
if k == 3 {
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
|
||||
func TestBaseTable(t *testing.T) {
|
||||
var sb strings.Builder
|
||||
|
||||
const N = 8
|
||||
var G = c256Point{
|
||||
xyz: [12]uint64{0x715A4589334C74C7,
|
||||
0x8FE30BBFF2660BE1,
|
||||
0x5F9904466A39C994,
|
||||
0x32C4AE2C1F198119,
|
||||
0x02DF32E52139F0A0,
|
||||
0xD0A9877CC62A4740,
|
||||
0x59BDCEE36B692153,
|
||||
0xBC3736A2F4F6779C,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0},
|
||||
}
|
||||
c256ToMont(G.xyz[:4], G.xyz[:4])
|
||||
c256ToMont(G.xyz[4:], G.xyz[4:])
|
||||
c256ToMont(G.xyz[8:], G.xyz[8:])
|
||||
|
||||
var P, Q c256Point
|
||||
P = G
|
||||
for i := 0; i < 256/N; i++ {
|
||||
Q = P
|
||||
|
||||
// P
|
||||
sb.WriteString(fmt.Sprintf("// [%d^%d]G\n", 1<<N, i))
|
||||
writePoint(&sb, Q)
|
||||
|
||||
// 2P
|
||||
c256PointDoubleAsm(Q.xyz[:], Q.xyz[:])
|
||||
sb.WriteString(fmt.Sprintf("// [2 * %d^%d]G\n", 1<<N, i))
|
||||
writePoint(&sb, Q)
|
||||
|
||||
for j := 3; j <= (1 << (N - 1)); j++ {
|
||||
// jP
|
||||
c256PointAddAsm(Q.xyz[:], Q.xyz[:], P.xyz[:])
|
||||
|
||||
sb.WriteString(fmt.Sprintf("// [%d * %d^%d]G\n", j, 1<<N, i))
|
||||
writePoint(&sb, Q)
|
||||
}
|
||||
// the last round
|
||||
if i == 256/N-1 {
|
||||
for j := (1 << (N - 1)) + 1; j <= (1 << N); j++ {
|
||||
c256PointAddAsm(Q.xyz[:], Q.xyz[:], P.xyz[:])
|
||||
sb.WriteString(fmt.Sprintf("// [%d * %d^%d]G\n", j, 1<<N, i))
|
||||
writePoint(&sb, Q)
|
||||
}
|
||||
}
|
||||
c256PointDoubleAsm(P.xyz[:], Q.xyz[:])
|
||||
}
|
||||
|
||||
os.WriteFile("/Users/fengwd/Files/Codes/go/src/xdx.jelly/xgcl/sm/sm2/tbl.txt", []byte(sb.String()), 0666)
|
||||
}
|
||||
|
||||
func TestBaseTable3(t *testing.T) {
|
||||
var G = c256Point{
|
||||
xyz: [12]uint64{0x715A4589334C74C7,
|
||||
0x8FE30BBFF2660BE1,
|
||||
0x5F9904466A39C994,
|
||||
0x32C4AE2C1F198119,
|
||||
0x02DF32E52139F0A0,
|
||||
0xD0A9877CC62A4740,
|
||||
0x59BDCEE36B692153,
|
||||
0xBC3736A2F4F6779C,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0},
|
||||
}
|
||||
c256ToMont(G.xyz[:4], G.xyz[:4])
|
||||
c256ToMont(G.xyz[4:], G.xyz[4:])
|
||||
c256ToMont(G.xyz[8:], G.xyz[8:])
|
||||
|
||||
scalarReversed := []uint64{0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF}
|
||||
var r, P c256Point
|
||||
P.c256BaseMult(scalarReversed)
|
||||
c256PointAddAsm(r.xyz[:], P.xyz[:], G.xyz[:])
|
||||
x, y := r.c256PointToAffine()
|
||||
r.c256PointFromAffine(x, y)
|
||||
|
||||
for k := 0; k < 8; k++ {
|
||||
fmt.Printf("0x%016x, ", r.xyz[k])
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// +build generic32
|
||||
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
)
|
||||
|
||||
// 窗口为8的预计算点
|
||||
func TestGenCurvePrecompute8(t *testing.T) {
|
||||
table := make([]*big.Int, 0, 2*256)
|
||||
// for i = i[k], i[i] = 0 or 1
|
||||
// table[i] is i[0] + i[1]*2^32 + i[2]*2^64 + ... + i[7]*2^{224}
|
||||
for i := 0; i < 256; i++ {
|
||||
|
||||
k := new(big.Int)
|
||||
for j := 7; j >= 0; j-- {
|
||||
if (i>>j)&1 != 0 {
|
||||
k.Add(k, gmath.BigInt1)
|
||||
}
|
||||
k.Lsh(k, 32)
|
||||
}
|
||||
|
||||
x, y := c256.ScalarBaseMult(k.Bytes())
|
||||
table = append(table, x)
|
||||
table = append(table, y)
|
||||
|
||||
}
|
||||
|
||||
for _, x := range table {
|
||||
var out [c256Limbs]uint32
|
||||
c256FromBig(&out, x)
|
||||
fmt.Printf("0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x\n",
|
||||
out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], out[8],
|
||||
)
|
||||
// fmt.Printf("&curvePoint{gfP{0x%x,0x%x,0x%x,0x%x},gfP{0x%x,0x%x,0x%x,0x%x},*newGFp(1),*newGFp(1)},\n",
|
||||
// x.x[0], x.x[1], x.x[2], x.x[3],
|
||||
// x.y[0], x.y[1], x.y[2], x.y[3])
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,431 @@
|
||||
//go:build (!amd64 && !arm64) || generic32 || generic64
|
||||
// +build !amd64,!arm64 generic32 generic64
|
||||
|
||||
// build when !amd64 AND !arm64 OR generic32 OR generic64
|
||||
|
||||
package ec256
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkScalarMultc256(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
// _, x, y, _ := elliptic.GenerateKey(c256, rand.Reader)
|
||||
// priv, _, _, _ := elliptic.GenerateKey(c256, rand.Reader)
|
||||
|
||||
priv, _ := new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
|
||||
bb := priv.Bytes()
|
||||
b.ReportAllocs()
|
||||
b.StartTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
// c256.ScalarMult(c256.Gx, c256.Gy, bb)
|
||||
c256.ScalarBaseMult(bb)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestPointMul(t *testing.T) {
|
||||
priv, _ := new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
|
||||
bb := priv.Bytes()
|
||||
cnt := 5000
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
// c256.ScalarMult(c256.Gx, c256.Gy, bb)
|
||||
c256.ScalarBaseMult(bb)
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
fmt.Printf("SM2 Scalar Mul Point: %d PerSec\n", int(float64(cnt)/elapsed.Seconds()))
|
||||
}
|
||||
|
||||
func TestReduceCarry(t *testing.T) {
|
||||
// fmt.Printf("%08x\n", 1<<29-1-2<<21)
|
||||
var inout [c256Limbs]uint32
|
||||
var temp [c256Limbs]uint32
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < c256Limbs; i++ {
|
||||
temp[i] = uint32(rnd.Int31()) & 0xFFFFFFF
|
||||
inout[i] = temp[i]
|
||||
}
|
||||
var carry uint32 = 5
|
||||
c256ReduceCarry(&inout, carry)
|
||||
// for _, n := range inout {
|
||||
// fmt.Printf("0x%08x, ", n)
|
||||
// }
|
||||
ret := c256ToBig(&inout)
|
||||
fmt.Println(ret.Text(16))
|
||||
|
||||
s := c256ToBig(&temp)
|
||||
r := big.NewInt(int64(carry))
|
||||
r.Lsh(r, 257)
|
||||
s.Add(s, r)
|
||||
s.Mod(s, c256.P)
|
||||
// c256FromBig(&inout, s)
|
||||
fmt.Println(s.Text(16))
|
||||
// c256FromBig(&inout, s)
|
||||
// for _, n := range inout {
|
||||
// fmt.Printf("0x%08x, ", n)
|
||||
// }
|
||||
ret.Sub(ret, s)
|
||||
fmt.Println(ret)
|
||||
}
|
||||
|
||||
func TestReduceDegree(t *testing.T) {
|
||||
|
||||
for j := uint64(0); j < 100000000; j++ {
|
||||
if j%1000000 == 0 {
|
||||
fmt.Println(j/10000, "万次pass")
|
||||
}
|
||||
var in [c256Limbs]uint32 //= [c256Limbs]uint32{0x1604a25, 0x6d1db34, 0x140458b9, 0xd3371b7, 0x79446ec, 0xd2bca28, 0xb98f19b, 0xc227f7c, 0xcaed5c}
|
||||
var out [c256Limbs]uint32
|
||||
var temp [c256Limbs]uint32 //= [c256Limbs]uint32{0xdb99003, 0x964a8c3, 0x1f7dc5a9, 0xc9db569, 0x1893e838, 0xeecb116, 0xca9ff4f, 0x68bd063, 0x11e538bf}
|
||||
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < c256Limbs; i++ {
|
||||
if i%2 == 0 {
|
||||
temp[i] = uint32(rnd.Int()) & 0x1FFFFFFF
|
||||
} else {
|
||||
temp[i] = uint32(rnd.Int()) & 0xFFFFFFF
|
||||
}
|
||||
// fmt.Printf("0x%x,", temp[i])
|
||||
}
|
||||
|
||||
for i := 0; i < c256Limbs; i++ {
|
||||
if i%2 == 0 {
|
||||
in[i] = uint32(rnd.Int31()) & 0x1FFFFFFF
|
||||
} else {
|
||||
in[i] = uint32(rnd.Int31()) & 0xFFFFFFF
|
||||
}
|
||||
// fmt.Printf("0x%x,", in[i])
|
||||
}
|
||||
|
||||
ret := c256ToBig(&temp)
|
||||
// fmt.Println("a:= ", ret.Text(16))
|
||||
// ret = c256ToBig(&in)
|
||||
// fmt.Println("b:= ", ret.Text(16))
|
||||
|
||||
c256Mul(&out, &in, &temp)
|
||||
ret = c256ToBig(&out)
|
||||
|
||||
ret.Mod(ret, c256.P)
|
||||
// fmt.Println("a*b=", ret.Text(16))
|
||||
|
||||
s := c256ToBig(&temp)
|
||||
s.Mul(s, c256ToBig(&in))
|
||||
s.Mul(s, c256RInverse)
|
||||
s.Mod(s, c256.P)
|
||||
|
||||
// ret.Mod(ret, c256.P)
|
||||
if ret.Cmp(s) != 0 {
|
||||
fmt.Println("failed")
|
||||
fmt.Println(ret.Text(16))
|
||||
fmt.Println(s.Text(16))
|
||||
fmt.Println("in:", in)
|
||||
fmt.Println("temp:", temp)
|
||||
fmt.Println("diff:", ret.Sub(ret, s).Text(16))
|
||||
return
|
||||
}
|
||||
// ret.Sub(ret, s)
|
||||
// fmt.Println("?0=", ret.Text(16))
|
||||
}
|
||||
fmt.Println("test over")
|
||||
}
|
||||
|
||||
func TestInverse(t *testing.T) {
|
||||
|
||||
for i := 0; i < 100000; i++ {
|
||||
if i%10000 == 0 {
|
||||
fmt.Println(i, "pass")
|
||||
}
|
||||
var in [c256Limbs]uint32 //= [c256Limbs]uint32{0x1604a25, 0x6d1db34, 0x140458b9, 0xd3371b7, 0x79446ec, 0xd2bca28, 0xb98f19b, 0xc227f7c, 0xcaed5c}
|
||||
var out [c256Limbs]uint32
|
||||
|
||||
rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < c256Limbs; i++ {
|
||||
if i%2 == 0 {
|
||||
in[i] = uint32(rnd.Int()) & 0x1FFFFFFF
|
||||
} else {
|
||||
in[i] = uint32(rnd.Int()) & 0xFFFFFFF
|
||||
}
|
||||
// fmt.Printf("0x%x,", temp[i])
|
||||
}
|
||||
c256Invert(&out, &in) // in^(-1)*R
|
||||
outInt := c256ToBig(&out)
|
||||
outInt.Mod(outInt, c256.P)
|
||||
// fmt.Println(outInt.Text(16))
|
||||
|
||||
inInt := c256ToBig(&in) // in * R
|
||||
inInt.ModInverse(inInt, c256.P) // (in*R)^-1
|
||||
inInt.Lsh(inInt, 257+257) // in^-1 * R
|
||||
inInt.Mod(inInt, c256.P)
|
||||
// fmt.Println(inInt.Text(16))
|
||||
|
||||
if inInt.Cmp(outInt) != 0 {
|
||||
fmt.Println("Failed")
|
||||
fmt.Println(in)
|
||||
fmt.Println(new(big.Int).Sub(inInt, outInt).Text(16))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenTable32(t *testing.T) {
|
||||
// Index | Index (binary) | Value
|
||||
// 0 | 0000 | 0G (all zeros, omitted)
|
||||
// 1 | 0001 | G
|
||||
// 2 | 0010 | 2**64G
|
||||
// 3 | 0011 | 2**64G + G
|
||||
// 4 | 0100 | 2**128G
|
||||
// 5 | 0101 | 2**128G + G
|
||||
// 6 | 0110 | 2**128G + 2**64G
|
||||
// 7 | 0111 | 2**128G + 2**64G + G
|
||||
// 8 | 1000 | 2**192G
|
||||
// 9 | 1001 | 2**192G + G
|
||||
// 10 | 1010 | 2**192G + 2**64G
|
||||
// 11 | 1011 | 2**192G + 2**64G + G
|
||||
// 12 | 1100 | 2**192G + 2**128G
|
||||
// 13 | 1101 | 2**192G + 2**128G + G
|
||||
// 14 | 1110 | 2**192G + 2**128G + 2**64G
|
||||
// 15 | 1111 | 2**192G + 2**128G + 2**64G + G
|
||||
//
|
||||
// The second table follows the same style, but the terms are 2**32G,
|
||||
// 2**96G, 2**160G, 2**224G.
|
||||
for i := 1; i < 16; i++ {
|
||||
n := new(big.Int)
|
||||
one := new(big.Int).SetInt64(1)
|
||||
if i&0x08 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 192), n)
|
||||
}
|
||||
if i&0x04 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 128), n)
|
||||
}
|
||||
if i&0x02 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 64), n)
|
||||
}
|
||||
if i&0x01 > 0 {
|
||||
n.Add(one, n)
|
||||
}
|
||||
// fmt.Println(n.Text(16))
|
||||
x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes())
|
||||
var xOut, yOut [c256Limbs]uint32
|
||||
c256FromBig(&xOut, x)
|
||||
c256FromBig(&yOut, y)
|
||||
for _, i := range xOut {
|
||||
fmt.Printf("0x%x, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
for _, i := range yOut {
|
||||
fmt.Printf("0x%x, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
for i := 1; i < 16; i++ {
|
||||
n := new(big.Int)
|
||||
one := new(big.Int).SetInt64(1)
|
||||
if i&0x08 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 224), n)
|
||||
}
|
||||
if i&0x04 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 160), n)
|
||||
}
|
||||
if i&0x02 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 96), n)
|
||||
}
|
||||
if i&0x01 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 32), n)
|
||||
}
|
||||
// fmt.Println(n.Text(16))
|
||||
x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes())
|
||||
var xOut, yOut [c256Limbs]uint32
|
||||
c256FromBig(&xOut, x)
|
||||
c256FromBig(&yOut, y)
|
||||
for _, i := range xOut {
|
||||
fmt.Printf("0x%x, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
for _, i := range yOut {
|
||||
fmt.Printf("0x%x, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// c256FromBig sets out = R*in.
|
||||
func c256FromBig64(out *[5]uint64, in *big.Int) {
|
||||
var bottom51Bits uint64 = 1<<51 - 1
|
||||
var bottom52Bits uint64 = 1<<52 - 1
|
||||
tmp := new(big.Int).Lsh(in, 257)
|
||||
tmp.Mod(tmp, c256.P)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
if bits := tmp.Bits(); len(bits) > 0 {
|
||||
out[i] = uint64(bits[0]) & bottom51Bits
|
||||
} else {
|
||||
out[i] = 0
|
||||
}
|
||||
tmp.Rsh(tmp, 51)
|
||||
|
||||
i++
|
||||
if i == 5 {
|
||||
break
|
||||
}
|
||||
|
||||
if bits := tmp.Bits(); len(bits) > 0 {
|
||||
out[i] = uint64(bits[0]) & bottom52Bits
|
||||
} else {
|
||||
out[i] = 0
|
||||
}
|
||||
tmp.Rsh(tmp, 52)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenTable64(t *testing.T) {
|
||||
// Index | Index (binary) | Value
|
||||
// 0 | 0000 | 0G (all zeros, omitted)
|
||||
// 1 | 0001 | G
|
||||
// 2 | 0010 | 2**64G
|
||||
// 3 | 0011 | 2**64G + G
|
||||
// 4 | 0100 | 2**128G
|
||||
// 5 | 0101 | 2**128G + G
|
||||
// 6 | 0110 | 2**128G + 2**64G
|
||||
// 7 | 0111 | 2**128G + 2**64G + G
|
||||
// 8 | 1000 | 2**192G
|
||||
// 9 | 1001 | 2**192G + G
|
||||
// 10 | 1010 | 2**192G + 2**64G
|
||||
// 11 | 1011 | 2**192G + 2**64G + G
|
||||
// 12 | 1100 | 2**192G + 2**128G
|
||||
// 13 | 1101 | 2**192G + 2**128G + G
|
||||
// 14 | 1110 | 2**192G + 2**128G + 2**64G
|
||||
// 15 | 1111 | 2**192G + 2**128G + 2**64G + G
|
||||
//
|
||||
// The second table follows the same style, but the terms are 2**32G,
|
||||
// 2**96G, 2**160G, 2**224G.
|
||||
for i := 1; i < 16; i++ {
|
||||
n := new(big.Int)
|
||||
one := new(big.Int).SetInt64(1)
|
||||
if i&0x08 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 192), n)
|
||||
}
|
||||
if i&0x04 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 128), n)
|
||||
}
|
||||
if i&0x02 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 64), n)
|
||||
}
|
||||
if i&0x01 > 0 {
|
||||
n.Add(one, n)
|
||||
}
|
||||
// fmt.Println(n.Text(16))
|
||||
x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes())
|
||||
var xOut, yOut [5]uint64
|
||||
c256FromBig64(&xOut, x)
|
||||
c256FromBig64(&yOut, y)
|
||||
for _, i := range xOut {
|
||||
fmt.Printf("0x%xLLU, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
for _, i := range yOut {
|
||||
fmt.Printf("0x%xLLU, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
for i := 1; i < 16; i++ {
|
||||
n := new(big.Int)
|
||||
one := new(big.Int).SetInt64(1)
|
||||
if i&0x08 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 224), n)
|
||||
}
|
||||
if i&0x04 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 160), n)
|
||||
}
|
||||
if i&0x02 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 96), n)
|
||||
}
|
||||
if i&0x01 > 0 {
|
||||
n.Add(new(big.Int).SetInt64(1).Lsh(one, 32), n)
|
||||
}
|
||||
// fmt.Println(n.Text(16))
|
||||
x, y := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes())
|
||||
var xOut, yOut [5]uint64
|
||||
c256FromBig64(&xOut, x)
|
||||
c256FromBig64(&yOut, y)
|
||||
for _, i := range xOut {
|
||||
fmt.Printf("0x%xLLU, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
for _, i := range yOut {
|
||||
fmt.Printf("0x%xLLU, ", i)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
func TestPointMul2(t *testing.T) {
|
||||
n, _ := crand.Int(crand.Reader, c256.N)
|
||||
n.SetInt64(4)
|
||||
//n.Set(c256.N)
|
||||
//n.Sub(n, gmath.BigInt1)
|
||||
//x, y := c256.ScalarBaseMult(n.Bytes())
|
||||
//fmt.Println(x.Text(16), y.Text(16))
|
||||
// n.Set(c256.N)
|
||||
//xx, yy := c256.ScalarMult(c256.Gx, c256.Gy, n.Bytes())
|
||||
xx, yy := c256.ScalarBaseMult(n.Bytes())
|
||||
fmt.Println(xx.Text(16), yy.Text(16))
|
||||
//fmt.Println(xx.Text(16), yy.Text(16))
|
||||
|
||||
// p := c256ToBig(&c256Zero31)
|
||||
// fmt.Println(p.Text(16))
|
||||
}
|
||||
|
||||
// FIXME c256ScalarBaseMult error when scalar = 0
|
||||
func TestZeroScaleBaseMult(t *testing.T) {
|
||||
n := new(big.Int)
|
||||
var scalarReversed [32]byte
|
||||
for i := 0; i < 32; i++ {
|
||||
scalarReversed[i] = 0xcc
|
||||
}
|
||||
|
||||
c256GetScalar(&scalarReversed, n.Bytes())
|
||||
var x1, y1, z1 [c256Limbs]uint32
|
||||
var tmp [17]uint64
|
||||
c256PointDouble(&x1, &y1, &z1, &x1, &y1, &z1)
|
||||
c256ReduceDegree(&z1, tmp)
|
||||
c256ScalarBaseMult(&x1, &y1, &z1, &scalarReversed)
|
||||
|
||||
for _, z := range z1 {
|
||||
if z != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReduce(t *testing.T) {
|
||||
var tmp = [17]uint64{1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1}
|
||||
var out [9]uint32
|
||||
c256ReduceDegree(&out, tmp)
|
||||
for i := 0; i < 9; i++ {
|
||||
fmt.Println(out[i])
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue52075(t *testing.T) {
|
||||
Gx, Gy := c256.Params().Gx, c256.Params().Gy
|
||||
scalar := make([]byte, 33)
|
||||
scalar[32] = 1
|
||||
x, y := c256.ScalarBaseMult(scalar)
|
||||
if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 {
|
||||
t.Errorf("unexpected output (%v,%v)", x, y)
|
||||
}
|
||||
x, y = c256.ScalarMult(Gx, Gy, scalar)
|
||||
if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 {
|
||||
t.Errorf("unexpected output (%v,%v)", x, y)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file:
|
||||
///
|
||||
/// \brief: general elliptic curve implements, modified from the
|
||||
/// Go standed library.
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// CurveParams implement Curve interface, of the most common case with big.Int
|
||||
var _ Curve = &CurveParams{}
|
||||
|
||||
// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
|
||||
// It only do affine-to-mont and mont-to-affine once, could be faster than do it seperatly.
|
||||
type combinedMult interface {
|
||||
CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
|
||||
}
|
||||
|
||||
// 没有太大作用
|
||||
type curveX interface {
|
||||
CombinedMultX(bigX, bigY *big.Int, baseScalar, scalar []byte) (x *big.Int)
|
||||
ScalarMultX(x1, y1 *big.Int, k []byte) (x *big.Int)
|
||||
ScalarBaseMultX(k []byte) (x *big.Int)
|
||||
}
|
||||
|
||||
// A Curve represents a short-form Weierstrass curve with a=-3.
|
||||
// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
|
||||
type Curve interface {
|
||||
// Params returns the parameters for the curve.
|
||||
Params() *CurveParams
|
||||
// IsOnCurve reports whether the given (x,y) lies on the curve.
|
||||
IsOnCurve(x, y *big.Int) bool
|
||||
// Add returns the sum of (x1,y1) and (x2,y2)
|
||||
Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
|
||||
// Double returns 2*(x,y)
|
||||
Double(x1, y1 *big.Int) (x, y *big.Int)
|
||||
// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
|
||||
ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int)
|
||||
|
||||
// ScalarBaseMult returns k*G, where G is the base point of the group
|
||||
// and k is an integer in big-endian form.
|
||||
ScalarBaseMult(k []byte) (x, y *big.Int)
|
||||
|
||||
// Add by xdx
|
||||
combinedMult
|
||||
// curveX
|
||||
}
|
||||
|
||||
// CurveParams contains the parameters of an elliptic curve and also provides
|
||||
// a generic, non-constant time implementation of Curve.
|
||||
type CurveParams struct {
|
||||
P *big.Int // the order of the underlying field
|
||||
N *big.Int // the order of the base point
|
||||
B *big.Int // the constant of the curve equation
|
||||
Gx, Gy *big.Int // (x,y) of the base point
|
||||
BitSize int // the size of the underlying field
|
||||
Name string // the canonical name of the curve
|
||||
}
|
||||
|
||||
// Params return the CurveParams
|
||||
func (curve *CurveParams) Params() *CurveParams {
|
||||
return curve
|
||||
}
|
||||
|
||||
// IsOnCurve return true if (x,y) is on the curve
|
||||
func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
|
||||
// y² = x³ - 3x + b
|
||||
y2 := new(big.Int).Mul(y, y)
|
||||
y2.Mod(y2, curve.P)
|
||||
|
||||
x3 := new(big.Int).Mul(x, x)
|
||||
x3.Mul(x3, x)
|
||||
|
||||
threeX := new(big.Int).Lsh(x, 1)
|
||||
threeX.Add(threeX, x)
|
||||
|
||||
x3.Sub(x3, threeX)
|
||||
x3.Add(x3, curve.B)
|
||||
x3.Mod(x3, curve.P)
|
||||
|
||||
return x3.Cmp(y2) == 0
|
||||
}
|
||||
|
||||
// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
|
||||
// y are zero, it assumes that they represent the point at infinity because (0,
|
||||
// 0) is not on the any of the curves handled here.
|
||||
func zForAffine(x, y *big.Int) *big.Int {
|
||||
z := new(big.Int)
|
||||
if x.Sign() != 0 || y.Sign() != 0 {
|
||||
z.SetInt64(1)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// affineFromJacobian reverses the Jacobian transform. See the comment at the
|
||||
// top of the file. If the point is ∞ it returns 0, 0.
|
||||
func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
|
||||
if z.Sign() == 0 {
|
||||
return new(big.Int), new(big.Int)
|
||||
}
|
||||
|
||||
zinv := new(big.Int).ModInverse(z, curve.P)
|
||||
zinvsq := new(big.Int).Mul(zinv, zinv)
|
||||
|
||||
xOut = new(big.Int).Mul(x, zinvsq)
|
||||
xOut.Mod(xOut, curve.P)
|
||||
zinvsq.Mul(zinvsq, zinv)
|
||||
yOut = new(big.Int).Mul(y, zinvsq)
|
||||
yOut.Mod(yOut, curve.P)
|
||||
return
|
||||
}
|
||||
|
||||
// Add returns (x1,y1) + (x2,y2)
|
||||
func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
z1 := zForAffine(x1, y1)
|
||||
z2 := zForAffine(x2, y2)
|
||||
return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
|
||||
}
|
||||
|
||||
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
|
||||
// (x2, y2, z2) and returns their sum, also in Jacobian form.
|
||||
func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
|
||||
// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
|
||||
x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
|
||||
if z1.Sign() == 0 {
|
||||
x3.Set(x2)
|
||||
y3.Set(y2)
|
||||
z3.Set(z2)
|
||||
return x3, y3, z3
|
||||
}
|
||||
if z2.Sign() == 0 {
|
||||
x3.Set(x1)
|
||||
y3.Set(y1)
|
||||
z3.Set(z1)
|
||||
return x3, y3, z3
|
||||
}
|
||||
|
||||
z1z1 := new(big.Int).Mul(z1, z1)
|
||||
z1z1.Mod(z1z1, curve.P)
|
||||
z2z2 := new(big.Int).Mul(z2, z2)
|
||||
z2z2.Mod(z2z2, curve.P)
|
||||
|
||||
u1 := new(big.Int).Mul(x1, z2z2)
|
||||
u1.Mod(u1, curve.P)
|
||||
u2 := new(big.Int).Mul(x2, z1z1)
|
||||
u2.Mod(u2, curve.P)
|
||||
h := new(big.Int).Sub(u2, u1)
|
||||
xEqual := h.Sign() == 0
|
||||
if h.Sign() == -1 {
|
||||
h.Add(h, curve.P)
|
||||
}
|
||||
i := new(big.Int).Lsh(h, 1)
|
||||
i.Mul(i, i)
|
||||
j := new(big.Int).Mul(h, i)
|
||||
|
||||
s1 := new(big.Int).Mul(y1, z2)
|
||||
s1.Mul(s1, z2z2)
|
||||
s1.Mod(s1, curve.P)
|
||||
s2 := new(big.Int).Mul(y2, z1)
|
||||
s2.Mul(s2, z1z1)
|
||||
s2.Mod(s2, curve.P)
|
||||
r := new(big.Int).Sub(s2, s1)
|
||||
if r.Sign() == -1 {
|
||||
r.Add(r, curve.P)
|
||||
}
|
||||
yEqual := r.Sign() == 0
|
||||
if xEqual && yEqual {
|
||||
return curve.doubleJacobian(x1, y1, z1)
|
||||
}
|
||||
r.Lsh(r, 1)
|
||||
v := new(big.Int).Mul(u1, i)
|
||||
|
||||
x3.Set(r)
|
||||
x3.Mul(x3, x3)
|
||||
x3.Sub(x3, j)
|
||||
x3.Sub(x3, v)
|
||||
x3.Sub(x3, v)
|
||||
x3.Mod(x3, curve.P)
|
||||
|
||||
y3.Set(r)
|
||||
v.Sub(v, x3)
|
||||
y3.Mul(y3, v)
|
||||
s1.Mul(s1, j)
|
||||
s1.Lsh(s1, 1)
|
||||
y3.Sub(y3, s1)
|
||||
y3.Mod(y3, curve.P)
|
||||
|
||||
z3.Add(z1, z2)
|
||||
z3.Mul(z3, z3)
|
||||
z3.Sub(z3, z1z1)
|
||||
z3.Sub(z3, z2z2)
|
||||
z3.Mul(z3, h)
|
||||
z3.Mod(z3, curve.P)
|
||||
|
||||
return x3, y3, z3
|
||||
}
|
||||
|
||||
// Double return 2(x1,y1)
|
||||
func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
z1 := zForAffine(x1, y1)
|
||||
return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
|
||||
}
|
||||
|
||||
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
|
||||
// returns its double, also in Jacobian form.
|
||||
func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
|
||||
// See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
|
||||
delta := new(big.Int).Mul(z, z)
|
||||
delta.Mod(delta, curve.P)
|
||||
gamma := new(big.Int).Mul(y, y)
|
||||
gamma.Mod(gamma, curve.P)
|
||||
alpha := new(big.Int).Sub(x, delta)
|
||||
if alpha.Sign() == -1 {
|
||||
alpha.Add(alpha, curve.P)
|
||||
}
|
||||
alpha2 := new(big.Int).Add(x, delta)
|
||||
alpha.Mul(alpha, alpha2)
|
||||
alpha2.Set(alpha)
|
||||
alpha.Lsh(alpha, 1)
|
||||
alpha.Add(alpha, alpha2)
|
||||
|
||||
beta := alpha2.Mul(x, gamma)
|
||||
|
||||
x3 := new(big.Int).Mul(alpha, alpha)
|
||||
beta8 := new(big.Int).Lsh(beta, 3)
|
||||
beta8.Mod(beta8, curve.P)
|
||||
x3.Sub(x3, beta8)
|
||||
if x3.Sign() == -1 {
|
||||
x3.Add(x3, curve.P)
|
||||
}
|
||||
x3.Mod(x3, curve.P)
|
||||
|
||||
z3 := new(big.Int).Add(y, z)
|
||||
z3.Mul(z3, z3)
|
||||
z3.Sub(z3, gamma)
|
||||
if z3.Sign() == -1 {
|
||||
z3.Add(z3, curve.P)
|
||||
}
|
||||
z3.Sub(z3, delta)
|
||||
if z3.Sign() == -1 {
|
||||
z3.Add(z3, curve.P)
|
||||
}
|
||||
z3.Mod(z3, curve.P)
|
||||
|
||||
beta.Lsh(beta, 2)
|
||||
beta.Sub(beta, x3)
|
||||
if beta.Sign() == -1 {
|
||||
beta.Add(beta, curve.P)
|
||||
}
|
||||
y3 := alpha.Mul(alpha, beta)
|
||||
|
||||
gamma.Mul(gamma, gamma)
|
||||
gamma.Lsh(gamma, 3)
|
||||
gamma.Mod(gamma, curve.P)
|
||||
|
||||
y3.Sub(y3, gamma)
|
||||
if y3.Sign() == -1 {
|
||||
y3.Add(y3, curve.P)
|
||||
}
|
||||
y3.Mod(y3, curve.P)
|
||||
|
||||
return x3, y3, z3
|
||||
}
|
||||
|
||||
// ScalarMult returns [k](Bx,By)
|
||||
func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
|
||||
printFuncName()
|
||||
|
||||
Bz := new(big.Int).SetInt64(1)
|
||||
x, y, z := new(big.Int), new(big.Int), new(big.Int)
|
||||
|
||||
for _, byte := range k {
|
||||
for bitNum := 0; bitNum < 8; bitNum++ {
|
||||
x, y, z = curve.doubleJacobian(x, y, z)
|
||||
if byte&0x80 == 0x80 {
|
||||
x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
|
||||
}
|
||||
byte <<= 1
|
||||
}
|
||||
}
|
||||
|
||||
return curve.affineFromJacobian(x, y, z)
|
||||
}
|
||||
|
||||
// ScalarBaseMult returns [k](Gx,Gy)
|
||||
func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
printFuncName()
|
||||
return curve.ScalarMult(curve.Gx, curve.Gy, k)
|
||||
}
|
||||
|
||||
// CombinedMult returns [baseScalar](Gx,Gy) + [scalar](bigX, bigY)
|
||||
func (curve *CurveParams) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
|
||||
printFuncName()
|
||||
t1, t2 := curve.ScalarBaseMult(baseScalar)
|
||||
t3, t4 := curve.ScalarMult(bigX, bigY, scalar)
|
||||
x, y = curve.Add(t1, t2, t3, t4)
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package ec256
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFuzz(t *testing.T) {
|
||||
|
||||
ec := CurveSM2()
|
||||
ge := ec.Params()
|
||||
|
||||
var scalar1 [32]byte
|
||||
var scalar2 [32]byte
|
||||
var timeout *time.Timer
|
||||
|
||||
timeout = time.NewTimer(10 * time.Second)
|
||||
count := 0
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-timeout.C:
|
||||
break loop
|
||||
default:
|
||||
count++
|
||||
if count%100 == 0 {
|
||||
fmt.Println("Tested for", count, "times")
|
||||
}
|
||||
|
||||
rand.Read(scalar1[:])
|
||||
rand.Read(scalar2[:])
|
||||
|
||||
x, y := ec.ScalarBaseMult(scalar1[:])
|
||||
x2, y2 := ge.ScalarBaseMult(scalar1[:])
|
||||
|
||||
xx, yy := ec.ScalarMult(x, y, scalar2[:])
|
||||
xx2, yy2 := ge.ScalarMult(x2, y2, scalar2[:])
|
||||
|
||||
if x.Cmp(x2) != 0 || y.Cmp(y2) != 0 {
|
||||
t.Fatalf("ScalarBaseMult does not match reference result with scalar: %x, please report this error to security@golang.org", scalar1)
|
||||
}
|
||||
|
||||
if xx.Cmp(xx2) != 0 || yy.Cmp(yy2) != 0 {
|
||||
t.Fatalf("ScalarMult does not match reference result with scalars: %x and %x, please report this error to security@golang.org", scalar1, scalar2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Total test %d times\n", count)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package ec256
|
||||
|
||||
import "math/big"
|
||||
|
||||
func bigFromBase16(s string) *big.Int {
|
||||
n, _ := new(big.Int).SetString(s, 16)
|
||||
return n
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: encryption.go
|
||||
///
|
||||
/// \brief: SM2加解密
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/utils/objectpool"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm2/ec256"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
// DefaultCipherLength is the default cipher length when init
|
||||
const DefaultCipherLength = 128
|
||||
|
||||
// Cipher 密文结构
|
||||
// (x,y): C1
|
||||
// hash: C3
|
||||
// c: C2
|
||||
type Cipher struct {
|
||||
X, Y *big.Int
|
||||
Hash [32]byte
|
||||
C []byte
|
||||
}
|
||||
|
||||
// NewCipher return a new instance of Cipher
|
||||
func NewCipher() *Cipher {
|
||||
return &Cipher{
|
||||
X: new(big.Int),
|
||||
Y: new(big.Int),
|
||||
C: make([]byte, 0, DefaultCipherLength),
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize reduce C1's x,y
|
||||
func (c *Cipher) Normalize() *Cipher {
|
||||
if c.X != nil {
|
||||
c.X.Mod(c.X, orderN)
|
||||
}
|
||||
if c.Y != nil {
|
||||
c.Y.Mod(c.Y, orderN)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Set c to src
|
||||
func (c *Cipher) Set(src *Cipher) *Cipher {
|
||||
c.X.Set(src.X)
|
||||
c.Y.Set(src.Y)
|
||||
c.Hash = src.Hash
|
||||
c.C = append(c.C[:0], src.C...)
|
||||
return c
|
||||
}
|
||||
|
||||
// cipherASN1 helper struct for ASN.1 encoding/decoding Cipher using asn1.Marshal.
|
||||
type cipherASN1 struct {
|
||||
X, Y *big.Int
|
||||
Hash []byte
|
||||
C []byte
|
||||
}
|
||||
|
||||
// MarshalASN1 marshal c to DER encoded and append to data.
|
||||
func (c *Cipher) MarshalASN1() ([]byte, error) {
|
||||
return asn1.Marshal(cipherASN1{
|
||||
X: c.X,
|
||||
Y: c.Y,
|
||||
Hash: c.Hash[:],
|
||||
C: c.C,
|
||||
})
|
||||
}
|
||||
|
||||
// UnmarshalASN1 unmarshal c from DER encoded data.
|
||||
func (c *Cipher) UnmarshalASN1(b []byte) (rest []byte, err error) {
|
||||
var ca cipherASN1
|
||||
|
||||
rest, err = asn1.Unmarshal(b, &ca)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
c.X = ca.X
|
||||
c.Y = ca.Y
|
||||
copy(c.Hash[:], ca.Hash)
|
||||
c.C = append(c.C, ca.C...)
|
||||
return rest, nil
|
||||
}
|
||||
|
||||
// MarshalUtil implements the gcl/util/encoding/UtilMarshaler interface
|
||||
func (c *Cipher) MarshalUtil(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
data = make([]byte, 0, 2*ECCRefMaxLen+32+4+DefaultCipherLength)
|
||||
}
|
||||
c.X.Mod(c.X, orderN)
|
||||
xBytes := gmath.BigIntToNByte(c.X, ECCRefMaxLen)
|
||||
data = append(data, xBytes...)
|
||||
|
||||
c.Y.Mod(c.Y, orderN)
|
||||
yBytes := gmath.BigIntToNByte(c.Y, ECCRefMaxLen)
|
||||
data = append(data, yBytes...)
|
||||
data = append(data, c.Hash[:]...)
|
||||
buf := []byte{0, 0, 0, 0}
|
||||
Endian.PutUint32(buf, uint32(len(c.C)))
|
||||
data = append(data, buf...)
|
||||
data = append(data, c.C...)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalUtil marshal the Cipher append to data
|
||||
func (c *Cipher) UnmarshalUtil(data []byte) (uint64, error) {
|
||||
n := uint64(0) // consumed bytes.
|
||||
if len(data) < 2*ECCRefMaxLen+32+4 {
|
||||
return 0, gerrors.WithAnnotatingf(ErrInvalidInput, "input(%d bytes) must be at least %d bytes", len(data), 2*ECCRefMaxLen+32+4)
|
||||
}
|
||||
|
||||
x := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
data = data[ECCRefMaxLen:]
|
||||
n += ECCRefMaxLen
|
||||
|
||||
y := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
data = data[ECCRefMaxLen:]
|
||||
n += ECCRefMaxLen
|
||||
|
||||
if x.Cmp(orderN) >= 0 || x.Sign() == 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "x is bigger then the order N")
|
||||
}
|
||||
if y.Cmp(orderN) >= 0 || y.Sign() == 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "y is bigger then the order N")
|
||||
}
|
||||
if !sm2Curve.IsOnCurve(x, y) {
|
||||
return 0, gerrors.WithAnnotating(ErrDecFailed, "C1 is not a valid curve point")
|
||||
}
|
||||
|
||||
c.X.Set(x)
|
||||
c.Y.Set(y)
|
||||
|
||||
copy(c.Hash[:], data[:32])
|
||||
data = data[32:]
|
||||
n += 32
|
||||
|
||||
clen := Endian.Uint32(data)
|
||||
data = data[4:]
|
||||
n += 4
|
||||
|
||||
if len(data) < int(clen) {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "C2 is too short")
|
||||
}
|
||||
|
||||
c.C = append(c.C[:0], data[:clen]...)
|
||||
n += uint64(clen)
|
||||
// return the rest data
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface
|
||||
// 返回字节符合GMT 0018的定义。
|
||||
// x||y||m||L||c
|
||||
func (c *Cipher) MarshalBinary() ([]byte, error) {
|
||||
//data := make([]byte, 2*ECCRefMaxLen+32+4+len(c.C))
|
||||
data := objectpool.GetBytes()
|
||||
c.X.Mod(c.X, orderN)
|
||||
xBytes := gmath.BigIntToNByte(c.X, ECCRefMaxLen)
|
||||
data = append(data, xBytes...)
|
||||
|
||||
c.Y.Mod(c.Y, orderN)
|
||||
yBytes := gmath.BigIntToNByte(c.Y, ECCRefMaxLen)
|
||||
data = append(data, yBytes...)
|
||||
data = append(data, c.Hash[:]...)
|
||||
buf := []byte{0, 0, 0, 0}
|
||||
Endian.PutUint32(buf, uint32(len(c.C)))
|
||||
data = append(data, buf...)
|
||||
data = append(data, c.C...)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
// 输入字节应符合GMT 0018的定义。
|
||||
func (c *Cipher) UnmarshalBinary(data []byte) error {
|
||||
if len(data) < 2*ECCRefMaxLen+32+4 {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "input(%d bytes) must be at least %d bytes", len(data), 2*ECCRefMaxLen+32+4)
|
||||
}
|
||||
|
||||
x := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
data = data[ECCRefMaxLen:]
|
||||
y := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
data = data[ECCRefMaxLen:]
|
||||
|
||||
if x.Cmp(orderN) >= 0 || x.Sign() == 0 {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "x is bigger then the order N")
|
||||
}
|
||||
if y.Cmp(orderN) >= 0 || y.Sign() == 0 {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "y is bigger then the order N")
|
||||
}
|
||||
if !sm2Curve.IsOnCurve(x, y) {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "(x,y) is not on the curve")
|
||||
}
|
||||
|
||||
c.X.Set(x)
|
||||
c.Y.Set(y)
|
||||
|
||||
copy(c.Hash[:], data[:32])
|
||||
data = data[32:]
|
||||
|
||||
clen := Endian.Uint32(data)
|
||||
data = data[4:]
|
||||
|
||||
if len(data) < int(clen) {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "C2 is too short")
|
||||
}
|
||||
|
||||
c.C = append(c.C[:0], data[:clen]...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes 转换密文结构为byte切片
|
||||
func (c *Cipher) Bytes() []byte {
|
||||
var buf bytes.Buffer
|
||||
buf.Write(gmath.BigIntToNByte(c.X, byteSize))
|
||||
buf.Write(gmath.BigIntToNByte(c.Y, byteSize))
|
||||
buf.Write(c.Hash[:])
|
||||
buf.Write(c.C)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// SetBytes 转换[]byte为Cipher
|
||||
func (c *Cipher) SetBytes(data []byte) error {
|
||||
if len(data) < 2*byteSize+32 {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "input(%d bytes) must be at least %d bytes", len(data), 2*byteSize+32)
|
||||
}
|
||||
if c.X == nil {
|
||||
c.X = new(big.Int)
|
||||
}
|
||||
if c.Y == nil {
|
||||
c.Y = new(big.Int)
|
||||
}
|
||||
c.X.SetBytes(data[:byteSize])
|
||||
c.Y.SetBytes(data[byteSize : 2*byteSize])
|
||||
copy(c.Hash[:], data[2*byteSize:2*byteSize+32])
|
||||
c.C = append(c.C[:0], data[2*byteSize+32:]...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String return a readable string
|
||||
func (c *Cipher) String() string {
|
||||
var buf strings.Builder
|
||||
buf.WriteString("x: ")
|
||||
buf.WriteString(hex.EncodeToString(c.X.Bytes()))
|
||||
buf.WriteString("\ny: ")
|
||||
buf.WriteString(hex.EncodeToString(c.Y.Bytes()))
|
||||
buf.WriteString("\nc: ")
|
||||
buf.WriteString(hex.EncodeToString(c.C))
|
||||
buf.WriteString("\nhash: ")
|
||||
buf.WriteString(hex.EncodeToString(c.Hash[:]))
|
||||
|
||||
return buf.String()
|
||||
// return hex.EncodeToString(c.Bytes())
|
||||
}
|
||||
|
||||
// Encrypt 加密
|
||||
func Encrypt(pk *PublicKey, data, rnd []byte) (*Cipher, error) {
|
||||
// k := new(big.Int).SetBytes(rnd)
|
||||
if rnd == nil || len(rnd) < byteSize {
|
||||
rnd = grand.GetRandom(byteSize)
|
||||
}
|
||||
// if !pk.IsValid() {
|
||||
// return nil, gerrors.ERR_SM2_INVALID_PUBKEY
|
||||
// }
|
||||
var x, y *big.Int
|
||||
cipher := new(Cipher)
|
||||
xBytes := make([]byte, byteSize)
|
||||
yBytes := make([]byte, byteSize)
|
||||
var err error
|
||||
outer:
|
||||
for {
|
||||
cipher.X, cipher.Y = sm2Curve.ScalarBaseMult(rnd[:byteSize])
|
||||
x, y = sm2Curve.ScalarMult(pk.X, pk.Y, rnd[:byteSize])
|
||||
if err = gmath.FillBytes(x, xBytes); err != nil {
|
||||
return nil, gerrors.WithAnnotating(ErrEncFailed, "x is too big")
|
||||
}
|
||||
|
||||
if err = gmath.FillBytes(y, yBytes); err != nil {
|
||||
return nil, gerrors.WithAnnotating(ErrEncFailed, "y is too big")
|
||||
}
|
||||
|
||||
cipher.C = make([]byte, len(data))
|
||||
if len(data) == 0 {
|
||||
break
|
||||
}
|
||||
Kdf(cipher.C, xBytes, yBytes)
|
||||
for _, k := range cipher.C {
|
||||
if k != 0 {
|
||||
break outer
|
||||
}
|
||||
}
|
||||
if _, err = grand.GenerateRandom(rnd); err != nil {
|
||||
return nil, gerrors.ChainErrors(gerrors.WithAnnotating(ErrEncFailed, "generate random failed"), err)
|
||||
}
|
||||
}
|
||||
|
||||
// 两个对C的遍历,上面那个不会执行太多。
|
||||
for i := range cipher.C {
|
||||
cipher.C[i] ^= data[i]
|
||||
}
|
||||
|
||||
digest := sm3.New()
|
||||
// need padding 0 if x < 2*248
|
||||
digest.Write(xBytes)
|
||||
digest.Write(data)
|
||||
digest.Write(yBytes)
|
||||
digest.Sum(cipher.Hash[:0])
|
||||
return cipher, nil
|
||||
}
|
||||
|
||||
// Decrypt 解密
|
||||
// 返回明文
|
||||
func Decrypt(sk *PrivateKey, cipher *Cipher) (plainText []byte, err error) {
|
||||
|
||||
if !ec256.Curve256.IsOnCurve(cipher.X, cipher.Y) {
|
||||
return nil, gerrors.WithAnnotating(ErrDecFailed, "C1 is not a valid curve point")
|
||||
}
|
||||
|
||||
x, y := ec256.Curve256.ScalarMult(cipher.X, cipher.Y, sk.Bytes())
|
||||
|
||||
return Decrypt_aux(x, y, cipher)
|
||||
}
|
||||
|
||||
// Decrypt_aux common decrypt function
|
||||
func Decrypt_aux(x, y *big.Int, cipher *Cipher) (plainText []byte, err error) {
|
||||
plainText = make([]byte, len(cipher.C))
|
||||
xBytes := make([]byte, byteSize)
|
||||
yBytes := make([]byte, byteSize)
|
||||
if err = gmath.FillBytes(x, xBytes); err != nil {
|
||||
return nil, gerrors.WithAnnotating(ErrDecFailed, "x is too big")
|
||||
}
|
||||
|
||||
if err = gmath.FillBytes(y, yBytes); err != nil {
|
||||
return nil, gerrors.WithAnnotating(ErrDecFailed, "y is too big")
|
||||
}
|
||||
|
||||
if len(plainText) == 0 {
|
||||
goto Next
|
||||
}
|
||||
if err := Kdf(plainText, xBytes, yBytes); err != nil {
|
||||
return nil, gerrors.ChainErrors(ErrDecFailed, err)
|
||||
}
|
||||
for _, k := range plainText {
|
||||
if k != 0 {
|
||||
goto Next
|
||||
}
|
||||
}
|
||||
return nil, gerrors.WithAnnotating(ErrDecFailed, "t is all zero while decryption")
|
||||
Next:
|
||||
for i := range plainText {
|
||||
plainText[i] ^= cipher.C[i]
|
||||
}
|
||||
|
||||
digest := sm3.New()
|
||||
digest.Write(xBytes)
|
||||
digest.Write(plainText)
|
||||
digest.Write(yBytes)
|
||||
d := digest.Sum(nil)
|
||||
if !bytes.Equal(d, cipher.Hash[:]) {
|
||||
return nil, gerrors.WithAnnotating(ErrDecFailed, "mac check failed (U!=C3) while decryption")
|
||||
}
|
||||
return plainText, nil
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"xdx.jelly/xgcl/sm"
|
||||
)
|
||||
|
||||
type endian struct {
|
||||
isBigEndian bool
|
||||
}
|
||||
|
||||
func (e *endian) PutUint32(b []byte, v uint32) {
|
||||
if e.isBigEndian {
|
||||
binary.BigEndian.PutUint32(b, v)
|
||||
} else {
|
||||
binary.LittleEndian.PutUint32(b, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *endian) Uint32(b []byte) uint32 {
|
||||
if e.isBigEndian {
|
||||
return binary.BigEndian.Uint32(b)
|
||||
}
|
||||
|
||||
return binary.LittleEndian.Uint32(b)
|
||||
}
|
||||
|
||||
var (
|
||||
// Endian is the endian when marshal a int, default is big endian
|
||||
Endian = endian{true}
|
||||
)
|
||||
|
||||
// SetToBigEndian 将端序设置为大端序
|
||||
func SetToBigEndian() {
|
||||
Endian.isBigEndian = true
|
||||
}
|
||||
|
||||
// SetToLittleEndian 设置为小端序
|
||||
func SetToLittleEndian() {
|
||||
Endian.isBigEndian = false
|
||||
}
|
||||
|
||||
// SetToDefaultEndian 恢复默认端序-大端
|
||||
func SetToDefaultEndian() {
|
||||
Endian.isBigEndian = true
|
||||
}
|
||||
|
||||
func init() {
|
||||
sm.RegisterCallBack(SetToBigEndian, SetToLittleEndian, SetToDefaultEndian)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package sm2
|
||||
|
||||
import "xdx.jelly/xgcl/gerrors"
|
||||
|
||||
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
|
||||
type ErrorCode gerrors.ErrorCode
|
||||
|
||||
func (e ErrorCode) Error() string {
|
||||
return gerrors.Format(uint32(e), e.String())
|
||||
}
|
||||
|
||||
// error codes
|
||||
const (
|
||||
ErrInvalidInput ErrorCode = 0x01002000 + iota //输入不合法
|
||||
ErrInvalidCurve //不是SM2曲线
|
||||
ErrInvalidPoint //不是SM2曲线上的点
|
||||
ErrDecodeASN1Failed //ASN.1解码失败
|
||||
ErrInvalidPublicKey //SM2公钥不合法
|
||||
ErrEncFailed //SM2加密失败
|
||||
ErrDecFailed //SM2解密失败
|
||||
ErrKeyExchangeFailed //SM2密钥交换失败
|
||||
ErrRandomError //输入随机数不合适,重新产生随机数
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
|
||||
|
||||
package sm2
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ErrInvalidInput-16785408]
|
||||
_ = x[ErrInvalidCurve-16785409]
|
||||
_ = x[ErrInvalidPoint-16785410]
|
||||
_ = x[ErrDecodeASN1Failed-16785411]
|
||||
_ = x[ErrInvalidPublicKey-16785412]
|
||||
_ = x[ErrEncFailed-16785413]
|
||||
_ = x[ErrDecFailed-16785414]
|
||||
_ = x[ErrKeyExchangeFailed-16785415]
|
||||
_ = x[ErrRandomError-16785416]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "输入不合法不是SM2曲线不是SM2曲线上的点ASN.1解码失败SM2公钥不合法SM2加密失败SM2解密失败SM2密钥交换失败输入随机数不合适,重新产生随机数"
|
||||
|
||||
var _ErrorCode_index = [...]uint8{0, 15, 30, 54, 71, 89, 104, 119, 140, 188}
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 16785408
|
||||
if i >= ErrorCode(len(_ErrorCode_index)-1) {
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i+16785408), 10) + ")"
|
||||
}
|
||||
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
|
||||
}
|
||||
+392
@@ -0,0 +1,392 @@
|
||||
package sm2
|
||||
|
||||
// sm2_golib implement the go-stdlib style sm2 Signer and verifier.
|
||||
// Notice: the original Sign and Verify is replaced by
|
||||
// func Sign() ==> func SignWithReader()
|
||||
// func Verify() ==> func VerifyWithRS()
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/cryptobyte/asn1"
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/internal/randutil"
|
||||
)
|
||||
|
||||
// SM2.PublicKey(PrivateKey) and ecdsa.PublicKey(PrivateKey) is essentially the same.
|
||||
// But we need a transform between them, to call their methods.
|
||||
// Note the underlying data are shared.
|
||||
func (pub *PublicKey) ViewFrom(ecPub *ecdsa.PublicKey) *PublicKey {
|
||||
return pub.From(ecPub)
|
||||
}
|
||||
|
||||
func (pub *PublicKey) From(ecPub *ecdsa.PublicKey) *PublicKey {
|
||||
if ecPub == nil {
|
||||
return nil
|
||||
}
|
||||
pub.Curve = ecPub.Curve
|
||||
pub.X = ecPub.X
|
||||
pub.Y = ecPub.Y
|
||||
return pub
|
||||
}
|
||||
|
||||
func (pub *PublicKey) View() *ecdsa.PublicKey {
|
||||
return pub.Into()
|
||||
}
|
||||
|
||||
func (pub *PublicKey) Into() *ecdsa.PublicKey {
|
||||
return &ecdsa.PublicKey{
|
||||
Curve: pub.Curve,
|
||||
X: pub.X,
|
||||
Y: pub.Y,
|
||||
}
|
||||
}
|
||||
|
||||
func (pri *PrivateKey) ViewFrom(ecPri *ecdsa.PrivateKey) *PrivateKey {
|
||||
return pri.From(ecPri)
|
||||
}
|
||||
|
||||
func (pri *PrivateKey) From(ecPri *ecdsa.PrivateKey) *PrivateKey {
|
||||
if ecPri == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
pri.PublicKey.Curve = ecPri.PublicKey.Curve
|
||||
pri.PublicKey.X = ecPri.PublicKey.X
|
||||
pri.PublicKey.Y = ecPri.PublicKey.Y
|
||||
pri.D = ecPri.D
|
||||
return pri
|
||||
}
|
||||
|
||||
func (pri *PrivateKey) View() *ecdsa.PrivateKey {
|
||||
return pri.Into()
|
||||
}
|
||||
func (pri *PrivateKey) Into() *ecdsa.PrivateKey {
|
||||
return &ecdsa.PrivateKey{
|
||||
PublicKey: ecdsa.PublicKey{
|
||||
Curve: pri.Curve,
|
||||
X: pri.X,
|
||||
Y: pri.Y,
|
||||
},
|
||||
D: pri.D,
|
||||
}
|
||||
}
|
||||
|
||||
// A invertible implements fast inverse mod Curve.Params().N
|
||||
type invertible interface {
|
||||
// Inverse returns the inverse of k in GF(P)
|
||||
Inverse(k *big.Int) *big.Int
|
||||
}
|
||||
|
||||
// combinedMult implements fast multiplication S1*g + S2*p (g - generator, p - arbitrary point)
|
||||
type combinedMult interface {
|
||||
CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
|
||||
}
|
||||
|
||||
// Any methods implemented on PublicKey might need to also be implemented on
|
||||
// PrivateKey, as the latter embeds the former and will expose its methods.
|
||||
|
||||
// Equal reports whether pub and x have the same value.
|
||||
//
|
||||
// Two keys are only considered to have the same value if they have the same Curve value.
|
||||
// Note that for example elliptic.P256() and elliptic.P256().Params() are different
|
||||
// values, as the latter is a generic not constant time implementation.
|
||||
func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
|
||||
xx, ok := x.(*PublicKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return pub.X.Cmp(xx.X) == 0 && pub.Y.Cmp(xx.Y) == 0 &&
|
||||
// Standard library Curve implementations are singletons, so this check
|
||||
// will work for those. Other Curves might be equivalent even if not
|
||||
// singletons, but there is no definitive way to check for that, and
|
||||
// better to err on the side of safety.
|
||||
pub.Curve == xx.Curve
|
||||
}
|
||||
|
||||
// randFieldElement returns a random element of the field underlying the given
|
||||
// curve using the procedure given in [NSA] A.2.1.
|
||||
func randFieldElement(c elliptic.Curve, r io.Reader) (k *big.Int, err error) {
|
||||
params := c.Params()
|
||||
for {
|
||||
k, err = rand.Int(r, params.N)
|
||||
if err != nil || k.Sign() != 0 {
|
||||
return k, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateKey generates a public and private key pair.
|
||||
func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
|
||||
if c != Curve() {
|
||||
return nil, gerrors.WithAnnotating(ErrInvalidCurve, "input curve is not sm2 curve")
|
||||
}
|
||||
k, err := randFieldElement(c, rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
priv := new(PrivateKey)
|
||||
priv.PublicKey.Curve = c
|
||||
priv.D = k
|
||||
priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
// Public returns the public key corresponding to priv.
|
||||
func (priv *PrivateKey) Public() crypto.PublicKey {
|
||||
if priv.PublicKey.X == nil {
|
||||
x, y := Curve().ScalarBaseMult(priv.D.Bytes())
|
||||
priv.PublicKey = PublicKey{Curve: Curve(), X: x, Y: y}
|
||||
}
|
||||
return &priv.PublicKey
|
||||
}
|
||||
|
||||
// Equal reports whether priv and x have the same value.
|
||||
//
|
||||
// See PublicKey.Equal for details on how Curve is compared.
|
||||
func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
|
||||
xx, ok := x.(*PrivateKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return priv.PublicKey.Equal(&xx.PublicKey) && priv.D.Cmp(xx.D) == 0
|
||||
}
|
||||
|
||||
// Sign signs digest with priv, reading randomness from rand. The opts argument
|
||||
// is not currently used but, in keeping with the crypto.Signer interface,
|
||||
// should be the hash function used to digest the message.
|
||||
//
|
||||
// This method implements crypto.Signer, which is an interface to support keys
|
||||
// where the private part is kept in, for example, a hardware module. Common
|
||||
// uses should use the Sign function in this package directly.
|
||||
func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
|
||||
r, s, err := SignWithReader(rand, priv, digest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1BigInt(r)
|
||||
b.AddASN1BigInt(s)
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
// This method implements crypto.Decrypter.
|
||||
// msg 应该是sm2使用规范中的密文结构
|
||||
func (priv *PrivateKey) Decrypt(rand io.Reader, msg []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
|
||||
var cipher Cipher
|
||||
_, err = cipher.UnmarshalASN1(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return Decrypt(priv, &cipher)
|
||||
}
|
||||
|
||||
// hashToInt converts a hash value to an integer. There is some disagreement
|
||||
// about how this is done. [NSA] suggests that this is done in the obvious
|
||||
// manner, but [SECG] truncates the hash to the bit-length of the curve order
|
||||
// first. We follow [SECG] because that's what OpenSSL does. Additionally,
|
||||
// OpenSSL right shifts excess bits from the number if the hash is too large
|
||||
// and we mirror that too.
|
||||
func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
|
||||
orderBits := c.Params().N.BitLen()
|
||||
orderBytes := (orderBits + 7) / 8
|
||||
if len(hash) > orderBytes {
|
||||
hash = hash[:orderBytes]
|
||||
}
|
||||
|
||||
ret := new(big.Int).SetBytes(hash)
|
||||
excess := len(hash)*8 - orderBits
|
||||
if excess > 0 {
|
||||
ret.Rsh(ret, uint(excess))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
var errZeroParam = errors.New("zero parameter")
|
||||
|
||||
const (
|
||||
aesIV = "IV for ECDSA CTR"
|
||||
)
|
||||
|
||||
// SignWithReader signs a hash (which should be the result of hashing a larger message)
|
||||
// using the private key, priv. If the hash is longer than the bit-length of the
|
||||
// private key's curve order, the hash will be truncated to that length. It
|
||||
// returns the signature as a pair of integers. The security of the private key
|
||||
// depends on the entropy of rand.
|
||||
//
|
||||
// It's the same of Sign in stdlib
|
||||
func SignWithReader(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
|
||||
randutil.MaybeReadByte(rand)
|
||||
|
||||
// Get min(log2(q) / 2, 256) bits of entropy from rand.
|
||||
entropylen := (priv.Curve.Params().BitSize + 7) / 16
|
||||
if entropylen > 32 {
|
||||
entropylen = 32
|
||||
}
|
||||
entropy := make([]byte, entropylen)
|
||||
_, err = io.ReadFull(rand, entropy)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Initialize an SHA-512 hash context; digest ...
|
||||
md := sha512.New()
|
||||
md.Write(priv.D.Bytes()) // the private key,
|
||||
md.Write(entropy) // the entropy,
|
||||
md.Write(hash) // and the input hash;
|
||||
key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512),
|
||||
// which is an indifferentiable MAC.
|
||||
|
||||
// Create an AES-CTR instance to use as a CSPRNG.
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Create a CSPRNG that xors a stream of zeros with
|
||||
// the output of the AES-CTR instance.
|
||||
csprng := cipher.StreamReader{
|
||||
R: zeroReader,
|
||||
S: cipher.NewCTR(block, []byte(aesIV)),
|
||||
}
|
||||
|
||||
// See [NSA] 3.4.1
|
||||
c := priv.PublicKey.Curve
|
||||
return sign(priv, &csprng, c, hash)
|
||||
}
|
||||
|
||||
func signGeneric(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
|
||||
N := c.Params().N
|
||||
if N.Sign() == 0 {
|
||||
return nil, nil, errZeroParam
|
||||
}
|
||||
var k *big.Int
|
||||
e := hashToInt(hash, c)
|
||||
for {
|
||||
for {
|
||||
k, err = randFieldElement(c, *csprng)
|
||||
if err != nil {
|
||||
r = nil
|
||||
return
|
||||
}
|
||||
|
||||
r, _ = priv.Curve.ScalarBaseMult(k.Bytes())
|
||||
r.Add(r, e)
|
||||
r.Mod(r, N)
|
||||
if r.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
s = new(big.Int).Add(priv.D, one) // s = (k-rd)/(1+d)=(k+r)/(1+d) - r
|
||||
if in, ok := priv.Curve.(invertible); ok {
|
||||
s = in.Inverse(s)
|
||||
} else {
|
||||
fermatInverse(s, N) // N != 0
|
||||
}
|
||||
k.Add(k, r)
|
||||
s.Mul(s, k)
|
||||
s.Sub(s, r)
|
||||
s.Mod(s, N) // N != 0
|
||||
if s.Sign() != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SignASN1 signs a hash (which should be the result of hashing a larger message)
|
||||
// using the private key, priv. If the hash is longer than the bit-length of the
|
||||
// private key's curve order, the hash will be truncated to that length. It
|
||||
// returns the ASN.1 encoded signature. The security of the private key
|
||||
// depends on the entropy of rand.
|
||||
func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
|
||||
return priv.Sign(rand, hash, nil)
|
||||
}
|
||||
|
||||
// Verify verifies the signature in r, s of hash using the public key, pub. Its
|
||||
// return value records whether the signature is valid.
|
||||
func VerifyWithRS(pub *PublicKey, hash []byte, r, s *big.Int) bool {
|
||||
// See [NSA] 3.4.2
|
||||
c := pub.Curve
|
||||
N := c.Params().N
|
||||
|
||||
if r.Sign() <= 0 || s.Sign() <= 0 {
|
||||
return false
|
||||
}
|
||||
if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
|
||||
return false
|
||||
}
|
||||
return verify(pub, c, hash, r, s)
|
||||
}
|
||||
|
||||
func verifyGeneric(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
|
||||
e := hashToInt(hash, c)
|
||||
N := c.Params().N
|
||||
|
||||
t := new(big.Int).Add(r, s)
|
||||
|
||||
// Check if implements S1*g + S2*p
|
||||
var x, y *big.Int
|
||||
if opt, ok := c.(combinedMult); ok {
|
||||
x, y = opt.CombinedMult(pub.X, pub.Y, s.Bytes(), t.Bytes())
|
||||
} else {
|
||||
x1, y1 := c.ScalarBaseMult(s.Bytes())
|
||||
x2, y2 := c.ScalarMult(pub.X, pub.Y, t.Bytes())
|
||||
x, y = c.Add(x1, y1, x2, y2)
|
||||
}
|
||||
x.Add(e, x)
|
||||
x.Mod(x, N)
|
||||
if x.Sign() == 0 && y.Sign() == 0 {
|
||||
return false
|
||||
}
|
||||
return x.Cmp(r) == 0
|
||||
}
|
||||
|
||||
// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
|
||||
// public key, pub. Its return value records whether the signature is valid.
|
||||
func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
|
||||
var (
|
||||
r, s = &big.Int{}, &big.Int{}
|
||||
inner cryptobyte.String
|
||||
)
|
||||
input := cryptobyte.String(sig)
|
||||
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
||||
!input.Empty() ||
|
||||
!inner.ReadASN1Integer(r) ||
|
||||
!inner.ReadASN1Integer(s) ||
|
||||
!inner.Empty() {
|
||||
return false
|
||||
}
|
||||
return VerifyWithRS(pub, hash, r, s)
|
||||
}
|
||||
|
||||
type zr struct {
|
||||
io.Reader
|
||||
}
|
||||
|
||||
// Read replaces the contents of dst with zeros.
|
||||
func (z *zr) Read(dst []byte) (n int, err error) {
|
||||
for i := range dst {
|
||||
dst[i] = 0
|
||||
}
|
||||
return len(dst), nil
|
||||
}
|
||||
|
||||
var zeroReader = &zr{}
|
||||
@@ -0,0 +1,15 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func sign(priv *PrivateKey, csprng *cipher.StreamReader, c elliptic.Curve, hash []byte) (r, s *big.Int, err error) {
|
||||
return signGeneric(priv, csprng, c, hash)
|
||||
}
|
||||
|
||||
func verify(pub *PublicKey, c elliptic.Curve, hash []byte, r, s *big.Int) bool {
|
||||
return verifyGeneric(pub, c, hash, r, s)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package sm2_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
)
|
||||
|
||||
func TestIssue8(t *testing.T) {
|
||||
for i := 0; i < 100000000; i++ {
|
||||
//err := gcl.SDF_GenerateKeyPair_ECC(nil, sdf.SGD_SM2, 256, pubKey, priKey)
|
||||
//if err != nil {
|
||||
// fmt.Println("gcl.SDF_GenerateKeyPair_ECC " + err.Error())
|
||||
// return
|
||||
//}
|
||||
|
||||
////生成32字节随机数
|
||||
//rnd := grand.GetRandom(32)
|
||||
//
|
||||
////使用随机数生成私钥
|
||||
//pri, err := sm2.GenPrivateKey(grand.Reader)
|
||||
//if err != nil {
|
||||
// fmt.Println("sm2.GenPrivateKey " + err.Error())
|
||||
// return
|
||||
//}
|
||||
//
|
||||
////使用私钥生成公钥
|
||||
//pub := sm2.GenPublicKey(pri)
|
||||
pri, pub, err := sm2.GenerateKeyPairs(grand.Reader)
|
||||
if err != nil {
|
||||
fmt.Println("sm2.GenerateKeyPairs " + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
//publicKey, _ := convert.ECCrefPublicKeytoPublicKey(pubKey)
|
||||
//privateKey, _ := convert.ECCrefPrivateKeytoPrivateKey(priKey)
|
||||
|
||||
data := "12345678901234561234567890123456"
|
||||
r, s, err := sm2.SignWithReader(grand.Reader, pri, []byte(data))
|
||||
if err != nil {
|
||||
fmt.Println("sm2.SignWithReader " + err.Error())
|
||||
return
|
||||
}
|
||||
//signValue, err := sm2.Sign([]byte(data), grand.GetRandom(32), pri)
|
||||
//if err != nil {
|
||||
// fmt.Println("sm2.Sign " + err.Error())
|
||||
// return
|
||||
//}
|
||||
|
||||
signValue := &sm2.Signature{
|
||||
R: r,
|
||||
S: s,
|
||||
}
|
||||
|
||||
if !sm2.Verify([]byte(data), pub, signValue) {
|
||||
fmt.Println("sm2.Verify error")
|
||||
fmt.Printf("pub = %s\n", pub.String() /* sdf.PublicKeyStructToByte(pubKey)*/)
|
||||
fmt.Printf("pri = %s\n", pri.String() /* sdf.PrivateKeyStructToByte(priKey)*/)
|
||||
return
|
||||
}
|
||||
if i%100000 == 0 {
|
||||
fmt.Printf("i = %d\n", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
+543
@@ -0,0 +1,543 @@
|
||||
///
|
||||
/// Copyright (c) 2018 xdx. All rights reserved.
|
||||
///
|
||||
/// \file: key.go
|
||||
///
|
||||
/// \brief: SM2密钥结构
|
||||
///
|
||||
/// \author: xdx
|
||||
///
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/internal"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////// PrivateKey
|
||||
|
||||
// PrivateKey 私钥, 使用NewPrivateKey生成
|
||||
type PrivateKey struct {
|
||||
// it is dangerous that &PrivateKey = &PrivateKey.PublicKey
|
||||
// We sometimes pass &PrivateKey.PublicKey to caller and he could read the D.
|
||||
// It is better to use *PublicKey.
|
||||
// But we are along with crypto/ecdsa.PrivateKey
|
||||
PublicKey
|
||||
D *big.Int // use D (not anonymous) to hide big.Int's methods
|
||||
}
|
||||
|
||||
// NewPrivateKey return a new PrivateKey instance
|
||||
// Equal to use PrivateKey{}
|
||||
func NewPrivateKey() *PrivateKey {
|
||||
return &PrivateKey{
|
||||
D: new(big.Int),
|
||||
}
|
||||
}
|
||||
|
||||
// Clear zero the privatekey, also it implements the gmath.Clearable interface
|
||||
func (k *PrivateKey) Clear() {
|
||||
gmath.ClearBigInt(k.D)
|
||||
}
|
||||
|
||||
// Get return k.D, if k.D is nil, new one and return it
|
||||
func (k *PrivateKey) Get() *big.Int {
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
return k.D
|
||||
}
|
||||
|
||||
// SetString set k to s.
|
||||
func (k *PrivateKey) SetString(s string, base int) (*PrivateKey, bool) {
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
|
||||
if _, ok := k.D.SetString(s, base); !ok {
|
||||
return k, ok
|
||||
}
|
||||
k.computePublicKeyUncheck()
|
||||
return k, true
|
||||
}
|
||||
func (k *PrivateKey) SetBigInt(b *big.Int) *PrivateKey {
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
k.D.Set(b)
|
||||
k.computePublicKeyUncheck()
|
||||
return k
|
||||
}
|
||||
func (k *PrivateKey) Set(x *PrivateKey) *PrivateKey {
|
||||
if x == nil {
|
||||
return k
|
||||
}
|
||||
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
|
||||
k.D.Set(x.D)
|
||||
k.PublicKey.Set(&x.PublicKey)
|
||||
return k
|
||||
}
|
||||
|
||||
// GenPublicKey generete the k.PublicKey and return it.
|
||||
func (k *PrivateKey) GenPublicKey() *PublicKey {
|
||||
k.computePublicKeyUncheck()
|
||||
return &k.PublicKey
|
||||
}
|
||||
|
||||
func (k *PrivateKey) computePublicKeyUncheck() {
|
||||
k.PublicKey.Curve = Curve()
|
||||
k.PublicKey.X, k.PublicKey.Y = Curve().ScalarBaseMult(k.D.Bytes())
|
||||
}
|
||||
|
||||
// Random set k to a random key
|
||||
func (k *PrivateKey) Random(r io.Reader) *PrivateKey {
|
||||
N := Curve().Params().N
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
for {
|
||||
d, err := rand.Int(r, N)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if d.Sign() != 0 {
|
||||
k.D = d
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
k.computePublicKeyUncheck()
|
||||
return k
|
||||
}
|
||||
|
||||
// MarshalUtil implements the gcl/util/encoding/UtilMarshaler interface
|
||||
func (k *PrivateKey) MarshalUtil(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
data = make([]byte, 0, 4+ECCRefMaxLen)
|
||||
}
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
k.D.Mod(k.D, orderN)
|
||||
|
||||
data, tail := internal.SliceForAppend(data, 4)
|
||||
Endian.PutUint32(tail, uint32(byteSize<<3))
|
||||
|
||||
data, tail = internal.SliceForAppend(data, ECCRefMaxLen)
|
||||
_ = gmath.FillBytes(k.D, tail)
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalUtil revert of MarshalUtil
|
||||
func (k *PrivateKey) UnmarshalUtil(data []byte) (uint64, error) {
|
||||
n := uint64(0)
|
||||
if len(data) < 4+ECCRefMaxLen {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
||||
}
|
||||
if ECCStrict {
|
||||
bits := binary.BigEndian.Uint32(data[:4])
|
||||
if bits != uint32(byteSize<<3) {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "may be bits are little endian")
|
||||
}
|
||||
}
|
||||
data = data[4:]
|
||||
n += 4
|
||||
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
|
||||
k.D.SetBytes(data[:ECCRefMaxLen])
|
||||
if k.D.Cmp(orderN) >= 0 || k.D.Sign() == 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "the input private key as an integer is bigger than the order N")
|
||||
}
|
||||
n += ECCRefMaxLen
|
||||
k.computePublicKeyUncheck()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface
|
||||
// 返回字节符合GMT 0018的定义。
|
||||
func (k *PrivateKey) MarshalBinary() ([]byte, error) {
|
||||
return k.MarshalUtil(nil)
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
// 返回字节符合GMT 0018的定义。
|
||||
// 注意:若返回错误,则k的值未定义。
|
||||
func (k *PrivateKey) UnmarshalBinary(data []byte) error {
|
||||
_, err := k.UnmarshalUtil(data)
|
||||
return gerrors.WithStack(err)
|
||||
}
|
||||
|
||||
// Bytes return the big-endian of privateKey, of byteSize bytes(aka. 32 bytes), padding 0 in the leading
|
||||
func (k *PrivateKey) Bytes() []byte {
|
||||
r := make([]byte, byteSize)
|
||||
k.D.Mod(k.D, orderN)
|
||||
_ = gmath.FillBytes(k.D, r)
|
||||
return r
|
||||
}
|
||||
|
||||
// SetBytes set buf to k, invert of Bytes()
|
||||
func (k *PrivateKey) SetBytes(buf []byte) error {
|
||||
if len(buf) < byteSize {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "input too small")
|
||||
}
|
||||
if k.D == nil {
|
||||
k.D = new(big.Int)
|
||||
}
|
||||
k.D.SetBytes(buf)
|
||||
// Mod unnessary?
|
||||
k.D.Mod(k.D, orderN)
|
||||
|
||||
k.computePublicKeyUncheck()
|
||||
return nil
|
||||
}
|
||||
|
||||
// String return a readable string
|
||||
func (k *PrivateKey) String() string {
|
||||
if k.D == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
// return k.Int.Text(16)
|
||||
return hex.EncodeToString(gmath.BigIntToNByte(k.D, byteSize))
|
||||
}
|
||||
|
||||
// GenPrivateKey 生成私钥。
|
||||
// rnd should be nil, io.Reader or []byte.
|
||||
// If rnd == nil, use package grand to generates random numbers.
|
||||
func GenPrivateKey(rnd any) (*PrivateKey, error) {
|
||||
if rnd == nil {
|
||||
return GenerateKey(Curve(), grand.Reader)
|
||||
}
|
||||
if rnd, ok := rnd.(io.Reader); ok {
|
||||
return GenerateKey(Curve(), rnd)
|
||||
}
|
||||
if b, ok := rnd.([]byte); ok {
|
||||
D := new(big.Int).SetBytes(b)
|
||||
D.Mod(D, OrderN())
|
||||
if D.Sign() == 0 {
|
||||
// D.SetInt64(1)
|
||||
return nil, gerrors.WithAnnotating(ErrRandomError, "input random bytes invalid, recall with another random bytes")
|
||||
}
|
||||
sk := &PrivateKey{D: D}
|
||||
sk.computePublicKeyUncheck()
|
||||
return sk, nil
|
||||
}
|
||||
panic("GenPrivateKey: input rnd must bi nil, io.Reader or []byte")
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////// PublicKey
|
||||
|
||||
// PublicKey 公钥
|
||||
type PublicKey struct {
|
||||
elliptic.Curve
|
||||
X, Y *big.Int
|
||||
}
|
||||
|
||||
// Set k=x
|
||||
func (k *PublicKey) Set(x *PublicKey) *PublicKey {
|
||||
if k.X == nil {
|
||||
k.X = new(big.Int)
|
||||
}
|
||||
if k.Y == nil {
|
||||
k.Y = new(big.Int)
|
||||
}
|
||||
|
||||
k.X.Set(x.X)
|
||||
k.Y.Set(x.Y)
|
||||
return k
|
||||
}
|
||||
|
||||
// NewPublicKey return a new PublicKey instance
|
||||
func NewPublicKey() *PublicKey {
|
||||
return &PublicKey{X: new(big.Int), Y: new(big.Int)}
|
||||
}
|
||||
func (k *PublicKey) MarshalASN1() ([]byte, error) {
|
||||
return elliptic.Marshal(Curve(), k.X, k.Y), nil
|
||||
}
|
||||
|
||||
func (k *PublicKey) UnmarshalASN1(b []byte) error {
|
||||
x, y := elliptic.Unmarshal(Curve(), b)
|
||||
if x == nil || y == nil {
|
||||
return gerrors.WithAnnotating(ErrInvalidPoint, "x or y coordinates are 0")
|
||||
}
|
||||
k.Curve = Curve()
|
||||
k.X = x
|
||||
k.Y = y
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalUtil implements the gcl/util/encoding/UtilMarshaler interface
|
||||
func (k *PublicKey) MarshalUtil(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
data = make([]byte, 0, 4+2*ECCRefMaxLen)
|
||||
}
|
||||
buf := []byte{0, 0, 0, 0}
|
||||
// 密钥位长应该是N的比特数
|
||||
Endian.PutUint32(buf, uint32(byteSize)<<3)
|
||||
data = append(data, buf...)
|
||||
|
||||
k.X.Mod(k.X, orderN)
|
||||
xBytes := gmath.BigIntToNByte(k.X, ECCRefMaxLen)
|
||||
data = append(data, xBytes...)
|
||||
|
||||
k.Y.Mod(k.Y, orderN)
|
||||
yBytes := gmath.BigIntToNByte(k.Y, ECCRefMaxLen)
|
||||
data = append(data, yBytes...)
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalUtil implements the gcl/util/encoding/UnmarshalUtil interface
|
||||
func (k *PublicKey) UnmarshalUtil(data []byte) (uint64, error) {
|
||||
n := uint64(0)
|
||||
if len(data) < 4+2*ECCRefMaxLen {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "input too small")
|
||||
}
|
||||
if ECCStrict {
|
||||
bits := binary.BigEndian.Uint32(data[:4])
|
||||
if bits != uint32(byteSize)<<3 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "may be bits are little endian")
|
||||
}
|
||||
}
|
||||
data = data[4:]
|
||||
n += 4
|
||||
|
||||
if k.X == nil {
|
||||
k.X = new(big.Int)
|
||||
}
|
||||
if k.Y == nil {
|
||||
k.Y = new(big.Int)
|
||||
}
|
||||
|
||||
x := k.X.SetBytes(data[:ECCRefMaxLen])
|
||||
if x.Cmp(orderN) >= 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "the x coordinate is bigger than the order N")
|
||||
}
|
||||
data = data[ECCRefMaxLen:]
|
||||
n += ECCRefMaxLen
|
||||
|
||||
y := k.Y.SetBytes(data[:ECCRefMaxLen])
|
||||
if y.Cmp(orderN) >= 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "the y coordinate is bigger than the order N")
|
||||
}
|
||||
data = data[ECCRefMaxLen:] //nolint
|
||||
n += ECCRefMaxLen
|
||||
|
||||
// exclude the infinity point
|
||||
if gmath.IsBigInt0(x) && gmath.IsBigInt0(y) {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "the x or y coordinate is 0")
|
||||
}
|
||||
|
||||
if !sm2Curve.IsOnCurve(x, y) {
|
||||
return 0, gerrors.WithStack(ErrInvalidPoint)
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface
|
||||
// 返回字节符合GMT 0018的定义。
|
||||
func (k *PublicKey) MarshalBinary() ([]byte, error) {
|
||||
ret := make([]byte, 4+2*ECCRefMaxLen)
|
||||
// 密钥位长应该是N的比特数
|
||||
Endian.PutUint32(ret[:4], uint32(byteSize)<<3)
|
||||
k.X.Mod(k.X, orderN)
|
||||
xBytes := k.X.Bytes()
|
||||
copy(ret[4+ECCRefMaxLen-len(xBytes):], xBytes)
|
||||
|
||||
k.Y.Mod(k.Y, orderN)
|
||||
yBytes := k.Y.Bytes()
|
||||
copy(ret[4+2*ECCRefMaxLen-len(yBytes):], yBytes)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
// 返回字节符合GMT 0018的定义。
|
||||
// 特殊情形:若data表示无穷远点,即00000100 0000...000,
|
||||
// 返回k.X=k.Y=0
|
||||
// 若返回错误,k的值未定义
|
||||
func (k *PublicKey) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 4+2*ECCRefMaxLen {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
||||
}
|
||||
k.Curve = sm2Curve
|
||||
if ECCStrict {
|
||||
bits := binary.BigEndian.Uint32(data[:4])
|
||||
if bits != uint32(byteSize)<<3 {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "input bits may be little endian, use big endian instead")
|
||||
}
|
||||
}
|
||||
|
||||
if k.X == nil {
|
||||
k.X = new(big.Int)
|
||||
}
|
||||
if k.Y == nil {
|
||||
k.Y = new(big.Int)
|
||||
}
|
||||
|
||||
data = data[4:]
|
||||
var sum byte
|
||||
for i := 0; i < ECCRefMaxLen-byteSize; i++ {
|
||||
sum |= data[i]
|
||||
}
|
||||
if sum != 0 {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "the x coordinate is more than %d bits", byteSize<<3)
|
||||
}
|
||||
x := k.X.SetBytes(data[ECCRefMaxLen-byteSize : ECCRefMaxLen])
|
||||
if x.Cmp(Prime()) >= 0 {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "the x coordinate is big than the prime P")
|
||||
}
|
||||
|
||||
data = data[ECCRefMaxLen:]
|
||||
for i := 0; i < ECCRefMaxLen-byteSize; i++ {
|
||||
sum |= data[i]
|
||||
}
|
||||
if sum != 0 {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "the y coordinate is more than %d bits", byteSize<<3)
|
||||
}
|
||||
y := k.Y.SetBytes(data[ECCRefMaxLen-byteSize : ECCRefMaxLen])
|
||||
if y.Cmp(Prime()) >= 0 {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "the y coordinate is big than the prime P")
|
||||
}
|
||||
|
||||
// exclude the infinity point
|
||||
if gmath.IsBigInt0(x) && gmath.IsBigInt0(y) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !sm2Curve.IsOnCurve(x, y) {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "the public key is not on the curve")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetToInf set k to infinity point
|
||||
func (k *PublicKey) SetToInf() {
|
||||
if k.X == nil {
|
||||
k.X = new(big.Int)
|
||||
}
|
||||
if k.Y == nil {
|
||||
k.Y = new(big.Int)
|
||||
}
|
||||
|
||||
k.X.SetInt64(0)
|
||||
k.Y.SetInt64(0)
|
||||
}
|
||||
|
||||
// Bytes 返回[x,y]的字节表示,共64字节,大端表示,不足用0补足。
|
||||
func (k *PublicKey) Bytes() []byte {
|
||||
k.X.Mod(k.X, orderN)
|
||||
k.Y.Mod(k.Y, orderN)
|
||||
r := make([]byte, 2*byteSize)
|
||||
_ = gmath.FillBytes(k.X, r[:byteSize])
|
||||
_ = gmath.FillBytes(k.Y, r[byteSize:])
|
||||
return r
|
||||
}
|
||||
|
||||
// SetBytes .
|
||||
func (k *PublicKey) SetBytes(buf []byte) error {
|
||||
if len(buf) < 2*byteSize {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
||||
}
|
||||
if k.X == nil {
|
||||
k.X = new(big.Int)
|
||||
}
|
||||
if k.Y == nil {
|
||||
k.Y = new(big.Int)
|
||||
}
|
||||
|
||||
k.X.SetBytes(buf[:byteSize])
|
||||
k.Y.SetBytes(buf[byteSize : 2*byteSize])
|
||||
if !k.IsValid() {
|
||||
return gerrors.WithAnnotatingf(ErrInvalidInput, "the public key is not on the curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String return a readable string
|
||||
func (k *PublicKey) String() string {
|
||||
buf, _ := k.MarshalBinary()
|
||||
return hex.EncodeToString(buf)
|
||||
}
|
||||
|
||||
// IsValid 返回公钥是否有效
|
||||
func (k *PublicKey) IsValid() bool {
|
||||
return sm2Curve.IsOnCurve(k.X, k.Y)
|
||||
}
|
||||
|
||||
// Normalize 公钥坐标mod n
|
||||
func (k *PublicKey) Normalize() {
|
||||
if k.X == nil {
|
||||
k.X = new(big.Int)
|
||||
}
|
||||
if k.Y == nil {
|
||||
k.Y = new(big.Int)
|
||||
}
|
||||
|
||||
k.X.Mod(k.X, OrderN())
|
||||
k.Y.Mod(k.Y, OrderN())
|
||||
}
|
||||
|
||||
// Equals 返回公钥是否相等
|
||||
func (k *PublicKey) Equals(p *PublicKey) bool {
|
||||
k.Normalize()
|
||||
p.Normalize()
|
||||
|
||||
return k.X.Cmp(p.X) == 0 && k.Y.Cmp(p.Y) == 0
|
||||
}
|
||||
|
||||
// Generate 生成公钥k = [d]G,
|
||||
// usage:
|
||||
//
|
||||
// pk := (&PublicKey{}).Generate(k)
|
||||
func (k *PublicKey) Generate(d *PrivateKey) *PublicKey {
|
||||
k.X, k.Y = sm2Curve.ScalarBaseMult(d.Bytes())
|
||||
k.Curve = sm2Curve
|
||||
return k
|
||||
}
|
||||
|
||||
// GenPublicKey 生成公钥。注意,返回的公钥指针是d.PublicKey
|
||||
func GenPublicKey(d *PrivateKey) *PublicKey {
|
||||
// We do't check that d < N
|
||||
// d.PublicKey.Curve = Curve()
|
||||
// d.PublicKey.X, d.PublicKey.Y = d.PublicKey.Curve.ScalarBaseMult(d.Bytes())
|
||||
// return &d.PublicKey
|
||||
return d.GenPublicKey()
|
||||
}
|
||||
|
||||
// GenerateKeyPairs return a key pair
|
||||
func GenerateKeyPairs(r io.Reader) (*PrivateKey, *PublicKey, error) {
|
||||
// b := make([]byte, byteSize)
|
||||
// if _, err := r.Read(b); err != nil {
|
||||
// return nil, nil, err
|
||||
// }
|
||||
sk, err := GenPrivateKey(r)
|
||||
if err != nil {
|
||||
return nil, nil, gerrors.WithAnnotating(err, "GenerateKeyPairs failed")
|
||||
}
|
||||
pk := GenPublicKey(sk)
|
||||
return sk, pk, nil
|
||||
}
|
||||
|
||||
// VerifyKeyPair verify if pk = [sk]·G
|
||||
func VerifyKeyPair(sk *PrivateKey, pk *PublicKey) bool {
|
||||
x, y := Curve().ScalarBaseMult(sk.Bytes())
|
||||
return pk.X.Cmp(x) == 0 && pk.Y.Cmp(y) == 0
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
var wMask *big.Int
|
||||
var w int
|
||||
|
||||
func initKeyExchange() {
|
||||
w = (Curve().Params().N.BitLen()+1)/2 - 1
|
||||
wMask = big.NewInt(1)
|
||||
wMask.Lsh(wMask, uint(w))
|
||||
wMask.Sub(wMask, gmath.BigInt1)
|
||||
}
|
||||
|
||||
var XBar = computeXBar
|
||||
|
||||
func computeXBar(x *big.Int) *big.Int {
|
||||
xBar := new(big.Int).And(x, wMask)
|
||||
xBar.SetBit(xBar, w, 1)
|
||||
return xBar
|
||||
}
|
||||
|
||||
// ///////////////////////////////////// 包函数的方式,不绑定方法到struct上
|
||||
type ExchgParameters struct {
|
||||
PrivateKey *PrivateKey // ra and Ra = [ra]·G or rb and Rb = [rb]·G
|
||||
IsSponsor bool
|
||||
}
|
||||
|
||||
func (p *ExchgParameters) PublicKey() *PublicKey {
|
||||
// return p.privateKey.PublicKey.X, p.privateKey.PublicKey.Y
|
||||
return &p.PrivateKey.PublicKey
|
||||
}
|
||||
|
||||
// SharedKey generate shared key.
|
||||
func (p *ExchgParameters) SharedKey(sk *PrivateKey, peerPk *PublicKey, peerPublicKey *PublicKey) (*big.Int, *big.Int, error) {
|
||||
xBar1 := XBar(p.PrivateKey.X)
|
||||
xBar2 := XBar(peerPublicKey.X)
|
||||
|
||||
t := new(big.Int).Mul(xBar1, p.PrivateKey.D)
|
||||
t.Add(sk.D, t)
|
||||
t.Mod(t, Curve().Params().N)
|
||||
x, y := Curve().ScalarMult(peerPublicKey.X, peerPublicKey.Y, xBar2.Bytes())
|
||||
x, y = Curve().Add(x, y, peerPk.X, peerPk.Y)
|
||||
x, y = Curve().ScalarMult(x, y, t.Bytes())
|
||||
|
||||
if gmath.IsBigInt0(x) && gmath.IsBigInt0(y) {
|
||||
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "U/V is infinity point")
|
||||
}
|
||||
return x, y, nil
|
||||
}
|
||||
|
||||
// GenerateAgreementData 发起方调用
|
||||
func GenerateAgreementData(rand io.Reader) (*ExchgParameters, error) {
|
||||
r, err := GenerateKey(Curve(), rand)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &ExchgParameters{
|
||||
PrivateKey: r,
|
||||
IsSponsor: true,
|
||||
}, err
|
||||
}
|
||||
|
||||
// GenerateAgreementDataAndKey 响应方调用生成临时公钥及协商密钥
|
||||
// Za、Zb由PreComputeWithIdAndPubkey计算
|
||||
func GenerateAgreementDataAndKey(
|
||||
id []byte,
|
||||
privateKey *PrivateKey,
|
||||
peerId []byte,
|
||||
peerPublicKey *PublicKey,
|
||||
peerParam *PublicKey,
|
||||
keyLength int, rand io.Reader) ([]byte, *ExchgParameters, error) {
|
||||
|
||||
r, err := GenerateAgreementData(rand)
|
||||
r.IsSponsor = false
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
key, err := GenerateSharedKey(r, id, privateKey, peerId, peerPublicKey, peerParam, keyLength)
|
||||
|
||||
return key, r, nil
|
||||
}
|
||||
|
||||
// GenerateSharedKey 发起方调用生成协商密钥。
|
||||
func GenerateSharedKey(
|
||||
r *ExchgParameters,
|
||||
id []byte,
|
||||
privateKey *PrivateKey,
|
||||
peerId []byte,
|
||||
peerPublicKey *PublicKey,
|
||||
peerParam *PublicKey,
|
||||
keyLength int) ([]byte, error) {
|
||||
|
||||
if !peerParam.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(ErrInvalidPublicKey, "peer's temp param is not a valid curve point")
|
||||
}
|
||||
|
||||
if !peerPublicKey.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(ErrInvalidPublicKey, "peer's public key is not a valid curve point")
|
||||
}
|
||||
x, y, err := r.SharedKey(privateKey, peerPublicKey, peerParam)
|
||||
if err != nil {
|
||||
return nil, gerrors.ChainErrors(ErrKeyExchangeFailed, err)
|
||||
}
|
||||
key := make([]byte, keyLength)
|
||||
if r.IsSponsor {
|
||||
Kdf(key, gmath.BigIntToNByte(x, byteSize),
|
||||
gmath.BigIntToNByte(y, byteSize),
|
||||
PreComputeWithIdAndPubkey(id, &privateKey.PublicKey),
|
||||
PreComputeWithIdAndPubkey(peerId, peerPublicKey),
|
||||
)
|
||||
} else {
|
||||
Kdf(key, gmath.BigIntToNByte(x, byteSize),
|
||||
gmath.BigIntToNByte(y, byteSize),
|
||||
PreComputeWithIdAndPubkey(peerId, peerPublicKey),
|
||||
PreComputeWithIdAndPubkey(id, &privateKey.PublicKey),
|
||||
)
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// Sponsor holds a sponsor's key pairs and temp key pairs, context data.
|
||||
// Sponsor对象可以重复使用
|
||||
type Sponsor struct {
|
||||
KeyBits uint32
|
||||
z []byte
|
||||
r *PrivateKey // sponsor's temp private key
|
||||
privateKey *PrivateKey
|
||||
publicKey *PublicKey
|
||||
tempKeyOfSponsor *PublicKey
|
||||
tempKeyOfResponsor *PublicKey
|
||||
}
|
||||
|
||||
// NewSponsor make a copy of privateKey, so Clear will not change the input privateKey
|
||||
// 若id=nil, 则使用默认id。
|
||||
func NewSponsor(id []byte, privateKey *PrivateKey) *Sponsor {
|
||||
pk := GenPublicKey(privateKey)
|
||||
return &Sponsor{
|
||||
z: PreComputeWithIdAndPubkey(id, pk),
|
||||
privateKey: NewPrivateKey().Set(privateKey),
|
||||
publicKey: pk,
|
||||
tempKeyOfSponsor: NewPublicKey(),
|
||||
tempKeyOfResponsor: NewPublicKey(),
|
||||
}
|
||||
}
|
||||
|
||||
// Clear 无论成功与否,最后调用Clear
|
||||
func (s *Sponsor) Clear() {
|
||||
s.privateKey.Clear()
|
||||
|
||||
}
|
||||
|
||||
// Responsor hold a responsor's key pairs and id
|
||||
// Responsor对象可以重复使用
|
||||
type Responsor struct {
|
||||
z []byte
|
||||
privateKey *PrivateKey
|
||||
publicKey *PublicKey
|
||||
}
|
||||
|
||||
// NewResponsor return a responsor's instance
|
||||
func NewResponsor(id []byte, privateKey *PrivateKey) *Responsor {
|
||||
pk := GenPublicKey(privateKey)
|
||||
return &Responsor{
|
||||
z: PreComputeWithIdAndPubkey(id, pk),
|
||||
privateKey: NewPrivateKey().Set(privateKey),
|
||||
publicKey: pk,
|
||||
}
|
||||
}
|
||||
|
||||
// Clear 无论成功与否,最后调用Clear
|
||||
func (rs *Responsor) Clear() {
|
||||
rs.privateKey.Clear()
|
||||
}
|
||||
|
||||
// A is sponsor and B is responsor
|
||||
|
||||
//////////////////////
|
||||
// 发起方函数
|
||||
|
||||
// GenerateAgreementData 发起方首先调用,za先计算好
|
||||
// Za、Zb由PreComputeWithIdAndPubkey计算
|
||||
// 输出tempPubkey需转化为[]byte
|
||||
func (s *Sponsor) GenerateAgreementData(rnd []byte) (tempKeyOfSponsor *PublicKey, err error) {
|
||||
if len(rnd) < byteSize {
|
||||
rnd = make([]byte, byteSize)
|
||||
if _, err := grand.GenerateRandom(rnd); err != nil {
|
||||
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "generate random numbers failed")
|
||||
}
|
||||
}
|
||||
// return error never happen
|
||||
s.r, _ = GenPrivateKey(rnd[:byteSize])
|
||||
tempKeyOfSponsor = GenPublicKey(s.r)
|
||||
s.tempKeyOfSponsor.Set(tempKeyOfSponsor)
|
||||
return tempKeyOfSponsor, nil
|
||||
}
|
||||
|
||||
// GenerateKey 发起方调用生成协商密钥。
|
||||
func (s *Sponsor) GenerateKey(idOfResponsor []byte, pubkeyOfResponsor, tempKeyOfResponsor *PublicKey, keyLength int) (outKey []byte, err error) {
|
||||
if !tempKeyOfResponsor.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's temp param is not a valid curve point")
|
||||
}
|
||||
|
||||
if !pubkeyOfResponsor.IsValid() {
|
||||
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's public key is not a valid curve point")
|
||||
}
|
||||
|
||||
xBar1 := computeXBar(s.tempKeyOfSponsor.X)
|
||||
xBar2 := computeXBar(tempKeyOfResponsor.X)
|
||||
ta := new(big.Int).Mul(xBar1, s.r.D)
|
||||
ta.Mod(ta, sm2Curve.Params().N)
|
||||
// fmt.Println("x1ra= ", ta.Text(16))
|
||||
ta.Add(s.privateKey.D, ta)
|
||||
ta.Mod(ta, sm2Curve.Params().N)
|
||||
|
||||
ux, uy := sm2Curve.ScalarMult(tempKeyOfResponsor.X, tempKeyOfResponsor.Y, xBar2.Bytes())
|
||||
ux, uy = sm2Curve.Add(ux, uy, pubkeyOfResponsor.X, pubkeyOfResponsor.Y)
|
||||
// fmt.Println("x2Rb= ", ux.Text(16), uy.Text(16))
|
||||
ux, uy = sm2Curve.ScalarMult(ux, uy, ta.Bytes())
|
||||
// fmt.Println("发起方U= ", ux.Text(16), uy.Text(16))
|
||||
// U = O?
|
||||
if gmath.IsBigInt0(ux) && gmath.IsBigInt0(uy) {
|
||||
return nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "U/V is infinity point")
|
||||
}
|
||||
|
||||
outKey = make([]byte, keyLength)
|
||||
zb := PreComputeWithIdAndPubkey(idOfResponsor, pubkeyOfResponsor)
|
||||
Kdf(outKey, gmath.BigIntToNByte(ux, byteSize), gmath.BigIntToNByte(uy, byteSize), s.z, zb)
|
||||
return outKey, nil
|
||||
}
|
||||
|
||||
// 响应方
|
||||
|
||||
// GenerateAgreementDataAndKey 响应方调用生成临时公钥及协商密钥
|
||||
// Za、Zb由PreComputeWithIdAndPubkey计算
|
||||
func (rs *Responsor) GenerateAgreementDataAndKey(idOfSponsor []byte, pubkeyOfSponsor, tempKeyOfSponsor *PublicKey, keyLength int, rnd []byte) (outKey []byte, tempKeyOfResponsor *PublicKey, err error) {
|
||||
|
||||
if len(rnd) < byteSize {
|
||||
rnd = make([]byte, byteSize)
|
||||
if _, err := grand.GenerateRandom(rnd); err != nil {
|
||||
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "generate random numbers failed")
|
||||
}
|
||||
}
|
||||
|
||||
rb, _ := GenPrivateKey(rnd[:byteSize])
|
||||
tempKeyOfResponsor = GenPublicKey(rb)
|
||||
|
||||
if !tempKeyOfSponsor.IsValid() {
|
||||
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's temp param is not a valid curve point")
|
||||
}
|
||||
if !pubkeyOfSponsor.IsValid() {
|
||||
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "responsor's public key is not a valid curve point")
|
||||
}
|
||||
|
||||
xBar1 := computeXBar(tempKeyOfSponsor.X)
|
||||
xBar2 := computeXBar(tempKeyOfResponsor.X)
|
||||
tb := new(big.Int).Mul(xBar2, rb.D)
|
||||
tb.Mod(tb, sm2Curve.Params().N)
|
||||
tb.Add(rs.privateKey.D, tb)
|
||||
tb.Mod(tb, sm2Curve.Params().N)
|
||||
|
||||
vx, vy := sm2Curve.ScalarMult(tempKeyOfSponsor.X, tempKeyOfSponsor.Y, xBar1.Bytes())
|
||||
vx, vy = sm2Curve.Add(vx, vy, pubkeyOfSponsor.X, pubkeyOfSponsor.Y)
|
||||
vx, vy = sm2Curve.ScalarMult(vx, vy, tb.Bytes())
|
||||
// U = O?
|
||||
if gmath.IsBigInt0(vx) && gmath.IsBigInt0(vy) {
|
||||
return nil, nil, gerrors.WithAnnotating(ErrKeyExchangeFailed, "U/V is infinity point")
|
||||
}
|
||||
za := PreComputeWithIdAndPubkey(idOfSponsor, pubkeyOfSponsor)
|
||||
outKey = make([]byte, keyLength)
|
||||
Kdf(outKey, gmath.BigIntToNByte(vx, byteSize), gmath.BigIntToNByte(vy, byteSize), za, rs.z)
|
||||
|
||||
return outKey, tempKeyOfResponsor, nil
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
var (
|
||||
// abg曲线相关参数,若曲线参数改变了,应该改变这里的数值。
|
||||
// 在init中从sm2Curve.Params()生成。
|
||||
abg []byte
|
||||
)
|
||||
|
||||
func initPrecompute() {
|
||||
abg = make([]byte, 0, 4*byteSize)
|
||||
abg = append(abg, gmath.BigIntToNByte(new(big.Int).Sub(sm2Curve.Params().P, gmath.BigInt3), byteSize)...)
|
||||
abg = append(abg, gmath.BigIntToNByte(sm2Curve.Params().B, byteSize)...)
|
||||
abg = append(abg, gmath.BigIntToNByte(sm2Curve.Params().Gx, byteSize)...)
|
||||
abg = append(abg, gmath.BigIntToNByte(sm2Curve.Params().Gy, byteSize)...)
|
||||
|
||||
// abg = []byte{
|
||||
// 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* a */
|
||||
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
// 0xFF, 0xFC,
|
||||
// 0x28, 0xE9, 0xFA, 0x9E, 0x9D, 0x9F, 0x5E, 0x34, 0x4D, 0x5A, /* b */
|
||||
// 0x9E, 0x4B, 0xCF, 0x65, 0x09, 0xA7, 0xF3, 0x97, 0x89, 0xF5,
|
||||
// 0x15, 0xAB, 0x8F, 0x92, 0xDD, 0xBC, 0xBD, 0x41, 0x4D, 0x94,
|
||||
// 0x0E, 0x93,
|
||||
// 0x32, 0xC4, 0xAE, 0x2C, 0x1F, 0x19, 0x81, 0x19, 0x5F, 0x99, /* Gx */
|
||||
// 0x04, 0x46, 0x6A, 0x39, 0xC9, 0x94, 0x8F, 0xE3, 0x0B, 0xBF,
|
||||
// 0xF2, 0x66, 0x0B, 0xE1, 0x71, 0x5A, 0x45, 0x89, 0x33, 0x4C,
|
||||
// 0x74, 0xC7,
|
||||
// 0xBC, 0x37, 0x36, 0xA2, 0xF4, 0xF6, 0x77, 0x9C, 0x59, 0xBD, /* Gy */
|
||||
// 0xCE, 0xE3, 0x6B, 0x69, 0x21, 0x53, 0xD0, 0xA9, 0x87, 0x7C,
|
||||
// 0xC6, 0x2A, 0x47, 0x40, 0x02, 0xDF, 0x32, 0xE5, 0x21, 0x39,
|
||||
// 0xF0, 0xA0,
|
||||
// }
|
||||
}
|
||||
|
||||
// GetDefaultID rt
|
||||
func GetDefaultID() []byte {
|
||||
|
||||
return []byte{
|
||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||
}
|
||||
}
|
||||
|
||||
// PreComputeWithIdAndPubkey 预计算Z
|
||||
// id = nil使用默认id, len(id)==0则使用空, 如[]byte("")
|
||||
// 注:基本上所有情况下,都是用默认id。所以id仅可传入默认id或nil.
|
||||
func PreComputeWithIdAndPubkey(id []byte, pubkey *PublicKey) []byte {
|
||||
var entl [2]byte
|
||||
var d hash.Hash
|
||||
|
||||
if id == nil {
|
||||
d = sm3.NewSm2Precomputed()
|
||||
} else {
|
||||
d = sm3.New()
|
||||
entl[0] = byte((len(id) >> 5) & 0xff)
|
||||
entl[1] = byte((len(id) << 3) & 0xff)
|
||||
d.Write(entl[:])
|
||||
d.Write(id)
|
||||
d.Write(abg)
|
||||
}
|
||||
|
||||
d.Write(gmath.BigIntToNByte(pubkey.X, byteSize))
|
||||
d.Write(gmath.BigIntToNByte(pubkey.Y, byteSize))
|
||||
return d.Sum(nil)
|
||||
}
|
||||
|
||||
// PreComputeWithIdAndPubkeyAndMessage 计算 e=hash(z||m)
|
||||
// z由PreComputeWithIdAndPubkey计算
|
||||
func PreComputeWithIdAndPubkeyAndMessage(id, msg []byte, pubkey *PublicKey) []byte {
|
||||
e := PreComputeWithIdAndPubkey(id, pubkey)
|
||||
d := sm3.New()
|
||||
d.Write(e)
|
||||
d.Write(msg)
|
||||
return d.Sum(e[:0])
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
|
||||
"xdx.jelly/xgcl/api/common"
|
||||
)
|
||||
|
||||
// MarshalSDF export privateKey to SDF type.
|
||||
func (privateKey *PrivateKey) MarshalSDF(sdfPrivateKey *common.ECCrefPrivateKey) error {
|
||||
sdfPrivateKey.Bits = uint32(byteSize * 8)
|
||||
if privateKey.D.BitLen() > byteSize*8 {
|
||||
return common.SDR_KEYERR
|
||||
}
|
||||
_ = gmath.FillBytes(privateKey.D, sdfPrivateKey.K[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalSDF import privateKey from SDF type.
|
||||
func (privateKey *PrivateKey) UnmarshalSDF(sdfPrivateKey *common.ECCrefPrivateKey) error {
|
||||
if privateKey.D == nil {
|
||||
privateKey.D = new(big.Int)
|
||||
}
|
||||
privateKey.D.SetBytes(sdfPrivateKey.K[:])
|
||||
px, py := Curve().ScalarBaseMult(privateKey.D.Bytes())
|
||||
privateKey.PublicKey = PublicKey{Curve: Curve(), X: px, Y: py}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalSDF export publicKey to SDF type.
|
||||
func (publicKey *PublicKey) MarshalSDF(sdfPublicKey *common.ECCrefPublicKey) error {
|
||||
sdfPublicKey.Bits = uint32(byteSize * 8)
|
||||
if publicKey.X.BitLen() > byteSize*8 || publicKey.Y.BitLen() > byteSize*8 {
|
||||
return common.SDR_UNKNOWERR
|
||||
}
|
||||
|
||||
_ = gmath.FillBytes(publicKey.X, sdfPublicKey.X[:])
|
||||
_ = gmath.FillBytes(publicKey.Y, sdfPublicKey.Y[:])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalSDF import publicKey from SDF type.
|
||||
func (publicKey *PublicKey) UnmarshalSDF(sdfPublicKey *common.ECCrefPublicKey) error {
|
||||
publicKey.X.SetBytes(sdfPublicKey.X[:])
|
||||
publicKey.Y.SetBytes(sdfPublicKey.Y[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalSDF export privateKey to SDF type.
|
||||
func (signature *Signature) MarshalSDF(sdfSignature *common.ECCSignature) error {
|
||||
|
||||
if signature.R.BitLen() > byteSize*8 || signature.S.BitLen() > byteSize*8 {
|
||||
return common.SDR_UNKNOWERR
|
||||
}
|
||||
_ = gmath.FillBytes(signature.R, sdfSignature.R[:])
|
||||
_ = gmath.FillBytes(signature.S, sdfSignature.S[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalSDF import signature from SDF type.
|
||||
func (signature *Signature) UnmarshalSDF(sdfSignature *common.ECCSignature) error {
|
||||
signature.R.SetBytes(sdfSignature.R[:])
|
||||
signature.S.SetBytes(sdfSignature.S[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalSDF export signature to SDF type.
|
||||
func (cipher *Cipher) MarshalSDF(sdfCipher *common.ECCCipher) error {
|
||||
if cipher.X.BitLen() > byteSize*8 || cipher.Y.BitLen() > byteSize*8 {
|
||||
return common.SDR_UNKNOWERR
|
||||
}
|
||||
|
||||
_ = gmath.FillBytes(cipher.X, sdfCipher.X[:])
|
||||
_ = gmath.FillBytes(cipher.Y, sdfCipher.Y[:])
|
||||
sdfCipher.M = cipher.Hash
|
||||
sdfCipher.L = uint32(len(cipher.C))
|
||||
sdfCipher.C = append(sdfCipher.C[:0], cipher.C...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UnmarshalSDF import privateKey from SDF type.
|
||||
func (cipher *Cipher) UnmarshalSDF(sdfCipher *common.ECCCipher) error {
|
||||
|
||||
cipher.X.SetBytes(sdfCipher.X[:])
|
||||
cipher.Y.SetBytes(sdfCipher.Y[:])
|
||||
cipher.Hash = sdfCipher.M
|
||||
cipher.C = append(cipher.C[:0], sdfCipher.C...)
|
||||
return nil
|
||||
}
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
"golang.org/x/crypto/cryptobyte/asn1"
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/sm/sm2/ec256"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
// Signature 签名结构体
|
||||
type Signature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
// NewSignature .
|
||||
func NewSignature() *Signature {
|
||||
return &Signature{
|
||||
R: new(big.Int),
|
||||
S: new(big.Int),
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalUtil implements the gcl/util/encoding/UtilMarshaler interface
|
||||
func (sig *Signature) MarshalUtil(data []byte) ([]byte, error) {
|
||||
if data == nil {
|
||||
data = make([]byte, 0, 2*ECCRefMaxLen)
|
||||
}
|
||||
|
||||
sig.R.Mod(sig.R, orderN)
|
||||
sig.S.Mod(sig.S, orderN)
|
||||
data = append(data, gmath.BigIntToNByte(sig.R, ECCRefMaxLen)...)
|
||||
data = append(data, gmath.BigIntToNByte(sig.S, ECCRefMaxLen)...)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (sig *Signature) UnmarshalUtil(data []byte) (uint64, error) {
|
||||
n := uint64(0)
|
||||
if len(data) < 2*ECCRefMaxLen {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
||||
}
|
||||
r := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
data = data[ECCRefMaxLen:]
|
||||
n += ECCRefMaxLen
|
||||
|
||||
if r.Cmp(orderN) >= 0 || r.Sign() == 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "r is zero or bigger than the order N")
|
||||
}
|
||||
s := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
data = data[ECCRefMaxLen:]
|
||||
n += ECCRefMaxLen
|
||||
|
||||
if s.Cmp(orderN) >= 0 || s.Sign() == 0 {
|
||||
return 0, gerrors.WithAnnotating(ErrInvalidInput, "s is zero or bigger than the order N")
|
||||
}
|
||||
sig.R.Set(r)
|
||||
sig.S.Set(s)
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements the encoding.BinaryMarshaler interface
|
||||
// r || s
|
||||
func (sig *Signature) MarshalBinary() ([]byte, error) {
|
||||
data := make([]byte, 2*ECCRefMaxLen)
|
||||
sig.R.Mod(sig.R, orderN)
|
||||
sig.S.Mod(sig.S, orderN)
|
||||
rBytes := sig.R.Bytes()
|
||||
copy(data[ECCRefMaxLen-len(rBytes):], rBytes)
|
||||
sBytes := sig.S.Bytes()
|
||||
copy(data[2*ECCRefMaxLen-len(sBytes):], sBytes)
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface
|
||||
func (sig *Signature) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 2*ECCRefMaxLen {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
||||
}
|
||||
r := new(big.Int).SetBytes(data[:ECCRefMaxLen])
|
||||
if r.Cmp(orderN) >= 0 || r.Sign() == 0 {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "r is zero or bigger than the order N")
|
||||
}
|
||||
s := new(big.Int).SetBytes(data[ECCRefMaxLen : 2*ECCRefMaxLen])
|
||||
if s.Cmp(orderN) >= 0 || s.Sign() == 0 {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "s is zero or bigger than the order N")
|
||||
}
|
||||
sig.R.Set(r)
|
||||
sig.S.Set(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (sig *Signature) MarshalASN1() ([]byte, error) {
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1BigInt(sig.R)
|
||||
b.AddASN1BigInt(sig.S)
|
||||
})
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func (sig *Signature) UnmarshalASN1(data []byte) error {
|
||||
if sig.R == nil {
|
||||
sig.R = new(big.Int)
|
||||
}
|
||||
if sig.S == nil {
|
||||
sig.S = new(big.Int)
|
||||
}
|
||||
|
||||
var inner cryptobyte.String
|
||||
input := cryptobyte.String(data)
|
||||
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
|
||||
!input.Empty() ||
|
||||
!inner.ReadASN1Integer(sig.R) ||
|
||||
!inner.ReadASN1Integer(sig.S) ||
|
||||
!inner.Empty() {
|
||||
return ErrDecodeASN1Failed
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetBytes set Signature from a byte slice
|
||||
func (sig *Signature) SetBytes(rs []byte) error {
|
||||
if len(rs) < 2*byteSize {
|
||||
return gerrors.WithAnnotating(ErrInvalidInput, "input data too short")
|
||||
}
|
||||
if sig.R == nil {
|
||||
sig.R = new(big.Int)
|
||||
}
|
||||
|
||||
if sig.S == nil {
|
||||
sig.S = new(big.Int)
|
||||
}
|
||||
|
||||
sig.R.SetBytes(rs[:byteSize])
|
||||
sig.S.SetBytes(rs[byteSize : 2*byteSize])
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes return byte slice of a signature
|
||||
func (sig *Signature) Bytes() []byte {
|
||||
buf := make([]byte, 2*byteSize)
|
||||
_ = gmath.FillBytes(sig.R, buf[:byteSize])
|
||||
_ = gmath.FillBytes(sig.S, buf[byteSize:])
|
||||
return buf
|
||||
}
|
||||
|
||||
// String return a readable string
|
||||
func (sig *Signature) String() string {
|
||||
var buf strings.Builder
|
||||
buf.WriteString("r: ")
|
||||
buf.WriteString(hex.EncodeToString(gmath.BigIntToNByte(sig.R, ECCRefMaxLen)))
|
||||
buf.WriteString("\ns: ")
|
||||
buf.WriteString(hex.EncodeToString(gmath.BigIntToNByte(sig.S, ECCRefMaxLen)))
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// update a random k in case when Sign got a random integer k error
|
||||
// k's address are unchanged
|
||||
func update(k []byte) {
|
||||
hash := sm3.Sum(k)
|
||||
copy(k, hash[:])
|
||||
}
|
||||
|
||||
// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
|
||||
// This has better constant-time properties than Euclid's method (implemented
|
||||
// in math/big.Int.ModInverse) although math/big itself isn't strictly
|
||||
// constant-time so it's not perfect.
|
||||
// k = k^{-1} mod N
|
||||
func fermatInverse(k, N *big.Int) {
|
||||
// two := big.NewInt(2)
|
||||
nMinus2 := new(big.Int)
|
||||
nMinus2.Sub(N, gmath.BigInt2)
|
||||
k.Exp(k, nMinus2, N)
|
||||
}
|
||||
|
||||
// Sign 签名
|
||||
// e: sm3(Z || M),使用PreComputeWithIdAndPubkeyAndMessage计算
|
||||
// k: 32字节随机数
|
||||
func Sign(e, k []byte, privateKey *PrivateKey) (*Signature, error) {
|
||||
if len(e) < byteSize {
|
||||
return nil, gerrors.WithAnnotatingf(ErrInvalidInput, "input e should be of %d bytes, but it is %d bytes", byteSize, len(e))
|
||||
}
|
||||
if len(k) < byteSize {
|
||||
return nil, gerrors.WithAnnotatingf(ErrInvalidInput, "input k should be of %d bytes, but it is %d bytes", byteSize, len(k))
|
||||
}
|
||||
|
||||
r := new(big.Int).SetBytes(e[:byteSize])
|
||||
s := new(big.Int)
|
||||
intK := new(big.Int)
|
||||
|
||||
// for only loop one time for almost all case
|
||||
for {
|
||||
intK.SetBytes(k[:byteSize])
|
||||
if intK.Cmp(orderN) >= 0 {
|
||||
intK.Sub(intK, orderN)
|
||||
}
|
||||
if intK.Sign() == 0 {
|
||||
// omit the return error cause nMinusOne > 0
|
||||
intK, _ = rand.Int(rand.Reader, nMinusOne)
|
||||
}
|
||||
// ScalarBaseMult is in constant-time
|
||||
x1, _ := sm2Curve.ScalarBaseMult(intK.Bytes())
|
||||
r.Add(x1, r) // r = x1 + e
|
||||
r.Mod(r, orderN)
|
||||
// rearly happen
|
||||
if gmath.IsBigInt0(r) {
|
||||
goto Next
|
||||
}
|
||||
|
||||
// s = (1+d)^(-1)(k + r - r - r*d)=(1+d)^(-1) * (k+r) - r
|
||||
s.Add(privateKey.D, gmath.BigInt1)
|
||||
// invert s mod N costs much time
|
||||
if f, ok := sm2Curve.(interface{ Inverse(*big.Int) *big.Int }); ok {
|
||||
s = f.Inverse(s)
|
||||
} else {
|
||||
// s.ModInverse(s, orderN)
|
||||
fermatInverse(s, orderN)
|
||||
}
|
||||
intK.Add(intK, r)
|
||||
|
||||
// k + r < 2N and k + r > N is the most likely case
|
||||
if cmpResult := intK.Cmp(orderN); cmpResult > 0 {
|
||||
intK.Sub(intK, orderN)
|
||||
} else if cmpResult == 0 {
|
||||
goto Next
|
||||
}
|
||||
|
||||
s.Mul(s, intK)
|
||||
s.Sub(s, r)
|
||||
s.Mod(s, orderN)
|
||||
break
|
||||
Next:
|
||||
// for another random k
|
||||
update(k[:byteSize])
|
||||
continue
|
||||
}
|
||||
return &Signature{R: r, S: s}, nil
|
||||
}
|
||||
|
||||
// Verify 验签
|
||||
// pk:公钥,不做验证pk是否有效,另调用pk.IsValid()判断pk是否是在曲线上。
|
||||
//
|
||||
// 当然如果pk无效,返回false
|
||||
//
|
||||
// e: sm3(Z || M),使用PreComputeWithIdAndPubkeyAndMessage计算
|
||||
func Verify(e []byte, pk *PublicKey, sig *Signature) bool {
|
||||
if len(e) != byteSize {
|
||||
return false
|
||||
}
|
||||
|
||||
r := sig.R
|
||||
s := sig.S
|
||||
|
||||
if r.Sign() <= 0 || s.Sign() <= 0 ||
|
||||
r.Cmp(orderN) >= 0 || s.Cmp(orderN) >= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
x := pk.X
|
||||
y := pk.Y
|
||||
t := new(big.Int).Add(r, s)
|
||||
var x1, y1 *big.Int
|
||||
if false {
|
||||
t.Mod(t, orderN)
|
||||
x1, y1 = sm2Curve.ScalarBaseMult(sig.S.Bytes())
|
||||
x2, y2 := sm2Curve.ScalarMult(x, y, t.Bytes())
|
||||
x1, _ = sm2Curve.Add(x1, y1, x2, y2)
|
||||
} else {
|
||||
x1, _ = ec256.CombinedMult(x, y, sig.S.Bytes(), t.Bytes())
|
||||
}
|
||||
t.SetBytes(e)
|
||||
x1.Add(x1, t)
|
||||
x1.Mod(x1, orderN)
|
||||
return x1.Cmp(r) == 0
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package sm2
|
||||
@@ -0,0 +1,90 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/internal/kdf"
|
||||
"xdx.jelly/xgcl/sm/sm2/ec256"
|
||||
)
|
||||
|
||||
const (
|
||||
// ECCRefMaxBits c.f. GMT 0018
|
||||
ECCRefMaxBits = 512
|
||||
// ECCRefMaxLen c.f. GMT 0018
|
||||
ECCRefMaxLen = (ECCRefMaxBits + 7) >> 3
|
||||
|
||||
// ECCStrict UnmarshalBinary的时候是否要求数据严格遵循GMT0018格式, 也就是要求
|
||||
// bits按大端存储,并且等于密钥长度即256
|
||||
ECCStrict = false
|
||||
)
|
||||
|
||||
var one = new(big.Int).SetInt64(1)
|
||||
|
||||
var (
|
||||
sm2Curve elliptic.Curve
|
||||
|
||||
// byteSize is the Bytes of prime, module...
|
||||
byteSize int
|
||||
|
||||
// orderN the order of Group of points on the curve
|
||||
orderN *big.Int
|
||||
|
||||
// byteOfN is the ByteSize - long of N of byte slice
|
||||
byteOfN []byte
|
||||
|
||||
// nMinusOne N-1
|
||||
nMinusOne *big.Int
|
||||
|
||||
// Curve256 export the curve param.
|
||||
Curve256 = ec256.Curve256
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Choose the curve
|
||||
// if the curve changed to a 384-bits curve,
|
||||
// just sm2Curve = ec.EC384()
|
||||
sm2Curve = ec256.CurveSM2()
|
||||
byteSize = (sm2Curve.Params().BitSize + 7) / 8
|
||||
orderN = new(big.Int).Set(sm2Curve.Params().N)
|
||||
byteOfN = gmath.BigIntToNByte(orderN, byteSize)
|
||||
nMinusOne = new(big.Int).Sub(orderN, gmath.BigInt1)
|
||||
// must after sm2Curve and byteSize
|
||||
initPrecompute()
|
||||
// for key exchange constants
|
||||
initKeyExchange()
|
||||
|
||||
}
|
||||
|
||||
// ByteSize 返回SM2的密钥大小
|
||||
func ByteSize() int {
|
||||
return byteSize
|
||||
}
|
||||
|
||||
// OrderN return the order of point group
|
||||
func OrderN() *big.Int {
|
||||
return orderN
|
||||
}
|
||||
|
||||
// Curve return the sm2 curve (interface)
|
||||
func Curve() elliptic.Curve {
|
||||
return sm2Curve
|
||||
}
|
||||
|
||||
// Prime return the p of field charactor
|
||||
func Prime() *big.Int {
|
||||
return sm2Curve.Params().P
|
||||
}
|
||||
|
||||
// BaseX return the x of base point
|
||||
func BaseX() *big.Int {
|
||||
return sm2Curve.Params().Gx
|
||||
}
|
||||
|
||||
// BaseY return the y of base point
|
||||
func BaseY() *big.Int {
|
||||
return sm2Curve.Params().Gy
|
||||
}
|
||||
|
||||
var Kdf = kdf.SMKDF.Kdf
|
||||
@@ -0,0 +1,241 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
var m sync.Mutex
|
||||
|
||||
var waittingIcons = string("|/-\\")
|
||||
|
||||
var i = 0
|
||||
var begin time.Time
|
||||
var last time.Time
|
||||
|
||||
func waitting() {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
if time.Since(last).Milliseconds() > 200 {
|
||||
elaspe := time.Since(begin)
|
||||
hours := int64(elaspe.Hours())
|
||||
elaspe -= time.Duration(hours) * time.Hour
|
||||
minutes := int64(elaspe.Minutes())
|
||||
elaspe -= time.Duration(minutes) * time.Minute
|
||||
seconds := int64(elaspe.Seconds())
|
||||
|
||||
fmt.Printf("\rTest is running for %02dh %02dm %02ds ", hours, minutes, seconds)
|
||||
fmt.Print(string(waittingIcons[i]))
|
||||
last = time.Now()
|
||||
i++
|
||||
if i >= len(waittingIcons) {
|
||||
i = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFuzz(t *testing.T) {
|
||||
wg := new(sync.WaitGroup)
|
||||
count := 1000
|
||||
begin = time.Now()
|
||||
last = begin
|
||||
|
||||
// test key generation
|
||||
wg.Add(1)
|
||||
go func(k int) {
|
||||
for i := 0; i < k; i++ {
|
||||
k := NewPrivateKey().Random(grand.Reader)
|
||||
pk := (&PublicKey{}).Generate(k)
|
||||
b, _ := pk.MarshalBinary()
|
||||
pk1 := &PublicKey{}
|
||||
pk1.UnmarshalBinary(b)
|
||||
if !pk1.Equals(pk) || !pk.IsValid() || !pk1.IsValid() {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
break
|
||||
}
|
||||
if i%100 == 0 {
|
||||
waitting()
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}(count)
|
||||
|
||||
wg.Add(1)
|
||||
go func(k int) {
|
||||
for i := 0; i < k; i++ {
|
||||
e := grand.GetRandom(ByteSize())
|
||||
k := grand.GetRandom(ByteSize())
|
||||
d := (&PrivateKey{}).Random(grand.Reader)
|
||||
pk := (&PublicKey{}).Generate(d)
|
||||
sig, err := Sign(e, k, d)
|
||||
if err != nil {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
break
|
||||
}
|
||||
|
||||
data, err := sig.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
sig1 := NewSignature()
|
||||
if err := sig1.UnmarshalBinary(data); err != nil {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
ret := Verify(e, pk, sig1)
|
||||
if !ret {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
break
|
||||
}
|
||||
if i%100 == 0 {
|
||||
waitting()
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}(count)
|
||||
|
||||
wg.Add(1)
|
||||
go func(k int) {
|
||||
for i := 0; i < k; i++ {
|
||||
k := grand.GetRandom(ByteSize())
|
||||
d := (&PrivateKey{}).Random(grand.Reader)
|
||||
pk := (&PublicKey{}).Generate(d)
|
||||
|
||||
msg := grand.GetRandom(i&0xff + 1)
|
||||
|
||||
cipher, err := Encrypt(pk, msg, k)
|
||||
if err != nil {
|
||||
t.Logf("pk=%v,msg=%v", pk, msg)
|
||||
t.Log(err)
|
||||
t.Fail()
|
||||
break
|
||||
}
|
||||
|
||||
data, _ := cipher.MarshalBinary()
|
||||
cipher1 := NewCipher()
|
||||
if err := cipher1.UnmarshalBinary(data); err != nil {
|
||||
t.Log("unmarshal failed")
|
||||
t.Fail()
|
||||
break
|
||||
}
|
||||
|
||||
//Decrypt
|
||||
decryptedMsg, err := Decrypt(d, cipher)
|
||||
if err != nil || bytes.Compare(decryptedMsg, msg) != 0 {
|
||||
t.Log(err)
|
||||
t.Fail()
|
||||
break
|
||||
}
|
||||
if i%100 == 0 {
|
||||
waitting()
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}(count)
|
||||
|
||||
// TODO generic32 and 64 panic
|
||||
// wg.Add(1)
|
||||
// go func(k int) {
|
||||
// for i := 0; i < k; i++ {
|
||||
// sponsorID := []byte("Sponsor")
|
||||
// responsorID := []byte("Responsor")
|
||||
// ska := (&PrivateKey{}).Random(grand.Reader)
|
||||
// skb := (&PrivateKey{}).Random(grand.Reader)
|
||||
|
||||
// // 使用默认id传入nil或GetDefaultID
|
||||
// s := NewSponsor(sponsorID, ska)
|
||||
// rs := NewResponsor(responsorID, skb)
|
||||
// keylen := i%128 + 1
|
||||
// tempKeyOfSponsor, err := s.GenerateAgreementData(nil)
|
||||
// if err != nil {
|
||||
// t.Log()
|
||||
// t.Fail()
|
||||
// }
|
||||
// keyOfResponsor, tempKeyOfResponsor, err := rs.GenerateAgreementDataAndKey(sponsorID, GenPublicKey(ska), tempKeyOfSponsor, keylen, nil)
|
||||
// if err != nil {
|
||||
// t.Log()
|
||||
// t.Fail()
|
||||
// }
|
||||
// keyOfSponsor, err := s.GenerateKey(responsorID, GenPublicKey(skb), tempKeyOfResponsor, keylen)
|
||||
// if err != nil {
|
||||
// t.Log()
|
||||
// t.Fail()
|
||||
// }
|
||||
// if bytes.Compare(keyOfResponsor, keyOfSponsor) != 0 {
|
||||
// t.Log()
|
||||
// t.Fail()
|
||||
// break
|
||||
// }
|
||||
|
||||
// ska.Clear()
|
||||
// skb.Clear()
|
||||
// s.Clear()
|
||||
// rs.Clear()
|
||||
// if i%100 == 0 {
|
||||
// waitting()
|
||||
// }
|
||||
// }
|
||||
// wg.Done()
|
||||
// }(count)
|
||||
|
||||
// wait for all routine finish
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func FuzzSign(f *testing.F) {
|
||||
f.Add([]byte{}, []byte{})
|
||||
f.Fuzz(func(t *testing.T, k, msg []byte) {
|
||||
d := sm3.Sum(k)
|
||||
sk := &PrivateKey{}
|
||||
sk.SetBytes(d[:])
|
||||
e := PreComputeWithIdAndPubkeyAndMessage(GetDefaultID(), msg, &sk.PublicKey)
|
||||
r, s, err := SignWithReader(rand.Reader, sk, e)
|
||||
if err != nil {
|
||||
t.Errorf("%v", err)
|
||||
}
|
||||
|
||||
if !VerifyWithRS(&sk.PublicKey, e, r, s) {
|
||||
t.Error("verify failed")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func FuzzEnc(f *testing.F) {
|
||||
f.Add([]byte{}, []byte{}, []byte{})
|
||||
f.Fuzz(func(t *testing.T, r1, r2, msg []byte) {
|
||||
buf := sm3.Sum(r1)
|
||||
d := &PrivateKey{}
|
||||
d.SetBytes(buf[:])
|
||||
pk := &d.PublicKey
|
||||
buf = sm3.Sum(r2)
|
||||
k := buf[:]
|
||||
cipher, err := Encrypt(pk, msg, k)
|
||||
if err != nil {
|
||||
t.Error("Encrypt failed")
|
||||
}
|
||||
|
||||
//Decrypt
|
||||
decryptedMsg, err := Decrypt(d, cipher)
|
||||
if err != nil || bytes.Compare(decryptedMsg, msg) != 0 {
|
||||
if err != nil {
|
||||
t.Error("Dencrypt failed")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"compress/bzip2"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"math/big"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func testKeyGeneration(t *testing.T, c elliptic.Curve, tag string) {
|
||||
priv, err := GenerateKey(c, rand.Reader)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error: %s", tag, err)
|
||||
return
|
||||
}
|
||||
if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
|
||||
t.Errorf("%s: public key invalid: %s", tag, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyGeneration(t *testing.T) {
|
||||
testKeyGeneration(t, Curve(), "sm2curve")
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
// testKeyGeneration(t, elliptic.P256(), "p256")
|
||||
// testKeyGeneration(t, elliptic.P384(), "p384")
|
||||
// testKeyGeneration(t, elliptic.P521(), "p521")
|
||||
}
|
||||
|
||||
func BenchmarkSignWithReader(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
p256 := Curve()
|
||||
hashed := []byte("testing")
|
||||
priv, _ := GenerateKey(p256, rand.Reader)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_, _, _ = SignWithReader(rand.Reader, priv, hashed)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkKeyGeneration(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
p256 := Curve()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
GenerateKey(p256, rand.Reader)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func testSignAndVerifyWithRS(t *testing.T, c elliptic.Curve, tag string) {
|
||||
priv, _ := GenerateKey(c, rand.Reader)
|
||||
|
||||
hashed := []byte("testing")
|
||||
r, s, err := SignWithReader(rand.Reader, priv, hashed)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error signing: %s", tag, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !VerifyWithRS(&priv.PublicKey, hashed, r, s) {
|
||||
t.Errorf("%s: Verify failed", tag)
|
||||
}
|
||||
|
||||
hashed[0] ^= 0xff
|
||||
if VerifyWithRS(&priv.PublicKey, hashed, r, s) {
|
||||
t.Errorf("%s: Verify always works!", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignAndVerifyWithRS(t *testing.T) {
|
||||
testSignAndVerifyWithRS(t, Curve(), "sm2")
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve, tag string) {
|
||||
priv, _ := GenerateKey(c, rand.Reader)
|
||||
|
||||
hashed := []byte("testing")
|
||||
sig, err := SignASN1(rand.Reader, priv, hashed)
|
||||
fmt.Printf("%02x\n", sig)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error signing: %s", tag, err)
|
||||
return
|
||||
}
|
||||
|
||||
if !VerifyASN1(&priv.PublicKey, hashed, sig) {
|
||||
t.Errorf("%s: VerifyASN1 failed", tag)
|
||||
}
|
||||
|
||||
hashed[0] ^= 0xff
|
||||
if VerifyASN1(&priv.PublicKey, hashed, sig) {
|
||||
t.Errorf("%s: VerifyASN1 always works!", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignAndVerifyASN1(t *testing.T) {
|
||||
testSignAndVerifyASN1(t, Curve(), "p224")
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
|
||||
priv, _ := GenerateKey(c, rand.Reader)
|
||||
|
||||
hashed := []byte("testing")
|
||||
r0, s0, err := SignWithReader(zeroReader, priv, hashed)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error signing: %s", tag, err)
|
||||
return
|
||||
}
|
||||
|
||||
hashed = []byte("testing...")
|
||||
r1, s1, err := SignWithReader(zeroReader, priv, hashed)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error signing: %s", tag, err)
|
||||
return
|
||||
}
|
||||
|
||||
if s0.Cmp(s1) == 0 {
|
||||
// This should never happen.
|
||||
t.Errorf("%s: the signatures on two different messages were the same", tag)
|
||||
}
|
||||
|
||||
if r0.Cmp(r1) == 0 {
|
||||
t.Errorf("%s: the nonce used for two different messages was the same", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonceSafety(t *testing.T) {
|
||||
testNonceSafety(t, Curve(), "p224")
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
|
||||
priv, _ := GenerateKey(c, rand.Reader)
|
||||
|
||||
hashed := []byte("testing")
|
||||
r0, s0, err := SignWithReader(rand.Reader, priv, hashed)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error signing: %s", tag, err)
|
||||
return
|
||||
}
|
||||
|
||||
r1, s1, err := SignWithReader(rand.Reader, priv, hashed)
|
||||
if err != nil {
|
||||
t.Errorf("%s: error signing: %s", tag, err)
|
||||
return
|
||||
}
|
||||
|
||||
if s0.Cmp(s1) == 0 {
|
||||
t.Errorf("%s: two signatures of the same message produced the same result", tag)
|
||||
}
|
||||
|
||||
if r0.Cmp(r1) == 0 {
|
||||
t.Errorf("%s: two signatures of the same message produced the same nonce", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestINDCCA(t *testing.T) {
|
||||
testINDCCA(t, Curve(), "p224")
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func fromHex(s string) *big.Int {
|
||||
r, ok := new(big.Int).SetString(s, 16)
|
||||
if !ok {
|
||||
panic("bad hex")
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func TestVectors(t *testing.T) {
|
||||
// This test runs the full set of NIST test vectors from
|
||||
// https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
|
||||
//
|
||||
// The SigVer.rsp file has been edited to remove test vectors for
|
||||
// unsupported algorithms and has been compressed.
|
||||
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open("testdata/SigVer.rsp.bz2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
buf := bufio.NewReader(bzip2.NewReader(f))
|
||||
|
||||
lineNo := 1
|
||||
var h hash.Hash
|
||||
var msg []byte
|
||||
var hashed []byte
|
||||
var r, s *big.Int
|
||||
pub := new(PublicKey)
|
||||
|
||||
for {
|
||||
line, err := buf.ReadString('\n')
|
||||
if len(line) == 0 {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
t.Fatalf("error reading from input: %s", err)
|
||||
}
|
||||
lineNo++
|
||||
// Need to remove \r\n from the end of the line.
|
||||
if !strings.HasSuffix(line, "\r\n") {
|
||||
t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
|
||||
}
|
||||
line = line[:len(line)-2]
|
||||
|
||||
if len(line) == 0 || line[0] == '#' {
|
||||
continue
|
||||
}
|
||||
|
||||
if line[0] == '[' {
|
||||
line = line[1 : len(line)-1]
|
||||
parts := strings.SplitN(line, ",", 2)
|
||||
|
||||
switch parts[0] {
|
||||
case "P-224":
|
||||
pub.Curve = elliptic.P224()
|
||||
case "P-256":
|
||||
pub.Curve = elliptic.P256()
|
||||
case "P-384":
|
||||
pub.Curve = elliptic.P384()
|
||||
case "P-521":
|
||||
pub.Curve = elliptic.P521()
|
||||
default:
|
||||
pub.Curve = nil
|
||||
}
|
||||
|
||||
switch parts[1] {
|
||||
case "SHA-1":
|
||||
h = sha1.New()
|
||||
case "SHA-224":
|
||||
h = sha256.New224()
|
||||
case "SHA-256":
|
||||
h = sha256.New()
|
||||
case "SHA-384":
|
||||
h = sha512.New384()
|
||||
case "SHA-512":
|
||||
h = sha512.New()
|
||||
default:
|
||||
h = nil
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if h == nil || pub.Curve == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(line, "Msg = "):
|
||||
if msg, err = hex.DecodeString(line[6:]); err != nil {
|
||||
t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
|
||||
}
|
||||
case strings.HasPrefix(line, "Qx = "):
|
||||
pub.X = fromHex(line[5:])
|
||||
case strings.HasPrefix(line, "Qy = "):
|
||||
pub.Y = fromHex(line[5:])
|
||||
case strings.HasPrefix(line, "R = "):
|
||||
r = fromHex(line[4:])
|
||||
case strings.HasPrefix(line, "S = "):
|
||||
s = fromHex(line[4:])
|
||||
case strings.HasPrefix(line, "Result = "):
|
||||
expected := line[9] == 'P'
|
||||
h.Reset()
|
||||
h.Write(msg)
|
||||
hashed := h.Sum(hashed[:0])
|
||||
if VerifyWithRS(pub, hashed, r, s) != expected {
|
||||
t.Fatalf("incorrect result on line %d", lineNo)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("unknown variable on line %d: %s", lineNo, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testNegativeInputs(t *testing.T, curve elliptic.Curve, tag string) {
|
||||
key, err := GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
t.Errorf("failed to generate key for %q", tag)
|
||||
}
|
||||
|
||||
var hash [32]byte
|
||||
r := new(big.Int).SetInt64(1)
|
||||
r.Lsh(r, 550 /* larger than any supported curve */)
|
||||
r.Neg(r)
|
||||
|
||||
if VerifyWithRS(&key.PublicKey, hash[:], r, r) {
|
||||
t.Errorf("bogus signature accepted for %q", tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNegativeInputs(t *testing.T) {
|
||||
testNegativeInputs(t, Curve(), "p224")
|
||||
}
|
||||
|
||||
func TestZeroHashSignature(t *testing.T) {
|
||||
zeroHash := make([]byte, 64)
|
||||
|
||||
for _, curve := range []elliptic.Curve{Curve()} {
|
||||
privKey, err := GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Sign a hash consisting of all zeros.
|
||||
r, s, err := SignWithReader(rand.Reader, privKey, zeroHash)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Confirm that it can be verified.
|
||||
if !VerifyWithRS(&privKey.PublicKey, zeroHash, r, s) {
|
||||
t.Errorf("zero hash signature verify failed for %T", curve)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
func TestKeyExchange(t *testing.T) {
|
||||
sponsorID := []byte("Sponsor")
|
||||
responsorID := []byte("Responsor")
|
||||
// Set random test data
|
||||
ska, _ := GenPrivateKey(nil)
|
||||
skb, _ := GenPrivateKey(nil)
|
||||
|
||||
// 使用默认id传入nil或GetDefaultID
|
||||
s := NewSponsor(sponsorID, ska)
|
||||
rs := NewResponsor(responsorID, skb)
|
||||
// NEVER FORGET CLEAR
|
||||
defer ska.Clear()
|
||||
defer skb.Clear()
|
||||
defer s.Clear()
|
||||
defer rs.Clear()
|
||||
|
||||
// 多次密钥交换是可以重复使用Sponsor和Responsor的-只要其私钥和id不变
|
||||
for keylen := 1; keylen < 256; keylen++ {
|
||||
// t.Log("key exchange test for key length = ", keylen)
|
||||
|
||||
// key exchange
|
||||
tempKeyOfSponsor, _ := s.GenerateAgreementData(nil)
|
||||
keyOfResponsor, tempKeyOfResponsor, _ := rs.GenerateAgreementDataAndKey(sponsorID, GenPublicKey(ska), tempKeyOfSponsor, keylen, nil)
|
||||
keyOfSponsor, _ := s.GenerateKey(responsorID, GenPublicKey(skb), tempKeyOfResponsor, keylen)
|
||||
|
||||
// check if OK
|
||||
printlen := 32
|
||||
if keylen < printlen {
|
||||
printlen = keylen
|
||||
}
|
||||
// t.Log("responsor: ", hex.EncodeToString(keyOfResponsor[:printlen]), "...")
|
||||
// t.Log("sponsor : ", hex.EncodeToString(keyOfSponsor[:printlen]), "...")
|
||||
if bytes.Compare(keyOfResponsor, keyOfSponsor) != 0 {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
// t.Log("OK\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyExchange2(t *testing.T) {
|
||||
sponsorID := []byte("Alice")
|
||||
responsorID := []byte("Bob")
|
||||
// Set random test data
|
||||
ska, _ := GenPrivateKey(nil)
|
||||
skb, _ := GenPrivateKey(nil)
|
||||
aliceC := new(big.Int)
|
||||
aliceC.SetString("0f136aaf135e03c43ed91131f45ea81d1defdef283efbd8493c4769886a6c677", 16)
|
||||
aliceS := new(big.Int)
|
||||
aliceS.SetString("70f88a29a9664d41f0aadb56b5802c116c4b6c69075550e246f2e6a168a157e9", 16)
|
||||
bobC := new(big.Int)
|
||||
bobC.SetString("0c16e4a0fe04131454dccf03243492c95f0126b71a5d804c7d11fc899d4ab9b2", 16)
|
||||
bobS := new(big.Int)
|
||||
bobS.SetString("f4b87de5b4c6559cd09d5539b3cd1a41eb898dbf9397af33b5e6afa4c7bd4c71", 16)
|
||||
|
||||
N := sm2Curve.Params().N
|
||||
ska.D.Add(aliceC, aliceS)
|
||||
ska.D.Mod(ska.D, N)
|
||||
skb.D.Add(bobC, bobS)
|
||||
skb.D.Mod(skb.D, N)
|
||||
|
||||
// 使用默认id传入nil或GetDefaultID
|
||||
s := NewSponsor(sponsorID, ska)
|
||||
rs := NewResponsor(responsorID, skb)
|
||||
// NEVER FORGET CLEAR
|
||||
defer ska.Clear()
|
||||
defer skb.Clear()
|
||||
defer s.Clear()
|
||||
defer rs.Clear()
|
||||
|
||||
// 多次密钥交换是可以重复使用Sponsor和Responsor的-只要其私钥和id不变
|
||||
|
||||
// t.Log("key exchange test for key length = ", keylen)
|
||||
keylen := 32
|
||||
// key exchange
|
||||
tempKeyOfSponsor, _ := s.GenerateAgreementData(nil)
|
||||
|
||||
keyOfResponsor, tempKeyOfResponsor, _ := rs.GenerateAgreementDataAndKey(sponsorID, GenPublicKey(ska), tempKeyOfSponsor, keylen, nil)
|
||||
keyOfSponsor, _ := s.GenerateKey(responsorID, GenPublicKey(skb), tempKeyOfResponsor, keylen)
|
||||
fmt.Println("Ra=", tempKeyOfSponsor)
|
||||
fmt.Println("Rb=", tempKeyOfResponsor)
|
||||
// check if OK
|
||||
t.Log("responsor: ", hex.EncodeToString(keyOfResponsor[:]), "...")
|
||||
t.Log("sponsor : ", hex.EncodeToString(keyOfSponsor[:]), "...")
|
||||
if bytes.Compare(keyOfResponsor, keyOfSponsor) != 0 {
|
||||
t.Fail()
|
||||
return
|
||||
|
||||
// t.Log("OK\n")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyExchange3(t *testing.T) {
|
||||
ida := []byte("Sponsor")
|
||||
idb := []byte("Responsor")
|
||||
ska, _ := GenerateKey(Curve(), grand.Reader)
|
||||
skb, _ := GenerateKey(Curve(), grand.Reader)
|
||||
keyLen := 64
|
||||
|
||||
pa, err := GenerateAgreementData(grand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal("GenerateAgreementData: " + err.Error())
|
||||
}
|
||||
kb, pb, err := GenerateAgreementDataAndKey(idb, skb, ida, &ska.PublicKey, pa.PublicKey(), keyLen, grand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal("GenerateAgreementDataAndKey: " + err.Error())
|
||||
}
|
||||
ka, err := GenerateSharedKey(pa, ida, ska, idb, &skb.PublicKey, pb.PublicKey(), keyLen)
|
||||
if err != nil {
|
||||
t.Fatal("GenerateSharedKey: " + err.Error())
|
||||
}
|
||||
if bytes.Compare(ka, kb) != 0 {
|
||||
t.Fatal("bytes.Compare not equal")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//x2rb= 4218415632c9e1dc64847e0eec2d389fabc363a050323e55c577ffc134b46014
|
||||
//x1Ra= a8e1a22f6684166804e1b9618f021306398669caded533f0cb22ddcbe6b07b1b 9b0cb1c02167fa8f449b03b8972b26689b2fdba41b5ea29ce3091882a96e6270
|
||||
//响应方V= ca53c881f2fc9d4863f8e484482ee029dcb1ee9f2f0001327d8140267ada7f37 80c869a8cab20c73ca497aba68a6574e5371b964fb8727682c66abacd848e45d
|
||||
//x1ra= d9231754b214e5d6adc81e2dbde50a777ad7d0609020f566dc8a91f2b2a4621f
|
||||
//x2Rb= 2a223af3c1012c753ab4f4aa51f1d9388e016c5a925715be1632d1710825043e c555b658c20d17a32dccb421f044bb26b4ad53c3ca574fe4999cdb8a2e582016
|
||||
|
||||
func TestU(t *testing.T) {
|
||||
ux := new(big.Int)
|
||||
ux.SetString("76c72b6b721c07e98a179e37bfd8f871276abe81e3097a44883394fac89ff3fd", 16)
|
||||
uy := new(big.Int)
|
||||
uy.SetString("663085bc7794789eb4593b8b8a7abf422e4acf5ec475b7078c5baf03b3a115b8", 16)
|
||||
aliceC := new(big.Int)
|
||||
aliceC.SetString("0f136aaf135e03c43ed91131f45ea81d1defdef283efbd8493c4769886a6c677", 16)
|
||||
aliceS := new(big.Int)
|
||||
aliceS.SetString("70f88a29a9664d41f0aadb56b5802c116c4b6c69075550e246f2e6a168a157e9", 16)
|
||||
bobC := new(big.Int)
|
||||
bobC.SetString("0c16e4a0fe04131454dccf03243492c95f0126b71a5d804c7d11fc899d4ab9b2", 16)
|
||||
bobS := new(big.Int)
|
||||
bobS.SetString("f4b87de5b4c6559cd09d5539b3cd1a41eb898dbf9397af33b5e6afa4c7bd4c71", 16)
|
||||
|
||||
x, y := sm2Curve.ScalarMult(ux, uy, aliceS.Bytes())
|
||||
fmt.Println("发起方服务端返回数据= ", x.Text(16), y.Text(16))
|
||||
|
||||
ux.SetString("21c77774c165bcc3c128908a9128acd63418accfed1a4699e34bd09ed80915f7", 16)
|
||||
uy.SetString("f69ea4620a47dfb40957b80f675de2304893c4dd00cad15aa6aaa16bbd023ca7", 16)
|
||||
x, y = sm2Curve.ScalarMult(ux, uy, aliceS.Bytes())
|
||||
fmt.Println("响应方服务端返回数据= ", x.Text(16), y.Text(16))
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
// Test Cipher
|
||||
func TestCipherP7(t *testing.T) {
|
||||
sk, _ := GenerateKey(Curve(), grand.Reader)
|
||||
data := make([]byte, 48)
|
||||
cipher, _ := Encrypt(&sk.PublicKey, data, grand.GetRandom(32))
|
||||
b, err := cipher.MarshalASN1()
|
||||
assert.Nil(t, err)
|
||||
|
||||
var cipher2 Cipher
|
||||
b, err = cipher2.UnmarshalASN1(b)
|
||||
assert.Equal(t, len(b), 0)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, cipher.String(), cipher2.String())
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/grand"
|
||||
)
|
||||
|
||||
// Sign 50000, used time: 1085 ms, 46082 pcs/s
|
||||
// verify 50000, used time: 3368 ms, 14845 pcs/s
|
||||
func TestSpeedSign(t *testing.T) {
|
||||
e := grand.GetRandom(ByteSize())
|
||||
k := grand.GetRandom(ByteSize())
|
||||
buf := grand.GetRandom(ByteSize())
|
||||
d, _ := GenPrivateKey(buf)
|
||||
|
||||
var sig *Signature
|
||||
cnt := 50000
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
sig, _ = Sign(e, k, d)
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
fmt.Printf("Sign %d, used time: %d ms, %d pcs/s\n", cnt, elapsed.Milliseconds(), int(float64(cnt)/float64(elapsed.Milliseconds())*1000))
|
||||
|
||||
pk := GenPublicKey(d)
|
||||
|
||||
start = time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
_ = Verify(e, pk, sig)
|
||||
}
|
||||
end = time.Now()
|
||||
elapsed = end.Sub(start)
|
||||
fmt.Printf("verify %d, used time: %d ms, %d pcs/s\n", cnt, elapsed.Milliseconds(), int(float64(cnt)/float64(elapsed.Milliseconds())*1000))
|
||||
|
||||
}
|
||||
|
||||
func TestSpeedEnc(t *testing.T) {
|
||||
fmt.Println("SM2加密性能测试")
|
||||
for i := 0; i < 3; i++ {
|
||||
fmt.Printf("第%d次测试: \n", i+1)
|
||||
sk, err := GenerateKey(Curve(), grand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pk := &sk.PublicKey
|
||||
data := make([]byte, 128*1024)
|
||||
if _, err := io.ReadFull(grand.Reader, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cnt := 8000
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
cipher, err := Encrypt(pk, data, grand.GetRandom(32))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = cipher
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
fmt.Printf("加密数据: %dKB\n", len(data)/1024)
|
||||
fmt.Printf("循环次数: %d\n", cnt)
|
||||
fmt.Printf("耗时时间(秒): %f\n", float64(elapsed.Seconds()))
|
||||
fmt.Printf("加密速率: %.2f Kbps\n", float64(8*len(data)*cnt)/(1024*elapsed.Seconds()))
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSpeedDec(t *testing.T) {
|
||||
fmt.Println("")
|
||||
fmt.Println("SM2: 解密性能测试")
|
||||
fmt.Println("测试结果: ")
|
||||
fmt.Println("")
|
||||
sk, err := GenerateKey(Curve(), grand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pk := &sk.PublicKey
|
||||
|
||||
data := make([]byte, 128*1024)
|
||||
if _, err := io.ReadFull(grand.Reader, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cipher, _ := Encrypt(pk, data, grand.GetRandom(32))
|
||||
cnt := 1000
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
decryptedData, err := Decrypt(sk, cipher)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_ = decryptedData
|
||||
}
|
||||
end := time.Now()
|
||||
elapsed := end.Sub(start)
|
||||
fmt.Printf("解密数据: %dKB\n", len(data)/1024)
|
||||
fmt.Printf("解密结果: 成功\n")
|
||||
fmt.Printf("耗时时间(单位: 秒): %f\n", float64(elapsed.Seconds())/float64(cnt))
|
||||
fmt.Printf("解密速率: %f Mbps\n", float64(8*len(data)*cnt)/(1024*1024*elapsed.Seconds()))
|
||||
fmt.Println()
|
||||
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
package sm2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/internal"
|
||||
)
|
||||
|
||||
func hexDecode(s string) []byte {
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func TestAudit(t *testing.T) {
|
||||
if !(Auditor{}).Correctness() {
|
||||
t.Fatal("Correctness check failed")
|
||||
}
|
||||
}
|
||||
|
||||
// TestCurve test speed of sm2 curve on ScalarMult and ScalarBaseMult.
|
||||
// A litter slower than P256 curve.
|
||||
func TestCurve(t *testing.T) {
|
||||
gx, gy := Curve().Params().Gx, Curve().Params().Gy
|
||||
k := make([]byte, 32)
|
||||
grand.GenerateRandom(k)
|
||||
|
||||
count, duation := internal.SingleThreadTester(func() {
|
||||
sm2Curve.ScalarMult(gx, gy, k)
|
||||
})
|
||||
fmt.Printf("SM2Curve ScalarMult: %d times/Sec\n", int(internal.Rate(count, duation)))
|
||||
|
||||
count, duation = internal.SingleThreadTester(func() {
|
||||
sm2Curve.ScalarBaseMult(k)
|
||||
})
|
||||
fmt.Printf("SM2Curve ScalarBaseMult: %d times/Sec\n", int(internal.Rate(count, duation)))
|
||||
}
|
||||
|
||||
// TestP256Curve test speed of P256 curve on ScalarMult and ScalarBaseMult.
|
||||
func TestP256Curve(t *testing.T) {
|
||||
c := elliptic.P256()
|
||||
gx, gy := c.Params().Gx, c.Params().Gy
|
||||
k := make([]byte, 32)
|
||||
grand.GenerateRandom(k)
|
||||
|
||||
count, duation := internal.SingleThreadTester(func() {
|
||||
c.ScalarMult(gx, gy, k)
|
||||
})
|
||||
fmt.Printf("P256 ScalarMult: %d times/Sec\n", int(internal.Rate(count, duation)))
|
||||
|
||||
count, duation = internal.SingleThreadTester(func() {
|
||||
c.ScalarBaseMult(k)
|
||||
})
|
||||
fmt.Printf("P256 ScalarBaseMult: %d times/Sec\n", int(internal.Rate(count, duation)))
|
||||
}
|
||||
|
||||
// func TestKeyGen(t *testing.T) {
|
||||
// sk, _ := GenPrivateKey(grand.GetRandom(32))
|
||||
// pk := GenPublicKey(sk)
|
||||
|
||||
// sm4Key := make([]byte, 16)
|
||||
// buf := make([]byte, 0)
|
||||
// fp, err := os.OpenFile("/Users/fengwd/Codes/go/src/xdx.jelly/xgcl/sm/sm2/key", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
// if err != nil {
|
||||
// panic("openfile failed")
|
||||
// }
|
||||
// for i := 0; i < 1000; i++ {
|
||||
// buf = buf[:0]
|
||||
// if i%1000 == 0 {
|
||||
// fmt.Printf("%d\n", i)
|
||||
// }
|
||||
// usk, _ := GenPrivateKey(grand.GetRandom(32))
|
||||
// upk := GenPublicKey(sk)
|
||||
// grand.GenerateRandom(sm4Key)
|
||||
// tmp, _ := usk.MarshalBinary()
|
||||
// buf = append(buf, tmp...)
|
||||
// tmp, _ = upk.MarshalBinary()
|
||||
// buf = append(buf, tmp...)
|
||||
// buf = padding.P7.Pad(buf, 16)
|
||||
// buf, _ = sm4.EncryptECB(buf, sm4Key, buf)
|
||||
// cipher, _ := Encrypt(pk, sm4Key, nil)
|
||||
// tmp, _ = cipher.MarshalBinary()
|
||||
// buf = append(buf, tmp...)
|
||||
// fp.Write(buf)
|
||||
|
||||
// }
|
||||
|
||||
// fp.Close()
|
||||
// }
|
||||
|
||||
func TestKeyValid(t *testing.T) {
|
||||
{
|
||||
k, _ := hex.DecodeString("000001000000000000000000000000000000000000000000000000000000000000000000972b80815e2c29e837fd006dc05534373950b221a090ad8dbeaa6e787bbbc85b00000000000000000000000000000000000000000000000000000000000000009ec521bc8fe61d2cfbc3bb8d4748ee6eb56e33d5955dba236f21085264095fa8")
|
||||
// pk := NewPublicKey()
|
||||
pk := &PublicKey{}
|
||||
pk.UnmarshalBinary(k)
|
||||
b, _ := pk.MarshalBinary()
|
||||
assert.Equal(t, k, b)
|
||||
}
|
||||
{
|
||||
k := NewPrivateKey().Random(grand.Reader)
|
||||
pk := (&PublicKey{}).Generate(k)
|
||||
b, _ := pk.MarshalBinary()
|
||||
pk1 := &PublicKey{}
|
||||
pk1.UnmarshalBinary(b)
|
||||
assert.True(t, pk1.Equal(pk))
|
||||
assert.True(t, pk.IsValid())
|
||||
assert.True(t, pk1.IsValid())
|
||||
}
|
||||
}
|
||||
func TestPreComputeWithIdAndPubkey(t *testing.T) {
|
||||
var r [32]byte
|
||||
r[31] = 1
|
||||
sk, _ := GenPrivateKey(r[:])
|
||||
pk := GenPublicKey(sk)
|
||||
e := PreComputeWithIdAndPubkey(nil, pk)
|
||||
assert.Equal(t, e, hexDecode("5b32bfe35482899b195d72c09d33ccdb465b2ded883240ff91f120a68bc91de8"))
|
||||
}
|
||||
|
||||
func TestSignStd(t *testing.T) {
|
||||
m := []byte("message digest")
|
||||
buf, _ := hex.DecodeString("3945208F7B2144B13F36E38AC6D39F95889393692860B51A42FB81EF4DF7C5B8")
|
||||
d, _ := GenPrivateKey(buf)
|
||||
pk := GenPublicKey(d)
|
||||
e := PreComputeWithIdAndPubkeyAndMessage(nil, m, pk)
|
||||
k, err := hex.DecodeString("59276E27D506861A16680F3AD9C02DCCEF3CC1FA3CDBE4CE6D54B80DEAC1BC21")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%x\n", e)
|
||||
fmt.Println(pk.X.Text(16))
|
||||
fmt.Println(pk.Y.Text(16))
|
||||
|
||||
sig, err := Sign(e, k, d)
|
||||
if err != nil {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
data, err := sig.MarshalBinary()
|
||||
if err != nil {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
}
|
||||
if hex.EncodeToString(data) != "0000000000000000000000000000000000000000000000000000000000000000f5a03b0648d2c4630eeac513e1bb81a15944da3827d5b74143ac7eaceee720b30000000000000000000000000000000000000000000000000000000000000000b1b6aa29df212fd8763182bc0d421ca1bb9038fd1f7f42d4840b69c485bbc1aa" {
|
||||
t.Log()
|
||||
t.Fail()
|
||||
}
|
||||
assert.True(t, Verify(e, pk, sig))
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
e := hexDecode("3854C463FA3F73783621B1CE4EF83F7C78048AAC79B221FCDD290866CC131174")
|
||||
k := hexDecode("F026AD9A7EB94401A800C8D8C3277E69972C7F3778ACE4D537012023EDFB69FF")
|
||||
d, err := GenPrivateKey(hexDecode("C242939DDAB6FCC07B6676C07D2DC117EC68A09142C25C008630B9756786162D"))
|
||||
assert.Nil(t, err)
|
||||
|
||||
sig, err := Sign(e, k, d)
|
||||
assert.Nil(t, err)
|
||||
|
||||
data, err := sig.MarshalBinary()
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, data, hexDecode("00000000000000000000000000000000000000000000000000000000000000006e5db49dbd0992b97040080a96003c721cdb9cf64c88d74321fc2f630adf377400000000000000000000000000000000000000000000000000000000000000002f6dff453dfc8d7a506d3f52301bee529e62fddd38948f0d5d2cbcbc55900cfa"))
|
||||
|
||||
sig1 := NewSignature()
|
||||
assert.Nil(t, sig1.UnmarshalBinary(data))
|
||||
assert.Equal(t, sig1.R.Cmp(sig.R), 0)
|
||||
assert.Equal(t, sig1.S.Cmp(sig.S), 0)
|
||||
|
||||
pk := GenPublicKey(d)
|
||||
fmt.Println(pk)
|
||||
data, err = pk.MarshalBinary()
|
||||
assert.Nil(t, err)
|
||||
|
||||
pk1 := NewPublicKey()
|
||||
assert.Nil(t, pk1.UnmarshalBinary(data))
|
||||
assert.Equal(t, fmt.Sprintf("%#v", pk), fmt.Sprintf("%#v", pk1))
|
||||
|
||||
assert.True(t, Verify(e, pk, sig))
|
||||
}
|
||||
|
||||
// (r,s)是e,pk的签名,则(r, -(s + 2rd/(1+d))也是e,pk的签名
|
||||
func TestSignDual(t *testing.T) {
|
||||
e := hexDecode("3854C463FA3F73783621B1CE4EF83F7C78048AAC79B221FCDD290866CC131174")
|
||||
k := hexDecode("F026AD9A7EB94401A800C8D8C3277E69972C7F3778ACE4D537012023EDFB69FF")
|
||||
sk, _ := GenPrivateKey(hexDecode("C242939DDAB6FCC07B6676C07D2DC117EC68A09142C25C008630B9756786162D"))
|
||||
pk := GenPublicKey(sk)
|
||||
|
||||
var sig *Signature
|
||||
sig, err := Sign(e, k, sk)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.True(t, Verify(e, pk, sig))
|
||||
|
||||
// s' = -(s + 2rd(1+d)^-1)
|
||||
tmp := big.NewInt(1)
|
||||
tmp.Add(tmp, sk.D)
|
||||
tmp.ModInverse(tmp, OrderN())
|
||||
tmp.Mul(tmp, sk.D)
|
||||
tmp.Mul(tmp, sig.R)
|
||||
tmp.Lsh(tmp, 1)
|
||||
tmp.Add(tmp, sig.S)
|
||||
tmp.Mod(tmp, OrderN())
|
||||
tmp.Sub(OrderN(), tmp)
|
||||
sig.S.Set(tmp)
|
||||
|
||||
assert.True(t, Verify(e, pk, sig))
|
||||
}
|
||||
|
||||
// 已知公钥P, 则可任意取r,s,并构造e = r-X(sG+(r+s)P)
|
||||
// verify(r,s,P,e) = true
|
||||
func TestSignForge(t *testing.T) {
|
||||
|
||||
d, err := hex.DecodeString("C242939DDAB6FCC07B6676C07D2DC117EC68A09142C25C008630B9756786162D")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
sk, _ := GenPrivateKey(d)
|
||||
pk := GenPublicKey(sk)
|
||||
|
||||
r, _ := rand.Int(grand.Reader, OrderN())
|
||||
s, _ := rand.Int(grand.Reader, OrderN())
|
||||
|
||||
u := big.NewInt(0)
|
||||
u.Add(r, s)
|
||||
u.Mod(u, OrderN())
|
||||
x1, y1 := Curve().ScalarMult(pk.X, pk.Y, u.Bytes())
|
||||
x2, y2 := Curve().ScalarBaseMult(s.Bytes())
|
||||
x1, _ = Curve().Add(x1, y1, x2, y2)
|
||||
e := new(big.Int)
|
||||
e = e.Sub(r, x1)
|
||||
e.Mod(e, OrderN())
|
||||
|
||||
sig := new(Signature)
|
||||
sig.S = s
|
||||
sig.R = r
|
||||
|
||||
assert.True(t, Verify(e.Bytes(), pk, sig))
|
||||
|
||||
}
|
||||
|
||||
func TestEncrypt(t *testing.T) {
|
||||
sk, _ := GenPrivateKey([]byte{
|
||||
0x81, 0x98, 0x7C, 0xC9, 0x0C, 0xF5, 0x05, 0x7C,
|
||||
0x2D, 0xCA, 0xA7, 0x5D, 0x1F, 0xDD, 0xCA, 0x84,
|
||||
0xB2, 0x48, 0x62, 0xF0, 0xCA, 0xD7, 0x3C, 0x7F,
|
||||
0x67, 0x34, 0x9A, 0xE6, 0x99, 0xB9, 0x29, 0x83},
|
||||
)
|
||||
|
||||
rnd := []byte{
|
||||
0x26, 0xD6, 0x16, 0x3F, 0xA1, 0x86, 0x03, 0xEE,
|
||||
0x2F, 0x3D, 0xE8, 0x93, 0x65, 0x44, 0xD5, 0xDF,
|
||||
0x12, 0x55, 0xA2, 0xDB, 0xEB, 0xA6, 0x3A, 0xFC,
|
||||
0x0D, 0x83, 0x3E, 0xC4, 0x49, 0xD2, 0xCB, 0x45,
|
||||
}
|
||||
|
||||
msg := []byte{
|
||||
0xC3, 0x53, 0xC6, 0x8E, 0xF0, 0x5C, 0x4B, 0x34,
|
||||
0x2B, 0x37, 0x7D, 0xA0, 0x55, 0xD9, 0x09, 0xFB,
|
||||
0x1F, 0xAA, 0x42, 0x55, 0x66, 0x2F, 0x3B, 0xAB,
|
||||
0x8D, 0xDB, 0x35, 0x35, 0xE4, 0x0B, 0xC9, 0x3B,
|
||||
}
|
||||
|
||||
wantCipher := "bf6cfcb8e6295dc22777376f8385c5d6aadd5e430d11e004246d6bebf99ec5249cb9ab2f9af688c77a1bdf9f3b0816a4eab7f5da22e5dacdc1c8f6e45499874e1fc32e35744161aa0ffa6c70fc811d3b66d4cacda3c0996b54768c603c6b24e0c85cdde8ad71a258b89ddb42da900bcf4f18ab52d7841134cac581d3cf7f58f7"
|
||||
pk := GenPublicKey(sk)
|
||||
|
||||
// pk.X.Add(pk.X, gmath.BigInt1)
|
||||
// fmt.Println(hex.EncodeToString(pk.x[:]) + hex.EncodeToString(pk.y[:]))
|
||||
cipher, err := Encrypt(pk, msg, rnd)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
if hex.EncodeToString(cipher.Bytes()) != wantCipher {
|
||||
t.Log("Encrypt Failed")
|
||||
t.Log("cipher :", hex.EncodeToString(cipher.Bytes()))
|
||||
t.Log("WantCipher:", wantCipher)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
// marshal test
|
||||
// t.Log(cipher)
|
||||
data, _ := cipher.MarshalBinary()
|
||||
// t.Log(hex.EncodeToString(data))
|
||||
cipher1 := NewCipher()
|
||||
if err := cipher1.UnmarshalBinary(data); err != nil {
|
||||
t.Log("unmarshal failed")
|
||||
}
|
||||
if fmt.Sprintf("%#v", cipher) != fmt.Sprintf("%#v", cipher1) {
|
||||
t.Log("Marshal Test failed")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
//Decrypt
|
||||
decryptedMsg, err := Decrypt(sk, cipher)
|
||||
if err != nil || bytes.Compare(decryptedMsg, msg) != 0 {
|
||||
t.Log(err)
|
||||
t.Log("decryptedMsg :", hex.EncodeToString(decryptedMsg))
|
||||
t.Log("msg :", hex.EncodeToString(msg))
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// func TestErrors(t *testing.T) {
|
||||
// errors.PrintErrorInfos(os.Stdout)
|
||||
// }
|
||||
|
||||
func TestZeroHashSign(t *testing.T) {
|
||||
zeroHash := make([]byte, 32)
|
||||
|
||||
for _, curve := range []elliptic.Curve{Curve()} {
|
||||
privKey, err := GenerateKey(curve, rand.Reader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Sign a hash consisting of all zeros.
|
||||
// r, s, err := Sign(rand.Reader, privKey, zeroHash)
|
||||
k := make([]byte, 32)
|
||||
grand.GenerateRandom(k)
|
||||
sig, err := Sign(zeroHash, k, privKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Confirm that it can be verified.
|
||||
if !Verify(zeroHash, privKey.Public().(*PublicKey), sig) {
|
||||
t.Errorf("zero hash signature verify failed for %T", curve)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncEmpty(t *testing.T) {
|
||||
sk, _ := GenPrivateKey([]byte{
|
||||
0x81, 0x98, 0x7C, 0xC9, 0x0C, 0xF5, 0x05, 0x7C,
|
||||
0x2D, 0xCA, 0xA7, 0x5D, 0x1F, 0xDD, 0xCA, 0x84,
|
||||
0xB2, 0x48, 0x62, 0xF0, 0xCA, 0xD7, 0x3C, 0x7F,
|
||||
0x67, 0x34, 0x9A, 0xE6, 0x99, 0xB9, 0x29, 0x83},
|
||||
)
|
||||
|
||||
rnd := []byte{
|
||||
0x26, 0xD6, 0x16, 0x3F, 0xA1, 0x86, 0x03, 0xEE,
|
||||
0x2F, 0x3D, 0xE8, 0x93, 0x65, 0x44, 0xD5, 0xDF,
|
||||
0x12, 0x55, 0xA2, 0xDB, 0xEB, 0xA6, 0x3A, 0xFC,
|
||||
0x0D, 0x83, 0x3E, 0xC4, 0x49, 0xD2, 0xCB, 0x45,
|
||||
}
|
||||
|
||||
msg := []byte{}
|
||||
|
||||
pk := &sk.PublicKey
|
||||
cipher, err := Encrypt(pk, msg, rnd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
decryptedMsg, err := Decrypt(sk, cipher)
|
||||
if err != nil || bytes.Compare(decryptedMsg, msg) != 0 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncLong(t *testing.T) {
|
||||
sk, err := GenerateKey(Curve(), grand.Reader)
|
||||
pk := &sk.PublicKey
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data := make([]byte, 409600)
|
||||
if _, err := io.ReadFull(grand.Reader, data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cipher, err := Encrypt(pk, data, grand.GetRandom(32))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
decryptedData, err := Decrypt(sk, cipher)
|
||||
if err != nil || bytes.Compare(decryptedData, data) != 0 {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSM2Point(t *testing.T) {
|
||||
x, _ := new(big.Int).SetString("54cb2e421e7119ddbba44ff0db131e9907ed90a1b0b9a23b9d3eb890519d5cae", 16)
|
||||
y, _ := new(big.Int).SetString("389646ab568a3bd7a566e1e49b98a4d41041b2fa2cf0af74fceef65ef1e986c6", 16)
|
||||
|
||||
pk := &PublicKey{
|
||||
Curve: Curve(),
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
assert.True(t, pk.IsValid())
|
||||
}
|
||||
|
||||
// func TestSM2Verify(t *testing.T) {
|
||||
// r, _ := new(big.Int).SetString("d3233fe6b680f1fc26bb4932b894af1e9e73c700554c39f407ac91c4d4d74347", 16)
|
||||
// s, _ := new(big.Int).SetString("08bc7476b0fd496287d162dfab5a68a340515b3f8647ed03f75c4d1b50aeb957", 16)
|
||||
// x, _ := new(big.Int).SetString("6a3f992330c0857eda4b914ebef614bf401266fb6168e3f90475ed1fcd3c2625", 16)
|
||||
// y, _ := new(big.Int).SetString("36341b6383d996205996aa164480bad952aa07a0db942858d103bf8f2f4b460a", 16)
|
||||
// pk := &PublicKey{
|
||||
// Curve: Curve(),
|
||||
// X: x,
|
||||
// Y: y,
|
||||
// }
|
||||
// sig := &Signature{
|
||||
// R: r,
|
||||
// S: s,
|
||||
// }
|
||||
// assert.True(t, pk.IsValid())
|
||||
// e, _ := hex.DecodeString("c3e283e5ad232e04b29d2422a88fb251cd08cad4f0e8b77cdcdd7859eb6fabd7")
|
||||
// // e = PreComputeWithIdAndPubkeyAndMessage(GetDefaultID(), e, pk)
|
||||
|
||||
// assert.True(t, Verify(e, pk, sig))
|
||||
// e, _ = hex.DecodeString("8d3eef66a23e3118a7b32a386cd1db41bc4e7a803098ee92c6b5cda43829ad96")
|
||||
// // e = PreComputeWithIdAndPubkeyAndMessage(GetDefaultID(), e, pk)
|
||||
// assert.True(t, Verify(e, pk, sig))
|
||||
// }
|
||||
Reference in New Issue
Block a user