hbakhtiyor / schnorr Goto Github PK
View Code? Open in Web Editor NEWGo implementation of the BIP Schnorr signature scheme.
License: MIT License
Go implementation of the BIP Schnorr signature scheme.
License: MIT License
good review and discussion here https://www.reddit.com/r/golang/comments/af3chc/go_implementation_of_the_bip_schnorr_signature/edw06bj/
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) {
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.