mirror of
https://github.com/arnaucube/cryptofun.git
synced 2026-02-28 05:16:46 +01:00
Schnorr signature implemented. ECC point multiplication with big int. Refactor of the code.
This commit is contained in:
136
schnorr/schnorr.go
Normal file
136
schnorr/schnorr.go
Normal 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
65
schnorr/schnorr_test.go
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user