/** * Synor ZK SDK Examples for C * * Demonstrates zero-knowledge proof operations: * - Circuit compilation (Circom) * - Proof generation and verification * - Multiple proving systems (Groth16, PLONK, STARK) * - Recursive proof composition * - Trusted setup ceremonies */ #include #include #include #include void circuit_example(synor_zk_t* zk) { printf("=== Circuit Compilation ===\n"); synor_error_t err; // Simple Circom circuit: prove knowledge of factors const char* circom_code = "pragma circom 2.1.0;\n" "\n" "template Multiplier() {\n" " signal input a;\n" " signal input b;\n" " signal output c;\n" "\n" " c <== a * b;\n" "}\n" "\n" "component main = Multiplier();\n"; // Compile the circuit printf("Compiling circuit...\n"); synor_circuit_source_t source = { .code = circom_code, .language = SYNOR_CIRCUIT_LANGUAGE_CIRCOM }; synor_circuit_t* circuit = NULL; err = synor_circuits_compile(zk, &source, &circuit); if (err != SYNOR_OK) { fprintf(stderr, "Failed to compile circuit\n"); return; } printf("Circuit compiled:\n"); printf(" Circuit ID: %s\n", synor_circuit_get_id(circuit)); printf(" Constraints: %zu\n", synor_circuit_get_constraints(circuit)); printf(" Public inputs: %zu\n", synor_circuit_get_public_inputs(circuit)); printf(" Private inputs: %zu\n", synor_circuit_get_private_inputs(circuit)); printf(" Outputs: %zu\n", synor_circuit_get_outputs(circuit)); // Get circuit info synor_circuit_info_t* info = NULL; err = synor_circuits_get(zk, synor_circuit_get_id(circuit), &info); if (err == SYNOR_OK) { printf("\nCircuit info:\n"); printf(" Name: %s\n", synor_circuit_info_get_name(info)); printf(" Version: %s\n", synor_circuit_info_get_version(info)); printf(" Wires: %zu\n", synor_circuit_info_get_wire_count(info)); printf(" Labels: %zu\n", synor_circuit_info_get_label_count(info)); synor_circuit_info_free(info); } // List available circuits synor_circuit_list_t* circuits = NULL; err = synor_circuits_list(zk, &circuits); if (err == SYNOR_OK) { printf("\nAvailable circuits: %zu\n", synor_circuit_list_count(circuits)); for (size_t i = 0; i < 3 && i < synor_circuit_list_count(circuits); i++) { synor_circuit_t* c = synor_circuit_list_get(circuits, i); printf(" %s: %s (%zu constraints)\n", synor_circuit_get_id(c), synor_circuit_get_name(c), synor_circuit_get_constraints(c)); } synor_circuit_list_free(circuits); } synor_circuit_free(circuit); printf("\n"); } void groth16_example(synor_zk_t* zk) { printf("=== Groth16 Proving System ===\n"); synor_error_t err; const char* circuit_id = "multiplier-v1"; // Generate proving/verification keys (trusted setup) printf("Generating keys...\n"); synor_groth16_keys_t* keys = NULL; err = synor_groth16_setup(zk, circuit_id, &keys); if (err != SYNOR_OK) { fprintf(stderr, "Failed to generate keys\n"); return; } printf("Keys generated:\n"); printf(" Proving key size: %zu bytes\n", synor_groth16_keys_get_pk_size(keys)); printf(" Verification key size: %zu bytes\n", synor_groth16_keys_get_vk_size(keys)); // Prepare witness (private inputs) synor_witness_t* witness = synor_witness_create(); synor_witness_set(witness, "a", "3"); synor_witness_set(witness, "b", "7"); // Generate proof printf("\nGenerating proof...\n"); synor_prove_request_t prove_req = { .circuit_id = circuit_id, .witness = witness, .proving_key = synor_groth16_keys_get_pk(keys), .proving_key_len = synor_groth16_keys_get_pk_size(keys) }; synor_proof_t* proof = NULL; err = synor_groth16_prove(zk, &prove_req, &proof); if (err != SYNOR_OK) { fprintf(stderr, "Failed to generate proof\n"); synor_witness_free(witness); synor_groth16_keys_free(keys); return; } printf("Proof generated:\n"); printf(" Proof size: %zu bytes\n", synor_proof_get_size(proof)); printf(" Public signals: %zu\n", synor_proof_get_public_signal_count(proof)); printf(" Proving time: %lums\n", synor_proof_get_proving_time_ms(proof)); // Verify proof printf("\nVerifying proof...\n"); synor_verify_request_t verify_req = { .proof = synor_proof_get_bytes(proof), .proof_len = synor_proof_get_size(proof), .public_signals = synor_proof_get_public_signals(proof), .public_signal_count = synor_proof_get_public_signal_count(proof), .verification_key = synor_groth16_keys_get_vk(keys), .verification_key_len = synor_groth16_keys_get_vk_size(keys) }; bool verified; err = synor_groth16_verify(zk, &verify_req, &verified); printf("Verification result: %s\n", verified ? "true" : "false"); // Export proof for on-chain verification char* solidity_calldata = NULL; err = synor_groth16_export_calldata(zk, proof, &solidity_calldata); if (err == SYNOR_OK && solidity_calldata) { printf("\nSolidity calldata: %.100s...\n", solidity_calldata); free(solidity_calldata); } synor_proof_free(proof); synor_witness_free(witness); synor_groth16_keys_free(keys); printf("\n"); } void plonk_example(synor_zk_t* zk) { printf("=== PLONK Proving System ===\n"); synor_error_t err; const char* circuit_id = "multiplier-v1"; // PLONK uses universal trusted setup printf("Getting universal setup...\n"); synor_srs_t* srs = NULL; err = synor_plonk_get_universal_setup(zk, 14, &srs); // 2^14 constraints if (err != SYNOR_OK) { fprintf(stderr, "Failed to get SRS\n"); return; } printf("SRS loaded: %zu bytes\n", synor_srs_get_size(srs)); // Generate circuit-specific keys printf("\nGenerating circuit keys...\n"); synor_plonk_keys_t* keys = NULL; err = synor_plonk_setup(zk, circuit_id, srs, &keys); if (err != SYNOR_OK) { fprintf(stderr, "Failed to generate keys\n"); synor_srs_free(srs); return; } printf("Keys generated\n"); // Generate proof synor_witness_t* witness = synor_witness_create(); synor_witness_set(witness, "a", "5"); synor_witness_set(witness, "b", "9"); printf("\nGenerating PLONK proof...\n"); synor_plonk_prove_request_t prove_req = { .circuit_id = circuit_id, .witness = witness, .proving_key = synor_plonk_keys_get_pk(keys), .proving_key_len = synor_plonk_keys_get_pk_size(keys) }; synor_proof_t* proof = NULL; err = synor_plonk_prove(zk, &prove_req, &proof); if (err == SYNOR_OK) { printf("Proof generated:\n"); printf(" Proof size: %zu bytes\n", synor_proof_get_size(proof)); printf(" Proving time: %lums\n", synor_proof_get_proving_time_ms(proof)); // Verify proof synor_plonk_verify_request_t verify_req = { .proof = synor_proof_get_bytes(proof), .proof_len = synor_proof_get_size(proof), .public_signals = synor_proof_get_public_signals(proof), .public_signal_count = synor_proof_get_public_signal_count(proof), .verification_key = synor_plonk_keys_get_vk(keys), .verification_key_len = synor_plonk_keys_get_vk_size(keys) }; bool verified; synor_plonk_verify(zk, &verify_req, &verified); printf("Verification result: %s\n", verified ? "true" : "false"); synor_proof_free(proof); } // Compare with Groth16 printf("\nPLONK advantages:\n"); printf(" - Universal trusted setup\n"); printf(" - Larger proofs (~2.5 KB vs ~200 bytes)\n"); printf(" - Faster proving for some circuits\n"); synor_witness_free(witness); synor_plonk_keys_free(keys); synor_srs_free(srs); printf("\n"); } void stark_example(synor_zk_t* zk) { printf("=== STARK Proving System ===\n"); synor_error_t err; const char* circuit_id = "multiplier-v1"; // STARKs don't need trusted setup printf("Configuring STARK parameters...\n"); synor_stark_config_t config = { .field_size = 256, .hash_function = SYNOR_HASH_FUNCTION_POSEIDON, .blowup_factor = 8, .num_queries = 30, .folding_factor = 8 }; // Generate proof synor_witness_t* witness = synor_witness_create(); synor_witness_set(witness, "a", "11"); synor_witness_set(witness, "b", "13"); printf("\nGenerating STARK proof...\n"); synor_stark_prove_request_t prove_req = { .circuit_id = circuit_id, .witness = witness, .config = &config }; synor_stark_proof_t* proof = NULL; err = synor_stark_prove(zk, &prove_req, &proof); if (err == SYNOR_OK) { printf("Proof generated:\n"); printf(" Proof size: %zu bytes\n", synor_stark_proof_get_size(proof)); printf(" Proving time: %lums\n", synor_stark_proof_get_proving_time_ms(proof)); printf(" FRI layers: %zu\n", synor_stark_proof_get_fri_layers(proof)); // Verify proof printf("\nVerifying STARK proof...\n"); synor_stark_verify_request_t verify_req = { .proof = synor_stark_proof_get_bytes(proof), .proof_len = synor_stark_proof_get_size(proof), .public_signals = synor_stark_proof_get_public_signals(proof), .public_signal_count = synor_stark_proof_get_public_signal_count(proof), .config = &config }; bool verified; synor_stark_verify(zk, &verify_req, &verified); printf("Verification result: %s\n", verified ? "true" : "false"); synor_stark_proof_free(proof); } // Compare with SNARKs printf("\nSTARK advantages:\n"); printf(" - No trusted setup needed\n"); printf(" - Post-quantum secure\n"); printf(" - Larger proofs (~100 KB)\n"); printf(" - Faster proving for complex computations\n"); synor_witness_free(witness); printf("\n"); } void recursive_example(synor_zk_t* zk) { printf("=== Recursive Proof Composition ===\n"); synor_error_t err; // Create inner proofs printf("Generating inner proofs...\n"); synor_recursive_proof_list_t* inner_proofs = synor_recursive_proof_list_create(); for (int i = 1; i <= 3; i++) { synor_witness_t* witness = synor_witness_create(); char a_str[16], b_str[16]; snprintf(a_str, sizeof(a_str), "%d", i); snprintf(b_str, sizeof(b_str), "%d", i + 1); synor_witness_set(witness, "a", a_str); synor_witness_set(witness, "b", b_str); synor_recursive_prove_request_t prove_req = { .circuit_id = "multiplier-v1", .witness = witness, .level = 0 }; synor_recursive_proof_t* proof = NULL; err = synor_recursive_prove_inner(zk, &prove_req, &proof); if (err == SYNOR_OK) { synor_recursive_proof_list_add(inner_proofs, proof); printf(" Inner proof %d generated\n", i); } synor_witness_free(witness); } // Aggregate proofs recursively printf("\nAggregating proofs...\n"); synor_aggregate_request_t aggregate_req = { .proofs = inner_proofs, .aggregation_circuit = "recursive-aggregator-v1" }; synor_aggregated_proof_t* aggregated = NULL; err = synor_recursive_aggregate(zk, &aggregate_req, &aggregated); if (err == SYNOR_OK) { printf("Aggregated proof:\n"); printf(" Proof size: %zu bytes\n", synor_aggregated_proof_get_size(aggregated)); printf(" Proofs aggregated: %zu\n", synor_aggregated_proof_get_count(aggregated)); printf(" Recursion depth: %zu\n", synor_aggregated_proof_get_depth(aggregated)); // Verify aggregated proof printf("\nVerifying aggregated proof...\n"); bool verified; err = synor_recursive_verify_aggregated(zk, aggregated, &verified); printf("Verification result: %s\n", verified ? "true" : "false"); synor_aggregated_proof_free(aggregated); } // Use cases printf("\nRecursive proof use cases:\n"); printf(" - Rollup batch verification\n"); printf(" - Incremental computation proofs\n"); printf(" - Cross-chain state proofs\n"); synor_recursive_proof_list_free(inner_proofs); printf("\n"); } void ceremony_example(synor_zk_t* zk) { printf("=== Trusted Setup Ceremony ===\n"); synor_error_t err; // List active ceremonies synor_ceremony_list_t* ceremonies = NULL; err = synor_ceremony_list(zk, SYNOR_CEREMONY_STATUS_ACTIVE, &ceremonies); if (err == SYNOR_OK) { printf("Active ceremonies: %zu\n", synor_ceremony_list_count(ceremonies)); for (size_t i = 0; i < 3 && i < synor_ceremony_list_count(ceremonies); i++) { synor_ceremony_t* ceremony = synor_ceremony_list_get(ceremonies, i); printf("\n %s:\n", synor_ceremony_get_id(ceremony)); printf(" Circuit: %s\n", synor_ceremony_get_circuit_id(ceremony)); printf(" Participants: %zu\n", synor_ceremony_get_participant_count(ceremony)); printf(" Current round: %zu\n", synor_ceremony_get_current_round(ceremony)); printf(" Status: %s\n", synor_ceremony_get_status(ceremony)); } synor_ceremony_list_free(ceremonies); } // Create a new ceremony printf("\nCreating new ceremony...\n"); synor_ceremony_config_t config = { .circuit_id = "new-circuit-v1", .min_participants = 10, .max_participants = 100, .round_duration = 3600, // 1 hour per round .verify_contributions = true }; synor_ceremony_t* new_ceremony = NULL; err = synor_ceremony_create(zk, &config, &new_ceremony); if (err == SYNOR_OK) { printf("Ceremony created:\n"); printf(" Ceremony ID: %s\n", synor_ceremony_get_id(new_ceremony)); printf(" Join URL: %s\n", synor_ceremony_get_join_url(new_ceremony)); // Participate in ceremony printf("\nParticipating in ceremony...\n"); uint8_t entropy[32]; // In real code, use secure random: arc4random_buf(entropy, sizeof(entropy)); memset(entropy, 0x42, sizeof(entropy)); // Example only synor_contribution_request_t contrib_req = { .ceremony_id = synor_ceremony_get_id(new_ceremony), .entropy = entropy, .entropy_len = sizeof(entropy) }; synor_contribution_t* contribution = NULL; err = synor_ceremony_contribute(zk, &contrib_req, &contribution); if (err == SYNOR_OK) { printf("Contribution made:\n"); printf(" Contribution ID: %s\n", synor_contribution_get_id(contribution)); printf(" Position: %zu\n", synor_contribution_get_position(contribution)); printf(" Hash: %s\n", synor_contribution_get_hash(contribution)); // Verify contribution printf("\nVerifying contribution...\n"); bool valid; synor_ceremony_verify_contribution(zk, synor_contribution_get_id(contribution), &valid); printf("Contribution valid: %s\n", valid ? "true" : "false"); synor_contribution_free(contribution); } // Get ceremony transcript synor_transcript_t* transcript = NULL; err = synor_ceremony_get_transcript(zk, synor_ceremony_get_id(new_ceremony), &transcript); if (err == SYNOR_OK) { printf("\nCeremony transcript:\n"); printf(" Total contributions: %zu\n", synor_transcript_get_contribution_count(transcript)); printf(" Start time: %s\n", synor_transcript_get_start_time(transcript)); const char* final_hash = synor_transcript_get_final_hash(transcript); printf(" Final hash: %s\n", final_hash ? final_hash : "pending"); synor_transcript_free(transcript); } synor_ceremony_free(new_ceremony); } printf("\n"); } int main(int argc, char** argv) { synor_error_t err; // Initialize client synor_zk_config_t config = { .api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key", .endpoint = "https://zk.synor.io/v1", .timeout_ms = 120000, // ZK operations can be slow .retries = 3, .debug = false, .default_proving_system = SYNOR_PROVING_SYSTEM_GROTH16, .prove_timeout_ms = 300000, .verify_timeout_ms = 30000 }; synor_zk_t* zk = NULL; err = synor_zk_init(&config, &zk); if (err != SYNOR_OK) { fprintf(stderr, "Failed to initialize ZK client: %s\n", synor_error_string(err)); return 1; } // Check service health bool healthy; err = synor_zk_health_check(zk, &healthy); printf("Service healthy: %s\n\n", healthy ? "true" : "false"); // Run examples circuit_example(zk); groth16_example(zk); plonk_example(zk); stark_example(zk); recursive_example(zk); ceremony_example(zk); // Cleanup synor_zk_free(zk); return 0; }