Initial Commit
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Test-only DI bindings for `@suaveplan/bitpacker-crypto` primitives.
|
||||
*
|
||||
* Implemented directly against the lower-level `@suaveplan/crypto-core`
|
||||
* (sign/verify) and `@suaveplan/crypto-cipher` (AEAD) packages so this
|
||||
* test surface has NO dependency on `@suaveplan/crypto`. That breaks an
|
||||
* otherwise-circular dep chain: `crypto` may depend on `bitpacker-crypto`
|
||||
* (e.g. for `EnvelopeSchema` in `chain-bundle`) without inducing a cycle
|
||||
* via this test helper.
|
||||
*
|
||||
* Production callers should still wire `verifyAuthoritySignature` from
|
||||
* `@suaveplan/crypto/authority` and `aeadEncrypt` / `aeadDecrypt` from
|
||||
* `@suaveplan/crypto` — those are the canonical implementations. This
|
||||
* file mirrors their shape for test purposes only.
|
||||
*/
|
||||
|
||||
import * as aesGcm from "@suaveplan/crypto-cipher/aes-256-gcm";
|
||||
import * as chacha20 from "@suaveplan/crypto-cipher/chacha20-poly1305";
|
||||
import * as xchacha20 from "@suaveplan/crypto-cipher/xchacha20-poly1305";
|
||||
import { ed25519 } from "@suaveplan/crypto-core/sign";
|
||||
import type {
|
||||
AeadAlgorithm,
|
||||
AeadOps,
|
||||
AeadOpsOptions,
|
||||
AuthorityVerifier,
|
||||
DomainTag,
|
||||
} from "@suaveplan/types";
|
||||
|
||||
const ED25519_ALGORITHM_ID = 0;
|
||||
|
||||
/**
|
||||
* Inline copy of `buildSigningInput` from `@suaveplan/crypto/domain-tags`.
|
||||
* Reproduced here to keep this test helper free of any `@suaveplan/crypto`
|
||||
* runtime dep. The byte layout is identical: `tag-bytes ‖ 0x00 ‖ payload`.
|
||||
*/
|
||||
function buildSigningInput(domain: DomainTag, payload: Uint8Array): Uint8Array {
|
||||
const tag = new TextEncoder().encode(domain);
|
||||
const out = new Uint8Array(tag.length + 1 + payload.length);
|
||||
out.set(tag, 0);
|
||||
out[tag.length] = 0;
|
||||
out.set(payload, tag.length + 1);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test verifier — mirrors `verifyAuthoritySignature` from
|
||||
* `@suaveplan/crypto/authority` byte-for-byte. Only ed25519 is supported
|
||||
* (matches the canonical impl); other algorithms throw to preserve the
|
||||
* "structural error → swallow as false" convention used by primitives.
|
||||
*/
|
||||
export const cryptoVerifier: AuthorityVerifier = (
|
||||
domain,
|
||||
publicSlot,
|
||||
payload,
|
||||
signature
|
||||
) => {
|
||||
if (publicSlot.algorithm !== ED25519_ALGORITHM_ID) {
|
||||
throw new Error(
|
||||
`cryptoVerifier: unsupported algorithm ${publicSlot.algorithm}`
|
||||
);
|
||||
}
|
||||
const message = buildSigningInput(domain, payload);
|
||||
return ed25519.verify(publicSlot.publicKey, signature, message);
|
||||
};
|
||||
|
||||
function encrypt(
|
||||
algorithm: AeadAlgorithm,
|
||||
key: Uint8Array,
|
||||
plaintext: Uint8Array,
|
||||
options: AeadOpsOptions
|
||||
): Uint8Array {
|
||||
switch (algorithm) {
|
||||
case "AES-256-GCM":
|
||||
return aesGcm.encrypt(key, options.nonce, plaintext, options.aad);
|
||||
case "ChaCha20-Poly1305":
|
||||
return chacha20.encrypt(key, options.nonce, plaintext, options.aad);
|
||||
case "XChaCha20-Poly1305":
|
||||
return xchacha20.encrypt(
|
||||
key,
|
||||
options.nonce,
|
||||
plaintext,
|
||||
options.aad
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function decrypt(
|
||||
algorithm: AeadAlgorithm,
|
||||
key: Uint8Array,
|
||||
ciphertext: Uint8Array,
|
||||
options: AeadOpsOptions
|
||||
): Uint8Array {
|
||||
switch (algorithm) {
|
||||
case "AES-256-GCM":
|
||||
return aesGcm.decrypt(key, options.nonce, ciphertext, options.aad);
|
||||
case "ChaCha20-Poly1305":
|
||||
return chacha20.decrypt(
|
||||
key,
|
||||
options.nonce,
|
||||
ciphertext,
|
||||
options.aad
|
||||
);
|
||||
case "XChaCha20-Poly1305":
|
||||
return xchacha20.decrypt(
|
||||
key,
|
||||
options.nonce,
|
||||
ciphertext,
|
||||
options.aad
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test AEAD bundle — dispatches to the per-algorithm functions exposed by
|
||||
* `@suaveplan/crypto-cipher`. Behaviorally identical to the canonical
|
||||
* `{ encrypt: aeadEncrypt, decrypt: aeadDecrypt }` shape from
|
||||
* `@suaveplan/crypto`.
|
||||
*/
|
||||
export const cryptoAead: AeadOps = { encrypt, decrypt };
|
||||
Reference in New Issue
Block a user