circom_witnesscalc 0.0.1-alpha.3 copy "circom_witnesscalc: ^0.0.1-alpha.3" to clipboard
circom_witnesscalc: ^0.0.1-alpha.3 copied to clipboard

Circom witness calculation Flutter Plugin

example/lib/main.dart

import 'dart:convert';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';

import 'package:flutter/services.dart';
import 'package:circom_witnesscalc/circom_witnesscalc.dart';
import 'package:flutter_rapidsnark/flutter_rapidsnark.dart';
import 'package:share_plus/share_plus.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _circomWitnesscalcPlugin = CircomWitnesscalc();

  String? _inputsPath;
  String? _graphWCDPath;
  String? _zkeyFilePath;

  String? _defaultInputsPath;
  String? _defaultGraphWCDPath;
  String? _defaultZkeyFilePath;

  Uint8List? _witness;
  int _witnessTimestamp = 0;
  int _proofGenerationTimestamp = 0;
  String? _proof;
  String _errorMessage = "";

  @override
  void initState() {
    super.initState();

    WidgetsBinding.instance.addPostFrameCallback((_) async {
      await copyAssetToDocumentsDirectory('assets/authV2_inputs.json');
      await copyAssetToDocumentsDirectory('assets/authV2.wcd');
      await copyAssetToDocumentsDirectory('assets/authV2.zkey');

      final directory = await getApplicationDocumentsDirectory();
      _defaultInputsPath = '${directory.path}/authV2_inputs.json';
      _defaultGraphWCDPath = '${directory.path}/authV2.wcd';
      _defaultZkeyFilePath = '${directory.path}/authV2.zkey';

      resetData();
    });
  }

  void resetData() {
    setState(() {
      _inputsPath = _defaultInputsPath;
      _graphWCDPath = _defaultGraphWCDPath;
      _zkeyFilePath = _defaultZkeyFilePath;
      resetOutputs();
    });
  }

  void resetOutputs() {
    _witness = null;
    _witnessTimestamp = 0;
    _proofGenerationTimestamp = 0;
    _proof = null;
    _errorMessage = "";
  }

  Future<void> copyAssetToDocumentsDirectory(String asset) async {
    final directory = await getApplicationDocumentsDirectory();
    final fileName = asset.split('/').last;
    final file = File('${directory.path}/$fileName');

    if (!await file.exists()) {
      final byteData = await rootBundle.load(asset);
      await file.writeAsBytes(byteData.buffer.asUint8List(), flush: true);
    }
  }

  @override
  Widget build(BuildContext context) {
    final String witnessResult;
    if (_errorMessage.isNotEmpty) {
      witnessResult = "Error: $_errorMessage";
    } else if (_witness != null) {
      witnessResult = ("Witness generated in $_witnessTimestamp millis");
    } else {
      witnessResult = "Generate witness";
    }

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: SafeArea(
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                ElevatedButton(
                  onPressed: resetData,
                  child: const Text("Reset all inputs"),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.black,
                    foregroundColor: Colors.white,
                  ),
                ),
                const SizedBox(height: 16),
                ListTile(
                  title: Text(
                    _defaultInputsPath != _inputsPath
                        ? "Inputs json: ${basename(_inputsPath!)}"
                        : "Default authV2 inputs selected",
                    style: const TextStyle(fontSize: 16),
                  ),
                  trailing: ElevatedButton.icon(
                    onPressed: () async {
                      final result = await FilePicker.platform.pickFiles(
                        type: FileType.custom,
                        allowedExtensions: ["json"],
                      );

                      final file = result?.files.first;
                      if (file != null && file.path != null) {
                        setState(() {
                          _inputsPath = file.path!;
                          resetOutputs();
                        });
                      }
                    },
                    icon: const Icon(Icons.file_open),
                    label: const Text("Select"),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black,
                      foregroundColor: Colors.white,
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                ListTile(
                  title: Text(
                    _defaultGraphWCDPath != _graphWCDPath
                        ? "Selected .wcd graph file: ${basename(_graphWCDPath!)}"
                        : "Default authV2.wcd graph selected",
                    style: const TextStyle(fontSize: 16),
                  ),
                  trailing: ElevatedButton.icon(
                    onPressed: () async {
                      final result = await FilePicker.platform
                          .pickFiles(type: FileType.any);

                      final filePath = result?.files.first.path;
                      if (filePath != null) {
                        setState(() {
                          _graphWCDPath = filePath;
                          resetOutputs();
                        });
                      }
                    },
                    icon: const Icon(Icons.file_open),
                    label: const Text("Select"),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black,
                      foregroundColor: Colors.white,
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                ListTile(
                  title: Text(
                    _defaultZkeyFilePath != _zkeyFilePath
                        ? "Selected .zkey File path: ${basename(_zkeyFilePath!)}"
                        : "Default authV2 zkey file selected",
                    style: const TextStyle(fontSize: 16),
                  ),
                  trailing: ElevatedButton.icon(
                    onPressed: () async {
                      final result = await FilePicker.platform
                          .pickFiles(type: FileType.any);

                      final file = result?.files.first;
                      if (file?.path != null) {
                        setState(() {
                          _zkeyFilePath = file!.path!;
                          resetOutputs();
                        });
                      }
                    },
                    icon: const Icon(Icons.file_open),
                    label: const Text("Select"),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black,
                      foregroundColor: Colors.white,
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                Text(witnessResult, style: const TextStyle(fontSize: 16)),
                const SizedBox(height: 16),
                ElevatedButton.icon(
                  onPressed: onGenerateWitness,
                  icon: const Icon(Icons.play_arrow),
                  label: const Text("Generate witness"),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.black,
                    foregroundColor: Colors.white,
                  ),
                ),
                if (_witness != null) ...[
                  const SizedBox(height: 16),
                  ElevatedButton(
                    onPressed: onShare,
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black,
                      foregroundColor: Colors.white,
                    ),
                    child: const Text("Share witness"),
                  ),
                  const SizedBox(height: 16),
                  ElevatedButton.icon(
                    onPressed: onGenerateProof,
                    icon: const Icon(Icons.play_arrow),
                    label: const Text("Generate proof"),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black,
                      foregroundColor: Colors.white,
                    ),
                  ),
                ],
                if (_proof != null) ...[
                  const SizedBox(height: 16),
                  ElevatedButton(
                    onPressed: onShareProof,
                    child: const Text("Share proof"),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.black,
                      foregroundColor: Colors.white,
                    ),
                  ),
                  const SizedBox(height: 16),
                  Text("Proof generated in $_proofGenerationTimestamp millis",
                      style: const TextStyle(fontSize: 16)),
                  const SizedBox(height: 16),
                  Text(_proof!, style: const TextStyle(fontSize: 16)),
                ],
              ],
            ),
          ),
        ),
      ),
    );
  }

  // Generate the witness
  Future<void> onGenerateWitness() async {
    final stopwatch = Stopwatch();
    try {
      if (_defaultInputsPath == null || _graphWCDPath == null) {
        return;
      }

      final file = File(_inputsPath!);
      final inputs = await file.readAsString();

      final fileWCD = File(_graphWCDPath!);
      final graphData = await fileWCD.readAsBytes();

      stopwatch.start();
      final witness = await _circomWitnesscalcPlugin.calculateWitness(
        inputs: inputs,
        graphData: graphData,
      );

      setState(() {
        _witness = witness;
        _witnessTimestamp = stopwatch.elapsedMilliseconds;
        _errorMessage = "";
      });
    } on PlatformException catch (e) {
      setState(() {
        _errorMessage = e.message ?? "Unknown error";
      });
    } finally {
      stopwatch.stop();
    }
  }

  // Generate the proof
  Future<void> onGenerateProof() async {
    if (_witness == null) {
      return;
    }

    final stopwatch = Stopwatch();
    try {
      stopwatch.start();
      final zkProof = await Rapidsnark().groth16Prove(
        zkeyPath: _zkeyFilePath!,
        witness: _witness!,
      );
      _proofGenerationTimestamp = stopwatch.elapsedMilliseconds;

      //console log the proof and public signals
      final proofData = {
        'proof': zkProof.proof,
        'pubSignals': zkProof.publicSignals,
      };

      // Convert the map to a JSON string
      final proofJson = jsonEncode(proofData);

      setState(() {
        _proof = proofJson;

        _errorMessage = "";
      });
    } on PlatformException catch (e) {
      setState(() {
        _errorMessage = e.message ?? "Unknown error";
      });
    } finally {
      stopwatch.stop();
    }
  }

  void onShare() {
    if (_witness == null) {
      return;
    }

    Share.shareXFiles(
      [
        XFile.fromData(_witness!, name: "witness.wtns"),
      ],
      text: "Witness generated in $_witnessTimestamp millis",
    );
  }

  void onShareProof() {
    if (_proof == null) {
      return;
    }

    Share.shareXFiles(
      [
        XFile.fromData(Uint8List.fromList(utf8.encode(_proof!)),
            name: "proof.json"),
      ],
      text: "Proof generated in $_proofGenerationTimestamp millis",
    );
  }
}
0
likes
150
points
309
downloads

Publisher

verified publisheriden3.io

Weekly Downloads

Circom witness calculation Flutter Plugin

Repository (GitHub)

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on circom_witnesscalc