> ## Documentation Index
> Fetch the complete documentation index at: https://transfiya.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Cómo crear llaves y firmas offline

> Guia para generar las llaves y poder firmar las peticiones offline

Las entidades bancarias son responsables de almacenar y gestionar sus propios **Keepers**.

Los **Keepers** se utilizan para generar **Signers** y firmar **Actions** de forma offline.

Una vez firmado, el **Action** debe enviarse al núcleo de TIN Cloud utilizando el endpoint:

**POST /v1/action/:action\_id/sendit**

* Si el **Action** firmado es aceptado por TIN Cloud, recibirá `labels.status: COMPLETED` y un valor en `labels.hash`.
* Si es rechazado, el estado será `labels.status: REJECTED` y `labels.hash` tendrá el valor `none`.

<Recommendation>
  **Recomendación:** Guarda localmente la relación entre Keeper, Signer, Wallet y la cuenta bancaria del usuario. Un esquema sugerido es:

  `public`, `secret`, `signer`, `wallet`, `phone`, `bank account reference`
</Recommendation>

### Firmar Action offline

Los **Keepers** deben cargarse desde el sistema de gestión de llaves (KMS) antes de firmar un **Action**.

Para firmar un **Action**, necesitas su `action_id` y el **Keeper** correspondiente a `Action.source`.

💻 Código de ejemplo en Java

```code theme={null}
import java.security.MessageDigest;
import java.security.Signature;

import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.Utils;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;

public class SignatureUtil {
    public static String OfflineSigning(String claimsHash, String secretKey) {
        try {
            // Convert private key to EdDSAPrivateKey
            EdDSANamedCurveSpec ed25519 = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
            EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(Utils.hexToBytes(secretKey), ed25519);
            EdDSAPrivateKey privateKey = new EdDSAPrivateKey(keySpec);

            // Sign the hash
            EdDSAParameterSpec spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
            Signature sgr = new EdDSAEngine(MessageDigest.getInstance(spec.getHashAlgorithm()));
            sgr.initSign(privateKey);
            sgr.update(Utils.hexToBytes(claimsHash));
            byte[] signature = sgr.sign();

            // Convert signature to hex string
            return Utils.bytesToHex(signature);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
```

```code theme={null}
package minka.crypto.dtos;

import java.security.KeyPair;

import net.i2p.crypto.eddsa.KeyPairGenerator;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.Utils;

public class KeeperDto {
    private String publicKey;
    private String secretKey;
    private String scheme = "eddsa-ed25519";

    public KeeperDto(String publicKey, String secretKey) {
        this.publicKey = publicKey;
        this.secretKey = secretKey;
    }

    public static KeeperDto GenerateKeys() {
        KeyPairGenerator keyPairGenerator = new KeyPairGenerator();
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        EdDSAPublicKey publicKey = (EdDSAPublicKey) keyPair.getPublic();
        EdDSAPrivateKey secretKey = (EdDSAPrivateKey) keyPair.getPrivate();

        String publicKeyHexStr = Utils.bytesToHex(publicKey.getA().toByteArray());
        String secretKeyHexStr = Utils.bytesToHex(secretKey.getSeed());

        return new KeeperDto(publicKeyHexStr, secretKeyHexStr);
    }
}
```

## Ejemplo C#\#

```code theme={null}
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Utilities.Encoders;

namespace Keeper {
    public class SignatureDto
    {
        private List<Signatures> signatures;

        public SignatureDto(HashDto hashDto, string address, string publicKey, string secretKey)
        {
            var decodedPrivateBytes = Hex.Decode(secretKey);
            var ed25519PrivateKeyParameters = new Ed25519PrivateKeyParameters(decodedPrivateBytes, 0);

            var ed25519Signer = new Ed25519Signer();
            ed25519Signer.Init(true, ed25519PrivateKeyParameters);
            byte[] msg = Hex.Decode(hashDto.Value);
            ed25519Signer.BlockUpdate(msg, 0, msg.Length);
            var signature = ed25519Signer.GenerateSignature();
            var signatureHexString = Hex.ToHexString(signature);

            List<Signatures> theSignatures = new List<Signatures>();
            Signatures oneSignature = new Signatures();
            oneSignature.Scheme = "eddsa-ed25519";
            oneSignature.String = signatureHexString;
            oneSignature.Signer = address;
            oneSignature.Public = publicKey;

            theSignatures.Add(oneSignature);
            this.signatures = theSignatures;
        }

        public List<Signatures> Signatures
        {
            get => signatures;
            set => signatures = value;
        }
    }
}
```

## Ejemplo Node JSON

```code theme={null}
const crypto = require('crypto')
const elliptic = require('elliptic')
const eddsa25519 = new elliptic.eddsa('ed25519')

const getClaims = () => {
  const date = new Date()
  return {
    source: 'source-address',
    symbol: 'symbol-address',
    target: 'target-address',
    amount: '1000',
    domain: 'tin',
    expiry: date.toISOString(),
  }
}

function signIOU(claims, privateKey) {
  let eddsaKeyPair = eddsa25519.keyFromSecret(privateKey)
  let signature = eddsaKeyPair.sign(claims)
  return signature.toHex()
}
```
