Giter VIP home page Giter VIP logo

schnorr's Introduction

GoDoc Build Status Go Report Card License Latest tag

Go implementation of the Schnorr BIP

This is a Go implementation of the standard 64-byte Schnorr signature scheme over the elliptic curve secp256k1.

The code is based upon the initial proposal of Pieter Wuille when it didn't have a BIP number assigned yet.

The current version passes all test vectors provided here. But the author does not give any guarantees that the algorithm is implemented correctly for every edge case!

Table of Contents

Usage

Install using:

go get -u github.com/hbakhtiyor/schnorr

In your code:

import "github.com/hbakhtiyor/schnorr"

signature, err := schnorr.Sign(privateKey, message)

result, err := schnorr.Verify(publicKey, message, signature)

result, err := schnorr.BatchVerify(publicKeys, messages, signatures)

signature, err := schnorr.AggregateSignatures(privateKeys, message)

API

Requiring the module gives an object with four methods:

Sign(privateKey *big.Int, message [32]byte) ([64]byte, error)

Sign a 32-byte message with the private key, returning a 64-byte signature. Read more

Arguments
  1. privateKey (*big.Int): The integer secret key in the range 1..n-1.
  2. message ([32]byte): The 32-byte array message.
Returns

([64]byte, error): A 64-byte array signature. An error if signing fails.

Examples
var message [32]byte

privateKey, _ := new(big.Int).SetString("B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF", 16)
msg, _ := hex.DecodeString("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
copy(message[:], msg)

signature, err := schnorr.Sign(privateKey, message)
if err != nil {
  fmt.Printf("The signing is failed: %v\n", err)
}
fmt.Printf("The signature is: %x\n", signature)

Verify(publicKey [33]byte, message [32]byte, signature [64]byte) (bool, error)

Verify a 64-byte signature of a 32-byte message against the public key. Read more

Arguments
  1. publicKey ([33]byte): The 33-byte array public key.
  2. message ([32]byte): The 32-byte array message.
  3. signature ([64]byte): The 64-byte array signature.
Returns

(bool, error): True if signature is valid, An error if verification fails.

Examples
var (
  publicKey [33]byte
  message   [32]byte
  signature [64]byte
)

pk, _ := hex.DecodeString("02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659")
copy(publicKey[:], pk)
msg, _ := hex.DecodeString("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
copy(message[:], msg)
sig, _ := hex.DecodeString("2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD")
copy(signature[:], sig)

if result, err := schnorr.Verify(publicKey, message, signature); err != nil {
  fmt.Printf("The signature verification failed: %v\n", err)
} else if result {
  fmt.Println("The signature is valid.")
}

BatchVerify(publicKeys [][33]byte, messages [][32]byte, signatures [][64]byte) (bool, error)

Verify a list of 64-byte signatures of a 32-byte messages against the public keys. Read more

Arguments
  1. publicKeys ([][33]byte): The list of 33-byte array public keys.
  2. messages ([][32]byte): The list of 32-byte array messages.
  3. signatures ([][64]byte): The list of 64-byte array signatures.
Returns

(bool, error): True if all signatures are valid, An error if one verification fails.

Examples
var (
  publicKey  [33]byte
  message    [32]byte
  signature  [64]byte
  publicKeys [][33]byte
  messages   [][32]byte
  signatures [][64]byte
)

pk, _ := hex.DecodeString("02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659")
copy(publicKey[:], pk)
publicKeys = append(publicKeys, publicKey)
pk, _ = hex.DecodeString("03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B")
copy(publicKey[:], pk)
publicKeys = append(publicKeys, publicKey)
pk, _ = hex.DecodeString("026D7F1D87AB3BBC8BC01F95D9AECE1E659D6E33C880F8EFA65FACF83E698BBBF7")
copy(publicKey[:], pk)
publicKeys = append(publicKeys, publicKey)
msg, _ := hex.DecodeString("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
copy(message[:], msg)
messages = append(messages, message)
msg, _ = hex.DecodeString("5E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C")
copy(message[:], msg)
messages = append(messages, message)
msg, _ = hex.DecodeString("B2F0CD8ECB23C1710903F872C31B0FD37E15224AF457722A87C5E0C7F50FFFB3")
copy(message[:], msg)
messages = append(messages, message)
sig, _ := hex.DecodeString("2A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D1E51A22CCEC35599B8F266912281F8365FFC2D035A230434A1A64DC59F7013FD")
copy(signature[:], sig)
signatures = append(signatures, signature)
sig, _ = hex.DecodeString("00DA9B08172A9B6F0466A2DEFD817F2D7AB437E0D253CB5395A963866B3574BE00880371D01766935B92D2AB4CD5C8A2A5837EC57FED7660773A05F0DE142380")
copy(signature[:], sig)
signatures = append(signatures, signature)
sig, _ = hex.DecodeString("68CA1CC46F291A385E7C255562068357F964532300BEADFFB72DD93668C0C1CAC8D26132EB3200B86D66DE9C661A464C6B2293BB9A9F5B966E53CA736C7E504F")
copy(signature[:], sig)
signatures = append(signatures, signature)

if result, err := schnorr.BatchVerify(publicKeys, messages, signatures); err != nil {
  fmt.Printf("The signature verification failed: %v\n", err)
} else if result {
  fmt.Println("The signature is valid.")
}

AggregateSignatures(privateKeys []*big.Int, message [32]byte) ([64]byte, error)

Aggregate multiple signatures of different private keys over the same message into a single 64-byte signature.

Arguments
  1. privateKeys ([]*big.Int): The list of integer secret keys in the range 1..n-1.
  2. message ([32]byte): The list of 32-byte array messages.
Returns

(bool, error): True if all signatures are valid, An error if one verification fails. ([64]byte, error): A 64-byte array signature. An error if signing fails.

Examples
var (
  publicKey [33]byte
  message   [32]byte
)

privateKey1, _ := new(big.Int).SetString("B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF", 16)
privateKey2, _ := new(big.Int).SetString("C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7", 16)
msg, _ := hex.DecodeString("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
copy(message[:], msg)

privateKeys := []*big.Int{privateKey1, privateKey2}
signature, _ := schnorr.AggregateSignatures(privateKeys, message)

// verifying an aggregated signature
pk, _ := hex.DecodeString("02DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659")
copy(publicKey[:], pk)
P1x, P1y := schnorr.Unmarshal(Curve, publicKey[:])

pk, _ = hex.DecodeString("03FAC2114C2FBB091527EB7C64ECB11F8021CB45E8E7809D3C0938E4B8C0E5F84B")
copy(publicKey[:], pk)
P2x, P2y := schnorr.Unmarshal(Curve, publicKey[:])
Px, Py := Curve.Add(P1x, P1y, P2x, P2y)

copy(publicKey[:], schnorr.Marshal(Curve, Px, Py))

if result, err := schnorr.Verify(publicKey, message, signature); err != nil {
  fmt.Printf("The signature verification failed: %v\n", err)
} else if result {
  fmt.Println("The signature is valid.")
}

Benchmarks

BenchmarkSign-4                  	    2000	   1015337 ns/op	   45812 B/op	     814 allocs/op
BenchmarkVerify-4                	     200	   8555659 ns/op	  217884 B/op	    3622 allocs/op
BenchmarkBatchVerify-4           	     100	  12114966 ns/op	  148343 B/op	    2220 allocs/op
BenchmarkAggregateSignatures-4   	    2000	    593665 ns/op	   21981 B/op	     400 allocs/op
Hardware used
  • Intel® Core™ i3-2310M CPU @ 2.10GHz × 4
  • 4Gb RAM
Versions
  • Go 1.11.2
  • Ubuntu 18.04.01 LTS x86_64 OS
  • 4.15.0-39-generic kernel

Credits

schnorr's People

Contributors

guggero avatar hbakhtiyor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

schnorr's Issues

Security: why do you require submitting private keys for the aggregatesignature function?

The scheme should make use of aggregating public keys, not using private keys, as one of the two parties having access to the other private keys is a security risk

I've tried to do the following

func AggregatePublicKeys(publicKeys [][]byte) ([33]byte, error) {
	var aggregatePubKeyX, aggregatePubKeyY *big.Int

	for _, pubKeyBytes := range publicKeys {
		pubKeyX, pubKeyY := Unmarshal(Curve, pubKeyBytes)
		if pubKeyX == nil || pubKeyY == nil {
			return [33]byte{}, errors.New("invalid public key")
		}
		if aggregatePubKeyX == nil || aggregatePubKeyY == nil {
			aggregatePubKeyX, aggregatePubKeyY = pubKeyX, pubKeyY
		} else {
			// Add the current public key to the aggregate public key.
			aggregatePubKeyX, aggregatePubKeyY = Curve.Add(aggregatePubKeyX, aggregatePubKeyY, pubKeyX, pubKeyY)
		}
	}

	if aggregatePubKeyX == nil || aggregatePubKeyY == nil {
		return [33]byte{}, errors.New("no public keys provided")
	}

	aggregatedPubKeyBytes := Marshal(Curve, aggregatePubKeyX, aggregatePubKeyY)
	var aggregatedPubKey [33]byte
	copy(aggregatedPubKey[:], aggregatedPubKeyBytes)
	return aggregatedPubKey, nil
}

and this test passes:

func TestAggregatePublicKeys(t *testing.T) {
	privKeyHex1 := "B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF"
	privKeyHex2 := "C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7"

	privKey1, _ := new(big.Int).SetString(privKeyHex1, 16)
	privKey2, _ := new(big.Int).SetString(privKeyHex2, 16)

	pubKey1X, pubKey1Y := Curve.ScalarBaseMult(privKey1.Bytes())
	pubKey2X, pubKey2Y := Curve.ScalarBaseMult(privKey2.Bytes())

	pubKeyBytes1 := Marshal(Curve, pubKey1X, pubKey1Y)
	pubKeyBytes2 := Marshal(Curve, pubKey2X, pubKey2Y)

	aggregatedPubKey, err := AggregatePublicKeys([][]byte{pubKeyBytes1, pubKeyBytes2})
	if err != nil {
		t.Fatalf("Failed to aggregate public keys: %v", err)
	}

	expectedAggregatedPubKeyHex := "03f0a6305d39a34582ba49a78bdf38ced935b3efce1e889d6820103665f35ee45b"
	expectedAggregatedPubKeyBytes, err := hex.DecodeString(expectedAggregatedPubKeyHex)
	if err != nil {
		t.Fatalf("Failed to decode expected aggregated public key hex: %v", err)
	}

	aggregatedPubKeyHex := hex.EncodeToString(aggregatedPubKey[:])

	if aggregatedPubKeyHex != expectedAggregatedPubKeyHex {
		t.Errorf("Aggregated public key does not match the expected value.\nExpected: %s\nGot: %s", expectedAggregatedPubKeyHex, aggregatedPubKeyHex)
	}

	if hex.EncodeToString(expectedAggregatedPubKeyBytes) != aggregatedPubKeyHex {
		t.Errorf("Aggregated public key bytes do not match the expected bytes.\nExpected: %x\nGot: %x", expectedAggregatedPubKeyBytes, aggregatedPubKey)
	}
}

but this test fails

func TestVerifyWithAggregatedPublicKey(t *testing.T) {
	// Step 1: Aggregate public keys
	privKeysHex := []string{
		"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF",
		"C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C7",
	}
	var publicKeys [][]byte
	for _, hexKey := range privKeysHex {
		privKey, ok := new(big.Int).SetString(hexKey, 16)
		if !ok {
			t.Fatalf("Failed to parse private key: %s", hexKey)
		}
		px, py := Curve.ScalarBaseMult(privKey.Bytes())
		publicKeys = append(publicKeys, Marshal(Curve, px, py))
	}
	fmt.Println(publicKeys)
	aggregatedPublicKey, err := AggregatePublicKeys(publicKeys)
	if err != nil {
		t.Fatalf("Failed to aggregate public keys: %v", err)
	}

	// Step 2: Sign a message using one of the private keys 
	message := [32]byte{ /* your message here, can be random */ }
	privKeyBigInt, ok := new(big.Int).SetString(privKeysHex[0], 16)
	if !ok {
		t.Fatalf("Failed to parse private key: %s", privKeysHex[0])
	}
	signature, err := Sign(privKeyBigInt, message)
	if err != nil {
		t.Fatalf("Failed to sign message: %v", err)
	}

	// Step 3: Verify the signature against the aggregated public key
	verified, err := Verify(aggregatedPublicKey, message, signature)
	if err != nil {
		t.Fatalf("Verification failed with error: %v", err)
	}
	if !verified {
		t.Fatal("Failed to verify signature with aggregated public key")
	}
}

why does the AggregateSignatures function signature expect a set of private keys instead of public keys:

func AggregateSignatures(privateKeys []*big.Int, message [32]byte) ([64]byte, error) {

2 of 3 signatures ?

Your go implementation is an amazing work! I was just wondering if it supports 2 of 3 multi-signature using schnorr? How can we do that? Is there an example of how to do it? I would love to use schnorr 2 of 3 multi-signature in my implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.