init: v1.0.0
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
"xdx.jelly/xgcl/sm/sm2/ec256"
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
var param = sm2.Curve().Params()
|
||||
var c256 = sm2.Curve().(ec256.SM2CurveParam)
|
||||
|
||||
func testScalarMult() {
|
||||
for i := 0; i < 1000; i++ {
|
||||
k, _ := rand.Int(rand.Reader, param.N)
|
||||
|
||||
x1, y1 := param.ScalarMult(param.Gx, param.Gy, k.Bytes())
|
||||
x2, y2 := c256.CurveParams.ScalarMult(param.Gx, param.Gy, k.Bytes())
|
||||
|
||||
assertEqual(x1, x2)
|
||||
assertEqual(y1, y2)
|
||||
}
|
||||
}
|
||||
|
||||
func testScalarBaseMult() {
|
||||
for i := 0; i < 1000; i++ {
|
||||
k, _ := rand.Int(rand.Reader, param.N)
|
||||
x1, y1 := param.ScalarBaseMult(k.Bytes())
|
||||
x2, y2 := c256.CurveParams.ScalarBaseMult(k.Bytes())
|
||||
|
||||
assertEqual(x1, x2)
|
||||
assertEqual(y1, y2)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
n := 10000000
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
for i := 0; i < n; i++ {
|
||||
if i%10 == 0 {
|
||||
fmt.Printf("testScalarBaseMult - %d\n", 1000*i)
|
||||
}
|
||||
testScalarBaseMult()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
go func() {
|
||||
for i := 0; i < n; i++ {
|
||||
if i%10 == 0 {
|
||||
fmt.Printf("testScalarMult - %d\n", 1000*i)
|
||||
}
|
||||
testScalarMult()
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
OS=$(shell uname)
|
||||
|
||||
ifeq (${OS}, Linux)
|
||||
LIB=libgcl.so
|
||||
endif
|
||||
ifeq (${OS}, Darwin)
|
||||
LIB=libgcl.dylib
|
||||
endif
|
||||
|
||||
TEST=test
|
||||
|
||||
All: lib test
|
||||
|
||||
lib: staticlib gcl.c
|
||||
gcc -fPIC -shared -o ${LIB} -L. gcl.c -lgcl_go
|
||||
|
||||
test: lib main.c
|
||||
gcc -o ${TEST} main.c -L. -lgcl -lpthread
|
||||
|
||||
staticlib: lib.go
|
||||
go build -buildmode=c-archive -o libgcl_go.a lib.go
|
||||
android:
|
||||
GOOS=android GOARCH=arm64 go build -buildmode=c-archive -o libgcl_go.a lib.go
|
||||
clean:
|
||||
rm -f libgcl_go.a *.dylib *.so ${LIB} ${TEST}
|
||||
@@ -0,0 +1,35 @@
|
||||
# 简介
|
||||
输出gcl中的功能为C库
|
||||
|
||||
步骤:
|
||||
- lib.go中编写要输出的函数:
|
||||
```
|
||||
//export Sm3
|
||||
func Sm3(in []byte, out []byte) {
|
||||
d := sm3.Sum(in)
|
||||
copy(out, d[:])
|
||||
}
|
||||
```
|
||||
- 生成go导出的C库(c-archive)
|
||||
```
|
||||
go build -buildmode=c-archive -o libgcl_go.a lib.go
|
||||
```
|
||||
- lib.c中编写C包装代码
|
||||
```
|
||||
int sm3(void *data, int dataLen, void *digest){
|
||||
// input check, omit
|
||||
|
||||
GoSlice in = {
|
||||
data, dataLen, dataLen
|
||||
};
|
||||
GoSlice out = {
|
||||
digest, 32, 32
|
||||
};
|
||||
Sm3(in,out);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
- gcc编译gcl.c为动态库
|
||||
```
|
||||
gcc -shared -o libgcl.dylib -L. -lgcl_go gcl.c
|
||||
```
|
||||
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
)
|
||||
|
||||
//export Sm3
|
||||
func Sm3(in []byte, out []byte) {
|
||||
d := sm3.Sum(in)
|
||||
copy(out, d[:])
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("...")
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "libgcl_go.h"
|
||||
|
||||
int sm3(void *data, int dataLen, void *digest){
|
||||
GoSlice in = {
|
||||
data, dataLen, dataLen
|
||||
};
|
||||
GoSlice out = {
|
||||
digest, 32, 32
|
||||
};
|
||||
Sm3(in,out);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef LIBGCL_H_
|
||||
#define LIBGCL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
int sm3(void *data, int dataLen, void *digest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // LIBGCL_H_
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Code generated by cmd/cgo; DO NOT EDIT. */
|
||||
|
||||
/* package command-line-arguments */
|
||||
|
||||
|
||||
#line 1 "cgo-builtin-export-prolog"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef GO_CGO_EXPORT_PROLOGUE_H
|
||||
#define GO_CGO_EXPORT_PROLOGUE_H
|
||||
|
||||
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
||||
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* Start of preamble from import "C" comments. */
|
||||
|
||||
|
||||
|
||||
|
||||
/* End of preamble from import "C" comments. */
|
||||
|
||||
|
||||
/* Start of boilerplate cgo prologue. */
|
||||
#line 1 "cgo-gcc-export-header-prolog"
|
||||
|
||||
#ifndef GO_CGO_PROLOGUE_H
|
||||
#define GO_CGO_PROLOGUE_H
|
||||
|
||||
typedef signed char GoInt8;
|
||||
typedef unsigned char GoUint8;
|
||||
typedef short GoInt16;
|
||||
typedef unsigned short GoUint16;
|
||||
typedef int GoInt32;
|
||||
typedef unsigned int GoUint32;
|
||||
typedef long long GoInt64;
|
||||
typedef unsigned long long GoUint64;
|
||||
typedef GoInt64 GoInt;
|
||||
typedef GoUint64 GoUint;
|
||||
typedef size_t GoUintptr;
|
||||
typedef float GoFloat32;
|
||||
typedef double GoFloat64;
|
||||
#ifdef _MSC_VER
|
||||
#include <complex.h>
|
||||
typedef _Fcomplex GoComplex64;
|
||||
typedef _Dcomplex GoComplex128;
|
||||
#else
|
||||
typedef float _Complex GoComplex64;
|
||||
typedef double _Complex GoComplex128;
|
||||
#endif
|
||||
|
||||
/*
|
||||
static assertion to make sure the file is being used on architecture
|
||||
at least with matching size of GoInt.
|
||||
*/
|
||||
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64/8 ? 1:-1];
|
||||
|
||||
#ifndef GO_CGO_GOSTRING_TYPEDEF
|
||||
typedef _GoString_ GoString;
|
||||
#endif
|
||||
typedef void *GoMap;
|
||||
typedef void *GoChan;
|
||||
typedef struct { void *t; void *v; } GoInterface;
|
||||
typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
||||
|
||||
#endif
|
||||
|
||||
/* End of boilerplate cgo prologue. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void Sm3(GoSlice in, GoSlice out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "gcl.h"
|
||||
|
||||
|
||||
int main() {
|
||||
int msgLen = 10*1024*1024;
|
||||
char *msg = malloc(msgLen);
|
||||
char digest[32];
|
||||
|
||||
clock_t start, end;
|
||||
int count = 100;
|
||||
start = clock();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sm3(msg, msgLen, &digest);
|
||||
}
|
||||
end = clock();
|
||||
printf("sm3: %.1fMBps\n", (double)count * msgLen/1024/1024/ ((double)(end - start) / CLOCKS_PER_SEC));
|
||||
free(msg);
|
||||
return 0;
|
||||
}
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
"xdx.jelly/xgcl/grand"
|
||||
"xdx.jelly/xgcl/he/paillier"
|
||||
"xdx.jelly/xgcl/sm/sm2"
|
||||
"xdx.jelly/xgcl/sm/sm3"
|
||||
"xdx.jelly/xgcl/tpc/sm2/sm2m"
|
||||
"xdx.jelly/xgcl/tpc/sm2/sm2m/outsource"
|
||||
)
|
||||
|
||||
type timer struct {
|
||||
totalTime float64
|
||||
last time.Time
|
||||
isStoped bool
|
||||
}
|
||||
|
||||
func (t *timer) ResetTimer() {
|
||||
t.last = time.Now()
|
||||
t.totalTime = 0
|
||||
t.isStoped = false
|
||||
}
|
||||
func (t *timer) StopTimer() {
|
||||
if t.isStoped {
|
||||
return
|
||||
}
|
||||
t.totalTime += time.Since(t.last).Seconds()
|
||||
t.isStoped = true
|
||||
}
|
||||
|
||||
func (t *timer) StartTimer() {
|
||||
if !t.isStoped {
|
||||
return
|
||||
}
|
||||
t.last = time.Now()
|
||||
t.isStoped = false
|
||||
}
|
||||
|
||||
func (t *timer) Seconds() float64 {
|
||||
t.StopTimer()
|
||||
return t.totalTime
|
||||
}
|
||||
|
||||
func testPaillierHomomorphicScalarMul() {
|
||||
_, pk, _ := paillier.GenerateKey(2048, grand.Reader)
|
||||
|
||||
limit := big.NewInt(1)
|
||||
limit.Lsh(limit, 256)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, limit)
|
||||
c, _ := paillier.Encrypt(m, pk, grand.Reader)
|
||||
|
||||
k, _ := rand.Int(grand.Reader, limit)
|
||||
|
||||
var b timer
|
||||
b.ResetTimer()
|
||||
|
||||
times := 1000
|
||||
for i := 0; i < times; i++ {
|
||||
c.HomomorphicScalarMul(c, k, pk)
|
||||
}
|
||||
b.StopTimer()
|
||||
fmt.Printf("HomomorphicScalarMul(single): %.2f per second\n", float64(times)/b.Seconds())
|
||||
}
|
||||
func testPaillierHomomorphicScalarAdd() {
|
||||
_, pk, _ := paillier.GenerateKey(2048, grand.Reader)
|
||||
|
||||
m1, _ := rand.Int(grand.Reader, pk.N)
|
||||
c1, _ := pk.Encrypt(m1, grand.Reader)
|
||||
m2, _ := rand.Int(grand.Reader, pk.N)
|
||||
c2, _ := pk.Encrypt(m2, grand.Reader)
|
||||
|
||||
var c paillier.Cipher
|
||||
times := 1000
|
||||
var b timer
|
||||
b.ResetTimer()
|
||||
for i := 0; i < times; i++ {
|
||||
c.HomomorphicAdd(c1, c2, pk)
|
||||
}
|
||||
b.StopTimer()
|
||||
fmt.Printf("HomomorphicAdd(single): %.2f per second\n", float64(times)/b.Seconds())
|
||||
}
|
||||
func testPaillierEnc() {
|
||||
_, pk, _ := paillier.GenerateKey(2048, grand.Reader)
|
||||
|
||||
m, _ := rand.Int(grand.Reader, pk.N)
|
||||
|
||||
times := 1000
|
||||
var b timer
|
||||
b.ResetTimer()
|
||||
for i := 0; i < times; i++ {
|
||||
pk.Encrypt(m, grand.Reader)
|
||||
}
|
||||
b.StopTimer()
|
||||
fmt.Printf("Encrypt(single): %.2f per second\n", float64(times)/b.Seconds())
|
||||
}
|
||||
|
||||
func testOS(N int) float64 {
|
||||
|
||||
// O、客户端生成paillier密钥
|
||||
salt := grand.GetRandom(16)
|
||||
paiPrivKey, _ := paillier.GenerateKeyFromPassword(2048, []byte("password123"), salt, 1024)
|
||||
paiPubKey := paiPrivKey.Public()
|
||||
|
||||
// 一、密钥生成
|
||||
|
||||
// 1)客户端第一步, a1, a2 发外包服务器
|
||||
clientKeyGen := &outsource.ClientKeyGenerator{}
|
||||
a1, a2, _ := clientKeyGen.Step1(paiPubKey, grand.Reader)
|
||||
|
||||
// 2) 外包服务器第一步
|
||||
// 保存encryptedClientKey1,encryptedClientKey2,
|
||||
// 把 P 发客户端
|
||||
// encryptedClientKey1 -签名用
|
||||
// encryptedClientKey2 -解密加密密钥保护结构用
|
||||
osKenGen := &outsource.OSKeyGenerator{}
|
||||
encryptedClientKey1, _, P, _ := osKenGen.Step1(a1, a2, paiPubKey, grand.Reader)
|
||||
|
||||
// 3) 客户端第二步
|
||||
// clientTempKey发协同签名服务端
|
||||
clientTempKey, _ := clientKeyGen.Step2(P)
|
||||
|
||||
// 4)协同签名服务器
|
||||
// serverTempKey 发客户端,保存serverKey-服务端密钥分量
|
||||
serverKey, serverTempKey, publicKey, _ := sm2m.ServerGenSignKey(clientTempKey, grand.GetRandom(32))
|
||||
|
||||
// 5)客户端第三步
|
||||
// 把(serverTempKey,S)发送给外包服务器
|
||||
S, _ := clientKeyGen.Step3(serverTempKey)
|
||||
|
||||
// 6)外包服务器第二步
|
||||
// 把T, osPublicKey发给客户端。保存osPublicKey为用户签名公钥
|
||||
T, osPublicKey, _ := osKenGen.Step2(serverTempKey, S)
|
||||
|
||||
// 7)客户端第四步
|
||||
// clientPublicKey, 客户端生成的公钥,如果没有返错,则应与ocPublicKey一致。
|
||||
|
||||
clientPublicKey, _ := clientKeyGen.Step4(T)
|
||||
clientPublicKey.Equals(osPublicKey)
|
||||
|
||||
e := grand.GetRandom(32)
|
||||
var b timer
|
||||
// N := 1000
|
||||
// 签名
|
||||
b.ResetTimer()
|
||||
for i := 0; i < N; i++ {
|
||||
// 1)客户端发起请求
|
||||
|
||||
// 2)外包方计算
|
||||
b.StartTimer()
|
||||
outsourcintCtx := new(outsource.OSSignContext)
|
||||
PPrime, _ := outsourcintCtx.Step1(grand.Reader) // P'
|
||||
|
||||
// outsourcintCtx把PPrime发给客户端,保存outsourcintCtx.Marshal()
|
||||
|
||||
// 3) 客户端组合数据data = (e,p)=e||px||py并发送给协同服务端
|
||||
b.StopTimer()
|
||||
data := make([]byte, sm3.Size+2*sm2.ByteSize())
|
||||
pos := copy(data, e)
|
||||
pos += copy(data[pos:], gmath.BigIntToNByte(PPrime.X, sm2.ByteSize()))
|
||||
copy(data[pos:], gmath.BigIntToNByte(PPrime.Y, sm2.ByteSize()))
|
||||
|
||||
// 4) 协同服务端计算,发回data
|
||||
b.StartTimer()
|
||||
data, _ = sm2m.ServerSign(serverKey, data, grand.Reader)
|
||||
|
||||
// 5) 客户端解析data = r || s1 || s2, 把s1, s2发给外包服务器。
|
||||
b.StopTimer()
|
||||
r := new(big.Int)
|
||||
r.SetBytes(data[:sm2.ByteSize()])
|
||||
s1 := new(big.Int).SetBytes(data[sm2.ByteSize() : 2*sm2.ByteSize()])
|
||||
s2 := new(big.Int).SetBytes(data[2*sm2.ByteSize():])
|
||||
|
||||
// 6) 外包服务器解析data并计算c,把c发送给客户端
|
||||
b.StartTimer()
|
||||
c, _ := outsourcintCtx.Step2(s1, s2, encryptedClientKey1, paiPubKey)
|
||||
|
||||
// 7) 客户端计算签名值
|
||||
b.StopTimer()
|
||||
s, _ := paillier.Decrypt(c, paiPrivKey)
|
||||
s.Sub(s, r)
|
||||
s.Mod(s, sm2.OrderN())
|
||||
sig := &sm2.Signature{
|
||||
R: r,
|
||||
S: s,
|
||||
}
|
||||
// 8) 客户端验证签名
|
||||
sm2.Verify(e, publicKey, sig)
|
||||
}
|
||||
return b.Seconds()
|
||||
// fmt.Printf("used time: %v\n", b.Seconds())
|
||||
// fmt.Printf("Outsource sign: %.2f per second\n", float64(N)/b.Seconds())
|
||||
|
||||
}
|
||||
|
||||
func multiTestOS(threads int) {
|
||||
N := 100
|
||||
|
||||
times := make([]float64, threads)
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go func(i int) {
|
||||
times[i] = testOS(N)
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
avg := 0.0
|
||||
for _, t := range times {
|
||||
avg += t
|
||||
}
|
||||
avg /= float64(threads)
|
||||
fmt.Printf("Outsource sign: %.2f per second\n", float64(N*threads)/avg)
|
||||
}
|
||||
|
||||
func main() {
|
||||
testPaillierEnc()
|
||||
testPaillierHomomorphicScalarAdd()
|
||||
testPaillierHomomorphicScalarMul()
|
||||
var threads int
|
||||
if len(os.Args) < 2 {
|
||||
threads = runtime.NumCPU()
|
||||
} else {
|
||||
threads, _ = strconv.Atoi(os.Args[1])
|
||||
}
|
||||
fmt.Println("Cores:", threads)
|
||||
multiTestOS(threads)
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"xdx.jelly/xgcl/grand/statistics"
|
||||
)
|
||||
|
||||
var suit = []struct {
|
||||
name string
|
||||
fn func([]byte) bool
|
||||
}{
|
||||
{
|
||||
name: "单比特频数检测 ",
|
||||
fn: statistics.Frequency,
|
||||
},
|
||||
|
||||
{
|
||||
name: "块内频数检测 ",
|
||||
fn: statistics.BlockFrequency,
|
||||
},
|
||||
{
|
||||
name: "扑克检测, m=4 ",
|
||||
fn: statistics.Poker4,
|
||||
},
|
||||
{
|
||||
name: "扑克检测, m=8 ",
|
||||
fn: statistics.Poker8,
|
||||
},
|
||||
{
|
||||
name: "重叠子序列检测, m=2",
|
||||
fn: statistics.Serial2,
|
||||
},
|
||||
{
|
||||
name: "重叠子序列检测, m=5",
|
||||
fn: statistics.Serial5,
|
||||
},
|
||||
{
|
||||
name: "游程总数检测 ",
|
||||
fn: statistics.Runs,
|
||||
},
|
||||
{
|
||||
name: "游程分布检测 ",
|
||||
fn: statistics.RunsDistribution,
|
||||
},
|
||||
{
|
||||
name: "二元推导检测, k=3 ",
|
||||
fn: statistics.BinaryDerivative3,
|
||||
},
|
||||
{
|
||||
name: "二元推导检测, k=7 ",
|
||||
fn: statistics.BinaryDerivative7,
|
||||
},
|
||||
{
|
||||
name: "自相关检测, d=1 ",
|
||||
fn: statistics.Autocorrelation1,
|
||||
},
|
||||
{
|
||||
name: "自相关检测, d=2 ",
|
||||
fn: statistics.Autocorrelation2,
|
||||
},
|
||||
{
|
||||
name: "自相关检测, d=8 ",
|
||||
fn: statistics.Autocorrelation8,
|
||||
},
|
||||
{
|
||||
name: "自相关检测, d=16 ",
|
||||
fn: statistics.Autocorrelation16,
|
||||
},
|
||||
{
|
||||
name: "矩阵秩检测 ",
|
||||
fn: statistics.Rank,
|
||||
},
|
||||
{
|
||||
name: "累加和检测 ",
|
||||
fn: statistics.CumulativeSums,
|
||||
},
|
||||
{
|
||||
name: "近似熵检测 ",
|
||||
fn: statistics.ApproximateEntropy,
|
||||
},
|
||||
{
|
||||
name: "线性复杂度检测 ",
|
||||
fn: statistics.LinearComplexity,
|
||||
},
|
||||
{
|
||||
name: "Maurer通用统计检测 ",
|
||||
fn: statistics.Universal,
|
||||
},
|
||||
{
|
||||
name: "离散傅立叶检测 ",
|
||||
fn: statistics.DiscreteFourierTransform,
|
||||
},
|
||||
}
|
||||
|
||||
type payload struct {
|
||||
e []byte
|
||||
fn func([]byte) bool
|
||||
}
|
||||
|
||||
func worker(in chan *payload, out chan bool, done chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
case p := <-in:
|
||||
out <- p.fn(p.e) // fn may panic
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
dataDir := flag.String("d", "./data", "The directory of random data, default is \"./data\"")
|
||||
flag.Parse()
|
||||
fmt.Println("=======================================================")
|
||||
fmt.Println(" 测试文件夹:", *dataDir)
|
||||
epsilons := make([][]byte, 0)
|
||||
|
||||
fs, err := ioutil.ReadDir(*dataDir)
|
||||
if err != nil {
|
||||
fmt.Println("文件夹读取错误: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range fs {
|
||||
if !file.IsDir() {
|
||||
epsilon, err := readFile(path.Join(*dataDir, file.Name()))
|
||||
if err != nil {
|
||||
fmt.Println("文件读取错误: ", err)
|
||||
return
|
||||
}
|
||||
epsilons = append(epsilons, epsilon)
|
||||
}
|
||||
}
|
||||
fmt.Printf(" 共有随机数文件%d个,每个文件%d比特\n", len(epsilons), len(epsilons[0]))
|
||||
bound := lowerBound(len(epsilons))
|
||||
fmt.Printf(" 每组检测通过的样本数必须不小于: %d\n", bound)
|
||||
fmt.Println("=======================================================")
|
||||
|
||||
threads := runtime.NumCPU()
|
||||
in := make(chan *payload, threads)
|
||||
out := make(chan bool, threads)
|
||||
done := make(chan struct{})
|
||||
|
||||
for i := 0; i < threads; i++ {
|
||||
go worker(in, out, done)
|
||||
}
|
||||
|
||||
// for {
|
||||
for _, t := range suit {
|
||||
// for _, t := range suit[len(suit)-1:] {
|
||||
sum := 0
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(epsilons))
|
||||
go func() {
|
||||
for _, e := range epsilons {
|
||||
in <- &payload{
|
||||
e: e,
|
||||
fn: t.fn,
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for i := 0; i < len(epsilons); i++ {
|
||||
b := <-out
|
||||
if b {
|
||||
sum += 1
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
if sum < bound {
|
||||
fmt.Printf("[x] %s 【失败】: %d / %d\n", t.name, sum, len(epsilons))
|
||||
} else {
|
||||
fmt.Printf("[o] %s 【通过】: %d / %d\n", t.name, sum, len(epsilons))
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
// readFile read from fileName and convert each bit to byte
|
||||
func readFile(fileName string) ([]byte, error) {
|
||||
content, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bits := make([]byte, 0, len(content)*8)
|
||||
for _, c := range content {
|
||||
bits = append(bits, (c>>7)&1)
|
||||
bits = append(bits, (c>>6)&1)
|
||||
bits = append(bits, (c>>5)&1)
|
||||
bits = append(bits, (c>>4)&1)
|
||||
bits = append(bits, (c>>3)&1)
|
||||
bits = append(bits, (c>>2)&1)
|
||||
bits = append(bits, (c>>1)&1)
|
||||
bits = append(bits, (c>>0)&1)
|
||||
}
|
||||
return bits, nil
|
||||
}
|
||||
|
||||
const alpha float64 = 0.01
|
||||
|
||||
func lowerBound(samples int) int {
|
||||
return int(math.Ceil((1 - alpha - 3*math.Sqrt((alpha*(1-alpha))/float64(samples))) * float64(samples)))
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLowerBound(t *testing.T) {
|
||||
fmt.Println(lowerBound(1024))
|
||||
}
|
||||
func TestP(t *testing.T) {
|
||||
tests := []string{
|
||||
"Frequency",
|
||||
"BlockFrequency",
|
||||
"CumulativeSums",
|
||||
"Runs",
|
||||
"LongestRunOfOnes",
|
||||
"Rank",
|
||||
"DiscreteFourierTransform",
|
||||
"Universal",
|
||||
"ApproximateEntropy",
|
||||
"LinearComplexity",
|
||||
"Serial",
|
||||
"Poker",
|
||||
"Autocorrelation",
|
||||
"BinaryDerivative",
|
||||
"RunsDistribution",
|
||||
}
|
||||
for _, t := range tests {
|
||||
fmt.Printf(`
|
||||
sum = 0
|
||||
for _, e := range epsilons {
|
||||
if statistics.%s(e) {
|
||||
sum += 1
|
||||
}
|
||||
}
|
||||
if sum < bound {
|
||||
fmt.Printf("%s Test Failed: \d/\d\n", sum, len(epsilons))
|
||||
}
|
||||
`, t, t)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
#include "RandomTest.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
// 记录有过失败的数据
|
||||
//
|
||||
int fileNo = 1;
|
||||
int testNo = 1;
|
||||
int failed[TEST_NUM+1][SAMPLE_NUM+1] = {0};
|
||||
|
||||
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
unsigned char *epsilon;
|
||||
int pass[TEST_NUM + 1];
|
||||
|
||||
if ( (epsilon = (BitSequence *) calloc(SAMPLE_LEN, sizeof(BitSequence))) == NULL ) {
|
||||
printf("BITSTREAM DEFINITION: Insufficient memory available.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
|
||||
int testVector[30] = {0};
|
||||
FILE *fp;
|
||||
char FileName[128] = {0};
|
||||
double passmin = 0.0;
|
||||
|
||||
|
||||
int loop = 1, passnum = 0;
|
||||
|
||||
bzero(pass, sizeof(pass));
|
||||
|
||||
|
||||
printf("\n\n I N P U T B A S E D I R\n");
|
||||
printf(" Make sure the test datas are ./data/Random_[x].bin\n");
|
||||
printf(" Press enter to continue.");
|
||||
getchar();
|
||||
|
||||
|
||||
|
||||
while (loop)
|
||||
{
|
||||
|
||||
ChooseItems(&testVector[0]);
|
||||
/* testVector[0] = 19;*/
|
||||
if (testVector[0] == 0)
|
||||
break;
|
||||
|
||||
// 一键测试
|
||||
if (testVector[0] == 80)
|
||||
{
|
||||
passnum = 0;
|
||||
|
||||
fprintf(stdout,">> one key test start.");
|
||||
|
||||
for (int k=1; k<=TEST_NUM ; ++k )
|
||||
{
|
||||
testNo = k;
|
||||
printf("\n");
|
||||
pass[k] = 0;
|
||||
// for (int i=1; i<=SAMPLE_NUM; i++)
|
||||
for (int i = 0; i < SAMPLE_NUM;)
|
||||
{
|
||||
fileNo = i;
|
||||
|
||||
sprintf(FileName, "./data/Random_%d.txt", i+1);
|
||||
|
||||
|
||||
if((fp = fopen(FileName,"rb")),!fp)
|
||||
{
|
||||
printf("\n打开文件失败\n");
|
||||
ret = -1;
|
||||
goto CLR;
|
||||
}
|
||||
|
||||
// read file and test
|
||||
readHexDigitsInBinaryFormat(fp,k, epsilon, pass);
|
||||
|
||||
// close file
|
||||
if (EOF == fclose(fp))
|
||||
{
|
||||
printf("\n关闭文件失败\n");
|
||||
ret = -1;
|
||||
goto CLR;
|
||||
}
|
||||
i++;
|
||||
if (0 == i%200)
|
||||
{
|
||||
printf("\n option %d: %d / %d pass.\n",k,pass[k],i);
|
||||
}
|
||||
if ( SAMPLE_NUM == i )
|
||||
{
|
||||
passmin = SAMPLE_NUM * (1 - ALPHA - 3 * sqrt( ALPHA*(1-ALPHA)/SAMPLE_NUM));
|
||||
if (pass[k] >= passmin)
|
||||
{
|
||||
passnum++;
|
||||
fprintf(stdout,"\n[O] option %d pass the test, result is %d / %d .", k, pass[k], SAMPLE_NUM);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout,"\n[X] option %d fail the test, result is %d / %d .", k, pass[k], SAMPLE_NUM);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (passnum == sizeof(pass)/sizeof(pass[0]))
|
||||
{
|
||||
fprintf(stdout,"\n\n>> one key test end, all options passed.");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout,"\n\n>> one key test end, some one failed.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\n");
|
||||
pass[testVector[0]] = 0;
|
||||
testNo = testVector[0];
|
||||
|
||||
for (int i=0; i<SAMPLE_NUM;)
|
||||
{
|
||||
fileNo = i;
|
||||
|
||||
sprintf(FileName, "./data/random%03d.bin", i);
|
||||
|
||||
// open file
|
||||
if((fp = fopen(FileName,"rb")),!fp)
|
||||
{
|
||||
printf("\n打开文件失败\n");
|
||||
ret = -1;
|
||||
goto CLR;
|
||||
}
|
||||
|
||||
// read file and test
|
||||
readHexDigitsInBinaryFormat(fp,testVector[0], epsilon, pass);
|
||||
|
||||
// close file
|
||||
if (EOF == fclose(fp))
|
||||
{
|
||||
printf("\n关闭文件失败\n");
|
||||
ret = -1;
|
||||
goto CLR;
|
||||
}
|
||||
i++;
|
||||
if (0 == i%200)
|
||||
{
|
||||
printf("\n option %d: %d / %d pass.\n",testVector[0],pass[testVector[0]],i);
|
||||
}
|
||||
if ( SAMPLE_NUM == i )
|
||||
{
|
||||
passmin = SAMPLE_NUM * (1 - ALPHA - 3 * sqrt( ALPHA*(1-ALPHA)/SAMPLE_NUM));
|
||||
if (pass[testVector[0]] >= passmin)
|
||||
{
|
||||
fprintf(stdout,"\n[O] option %d pass the test, result is %d / %d .", testVector[0], pass[testVector[0]], SAMPLE_NUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout,"\n[X] option %d fail the test, result is %d / %d .", testVector[0], pass[testVector[0]], SAMPLE_NUM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf("\n\n F A I L E D T E S T D E T A I L S\n");
|
||||
int filePassResult[SAMPLE_NUM + 1] = {0};
|
||||
for (int j = 1; j < SAMPLE_NUM+1; j++){
|
||||
for (int i = 1; i <= TEST_NUM; i++){
|
||||
if (failed[i][j]){
|
||||
printf(" random%d.bin failed test %d\n", j, i);
|
||||
filePassResult[j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n\n F A I L E D T E S T S U M A R R Y\n");
|
||||
printf(" The following files are failed in some test:\n");
|
||||
for (int j = 1; j < SAMPLE_NUM+1; j++){
|
||||
if (filePassResult[j]){
|
||||
printf(" random%i.bin\n", j);
|
||||
}
|
||||
}
|
||||
if (testVector[0] == 80){
|
||||
break;
|
||||
}else{
|
||||
printf("\n\nPress any key to go on!\n");
|
||||
getchar();
|
||||
}
|
||||
|
||||
}
|
||||
CLR:
|
||||
|
||||
free(epsilon);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ChooseItems(int *pChoice)
|
||||
{
|
||||
printf("\n\n R A N D O M N E S S T E S T S\n");
|
||||
printf(" _________________________________\n\n");
|
||||
printf(" [01] monobit frequency test (单比特频数检测)\n");
|
||||
printf(" [02] frequency test with a block (块内频数检测)\n");
|
||||
printf(" [03] poker test (扑克检测, m=4)\n");
|
||||
|
||||
printf(" [04] serial test (重叠子序列检测, m=2)\n");
|
||||
|
||||
printf(" [05] runs test (游程总数检测)\n");
|
||||
printf(" [06] runs distribution test (游程分布检测)\n");
|
||||
printf(" [07] test for the longest run of ones in a block\n");
|
||||
printf(" (块内最大“1”游程检测)\n");
|
||||
printf(" [08] binary derivative test (二元推导检测, k=3)\n");
|
||||
|
||||
printf(" [09] autocorrelation test (自相关检测, d=1)\n");
|
||||
|
||||
printf(" [10] binary matrix rank test (矩阵秩检测)\n");
|
||||
printf(" [11] cumulative test (累加和检测)\n");
|
||||
printf(" [12] approximate entropy test (近似熵检测)\n");
|
||||
printf(" [13] linear complexity test (线性复杂度检测)\n");
|
||||
printf(" [14] Maurer's \"Universal Test\" (Maurer通用统计检测)\n");
|
||||
printf(" [15] discrete fourier transform test (离散傅立叶检测)\n\n");
|
||||
|
||||
printf(" [16] poker test (扑克检测, m=8)\n");
|
||||
printf(" [17] serial test (重叠子序列检测, m=5)\n");
|
||||
printf(" [18] binary derivative test (二元推导检测, k=7)\n");
|
||||
printf(" [19] autocorrelation test (自相关检测, d=2)\n");
|
||||
printf(" [20] autocorrelation test (自相关检测, d=8)\n");
|
||||
printf(" [21] autocorrelation test (自相关检测, d=16)\n\n");
|
||||
|
||||
printf(" [80] One Key Test All\n");
|
||||
printf(" [00] Quit\n\n");
|
||||
printf("> Enter Choice: ");
|
||||
scanf("%d", pChoice);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void Test_Suite(unsigned char *epsilon, int n, int Choice, int *pass)
|
||||
{
|
||||
if (TEST_FREQUENCY == Choice)
|
||||
pass[TEST_FREQUENCY] += Frequency(epsilon, n);
|
||||
|
||||
if (TEST_BLOCK_FREQUENCY == Choice)
|
||||
pass[TEST_BLOCK_FREQUENCY] += BlockFrequency(epsilon, n);
|
||||
|
||||
if ( TEST_CUSUM == Choice )
|
||||
pass[TEST_CUSUM] += CumulativeSums(epsilon, n);
|
||||
|
||||
if ( TEST_RUNS == Choice )
|
||||
pass[TEST_RUNS] += Runs(epsilon, n);
|
||||
|
||||
if ( TEST_LONGEST_RUN == Choice)
|
||||
pass[TEST_LONGEST_RUN] += LongestRunOfOnes(epsilon, n);
|
||||
|
||||
if ( TEST_RANK == Choice)
|
||||
pass[TEST_RANK] += Rank(epsilon, n);
|
||||
|
||||
if ( TEST_FFT == Choice)
|
||||
pass[TEST_FFT] += DiscreteFourierTransform(epsilon, n);
|
||||
|
||||
if ( TEST_UNIVERSAL == Choice)
|
||||
pass[TEST_UNIVERSAL] += Universal(epsilon, n);
|
||||
|
||||
if ( TEST_APEN == Choice)
|
||||
pass[TEST_APEN] += ApproximateEntropy(epsilon, n);
|
||||
|
||||
if ( TEST_SERIAL2 == Choice)
|
||||
pass[TEST_SERIAL2] += Serial(epsilon, n, 2);
|
||||
|
||||
if ( TEST_LINEARCOMPLEXITY == Choice)
|
||||
pass[TEST_LINEARCOMPLEXITY] += LinearComplexity(epsilon, n);
|
||||
|
||||
if (TEST_POKER4 == Choice)
|
||||
pass[TEST_POKER4] += Poker(epsilon, n, 4);
|
||||
|
||||
if (TEST_AUTOCORRELATION1 == Choice)
|
||||
pass[TEST_AUTOCORRELATION1] += Autocorrelation(epsilon, n, 1);
|
||||
|
||||
if (TEST_BINARYDERIVATION3 == Choice)
|
||||
pass[TEST_BINARYDERIVATION3] += BinaryDerivative(epsilon, n, 3);
|
||||
|
||||
if (TEST_RUNSDISTRIBUTION == Choice)
|
||||
pass[TEST_RUNSDISTRIBUTION] += RunsDistribution(epsilon, n);
|
||||
|
||||
if (TEST_POKER8 == Choice)
|
||||
pass[TEST_POKER8] += Poker(epsilon, n, 8);
|
||||
|
||||
if (TEST_SERIAL5 == Choice)
|
||||
pass[TEST_SERIAL5] += Serial(epsilon, n, 5);
|
||||
|
||||
if (TEST_BINARYDERIVATION7 == Choice)
|
||||
pass[TEST_BINARYDERIVATION7] += BinaryDerivative(epsilon, n, 7);
|
||||
|
||||
if (TEST_AUTOCORRELATION2 == Choice)
|
||||
pass[TEST_AUTOCORRELATION2] += Autocorrelation(epsilon, n, 2);
|
||||
|
||||
if (TEST_AUTOCORRELATION8 == Choice)
|
||||
pass[TEST_AUTOCORRELATION8] += Autocorrelation(epsilon, n, 8);
|
||||
|
||||
if (TEST_AUTOCORRELATION16 == Choice)
|
||||
pass[TEST_AUTOCORRELATION16] += Autocorrelation(epsilon, n, 16);
|
||||
}
|
||||
|
||||
void readHexDigitsInBinaryFormat(FILE *fp,int choose, unsigned char *epsilon, int *pass)
|
||||
{
|
||||
int i, done, num_0s, num_1s, bitsRead;
|
||||
BYTE buffer[4];
|
||||
|
||||
|
||||
|
||||
// printf(" Statistical Testing In Progress.........\n\n");
|
||||
for ( i=0; i<1; i++ ) {
|
||||
num_0s = 0;
|
||||
num_1s = 0;
|
||||
bitsRead = 0;
|
||||
done = 0;
|
||||
do {
|
||||
if ( fread(buffer, sizeof(unsigned char), 4, fp) != 4 ) {
|
||||
printf("READ ERROR: Insufficient data in file.\n");
|
||||
free(epsilon);
|
||||
return;
|
||||
}
|
||||
done = convertToBits(epsilon,buffer, 32,SAMPLE_LEN, &num_0s, &num_1s, &bitsRead);
|
||||
} while ( !done );
|
||||
// fprintf(freqfp, "\t\tBITSREAD = %d 0s = %d 1s = %d\n", bitsRead, num_0s, num_1s);
|
||||
|
||||
Test_Suite(epsilon, SAMPLE_LEN, choose, pass);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int convertToBits(unsigned char *epsilon, BYTE *x, int xBitLength, int bitsNeeded, int *num_0s, int *num_1s, int *bitsRead)
|
||||
{
|
||||
int i, j, count, bit;
|
||||
BYTE mask;
|
||||
int zeros, ones;
|
||||
|
||||
count = 0;
|
||||
zeros = ones = 0;
|
||||
for ( i=0; i<(xBitLength+7)/8; i++ ) {
|
||||
mask = 0x80;
|
||||
for ( j=0; j<8; j++ ) {
|
||||
if ( *(x+i) & mask ) {
|
||||
bit = 1;
|
||||
(*num_1s)++;
|
||||
ones++;
|
||||
}
|
||||
else {
|
||||
bit = 0;
|
||||
(*num_0s)++;
|
||||
zeros++;
|
||||
}
|
||||
mask >>= 1;
|
||||
epsilon[*bitsRead] = bit;
|
||||
(*bitsRead)++;
|
||||
if ( *bitsRead == bitsNeeded )
|
||||
return 1;
|
||||
if ( ++count == xBitLength )
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"xdx.jelly/xgcl/rsa"
|
||||
)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
func sign(sk *rsa.PrivateKey, digestData []byte, work, done chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
case <-work:
|
||||
_, _ = rsa.PKCS1v15{}.Sign(sk, crypto.SHA256, digestData)
|
||||
case <-done:
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
msg := []byte("message")
|
||||
digestData := sha256.Sum256(msg)
|
||||
|
||||
sk, _, _ := rsa.PKCS1v15{}.GenerateKeyPairRSA(2048)
|
||||
threads := runtime.NumCPU()
|
||||
|
||||
loops := 1000
|
||||
work := make(chan struct{})
|
||||
done := make(chan struct{})
|
||||
|
||||
if len(os.Args) >= 2 {
|
||||
threads, _ = strconv.Atoi(os.Args[1])
|
||||
}
|
||||
|
||||
if len(os.Args) >= 3 {
|
||||
loops, _ = strconv.Atoi(os.Args[2])
|
||||
}
|
||||
|
||||
for i := 0; i < threads; i++ {
|
||||
wg.Add(1)
|
||||
go sign(sk, digestData[:], work, done)
|
||||
}
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
// warm up
|
||||
work <- struct{}{}
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
for i := 0; i < threads*loops; i++ {
|
||||
work <- struct{}{}
|
||||
}
|
||||
close(done)
|
||||
wg.Wait()
|
||||
elapsed := time.Since(start)
|
||||
cnt := threads * loops
|
||||
fmt.Printf("Sign %d times on %d cores\n", threads*loops, threads)
|
||||
fmt.Printf("Used time: %d ms, %d pcs/s\n", elapsed.Milliseconds(), int(float64(cnt)/float64(elapsed.Milliseconds())*1000))
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package main_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPow(t *testing.T) {
|
||||
|
||||
n, _ := big.NewInt(1).SetString("151787717184422252307365020658866150659139813606887864663574443176328014948429913407344055128026662986925949147541666619511526142491196760869802510776788353419093645990851372578901256051814507665042918937343846064086867942964225457691185973174205523727877484153730596121423900155549117133518141928295347285789", 10)
|
||||
m, _ := big.NewInt(1).SetString("15178771718442225230736502065886615065913981360688786466357444317632801494842991340734405512802666298692594914754166661951152614249119676086980251077678835341909364599085137257890125605181450766504291893734384606408686794296422545769118597317420552372787748415373059612142390015554911713351814192829534728578", 10)
|
||||
d, _ := big.NewInt(1).SetString("141787717184422252307365020658866150659139813606887864663574443176328014948429913407344055128026662986925949147541666619511526142491196760869802510776788353419093645990851372578901256051814507665042918937343846064086867942964225457691185973174205523727877484153730596121423900155549117133518141928295347285789", 10)
|
||||
c := big.NewInt(1)
|
||||
|
||||
cnt := 10000
|
||||
start := time.Now()
|
||||
for i := 0; i < cnt; i++ {
|
||||
c.Exp(m, d, n)
|
||||
}
|
||||
elapsed := time.Since(start)
|
||||
fmt.Printf("Sign %d times\n", cnt)
|
||||
fmt.Printf("Used time: %d ms, %d pcs/s\n", elapsed.Milliseconds(), int(float64(cnt)/float64(elapsed.Seconds())))
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user