Skip to content

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

Description

@Jovonni

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) {

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions