cardano-serialization-lib icon indicating copy to clipboard operation
cardano-serialization-lib copied to clipboard

User has accepted the transaction sign, but the wallet was unable to sign the transaction (e.g. not having some of the private keys).

Open eric248550 opened this issue 3 years ago • 10 comments

Currently, we want to sign the transaction(mint) with Nami wallet while using below function

const t = await nami.transaction({
            PaymentAddress: myAddress,
            recipients: recipients,
            metadata: metadataTransaction,
            utxosRaw: utxos,
            networkId: netId.id,
            ttl: 3600,
            multiSig: null
        })
setBuiltTransaction(t)
const signature = await nami.signTx(t)

but get the error

{
    "code": 1,
    "info": "User has accepted the transaction sign, but the wallet was unable to sign the transaction (e.g. not having some of the private keys)."
}

I used Cardano CLI to generate the standard "script, vkey, skey" files below(testnet)

{
    "type": "PaymentSigningKeyShelley_ed25519",
    "description": "Payment Signing Key",
    "cborHex": "582009d11fd26816c747afec7c80ca775490d3b91d0ef8d6c4dee963219ec1fed3c1"
}
{
    "type": "PaymentVerificationKeyShelley_ed25519",
    "description": "Payment Verification Key",
    "cborHex": "58206aa1c3467689f995a884b8792968e23edd5a8ac46f8409cd6e249e0dd8f3cfa3"
}

Is there any way to convert "vkey, skey" to createNewBech32PrivateKey()

eric248550 avatar Jan 14 '22 08:01 eric248550

I'm not sure what exactly is being asked here, but I'm also not familiar with all the functionality nami exposes(nami.transaction). If you parse the bytes out of those cborHex fields you can create PrivateKey and PublicKey objects using cardano-serialization-lib if that helps. You won't be able to directly use PublicKey::from_bytes() as that doesn't expect CBOR but instead just the raw bytes of the key. For example with 582009d11fd26816c747afec7c80ca775490d3b91d0ef8d6c4dee963219ec1fed3c1 you have 5820 being the CBOR bytestring tag + length and 09d11fd26816c747afec7c80ca775490d3b91d0ef8d6c4dee963219ec1fed3c1 is the actual bytes of the key.

The error you're getting back from the CIP-30 tx sign endpoint in nami.signTx() sounds like it was unable to sign for one or more of credentials required in the tx. This sounds like it might be better to open the issue there instead of here if you're giving it a transaction that you are sure it should be able to sign.

rooooooooob avatar Jan 15 '22 02:01 rooooooooob

@rooooooooob Thank you for your great help, To be more specific, I want to know how to convert cborHex(e.g. 582009d11fd26816c747afec7c80ca775490d3b91d0ef8d6c4dee963219ec1fed3c1 ) to bech32 format(e.g. xprv1wqf6xk9fym8u99qk8ec5l3khk7q4ed00d6ftvz59q6tju6vsgetpnvy0lcmyqdmrah8qj6yrmh0zygzn8smx8zuk6rh8te3248dun8dal8vjzjxj84v4dkx85m0k3lmas40n3n08yv5t9pp7jzgfxyvz4vh6j3e7)

I found the function S.Bip32PrivateKey.from_bip39_entropy() , it convert to bech32 privateKey, but not sure will that be any problem?

skeyToPrivateKey(){
        const privateKey = S.Bip32PrivateKey.from_bip39_entropy(
            Buffer.from('09d11fd26816c747afec7c80ca775490d3b91d0ef8d6c4dee963219ec1fed3c1', 'hex'),
            Buffer.from('')
        )
        return privateKey.to_bech32()
    }```

eric248550 avatar Jan 16 '22 16:01 eric248550

To be more specific, I want to know how to convert cborHex(e.g. 582009d11fd26816c747afec7c80ca775490d3b91d0ef8d6c4dee963219ec1fed3c1 ) to bech32 format(e.g. xprv1wqf6xk9fym8u99qk8ec5l3khk7q4ed00d6ftvz59q6tju6vsgetpnvy0lcmyqdmrah8qj6yrmh0zygzn8smx8zuk6rh8te3248dun8dal8vjzjxj84v4dkx85m0k3lmas40n3n08yv5t9pp7jzgfxyvz4vh6j3e7)

As I meantioned you'll have to extract the bytestring from within that CBOR which in the above case is just stripping those first few bytes but that's hacky since it's theoretically possible they could instead of encoding it as BYTES(32) || bytes, they could encode it as BYTES(indefinite) || bytes || BREAK using indefinite encoding. So ideally you'd want to actually parse the CBOR then use just bytes but just as a hacky workaround for now if that's not possible you could just strip those first 4 characters but that's not recommended outside of just playing around/testing.

Once you have those bytes just pass it to PublicKey::from_bytes() then call to_bech32() on it. For PrivateKey you'll use either from_extended_bytes() or from_normal_bytes()

rooooooooob avatar Jan 17 '22 19:01 rooooooooob

@rooooooooob Still have not figured out the format relationship. According to the key example: https://github.com/Emurgo/cardano-serialization-lib/blob/master/doc/getting-started/generating-keys.md I want to generate "rootkey" from "skey" and "vkey", From my test, If I just use from_normal_bytes() and expected to get rootkey is not equal

S.PrivateKey.from_normal_bytes(Buffer.from(sKey, "hex")

is equal to

accountKey.derive(0).derive(0).to_raw_key()

eric248550 avatar Jan 23 '22 12:01 eric248550

@rooooooooob Still have not figured out the format relationship. According to the key example: https://github.com/Emurgo/cardano-serialization-lib/blob/master/doc/getting-started/generating-keys.md I want to generate "rootkey" from "skey" and "vkey", From my test, If I just use from_normal_bytes() and expected to get rootkey is not equal

S.PrivateKey.from_normal_bytes(Buffer.from(sKey, "hex")

is equal to

accountKey.derive(0).derive(0).to_raw_key()

Sorry @eric248550. I think we have a slightly different use case but I'm still struggling. I want to use skey and vkey to construct a transaction with the cardano serialisation library. I am unsure how to convert these. I do not have a .script file.

benjichat avatar Jan 23 '22 12:01 benjichat

@eric248550

I want to generate "rootkey" from "skey" and "vkey",

Could you give a bit more info about what you mean by rootKey? Are you referring to the docs? What are you trying to get rootKey for? If you're talking about the root key from derived keys, it's not possible in the general case (see: hardened derivations). I suggest reading up on bip32 HD wallets if that's where the confusion is from. In those docs you go the other way around, rootKey(bip32) -> the derived keys. There are two key types: BIP*Key and Key in the library. The BIPKey types contain additional chain information following bip32, and you must call to_raw_key() to convert to the regular keys if you want to hash/sign/etc with them.

Is there any way to convert "vkey, skey" to createNewBech32PrivateKey()

Are you looking for something like Bip32PublicKey::from_raw_and_chain(key: &PublicKey, chaincode: Vec<u8>) -> Result<Self, JsError>? We don't provide that functionality if that's what you were looking for. You could however try and use (I haven't tried this) Bip32PublicKey::from_bytes() and append the chaincode so you'd pass in a 96-byte bytestring with the first 64 bytes being the bytes of PublicKey and the next 32-byte being the chaincode information. You would need to use the chain-code information that came originally from Bip32PublicKey::chaincode(). I am not sure if those 32 bytes are only storing the chaincode e.g. if Bip32PublicKey::generate_ed25519_bip32().derive(1).derive(2).derive(3).chaincode() is always the same, or if there's some other crypto stuff going on involving incorporating the root key itself or what.

@benjichat

I want to use skey and vkey to construct a transaction with the cardano serialisation library. I am unsure how to convert these. I do not have a .script file.

What format do you have skey/vkey in?

rooooooooob avatar Feb 08 '22 00:02 rooooooooob

Hi @eric248550 again. Looks like we are trying to solve the same thing. I tried your suggested:

skeyToPrivateKey(){
        const privateKey = S.Bip32PrivateKey.from_bip39_entropy(
            Buffer.from('SKEY_cborHex', 'hex'),
            Buffer.from('')
        )
        return privateKey.to_bech32()
}

It didn't had any error, I don't think this is correct as the input should be key phrases right?

I also tried:

let PrivateKey = S.PrivateKey.from_normal_bytes(cbor.decode('SKEY_cborHex'));
let Bip32PrivateKey = S.Bip32PrivateKey.from_bytes(PrivateKey.as_bytes())

It complains:

>  e Invalid Secret Key size

SKEY_cborHex is in this format (do not use this key, just a sample):

582099n3n930d9n31b5b102h3vd9csa290c14e0898sn1d278f1939f3e4bed890675a

Taken from the skey file generated by cardano-cli:

{
    "type": "PaymentSigningKeyShelley_ed25519",
    "description": "Payment Signing Key",
    "cborHex": "582099n3n930d9n31b5b102h3vd9csa290c14e0898sn1d278f1939f3e4bed890675a"
}

@rooooooooob, thanks a lot of answering all the questions that's is in this repo, but I can't understand what you're saying =(

More info

Keys created via this method: https://developers.cardano.org/docs/stake-pool-course/handbook/keys-addresses/#payment-key-pair:

cardano-cli address key-gen \
    --verification-key-file payment.vkey \
    --signing-key-file payment.skey

Policy created via this method: https://developers.cardano.org/docs/native-tokens/minting#minting-native-assets

Main objective:

How to load these keys and policy script, into cardano-serialization-lib NodeJs?

jinglescode avatar Apr 02 '22 06:04 jinglescode

Hey, was this issue resolved? I am currently trying to do the same thing.

erickjavalos avatar Apr 11 '22 23:04 erickjavalos

Using cardano-serialization-lib and 'cbor' library you can create locking policy script like this

      // use the api to get epoch parameter     
      const slot = protocolParameters.slot 
      const ttl = slot + 2000
      // get the prvKey from the signing key
      const prvkey = Loader.Cardano.PrivateKey.from_normal_bytes(
        cbor.decodeFirstSync(
          '582099n3n930d9n31b5b102h3vd9csa290c14e0898sn1d278f1939f3e4bed890675a'
        )
      )
      const nativeScripts = Loader.Cardano.NativeScripts.new()
      const script = Loader.Cardano.ScriptPubkey.new(prvkey.to_public().hash())
      console.log(script.addr_keyhash().toString())
      const nativeScript = Loader.Cardano.NativeScript.new_script_pubkey(script)
      const lockScript = Loader.Cardano.NativeScript.new_timelock_expiry(
        this.lib.TimelockExpiry.new(ttl)
      )
      nativeScripts.add(nativeScript)
      nativeScripts.add(lockScript)
      const finalScript = Loader.Cardano.NativeScript.new_script_all(
        this.lib.ScriptAll.new(nativeScripts)
      )
      const policyId = Buffer.from(
        Loader.Cardano.ScriptHash.from_bytes(finalScript.hash().to_bytes()).to_bytes()
      ).toString('hex')
      // then you  return { id: policyId, script: finalScript, ttl }

HT-Moh avatar Nov 17 '22 00:11 HT-Moh

Load CLI generated keys into cardano-serialization-lib:

import { AppWallet } from '@martifylabs/mesh';
import { KoiosProvider } from '@martifylabs/mesh';

const blockchainProvider = new KoiosProvider('<api,testnet,guild>');

const wallet = new AppWallet({
  networkId: 0,
  fetcher: blockchainProvider,
  submitter: blockchainProvider,
  key: {
    type: 'cli',
    payment: '5820aaca553a7b95b38b5d9b82a5daa7a27ac8e34f3cf27152a978f4576520dd6503',
    stake: '582097c458f19a3111c3b965220b1bef7d548fd75bc140a7f0a4f080e03cce604f0e',
  },
});

See Mesh docs. It works! With the wallet, you can do anything with cardano-serialization-lib on web app or node backend.

jinglescode avatar Nov 17 '22 02:11 jinglescode