@credo-ts/core
Version:
<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1
91 lines (90 loc) • 3.5 kB
JavaScript
import { KeyManagementError } from "../../../error/KeyManagementError.mjs";
import { ecCrvToCurveParams } from "./ecPublicKey.mjs";
import { ECDSASigValue } from "@peculiar/asn1-ecc";
import { AsnConvert } from "@peculiar/asn1-schema";
//#region src/modules/kms/jwk/kty/ec/ecSignature.ts
/**
* Converts a RAW EC signature to DER format
*
* @param rawSignature - Raw signature as r || s concatenated values
* @param crv - The EC crv of the key used for the signature
* @returns DER encoded signature
*/
function rawEcSignatureToDer(rawSignature, crv) {
const pointBitLength = ecCrvToCurveParams[crv].pointBitLength;
const pointByteLength = Math.ceil(pointBitLength / 8);
if (rawSignature.length !== pointByteLength * 2) throw new KeyManagementError(`Invalid raw signature length for EC signature conversion. Expected ${pointByteLength * 2} bytes for crv ${crv}`);
const r = rawSignature.slice(0, pointByteLength);
const s = rawSignature.slice(pointByteLength);
const rValue = removeLeadingZeros(r);
const sValue = removeLeadingZeros(s);
const signature = new ECDSASigValue();
signature.r = new Uint8Array(ensurePositive(rValue)).buffer;
signature.s = new Uint8Array(ensurePositive(sValue)).buffer;
return new Uint8Array(AsnConvert.serialize(signature));
}
/**
* Converts a DER encoded EC signature to RAW format
*
* @param derSignature - DER encoded signature
* @param crv - The EC crv of the key used for the signature
* @returns Raw signature as r || s concatenated values
*/
function derEcSignatureToRaw(derSignature, crv) {
const asn = AsnConvert.parse(derSignature, ECDSASigValue);
const pointBitLength = ecCrvToCurveParams[crv].pointBitLength;
const pointByteLength = Math.ceil(pointBitLength / 8);
const rPadded = padToLength(new Uint8Array(asn.r), pointByteLength);
const sPadded = padToLength(new Uint8Array(asn.s), pointByteLength);
const rawSignature = new Uint8Array(pointByteLength * 2);
rawSignature.set(rPadded, 0);
rawSignature.set(sPadded, pointByteLength);
return rawSignature;
}
/**
* Helper function to remove unnecessary leading zeros from an integer representation
*
* @param data - The integer bytes
* @returns - Data with leading zeros removed
*/
function removeLeadingZeros(data) {
let startIndex = 0;
while (startIndex < data.length - 1 && data[startIndex] === 0) startIndex++;
return data.slice(startIndex);
}
/**
* Ensures an integer value is represented as positive in ASN.1 by
* adding a leading zero if the high bit is set
*
* @param data - The integer bytes
* @returns Data ensuring positive integer representation
*/
function ensurePositive(data) {
if (data.length > 0 && (data[0] & 128) !== 0) {
const result = new Uint8Array(data.length + 1);
result.set(data, 1);
return result;
}
return data;
}
/**
* Pads an integer value to the specified length
*
* @param data - The integer bytes
* @param targetLength - The desired length
* @returns Padded data
*/
function padToLength(data, targetLength) {
if (data.length === targetLength) return data;
if (data.length > targetLength) {
const significantStart = data.length - targetLength;
for (let i = 0; i < significantStart; i++) if (data[i] !== 0) throw new KeyManagementError("Value too large for the specified point size");
return data.slice(significantStart);
}
const result = new Uint8Array(targetLength);
result.set(data, targetLength - data.length);
return result;
}
//#endregion
export { derEcSignatureToRaw, rawEcSignatureToDer };
//# sourceMappingURL=ecSignature.mjs.map