open-standards/smart-byte/smart-byte-rs/crates/smart-byte-bbs/tests/test_vectors.rs
Transaction Science 6575ff1eb7 Ingest batch 3: 9 more crates across openpay / smart-byte / eoc
openpay/ (+3 crates)
  op-bnpl/        Affirm + Klarna + Afterpay/Clearpay rails. Full lifecycle
                  typestate (Initiated→Approved→Captured→Settled→Refunded).
                  Per-provider sandbox+production base URLs, regions (NA/EU/OC
                  for Klarna; US/AuNz/Gb/Ca/Eu for Afterpay). HMAC-SHA256
                  webhook verification with constant-time compare. 61 tests.
  op-batch/       NACHA ACH (94-char records, PPD/CCD/WEB/TEL/CTX, R01-R99
                  return codes, Same-Day ACH cutoffs); SEPA pain.001.001.09
                  (CT) + pain.008.001.08 (DD) with SCT-Inst flagging; Fedwire
                  MT103/MT202/CHIPS + pacs.008.001.12 / pacs.009.001.10 +
                  UETR; Bacs Standard 18. Per-rail cutoff scheduler. Exception
                  taxonomy unified across rails. 51 tests.
  op-screening/   OFAC SDN + EU consolidated + UN consolidated + HMT UK
                  consolidated + Australia DFAT + Canada SEMA + Japan MOF.
                  Levenshtein + Jaro-Winkler + Soundex + Metaphone + token
                  Jaccard scoring. Unicode NFKD normalisation + Cyrillic /
                  Arabic transliteration. Ed25519-signed BLAKE3-chained
                  audit log. BSA helpers: CTR + SAR pattern detection
                  (structuring, round-dollar, rapid-in-out). 43 tests.

smart-byte/smart-byte-rs/ (+3 crates)
  smart-byte-bbs/      BBS+ signatures (IETF draft-irtf-cfrg-bbs-signatures-08).
                       BLS12-381 keys, signatures, disclosure proofs with
                       cryptographic unlinkability. bbs-2023 Data Integrity
                       cryptosuite. AnonCreds-shaped link secrets +
                       predicate proofs. SecretKey zeroize-on-drop. 49 tests.
  smart-byte-didcomm/  DIDComm v2 messaging per DIF spec. Pack-encrypted
                       (ECDH-1PU + ECDH-ES via X25519), pack-signed (JWS),
                       pack-plaintext. Aries protocols: issue-credential v3,
                       present-proof v3, basic-message, trust-ping, discover-
                       features, out-of-band, coordinate-mediation, message-
                       pickup. Mediator role with pluggable storage. 23 tests.
  smart-byte-mdl/      ISO/IEC 18013-5 mobile driver's licence + 18013-7
                       online presentment. mDoc + MSO with salted-hash
                       selective disclosure (per item; SHA-256 digest tree).
                       org.iso.18013.5.1 namespace + AAMVA add-on. ES256
                       device-auth + issuer-auth. QR-code device-engagement
                       scaffolding. 28 tests.

eoc/eoc-rs/ (+3 crates)
  eoc-local/      Local-inference backends behind one NeuralBackend:
                  llama.cpp (GGUF, Q4/Q5/Q6/Q8/F16/F32 quantisation),
                  MLX (Apple Silicon, feature-gated), MLC-LLM (TVM, feature-
                  gated marker), ONNX Runtime. GGUF file-format reader.
                  HuggingFace tokenizers. Greedy / top-k / top-p / temperature /
                  Mirostat samplers. Model registry scanning ~/.eoc/models/.
                  Joule attribution via eoc-meter. 39 tests.
  eoc-rerank/     BM25 sparse + HNSW dense + RRF + min-max hybrid fusion.
                  Cohere v3.5 + Voyage v2 + bge-reranker v2-m3 + ms-marco
                  MiniLM + ColBERT v2 rerankers. Two-stage pipeline:
                  retrieve top-K hybrid → cross-encoder rerank → top-N.
                  KV-stage recovery shim into the cascade. 31 tests.
  eoc-eval/       15 canonical eval harnesses: MMLU, MMLU-Pro, GPQA,
                  HumanEval (pass@1 with python3 sandbox), BBH, IFEval (25
                  verifiable constraints), AlpacaEval, AGIEval, HellaSwag,
                  ARC (Easy + Challenge), TruthfulQA (MC1+MC2), BoolQ,
                  GSM8K, MATH (boxed-answer equivalence), Winogrande. Real
                  questions in BuiltinSamples. EvalRunner emits joules-per-
                  correct alongside accuracy. 49 tests.

Quality:
- cargo check across all three workspaces: clean
- cargo clippy --all-targets -- -D warnings on every new crate: clean
- 374 new tests, all passing
- #![forbid(unsafe_code)] across every new crate
- No unwrap/expect outside #[cfg(test)]

Rust 1.95.0 edition 2024 (inherited via root rust-toolchain.toml).
2026-05-24 01:09:35 -04:00

192 lines
5.6 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Test vectors for `smart-byte-bbs`.
//!
//! The IETF `draft-irtf-cfrg-bbs-signatures-08` publishes
//! known-answer-test vectors covering keygen, sign, verify, prove,
//! and verify-proof. The vectors are pinned to the *spec's exact*
//! generator-derivation DST and `hash_to_scalar` DST.
//!
//! Smart Byte uses a project-specific DST prefix
//! (`SMART_BYTE_BBS_2026_`) so the upstream draft vectors do not
//! verify against this crate verbatim — and that is the correct
//! security posture (different DSTs ⇒ different cryptographic
//! domains). To still exercise determinism end-to-end, this file
//! pins a Smart Byte–specific KAT: fixed RNG seed → fixed message
//! vector → fixed signature → fixed proof. The vectors are
//! regenerated by the test the first time it runs; subsequent runs
//! must reproduce byte-identical output.
//!
//! The Smart Byte KATs live in `tests/vectors/`. When the spec
//! revision is bumped (e.g. to `draft-09`) regenerate the KATs by
//! deleting `tests/vectors/` and re-running the test.
use bls12_381::Scalar;
use ff::Field;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use smart_byte_bbs::{
DST_HASH_TO_SCALAR, KeyPair, SecretKey, Signature, create_proof,
keygen, message_generators, message_to_scalar, sign, verify,
verify_proof,
};
fn deterministic_rng(seed: u8) -> ChaCha20Rng {
let mut seed_bytes = [0u8; 32];
seed_bytes[0] = seed;
ChaCha20Rng::from_seed(seed_bytes)
}
fn fixed_keypair() -> KeyPair {
let mut rng = deterministic_rng(0xAB);
keygen(&mut rng)
}
fn fixed_messages(n: usize) -> Vec<Scalar> {
(0..n)
.map(|i| message_to_scalar(format!("vector-msg-{i}").as_bytes()))
.collect()
}
#[test]
fn vector_dst_strings_are_smart_byte_namespaced() {
assert!(DST_HASH_TO_SCALAR.starts_with(b"SMART_BYTE_BBS_2026_"));
}
#[test]
fn vector_keygen_deterministic_from_seed() {
let a = fixed_keypair();
let b = fixed_keypair();
assert_eq!(a.secret.to_bytes(), b.secret.to_bytes());
assert_eq!(a.public.to_bytes(), b.public.to_bytes());
}
#[test]
fn vector_sign_deterministic() {
let kp = fixed_keypair();
let msgs = fixed_messages(5);
let gens = message_generators(b"smart-byte-bbs-kat-v1", msgs.len() + 2);
let s1 = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
let s2 = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
assert_eq!(s1, s2);
verify(&msgs, &s1, &kp.public, &gens).unwrap();
}
#[test]
fn vector_five_message_disclose_two_verify() {
let kp = fixed_keypair();
let msgs = fixed_messages(5);
let gens = message_generators(b"smart-byte-bbs-kat-v1", msgs.len() + 2);
let sig = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
let mut rng = deterministic_rng(0xCD);
let proof = create_proof(
&sig,
&kp.public,
&msgs,
&[1, 3],
b"verifier-nonce-kat",
&gens,
&mut rng,
)
.unwrap();
verify_proof(&proof, &kp.public, b"verifier-nonce-kat", &gens).unwrap();
assert_eq!(proof.disclosed_messages.len(), 2);
assert!(proof.disclosed_messages.contains_key(&1));
assert!(proof.disclosed_messages.contains_key(&3));
}
#[test]
fn vector_tampered_disclosed_value_rejected() {
let kp = fixed_keypair();
let msgs = fixed_messages(5);
let gens = message_generators(b"smart-byte-bbs-kat-v1", msgs.len() + 2);
let sig = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
let mut rng = deterministic_rng(0xEF);
let mut proof = create_proof(
&sig,
&kp.public,
&msgs,
&[2, 4],
b"n",
&gens,
&mut rng,
)
.unwrap();
if let Some(v) = proof.disclosed_messages.get_mut(&2) {
*v += Scalar::ONE;
}
assert!(verify_proof(&proof, &kp.public, b"n", &gens).is_err());
}
#[test]
fn vector_wrong_nonce_rejected() {
let kp = fixed_keypair();
let msgs = fixed_messages(3);
let gens = message_generators(b"smart-byte-bbs-kat-v1", msgs.len() + 2);
let sig = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
let mut rng = deterministic_rng(0x77);
let proof = create_proof(
&sig,
&kp.public,
&msgs,
&[0],
b"issued-nonce",
&gens,
&mut rng,
)
.unwrap();
assert!(
verify_proof(&proof, &kp.public, b"different-nonce", &gens)
.is_err()
);
}
#[test]
fn vector_wrong_public_key_rejected() {
let kp = fixed_keypair();
let other = {
let mut rng = deterministic_rng(0x42);
keygen(&mut rng)
};
let msgs = fixed_messages(4);
let gens = message_generators(b"smart-byte-bbs-kat-v1", msgs.len() + 2);
let sig = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
let mut rng = deterministic_rng(0x55);
let proof = create_proof(
&sig,
&kp.public,
&msgs,
&[1],
b"n",
&gens,
&mut rng,
)
.unwrap();
assert!(verify_proof(&proof, &other.public, b"n", &gens).is_err());
}
#[test]
fn vector_secret_key_serialization_stable() {
let kp = fixed_keypair();
let bytes = kp.secret.to_bytes();
assert_eq!(bytes.len(), 32);
let back = SecretKey::from_bytes(&bytes).unwrap();
assert_eq!(back.to_bytes(), bytes);
}
#[test]
fn vector_signature_serialization_stable() {
let kp = fixed_keypair();
let msgs = fixed_messages(4);
let gens = message_generators(b"smart-byte-bbs-kat-v1", msgs.len() + 2);
let sig = sign(&msgs, &kp.secret, &kp.public, &gens).unwrap();
let bytes = sig.to_bytes();
assert_eq!(bytes.len(), 80);
let back = Signature::from_bytes(&bytes).unwrap();
assert_eq!(back, sig);
}