#![no_main] use arbitrary::{Arbitrary, Unstructured}; use commonware_cryptography::bls12381::primitives::{ group::{Share, G1, G2}, ops::*, sharing::Sharing, variant::{MinPk, MinSig, PartialSignature}, }; use libfuzzer_sys::fuzz_target; mod common; use common::{ arbitrary_bytes, arbitrary_messages, arbitrary_optional_bytes, arbitrary_partial_sig_g1, arbitrary_partial_sig_g2, arbitrary_share, arbitrary_vec_g1, arbitrary_vec_g2, arbitrary_vec_indexed_g1, arbitrary_vec_indexed_g2, arbitrary_vec_of_vec_partial_sig_g1, arbitrary_vec_of_vec_partial_sig_g2, arbitrary_vec_partial_sig_g1, arbitrary_vec_partial_sig_g2, }; type Message = (Option>, Vec); enum FuzzOperation { PartialSignProofOfPossessionMinPk { public: Sharing, share: Share, }, PartialSignProofOfPossessionMinSig { public: Sharing, share: Share, }, PartialVerifyProofOfPossessionMinPk { public: Sharing, partial: PartialSignature, }, PartialVerifyProofOfPossessionMinSig { public: Sharing, partial: PartialSignature, }, PartialAggregateSignaturesMinPk { partials: Vec>, }, PartialAggregateSignaturesMinSig { partials: Vec>, }, PartialVerifyMultipleMessagesMinPk { public: Sharing, index: u32, messages: Vec<(Option>, Vec)>, partials: Vec, }, PartialVerifyMultipleMessagesMinSig { public: Sharing, index: u32, messages: Vec<(Option>, Vec)>, partials: Vec, }, PartialVerifyMultiplePublicKeysMinPk { public: Sharing, namespace: Option>, message: Vec, partials: Vec<(u32, G2)>, }, PartialVerifyMultiplePublicKeysMinSig { public: Sharing, namespace: Option>, message: Vec, partials: Vec<(u32, G1)>, }, ThresholdSignatureRecoverMinPk { sharing: Sharing, partials: Vec>, }, ThresholdSignatureRecoverMinSig { sharing: Sharing, partials: Vec>, }, ThresholdSignatureRecoverMultipleMinPk { sharing: Sharing, signature_groups: Vec>>, concurrency: usize, }, ThresholdSignatureRecoverMultipleMinSig { sharing: Sharing, signature_groups: Vec>>, concurrency: usize, }, ThresholdSignatureRecoverPairMinPk { sharing: Sharing, partials_1: Vec>, partials_2: Vec>, }, ThresholdSignatureRecoverPairMinSig { sharing: Sharing, partials_1: Vec>, partials_2: Vec>, }, } impl<'a> Arbitrary<'a> for FuzzOperation { fn arbitrary(u: &mut Unstructured<'a>) -> Result { let choice = u.int_in_range(0..=15)?; match choice { 0 => Ok(FuzzOperation::PartialSignProofOfPossessionMinPk { public: u.arbitrary()?, share: arbitrary_share(u)?, }), 1 => Ok(FuzzOperation::PartialSignProofOfPossessionMinSig { public: u.arbitrary()?, share: arbitrary_share(u)?, }), 2 => Ok(FuzzOperation::PartialVerifyProofOfPossessionMinPk { public: u.arbitrary()?, partial: arbitrary_partial_sig_g2(u)?, }), 3 => Ok(FuzzOperation::PartialVerifyProofOfPossessionMinSig { public: u.arbitrary()?, partial: arbitrary_partial_sig_g1(u)?, }), 4 => Ok(FuzzOperation::PartialAggregateSignaturesMinPk { partials: arbitrary_vec_partial_sig_g2(u, 0, 10)?, }), 5 => Ok(FuzzOperation::PartialAggregateSignaturesMinSig { partials: arbitrary_vec_partial_sig_g1(u, 0, 10)?, }), 6 => Ok(FuzzOperation::PartialVerifyMultipleMessagesMinPk { public: u.arbitrary()?, index: u.int_in_range(1..=100)?, messages: arbitrary_messages(u, 0, 10)?, partials: arbitrary_vec_g2(u, 0, 10)?, }), 7 => Ok(FuzzOperation::PartialVerifyMultipleMessagesMinSig { public: u.arbitrary()?, index: u.int_in_range(1..=100)?, messages: arbitrary_messages(u, 0, 10)?, partials: arbitrary_vec_g1(u, 0, 10)?, }), 8 => Ok(FuzzOperation::PartialVerifyMultiplePublicKeysMinPk { public: u.arbitrary()?, namespace: arbitrary_optional_bytes(u, 50)?, message: arbitrary_bytes(u, 0, 100)?, partials: arbitrary_vec_indexed_g2(u, 0, 10)?, }), 9 => Ok(FuzzOperation::PartialVerifyMultiplePublicKeysMinSig { public: u.arbitrary()?, namespace: arbitrary_optional_bytes(u, 50)?, message: arbitrary_bytes(u, 0, 100)?, partials: arbitrary_vec_indexed_g1(u, 0, 10)?, }), 10 => Ok(FuzzOperation::ThresholdSignatureRecoverMinSig { sharing: u.arbitrary()?, partials: arbitrary_vec_partial_sig_g1(u, 0, 20)?, }), 11 => Ok(FuzzOperation::ThresholdSignatureRecoverMinPk { sharing: u.arbitrary()?, partials: arbitrary_vec_partial_sig_g2(u, 0, 20)?, }), 12 => Ok(FuzzOperation::ThresholdSignatureRecoverMultipleMinPk { sharing: u.arbitrary()?, signature_groups: arbitrary_vec_of_vec_partial_sig_g2(u, 0, 5, 0, 10)?, concurrency: u.int_in_range(1..=4)?, }), 13 => Ok(FuzzOperation::ThresholdSignatureRecoverMultipleMinSig { sharing: u.arbitrary()?, signature_groups: arbitrary_vec_of_vec_partial_sig_g1(u, 0, 5, 0, 10)?, concurrency: u.int_in_range(1..=4)?, }), 14 => Ok(FuzzOperation::ThresholdSignatureRecoverPairMinPk { sharing: u.arbitrary()?, partials_1: arbitrary_vec_partial_sig_g2(u, 0, 10)?, partials_2: arbitrary_vec_partial_sig_g2(u, 0, 10)?, }), 15 => Ok(FuzzOperation::ThresholdSignatureRecoverPairMinSig { sharing: u.arbitrary()?, partials_1: arbitrary_vec_partial_sig_g1(u, 0, 10)?, partials_2: arbitrary_vec_partial_sig_g1(u, 0, 10)?, }), _ => { panic!("Unsupported operation type"); } } } } fn fuzz(op: FuzzOperation) { match op { FuzzOperation::PartialSignProofOfPossessionMinPk { public, share } => { if share.index <= public.required() { let _ = partial_sign_proof_of_possession::(&public, &share); } } FuzzOperation::PartialSignProofOfPossessionMinSig { public, share } => { if share.index <= public.required() { let _ = partial_sign_proof_of_possession::(&public, &share); } } FuzzOperation::PartialVerifyProofOfPossessionMinPk { public, partial } => { if partial.index <= public.required() { let _ = partial_verify_proof_of_possession::(&public, &partial); } } FuzzOperation::PartialVerifyProofOfPossessionMinSig { public, partial } => { if partial.index <= public.required() { let _ = partial_verify_proof_of_possession::(&public, &partial); } } FuzzOperation::PartialAggregateSignaturesMinPk { partials } => { let _ = partial_aggregate_signatures::(&partials); } FuzzOperation::PartialAggregateSignaturesMinSig { partials } => { let _ = partial_aggregate_signatures::(&partials); } FuzzOperation::PartialVerifyMultipleMessagesMinPk { public, index, messages, partials, } => { if index <= public.required() && messages.len() == partials.len() { let messages_refs: Vec<(Option<&[u8]>, &[u8])> = messages .iter() .map(|(ns, msg)| (ns.as_deref(), msg.as_slice())) .collect(); let partials_evals: Vec> = partials .into_iter() .enumerate() .map(|(i, sig)| PartialSignature { index: index + i as u32, value: sig, }) .collect(); let _ = partial_verify_multiple_messages::( &public, index, &messages_refs, &partials_evals, ); } } FuzzOperation::PartialVerifyMultipleMessagesMinSig { public, index, messages, partials, } => { if index <= public.required() && messages.len() == partials.len() { let messages_refs: Vec<(Option<&[u8]>, &[u8])> = messages .iter() .map(|(ns, msg)| (ns.as_deref(), msg.as_slice())) .collect(); let partials_evals: Vec> = partials .into_iter() .enumerate() .map(|(i, sig)| PartialSignature { index: index + i as u32, value: sig, }) .collect(); let _ = partial_verify_multiple_messages::( &public, index, &messages_refs, &partials_evals, ); } } FuzzOperation::PartialVerifyMultiplePublicKeysMinPk { public, namespace, message, partials, } => { if public.required() as usize == partials.len() { let partials_evals: Vec> = partials .into_iter() .map(|(idx, sig)| PartialSignature { index: idx, value: sig, }) .collect(); let _ = partial_verify_multiple_public_keys::( &public, namespace.as_deref(), &message, &partials_evals, ); } } FuzzOperation::PartialVerifyMultiplePublicKeysMinSig { public, namespace, message, partials, } => { if public.required() as usize == partials.len() { let partials_evals: Vec> = partials .into_iter() .map(|(idx, sig)| PartialSignature { index: idx, value: sig, }) .collect(); let _ = partial_verify_multiple_public_keys::( &public, namespace.as_deref(), &message, &partials_evals, ); } } FuzzOperation::ThresholdSignatureRecoverMinPk { sharing, partials } => { let _ = threshold_signature_recover::(&sharing, &partials); } FuzzOperation::ThresholdSignatureRecoverMinSig { sharing, partials } => { let _ = threshold_signature_recover::(&sharing, &partials); } FuzzOperation::ThresholdSignatureRecoverMultipleMinPk { sharing, signature_groups, concurrency, } => { if concurrency > 0 && !signature_groups.is_empty() { let groups_refs: Vec>> = signature_groups .iter() .map(|group| group.iter().collect()) .collect(); let _ = threshold_signature_recover_multiple::( &sharing, groups_refs, concurrency, ); } } FuzzOperation::ThresholdSignatureRecoverMultipleMinSig { sharing, signature_groups, concurrency, } => { if concurrency > 0 && !signature_groups.is_empty() { let groups_refs: Vec>> = signature_groups .iter() .map(|group| group.iter().collect()) .collect(); let _ = threshold_signature_recover_multiple::( &sharing, groups_refs, concurrency, ); } } FuzzOperation::ThresholdSignatureRecoverPairMinPk { sharing, partials_1, partials_2, } => { let _ = threshold_signature_recover_pair::(&sharing, &partials_1, &partials_2); } FuzzOperation::ThresholdSignatureRecoverPairMinSig { sharing, partials_1, partials_2, } => { let _ = threshold_signature_recover_pair::(&sharing, &partials_1, &partials_2); } } } fuzz_target!(|data: &[u8]| { let mut u = Unstructured::new(data); let num_ops = u.int_in_range(1..=100).unwrap_or(1); for _ in 0..num_ops { match u.arbitrary::() { Ok(op) => fuzz(op), Err(_) => break, } } });