//! 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 { (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); }