😎

Expo Go + React NativeでSindri APIを実行してみる

2024/02/01に公開

Sindri API とは

Sindri は、ゼロ知識証明を簡単に生成できるAPIを提供します。これにより、開発者はプライバシーを保護しながら、特定の情報(例えば、年齢の証明)が真実であることを証明できます。

準備

ゼロ知識証明とは

イーサリアムコミュニティとゼロ知識証明の発展
あたりで学習しておくとイメージがつかみやすいです。

Sindri API キーの取得

Sindri にログインするためのユーザー情報を発行して貰う必要があります。
直接メールをするなりしてコンタクトをしてログインするためのユーザー情報を発行してもらいます。
無事ログインができるとAccount Settings -> API KeysからAPI Keyを発行できます。
なお、APIやCLI経由でもAPI Keyは発行できます。
具体的なやり方はチュートリアルに書いてありますが次のようになります。

npm install -g sindri@latest
sindri login

と実行してログインをするとAPI Keyが発行されます。

回路のデプロイ

Sindri CLIを使ってゼロ知識証明回路をデプロイする
で使用した回路を使っています。

Expoのセットアップ

Tutorialに書いてある手順でExpoをインストールします。
合わせてスマートフォン側でアプリをインストールしておきます。

npx create-expo-app SindriAPISample

cd SindriAPISample
npx expo start

Sindri APIを実行する準備

APIを実行するためのライブラリのインストール。

npm install axios react-native-config
import axios from 'axios';
import Config from 'react-native-config';

// APIキーとURLの取得
const API_KEY = Config.SINDRI_API_KEY || "";
const API_URL_PREFIX = Config.SINDRI_API_URL || "https://sindri.app/api/";
const API_VERSION = "v1";
const API_URL = API_URL_PREFIX.concat(API_VERSION);

const headersJson = {
  Accept: "application/json",
  Authorization: `Bearer ${API_KEY}`
};

async function pollForStatus(endpoint, timeout = 20 * 60) {
  for (let i = 0; i < timeout; i++) {
    const response = await axios.get(API_URL + endpoint, {
      headers: headersJson,
      validateStatus: (status) => status === 200,
    });

    const status = response.data.status;
    if (["Ready", "Failed"].includes(status)) {
      console.log(`Poll exited after ${i} seconds with status: ${status}`);
      return response;
    }

    await new Promise((r) => setTimeout(r, 1000));
  }

  throw new Error(`Polling timed out after ${timeout} seconds.`);
}

export async function generateProof(input) {
  try {
    const circuitId = "SindriでデプロイしたIDに置き換える";
    console.log("Proving circuit...");
    const proofInput = `input = ${input}`;
    const proveResponse = await axios.post(
      API_URL + `/circuit/${circuitId}/prove`,
      { proof_input: proofInput },
      { headers: headersJson, validateStatus: (status) => status === 201 },
    );
    const proofId = proveResponse.data.proof_id;

    const proofDetailResponse = await pollForStatus(`/proof/${proofId}/detail`);
    const proofDetailStatus = proveResponse.data.status;
    if (proofDetailStatus === "Failed") {
      throw new Error("Proving failed");
    }

    const proverTomlContent = proofDetailResponse.data.proof_input['Prover.toml'];
    const verifierTomlContent = proofDetailResponse.data.public['Verifier.toml'];

    console.log(proverTomlContent);
    console.log(verifierTomlContent);
    const publicOutput = verifierTomlContent;
    console.log(`Circuit proof output signal: ${publicOutput}`);
  } catch (error) {
    if (error instanceof Error) {
      console.error(error.message);
    } else {
      console.error("An unknown error occurred.");
    }
  }
}
import React, { useState } from 'react';
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, TextInput, Button } from 'react-native';
import { generateProof } from 'Sindri.jsへのパス';

export default function App() {
  const [age, setAge] = useState('');
  const [proofResult, setProofResult] = useState('');

  const handleGenerateProof = async () => {
    try {
      const result = await generateProof(age);
      setProofResult('年齢が証明されました');
    } catch (error) {
      setProofResult('証明に失敗しました');
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="年齢を入力"
        value={age}
        onChangeText={setAge}
        keyboardType="numeric"
      />
      <Button title="年齢を証明" onPress={handleGenerateProof} />
      {proofResult ? <Text>{proofResult}</Text> : null}
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  input: {
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
    width: '80%',
  },
});

動作確認

npx expo start

その後、アプリ側でQRコードをスキャンすると確認できます。

検証

noirの場合はnargo verifyを使います。

GitHubで編集を提案

Discussion