bnb-chain / tss-lib

Threshold Signature Scheme, for ECDSA and EDDSA
MIT License
803 stars 273 forks source link

How can I use it in the Solana chain #238

Open 008mkcir opened 1 year ago

008mkcir commented 1 year ago

Hi there,

Is this lib could be used for Solana network?

I am trying to use this lib to sign the Solana transaction which build-up from this Solana SDK.

        c := rpc.New("https://api.devnet.solana.com")

    pubKeyByte := base58.Decode(pubKeyBase58)
    t.Logf("sol pub key: %+v", pubKeyByte)
    t.Logf("sol pub key base58: %s", pubKeyBase58)
    accountFrom := solana.MustPublicKeyFromBase58(pubKeyBase58)
    accountTo := solana.MustPublicKeyFromBase58(pubKeyBase58)
    amount := uint64(1)
    sigBase58, err := c.RequestAirdrop(context.Background(), accountFrom, solana.LAMPORTS_PER_SOL, rpc.CommitmentConfirmed)
    t.Logf("airdrop sig base58: %s", sigBase58)

    recentHash, err := c.GetRecentBlockhash(context.Background(), rpc.CommitmentFinalized)
    if err != nil {
        panic(err)
    }
    t.Logf("recent block hash: %s", recentHash.Value.Blockhash)

    tx, err := solana.NewTransaction(
        []solana.Instruction{
            system.NewTransferInstruction(
                amount,
                accountFrom,
                accountTo,
            ).Build(),
        },
        solana.MustHashFromBase58(recentHash.Value.Blockhash.String()),
        solana.TransactionPayer(accountFrom),
    )
    if err != nil {
        panic(err)
    }
    msg, err := tx.Message.MarshalBinary()
    if err != nil {
        panic(err)
    }

        // use it as original message
    msgBigInt := (&big.Int{}).SetBytes(msg)

Then, I pass msgBigInt to signing function (like TestE2EConcurrent test case flow) to get the r, s signature.

...
        case <-endCh:
            atomic.AddInt32(&ended, 1)
            if atomic.LoadInt32(&ended) == int32(len(signPIDs)) {
                t.Logf("Done. Received signature data from %d participants", ended)
                R := parties[0].temp.r

                // BEGIN check s correctness
                sumS := parties[0].temp.si
                for i, p := range parties {
                    if i == 0 {
                        continue
                    }

                    var tmpSumS [32]byte
                    edwards25519.ScMulAdd(&tmpSumS, sumS, bigIntToEncodedBytes(big.NewInt(1)), p.temp.si)
                    sumS = &tmpSumS
                }
                fmt.Printf("S: %s\n", encodedBytesToBigInt(sumS).String())
                fmt.Printf("R: %s\n", R.String())
                // END check s correctness

                // BEGIN EDDSA verify
                pkX, pkY := keys[0].EDDSAPub.X(), keys[0].EDDSAPub.Y()
                pk := edwards.PublicKey{
                    Curve: tss.Edwards(),
                    X:     pkX,
                    Y:     pkY,
                }
                t.Logf("combine pub key: %s", base58.Encode(pk.Serialize()))

                                 newSig, err := edwards.ParseSignature(parties[0].data.Signature)
                if err != nil {
                    println("new sig error, ", err.Error())
                }

                ok := edwards.Verify(&pk, msg, newSig.R, newSig.S)
                assert.True(t, ok, "eddsa verify must pass")
                t.Log("EDDSA signing test done.")
                // END EDDSA verify

                signingSigBytes := make([]byte, 64)
                copy(signingSigBytes[:32], newSig.R.Bytes())
                copy(signingSigBytes[32:], newSig.S.Bytes())

                signature := solana.SignatureFromBytes(signingSigBytes)
                t.Logf("sign sig: %s", signature)
                tx.Signatures = append(tx.Signatures, signature)
                err = tx.VerifySignatures()
                if err != nil {
                    panic(err)
                }

Test it with VerifySignatures() function, but got the transaction signature failed panic: invalid signature by FKAAiwGD73AWgW6WhETAqvuoqHjLLbibSwiSJfU1qt5r

How can I fix it? Thanks.

trivonhan commented 1 year ago

Hi there,

Is this lib could be used for Solana network?

I am trying to use this lib to sign the Solana transaction which build-up from this Solana SDK.

        c := rpc.New("https://api.devnet.solana.com")

  pubKeyByte := base58.Decode(pubKeyBase58)
  t.Logf("sol pub key: %+v", pubKeyByte)
  t.Logf("sol pub key base58: %s", pubKeyBase58)
  accountFrom := solana.MustPublicKeyFromBase58(pubKeyBase58)
  accountTo := solana.MustPublicKeyFromBase58(pubKeyBase58)
  amount := uint64(1)
  sigBase58, err := c.RequestAirdrop(context.Background(), accountFrom, solana.LAMPORTS_PER_SOL, rpc.CommitmentConfirmed)
  t.Logf("airdrop sig base58: %s", sigBase58)

  recentHash, err := c.GetRecentBlockhash(context.Background(), rpc.CommitmentFinalized)
  if err != nil {
      panic(err)
  }
  t.Logf("recent block hash: %s", recentHash.Value.Blockhash)

  tx, err := solana.NewTransaction(
      []solana.Instruction{
          system.NewTransferInstruction(
              amount,
              accountFrom,
              accountTo,
          ).Build(),
      },
      solana.MustHashFromBase58(recentHash.Value.Blockhash.String()),
      solana.TransactionPayer(accountFrom),
  )
  if err != nil {
      panic(err)
  }
  msg, err := tx.Message.MarshalBinary()
  if err != nil {
      panic(err)
  }

        // use it as original message
  msgBigInt := (&big.Int{}).SetBytes(msg)

Then, I pass msgBigInt to signing function (like TestE2EConcurrent test case flow) to get the r, s signature.

...
      case <-endCh:
          atomic.AddInt32(&ended, 1)
          if atomic.LoadInt32(&ended) == int32(len(signPIDs)) {
              t.Logf("Done. Received signature data from %d participants", ended)
              R := parties[0].temp.r

              // BEGIN check s correctness
              sumS := parties[0].temp.si
              for i, p := range parties {
                  if i == 0 {
                      continue
                  }

                  var tmpSumS [32]byte
                  edwards25519.ScMulAdd(&tmpSumS, sumS, bigIntToEncodedBytes(big.NewInt(1)), p.temp.si)
                  sumS = &tmpSumS
              }
              fmt.Printf("S: %s\n", encodedBytesToBigInt(sumS).String())
              fmt.Printf("R: %s\n", R.String())
              // END check s correctness

              // BEGIN EDDSA verify
              pkX, pkY := keys[0].EDDSAPub.X(), keys[0].EDDSAPub.Y()
              pk := edwards.PublicKey{
                  Curve: tss.Edwards(),
                  X:     pkX,
                  Y:     pkY,
              }
              t.Logf("combine pub key: %s", base58.Encode(pk.Serialize()))

                                 newSig, err := edwards.ParseSignature(parties[0].data.Signature)
              if err != nil {
                  println("new sig error, ", err.Error())
              }

              ok := edwards.Verify(&pk, msg, newSig.R, newSig.S)
              assert.True(t, ok, "eddsa verify must pass")
              t.Log("EDDSA signing test done.")
              // END EDDSA verify

              signingSigBytes := make([]byte, 64)
              copy(signingSigBytes[:32], newSig.R.Bytes())
              copy(signingSigBytes[32:], newSig.S.Bytes())

              signature := solana.SignatureFromBytes(signingSigBytes)
              t.Logf("sign sig: %s", signature)
              tx.Signatures = append(tx.Signatures, signature)
              err = tx.VerifySignatures()
              if err != nil {
                  panic(err)
              }

Test it with VerifySignatures() function, but got the transaction signature failed panic: invalid signature by FKAAiwGD73AWgW6WhETAqvuoqHjLLbibSwiSJfU1qt5r

How can I fix it? Thanks.

Did you solve this?

web3rover commented 9 months ago

You should pass Signature from SignatureData end channel to solana. SignatureFromBytes directly. No need of signingSigBytes