import type { Address } from '@ton/core'; import { BLS_DST_G2_POP, BLS_PUBKEY_BYTES, BLS_SIG_BYTES } from './opcodes'; export { BLS_PUBKEY_BYTES, BLS_SIG_BYTES, BLS_DST_G2_POP }; /** * Generate a fresh 32-byte cryptographically-random BLS secret key. * * In production: operators run `automaton bls keygen` instead — this is the * dev/test path. Mainnet operators MUST persist the secret in an HSM-style * keystore, never bundle it in client code. * * @example * const sk = randomBlsSecret(); * const pk = blsPublicKey(sk); // 48-byte G1 compressed */ export declare function randomBlsSecret(): Uint8Array; /** * Derive the 48-byte compressed G1 public key for a given secret. Min-pk * ciphersuite, so this IS the on-chain `groupPk` representation. */ export declare function blsPublicKey(sk: Uint8Array): Buffer; /** * Aggregate N pkShares into one 48-byte compressed G1 group public key. * * For solo-mode (n=1): use `blsPublicKey(sk)` directly — Atlas's solo-mode * invariant requires `pkShare == groupPk` so there's no "aggregation" to do. * * For multi-op DKG groups: Atlas publishes the aggregate; off-chain * aggregation here is for tests / pre-deploy validation only. * * @example * const groupPk = aggregateGroupPublicKey([sk1, sk2, sk3]); */ export declare function aggregateGroupPublicKey(sks: readonly Uint8Array[]): Buffer; /** * Sign a 32-byte message digest (typically `computeSnapshotHash` output) * with a pkShare secret. Returns a 96-byte compressed G2 signature. * * **Always uses `BLS_DST_G2_POP`** — bypasses the noble-curves default-DST * footgun. Sigs from this function verify against TVM's `BLS_VERIFY` * unmodified. * * @example * const msg = computeSnapshotHash(phoebe.address, timestamp, root); * const sig = signMessage(operatorSk, msg); * await phoebe.sendPushSnapshot(via, { value, timestamp, root, aggSig: sig }); */ export declare function signMessage(sk: Uint8Array, msgHash: Uint8Array): Buffer; /** * Aggregate N G2 signatures into one 96-byte compressed G2 aggregate. * * For solo-mode (n=1): pass `[sig]` — round-trips to the same bytes. * * For multi-op: each operator returns their partial via `signMessage`; * the aggregator combines them here. The on-chain `BLS_VERIFY` checks * the aggregate against the cached `groupPk` as a single (pk, sig, msg) * tuple. * * @example * const partials = [sig1, sig2, sig3]; * const aggSig = aggregateSignatures(partials); */ export declare function aggregateSignatures(sigs: readonly (Buffer | Uint8Array)[]): Buffer; /** * Build the BLS message bytes for a snapshot push. Byte-identical to the * on-chain hash domain in `phoebe/contracts/phoebe.tolk:handlePushSnapshot`: * `msg.signedDataRef.beginParse()` — the raw 68 bytes of * `(phoebeHash:uint256 BE, timestamp:uint32 BE, root:uint256 BE)`. * * `phoebe` is the address of the receiving Phoebe contract. Its 32-byte * hash is the first field of the signed payload — binds the snapshot to * exactly one Phoebe deployment. Without this prefix, two Phoebe instances * sharing the same Atlas group key would accept each other's PushSnapshots * (the operator's BLS sig would verify under the same `groupPk` regardless * of which Phoebe forwarded it). Cross-deployment replay is closed * cryptographically by including the address hash in every signed payload. * * TVM `BLS_VERIFY` hashes-to-curve over those 68 bytes via RFC 9380 * SSWU_RO with the POP DST. Off-chain operators feed this buffer to * `signMessage`, which applies the same hash-to-curve before signing. * * Workchain note: only the 256-bit address hash is included in the signed * bytes (not the full 264-bit workchain + hash representation). Phoebe is * pinned to workchain 0 by titon convention. * * @example * const root = tree.rootAsBigint(); * const sigInput = computeSnapshotHash(phoebe.address, timestamp, root); * const sig = signMessage(operatorSk, sigInput); */ export declare function computeSnapshotHash(phoebe: Address, timestamp: number, root: bigint): Buffer;