This repository has been archived on 2023-04-09. You can view files and clone it, but cannot push or open issues or pull requests.
chainsafe-bls/src/herumi/signature.ts

94 lines
3.0 KiB
TypeScript
Raw Normal View History

import type {SignatureType} from "bls-eth-wasm";
import {getContext} from "./context.js";
import {PublicKey} from "./publicKey.js";
import {bytesToHex, concatUint8Arrays, hexToBytes, isZeroUint8Array} from "../helpers/index.js";
import {PointFormat, Signature as ISignature, CoordType} from "../interface.js";
import {EmptyAggregateError, InvalidLengthError, InvalidOrderError} from "../errors.js";
import {SIGNATURE_LENGTH_COMPRESSED, SIGNATURE_LENGTH_UNCOMPRESSED} from "../constants.js";
2020-11-19 13:22:41 +00:00
2020-11-20 19:03:17 +00:00
export class Signature implements ISignature {
2020-11-19 13:22:41 +00:00
readonly value: SignatureType;
constructor(value: SignatureType) {
2020-11-29 13:57:08 +00:00
if (!value.isValidOrder()) {
2020-11-30 00:20:52 +00:00
throw new InvalidOrderError();
2020-11-29 13:57:08 +00:00
}
2020-11-19 13:22:41 +00:00
this.value = value;
}
2021-09-22 15:21:31 +00:00
/**
* @param type Does not affect `herumi` implementation, always de-serializes to `jacobian`
* @param validate With `herumi` implementation signature validation is always on regardless of this flag.
*/
static fromBytes(bytes: Uint8Array, _type?: CoordType, _validate = true): Signature {
2020-11-19 13:22:41 +00:00
const context = getContext();
const signature = new context.Signature();
if (!isZeroUint8Array(bytes)) {
if (bytes.length === SIGNATURE_LENGTH_COMPRESSED) {
signature.deserialize(bytes);
} else if (bytes.length === SIGNATURE_LENGTH_UNCOMPRESSED) {
signature.deserializeUncompressed(bytes);
} else {
throw new InvalidLengthError("Signature", bytes.length);
}
2020-11-19 13:22:41 +00:00
signature.deserialize(bytes);
}
return new Signature(signature);
}
static fromHex(hex: string): Signature {
return this.fromBytes(hexToBytes(hex));
}
static aggregate(signatures: Signature[]): Signature {
if (signatures.length === 0) {
2020-11-30 00:20:52 +00:00
throw new EmptyAggregateError();
}
2020-11-19 13:22:41 +00:00
const context = getContext();
const signature = new context.Signature();
signature.aggregate(signatures.map((sig) => sig.value));
return new Signature(signature);
}
static verifyMultipleSignatures(sets: {publicKey: PublicKey; message: Uint8Array; signature: Signature}[]): boolean {
const context = getContext();
return context.multiVerify(
sets.map((s) => s.publicKey.value),
sets.map((s) => s.signature.value),
sets.map((s) => s.message)
2020-12-02 21:44:25 +00:00
);
}
2020-11-19 13:22:41 +00:00
verify(publicKey: PublicKey, message: Uint8Array): boolean {
return publicKey.value.verify(this.value, message);
}
verifyAggregate(publicKeys: PublicKey[], message: Uint8Array): boolean {
return this.value.fastAggregateVerify(
publicKeys.map((key) => key.value),
message
);
}
verifyMultiple(publicKeys: PublicKey[], messages: Uint8Array[]): boolean {
return this.value.aggregateVerifyNoCheck(
publicKeys.map((key) => key.value),
concatUint8Arrays(messages)
2020-11-19 13:22:41 +00:00
);
}
toBytes(format?: PointFormat): Uint8Array {
if (format === PointFormat.uncompressed) {
return this.value.serializeUncompressed();
} else {
return this.value.serialize();
}
2020-11-19 13:22:41 +00:00
}
toHex(format?: PointFormat): string {
return bytesToHex(this.toBytes(format));
2020-11-19 13:22:41 +00:00
}
}