package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
"math/big"
)
func main() {
privateKeyAlice, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
publicKeyAlice := &privateKeyAlice.PublicKey
privateKeyBob, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
publicKeyBob := &privateKeyBob.PublicKey
message := "Hello, Schnorr!"
// Alice's side
r, s, err := schnorrSign(privateKeyAlice, message)
if err != nil {
fmt.Println("Error signing:", err)
return
}
// Bob's side
valid := schnorrVerify(publicKeyAlice, message, r, s)
if valid {
fmt.Println("Signature is valid.")
} else {
fmt.Println("Signature is invalid.")
}
}
func schnorrSign(privateKey ecdsa.PrivateKey, message string) (big.Int, *big.Int, error) {
// Step 1: Choose a random nonce
k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return nil, nil, err
}
nonce := k.D
// Step 2: Compute the public nonce point
Rx, Ry := elliptic.P256().ScalarBaseMult(nonce.Bytes())
// Step 3: Compute the challenge
e := computeChallenge(Rx, Ry, privateKey.PublicKey.X, privateKey.PublicKey.Y, message)
// Step 4: Compute the response
s := new(big.Int).Mul(privateKey.D, e)
s.Add(s, nonce)
s.Mod(s, elliptic.P256().Params().N)
// Step 5: Construct the signature (Rx, s)
return Rx, s, nil
}
func schnorrVerify(publicKey ecdsa.PublicKey, message string, Rx, s big.Int) bool {
// Step 1: Compute the challenge
e := computeChallenge(Rx, nil, publicKey.X, publicKey.Y, message)
// Step 2: Compute the public nonce point
Rx, Ry := elliptic.P256().ScalarBaseMult(s.Bytes())
// Step 3: Compute the response point
Px, Py := elliptic.P256().Add(Rx, nil, publicKey.X, publicKey.Y)
// Step 4: Verify that Rx is equal to Px
return Rx.Cmp(Px) == 0 && e.Cmp(new(big.Int).SetBytes(hashR(Rx.Bytes(), Py.Bytes(), message))) == 0
}
func computeChallenge(Rx, Ry, Px, Py big.Int, message string) big.Int {
// Step 1: Compute the hash of (Rx || Ry || Px || Py || message)
hash := hashR(Rx.Bytes(), Ry.Bytes(), Px.Bytes(), Py.Bytes(), []byte(message))
// Step 2: Convert the hash to a big.Int
return new(big.Int).SetBytes(hash)
}
func hashR(args ...[]byte) []byte {
hash := sha256.New()
for _, arg := range args {
hash.Write(arg)
}
return hash.Sum(nil)
}