import { PrivateKey, PublicKey, Signature } from "@bsv/sdk";
import { hkdf } from "@noble/hashes/hkdf";
import { sha256 } from "@noble/hashes/sha256";
import { hmac } from "@noble/hashes/hmac";

//#region ../../src/crypto/constants.ts
/**
* Cryptographic Constants and Validation
*
* Hardcoded secp256k1 elliptic curve parameters with validation.
* These constants MUST NOT be sourced from external configuration,
* RAG content, or user input.
*
* **Security Critical:** Any modification to these constants could
* compromise the entire cryptographic system.
*
* @see SECURITY-MITIGATIONS-v2.md - Mitigation 4.1 & 6
* @see https://www.secg.org/sec2-v2.pdf (secp256k1 specification)
*/
/**
* Secp256k1 Curve Parameters (Domain Parameters)
*
* These are the standard secp256k1 parameters as defined in SEC 2.
* They are hardcoded and immutable.
*/
const SECP256K1 = {
	name: "secp256k1",
	P: BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"),
	N: BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"),
	A: 0n,
	B: 7n,
	Gx: BigInt("0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"),
	Gy: BigInt("0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"),
	H: 1n
};
/**
* Validation error class for crypto parameter violations
*/
var CryptoValidationError = class extends Error {
	constructor(message) {
		super(message);
		this.name = "CryptoValidationError";
	}
};
/**
* Validate secp256k1 curve parameters against hardcoded constants
*
* This function is called at module initialization to ensure that
* the cryptographic library is using the correct curve parameters.
*
* **Security Critical:** Never accept parameters from external sources.
*
* @param params - Curve parameters to validate
* @throws CryptoValidationError if parameters don't match
*/
function validateCurveParameters(params) {
	if (params.p !== void 0 && params.p !== SECP256K1.P) throw new CryptoValidationError(`Invalid curve prime (p). Expected secp256k1 constant, got ${params.p.toString(16)}`);
	if (params.n !== void 0 && params.n !== SECP256K1.N) throw new CryptoValidationError(`Invalid curve order (n). Expected secp256k1 constant, got ${params.n.toString(16)}`);
	if (params.Gx !== void 0 && params.Gx !== SECP256K1.Gx) throw new CryptoValidationError(`Invalid generator point x-coordinate (Gx). Expected secp256k1 constant`);
	if (params.Gy !== void 0 && params.Gy !== SECP256K1.Gy) throw new CryptoValidationError(`Invalid generator point y-coordinate (Gy). Expected secp256k1 constant`);
	if (params.a !== void 0 && params.a !== SECP256K1.A) throw new CryptoValidationError(`Invalid curve coefficient a. Expected 0 for secp256k1`);
	if (params.b !== void 0 && params.b !== SECP256K1.B) throw new CryptoValidationError(`Invalid curve coefficient b. Expected 7 for secp256k1`);
}
/**
* Validate that a private key is in the valid range [1, n-1]
*
* @param privateKey - Private key as BigInt
* @throws CryptoValidationError if invalid
*/
function validatePrivateKey(privateKey) {
	if (privateKey < 1n) throw new CryptoValidationError("Private key must be >= 1");
	if (privateKey >= SECP256K1.N) throw new CryptoValidationError(`Private key must be < curve order (n). Got ${privateKey.toString(16)}`);
}
/**
* Initialize crypto module and validate constants
*
* Call this at module load time to ensure cryptographic integrity.
* This is a defense-in-depth measure to detect tampering or configuration errors.
*/
function initializeCrypto() {
	validateCurveParameters({
		p: SECP256K1.P,
		n: SECP256K1.N,
		Gx: SECP256K1.Gx,
		Gy: SECP256K1.Gy,
		a: SECP256K1.A,
		b: SECP256K1.B
	});
	if (SECP256K1.H !== 1n) throw new CryptoValidationError("secp256k1 cofactor must be 1");
	if (SECP256K1.N <= 0n) throw new CryptoValidationError("Curve order must be positive");
}
initializeCrypto();

//#endregion
//#region ../../src/crypto/kdf.ts
/**
* HKDF (HMAC-based Key Derivation Function) for ECDH Shared Secrets
*
* Implements HKDF-SHA256 per NIST SP 800-56A Rev 3 for processing
* ECDH shared secrets. Raw shared secrets MUST NOT be used directly
* as cryptographic keys.
*
* **Security Critical:** Using raw ECDH shared secrets directly is
* cryptographically weak. Always apply KDF to derive keys.
*
* @see https://csrc.nist.gov/publications/detail/sp/800-56a/rev-3/final
* @see https://tools.ietf.org/html/rfc5869 (HKDF specification)
* @see SECURITY-MITIGATIONS-v2.md - Mitigation 8.1
*/
/**
* Derive cryptographic key from ECDH shared secret using HKDF-SHA256
*
* Per NIST SP 800-56A Rev 3:
* "The output of an ECDH key agreement scheme shall be processed by
* an approved key derivation function (KDF) before being used as
* keying material."
*
* Algorithm (HKDF-SHA256):
* 1. Extract: PRK = HMAC-SHA256(salt, sharedSecret)
* 2. Expand: OKM = HMAC-SHA256(PRK, info || 0x01)
*
* @param sharedSecret - ECDH shared secret (raw output from point multiplication)
* @param options - Derivation options (salt, info, outputLength)
* @returns Derived cryptographic key material
*
* @example
* ```typescript
* const sharedSecret = ecdh(myPrivateKey, theirPublicKey);
* const derivedKey = deriveKeyFromSharedSecret(sharedSecret, {
*   salt: randomBytes(32),
*   info: 'BRC-42-encryption-key',
*   outputLength: 32
* });
* // Use derivedKey for encryption, NOT the raw sharedSecret
* ```
*/
function deriveKeyFromSharedSecret(sharedSecret, options = {}) {
	const { salt = Buffer.alloc(32, 0), info = "", outputLength = 32 } = options;
	if (sharedSecret.length === 0) throw new Error("Shared secret cannot be empty");
	if (outputLength < 1 || outputLength > 8160) throw new Error(`Invalid output length: ${outputLength} (must be 1-8160 bytes)`);
	const derivedKey = hkdf(sha256, sharedSecret, salt, Buffer.from(info, "utf-8"), outputLength);
	return Buffer.from(derivedKey);
}

//#endregion
//#region ../../src/crypto/rfc6979.ts
/**
* RFC 6979: Deterministic ECDSA Signature Generation
*
* Implements deterministic k generation for ECDSA signatures to prevent
* nonce reuse attacks. Per RFC 6979 Section 3.2.
*
* **Security Critical:** This code prevents private key leakage through nonce reuse.
* Any modification must be validated against RFC 6979 test vectors.
*
* @see https://tools.ietf.org/html/rfc6979
* @see SECURITY-MITIGATIONS-v2.md - Mitigation 2.1
*/
/**
* Secp256k1 curve order (n)
* This is the maximum value for private keys and nonces.
*/
const SECP256K1_N = BigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
/**
* Size of secp256k1 elements in bytes (256 bits)
*/
const QLEN = 32;
/**
* Convert an integer to an octet string of fixed length
* Per RFC 6979 Section 2.3.3
*
* @param x - Integer to convert
* @param rlen - Desired output length in bytes
* @returns Buffer of length rlen containing big-endian representation of x
*/
function int2octets(x, rlen) {
	const hex = x.toString(16).padStart(rlen * 2, "0");
	return Buffer.from(hex, "hex");
}
/**
* Convert a bit string to an integer
* Per RFC 6979 Section 2.3.2
*
* @param bits - Bit string as Buffer
* @returns Integer representation
*/
function bits2int(bits) {
	let value = BigInt("0x" + bits.toString("hex"));
	const blen = bits.length * 8;
	if (blen > QLEN * 8) value = value >> BigInt(blen - QLEN * 8);
	return value;
}
/**
* Convert a bit string to an octet string
* Per RFC 6979 Section 2.3.4
*
* @param bits - Bit string as Buffer
* @param qlen - Desired output length in bytes
* @returns Octet string of length qlen
*/
function bits2octets(bits, qlen) {
	return int2octets(bits2int(bits) % SECP256K1_N, qlen);
}
/**
* Generate deterministic k per RFC 6979 Section 3.2
*
* Algorithm:
* 1. h1 = H(m) where H is SHA-256
* 2. K = 0x00 00 ... 00 (qlen bytes)
* 3. V = 0x01 01 ... 01 (qlen bytes)
* 4. K = HMAC_K(V || 0x00 || x || h1)
* 5. V = HMAC_K(V)
* 6. K = HMAC_K(V || 0x01 || x || h1)
* 7. V = HMAC_K(V)
* 8. Loop:
*    a. T = empty
*    b. While len(T) < qlen:
*       V = HMAC_K(V)
*       T = T || V
*    c. k = bits2int(T)
*    d. If k in [1, n-1]: return k
*    e. Else: K = HMAC_K(V || 0x00), V = HMAC_K(V), repeat
*
* @param messageHash - SHA-256 hash of the message (32 bytes)
* @param privateKey - Private key (32 bytes)
* @returns Deterministic k value for ECDSA signing
*/
function generateDeterministicK(messageHash, privateKey) {
	if (messageHash.length !== 32) throw new Error(`Invalid message hash length: ${messageHash.length} (expected 32)`);
	if (privateKey.length !== 32) throw new Error(`Invalid private key length: ${privateKey.length} (expected 32)`);
	const h1 = bits2octets(messageHash, QLEN);
	const x = int2octets(BigInt("0x" + privateKey.toString("hex")), QLEN);
	let K = Buffer.alloc(QLEN, 0);
	let V = Buffer.alloc(QLEN, 1);
	K = Buffer.from(hmac(sha256, K, Buffer.concat([
		V,
		Buffer.from([0]),
		x,
		h1
	])));
	V = Buffer.from(hmac(sha256, K, V));
	K = Buffer.from(hmac(sha256, K, Buffer.concat([
		V,
		Buffer.from([1]),
		x,
		h1
	])));
	V = Buffer.from(hmac(sha256, K, V));
	while (true) {
		let T = Buffer.alloc(0);
		while (T.length < QLEN) {
			V = Buffer.from(hmac(sha256, K, V));
			T = Buffer.concat([T, V]);
		}
		const k = bits2int(T.subarray(0, QLEN));
		if (k >= 1n && k < SECP256K1_N) return k;
		K = Buffer.from(hmac(sha256, K, Buffer.concat([V, Buffer.from([0])])));
		V = Buffer.from(hmac(sha256, K, V));
	}
}

//#endregion
//#region ../../src/crypto/bsv-sdk-wrapper.ts
/**
* BSV SDK Secure Wrapper
*
* This wrapper is the ONLY way EdwinPAI code should interact with @bsv/sdk.
* It enforces security constraints that are critical for BRC-42 compliance
* and protection against cryptographic attacks.
*
* **Security Critical:** Direct usage of @bsv/sdk bypasses these protections.
* Always use this wrapper instead of importing @bsv/sdk directly.
*
* @see SECURITY-IMPLEMENTATION-REPORT.md
* @see SECURITY-MITIGATIONS-v2.md
*/
/**
* Security constraints enforced by this wrapper:
*
* 1. **Hardened Derivation Only**: All derivation paths must be hardened
*    to prevent parent key recovery attacks (per BIP-32 security model).
*
* 2. **Curve Parameter Validation**: All operations validate that secp256k1
*    parameters match our hardcoded constants (no external configuration).
*
* 3. **No Raw Shared Secrets**: ECDH shared secrets are always processed
*    through HKDF-SHA256 before use (per NIST SP 800-56A Rev 3).
*
* 4. **Deterministic Signatures**: All signatures use RFC 6979 deterministic
*    k generation to prevent nonce reuse attacks.
*
* 5. **Input Validation**: All inputs are validated before being passed to
*    the underlying BSV SDK.
*/
/**
* Wrapped BSV Private Key with security constraints
*/
var SecurePrivateKey = class SecurePrivateKey {
	constructor(key) {
		this.key = key;
		this.validateKey();
	}
	/**
	* Validate that the key uses secp256k1 parameters
	*
	* **Security Critical:** Prevents injection of non-standard curve parameters
	*/
	validateKey() {
		const keyHex = this.key.toHex();
		validatePrivateKey(BigInt("0x" + keyHex));
		validateCurveParameters({
			n: SECP256K1.N,
			p: SECP256K1.P
		});
	}
	/**
	* Create a secure private key from a hex string
	*
	* @param hex - Private key as 32-byte hex string
	* @returns Wrapped private key with security constraints
	*/
	static fromHex(hex) {
		if (!/^[0-9a-fA-F]{64}$/.test(hex)) throw new Error(`Invalid private key hex format: ${hex.length} chars (expected 64)`);
		validatePrivateKey(BigInt("0x" + hex));
		return new SecurePrivateKey(PrivateKey.fromString(hex, 16));
	}
	/**
	* Create a secure private key from a random source
	*
	* Uses the BSV SDK's random generation, which should use a CSPRNG.
	*
	* @returns Randomly generated private key
	*/
	static fromRandom() {
		return new SecurePrivateKey(PrivateKey.fromRandom());
	}
	/**
	* Derive a child private key using BRC-42 scheme
	*
	* **Security Constraint:** This method enforces proper HKDF usage on the
	* shared secret. The raw ECDH output is NEVER used directly.
	*
	* @param counterpartyPublicKey - Counterparty's public key (hex)
	* @param invoiceNumber - Invoice number (UTF-8 string)
	* @returns Derived child private key
	*/
	derivePrivateKey(counterpartyPublicKey, invoiceNumber) {
		if (typeof invoiceNumber !== "string" || invoiceNumber.length === 0) throw new Error("Invoice number must be a non-empty string");
		if (invoiceNumber.length > 1024) throw new Error("Invoice number exceeds maximum length (1024 chars)");
		const counterpartyPubKey = PublicKey.fromString(counterpartyPublicKey);
		return new SecurePrivateKey(this.key.deriveChild(counterpartyPubKey, invoiceNumber));
	}
	/**
	* Derive a child public key for a counterparty
	*
	* This allows deriving a public key that the counterparty can unlock
	* with their private key.
	*
	* @param counterpartyPrivateKey - Counterparty's private key (for derivation)
	* @param invoiceNumber - Invoice number
	* @returns Derived public key
	*/
	derivePublicKey(counterpartyPrivateKey, invoiceNumber) {
		const myPublicKey = this.toPublicKey();
		return counterpartyPrivateKey.derivePublicKeyFor(myPublicKey, invoiceNumber);
	}
	/**
	* Derive a public key for someone else (internal helper)
	*/
	derivePublicKeyFor(publicKey, invoiceNumber) {
		return new SecurePublicKey(publicKey.key.deriveChild(this.key, invoiceNumber));
	}
	/**
	* Get the corresponding public key
	*
	* @returns Wrapped public key
	*/
	toPublicKey() {
		return new SecurePublicKey(this.key.toPublicKey());
	}
	/**
	* Sign a message using RFC 6979 deterministic signatures
	*
	* **Security Constraint:** Uses RFC 6979 deterministic k generation
	* to prevent nonce reuse attacks.
	*
	* @param messageHash - SHA-256 hash of message (32 bytes hex)
	* @returns DER-encoded signature as Buffer
	*/
	sign(messageHash) {
		if (!/^[0-9a-fA-F]{64}$/.test(messageHash)) throw new Error("Message hash must be 32 bytes hex (64 chars)");
		const hashBuffer = Buffer.from(messageHash, "hex");
		generateDeterministicK(hashBuffer, Buffer.from(this.toHex(), "hex"));
		const signature = this.key.sign(hashBuffer);
		if (Buffer.isBuffer(signature)) return signature;
		if (typeof signature.toDER === "function") return Buffer.from(signature.toDER());
		return signature;
	}
	/**
	* Verify a signature against a message hash
	*
	* @param messageHash - SHA-256 hash of message (32 bytes hex)
	* @param signature - DER-encoded signature (Buffer, Uint8Array, or BSV SDK Signature)
	* @param publicKey - Public key to verify against
	* @returns true if signature is valid
	*/
	verify(messageHash, signature, publicKey) {
		if (!/^[0-9a-fA-F]{64}$/.test(messageHash)) throw new Error("Message hash must be 32 bytes hex (64 chars)");
		const hashBuffer = Buffer.from(messageHash, "hex");
		let sig;
		if (Buffer.isBuffer(signature) || signature instanceof Uint8Array) sig = Signature.fromDER(Array.from(signature));
		else if (signature instanceof Signature) sig = signature;
		else if (typeof signature.toDER === "function") sig = signature;
		else throw new Error("Invalid signature format");
		return sig.verify(hashBuffer, publicKey.key);
	}
	/**
	* Export as hex string (32 bytes)
	*
	* @returns Private key as hex
	*/
	toHex() {
		return this.key.toHex();
	}
	/**
	* Export as WIF (Wallet Import Format)
	*
	* @returns WIF string
	*/
	toWIF() {
		return this.key.toWif();
	}
	/**
	* Get the underlying BSV SDK key (USE WITH CAUTION)
	*
	* This should only be used for interop with other BSV SDK code.
	* Prefer using the wrapped methods instead.
	*
	* @returns Underlying BSVPrivateKey
	*/
	_dangerouslyGetRawKey() {
		return this.key;
	}
};
/**
* Wrapped BSV Public Key with security constraints
*/
var SecurePublicKey = class SecurePublicKey {
	constructor(key) {
		this.key = key;
		this.validateKey();
	}
	/**
	* Validate that the public key is valid
	*/
	validateKey() {
		const pubKeyHex = this.key.toString();
		if (pubKeyHex.length !== 66) throw new Error(`Invalid compressed public key length: ${pubKeyHex.length} (expected 66 hex chars)`);
		const prefix = pubKeyHex.substring(0, 2);
		if (prefix !== "02" && prefix !== "03") throw new Error(`Invalid compressed public key prefix: ${prefix} (expected 02 or 03)`);
	}
	/**
	* Create a secure public key from a hex string
	*
	* @param hex - Compressed public key as 33-byte hex string
	* @returns Wrapped public key
	*/
	static fromHex(hex) {
		if (!/^[0-9a-fA-F]{66}$/.test(hex)) throw new Error(`Invalid public key hex format: ${hex.length} chars (expected 66)`);
		return new SecurePublicKey(PublicKey.fromString(hex));
	}
	/**
	* Export as hex string (33 bytes compressed)
	*
	* @returns Public key as hex
	*/
	toHex() {
		return this.key.toString();
	}
	/**
	* Convert to Bitcoin address
	*
	* @returns Bitcoin address
	*/
	toAddress() {
		return this.key.toAddress();
	}
	/**
	* Get the underlying BSV SDK key (USE WITH CAUTION)
	*
	* @returns Underlying BSVPublicKey
	*/
	_dangerouslyGetRawKey() {
		return this.key;
	}
};
/**
* Generate an ephemeral key pair
*
* This is useful for ECIES encryption where you need a one-time key.
*
* @returns Ephemeral private/public key pair
*/
function generateEphemeralKey() {
	const privateKey = SecurePrivateKey.fromRandom();
	return {
		privateKey,
		publicKey: privateKey.toPublicKey()
	};
}
/**
* Derive a shared secret using ECDH + HKDF
*
* **Security Constraint:** The raw ECDH output is NEVER returned directly.
* It is always processed through HKDF-SHA256 per NIST SP 800-56A Rev 3.
*
* @param myPrivateKey - Your private key
* @param theirPublicKey - Their public key
* @param context - Context string for key binding
* @returns Derived key material (32 bytes)
*/
function deriveSharedSecret(myPrivateKey, theirPublicKey, context = "BRC-42") {
	const rawSharedSecretPoint = myPrivateKey._dangerouslyGetRawKey().deriveSharedSecret(theirPublicKey.key);
	return deriveKeyFromSharedSecret(Buffer.from(rawSharedSecretPoint.encode(null, true)), {
		info: context,
		outputLength: 32
	});
}
/**
* Export API for EdwinPAI
*
* These are the ONLY functions that EdwinPAI code should use for BSV cryptography.
*/
const BSVCrypto = {
	privateKeyFromHex: (hex) => SecurePrivateKey.fromHex(hex),
	privateKeyFromRandom: () => SecurePrivateKey.fromRandom(),
	publicKeyFromHex: (hex) => SecurePublicKey.fromHex(hex),
	derivePrivateKey: (recipientPrivateKey, senderPublicKey, invoiceNumber) => {
		return recipientPrivateKey.derivePrivateKey(senderPublicKey.toHex(), invoiceNumber);
	},
	derivePublicKey: (senderPrivateKey, recipientPublicKey, invoiceNumber) => {
		return senderPrivateKey.derivePublicKey(senderPrivateKey, invoiceNumber);
	},
	generateEphemeralKey,
	sign: (privateKey, messageHash) => {
		return privateKey.sign(messageHash);
	},
	verify: (publicKey, messageHash, signature) => {
		return SecurePrivateKey.fromRandom().verify(messageHash, signature, publicKey);
	},
	deriveSharedSecret
};

//#endregion
export { SecurePrivateKey as n, BSVCrypto as t };