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) {
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
and this test passes:
but this test fails
why does the
AggregateSignaturesfunction signature expect a set of private keys instead of public keys: