-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
2,957 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package ekliptic | ||
|
||
import "math/big" | ||
|
||
// SignECDSA signs a message hash z using the private key d, and a random (or deterministically | ||
// derived) nonce k. It sets r and s to the resulting signature parts. | ||
// | ||
// Both the nonce k and the private key d should be generated with equal probability distribution | ||
// over the range [1, Secp256k1_CurveOrder). SignECDSA Panics if k or d is not within this range. | ||
func SignECDSA( | ||
d, k, z *big.Int, | ||
r, s *big.Int, | ||
) { | ||
if k.Cmp(Secp256k1_CurveOrder) >= 0 || k.Cmp(one) == -1 { | ||
panic("SignECDSA: expected nonce k to be in range [1, Secp256k1_CurveOrder)") | ||
} else if d.Cmp(Secp256k1_CurveOrder) >= 0 || d.Cmp(one) == -1 { | ||
panic("SignECDSA: expected private key d to be in range [1, Secp256k1_CurveOrder)") | ||
} | ||
|
||
// (x, _) = k * G | ||
x := new(big.Int) | ||
MultiplyBasePoint(k, x, new(big.Int)) | ||
|
||
// r = x mod N | ||
r.Mod(x, Secp256k1_CurveOrder) | ||
|
||
// m = rd + z | ||
m := x.Mul(r, d) | ||
m.Add(m, z) | ||
x = nil | ||
|
||
// s = k⁻¹ * m mod N | ||
s.ModInverse(k, Secp256k1_CurveOrder) | ||
s.Mul(s, m) | ||
s.Mod(s, Secp256k1_CurveOrder) | ||
|
||
// always provide canonical signatures. | ||
// | ||
// if s > (N/2): | ||
// s = N - s | ||
if s.Cmp(Secp256k1_CurveOrderHalf) == 1 { | ||
s.Sub(Secp256k1_CurveOrder, s) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package ekliptic | ||
|
||
import ( | ||
cryptorand "crypto/rand" | ||
"crypto/sha256" | ||
"fmt" | ||
"math/big" | ||
mathrand "math/rand" | ||
"testing" | ||
|
||
"github.com/kklash/ekliptic/test_vectors" | ||
) | ||
|
||
func TestSignECDSA(t *testing.T) { | ||
r := new(big.Int) | ||
s := new(big.Int) | ||
|
||
for i, vector := range test_vectors.ECDSAVectors { | ||
SignECDSA( | ||
vector.PrivateKey, vector.Nonce, vector.Hash, | ||
r, s, | ||
) | ||
|
||
if !equal(r, vector.R) || !equal(s, vector.S) { | ||
t.Errorf(`invalid ECDSA signature for vector %d. Got: | ||
r: %.64x | ||
s: %.64x | ||
Wanted: | ||
r: %.64x | ||
s: %.64x | ||
`, i, r, s, vector.R, vector.S) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkSignECDSA(b *testing.B) { | ||
r := new(big.Int) | ||
s := new(big.Int) | ||
|
||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
vector := test_vectors.ECDSAVectors[i%len(test_vectors.ECDSAVectors)] | ||
SignECDSA( | ||
vector.PrivateKey, vector.Nonce, vector.Hash, | ||
r, s, | ||
) | ||
} | ||
} | ||
|
||
func ExampleSignECDSA() { | ||
randReader := mathrand.New(mathrand.NewSource(1)) | ||
|
||
key, _ := cryptorand.Int(randReader, Secp256k1_CurveOrder) | ||
nonce, _ := cryptorand.Int(randReader, Secp256k1_CurveOrder) | ||
|
||
hashedMessage := sha256.Sum256([]byte("i love you")) | ||
hashedMessageInt := new(big.Int).SetBytes(hashedMessage[:]) | ||
|
||
r := new(big.Int) | ||
s := new(big.Int) | ||
|
||
SignECDSA( | ||
key, nonce, hashedMessageInt, | ||
r, s, | ||
) | ||
|
||
fmt.Printf("r: %x\n", r) | ||
fmt.Printf("s: %x\n", s) | ||
|
||
// output: | ||
// | ||
// r: 4a821d5ec008712983929de448b8afb6c24e5a1b97367b9a65b6220d7f083fe3 | ||
// s: 2e4f380e0ea1dfcb7cced430437c98b4570a06b3e929a3b19e6bbd53df2cf3f6 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package test_vectors | ||
|
||
import ( | ||
_ "embed" | ||
"encoding/json" | ||
"math/big" | ||
) | ||
|
||
// ECDSAVector represents a test vector for the elliptic curve digital signature algorithm | ||
// on a given message hash with a private key and nonce. | ||
type ECDSAVector struct { | ||
Hash *big.Int | ||
PrivateKey *big.Int | ||
Nonce *big.Int | ||
R, S *big.Int | ||
} | ||
|
||
//go:embed ecdsa.json | ||
var ecdsaJsonBytes []byte | ||
|
||
func loadECDSAVectors() ([]*ECDSAVector, error) { | ||
var rawJsonObjects []map[string]string | ||
|
||
if err := json.Unmarshal(ecdsaJsonBytes, &rawJsonObjects); err != nil { | ||
return nil, err | ||
} | ||
|
||
vectors := make([]*ECDSAVector, len(rawJsonObjects)) | ||
|
||
for i, obj := range rawJsonObjects { | ||
vectors[i] = &ECDSAVector{ | ||
Hash: hexint(obj["hash"]), | ||
PrivateKey: hexint(obj["d"]), | ||
Nonce: hexint(obj["nonce"]), | ||
R: hexint(obj["r"]), | ||
S: hexint(obj["s"]), | ||
} | ||
} | ||
|
||
return vectors, nil | ||
} |
Oops, something went wrong.