Schnorr signature implemented. ECC point multiplication with big int. Refactor of the code.

This commit is contained in:
arnaucube
2018-09-24 19:20:39 +02:00
parent 0266c94332
commit 4acca94c9e
19 changed files with 504 additions and 198 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
fmt fmt
schnorr.goBACKUP

View File

@@ -1,4 +1,4 @@
# cryptofun [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucode/cryptofun)](https://goreportcard.com/report/github.com/arnaucode/cryptofun) # cryptofun [![Go Report Card](https://goreportcard.com/badge/github.com/arnaucube/cryptofun)](https://goreportcard.com/report/github.com/arnaucube/cryptofun)
Crypto algorithms from scratch. Academic purposes only. Crypto algorithms from scratch. Academic purposes only.
@@ -51,6 +51,12 @@ https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
- [x] ECDSA Verify signature - [x] ECDSA Verify signature
## Schnorr signature
https://en.wikipedia.org/wiki/Schnorr_signature
- [x] Hash[M || R] (where M is the msg bytes and R is a Point on the ECC, using sha256 hash function)
- [x] Generate Schnorr scheme
- [x] Sign
- [x] Verify signature
--- ---

View File

@@ -4,6 +4,8 @@ import (
"crypto/rand" "crypto/rand"
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
const ( const (
@@ -12,26 +14,19 @@ const (
func TestDiffieHellman(t *testing.T) { func TestDiffieHellman(t *testing.T) {
p, err := rand.Prime(rand.Reader, bits/2) p, err := rand.Prime(rand.Reader, bits/2)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
g, err := rand.Prime(rand.Reader, bits/2) g, err := rand.Prime(rand.Reader, bits/2)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
max, err := rand.Prime(rand.Reader, bits/2) max, err := rand.Prime(rand.Reader, bits/2)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
a, err := rand.Int(rand.Reader, max) a, err := rand.Int(rand.Reader, max)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
b, err := rand.Int(rand.Reader, max) b, err := rand.Int(rand.Reader, max)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
A := new(big.Int).Exp(g, a, p) A := new(big.Int).Exp(g, a, p)
B := new(big.Int).Exp(g, b, p) B := new(big.Int).Exp(g, b, p)

View File

@@ -49,20 +49,6 @@ func (ec *EC) Neg(p Point) Point {
return Point{p.X, new(big.Int).Sub(ec.Q, p.Y)} return Point{p.X, new(big.Int).Sub(ec.Q, p.Y)}
} }
// Order returns smallest n where nG = O (point at zero)
func (ec *EC) Order(g Point) (int, error) {
for i := 1; i < int(ec.Q.Int64())+1; i++ {
mPoint, err := ec.Mul(g, i)
if err != nil {
return i, err
}
if mPoint.Equal(zeroPoint) {
return i, nil
}
}
return -1, errors.New("invalid order")
}
// Add adds two points p1 and p2 and gets q, returns the negate of q // Add adds two points p1 and p2 and gets q, returns the negate of q
func (ec *EC) Add(p1, p2 Point) (Point, error) { func (ec *EC) Add(p1, p2 Point) (Point, error) {
if p1.Equal(zeroPoint) { if p1.Equal(zeroPoint) {
@@ -126,23 +112,41 @@ func (ec *EC) Add(p1, p2 Point) (Point, error) {
} }
// Mul multiplies a point n times on the elliptic curve // Mul multiplies a point n times on the elliptic curve
func (ec *EC) Mul(p Point, n int) (Point, error) { func (ec *EC) Mul(p Point, n *big.Int) (Point, error) {
var err error var err error
p2 := p p2 := p
r := zeroPoint r := zeroPoint
for 0 < n { for bigZero.Cmp(n) == -1 { // 0<n
if n&1 == 1 { z := new(big.Int).And(n, bigOne) // n&1
if bytes.Equal(z.Bytes(), bigOne.Bytes()) { // n&1==1
r, err = ec.Add(r, p2) r, err = ec.Add(r, p2)
if err != nil { if err != nil {
return p, err return p, err
} }
} }
n = n >> 1 n = n.Rsh(n, 1) // n = n>>1
p2, err = ec.Add(p2, p2) p2, err = ec.Add(p2, p2)
if err != nil { if err != nil {
return p, err return p, err
} }
} }
return r, nil return r, nil
} }
// Order returns smallest n where nG = O (point at zero)
func (ec *EC) Order(g Point) (*big.Int, error) {
// loop from i:=1 to i<ec.Q+1
start := big.NewInt(1)
end := new(big.Int).Add(ec.Q, bigOne)
for i := new(big.Int).Set(start); i.Cmp(end) <= 0; i.Add(i, bigOne) {
iCopy := new(big.Int).SetBytes(i.Bytes())
mPoint, err := ec.Mul(g, iCopy)
if err != nil {
return i, err
}
if mPoint.Equal(zeroPoint) {
return i, nil
}
}
return bigZero, errors.New("invalid order")
}

View File

@@ -1,17 +1,17 @@
package ecc package ecc
import ( import (
"fmt"
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestECC(t *testing.T) { func TestECC(t *testing.T) {
ec := NewEC(0, 7, 11) ec := NewEC(0, 7, 11)
p1, p1i, err := ec.At(big.NewInt(int64(7))) p1, p1i, err := ec.At(big.NewInt(int64(7)))
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !p1.Equal(Point{big.NewInt(int64(7)), big.NewInt(int64(3))}) { if !p1.Equal(Point{big.NewInt(int64(7)), big.NewInt(int64(3))}) {
t.Errorf("p1!=(7, 11)") t.Errorf("p1!=(7, 11)")
} }
@@ -22,32 +22,30 @@ func TestECC(t *testing.T) {
func TestNeg(t *testing.T) { func TestNeg(t *testing.T) {
ec := NewEC(0, 7, 11) ec := NewEC(0, 7, 11)
p1, p1i, err := ec.At(big.NewInt(int64(7))) p1, p1i, err := ec.At(big.NewInt(int64(7)))
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
p1Neg := ec.Neg(p1) p1Neg := ec.Neg(p1)
if !p1Neg.Equal(p1i) { if !p1Neg.Equal(p1i) {
t.Errorf("p1Neg!=p1i") t.Errorf("p1Neg!=p1i")
} }
} }
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
ec := NewEC(0, 7, 11) ec := NewEC(0, 7, 11)
p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(7))} p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(7))}
p2 := Point{big.NewInt(int64(2)), big.NewInt(int64(2))} p2 := Point{big.NewInt(int64(2)), big.NewInt(int64(2))}
q, err := ec.Add(p1, p2) q, err := ec.Add(p1, p2)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !q.Equal(Point{big.NewInt(int64(3)), big.NewInt(int64(1))}) { if !q.Equal(Point{big.NewInt(int64(3)), big.NewInt(int64(1))}) {
t.Errorf("q!=(3, 1)") t.Errorf("q!=(3, 1)")
} }
// check that q exists on the elliptic curve // check that q exists on the elliptic curve
pt, pti, err := ec.At(q.X) pt, pti, err := ec.At(q.X)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !q.Equal(pt) && !q.Equal(pti) { if !q.Equal(pt) && !q.Equal(pti) {
t.Errorf("q not exist on the elliptic curve") t.Errorf("q not exist on the elliptic curve")
} }
@@ -60,69 +58,155 @@ func TestAddSamePoint(t *testing.T) {
p1i := Point{big.NewInt(int64(4)), big.NewInt(int64(4))} p1i := Point{big.NewInt(int64(4)), big.NewInt(int64(4))}
q, err := ec.Add(p1, p1) q, err := ec.Add(p1, p1)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !q.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(5))}) { if !q.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(5))}) {
t.Errorf("q!=(6, 5)") t.Errorf(q.String() + " == q != (6, 5)")
} }
q_, err := ec.Add(p1i, p1i) q_, err := ec.Add(p1i, p1i)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !q_.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(6))}) { if !q_.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(6))}) {
t.Errorf("q_!=(6, 6)") t.Errorf(q_.String() + " == q_ != (6, 6)")
} }
} }
func TestMulPoint1(t *testing.T) {
ec := NewEC(0, 7, 29)
p := Point{big.NewInt(int64(11)), big.NewInt(int64(27))}
q, err := ec.Mul(p, big.NewInt(int64(1)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(11)), big.NewInt(int64(27))}) {
t.Errorf(q.String() + " == q != (11, 27)")
}
q, err = ec.Mul(p, big.NewInt(int64(2)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(12)), big.NewInt(int64(13))}) {
t.Errorf(q.String() + " == q != (12, 13)")
}
q, err = ec.Mul(p, big.NewInt(int64(3)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(28)), big.NewInt(int64(8))}) {
t.Errorf(q.String() + " == q != (28, 8)")
}
q, err = ec.Mul(p, big.NewInt(int64(4)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(22))}) {
t.Errorf(q.String() + " == q != (6, 22)")
}
}
func TestMulPoint2(t *testing.T) {
ec := NewEC(0, 7, 29)
p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(19))}
q3, err := ec.Mul(p1, big.NewInt(int64(3)))
assert.Nil(t, err)
if !q3.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(7))}) {
t.Errorf(q3.String() + " == q3 != (6, 7)")
}
q7, err := ec.Mul(p1, big.NewInt(int64(7)))
assert.Nil(t, err)
if !q7.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(14))}) {
t.Errorf(q7.String() + " == q7 != (19, 14)")
}
q8, err := ec.Mul(p1, big.NewInt(int64(8)))
assert.Nil(t, err)
if !q8.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(15))}) {
t.Errorf(q8.String() + " == q8 != (12, 16)")
}
}
func TestMulPoint3(t *testing.T) {
// in this test we will multiply by a high number
ec := NewEC(0, 7, 11)
p := Point{big.NewInt(int64(7)), big.NewInt(int64(3))}
q, err := ec.Mul(p, big.NewInt(int64(100)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(3)), big.NewInt(int64(1))}) {
t.Errorf(q.String() + " == q != (3, 1)")
}
q, err = ec.Mul(p, big.NewInt(int64(100)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(3)), big.NewInt(int64(1))}) {
t.Errorf(q.String() + " == q != (3, 1)")
}
}
func TestMulEqualSelfAdd(t *testing.T) { func TestMulEqualSelfAdd(t *testing.T) {
ec := NewEC(0, 7, 29) ec := NewEC(0, 7, 29)
p1 := Point{big.NewInt(int64(11)), big.NewInt(int64(27))} p1 := Point{big.NewInt(int64(11)), big.NewInt(int64(27))}
p1p1, err := ec.Add(p1, p1) p1_2, err := ec.Add(p1, p1)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
p1_3, err := ec.Add(p1_2, p1)
assert.Nil(t, err)
// q * 3
q, err := ec.Mul(p1, big.NewInt(int64(3)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(28)), big.NewInt(int64(8))}) {
t.Errorf(q.String() + " == q != (28, 8)")
} }
p1p1, err = ec.Add(p1p1, p1) if !q.Equal(p1_3) {
if err != nil { t.Errorf("p*3 == " + q.String() + ", p+p+p == " + p1_3.String())
t.Errorf(err.Error())
} }
q, err := ec.Mul(p1, 3)
if err != nil { // q * 4
t.Errorf(err.Error()) p1_4, err := ec.Add(p1_3, p1)
assert.Nil(t, err)
q, err = ec.Mul(p1, big.NewInt(int64(4)))
assert.Nil(t, err)
if !q.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(22))}) {
t.Errorf(q.String() + " == q != (6, 22)")
} }
if !q.Equal(p1p1) { if !q.Equal(p1_4) {
fmt.Println(q) t.Errorf("p*4 == " + q.String() + ", p+p+p+p == " + p1_4.String())
fmt.Println(p1p1)
t.Errorf("q!=p1*p1")
} }
} }
func TestMul(t *testing.T) { func TestOrder(t *testing.T) {
ec := NewEC(0, 7, 29) ec := NewEC(0, 7, 11)
p1 := Point{big.NewInt(int64(4)), big.NewInt(int64(19))} g := Point{big.NewInt(int64(7)), big.NewInt(int64(8))}
q3, err := ec.Mul(p1, 3) order, err := ec.Order(g)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error()) assert.Equal(t, order.Int64(), int64(12))
}
if !q3.Equal(Point{big.NewInt(int64(6)), big.NewInt(int64(7))}) {
t.Errorf("q3!=(6, 7)")
}
q7, err := ec.Mul(p1, 7)
if err != nil {
t.Errorf(err.Error())
}
if !q7.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(14))}) {
t.Errorf("q7!=(19, 14)")
}
q8, err := ec.Mul(p1, 8) // another test
if err != nil { g = Point{big.NewInt(int64(2)), big.NewInt(int64(9))}
t.Errorf(err.Error()) order, err = ec.Order(g)
} assert.Nil(t, err)
if !q8.Equal(Point{big.NewInt(int64(19)), big.NewInt(int64(15))}) { assert.Equal(t, order.Int64(), int64(4))
t.Errorf("q8!=(19, 15)")
} // another test with another curve
ec = NewEC(0, 7, 29)
g = Point{big.NewInt(int64(6)), big.NewInt(int64(22))}
order, err = ec.Order(g)
assert.Nil(t, err)
assert.Equal(t, order.Int64(), int64(5))
// another test
g = Point{big.NewInt(int64(23)), big.NewInt(int64(9))}
order, err = ec.Order(g)
assert.Nil(t, err)
assert.Equal(t, order.Int64(), int64(30))
} }

View File

@@ -7,6 +7,7 @@ import (
var ( var (
bigZero = big.NewInt(int64(0)) bigZero = big.NewInt(int64(0))
bigOne = big.NewInt(int64(1))
zeroPoint = Point{bigZero, bigZero} zeroPoint = Point{bigZero, bigZero}
) )
@@ -26,3 +27,8 @@ func (c1 *Point) Equal(c2 Point) bool {
} }
return true return true
} }
// String returns the components of the point in a string
func (p *Point) String() string {
return "(" + p.X.String() + ", " + p.Y.String() + ")"
}

View File

@@ -4,14 +4,15 @@ import (
"bytes" "bytes"
"math/big" "math/big"
ecc "../ecc" // ecc "../ecc"
"github.com/arnaucube/cryptofun/ecc"
) )
// DSA is the ECDSA data structure // DSA is the ECDSA data structure
type DSA struct { type DSA struct {
EC ecc.EC EC ecc.EC
G ecc.Point G ecc.Point
N int N *big.Int
} }
// NewDSA defines a new DSA data structure // NewDSA defines a new DSA data structure
@@ -25,40 +26,48 @@ func NewDSA(ec ecc.EC, g ecc.Point) (DSA, error) {
} }
// PubK returns the public key Point calculated from the private key over the elliptic curve // PubK returns the public key Point calculated from the private key over the elliptic curve
func (dsa DSA) PubK(privK int) (ecc.Point, error) { func (dsa DSA) PubK(privK *big.Int) (ecc.Point, error) {
// privK: rand < ec.Q // privK: rand < ec.Q
pubK, err := dsa.EC.Mul(dsa.G, privK) privKCopy := new(big.Int).SetBytes(privK.Bytes())
pubK, err := dsa.EC.Mul(dsa.G, privKCopy)
return pubK, err return pubK, err
} }
func (dsa DSA) Sign(hashval *big.Int, privK int, r *big.Int) ([2]*big.Int, error) {
m, err := dsa.EC.Mul(dsa.G, int(r.Int64())) // Sign performs the ECDSA signature
func (dsa DSA) Sign(hashval *big.Int, privK *big.Int, r *big.Int) ([2]*big.Int, error) {
rCopy := new(big.Int).SetBytes(r.Bytes())
m, err := dsa.EC.Mul(dsa.G, rCopy)
if err != nil { if err != nil {
return [2]*big.Int{}, err return [2]*big.Int{}, err
} }
// inv(r) mod dsa.N // inv(r) mod dsa.N
inv := new(big.Int).ModInverse(r, big.NewInt(int64(dsa.N))) inv := new(big.Int).ModInverse(r, dsa.N)
// m.X * privK // m.X * privK
xPrivK := new(big.Int).Mul(m.X, big.NewInt(int64(privK))) privKCopy := new(big.Int).SetBytes(privK.Bytes())
xPrivK := new(big.Int).Mul(m.X, privKCopy)
// (hashval + m.X * privK) // (hashval + m.X * privK)
hashvalXPrivK := new(big.Int).Add(hashval, xPrivK) hashvalXPrivK := new(big.Int).Add(hashval, xPrivK)
// inv * (hashval + m.X * privK) mod dsa.N // inv * (hashval + m.X * privK) mod dsa.N
a := new(big.Int).Mul(inv, hashvalXPrivK) a := new(big.Int).Mul(inv, hashvalXPrivK)
r2 := new(big.Int).Mod(a, big.NewInt(int64(dsa.N))) r2 := new(big.Int).Mod(a, dsa.N)
return [2]*big.Int{m.X, r2}, err return [2]*big.Int{m.X, r2}, err
} }
// Verify validates the ECDSA signature
func (dsa DSA) Verify(hashval *big.Int, sig [2]*big.Int, pubK ecc.Point) (bool, error) { func (dsa DSA) Verify(hashval *big.Int, sig [2]*big.Int, pubK ecc.Point) (bool, error) {
w := new(big.Int).ModInverse(sig[1], big.NewInt(int64(dsa.N))) w := new(big.Int).ModInverse(sig[1], dsa.N)
u1raw := new(big.Int).Mul(hashval, w) wCopy := new(big.Int).SetBytes(w.Bytes())
u1 := new(big.Int).Mod(u1raw, big.NewInt(int64(dsa.N))) u1raw := new(big.Int).Mul(hashval, wCopy)
u2raw := new(big.Int).Mul(sig[0], w) u1 := new(big.Int).Mod(u1raw, dsa.N)
u2 := new(big.Int).Mod(u2raw, big.NewInt(int64(dsa.N))) wCopy = new(big.Int).SetBytes(w.Bytes())
u2raw := new(big.Int).Mul(sig[0], wCopy)
u2 := new(big.Int).Mod(u2raw, dsa.N)
gU1, err := dsa.EC.Mul(dsa.G, int(u1.Int64())) gU1, err := dsa.EC.Mul(dsa.G, u1)
if err != nil { if err != nil {
return false, err return false, err
} }
pubKU2, err := dsa.EC.Mul(pubK, int(u2.Int64())) pubKU2, err := dsa.EC.Mul(pubK, u2)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -66,6 +75,6 @@ func (dsa DSA) Verify(hashval *big.Int, sig [2]*big.Int, pubK ecc.Point) (bool,
if err != nil { if err != nil {
return false, err return false, err
} }
pXmodN := new(big.Int).Mod(p.X, big.NewInt(int64(dsa.N))) pXmodN := new(big.Int).Mod(p.X, dsa.N)
return bytes.Equal(pXmodN.Bytes(), sig[0].Bytes()), nil return bytes.Equal(pXmodN.Bytes(), sig[0].Bytes()), nil
} }

View File

@@ -4,21 +4,20 @@ import (
"math/big" "math/big"
"testing" "testing"
ecc "../ecc" "github.com/arnaucube/cryptofun/ecc"
"github.com/stretchr/testify/assert"
) )
func TestNewECDSA(t *testing.T) { func TestNewECDSA(t *testing.T) {
ec := ecc.NewEC(1, 18, 19) ec := ecc.NewEC(1, 18, 19)
g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))}
dsa, err := NewDSA(ec, g) dsa, err := NewDSA(ec, g)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
} privK := big.NewInt(int64(5))
privK := 5
pubK, err := dsa.PubK(privK) pubK, err := dsa.PubK(privK)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !pubK.Equal(ecc.Point{big.NewInt(int64(13)), big.NewInt(int64(9))}) { if !pubK.Equal(ecc.Point{big.NewInt(int64(13)), big.NewInt(int64(9))}) {
t.Errorf("pubK!=(13, 9)") t.Errorf("pubK!=(13, 9)")
} }
@@ -28,24 +27,18 @@ func TestECDSASignAndVerify(t *testing.T) {
ec := ecc.NewEC(1, 18, 19) ec := ecc.NewEC(1, 18, 19)
g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))}
dsa, err := NewDSA(ec, g) dsa, err := NewDSA(ec, g)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
} privK := big.NewInt(int64(5))
privK := 5
pubK, err := dsa.PubK(privK) pubK, err := dsa.PubK(privK)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
hashval := big.NewInt(int64(40)) hashval := big.NewInt(int64(40))
r := big.NewInt(int64(11)) r := big.NewInt(int64(11))
sig, err := dsa.Sign(hashval, privK, r) sig, err := dsa.Sign(hashval, privK, r)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
verified, err := dsa.Verify(hashval, sig, pubK) verified, err := dsa.Verify(hashval, sig, pubK)
if !verified { assert.True(t, verified)
t.Errorf("verified == false")
}
} }

View File

@@ -1,14 +1,16 @@
package elgamal package elgamal
import ( import (
ecc "../ecc" "math/big"
"github.com/arnaucube/cryptofun/ecc"
) )
// EG is the ElGamal data structure // EG is the ElGamal data structure
type EG struct { type EG struct {
EC ecc.EC EC ecc.EC
G ecc.Point G ecc.Point
N int N *big.Int
} }
// NewEG defines a new EG data structure // NewEG defines a new EG data structure
@@ -22,19 +24,22 @@ func NewEG(ec ecc.EC, g ecc.Point) (EG, error) {
} }
// PubK returns the public key Point calculated from the private key over the elliptic curve // PubK returns the public key Point calculated from the private key over the elliptic curve
func (eg EG) PubK(privK int) (ecc.Point, error) { func (eg EG) PubK(privK *big.Int) (ecc.Point, error) {
// privK: rand < ec.Q // privK: rand < ec.Q
pubK, err := eg.EC.Mul(eg.G, privK) privKCopy := new(big.Int).SetBytes(privK.Bytes())
pubK, err := eg.EC.Mul(eg.G, privKCopy)
return pubK, err return pubK, err
} }
// Encrypt encrypts a point m with the public key point, returns two points // Encrypt encrypts a point m with the public key point, returns two points
func (eg EG) Encrypt(m ecc.Point, pubK ecc.Point, r int) ([2]ecc.Point, error) { func (eg EG) Encrypt(m ecc.Point, pubK ecc.Point, r *big.Int) ([2]ecc.Point, error) {
p1, err := eg.EC.Mul(eg.G, r) rCopy := new(big.Int).SetBytes(r.Bytes())
p1, err := eg.EC.Mul(eg.G, rCopy)
if err != nil { if err != nil {
return [2]ecc.Point{}, err return [2]ecc.Point{}, err
} }
p2, err := eg.EC.Mul(pubK, r) rCopy = new(big.Int).SetBytes(r.Bytes())
p2, err := eg.EC.Mul(pubK, rCopy)
if err != nil { if err != nil {
return [2]ecc.Point{}, err return [2]ecc.Point{}, err
} }
@@ -47,10 +52,11 @@ func (eg EG) Encrypt(m ecc.Point, pubK ecc.Point, r int) ([2]ecc.Point, error) {
} }
// Decrypt decrypts c (two points) with the private key, returns the point decrypted // Decrypt decrypts c (two points) with the private key, returns the point decrypted
func (eg EG) Decrypt(c [2]ecc.Point, privK int) (ecc.Point, error) { func (eg EG) Decrypt(c [2]ecc.Point, privK *big.Int) (ecc.Point, error) {
c1 := c[0] c1 := c[0]
c2 := c[1] c2 := c[1]
c1PrivK, err := eg.EC.Mul(c1, privK) privKCopy := new(big.Int).SetBytes(privK.Bytes())
c1PrivK, err := eg.EC.Mul(c1, privKCopy)
if err != nil { if err != nil {
return ecc.Point{}, err return ecc.Point{}, err
} }

View File

@@ -4,21 +4,20 @@ import (
"math/big" "math/big"
"testing" "testing"
ecc "../ecc" "github.com/arnaucube/cryptofun/ecc"
"github.com/stretchr/testify/assert"
) )
func TestNewEG(t *testing.T) { func TestNewEG(t *testing.T) {
ec := ecc.NewEC(1, 18, 19) ec := ecc.NewEC(1, 18, 19)
g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))}
eg, err := NewEG(ec, g) eg, err := NewEG(ec, g)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
} privK := big.NewInt(int64(5))
privK := 5
pubK, err := eg.PubK(privK) pubK, err := eg.PubK(privK)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !pubK.Equal(ecc.Point{big.NewInt(int64(13)), big.NewInt(int64(9))}) { if !pubK.Equal(ecc.Point{big.NewInt(int64(13)), big.NewInt(int64(9))}) {
t.Errorf("pubK!=(13, 9)") t.Errorf("pubK!=(13, 9)")
} }
@@ -27,20 +26,17 @@ func TestEGEncrypt(t *testing.T) {
ec := ecc.NewEC(1, 18, 19) ec := ecc.NewEC(1, 18, 19)
g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))}
eg, err := NewEG(ec, g) eg, err := NewEG(ec, g)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
} privK := big.NewInt(int64(5))
privK := 5
pubK, err := eg.PubK(privK) pubK, err := eg.PubK(privK)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
// m: point to encrypt // m: point to encrypt
m := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(12))} m := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(12))}
c, err := eg.Encrypt(m, pubK, 15) c, err := eg.Encrypt(m, pubK, big.NewInt(int64(15)))
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !c[0].Equal(ecc.Point{big.NewInt(int64(8)), big.NewInt(int64(5))}) { if !c[0].Equal(ecc.Point{big.NewInt(int64(8)), big.NewInt(int64(5))}) {
t.Errorf("c[0] != (8, 5), encryption failed") t.Errorf("c[0] != (8, 5), encryption failed")
} }
@@ -53,24 +49,20 @@ func TestEGDecrypt(t *testing.T) {
ec := ecc.NewEC(1, 18, 19) ec := ecc.NewEC(1, 18, 19)
g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))} g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(11))}
eg, err := NewEG(ec, g) eg, err := NewEG(ec, g)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
} privK := big.NewInt(int64(5))
privK := 5
pubK, err := eg.PubK(privK) pubK, err := eg.PubK(privK)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
// m: point to encrypt // m: point to encrypt
m := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(12))} m := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(12))}
c, err := eg.Encrypt(m, pubK, 15) c, err := eg.Encrypt(m, pubK, big.NewInt(int64(15)))
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
d, err := eg.Decrypt(c, privK) d, err := eg.Decrypt(c, privK)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
if !m.Equal(d) { if !m.Equal(d) {
t.Errorf("m != d, decrypting failed") t.Errorf("m != d, decrypting failed")
} }

7
go.mod Normal file
View File

@@ -0,0 +1,7 @@
module github.com/arnaucube/cryptofun
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)

6
go.sum Normal file
View File

@@ -0,0 +1,6 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=

View File

@@ -5,7 +5,8 @@ import (
"errors" "errors"
"math/big" "math/big"
prime "../prime" // prime "../prime"
"github.com/arnaucube/cryptofun/prime"
) )
const ( const (

View File

@@ -5,13 +5,14 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestEncryptDecrypt(t *testing.T) { func TestEncryptDecrypt(t *testing.T) {
key, err := GenerateKeyPair() key, err := GenerateKeyPair()
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
mBytes := []byte("Hi") mBytes := []byte("Hi")
m := new(big.Int).SetBytes(mBytes) m := new(big.Int).SetBytes(mBytes)
c := Encrypt(m, key.PubK) c := Encrypt(m, key.PubK)
@@ -24,9 +25,8 @@ func TestEncryptDecrypt(t *testing.T) {
func TestHomomorphicAddition(t *testing.T) { func TestHomomorphicAddition(t *testing.T) {
key, err := GenerateKeyPair() key, err := GenerateKeyPair()
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
n1 := big.NewInt(int64(110)) n1 := big.NewInt(int64(110))
n2 := big.NewInt(int64(150)) n2 := big.NewInt(int64(150))
c1 := Encrypt(n1, key.PubK) c1 := Encrypt(n1, key.PubK)

View File

@@ -4,13 +4,14 @@ import (
"bytes" "bytes"
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestEncryptDecrypt(t *testing.T) { func TestEncryptDecrypt(t *testing.T) {
key, err := GenerateKeyPair() key, err := GenerateKeyPair()
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
mBytes := []byte("Hi") mBytes := []byte("Hi")
m := new(big.Int).SetBytes(mBytes) m := new(big.Int).SetBytes(mBytes)
c := Encrypt(m, key.PubK) c := Encrypt(m, key.PubK)
@@ -22,9 +23,7 @@ func TestEncryptDecrypt(t *testing.T) {
} }
func TestBlindSignature(t *testing.T) { func TestBlindSignature(t *testing.T) {
key, err := GenerateKeyPair() key, err := GenerateKeyPair()
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
mBytes := []byte("Hi") mBytes := []byte("Hi")
m := new(big.Int).SetBytes(mBytes) m := new(big.Int).SetBytes(mBytes)
@@ -46,9 +45,7 @@ func TestBlindSignature(t *testing.T) {
func TestHomomorphicMultiplication(t *testing.T) { func TestHomomorphicMultiplication(t *testing.T) {
key, err := GenerateKeyPair() key, err := GenerateKeyPair()
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
n1 := big.NewInt(int64(11)) n1 := big.NewInt(int64(11))
n2 := big.NewInt(int64(15)) n2 := big.NewInt(int64(15))

136
schnorr/schnorr.go Normal file
View File

@@ -0,0 +1,136 @@
package schnorr
import (
"crypto/rand"
"crypto/sha256"
"math/big"
"github.com/arnaucube/cryptofun/ecc"
)
const (
bits = 512 // 2048
)
// PubK is the public key of the Schnorr scheme
type PubK struct {
P ecc.Point
Q ecc.Point
}
// PrivK is the private key of the Schnorr scheme
type PrivK struct {
PubK PubK
A *big.Int
}
// Schnorr is the data structure for the Schnorr scheme
type Schnorr struct {
EC ecc.EC
D *big.Int // K
G ecc.Point
Q ecc.Point // P
N int // order of curve
}
// Hash calculates a hash concatenating a given message bytes with a given EC Point. H(M||R)
func Hash(m []byte, c ecc.Point) *big.Int {
var b []byte
b = append(b, m...)
cXBytes := c.X.Bytes()
cYBytes := c.Y.Bytes()
b = append(b, cXBytes...)
b = append(b, cYBytes...)
h := sha256.New()
h.Write(b)
hash := h.Sum(nil)
r := new(big.Int).SetBytes(hash)
return r
}
// Gen generates the Schnorr scheme
func Gen(ec ecc.EC, g ecc.Point, r *big.Int) (Schnorr, PrivK, error) {
var err error
var schnorr Schnorr
var sk PrivK
schnorr.EC = ec
schnorr.G = g
sk.PubK.P, _, err = ec.At(r)
if err != nil {
return schnorr, sk, err
}
orderP, err := ec.Order(sk.PubK.P)
if err != nil {
return schnorr, sk, err
}
// rand int between 1 and oerder of P
sk.A, err = rand.Int(rand.Reader, orderP)
if err != nil {
return schnorr, sk, err
}
sk.A = big.NewInt(int64(7))
skACopy := new(big.Int).SetBytes(sk.A.Bytes())
// pk.Q = k x P
sk.PubK.Q, err = ec.Mul(sk.PubK.P, skACopy)
if err != nil {
return schnorr, sk, err
}
return schnorr, sk, nil
}
// Sign performs the signature of the message m with the given private key
func (schnorr Schnorr) Sign(sk PrivK, m []byte) (*big.Int, ecc.Point, error) {
var e *big.Int
orderP, err := schnorr.EC.Order(sk.PubK.P)
if err != nil {
return e, ecc.Point{}, err
}
// rand k <-[1,r]
k, err := rand.Int(rand.Reader, orderP)
if err != nil {
return e, ecc.Point{}, err
}
// R = k x P
rPoint, err := schnorr.EC.Mul(sk.PubK.P, k)
if err != nil {
return e, ecc.Point{}, err
}
// e = H(M||R)
e = Hash(m, rPoint)
// a*e
ae := new(big.Int).Mul(sk.A, e)
// k + a*e
kae := new(big.Int).Add(k, ae)
// k + a*e mod r, where r is order of P
s := new(big.Int).Mod(kae, orderP)
return s, rPoint, nil
}
// Verify checks if the given public key matches with the given signature of the message m, in the given EC
func Verify(ec ecc.EC, pk PubK, m []byte, s *big.Int, rPoint ecc.Point) (bool, error) {
// e = H(M||R)
e := Hash(m, rPoint)
eCopy := new(big.Int).SetBytes(e.Bytes())
// e x Q
eQ, err := ec.Mul(pk.Q, eCopy)
if err != nil {
return false, err
}
// R + e x Q
// reQ, err := schnorr.EC.Add(rPoint, eQ)
// if err != nil {
// return false, err
// }
// s x P
sp, err := ec.Mul(pk.P, s)
// return reQ.Equal(sp), nil
return eQ.Equal(sp), nil
}

65
schnorr/schnorr_test.go Normal file
View File

@@ -0,0 +1,65 @@
package schnorr
import (
"math/big"
"testing"
"github.com/arnaucube/cryptofun/ecc"
"github.com/stretchr/testify/assert"
)
// func TestNewSystem(t *testing.T) {
//
// ec := ecc.NewEC(0, 7, 11)
// g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(8))} // Generator
// r := big.NewInt(int64(7)) // random r
// schnorr, sk, err := Gen(ec, g, r)
// assert.Nil(t, err)
//
// fmt.Print("schnorr")
// fmt.Println(schnorr)
// fmt.Print("sk")
// fmt.Println(sk)
// }
func TestHash(t *testing.T) {
c := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(8))} // Generator
h := Hash([]byte("hola"), c)
assert.Equal(t, h.String(), "34719153732582497359642109898768696927847420320548121616059449972754491425079")
}
func TestSign(t *testing.T) {
ec := ecc.NewEC(0, 7, 11)
g := ecc.Point{big.NewInt(int64(7)), big.NewInt(int64(8))} // Generator
r := big.NewInt(int64(7)) // random r
schnorr, sk, err := Gen(ec, g, r)
assert.Nil(t, err)
m := []byte("hola")
s, rPoint, err := schnorr.Sign(sk, m)
assert.Nil(t, err)
verified, err := Verify(schnorr.EC, sk.PubK, m, s, rPoint)
assert.Nil(t, err)
assert.True(t, verified)
}
func TestSign2(t *testing.T) {
ec := ecc.NewEC(0, 7, 29)
g := ecc.Point{big.NewInt(int64(11)), big.NewInt(int64(27))} // Generator
r := big.NewInt(int64(23)) // random r
schnorr, sk, err := Gen(ec, g, r)
assert.Nil(t, err)
m := []byte("hola")
s, rPoint, err := schnorr.Sign(sk, m)
assert.Nil(t, err)
verified, err := Verify(schnorr.EC, sk.PubK, m, s, rPoint)
assert.Nil(t, err)
assert.True(t, verified)
}

View File

@@ -1,4 +1,4 @@
package secrets package shamirsecretsharing
import ( import (
"crypto/rand" "crypto/rand"
@@ -10,11 +10,11 @@ const (
bits = 1024 bits = 1024
) )
// Create calculates the secrets to share from given parameters
// t: number of secrets needed // t: number of secrets needed
// n: number of shares // n: number of shares
// p: random point // p: random point
// k: secret to share // k: secret to share
// Create calculates the secrets to share from given parameters
func Create(t, n, p, k *big.Int) (result [][]*big.Int, err error) { func Create(t, n, p, k *big.Int) (result [][]*big.Int, err error) {
if k.Cmp(p) > 0 { if k.Cmp(p) > 0 {
return nil, errors.New("Error: need k<p. k: " + k.String() + ", p: " + p.String()) return nil, errors.New("Error: need k<p. k: " + k.String() + ", p: " + p.String())

View File

@@ -1,17 +1,17 @@
package secrets package shamirsecretsharing
import ( import (
"crypto/rand" "crypto/rand"
"math/big" "math/big"
"testing" "testing"
"github.com/stretchr/testify/assert"
) )
func TestCreate(t *testing.T) { func TestCreate(t *testing.T) {
k := 123456789 k := 123456789
p, err := rand.Prime(rand.Reader, bits/2) p, err := rand.Prime(rand.Reader, bits/2)
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
nNeededSecrets := big.NewInt(int64(3)) nNeededSecrets := big.NewInt(int64(3))
nShares := big.NewInt(int64(6)) nShares := big.NewInt(int64(6))
@@ -20,9 +20,7 @@ func TestCreate(t *testing.T) {
nShares, nShares,
p, p,
big.NewInt(int64(k))) big.NewInt(int64(k)))
if err != nil { assert.Nil(t, err)
t.Errorf(err.Error())
}
//generate sharesToUse //generate sharesToUse
var sharesToUse [][]*big.Int var sharesToUse [][]*big.Int