'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

var cryptoWasmTs = require('@docknetwork/crypto-wasm-ts');
var b58 = require('bs58');
var stringify = require('json-stringify-deterministic');
var utils_inheritance = require('../../../utils/inheritance.cjs');
var vc_crypto_common_CustomLinkedDataSignature = require('./CustomLinkedDataSignature.cjs');
var vc_crypto_common_DockCryptoSignature = require('./DockCryptoSignature.cjs');
require('../../../utils/types/object.cjs');
require('../../../utils/types/iterable.cjs');
require('../../../utils/types/set.cjs');
require('jsonld-signatures');
require('base64url');
require('jsonld');
require('../../../types/did/document/verification-method-ref.cjs');
require('../../../types/generic/typed-enum.cjs');
require('../../../utils/types/array.cjs');
require('crypto');
require('../../../utils/interfaces.cjs');
require('../../../utils/assert.cjs');
require('../../../utils/error.cjs');
require('multiformats/bases/base58');
require('varint');
require('../../../utils/encoding/ss-58.cjs');
require('blake2b');
require('../../../utils/types/bytes.cjs');
require('../../../utils/types/string.cjs');
require('../../../types/generic/with-base.cjs');
require('../../../types/generic/with-catch-null.cjs');
require('../../../types/generic/with-eq.cjs');
require('../../../types/generic/any-of.cjs');
require('../../../types/generic/with-from.cjs');
require('../../../types/generic/with-from-json-bytes.cjs');
require('../../../types/generic/typed-null.cjs');
require('../../../types/generic/create-placeholder.cjs');
require('../../../types/generic/typed-bytes.cjs');
require('../../../types/generic/typed-string.cjs');
require('../../../types/generic/typed-array.cjs');
require('../../../types/generic/typed-tuple.cjs');
require('../../../types/generic/typed-number.cjs');
require('../../../types/generic/typed-set.cjs');
require('../../../types/generic/typed-map.cjs');
require('../../../types/generic/typed-struct.cjs');
require('uuid');
require('js-sha256');
require('../../../types/generic/with-qualifier.cjs');
require('../../../types/generic/utils.cjs');
require('../../../types/generic/typed-bytes-array.cjs');
require('../../../types/did/onchain/typed-did/index.cjs');
require('../../../types/did/onchain/typed-did/did-method-key/did-method-key-public-key.cjs');
require('../../../utils/encoding/base-58-btc.cjs');
require('../../../types/generic/sized.cjs');
require('../../../utils/types/number.cjs');
require('../../../types/public-keys/public-key.cjs');
require('../../../types/public-keys/public-key-x25519-value.cjs');
require('../../../types/public-keys/public-key-ed25519-value.cjs');
require('../constants.cjs');
require('../../../types/public-keys/public-key-secp256k1-value.cjs');
require('../../../types/public-keys/public-key-sr25519-value.cjs');
require('../../../types/did/onchain/constants.cjs');
require('../../../types/did/onchain/typed-did/signature.cjs');
require('../../../types/did/onchain/typed-did/did-method-key/did-method-key-signature.cjs');
require('../../../types/signatures/signature-value.cjs');
require('../../../types/signatures/signature-ed25519-value.cjs');
require('../../../types/signatures/signature-secp256k1-value.cjs');
require('../../../types/signatures/signature.cjs');
require('../../../types/signatures/signature-sr25519-value.cjs');
require('../../../types/did/onchain/typed-did/dock-did-value.cjs');
require('../../../types/generic/typed-uuid.cjs');
require('../../../types/did/onchain/typed-did/cheqd-did.cjs');
require('../../jws.cjs');
require('semver/preload.js');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var b58__default = /*#__PURE__*/_interopDefault(b58);
var stringify__default = /*#__PURE__*/_interopDefault(stringify);

const SUITE_CONTEXT_URL = 'https://www.w3.org/2018/credentials/v1';

const DOCK_ANON_CREDENTIAL_ID = 'dock:anonymous:credential';

/**
 * Defines commons for the `@docknetwork/crypto-wasm-ts` signature proofs.
 */
var DockCryptoSignatureProof = utils_inheritance.withExtendedStaticProperties(
  ['Signature', 'proofType', 'sigName'],
  class DockCryptoSignatureProof extends vc_crypto_common_CustomLinkedDataSignature.default {
    /**
     * Default constructor
     * @param options {SignatureSuiteOptions} options for constructing the signature suite
     * @param type
     * @param LDKeyClass
     * @param link
     */
    constructor(options = {}, type, LDKeyClass, link) {
      const { verificationMethod } = options;

      super({
        type,
        LDKeyClass,
        contextUrl: SUITE_CONTEXT_URL,
        alg: type,
        useProofValue: true,
      });

      this.proof = {
        '@context': [
          {
            sec: 'https://w3id.org/security#',
            proof: {
              '@id': 'sec:proof',
              '@type': '@id',
              '@container': '@graph',
            },
          },
          link,
        ],
        type,
      };

      this.verificationMethod = verificationMethod;
      this.accumulatorPublicKeys = options.accumulatorPublicKeys;
      this.predicateParams = options.predicateParams;
      this.circomOutputs = options.circomOutputs;
      this.blindedAttributesCircomOutputs = options.blindedAttributesCircomOutputs;
    }

    async verifyProof({
      proof, document, documentLoader, expansionMap,
    }) {
      try {
        const verificationMethod = await this.getVerificationMethod({
          proof,
          document,
          documentLoader,
          expansionMap,
        });

        const presentationJSON = this.constructor.derivedToAnoncredsPresentation({
          ...document,
          proof,
        });
        const recreatedPres = cryptoWasmTs.Presentation.fromJSON(presentationJSON);

        // NOTE: Another example that this credential derivation doesn't work for presentation with more than 1 credential
        const pks = verificationMethod !== undefined
          ? [verificationMethod].map((keyDocument) => {
            const pkRaw = b58__default.default.decode(keyDocument.publicKeyBase58);
            return new this.constructor.Signature.KeyPair.PublicKey(pkRaw);
          })
          : [];

        const {
          accumulatorPublicKeys,
          predicateParams,
          circomOutputs,
          blindedAttributesCircomOutputs,
        } = this;

        const expectedAccumulatorPKs = accumulatorPublicKeys
          ? new Map()
          : undefined;
        if (accumulatorPublicKeys) {
          const expectedAccumulatorPK = accumulatorPublicKeys.get(
            document?.credentialStatus?.id,
          );
          if (expectedAccumulatorPK) {
            expectedAccumulatorPKs.set(0, expectedAccumulatorPK);
          }
        }

        const res = recreatedPres.verify(
          pks,
          expectedAccumulatorPKs,
          predicateParams,
          circomOutputs,
          blindedAttributesCircomOutputs,
        );
        if (!res.verified) {
          throw new Error(
            `Invalid anoncreds presentation due to error: ${res.error}`,
          );
        }

        return { verified: true, verificationMethod };
      } catch (error) {
        return { verified: false, error };
      }
    }

    /**
     * Converts a derived proof credential to the native presentation format
     * @param document
     */
    static derivedToAnoncredsPresentation(document) {
      const {
        '@context': context,
        type,
        credentialSchema,
        credentialStatus,
        // issuance date isn't revealed in presentations but for W3C style credential or for the frontend, it needs to be
        // present in the derived credential. Popping it out so that it doesn't end up in `revealedAttributes`. Note that this
        // can be a problem when `issuanceDate` is actually revealed which is rare but a possibility
        issuanceDate: _issuanceDate,
        proof,
        ...revealedAttributes
      } = document;

      // Old prover don't reveal the issuer so remove this field from the revealed attributes
      if (proof.presVersion === undefined) {
        delete revealedAttributes.issuer;
      }

      // ID wasnt revealed but placeholder was used to conform to W3C spec, trim it
      if (revealedAttributes.id === DOCK_ANON_CREDENTIAL_ID) {
        delete revealedAttributes.id;
      }

      const credVersion = proof.version;
      const newCredVersion = vc_crypto_common_DockCryptoSignature.isCredVerGte060(credVersion);
      // TODO: This is wrong. This won't work with presentation from 2 or more credentials
      const c = {
        sigType: proof.sigType,
        version: credVersion,
        bounds: proof.bounds,
        schema: newCredVersion
          ? credentialSchema
          : JSON.stringify(credentialSchema),
        revealedAttributes: {
          proof: {
            type: this.sigName,
            verificationMethod: proof.verificationMethod,
          },
          '@context': newCredVersion
            ? stringify__default.default(context)
            : JSON.stringify(context),
          type: newCredVersion ? stringify__default.default(type) : JSON.stringify(type),
          ...revealedAttributes,
        },
      };
      if (credentialStatus !== undefined) {
        c.status = credentialStatus;
      }
      return {
        // Old credentials incorrectly set the presentation version as credential version which was fine because coincidentally
        // both versions were same. Correcting this mistake now. Once all dependents have upgraded and old presentations don't
        // need to be supported, `proof.presVersion` should be used.
        version:
          proof.presVersion !== undefined ? proof.presVersion : proof.version,
        nonce: proof.nonce,
        context: proof.context,
        spec: {
          credentials: [c],
          attributeEqualities: proof.attributeEqualities,
          boundedPseudonyms: proof.boundedPseudonyms,
          unboundedPseudonyms: proof.unboundedPseudonyms,
        },
        attributeCiphertexts: proof.attributeCiphertexts,
        proof: proof.proofValue,
      };
    }

    /**
     * @param document {object} to be signed.
     * @param proof {object}
     * @param documentLoader {function}
     * @param expansionMap {function}
     */
    async getVerificationMethod({ proof, documentLoader }) {
      return this.constructor.Signature.getVerificationMethod({
        proof,
        documentLoader,
      });
    }
  },
);

exports.DOCK_ANON_CREDENTIAL_ID = DOCK_ANON_CREDENTIAL_ID;
exports.default = DockCryptoSignatureProof;
//# sourceMappingURL=DockCryptoSignatureProof.cjs.map
