threshold_test - DKLS23 Threshold ECDSA Tests

Overview

The threshold_test module provides comprehensive test coverage for the DKLS23 threshold ECDSA implementation. It validates all components of the threshold signature protocol including oblivious transfer, MtA conversion, secret sharing, distributed key generation, presigning, and signing.

These tests ensure correctness, security properties, and proper error handling across the entire threshold ECDSA stack.

Test Categories

The test suite is organized into the following categories:

Oblivious Transfer Tests (TestSimpleOT, TestOTExtension)
  • Basic OT correctness for choice bits 0 and 1

  • Multiple independent OT transfers

  • Invalid point rejection (identity element attacks)

  • OT extension with 256+ OTs

  • Base OT setup verification

MtA Tests (TestMtA, TestMtAwc)
  • Multiplicative-to-additive correctness: a·b = α + β

  • Real OT security (receiver never sees both messages)

  • Edge cases near curve order boundary

  • MtAwc zero-knowledge proof verification

  • Proof structure validation (no secret leakage)

Threshold Sharing Tests (TestThresholdSharing, TestPedersenVSS)
  • Basic Shamir sharing and reconstruction

  • Feldman VSS verification

  • Tampered share detection

  • Various threshold configurations (2-of-3, 3-of-5)

  • Pedersen VSS with blinding factors

DKG Tests (TestDKLS23_DKG)
  • 2-of-3 distributed key generation

  • Public key consistency across parties

  • Correct public key computation

  • Session ID validation

Presigning Tests (TestDKLS23_Presign)
  • Valid presignature generation

  • Consistent r values across participants

  • Session ID requirements

Signing Tests (TestDKLS23_Sign)
  • Signature share generation

  • Standard ECDSA verification

  • Wrong message detection

  • Invalid signature share detection

End-to-End Tests (TestDKLS23_Complete)
  • Complete 2-of-3 signing flow

  • Different participant combinations

  • Standard ECDSA format output

  • DER encoding validation

  • Multiple messages with same keys

Security Tests (TestMaliciousParties)
  • Invalid share detection during DKG

  • Commitment mismatch detection

  • Malicious party identification

Running the Tests

Run all threshold tests with pytest:

pytest charm/test/schemes/threshold_test.py -v

Run specific test class:

pytest charm/test/schemes/threshold_test.py::TestDKLS23_Complete -v

Run with coverage:

pytest charm/test/schemes/threshold_test.py --cov=charm.schemes.threshold --cov-report=html

Key Test Scenarios

Complete Signing Flow:

def test_complete_2_of_3_signing(self):
    dkls = DKLS23(self.group, threshold=2, num_parties=3)
    g = self.group.random(G)

    # Step 1: Distributed Key Generation
    key_shares, public_key = dkls.distributed_keygen(g)

    # Step 2: Generate presignatures
    presignatures = dkls.presign([1, 2], key_shares, g)

    # Step 3: Sign a message
    message = b"Hello, threshold ECDSA!"
    signature = dkls.sign([1, 2], presignatures, key_shares, message, g)

    # Step 4: Verify signature
    assert dkls.verify(public_key, signature, message, g)

Curve Agnosticism:

def test_curve_agnostic_prime256v1(self):
    from charm.toolbox.eccurve import prime256v1
    group = ECGroup(prime256v1)

    dkls = DKLS23(group, threshold=2, num_parties=3)
    # Protocol works with P-256 curve

Malicious Party Detection:

def test_dkg_invalid_share_detected(self):
    # Tamper with a share during DKG
    tampered_share = original_share + one

    # Victim party detects the invalid share
    key_share, complaint = dkg.keygen_round3(victim_id, state, received, msgs)

    assert key_share is None  # Verification failed
    assert complaint is not None  # Complaint generated

API Reference

Tests for DKLS23 Threshold ECDSA implementation.

Run with: pytest charm/test/schemes/threshold_test.py -v

This module tests: - SimpleOT: Base Oblivious Transfer protocol - OTExtension: IKNP-style OT extension - MtA/MtAwc: Multiplicative-to-Additive conversion - ThresholdSharing/PedersenVSS: Threshold secret sharing - DKLS23_DKG: Distributed Key Generation - DKLS23_Presign: Presigning protocol - DKLS23_Sign: Signing protocol - DKLS23: Complete threshold ECDSA protocol

class threshold_test.TestCurveAgnostic(methodName='runTest')[source]

Bases: TestCase

Tests for curve agnosticism (MEDIUM-11)

test_curve_agnostic_prime256v1()[source]

Test that DKLS23 works with different curves (MEDIUM-11).

Uses prime256v1 (P-256/secp256r1) instead of secp256k1 to verify the protocol is curve-agnostic.

class threshold_test.TestDKLS23_Complete(methodName='runTest')[source]

Bases: TestCase

End-to-end tests for complete DKLS23 protocol

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_3_of_5_threshold()[source]

Test 3-of-5 threshold scheme

test_complete_2_of_3_signing()[source]

Complete flow: keygen -> presign -> sign -> verify

test_different_participant_combinations()[source]

Test that any 2 of 3 parties can sign

test_insufficient_participants_raises_error()[source]

Test that signing with insufficient participants raises error

test_invalid_threshold_raises_error()[source]

Test that invalid threshold/num_parties raises error

test_keygen_interface()[source]

Test the PKSig-compatible keygen interface

test_multiple_messages_same_keys()[source]

Test signing multiple messages with same key shares

test_signature_is_standard_ecdsa()[source]

Verify that output is standard ECDSA signature format

test_wrong_message_fails_verification()[source]

Test that signature verification fails with wrong message

class threshold_test.TestDKLS23_DKG(methodName='runTest')[source]

Bases: TestCase

Tests for Distributed Key Generation

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_2_of_3_dkg()[source]

Test 2-of-3 distributed key generation

test_all_parties_same_pubkey()[source]

All parties should derive the same public key

test_dkg_computes_correct_public_key()[source]

Test that DKG computes public key as product of individual contributions

test_dkg_rejects_empty_session_id()[source]

Test that DKG keygen_round1 rejects empty session_id

test_dkg_rejects_none_session_id()[source]

Test that DKG keygen_round1 rejects None session_id

class threshold_test.TestDKLS23_Presign(methodName='runTest')[source]

Bases: TestCase

Tests for presigning protocol

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_presign_generates_valid_presignature()[source]

Test that presigning produces valid presignature objects

test_presign_rejects_empty_session_id()[source]

Test that presign_round1 rejects empty session_id

test_presign_rejects_none_session_id()[source]

Test that presign_round1 rejects None session_id

test_presignatures_have_same_r()[source]

All parties’ presignatures should have the same r value

class threshold_test.TestDKLS23_Sign(methodName='runTest')[source]

Bases: TestCase

Tests for signing protocol

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_signature_share_generation()[source]

Test that signature shares are generated correctly

test_signature_share_verification()[source]

Test that invalid signature shares are detected (MEDIUM-06).

test_signature_verification_correct()[source]

Test that valid ECDSA signatures verify correctly

test_signature_verification_wrong_message()[source]

Test that signature verification fails with wrong message

class threshold_test.TestDPF(methodName='runTest')[source]

Bases: TestCase

Tests for Distributed Point Function (GGM-based)

test_dpf_full_eval()[source]

Test DPF full domain evaluation.

test_dpf_key_independence()[source]

Test that individual keys reveal nothing about alpha/beta.

test_dpf_off_points()[source]

Test DPF correctness at non-target points.

test_dpf_single_point()[source]

Test DPF correctness at target point.

class threshold_test.TestMPFSS(methodName='runTest')[source]

Bases: TestCase

Tests for Multi-Point Function Secret Sharing

test_mpfss_empty()[source]

Test MPFSS with empty point set.

test_mpfss_full_eval()[source]

Test MPFSS full domain evaluation.

test_mpfss_multiple_points()[source]

Test MPFSS with multiple points.

test_mpfss_single_point()[source]

Test MPFSS with single point (should match DPF).

class threshold_test.TestMaliciousParties(methodName='runTest')[source]

Bases: TestCase

Tests for adversarial/malicious party scenarios in threshold ECDSA.

These tests verify that the protocol correctly detects and handles various forms of malicious behavior including: - Invalid shares during DKG - Wrong commitments - Commitment mismatches during presigning - Invalid signature shares

classmethod setUpClass()[source]

Hook method for setting up class fixture before running tests in the class.

test_dkg_insufficient_honest_parties()[source]

Test that a party can identify malicious parties when multiple collude.

Run 2-of-3 DKG where 2 parties (party 2 and party 3) send invalid shares to party 1. Verify party 1 can identify both malicious parties.

test_dkg_invalid_share_detected()[source]

Test that DKG detects tampered shares during round 3.

Run DKG with 3 parties. In round 2, tamper with party 3’s share to party 1 (add 1 to the share value). Verify that party 1 detects the invalid share in round 3 (returns a complaint).

test_dkg_wrong_commitment_detected()[source]

Test that DKG detects when a party’s commitment doesn’t match their shares.

Run DKG round 1, then modify party 2’s commitment list by changing the first commitment to a random point. Verify share verification fails for party 2’s shares.

test_mta_receiver_learns_only_chosen_message()[source]

Test MtA security property: receiver’s beta depends only on chosen values.

Run MtA protocol and verify that the receiver’s beta calculation depends only on the specific input values used, not any other information. This tests the basic security property of the MtA protocol.

test_presign_commitment_mismatch_detected()[source]

Test that presigning detects when Gamma_i doesn’t match the commitment.

Run presign round 1 with 3 parties. In round 2 messages, replace party 2’s Gamma_i with a different value that doesn’t match the commitment. Verify round 3 raises ValueError about commitment verification.

Note: This test validates the commitment verification logic in the presigning protocol. The test directly verifies commitment checking without going through the full MtA completion (which has a separate API change).

test_signature_invalid_share_produces_invalid_sig()[source]

Test that tampering with signature shares produces invalid signatures.

Use simulated presignatures to test that modifying a party’s signature share (s_i) causes the aggregated signature to fail ECDSA verification. This validates that malicious tampering with signature shares is detectable.

class threshold_test.TestMtA(methodName='runTest')[source]

Bases: TestCase

Tests for Multiplicative-to-Additive conversion

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_mta_correctness()[source]

Test that a*b = alpha + beta (mod q) - multiplicative to additive with real OT

test_mta_edge_case_near_order()[source]

Test MtA with values close to the curve order (MEDIUM-04).

test_mta_multiple_invocations()[source]

Test MtA with multiple random values

test_mta_return_types()[source]

Test MtA methods have documented return types (LOW-03).

test_mta_uses_real_ot()[source]

Test that MtA uses real OT - receiver never sees both messages

class threshold_test.TestMtAwc(methodName='runTest')[source]

Bases: TestCase

Tests for MtA with correctness check

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_mtawc_correctness()[source]

Test MtA with correctness check produces valid shares

test_mtawc_proof_does_not_reveal_sender_bits()[source]

Test that MtAwc proof does NOT contain sender_bits (CRITICAL-02 fix)

class threshold_test.TestOTExtension(methodName='runTest')[source]

Bases: TestCase

Tests for IKNP-style OT Extension

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_base_ot_required_for_receiver_extend()[source]

Verify receiver_extend fails if base OT not completed.

test_base_ot_required_for_sender_init()[source]

Verify sender_init fails if base OT not completed.

test_ot_extension_alternating_bits()[source]

Test OT extension with alternating choice bits

test_ot_extension_basic()[source]

Test OT extension with 256 OTs

test_sender_s_not_exposed()[source]

Verify receiver cannot access sender’s random bits.

class threshold_test.TestPedersenVSS(methodName='runTest')[source]

Bases: TestCase

Tests for Pedersen VSS (information-theoretically hiding)

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_pedersen_vss_reconstruction()[source]

Test that Pedersen VSS shares reconstruct correctly

test_pedersen_vss_verification()[source]

Test Pedersen VSS share verification

class threshold_test.TestSilentOT(methodName='runTest')[source]

Bases: TestCase

Tests for Silent OT Extension (PCG-based)

test_silent_ot_basic()[source]

Test basic Silent OT correctness.

test_silent_ot_choice_distribution()[source]

Test that choice bits come from sparse set.

test_silent_ot_different_messages()[source]

Test that m0 and m1 are different for each OT.

test_silent_ot_larger()[source]

Test Silent OT with larger output size.

test_silent_ot_messages_32_bytes()[source]

Test that OT messages are 32 bytes each.

class threshold_test.TestSimpleOT(methodName='runTest')[source]

Bases: TestCase

Tests for base Oblivious Transfer (Chou-Orlandi style)

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_ot_choice_one()[source]

Test OT with choice bit 1 - receiver should learn m1

test_ot_choice_zero()[source]

Test OT with choice bit 0 - receiver should learn m0

test_ot_invalid_point_rejected()[source]

Test that invalid points from malicious sender are rejected

test_ot_multiple_transfers()[source]

Test multiple independent OT instances

test_ot_reset_sender()[source]

Test that reset_sender clears sender state

class threshold_test.TestThresholdSharing(methodName='runTest')[source]

Bases: TestCase

Tests for threshold secret sharing (Shamir-style)

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_basic_sharing_and_reconstruction()[source]

Test basic 2-of-3 secret sharing and reconstruction

test_feldman_vss_detects_invalid_share()[source]

Test that Feldman VSS detects tampered shares

test_feldman_vss_verification()[source]

Test Feldman VSS verification - shares should verify against commitments

test_insufficient_shares_raises_error()[source]

Test that reconstruction fails with insufficient shares

test_invalid_threshold_raises_error()[source]

Test that invalid threshold values raise errors

test_threshold_3_of_5()[source]

Test 3-of-5 threshold scheme

test_threshold_limit_validation()[source]

Test that excessive thresholds are rejected (MEDIUM-05).

class threshold_test.TestThresholdSignature(methodName='runTest')[source]

Bases: TestCase

Tests for ThresholdSignature class

setUp()[source]

Hook method for setting up the test fixture before exercising it.

test_der_encoding()[source]

Test DER encoding produces valid structure

test_signature_equality()[source]

Test ThresholdSignature equality comparison

test_signature_inequality()[source]

Test ThresholdSignature inequality