This commit introduces two new files: `BENCHMARK_RESULTS.md` and `benchmark_results.txt`, which document the performance metrics of various cryptographic operations, including ECDSA signing, verification, and ECDH key exchange. The results provide insights into operation times, memory allocations, and comparisons with C implementations. Additionally, new test files for ECDSA and ECDH functionalities have been added, ensuring comprehensive coverage and validation of the implemented algorithms. This enhances the overall robustness and performance understanding of the secp256k1 implementation.
221 lines
4.6 KiB
Go
221 lines
4.6 KiB
Go
package p256k1
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
)
|
|
|
|
// ECSeckeyVerify verifies that a 32-byte array is a valid secret key
|
|
func ECSeckeyVerify(seckey []byte) bool {
|
|
if len(seckey) != 32 {
|
|
return false
|
|
}
|
|
|
|
var scalar Scalar
|
|
return scalar.setB32Seckey(seckey)
|
|
}
|
|
|
|
// ECSeckeyNegate negates a secret key in place
|
|
func ECSeckeyNegate(seckey []byte) bool {
|
|
if len(seckey) != 32 {
|
|
return false
|
|
}
|
|
|
|
var scalar Scalar
|
|
if !scalar.setB32Seckey(seckey) {
|
|
return false
|
|
}
|
|
|
|
scalar.negate(&scalar)
|
|
scalar.getB32(seckey)
|
|
return true
|
|
}
|
|
|
|
// ECSeckeyGenerate generates a new random secret key
|
|
func ECSeckeyGenerate() ([]byte, error) {
|
|
seckey := make([]byte, 32)
|
|
for {
|
|
if _, err := rand.Read(seckey); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if ECSeckeyVerify(seckey) {
|
|
return seckey, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
// ECKeyPairGenerate generates a new key pair (private key and public key)
|
|
func ECKeyPairGenerate() (seckey []byte, pubkey *PublicKey, err error) {
|
|
seckey, err = ECSeckeyGenerate()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
pubkey = &PublicKey{}
|
|
if err := ECPubkeyCreate(pubkey, seckey); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return seckey, pubkey, nil
|
|
}
|
|
|
|
// ECSeckeyTweakAdd adds a tweak to a secret key: seckey = seckey + tweak mod n
|
|
func ECSeckeyTweakAdd(seckey []byte, tweak []byte) error {
|
|
if len(seckey) != 32 {
|
|
return errors.New("secret key must be 32 bytes")
|
|
}
|
|
if len(tweak) != 32 {
|
|
return errors.New("tweak must be 32 bytes")
|
|
}
|
|
|
|
var sec, tw Scalar
|
|
if !sec.setB32Seckey(seckey) {
|
|
return errors.New("invalid secret key")
|
|
}
|
|
if !tw.setB32Seckey(tweak) {
|
|
return errors.New("invalid tweak")
|
|
}
|
|
|
|
// Add tweak
|
|
sec.add(&sec, &tw)
|
|
|
|
// Check if result is valid
|
|
if sec.isZero() {
|
|
return errors.New("resulting secret key is zero")
|
|
}
|
|
|
|
// Get result
|
|
sec.getB32(seckey)
|
|
return nil
|
|
}
|
|
|
|
// ECSeckeyTweakMul multiplies a secret key by a tweak: seckey = seckey * tweak mod n
|
|
func ECSeckeyTweakMul(seckey []byte, tweak []byte) error {
|
|
if len(seckey) != 32 {
|
|
return errors.New("secret key must be 32 bytes")
|
|
}
|
|
if len(tweak) != 32 {
|
|
return errors.New("tweak must be 32 bytes")
|
|
}
|
|
|
|
var sec, tw Scalar
|
|
if !sec.setB32Seckey(seckey) {
|
|
return errors.New("invalid secret key")
|
|
}
|
|
if !tw.setB32Seckey(tweak) {
|
|
return errors.New("invalid tweak")
|
|
}
|
|
|
|
// Multiply by tweak
|
|
sec.mul(&sec, &tw)
|
|
|
|
// Check if result is valid
|
|
if sec.isZero() {
|
|
return errors.New("resulting secret key is zero")
|
|
}
|
|
|
|
// Get result
|
|
sec.getB32(seckey)
|
|
return nil
|
|
}
|
|
|
|
// ECPubkeyTweakAdd adds a tweak to a public key: pubkey = pubkey + tweak*G
|
|
func ECPubkeyTweakAdd(pubkey *PublicKey, tweak []byte) error {
|
|
if len(tweak) != 32 {
|
|
return errors.New("tweak must be 32 bytes")
|
|
}
|
|
|
|
var tw Scalar
|
|
if !tw.setB32Seckey(tweak) {
|
|
return errors.New("invalid tweak")
|
|
}
|
|
|
|
// Load public key
|
|
var pubkeyPoint GroupElementAffine
|
|
pubkeyPoint.fromBytes(pubkey.data[:])
|
|
if pubkeyPoint.isInfinity() {
|
|
return errors.New("invalid public key")
|
|
}
|
|
|
|
// Compute tweak*G
|
|
var tweakG GroupElementJacobian
|
|
EcmultGen(&tweakG, &tw)
|
|
|
|
// Add to public key
|
|
var pubkeyJac GroupElementJacobian
|
|
pubkeyJac.setGE(&pubkeyPoint)
|
|
|
|
// result = pubkey + tweak*G
|
|
var result GroupElementJacobian
|
|
result.addVar(&pubkeyJac, &tweakG)
|
|
|
|
// Check if result is infinity
|
|
if result.isInfinity() {
|
|
return errors.New("resulting public key is infinity")
|
|
}
|
|
|
|
// Convert back to affine and store
|
|
var resultAff GroupElementAffine
|
|
resultAff.setGEJ(&result)
|
|
resultAff.toBytes(pubkey.data[:])
|
|
|
|
return nil
|
|
}
|
|
|
|
// ECPubkeyTweakMul multiplies a public key by a tweak: pubkey = pubkey * tweak
|
|
func ECPubkeyTweakMul(pubkey *PublicKey, tweak []byte) error {
|
|
if len(tweak) != 32 {
|
|
return errors.New("tweak must be 32 bytes")
|
|
}
|
|
|
|
var tw Scalar
|
|
if !tw.setB32Seckey(tweak) {
|
|
return errors.New("invalid tweak")
|
|
}
|
|
|
|
// Load public key
|
|
var pubkeyPoint GroupElementAffine
|
|
pubkeyPoint.fromBytes(pubkey.data[:])
|
|
if pubkeyPoint.isInfinity() {
|
|
return errors.New("invalid public key")
|
|
}
|
|
|
|
// Multiply by tweak using binary method
|
|
var pubkeyJac GroupElementJacobian
|
|
pubkeyJac.setGE(&pubkeyPoint)
|
|
|
|
var result GroupElementJacobian
|
|
result.setInfinity()
|
|
var base GroupElementJacobian
|
|
base = pubkeyJac
|
|
|
|
// Simple binary method
|
|
for i := 0; i < 256; i++ {
|
|
if i > 0 {
|
|
result.double(&result)
|
|
}
|
|
bit := tw.getBits(uint(255-i), 1)
|
|
if bit != 0 {
|
|
if result.isInfinity() {
|
|
result = base
|
|
} else {
|
|
result.addVar(&result, &base)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if result is infinity
|
|
if result.isInfinity() {
|
|
return errors.New("resulting public key is infinity")
|
|
}
|
|
|
|
// Convert back to affine and store
|
|
var resultAff GroupElementAffine
|
|
resultAff.setGEJ(&result)
|
|
resultAff.toBytes(pubkey.data[:])
|
|
|
|
return nil
|
|
}
|
|
|