ltmarx / core /dmqim.ts
harelcain's picture
Upload 37 files
f2f99a3 verified
/**
* Dither-Modulated Quantization Index Modulation (DM-QIM)
*
* Embeds a single bit into a coefficient using quantization.
* The dither value provides key-dependent randomization.
*/
/**
* Embed a single bit into a coefficient using DM-QIM
*
* @param coeff - Original coefficient value
* @param bit - Bit to embed (0 or 1)
* @param delta - Quantization step size
* @param dither - Key-dependent dither value
* @returns Watermarked coefficient
*/
export function dmqimEmbed(coeff: number, bit: number, delta: number, dither: number): number {
// Dither modulation: shift coefficient by dither before quantizing
const shifted = coeff - dither;
// Quantize to the nearest lattice point for the given bit
// Bit 0 → even quantization levels: ..., -2Δ, 0, 2Δ, ...
// Bit 1 → odd quantization levels: ..., -Δ, Δ, 3Δ, ...
const halfDelta = delta / 2;
if (bit === 0) {
// Quantize to nearest even multiple of delta
const quantized = Math.round(shifted / delta) * delta;
return quantized + dither;
} else {
// Quantize to nearest odd multiple of delta (offset by delta/2)
const quantized = Math.round((shifted - halfDelta) / delta) * delta + halfDelta;
return quantized + dither;
}
}
/**
* Extract a soft decision from a coefficient using DM-QIM
*
* Returns a signed float:
* Positive → likely bit 1
* Negative → likely bit 0
* Magnitude → confidence (closer to ±delta/4 = maximum confidence)
*
* @param coeff - Possibly watermarked coefficient
* @param delta - Quantization step size
* @param dither - Key-dependent dither value (must match embed)
* @returns Soft decision value in [-delta/4, +delta/4]
*/
export function dmqimExtractSoft(coeff: number, delta: number, dither: number): number {
const shifted = coeff - dither;
const halfDelta = delta / 2;
// Distance to nearest even lattice point (bit 0)
const d0 = Math.abs(shifted - Math.round(shifted / delta) * delta);
// Distance to nearest odd lattice point (bit 1)
const d1 = Math.abs(shifted - halfDelta - Math.round((shifted - halfDelta) / delta) * delta);
// Soft output: positive for bit 1, negative for bit 0
// Magnitude reflects confidence
return (d0 - d1) / delta;
}
/**
* Extract a hard decision (0 or 1) from a coefficient
*/
export function dmqimExtractHard(coeff: number, delta: number, dither: number): number {
return dmqimExtractSoft(coeff, delta, dither) > 0 ? 1 : 0;
}