티스토리 뷰

반응형

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/index.html

다음은 Indy SDK의 핵심 개념을 설명하는 디자인 문서입니다.:

 

Indy CLI Design

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/001-cli/README.html

 

Re-implementation of CLI(CLI 재구현)

이 제안은 CLI를 처음부터 다시 구현한다는 아이디어를 따릅니다. 주요 이유는 다음과 같습니다.:

  • 기존 코드 기반이 지원하기 어려운 방식으로 작성되었습니다.
  • 기존 코드 기반이 libindy 엔티티 모델과 너무 멀리 떨어져 있습니다.
  • 기존 코드 기반에는 복잡한 런타임(python)과 배포를 복잡하게 하는 추가 종속성(python libindy wrapper)이 필요합니다.
  • 심층 리팩토링을 수행하는 것보다 CLI를 다시 구현하는 것이 훨씬 저렴합니다.

 

Use Rust language(Rust 언어 사용)

Rust에서 CLI를 재구현할 것을 제안합니다. 주요 이유는 다음과 같습니다.:

  • 주요 libindy 코드 베이스는 Rust를 사용합니다.팀은 깊은 Rust 경험이 있습니다.
  • 큰 런타임, 작은 종속성 목록이 필요 없습니다. 결과적으로 간단한 패키징 및 배포가 가능합니다.
  • Rust는 네이티브 앱을 위한 훌륭하고 안정적인 크로스 플랫폼 솔루션입니다.

 

Terminal input-output handling(터미널 입출력 처리)

복잡한 터미널 입력을 처리하기 위해 서로 다른 터미널의 라인 피드(linefeed) 상자에 대한 이력 및 자동 완성 지원이 사용됩니다(몇 가지 추가 옵션도 가능). 컬러 터미널 출력을 처리하기 위해 asni_term 상자가 사용됩니다.

 

Auto completion(자동 완성)

readline 인프라를 통해 다음과 같은 자동 완성이 제공됩니다.:

  • 명령 그룹(Command group) 이름 완성
  • 명령(Command) 이름 완성
  • 명령 파라매터(Command param) 이름 완성

 

Libindy wrapper

CLI 프로젝트에는 간단한 동기식 libindy wrapper가 포함됩니다.:

  • 유사한 wrapper를 제공하는 libindy 테스트 코드는 부분적으로 제사용됩니다.
  • Rust 채널을 통해 동기화가 수행됩니다.:
    • 메인 스레드는 이 채널에 메시지를 보낼 채널과 클로저(closure)를 생성합니다.
    • libindy를 호출하고 이 클로저(closure)를 콜백으로 설정합니다.
    • 채널에서 읽기를 차단합니다.

채널 읽기는 시간 초과를 가정하므로 진행률 업데이트를 에뮬레이션 할 수 있습니다.

 

Threading model(스레딩 모델)

Rust 채널을 통해 동기화 된 터미널 및 libindy 호출을 사용하여 io 작업을 수행하는 주요 스레드가 하나 있습니다. 작은 채널 읽기 시간 초과로 인해 차단이 제한됩니다.

 

Execution modes(실행 모드)

CLI는 2 가지 실행 모드를 지원합니다.:

  • Interactive. 이 모드에서 CLI는 터미널에서 대화식으로 명령을 읽습니다.
  • Batch. 이 코드에서 모든 명령은 파일이나 파이프에서 읽고 연속적으로 실행됩니다.

 

Code structure(코드 구조)

  • CLI 코드는 다음에 대한 컨테이너가 될 "Command" 구조를 정의합니다.:
    • 명령 메타 정보(이름, 명령 도움말, 지원되는 매개변수, 매개변수 도움말)
    • 명령 실행 로직을 포함하는 "Executor" 기능
    • 명령 정리 로직을 포함하는 "Cleaner" 기능
  • 각 명령은 구성된 "Command" 인스턴스를 반환하는 하나의 퍼블릭 "new" 함수를 가진 Rust 모듈로 구현됩니다.
  • 모든 명령은 하나의 "CommandContext"를 공유합니다. "CommandContext"는 응용 프로그램 상태를 유지하며 두 부분으로 구성됩니다.:
    • 사전 정의된 응용 프로그램 부분. 명령 프롬프트, isExit 플래그 등과 같은 응용 프로그램 수준 상태를 유지하는 부분
    • 일반 명령 특정 부분. 이 부분은 명령이 Indy SDK 핸들, 사용된 DID 등과 같은 명령 별 데이터를 저장할 수 있는 key-value 스토리지입니다.
  • "Executor" 및 "Cleaner" 함수는 CommandContext를 매개 변수로 가져옵니다.
  • 실제 명령 실행은 CommandExecutor 클래스에 의해 수행됩니다. 이 클래스는:
    • 공유 "CommandContext"의 인스턴스화
    • 모든 명령 및 명령 그룹핑 정보 보유
    • 명령 메타 정보에 따라 명령 줄 구문 분석 및 관련 명령 검색
    • 명령 실행 트리거
    • 라인 자동 완성 로직 제공
    • 명령 정리의 Triggerid 명령 인스턴스는 선택적으로 몇 가지 컨텍스트를 공유합니다.
  • EntryPoint는:
  • CommandExecutor를 인스턴스화하고 executor 인스턴스를 명령하기 위한 command를 제공하십시오.
  • 실행 모드를 결정하십시오.
    • 대화식 모드에서는 readline cycle을 시작하고 Exit command가 수신될 때까지 CommandExecutor로 각 행을 실행합니다.
    • 배치 모드에서는 목록의 각 명령을 실행하고 모든 명령을 완료한 후 실행을 완료합니다.

다이어그램 참조:

(그림 깨짐)

 

Commands

Command 형식

indy> [<group>] <command> [[<main_param_name>=]<main_param_value>] [<param_name1>=<param_value1>] ... [<param_nameN>=<param_valueN>]

 

Common commands

Help

그룹 도움말이 있는 그룹 목록 출력:

indy> help

help 명령을 사용하여 그룹 명령 목록 출력:

indy> <group> help

help 명령, 명령 매개 변수 목록 및 각 매개 변수에 대한 도움말 출력:

indy> <group> <command> help

 

About

정보 및 라이센스 정보를 출력:

indy> about

 

Exit

CLI 종료:

indy> exit

 

Prompt

명령 프롬프트 변경:

indy> prompt <new_prompt>

 

 

Show

파일 내용 출력:

indy> show [<file_path>

 

Load Plugin

Libindy에서 플러그인 로드:

indy> load-plugin library=<name/path> initializer=<init_function>

 

Wallets management commands (wallet group)

indy> wallet <command>

 

 

Wallet create

새로운 wallet 생성 및 Indy CLI에 연결:

indy> wallet create <wallet name> key [key_derivation_method=<key_derivation_method>] [storage_type=<storage_type>] [storage_config={config json}]

TODO: custom wallet 유형 지원에 대해 생각해보십시오. 이제 기본 wallet 보안 모델을 강요합니다.

 

Wallet attach

기존 wallet을 Indy CLI에 연결:

indy> wallet attach <wallet name> [storage_type=<storage_type>] [storage_config={config json}]

 

Wallet open

지정된 이름으로 wallet을 오픈하고 wallet이 필요한 명령을 사용할 수 있도록 하십시오. 오픈된 wallet이 있으면 닫히게 됩니다.:

indy> wallet open <wallet name> key [key_derivation_method=<key_derivation_method>] [rekey] [rekey_derivation_method=<rekey_derivation_method>]

 

Wallet close

오픈된 wallet 닫기

indy> wallet close

 

 

Wallet delete

wallet 제거

indy> wallet delete <wallet name> key [key_derivation_method=<key_derivation_method>]

 

Wallet detach

Indy CLI에서 wallet 분리

indy> wallet detach <wallet name>

 

 

Wallet list

연결된 상태의 모든 wallet을 해당 상태로 나열합니다(열린 상태).:

indy> wallet list

 

 

Export wallet

열린 wallet을 지정된 파일로 내보냅니다.

indy> wallet export export_path=<path-to-file> export_key=[<export key>] [export_key_derivation_method=<export_key_derivation_method>]

 

Import wallet

새 wallet을 만든 다음 지정된 파일에서 컨텐츠를 가져옵니다.

indy> wallet import <wallet name> key=<key> [key_derivation_method=<key_derivation_method>] export_path=<path-to-file> export_key=<key used for export>  [storage_type=<storage_type>] [storage_config={config json}]

 

Pool management commands

indy> pool <subcommand>

 

 

Create config

이름 pool (network) 구성 생성

indy> pool create [name=]<pool name> gen_txn_file=<gen txn file path>

 

Connect

Indy 노드 pool에 연결하여 pool 액세스가 필요한 작업에 사용할 수 있도록 합니다. pool 연결이 있으면 연결이 끊어집니다.

indy> pool connect [name=]<pool name> [protocol-version=<version>] [timeout=<timeout>] [extended-timeout=<timeout>] [pre-ordered-nodes=<node names>]

 

Refresh

pool 원장의 로컬 복사본을 새로 고치고 pool 노드 연결을 업데이트합니다.

indy> pool refresh

 

 

Disconnect

Indy 노드 pool에서 연결 끊기

indy> pool disconnect

 

 

List

작성된 모든 pool 구성을 상태와 함께 나열합니다(연결된 것을 나타냄).

indy> pool list

 

 

Identity Management

indy> did <subcommand>

 

New

오픈된 wallet에 DID를 작성하고 저장하십시오. 오픈된 wallet이 필요합니다.

indy> did new [did=<did>] [seed=<UTF-8, base64 or hex string>] [metadata=<metadata string>]

List

오픈된 wallet에 저장된 내 DID를 테이블(did, verkey, metadata)로 나열하십시오. wallet이 오픈되어있어야 합니다.

indy> did list

 

Use

identity 소유자가 필요한 명령에 대해 DID를 identity 소유자로 사용하십시오.

indy> did use [did=]<did>

Rotate key

사용된 DID의 키를 회전합니다. 업데이트 된 키를 사용하여 NYM을 원장에 전송합니다. 오픈된 wallet과 pool 연결이 필요합니다.

indy> did rotate-key [seed=<UTF-8, base64 or hex string>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>]

Ledger transactions/messages

indy> ledger <subcommand>

 

NYM transaction

NYM 트랜잭션 전송

ledger nym did=<did-value> [verkey=<verkey-value>] [role=<role-value>] [source_payment_address=<source_payment_address-value>] [fee=<fee-value>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>] [send=<true or false>] [endorser=<endorser did>]

GET_NYM transaction

GET_NYM 트랜잭션 전송

ledger get-nym did=<did-value> [send=<true or false>]

ATTRIB transaction

ATTRIB 트랜잭션 전송

ledger attrib did=<did-value> [hash=<hash-value>] [raw=<raw-value>] [enc=<enc-value>] [source_payment_address=<source_payment_address-value>] [fee=<fee-value>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>]  [send=<true or false>] [endorser=<endorser did>]

GET_ATTRIB transaction

GET_ATTRIB 트랜잭션 전송

ledger get-attrib did=<did-value> [raw=<raw-value>] [hash=<hash-value>] [enc=<enc-value>] [send=<true or false>]

SCHEMA transaction

SCHEMA 트랜잭션 전송

ledger schema name=<name-value> version=<version-value> attr_names=<attr_names-value> [source_payment_address=<source_payment_address-value>] [fee=<fee-value>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>]  [send=<true or false>] [endorser=<endorser did>]

GET_SCHEMA transaction

ledger get-schema did=<did-value> name=<name-value> version=<version-value> [send=<true or false>]

CRED_DEF transaction

CRED_DEF 트랜잭션 전송

ledger cred-def schema_id=<schema_id-value> signature_type=<signature_type-value> [tag=<tag>] primary=<primary-value> [revocation=<revocation-value>] [source_payment_address=<source_payment_address-value>] [fee=<fee-value>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>]  [send=<true or false>] [endorser=<endorser did>]

GET_CRED_DEF transaction

GET_CRED_DEF 트랜잭션 전송

ledger get-cred-def schema_id=<schema_id-value> signature_type=<signature_type-value> origin=<origin-value> [send=<true or false>]

NODE transaction

NODE 트랜잭션 전송

ledger node target=<target-value> alias=<alias-value> [node_ip=<node_ip-value>] [node_port=<node_port-value>] [client_ip=<client_ip-value>] [client_port=<client_port-value>] [blskey=<blskey-value>] [blskey_pop=<blskey-proof-of-possession>] [services=<services-value>] [sign=<true or false>]  [send=<true or false>]

GET_VALIDATOR_INFO transaction

모든 노드에서 정보를 얻기 위해 GET_VALIDATOR_INFO 트랜잭션 전송

ledger get-validator-info [nodes=<node names>] [timeout=<timeout>]

POOL_UPGRADE transaction

POOL_UPGRADE 트랜잭션 전송

ledger pool-upgrade name=<name> version=<version> action=<start or cancel> sha256=<sha256> [timeout=<timeout>] [schedule=<schedule>] [justification=<justification>] [reinstall=<true or false (default false)>] [force=<true or false (default false)>] [package=<package>] [sign=<true or false>]  [send=<true or false>]

POOL_CONFIG transaction

POOL_CONFIG 트랜잭션 전송

ledger pool-config writes=<true or false (default false)> [force=<true or false (default false)>] [sign=<true or false>]  [send=<true or false>]

POOL_RESTART transaction

POOL_RESTART 트랜잭션 전송

ledger pool-restart action=<start or cancel> [datetime=<datetime>] [nodes=<node names>] [timeout=<timeout>]

Custom transaction

사용자 정의 json body 및 선택적 서명으로 custom 트랜잭션 전송

ledger custom [txn=]<txn-json-value> [sign=<true|false>]

AUTH_RULE transaction

AUTH_RULE 트랜잭션 전송

ledger auth-rule txn_type=<txn type> action=<add or edit> field=<txn field> [old_value=<value>] [new_value=<new_value>] constraint=<{constraint json}> [sign=<true or false>]  [send=<true or false>]

GET_AUTH_RULE transaction

GET_AUTH_RULE 트랜잭션 전송

ledger get-auth-rule [txn_type=<txn type>] [action=<ADD or EDIT>] [field=<txn field>] [old_value=<value>] [new_value=<new_value>] [send=<true or false>]

GET_PAYMENT_SOURCES transaction

GET_PAYMENT_SOURCES 트랜잭션 전송

ledger get-payment-sources payment_address=<payment_address> [send=<true or false>]

PAYMENT transaction

PAYMENT 트랜잭션 전송

ledger payment [source_payment_address=<payment address>] [target_payment_address=<payment address>] [amount=<number>] [fee=<transaction fee amount>] [inputs=<source-1>,..,<source-n>] [outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>]  [send=<true or false>]

GET_FEES transaction

GET_FEES 트랜잭션 전송

ledger get-fees payment_method=<payment_method> [send=<true or false>]

MINT transaction

MINT 트랜잭션 준비

ledger mint-prepare outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>) [extra=<extra>]

SET_FEES transaction

SET_FEES 트랜잭션 준비

ledger set-fees-prepare payment_method=<payment_method> fees=<txn-type-1>:<amount-1>,..,<txn-type-n>:<amount-n>

VERIFY_PAYMENT_RECEIPT transaction

VERIFY_PAYMENT_RECEIPT 트랜잭션 준비

ledger verify-payment-receipt <receipt> [send=<true or false>]

Add multi signature to transaction

현재 DID 별 다중 서명을 트랜잭션에 추가

ledger sign-multi txn=<txn_json>

Save transaction to a file.

CLI 컨텍스트 트랜잭션에 저장된 파일로 저장

ledger save-transaction file=<path to file>

Load transaction from a file.

파일에서 트랜잭션을 읽고 CLI 컨텍스트에 저장

ledger load-transaction file=<path to file>

TXN_AUTHR_AGRMT transaction.

원장에 새 버전의 Transaction Author Agreement 추가 요청

ledger ledger txn-author-agreement [text=<agreement content>] [file=<file with agreement>] version=<version> [source_payment_address=<source_payment_address-value>] [fee=<fee-value>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>]  [send=<true or false>]

SET_TXN_AUTHR_AGRMT_AML transaction.

Transaction Author Agreement를 위한 새로운 수락 메커니즘 추가 요청

ledger txn-acceptance-mechanisms [aml=<acceptance mechanisms>] [file=<file with acceptance mechanisms>] version=<version> [context=<some context>] [source_payment_address=<source_payment_address-value>] [fee=<fee-value>] [fees_inputs=<source-1,..,source-n>] [fees_outputs=(<recipient-1>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>] [sign=<true or false>]  [send=<true or false>]

 

Payment Address commands

indy> payment-address <subcommand>

Create

지정된 지불 방법에 대한 지불 주소 생성. 오픈된 wallet이 필요.

payment-address create payment_method=<payment_method> [seed=<seed-value>]

List

모든 지불 주소 나열. 오픈된 wallet 필요.

payment-address list

Sign

입력에 서명하고 서명을 생성하여 지불 증명 주소 제어를 생성

payment-address sign address=<payment_address> input=<string to sign>

Verify

서명을 확인하여 지불 증명 주소 제어를 검증

payment-address verify address=<payment_address> input=<signed string> signature=<signature>

 

Examples

Create pool configuration and connect to pool

indy> pool create sandbox gen_txn_file=/etc/sovrin/sandbox.txn
indy> pool connect sandbox
pool(sandbox):indy> pool list

 

Create and open wallet

sandbox|indy> wallet create alice_wallet key
sandbox|indy> wallet open alice_wallet key
pool(sandbox):wallet(alice_wallet):indy> wallet list

 

Create DID in the wallet from seed and use it for the next commands

pool(sandbox):wallet(alice_wallet):indy> did new seed=SEED0000000000000000000000000001 metadata="Alice DID"
pool(sandbox):wallet(alice_wallet):indy> did use MYDID000000000000000000001
pool(sandbox):wallet(alice_wallet):did(MYD...001):indy> did list

 

Create new DID for BOB

pool(sandbox):wallet(alice_wallet):did(MYD...001):indy> did new metadata="Bob DID"

 

Post new NYM to the ledger

pool(sandbox):wallet(alice_wallet):did(MYD...001):indy> ledger nym did=MYDID000000000000000000001

 

Send GET_NYM transaction

pool(sandbox):wallet(alice_wallet):did(MYD...001):indy> ledger get-nym did=MYDID000000000000000000001

 

Anoncreds Design

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/002-anoncreds/README.html

여기서 Indy SDK Anoncreds 워크 플로우(해지 포함)의 요구 사항과 디자인을 찾을 수 있습니다.

 

Anoncreds References

Anoncreds 프로토콜 링크:

 

Design Goals

  • Indy SDK와 Indy Node는 공개 Anoncreds 엔티티(Schema, Credential Definition, Revocation Registry Definition, Revocation Registry Delta)에 대해 동일한 형식을 사용해야합니다.
  • Indy SDK와 Indy Node는 동일한 엔티티 참조 접근 방식을 사용해야합니다.
  • API 변경을 중단하지 않고 추가 credential 서명 및 해지 스키마를 통합할 수 있어야합니다.
  • API는 해지 tails files를 처리하기 위한 유연하고 플러그 가능한 접근 방식을 제공해야합니다.
  • API는 엣지 디바이스(edge devices)에서 hole tails file이 다운로드되지 않도록 클라우드 agent에서 해지 증거 값을 계산하는 방법을 제공해야합니다.

 

Anoncreds Workflow

API

Issuer

/// Create credential schema entity that describes credential attributes list and allows credentials
/// interoperability.
///
/// Schema is public and intended to be shared with all anoncreds workflow actors usually by publishing SCHEMA transaction
/// to Indy distributed ledger.
///
/// It is IMPORTANT for current version POST Schema in Ledger and after that GET it from Ledger
/// with correct seq_no to save compatibility with Ledger.
/// After that can call indy_issuer_create_and_store_credential_def to build corresponding Credential Definition.
///
/// #Params
/// command_handle: command handle to map callback to user context
/// issuer_did: DID of schema issuer
/// name: a name the schema
/// version: a version of the schema
/// attrs: a list of schema attributes descriptions
/// cb: Callback that takes command result as parameter
///
/// #Returns
/// schema_id: identifier of created schema
/// schema_json: schema as json
///
/// #Errors
/// Common*
/// Anoncreds*
#[no_mangle]
pub extern fn indy_issuer_create_schema(command_handle: i32,
                                        issuer_did: *const c_char,
                                        name: *const c_char,
                                        version: *const c_char,
                                        attrs: *const c_char,
                                        cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                             schema_id: *const c_char, schema_json: *const c_char)>) -> ErrorCode
/// Create credential definition entity that encapsulates credentials issuer DID, credential schema, secrets used for signing credentials
/// and secrets used for credentials revocation.
///
/// Credential definition entity contains private and public parts. Private part will be stored in the wallet. Public part
/// will be returned as json intended to be shared with all anoncreds workflow actors usually by publishing CRED_DEF transaction
/// to Indy distributed ledger.
///
/// It is IMPORTANT for current version GET Schema from Ledger with correct seq_no to save compatibility with Ledger.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// issuer_did: a DID of the issuer signing cred_def transaction to the Ledger
/// schema_json: credential schema as a json
/// tag: allows to distinct between credential definitions for the same issuer and schema
/// signature_type: credential definition type (optional, 'CL' by default) that defines credentials signature and revocation math. Supported types are:
/// - 'CL': Camenisch-Lysyanskaya credential signature type
/// config_json: type-specific configuration of credential definition as json:
/// - 'CL':
///   - support_revocation: whether to request non-revocation credential (optional, default false)
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// cred_def_id: identifier of created credential definition
/// cred_def_json: public part of created credential definition
///
/// #Errors
/// Common*
/// Wallet*
/// Anoncreds*
#[no_mangle]
pub extern fn indy_issuer_create_and_store_credential_def(command_handle: i32,
                                                          wallet_handle: i32,
                                                          issuer_did: *const c_char,
                                                          schema_json: *const c_char,
                                                          tag: *const c_char,
                                                          signature_type: *const c_char,
                                                          config_json: *const c_char,
                                                          cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                               cred_def_id: *const c_char,
                                                                               cred_def_json: *const c_char)>) -> ErrorCode
/// Create a new revocation registry for the given credential definition as tuple of entities:
/// - Revocation registry definition that encapsulates credentials definition reference, revocation type specific configuration and
///   secrets used for credentials revocation
/// - Revocation registry state that stores the information about revoked entities in a non-disclosing way. The state can be
///   represented as ordered list of revocation registry entries were each entry represents the list of revocation or issuance operations.
///
/// Revocation registry definition entity contains private and public parts. Private part will be stored in the wallet. Public part
/// will be returned as json intended to be shared with all anoncreds workflow actors usually by publishing REVOC_REG_DEF transaction
/// to Indy distributed ledger.
///
/// Revocation registry state is stored on the wallet and also intended to be shared as the ordered list of REVOC_REG_ENTRY transactions.
/// This call initializes the state in the wallet and returns the initial entry.
///
/// Some revocation registry types (for example, 'CL_ACCUM') can require generation of binary blob called tails used to hide information about revoked credentials in public
/// revocation registry and intended to be distributed out of leger (REVOC_REG_DEF transaction will still contain uri and hash of tails).
/// This call requires access to pre-configured blob storage writer instance handle that will allow to write generated tails.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// issuer_did: a DID of the issuer signing transaction to the Ledger
/// revoc_def_type: revocation registry type (optional, default value depends on credential definition type). Supported types are:
/// - 'CL_ACCUM': Type-3 pairing based accumulator. Default for 'CL' credential definition type
/// tag: allows to distinct between revocation registries for the same issuer and credential definition
/// cred_def_id: id of stored in ledger credential definition
/// config_json: type-specific configuration of revocation registry as json:
/// - 'CL_ACCUM': {
///     "issuance_type": (optional) type of issuance. Currently supported:
///         1) ISSUANCE_BY_DEFAULT: all indices are assumed to be issued and initial accumulator is calculated over all indices;
///            Revocation Registry is updated only during revocation.
///         2) ISSUANCE_ON_DEMAND: nothing is issued initially accumulator is 1 (used by default);
///     "max_cred_num": maximum number of credentials the new registry can process (optional, default 100000)
/// }
/// tails_writer_handle: handle of blob storage to store tails
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// revoc_reg_id: identifier of created revocation registry definition
/// revoc_reg_def_json: public part of revocation registry definition
/// revoc_reg_entry_json: revocation registry entry that defines initial state of revocation registry
///
/// #Errors
/// Common*
/// Wallet*
/// Anoncreds*
#[no_mangle]
pub extern fn indy_issuer_create_and_store_revoc_reg(command_handle: i32,
                                                     wallet_handle: i32,
                                                     blob_storage_writer_handle: i32,
                                                     cred_def_id:  *const c_char,
                                                     tag: *const c_char,
                                                     revoc_def_type: *const c_char,
                                                     config_json: *const c_char,
                                                     cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                          revoc_reg_def_id: *const c_char,
                                                                          revoc_reg_def_json: *const c_char,
                                                                          revoc_reg_entry_json: *const c_char)>) -> ErrorCode
/// Create credential offer that will be used by Prover for
/// credential request creation. Offer includes nonce and key correctness proof
/// for authentication between protocol steps and integrity checking.
///
/// #Params
/// command_handle: command handle to map callback to user context
/// wallet_handle: wallet handler (created by open_wallet)
/// cred_def_id: id of credential definition stored in the wallet
/// cb: Callback that takes command result as parameter
///
/// #Returns
/// credential offer json:
///     {
///         "schema_id": string,
///         "cred_def_id": string,
///         // Fields below can depend on Cred Def type
///         "nonce": string,
///         "key_correctness_proof" : <key_correctness_proof>
///     }
///
/// #Errors
/// Common*
/// Wallet*
/// Anoncreds*
#[no_mangle]
pub extern fn indy_issuer_create_credential_offer(command_handle: i32,
                                                  wallet_handle: i32,
                                                  cred_def_id: *const c_char,
                                                  cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                       cred_offer_json: *const c_char)>) -> ErrorCode
/// Check Cred Request for the given Cred Offer and issue Credential for the given Cred Request.
///
/// Cred Request must match Cred Offer. The credential definition and revocation registry definition
/// referenced in Cred Offer and Cred Request must be already created and stored into the wallet.
///
/// Information for this credential revocation will be store in the wallet as part of revocation registry under
/// generated cred_revoc_id local for this wallet.
///
/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction.
/// Note that it is possible to accumulate deltas to reduce ledger load.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// cred_offer_json: a cred offer created by indy_issuer_create_credential_offer
/// cred_req_json: a credential request created by indy_prover_create_credential_req
/// cred_values_json: a credential containing attribute values for each of requested attribute names.
///     Example:
///     {
///      "attr1" : {"raw": "value1", "encoded": "value1_as_int" },
///      "attr2" : {"raw": "value1", "encoded": "value1_as_int" }
///     }
/// rev_reg_id: id of revocation registry stored in the wallet
/// blob_storage_reader_handle: configuration of blob storage reader handle that will allow to read revocation tails
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// cred_json: Credential json containing signed credential values
///     {
///         "schema_id": string,
///         "cred_def_id": string,
///         "rev_reg_def_id", Optional<string>,
///         "values": <see cred_values_json above>,
///         // Fields below can depend on Cred Def type
///         "signature": <signature>,
///         "signature_correctness_proof": <signature_correctness_proof>
///     }
/// cred_revoc_id: local id for revocation info (Can be used for revocation of this credential)
/// revoc_reg_delta_json: Revocation registry delta json with a newly issued credential
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_issuer_create_credential(command_handle: i32,
                                            wallet_handle: i32,
                                            cred_offer_json: *const c_char,
                                            cred_req_json: *const c_char,
                                            cred_values_json: *const c_char,
                                            rev_reg_id: *const c_char,
                                            blob_storage_reader_handle: i32,
                                            cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                 cred_revoc_id: *const c_char,
                                                                 revoc_reg_delta_json: *const c_char,
                                                                 cred_json: *const c_char)>) -> ErrorCode
/// Revoke a credential identified by a cred_revoc_id (returned by indy_issuer_create_credential).
///
/// The corresponding credential definition and revocation registry must be already
/// created an stored into the wallet.
///
/// This call returns revoc registry delta as json file intended to be shared as REVOC_REG_ENTRY transaction.
/// Note that it is possible to accumulate deltas to reduce ledger load.
///
/// #Params
/// command_handle: command handle to map callback to user context.
/// wallet_handle: wallet handler (created by open_wallet).
/// blob_storage_reader_cfg_handle: configuration of blob storage reader handle that will allow to read revocation tails
/// rev_reg_id: id of revocation registry stored in wallet
/// cred_revoc_id: local id for revocation info
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// revoc_reg_delta_json: Revocation registry delta json with a revoked credential
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_issuer_revoke_cred(command_handle: i32,
                                      wallet_handle: i32,
                                      blob_storage_reader_handle: i32,
                                      cred_revoc_id: *const c_char,
                                      cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                           revoc_reg_delta_json: *const c_char)>) -> ErrorCode
/// Merge two revocation registry deltas (returned by indy_issuer_create_credential or indy_issuer_revoke_credential) to accumulate common delta.
/// Send common delta to ledger to reduce the load.
///
/// #Params
/// command_handle: command handle to map callback to user context.
/// rev_reg_delta_json: revocation registry delta.
/// other_rev_reg_delta_json: revocation registry delta for which PrevAccum value  is equal to current accum value of rev_reg_delta_json.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// merged_rev_reg_delta: Merged revocation registry delta
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_issuer_merge_revocation_registry_deltas(command_handle: i32,
                                                           rev_reg_delta_json: *const c_char,
                                                           other_rev_reg_delta_json: *const c_char,
                                                           cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                                merged_rev_reg_delta: *const c_char)>) -> ErrorCode

Prover

/// Creates a master secret with a given id and stores it in the wallet.
/// The id must be unique.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// master_secret_id: (optional, if not present random one will be generated) new master id
///
/// #Returns
/// out_master_secret_id: Id of generated master secret
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_create_master_secret(command_handle: i32,
                                               wallet_handle: i32,
                                               master_secret_id: *const c_char,
                                               cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                    out_master_secret_id: *const c_char)>) -> ErrorCode
/// Creates a credential request for the given credential offer.
///
/// The method creates a blinded master secret for a master secret identified by a provided name.
/// The master secret identified by the name must be already stored in the secure wallet (see prover_create_master_secret)
/// The blinded master secret is a part of the credential request.
///
/// #Params
/// command_handle: command handle to map callback to user context
/// wallet_handle: wallet handler (created by open_wallet)
/// prover_did: a DID of the prover
/// cred_offer_json: credential offer as a json containing information about the issuer and a credential
/// cred_def_json: credential definition json related to <cred_def_id> in <cred_offer_json> 
/// master_secret_id: the id of the master secret stored in the wallet
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// cred_req_json: Credential request json for creation of credential by Issuer
///     {
///      "prover_did" : string,
///      "cred_def_id" : string,
///         // Fields below can depend on Cred Def type
///      "blinded_ms" : <blinded_master_secret>,
///      "blinded_ms_correctness_proof" : <blinded_ms_correctness_proof>,
///      "nonce": string
///    }
/// cred_req_metadata_json: Credential request metadata json for further processing of received form Issuer credential.
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_create_credential_req(command_handle: i32,
                                                wallet_handle: i32,
                                                prover_did: *const c_char,
                                                cred_offer_json: *const c_char,
                                                cred_def_json: *const c_char,
                                                master_secret_id: *const c_char,
                                                cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                     cred_req_json: *const c_char)>) -> ErrorCode
/// Check credential provided by Issuer for the given credential request,
/// updates the credential by a master secret and stores in a secure wallet.
///
/// To support efficient and flexible search the following tags will be created for stored credential:
///     {
///         "schema_id": <credential schema id>,
///         "schema_issuer_did": <credential schema issuer did>,
///         "schema_name": <credential schema name>,
///         "schema_version": <credential schema version>,
///         "issuer_did": <credential issuer did>,
///         "cred_def_id": <credential definition id>,
///         "rev_reg_id": <credential revocation registry id>, // "None" as string if not present
///         // for every attribute in <credential values>
///         "attr::<attribute name>::marker": "1",
///         "attr::<attribute name>::value": <attribute raw value>,
///     }
/// 
/// #Params
/// command_handle: command handle to map callback to user context.
/// wallet_handle: wallet handler (created by open_wallet).
/// cred_id: (optional, default is a random one) identifier by which credential will be stored in the wallet
/// cred_req_metadata_json: a credential request metadata created by indy_prover_create_credential_req
/// cred_json: credential json received from issuer
/// cred_def_json: credential definition json related to <cred_def_id> in <cred_json>
/// rev_reg_def_json: revocation registry definition json related to <rev_reg_def_id> in <cred_json>
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// out_cred_id: identifier by which credential is stored in the wallet
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_store_credential(command_handle: i32,
                                           wallet_handle: i32,
                                           cred_id: *const c_char,
                                           cred_req_metadata_json: *const c_char,
                                           cred_json: *const c_char,
                                           cred_def_json: *const c_char,
                                           rev_reg_def_json: *const c_char,
                                           cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                                out_cred_id: *const c_char)>) -> ErrorCode
/// Gets human readable credential by the given id.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// cred_id: Identifier by which requested credential is stored in the wallet
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// credential json:
///     {
///         "referent": string, // cred_id in the wallet
///         "attrs": {"key1":"raw_value1", "key2":"raw_value2"},
///         "schema_id": string,
///         "cred_def_id": string,
///         "rev_reg_id": Optional<string>,
///         "cred_rev_id": Optional<string>
///     }
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_get_credential(command_handle: i32,
                                         wallet_handle: i32,
                                         cred_id: *const c_char,
                                         cb: Option<extern fn(
                                             xcommand_handle: i32, err: ErrorCode,
                                             credential_json: *const c_char)>) -> ErrorCode
/// Gets human readable credentials according to the filter.
/// If filter is NULL, then all credentials are returned.
/// Credentials can be filtered by Issuer, credential_def and/or Schema.
///
/// NOTE: This method is deprecated because immediately returns all fetched credentials.
/// Use <indy_prover_search_credentials> to fetch records by small batches.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// filter_json: filter for credentials
///        {
///            "schema_id": string, (Optional)
///            "schema_issuer_did": string, (Optional)
///            "schema_name": string, (Optional)
///            "schema_version": string, (Optional)
///            "issuer_did": string, (Optional)
///            "cred_def_id": string, (Optional)
///        }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// credentials json
///     [{
///         "referent": string, // cred_id in the wallet
///         "attrs": {"key1":"raw_value1", "key2":"raw_value2"},
///         "schema_id": string,
///         "cred_def_id": string,
///         "rev_reg_id": Optional<string>,
///         "cred_rev_id": Optional<string>
///     }]
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_get_credentials(command_handle: i32,
                                          wallet_handle: i32,
                                          filter_json: *const c_char,
                                          cb: Option<extern fn(
                                              xcommand_handle: i32, err: ErrorCode,
                                              matched_credentials_json: *const c_char)>) -> ErrorCode
/// Search for credentials stored in wallet.
/// Credentials can be filtered by tags created during saving of credential.
///
/// Instead of immediately returning of fetched credentials
/// this call returns search_handle that can be used later
/// to fetch records by small batches (with indy_prover_fetch_credentials).
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// query_json: Wql style filter for credentials searching based on tags.
///     where wql query: indy-sdk/docs/design/011-wallet-query-language/README.md
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// search_handle: Search handle that can be used later to fetch records by small batches (with indy_prover_fetch_credentials)
/// total_count: Total count of records
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_search_credentials(command_handle: i32,
                                             wallet_handle: i32,
                                             query_json: *const c_char,
                                             cb: Option<extern fn(
                                                 xcommand_handle: i32, err: ErrorCode,
                                                 search_handle: i32,
                                                 total_count: usize)>) -> ErrorCode
                                                 
/// Fetch next credentials for search.
///
/// #Params
/// search_handle: Search handle (created by indy_prover_search_credentials) 
/// count: Count of credentials to fetch
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// credentials_json: List of human readable credentials:
///     [{
///         "referent": string, // cred_id in the wallet
///         "attrs": {"key1":"raw_value1", "key2":"raw_value2"},
///         "schema_id": string,
///         "cred_def_id": string,
///         "rev_reg_id": Optional<string>,
///         "cred_rev_id": Optional<string>
///     }]
/// NOTE: The list of length less than the requested count means credentials search iterator is completed.
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub  extern fn indy_prover_fetch_credentials(command_handle: i32,
                                             search_handle: i32,
                                             count: usize,
                                             cb: Option<extern fn(command_handle_: i32, err: ErrorCode,
                                                                  credentials_json: *const c_char)>) -> ErrorCode

/// Close credentials search (make search handle invalid)
///
/// #Params
/// search_handle: Search handle (created by indy_prover_search_credentials)
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub  extern fn indy_prover_close_credentials_search(command_handle: i32,
                                                    search_handle: i32,
                                                    cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode
/// Gets human readable credentials matching the given proof request.
///
/// NOTE: This method is deprecated because immediately returns all fetched credentials.
/// Use <indy_prover_search_credentials_for_proof_req> to fetch records by small batches.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// proof_request_json: proof request json
///     {
///         "name": string,
///         "version": string,
///         "nonce": string,
///         "requested_attributes": { // set of requested attributes
///              "<attr_referent>": <attr_info>, // see below
///              ...,
///         },
///         "requested_predicates": { // set of requested predicates
///              "<predicate_referent>": <predicate_info>, // see below
///              ...,
///          },
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval for each attribute
///                        // (can be overridden on attribute level)
///     }
/// cb: Callback that takes command result as parameter.
///
/// where
/// attr_referent: Proof-request local identifier of requested attribute
/// attr_info: Describes requested attribute
///     {
///         "name": string, // attribute name, (case insensitive and ignore spaces)
///         "restrictions": Optional<filter_json>, // see above
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval this attribute
///                        // (overrides proof level interval)
///     }
/// predicate_referent: Proof-request local identifier of requested attribute predicate
/// predicate_info: Describes requested attribute predicate
///     {
///         "name": attribute name, (case insensitive and ignore spaces)
///         "p_type": predicate type (Currently ">=" only)
///         "p_value": int predicate value
///         "restrictions": Optional<filter_json>, // see above
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval this attribute
///                        // (overrides proof level interval)
///     }
/// non_revoc_interval: Defines non-revocation interval
///     {
///         "from": Optional<int>, // timestamp of interval beginning
///         "to": Optional<int>, // timestamp of interval ending
///     }
///
/// #Returns
/// credentials_json: json with credentials for the given proof request.
///     {
///         "requested_attrs": {
///             "<attr_referent>": [{ cred_info: <credential_info>, interval: Optional<non_revoc_interval> }],
///             ...,
///         },
///         "requested_predicates": {
///             "requested_predicates": [{ cred_info: <credential_info>, timestamp: Optional<integer> }, { cred_info: <credential_2_info>, timestamp: Optional<integer> }],
///             "requested_predicate_2_referent": [{ cred_info: <credential_2_info>, timestamp: Optional<integer> }]
///         }
///     }, where credential is
///     {
///         "referent": <string>,
///         "attrs": {"attr_name" : "attr_raw_value"},
///         "schema_id": string,
///         "cred_def_id": string,
///         "rev_reg_id": Optional<int>,
///         "cred_rev_id": Optional<int>,
///     }
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_get_credentials_for_proof_req(command_handle: i32,
                                                        wallet_handle: i32,
                                                        proof_request_json: *const c_char,
                                                        cb: Option<extern fn(
                                                            xcommand_handle: i32, err: ErrorCode,
                                                            credentials_json: *const c_char)>) -> ErrorCode
/// Search for credentials matching the given proof request.
///
/// Instead of immediately returning of fetched credentials
/// this call returns search_handle that can be used later
/// to fetch records by small batches (with indy_prover_fetch_credentials_for_proof_req).
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// proof_request_json: proof request json
///     {
///         "name": string,
///         "version": string,
///         "nonce": string,
///         "requested_attributes": { // set of requested attributes
///              "<attr_referent>": <attr_info>, // see below
///              ...,
///         },
///         "requested_predicates": { // set of requested predicates
///              "<predicate_referent>": <predicate_info>, // see below
///              ...,
///          },
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval for each attribute
///                        // (can be overridden on attribute level)
///     }
/// extra_query_json:(Optional) List of extra queries that will be applied to correspondent attribute/predicate:
///     {
///         "<attr_referent>": <wql query>,
///         "<predicate_referent>": <wql query>,
///     }
/// where wql query: indy-sdk/docs/design/011-wallet-query-language/README.md
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// search_handle: Search handle that can be used later to fetch records by small batches (with indy_prover_fetch_credentials_for_proof_req)
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_search_credentials_for_proof_req(command_handle: i32,
                                                           wallet_handle: i32,
                                                           proof_request_json: *const c_char,
                                                           extra_query_json: *const c_char,
                                                           cb: Option<extern fn(
                                                               xcommand_handle: i32, err: ErrorCode,
                                                               search_handle: i32)>) -> ErrorCode

/// Fetch next credentials for the requested item using proof request search 
/// handle (created by indy_prover_search_credentials_for_proof_req).
///
/// #Params
/// search_handle: Search handle (created by indy_prover_search_credentials_for_proof_req)
/// item_referent: Referent of attribute/predicate in the proof request
/// count: Count of credentials to fetch
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// credentials_json: List of credentials for the given proof request.
///     [{
///         cred_info: <credential_info>,
///         interval: Optional<non_revoc_interval>
///     }]
/// where 
/// credential_info:
///     {
///         "referent": <string>,
///         "attrs": {"attr_name" : "attr_raw_value"},
///         "schema_id": string,
///         "cred_def_id": string,
///         "rev_reg_id": Optional<int>,
///         "cred_rev_id": Optional<int>,
///     }
/// non_revoc_interval:
///     {
///         "from": Optional<int>, // timestamp of interval beginning
///         "to": Optional<int>, // timestamp of interval ending
///     }
/// NOTE: The list of length less than the requested count means that search iterator
/// correspondent to the requested <item_referent> is completed.
/// 
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub  extern fn indy_prover_fetch_credentials_for_proof_req(command_handle: i32,
                                                           search_handle: i32,
                                                           item_referent: *const c_char,
                                                           count: usize,
                                                           cb: Option<extern fn(command_handle_: i32, err: ErrorCode,
                                                                                    credentials_json: *const c_char)>) -> ErrorCode

/// Close credentials search for proof request (make search handle invalid)
///
/// #Params
/// search_handle: Search handle (created by indy_prover_search_credentials_for_proof_req)
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub  extern fn indy_prover_close_credentials_search_for_proof_req(command_handle: i32,
                                                                  search_handle: i32,
                                                                  cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode
/// Creates a proof according to the given proof request
/// Either a corresponding credential with optionally revealed attributes or self-attested attribute must be provided
/// for each requested attribute (see indy_prover_get_credentials_for_pool_req).
/// A proof request may request multiple credentials from different schemas and different issuers.
/// All required schemas, public keys and revocation registries must be provided.
/// The proof request also contains nonce.
/// The proof contains either proof or self-attested attribute value for each requested attribute.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// proof_request_json: proof request json
///     {
///         "name": string,
///         "version": string,
///         "nonce": string,
///         "requested_attributes": { // set of requested attributes
///              "<attr_referent>": <attr_info>, // see below
///              ...,
///         },
///         "requested_predicates": { // set of requested predicates
///              "<predicate_referent>": <predicate_info>, // see below
///              ...,
///          },
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval for each attribute
///                        // (can be overridden on attribute level)
///     }
/// requested_credentials_json: either a credential or self-attested attribute for each requested attribute
///     {
///         "self_attested_attributes": {
///             "self_attested_attribute_referent": string
///         },
///         "requested_attributes": {
///             "requested_attribute_referent_1": {"cred_id": string, "timestamp": Optional<number>, revealed: <bool> }},
///             "requested_attribute_referent_2": {"cred_id": string, "timestamp": Optional<number>, revealed: <bool> }}
///         },
///         "requested_predicates": {
///             "requested_predicates_referent_1": {"cred_id": string, "timestamp": Optional<number> }},
///         }
///     }
/// master_secret_id: the id of the master secret stored in the wallet
/// schemas_json: all schemas json participating in the proof request
///     {
///         <schema1_id>: <schema1_json>,
///         <schema2_id>: <schema2_json>,
///         <schema3_id>: <schema3_json>,
///     }
/// credential_defs_json: all credential definitions json participating in the proof request
///     {
///         "cred_def1_id": <credential_def1_json>,
///         "cred_def2_id": <credential_def2_json>,
///         "cred_def3_id": <credential_def3_json>,
///     }
/// rev_states_json: all revocation states json participating in the proof request
///     {
///         "rev_reg_def1_id": {
///             "timestamp1": <rev_state1>,
///             "timestamp2": <rev_state2>,
///         },
///         "rev_reg_def2_id": {
///             "timestamp3": <rev_state3>
///         },
///         "rev_reg_def3_id": {
///             "timestamp4": <rev_state4>
///         },
///     }
/// cb: Callback that takes command result as parameter.
///
/// where
/// wql query: indy-sdk/docs/design/011-wallet-query-language/README.md
/// attr_referent: Proof-request local identifier of requested attribute
/// attr_info: Describes requested attribute
///     {
///         "name": string, // attribute name, (case insensitive and ignore spaces)
///         "restrictions": Optional<filter_json> // see above.
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval this attribute
///                        // (overrides proof level interval)
///     }
/// predicate_referent: Proof-request local identifier of requested attribute predicate
/// predicate_info: Describes requested attribute predicate
///     {
///         "name": attribute name, (case insensitive and ignore spaces)
///         "p_type": predicate type (Currently >= only)
///         "p_value": predicate value
///         "restrictions": Optional<wql query>,
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval this attribute
///                        // (overrides proof level interval)
///     }
/// non_revoc_interval: Defines non-revocation interval
///     {
///         "from": Optional<int>, // timestamp of interval beginning
///         "to": Optional<int>, // timestamp of interval ending
///     }
///
/// #Returns
/// Proof json
/// For each requested attribute either a proof (with optionally revealed attribute value) or
/// self-attested attribute value is provided.
/// Each proof is associated with a credential and corresponding schema_id, cred_def_id, rev_reg_id and timestamp.
/// There is also aggregated proof part common for all credential proofs.
///     {
///         "requested": {
///             "revealed_attrs": {
///                 "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string},
///                 "requested_attr4_id": {sub_proof_index: number: string, encoded: string},
///             },
///             "unrevealed_attrs": {
///                 "requested_attr3_id": {sub_proof_index: number}
///             },
///             "self_attested_attrs": {
///                 "requested_attr2_id": self_attested_value,
///             },
///             "requested_predicates": {
///                 "requested_predicate_1_referent": {sub_proof_index: int},
///                 "requested_predicate_2_referent": {sub_proof_index: int},
///             }
///         }
///         "proof": {
///             "proofs": [ <credential_proof>, <credential_proof>, <credential_proof> ],
///             "aggregated_proof": <aggregated_proof>
///         }
///         "identifiers": [{schema_id, cred_def_id, Optional<rev_reg_id>, Optional<timestamp>}]
///     }
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_prover_create_proof(command_handle: i32,
                                       wallet_handle: i32,
                                       proof_req_json: *const c_char,
                                       requested_credentials_json: *const c_char,
                                       master_secret_id: *const c_char,
                                       schemas_json: *const c_char,
                                       credential_defs_json: *const c_char,
                                       rev_states_json: *const c_char,
                                       cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                            proof_json: *const c_char)>) -> ErrorCode
/// Verifies a proof (of multiple credential).
/// All required schemas, public keys and revocation registries must be provided.
///
/// #Params
/// wallet_handle: wallet handler (created by open_wallet).
/// command_handle: command handle to map callback to user context.
/// proof_request_json: proof request json
///     {
///         "name": string,
///         "version": string,
///         "nonce": string,
///         "requested_attributes": { // set of requested attributes
///              "<attr_referent>": <attr_info>, // see below
///              ...,
///         },
///         "requested_predicates": { // set of requested predicates
///              "<predicate_referent>": <predicate_info>, // see below
///              ...,
///          },
///         "non_revoked": Optional<<non_revoc_interval>>, // see below,
///                        // If specified prover must proof non-revocation
///                        // for date in this interval for each attribute
///                        // (can be overridden on attribute level)
///     }
/// proof_json: created for request proof json
///     {
///         "requested": {
///             "revealed_attrs": {
///                 "requested_attr1_id": {sub_proof_index: number, raw: string, encoded: string},
///                 "requested_attr4_id": {sub_proof_index: number: string, encoded: string},
///             },
///             "unrevealed_attrs": {
///                 "requested_attr3_id": {sub_proof_index: number}
///             },
///             "self_attested_attrs": {
///                 "requested_attr2_id": self_attested_value,
///             },
///             "requested_predicates": {
///                 "requested_predicate_1_referent": {sub_proof_index: int},
///                 "requested_predicate_2_referent": {sub_proof_index: int},
///             }
///         }
///         "proof": {
///             "proofs": [ <credential_proof>, <credential_proof>, <credential_proof> ],
///             "aggregated_proof": <aggregated_proof>
///         }
///         "identifiers": [{schema_id, cred_def_id, Optional<rev_reg_id>, Optional<timestamp>}]
///     }
/// schemas_json: all schema jsons participating in the proof
///     {
///         <schema1_id>: <schema1_json>,
///         <schema2_id>: <schema2_json>,
///         <schema3_id>: <schema3_json>,
///     }
/// credential_defs_json: all credential definitions json participating in the proof
///     {
///         "cred_def1_id": <credential_def1_json>,
///         "cred_def2_id": <credential_def2_json>,
///         "cred_def3_id": <credential_def3_json>,
///     }
/// rev_reg_defs_json: all revocation registry definitions json participating in the proof
///     {
///         "rev_reg_def1_id": <rev_reg_def1_json>,
///         "rev_reg_def2_id": <rev_reg_def2_json>,
///         "rev_reg_def3_id": <rev_reg_def3_json>,
///     }
/// rev_regs_json: all revocation registries json participating in the proof
///     {
///         "rev_reg_def1_id": {
///             "timestamp1": <rev_reg1>,
///             "timestamp2": <rev_reg2>,
///         },
///         "rev_reg_def2_id": {
///             "timestamp3": <rev_reg3>
///         },
///         "rev_reg_def3_id": {
///             "timestamp4": <rev_reg4>
///         },
///     }
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// valid: true - if signature is valid, false - otherwise
///
/// #Errors
/// Annoncreds*
/// Common*
/// Wallet*
#[no_mangle]
pub extern fn indy_verifier_verify_proof(command_handle: i32,
                                         proof_request_json: *const c_char,
                                         proof_json: *const c_char,
                                         schemas_json: *const c_char,
                                         credential_defs_json: *const c_char,
                                         rev_reg_defs_json: *const c_char,
                                         rev_regs_json: *const c_char,
                                         cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode,
                                                              valid: bool)>) -> ErrorCode
/// Create revocation state for a credential in the particular time moment.
///
/// #Params
/// command_handle: command handle to map callback to user context
/// blob_storage_reader_handle: configuration of blob storage reader handle that will allow to read revocation tails
/// rev_reg_def_json: revocation registry definition json
/// rev_reg_delta_json: revocation registry definition delta json
/// timestamp: time represented as a total number of seconds from Unix Epoch
/// cred_rev_id: user credential revocation id in revocation registry
/// cb: Callback that takes command result as parameter
///
/// #Returns
/// revocation state json:
///     {
///         "rev_reg": <revocation registry>,
///         "witness": <witness>,
///         "timestamp" : integer
///     }
///
/// #Errors
/// Common*
/// Wallet*
/// Anoncreds*
#[no_mangle]
pub extern fn indy_create_revocation_state(command_handle: i32,
                                           blob_storage_reader_handle: i32,
                                           rev_reg_def_json: *const c_char,
                                           rev_reg_delta_json: *const c_char,
                                           timestamp: u64,
                                           cred_rev_id: *const c_char,
                                           cb: Option<extern fn(
                                               xcommand_handle: i32, err: ErrorCode,
                                               rev_state_json: *const c_char
                                           )>) -> ErrorCode
/// Create new revocation state for a credential based on existed state
/// at the particular time moment (to reduce calculation time).
///
/// #Params
/// command_handle: command handle to map callback to user context
/// blob_storage_reader_handle: configuration of blob storage reader handle that will allow to read revocation tails
/// rev_state_json: revocation registry state json
/// rev_reg_def_json: revocation registry definition json
/// rev_reg_delta_json: revocation registry definition delta json
/// timestamp: time represented as a total number of seconds from Unix Epoch
/// cred_rev_id: user credential revocation id in revocation registry
/// cb: Callback that takes command result as parameter
///
/// #Returns
/// revocation state json:
///     {
///         "rev_reg": <revocation registry>,
///         "witness": <witness>,
///         "timestamp" : integer
///     }
///
/// #Errors
/// Common*
/// Wallet*
/// Anoncreds*
#[no_mangle]
pub extern fn indy_update_revocation_state(command_handle: i32,
                                           blob_storage_reader_handle: i32,
                                           rev_state_json: *const c_char,
                                           rev_reg_def_json: *const c_char,
                                           rev_reg_delta_json: *const c_char,
                                           timestamp: u64,
                                           cred_rev_id: *const c_char,
                                           cb: Option<extern fn(
                                               xcommand_handle: i32, err: ErrorCode,
                                               updated_rev_state_json: *const c_char
                                           )>) -> ErrorCode

 

Blob Storage

CL 해지 schema에는 공개 해지 레지스트리에서 해지된 credential에 대한 정보를 숨기는 데 사용되는 해지 tails 항목 엔티티가 도입되었습니다. Tails는

  • 이진 Blob 또는 파일로 표시될 수 있는 BigInteger의 정적(한 번 생성된) 배열입니다.
  • 상당히 많은 양의 데이터가 필요할 수 있습니다(해지 레지스트리 당 최대 1GB).
  • issuer에 의해 작성 및 공유됩니다.
  • Prover와 Issuer 모두 필요합니다(다운로드 가능해야함).
  • 캐시될 수 있으며 한 번만 다운로드할 수 있습니다.
  • 일부 작업(증가 감시 업데이트)은 작은 부분의 Blob 파일만 읽도록 요구할 수 있습니다. 클라우드에 완전한 tails blob을 저장하고 네트워크를 통해 일부 부분을 요청하는 것이 더 효율적일 수 있습니다.

결과적으로 tails blobs에 액세스하는 방법은 응용 프로그램마다 매우 다를 수 있습니다. 이 SDK를 해결하기 위해 다음을 제공합니다.:

  • Blob 읽기를 위한 사용자 정의 핸들러를 등록하기 위한 API
  • Blob 작성을 위한 사용자 정의 핸들러를 등록하기 위한 API
  • Blob 일관성 검증을 위한 API
  • 로컬 파일에서 Blob을 읽고 Blob을 로컬 파일에 쓸 수 있는 기본 핸들러 구현

Tails 게시 및 액세스 워크 플로우는 다음과 같은 방식으로 Indy Node와 통합될 수 있습니다.:

  • Issuer는 tails를 생성하고 tails blob을 로컬 파일에 기록합니다(기본 핸들러 사용). 또한 API는 blob hash를 제공하고 구성 가능한 URI 패턴을 기반으로 URI를 생성합니다.
  • Issuer는 해당 URI를 사용하여 일부 CDN에 blob을 업로드합니다(SDK 범위를 벗어남).
  • Issuer는 tails URI 및 hash와 함께 REVOC_REG_DEF 트랜잭션을 보내고 게시합니다.
  • Prover는 GET_REVOC_REG_DEF 요청을 보내고 tails URI 및 hash를 받습니다.
  • Prover는 게시된 tails 파일을 다운로드하여 로컬로 저장합니다(SDK 외부).

 

Wallet Storage Design

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/003-wallet-storage/README.html

현재 상태에서 libindy는 다른 wallet 구현을 연결할 수 있습니다. 플러그된 wallet은 이제 보안 및 스토리지 계층을 모두 처리합니다. 이 설계에서는 스토리지 계층만 처리하여 연결된 인터페이스를 제한할 것을 제안합니다. 모든 암호화는 libindy에서 수행됩니다. 플러그된 wallet을 단순화하고 3d party wallet 구현을 위해 우수한 보안 수준을 보장합니다.

또한 proposal은 페이징 지원으로 효율적이고 유연한 검색을 위해 API를 향상시킵니다.

또한 proposal은 API가 응용 프로그램 특정 데이터를 wallet에 저장할 수 있도록 API가 향상되었습니다.

 

Goals and ideas

  • libindy 레벨에서 모든 암호화를 수행하여 3d party wallet 구현을 위한 플러그된 wallet 및 보증 보안 레벨을 단순화하십시오.
    • 레코드 ID는 항상 암호화됩니다.
    • 레코드 값은 항상 암호화됩니다.
    • 태그 이름은 항상 암호화됩니다.
    • 태그 값은 선택적으로 암호화됩니다. 사용자가 복잡한 검색을 수행하려는 경우 암호화되지 않은 추가 태그를 포함하는 것이 가능합니다.
  • 네이티브 OpenSSL 스타일 객체 지향 C 인터페이스를 사용하여 다른 스토리지를 연결할 수 있습니다. 불필요한 json 및 재할당(re-allocation)을 피하십시오.
  • 페이지 매김을 지원하는 엔티티를 효율적이고 유연하게 검색할 수 있습니다.
  • 애플리케이션 특정 데이터를 wallet에 저장하기 위해 퍼블릭 API를 노출합니다. 이 API는 libindy에 의해 저장된 secret에 액세스할 수 없습니다.

 

Wallet Components

 

Secrets API

indy_create_and_store_did 또는 indy_create_and_store_cred_def와 같은 secret 생성 및 액세스를 위한 기존 엔드 포인트입니다.:

  1. wallet에 secret을 생성 허용
  2. 레코드 ID 및 선택적으로 퍼블릭한 부분(필요한 경우) 반환
  3. 저장된 secret ID를 검색하도록 허용(필요한 경우)
  4. 이 secret이 필요한 암호화 호출에서 ID로 secret을 참조하도록 허용
  5. 저장된 secret을 다시 불러오는 것을 불허용

 

Non-secrets API

이 API는 wallet에 애플리케이션 특정 ID 데이터를 저장하고 읽을 수 있도록 고안되었습니다. 이 API는 Secret Entities API에 의해 저장된 secret에 액세스할 수 없습니다.

/// Create a new non-secret record in the wallet
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// id: the id of record
/// value: the value of record
/// tags_json: the record tags used for search and storing meta information as json:
///   {
///     "tagName1": <str>, // string tag (will be stored encrypted)
///     "tagName2": <int>, // int tag (will be stored encrypted)
///     "~tagName3": <str>, // string tag (will be stored un-encrypted)
///     "~tagName4": <int>, // int tag (will be stored un-encrypted)
///   }
///   Note that null means no tags
///   If tag name starts with "~" the tag will be stored un-encrypted that will allow
///   usage of this tag in complex search queries (comparison, predicates)
///   Encrypted tags can be searched only for exact matching
extern pub fn indy_add_wallet_record(command_handle: i32,
                                     wallet_handle: i32,
                                     type_: *const c_char,
                                     id: *const c_char,
                                     value: *const c_char,
                                     tags_json: *const c_char,
                                     cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode {}

/// Update a non-secret wallet record value
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// id: the id of record
/// value: the new value of record
extern pub fn indy_update_wallet_record_value(command_handle: i32,
                                              wallet_handle: i32,
                                              type_: *const c_char,
                                              id: *const c_char,
                                              value: *const c_char,
                                              cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode {}

/// Update a non-secret wallet record tags
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// id: the id of record
/// tags_json: the record tags used for search and storing meta information as json:
///   {
///     "tagName1": <str>, // string tag (will be stored encrypted)
///     "tagName2": <int>, // int tag (will be stored encrypted)
///     "~tagName3": <str>, // string tag (will be stored un-encrypted)
///     "~tagName4": <int>, // int tag (will be stored un-encrypted)
///   }
///   Note that null means no tags
///   If tag name starts with "~" the tag will be stored un-encrypted that will allow
///   usage of this tag in complex search queries (comparison, predicates)
///   Encrypted tags can be searched only for exact matching
extern pub fn indy_update_wallet_record_tags(command_handle: i32,
                                             wallet_handle: i32,
                                             type_: *const c_char,
                                             id: *const c_char,
                                             tags_json: *const c_char,
                                             cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode {}

/// Add new tags to the wallet record
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// id: the id of record
/// tags_json: the record tags used for search and storing meta information as json:
///   {
///     "tagName1": <str>, // string tag (will be stored encrypted)
///     "tagName2": <int>, // int tag (will be stored encrypted)
///     "~tagName3": <str>, // string tag (will be stored un-encrypted)
///     "~tagName4": <int>, // int tag (will be stored un-encrypted)
///   }
///   Note that null means no tags
///   If tag name starts with "~" the tag will be stored un-encrypted that will allow
///   usage of this tag in complex search queries (comparison, predicates)
///   Encrypted tags can be searched only for exact matching
///   Note if some from provided tags already assigned to the record than
///     corresponding tags values will be replaced
extern pub fn indy_add_wallet_record_tags(command_handle: i32,
                                          wallet_handle: i32,
                                          type_: *const c_char,
                                          id: *const c_char,
                                          tags_json: *const c_char,
                                          cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode {}

/// Delete tags from the wallet record
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// id: the id of record
/// tag_names_json: the list of tag names to remove from the record as json array:
///   ["tagName1", "tagName2", ...]
///   Note that null means no tag names
extern pub fn indy_delete_wallet_record_tags(command_handle: i32,
                                             wallet_handle: i32,
                                             type_: *const c_char,
                                             id: *const c_char,
                                             tag_names_json: *const c_char,
                                             cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode {}

/// Delete an existing wallet record in the wallet
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: record type
/// id: the id of record
extern pub fn indy_delete_wallet_record(command_handle: i32,
                                        wallet_handle: i32,
                                        type_: *const c_char,
                                        id: *const c_char,
                                        cb: Option<extern fn(command_handle_: i32, err: ErrorCode)>) -> ErrorCode> {}

/// Get an wallet record by id
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// id: the id of record
/// options_json: //TODO: FIXME: Think about replacing by bitmask
///  {
///    retrieveType: (optional, false by default) Retrieve record type,
///    retrieveValue: (optional, true by default) Retrieve record value,
///    retrieveTags: (optional, false by default) Retrieve record tags
///  }
/// #Returns
/// wallet record json:
/// {
///   id: "Some id",
///   value: "Some value", // present only if retrieveValue set to true
///   tags: <tags json>, // present only if retrieveTags set to true
/// }
extern pub fn indy_get_wallet_record(command_handle: i32,
                                     wallet_handle: i32,
                                     type_: *const c_char,
                                     id: *const c_char,
                                     options_json: *const c_char,
                                     cb: Option<extern fn(command_handle_: i32, err: ErrorCode,
                                                          record_json: *const c_char)>) -> ErrorCode {}

/// Search for wallet records.
///
/// Note instead of immediately returning of fetched records
/// this call returns wallet_search_handle that can be used later
/// to fetch records by small batches (with indy_fetch_wallet_search_next_records).
///
/// #Params
/// wallet_handle: wallet handle (created by open_wallet)
/// type_: allows to separate different record types collections
/// query_json: MongoDB style query to wallet record tags:
///  {
///    "tagName": "tagValue",
///    $or: {
///      "tagName2": { $regex: 'pattern' },
///      "tagName3": { $gte: 123 },
///    },
///  }
/// options_json: //TODO: FIXME: Think about replacing by bitmask
///  {
///    retrieveRecords: (optional, true by default) If false only "counts" will be calculated,
///    retrieveTotalCount: (optional, false by default) Calculate total count,
///    retrieveValue: (optional, true by default) Retrieve record value,
///    retrieveTags: (optional, false by default) Retrieve record tags,
///  }
/// #Returns
/// wallet_search_handle: Wallet search handle that can be used later
///   to fetch records by small batches (with indy_fetch_wallet_search_next_records)
extern pub fn indy_open_wallet_search(command_handle: i32,
                                      wallet_handle: i32,
                                      type_: *const c_char,
                                      query_json: *const c_char,
                                      options_json: *const c_char,
                                      cb: Option<extern fn(command_handle_: i32, err: ErrorCode,
                                                           wallet_search_handle_p: *mut i32)>) -> ErrorCode {}


/// Fetch next records for wallet search.
///
/// Not if there are no records this call returns WalletNoRecords error.
///
/// #Params
/// wallet_handle: wallet handle (created by open_wallet)
/// wallet_search_handle: wallet wallet handle (created by indy_open_wallet_search)
/// count: Count of records to fetch
///
/// #Returns
/// wallet records json:
/// {
///   totalCount: <int>, // present only if retrieveTotalCount set to true
///   records: [{ // present only if retrieveRecords set to true
///       id: "Some id",
///       value: "Some value", // present only if retrieveValue set to true
///       tags: <tags json>, // present only if retrieveTags set to true
///   }],
/// }
extern pub fn indy_fetch_wallet_search_next_records(command_handle: i32,
                                                    wallet_handle: i32,
                                                    wallet_search_handle: i32,
                                                    count: usize,
                                                    cb: Option<extern fn(command_handle_: i32, err: ErrorCode,
                                                                         records_json: *const c_char)>) -> ErrorCode {}

 

Wallet API and Storage Interface

Wallet API가 이미 존재하여 wallet 관리가 가능합니다. 다른 스토리지 구현을 libindy에 플러그인 할 수 있도록 업데이트해야합니다. 예를 들어, SQL 데이터베이스에 wallet 레코드를 저장할 수 있습니다. 이를 위해 기존 indy_register_wallet_type 호출을 indy_register_wallet_storage 호출로 대체합니다.

/// Register custom wallet storage implementation.
///
/// It allows library user to provide custom wallet storage implementation as set of handlers.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// type_: Wallet storage name.
/// create: Wallet storage "create" operation handler
/// delete: Wallet storage "delete" operation handler
/// open: Wallet storage "open" operation handler
/// close: Wallet storage "close" operation handler
/// add_record: Wallet storage "add_record" operation handler
/// update_record_value: Wallet storage "update_record_value" operation handler
/// update_record_tags: Wallet storage "update_record_tags" operation handler
/// add_record_tags: Wallet storage "add_record_tags" operation handler
/// delete_record_tags: Wallet storage "delete_record_tags" operation handler
/// delete_record: Wallet storage "delete_record" operation handler
/// get_record: Wallet storage "get_record" operation handler
/// get_record_id: Wallet storage "get_record_id" operation handler
/// get_record_value: Wallet storage "get_record_value" operation handler
/// get_record_tags: Wallet storage "get_record_tags" operation handler
/// free_record: Wallet storage "free_record" operation handler
/// search_records: Wallet storage "search_records" operation handler
/// get_search_total_count: Wallet storage "get_search_total_count" operation handler
/// get_search_count: Wallet storage "get_search_count" operation handler
/// get_search_next_record: Wallet storage "get_search_next_record" operation handler
/// free_search: Wallet storage "free_search" operation handler
///
/// #Returns
/// Error code
#[no_mangle]
pub extern fn indy_register_wallet_storage(command_handle: i32,
                                           type_: *const c_char,

                                           /// Create the wallet storage (For example, database creation)
                                           ///
                                           /// #Params
                                           /// name: wallet storage name (the same as wallet name)
                                           /// config: wallet storage config (For example, database config)
                                           /// credentials: wallet storage credentials (For example, database credentials)
                                           create: Option<extern fn(name: *const c_char,
                                                                    config: *const c_char,
                                                                    credentials: *const c_char) -> ErrorCode>,

                                           /// Delete the wallet storage (For example, database deletion)
                                           ///
                                           /// #Params
                                           /// name: wallet storage name (the same as wallet name)
                                           /// config: wallet storage config (For example, database config)
                                           /// credentials: wallet storage credentials (For example, database credentials)
                                           delete: Option<extern fn(name: *const c_char,
                                                                    config: *const c_char,
                                                                    credentials: *const c_char) -> ErrorCode>,

                                           /// Open the wallet storage (For example, opening database connection)
                                           ///
                                           /// #Params
                                           /// name: wallet storage name (the same as wallet name)
                                           /// config: wallet storage config (For example, database config)
                                           /// runtime_config: wallet storage runtime config (For example, connection config)
                                           /// credentials: wallet storage credentials (For example, database credentials)
                                           /// storage_handle_p: pointer to store opened storage handle
                                           open: Option<extern fn(name: *const c_char,
                                                                  config: *const c_char,
                                                                  runtime_config: *const c_char,
                                                                  credentials: *const c_char,
                                                                  storage_handle_p: *mut i32) -> ErrorCode>,

                                           /// Close the opened walled storage (For example, closing database connection)
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           close: Option<extern fn(handle: i32) -> ErrorCode>,

                                           /// Create a new record in the wallet storage
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: allows to separate different record types collections
                                           /// id: the id of record
                                           /// value: the value of record (pointer to buffer)
                                           /// value_len: the value of record (buffer size)
                                           /// tags_json: the record tags used for search and storing meta information as json:
                                           ///   {
                                           ///     "tagName1": "tag value 1", // string value
                                           ///     "tagName2": 123, // numeric value
                                           ///   }
                                           ///   Note that null means no tags
                                           add_record: Option<extern fn(storage_handle: i32,
                                                                        type_: *const c_char,
                                                                        id: *const c_char,
                                                                        value: *const u8,
                                                                        value_len: usize,
                                                                        tags_json: *const c_char) -> ErrorCode>,

                                           /// Update a record value
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: allows to separate different record types collections
                                           /// id: the id of record
                                           /// value: the value of record (pointer to buffer)
                                           /// value_len: the value of record (buffer size)
                                           update_record_value: Option<extern fn(storage_handle: i32,
                                                                                 type_: *const c_char,
                                                                                 id: *const c_char,
                                                                                 value: *const c_char,
                                                                                 value_len: usize) -> ErrorCode>,

                                           /// Update a record tags
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: allows to separate different record types collections
                                           /// id: the id of record
                                           /// tags_json: the new record tags used for search and storing meta information as json:
                                           ///   {
                                           ///     "tagName1": "tag value 1", // string value
                                           ///     "tagName2": 123, // numeric value
                                           ///   }
                                           ///   Note that null means no tags
                                           update_record_tags: Option<extern fn(storage_handle: i32,
                                                                                type_: *const c_char,
                                                                                id: *const c_char,
                                                                                tags_json: *const c_char) -> ErrorCode>,

                                           /// Add new tags to the record
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: allows to separate different record types collections
                                           /// id: the id of record
                                           /// tags_json: the additional record tags as json:
                                           ///   {
                                           ///     "tagName1": "tag value 1", // string value
                                           ///     "tagName2": 123, // numeric value,
                                           ///     ...
                                           ///   }
                                           ///   Note that null means no tags
                                           ///   Note if some from provided tags already assigned to the record than
                                           ///     corresponding tags values will be replaced
                                           add_record_tags: Option<extern fn(storage_handle: i32,
                                                                             type_: *const c_char,
                                                                             id: *const c_char,
                                                                             tags_json: *const c_char) -> ErrorCode>,

                                           /// Delete tags from the record
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: allows to separate different record types collections
                                           /// id: the id of record
                                           /// tag_names_json: the list of tag names to remove from the record as json array:
                                           ///   ["tagName1", "tagName2", ...]
                                           ///   Note that null means no tag names
                                           delete_record_tags: Option<extern fn(storage_handle: i32,
                                                                                type_: *const c_char,
                                                                                id: *const c_char,
                                                                                tag_names_json: *const c_char) -> ErrorCode>,

                                           /// Delete an existing record in the wallet storage
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: record type
                                           /// id: the id of record
                                           delete_record: Option<extern fn(storage_handle: i32,
                                                                           type_: *const c_char,
                                                                           id: *const c_char) -> ErrorCode>,

                                           /// Get an wallet storage record by id
                                           ///
                                           /// #Params
                                           /// storage_handle: opened storage handle (See open handler)
                                           /// type_: allows to separate different record types collections
                                           /// id: the id of record
                                           /// options_json: //TODO: FIXME: Think about replacing by bitmask
                                           ///  {
                                           ///    retrieveType: (optional, false by default) Retrieve record type,
                                           ///    retrieveValue: (optional, true by default) Retrieve record value,
                                           ///    retrieveTags: (optional, false by default) Retrieve record tags
                                           ///  }
                                           /// record_handle_p: pointer to store retrieved record handle
                                           get_record: Option<extern fn(storage_handle: i32,
                                                                        type_: *const c_char,
                                                                        id: *const c_char,
                                                                        options_json: *const c_char,
                                                                        record_handle_p: *mut i32) -> ErrorCode>,

                                          /// Get an id for retrieved wallet storage record
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// record_handle: retrieved record handle (See get_record handler)
                                          ///
                                          /// returns: record id
                                          ///          Note that pointer lifetime the same as retrieved record lifetime
                                          ///            (until record_free called)
                                          get_record_id: Option<extern fn(storage_handle: i32,
                                                                          record_handle: i32,
                                                                          record_id_p: *mut *const c_char) -> ErrorCode>,

                                          /// Get an type for retrieved wallet storage record
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// record_handle: retrieved record handle (See get_record handler)
                                          ///
                                          /// returns: record id
                                          ///          Note that pointer lifetime the same as retrieved record lifetime
                                          ///            (until record_free called)
                                          ///          Note that null be returned if no type retrieved
                                          get_record_type: Option<extern fn(storage_handle: i32,
                                                                            record_handle: i32,
                                                                            record_type_p: *mut *const c_char) -> ErrorCode>,

                                          /// Get an value for retrieved wallet storage record
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// record_handle: retrieved record handle (See get_record handler)
                                          ///
                                          /// returns: record value
                                          ///          Note that pointer lifetime the same as retrieved record lifetime
                                          ///            (until record_free called)
                                          ///          Note that null be returned if no value retrieved
                                          get_record_value: Option<extern fn(storage_handle: i32,
                                                                             record_handle: i32,
                                                                             record_value_p: *mut *const u8,
                                                                             record_value_len_p: *mut i32) -> ErrorCode>,

                                          /// Get an tags for retrieved wallet record
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// record_handle: retrieved record handle (See get_record handler)
                                          ///
                                          /// returns: record tags as json
                                          ///          Note that pointer lifetime the same as retrieved record lifetime
                                          ///            (until record_free called)
                                          ///          Note that null be returned if no tags retrieved
                                          get_record_tags: Option<extern fn(storage_handle: i32,
                                                                            record_handle: i32,
                                                                            record_tags_p: *mut *const c_char) -> ErrorCode>,

                                          /// Free retrieved wallet record (make retrieved record handle invalid)
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open_wallet_storage)
                                          /// record_handle: retrieved record handle (See wallet_storage_get_wallet_record)
                                          free_record: Option<extern fn(storage_handle: i32,
                                                                        record_handle: i32) -> ErrorCode>,

                                          /// Search for wallet storage records
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// type_: allows to separate different record types collections
                                          /// query_json: MongoDB style query to wallet record tags:
                                          ///  {
                                          ///    "tagName": "tagValue",
                                          ///    $or: {
                                          ///      "tagName2": { $regex: 'pattern' },
                                          ///      "tagName3": { $gte: 123 },
                                          ///    },
                                          ///  }
                                          /// options_json: //TODO: FIXME: Think about replacing by bitmask
                                          ///  {
                                          ///    retrieveRecords: (optional, true by default) If false only "counts" will be calculated,
                                          ///    retrieveTotalCount: (optional, false by default) Calculate total count,
                                          ///    retrieveType: (optional, false by default) Retrieve record type,
                                          ///    retrieveValue: (optional, true by default) Retrieve record value,
                                          ///    retrieveTags: (optional, false by default) Retrieve record tags,
                                          ///  }
                                          /// search_handle_p: pointer to store wallet search handle
                                          search_records: Option<extern fn(storage_handle: i32,
                                                                           type_: *const c_char,
                                                                           query_json: *const c_char,
                                                                           options_json: *const c_char,
                                                                           search_handle_p: *mut i32) -> ErrorCode>,

                                          /// Search for wallet storage records
                                          ///
                                          /// Note that for each record id, type, value and tags will be retrieved
                                          /// Note that total count will not be calculated
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// search_handle_p: pointer to store wallet search handle
                                          search_all_records: Option<extern fn(storage_handle: i32,
                                                                               search_handle_p: *mut i32) -> ErrorCode>,

                                          /// Get total count of records that corresponds to wallet storage search query
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// search_handle: wallet search handle (See search_records handler)
                                          ///
                                          /// returns: total count of records that corresponds to wallet storage search query
                                          ///          Note -1 will be returned if retrieveTotalCount set to false for search_records
                                          get_search_total_count: Option<extern fn(storage_handle: i32,
                                                                                   search_handle: i32,
                                                                                   total_count_p: *mut usize) -> ErrorCode>,

                                          /// Get the next wallet storage record handle retrieved by this wallet search.
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// search_handle: wallet search handle (See search_records handler)
                                          ///
                                          /// returns: record handle (the same as for get_record handler)
                                          ///          Note if no more records WalletNoRecords error will be returned
                                          fetch_search_next_record: Option<extern fn(storage_handle: i32,
                                                                                     search_handle: i32,
                                                                                     record_handle_p: *mut i32) -> ErrorCode>,

                                          /// Free wallet search (make search handle invalid)
                                          ///
                                          /// #Params
                                          /// storage_handle: opened storage handle (See open handler)
                                          /// search_handle: wallet search handle (See search_records handler)
                                          free_search: Option<extern fn(storage_handle: i32,
                                                                        search_handle: i32) -> ErrorCode>,

                                          cb: Option<extern fn(command_handle_: i32,
                                                               err: ErrorCode)>) -> ErrorCode

스토리지 인터페이스 엔티티는 다음과 같습니다.:

Wallet Service Interface

impl WalletService {

  pub fn new() -> WalletService {}

  pub fn register_wallet_storage(&self,
                                 type_: *const c_char,
                                 create: extern fn(name: *const c_char,
                                                   config: *const c_char)  -> ErrorCode,
                                 delete: extern fn(name: *const c_char,
                                                   config: *const c_char,
                                                   credentials: *const c_char) -> ErrorCode,
                                 open: extern fn(name: *const c_char,
                                                 config: *const c_char,
                                                 runtime_config: *const c_char,
                                                 credentials: *const c_char,
                                                 storage_handle_p: *mut i32) -> ErrorCode,
                                 close: extern fn(handle: i32) -> ErrorCode,
                                 add_record: extern fn(storage_handle: i32,
                                                       type_: *const c_char,
                                                       id: *const c_char,
                                                       value: *const u8,
                                                       value_len: usize,
                                                       tags_json: *const c_char) -> ErrorCode,
                                 update_record_value: extern fn(storage_handle: i32,
                                                                type_: *const c_char,
                                                                id: *const c_char,
                                                                value: *const u8,
                                                                value_len: usize) -> ErrorCode,
                                 update_record_tags: extern fn(storage_handle: i32,
                                                               type_: *const c_char,
                                                               id: *const c_char,
                                                               tags_json: *const c_char) -> ErrorCode,
                                 add_record_tags: extern fn(storage_handle: i32,
                                                            type_: *const c_char,
                                                            id: *const c_char,
                                                            tags_json: *const c_char) -> ErrorCode,
                                 delete_record_tags: extern fn(storage_handle: i32,
                                                               type_: *const c_char,
                                                               id: *const c_char,
                                                               tag_names_json: *const c_char) -> ErrorCode,
                                 delete_record: extern fn(storage_handle: i32,
                                                          type_: *const c_char,
                                                          id: *const c_char) -> ErrorCode,
                                 get_record: extern fn(storage_handle: i32,
                                                       type_: *const c_char,
                                                       id: *const c_char,
                                                       options_json: *const c_char,
                                                       record_handle_p: *mut i32) -> ErrorCode,
                                 get_record_id: extern fn(storage_handle: i32,
                                                          record_handle: i32,
                                                          record_id_p: *mut *const c_char) -> ErrorCode,
                                 get_record_value: extern fn(storage_handle: i32,
                                                             record_handle: i32,
                                                             record_value_p: *mut *const u8,
                                                             record_value_len_p: *mut usize) -> ErrorCode,
                                 get_record_tags: extern fn(storage_handle: i32,
                                                            record_handle: i32,
                                                            record_tags_p: *mut *const c_char) -> ErrorCode,
                                 free_record: extern fn(storage_handle: i32,
                                                        record_handle: i32) -> ErrorCode,
                                 search_records: extern fn(storage_handle: i32,
                                                           type_: *const c_char,
                                                           query_json: *const c_char,
                                                           options_json: *const c_char,
                                                           search_handle_p: *mut i32) -> ErrorCode,
                                search_all_records: extern fn(storage_handle: i32,
                                                              search_handle_p: *mut i32) -> ErrorCode,
                                 get_search_total_count: extern fn(storage_handle: i32,
                                                                   search_handle: i32,
                                                                   total_count_p: *mut usize) -> ErrorCode,
                                 fetch_search_next_record: Option<extern fn(storage_handle: i32,
                                                                            search_handle: i32,
                                                                            record_handle_p: *mut i32) -> ErrorCode,
                                 free_search: extern fn(storage_handle: i32,
                                                        search_handle: i32) -> ErrorCode>) -> Result<(), WalletError> {}

   pub fn create_wallet(&self,
                        pool_name: &str,
                        name: &str,
                        storage_type: Option<&str>,
                        storage_config: Option<&str>,
                        credentials: &str) -> Result<(), WalletError> {}

   pub fn delete_wallet(&self,
                        name: &str,
                        credentials: &str) -> Result<(), WalletError> {}

   pub fn open_wallet(&self,
                      name: &str,
                      credentials: &str) -> Result<i32, WalletError> {}

   pub fn close_wallet(&self,
                       wallet_handle: i32) -> Result<(), WalletError> {}

   pub fn list_wallets(&self) -> Result<Vec<WalletMetadata>, WalletError> {}

   pub fn add_record(wallet_handle: i32,
                     type_: &str,
                     id: &str,
                     tags_json: &str) -> Result<(), WalletError> {}

   pub fn update_record_value(wallet_handle: i32,
                              type_: &str,
                              id: &str,
                              value: &str) -> Result<(), WalletError> {}

   pub fn update_record_tags(wallet_handle: i32,
                             type_: &str,
                             id: &str,
                             tags_json: &str) -> Result<(), WalletError> {}

   pub fn add_record_tags(wallet_handle: i32,
                          type_: &str,
                          id: &str,
                          tags_json: &str) -> Result<(), WalletError> {}

   pub fn delete_record_tags(storage_handle: i32,
                             type_: &str,
                             id: &str,
                             tag_names_json: &str) -> Result<(), WalletError> {}

   pub fn delete_record(storage_handle: i32,
                        type_: &str,
                        id: &str) -> Result<(), WalletError> {}

   pub fn get_record(storage_handle: i32,
                     type_: &str,
                     id: &str,
                     options_json: &str) -> Result<WalletRecord, WalletError> {}

    pub fn search_records(storage_handle: i32,
                          type_: &str,
                          query_json: &str,
                          options_json: &str) -> Result<WalletSearch, WalletError> {}

    pub fn search_all_records(storage_handle: i32) -> Result<WalletSearch, WalletError> {}
}

impl WalletRecord {

  pub fn get_id() -> &str {}

  pub fn get_type() -> Option<&str> {}

  pub fn get_value() -> Option<&str> {}

  pub fn get_tags() -> Option<&str> {}
}

impl WalletSearch {

  pub fn get_total_count() -> Result<Option<i32>, WalletError> {}

  pub fn fetch_next_record() -> Result<Option<WalletRecord>, WalletError> {}
}

 

Wallet Query Language

이 언어는 Non-secret API, Wallet 서비스 및 Wallet 스토리지 인터페이스에서 쿼리를 정의하는 데 사용됩니다.

query = {subquery}
subquery = {subquery, ..., subquery} - WHERE subquery AND ... AND subquery
subquery = $or: [{subquery},..., {subquery}] - WHERE subquery OR ... OR subquery
subquery = $not: {subquery} - Where NOT (subquery)
subquery = "tagName": tagValue - WHERE tagName == tagValue
subquery = "tagName": {$neq: tagValue} - WHERE tagName != tagValue
subquery = "tagName": {$gt: tagValue} - WHERE tagName > tagValue
subquery = "tagName": {$gte: tagValue} - WHERE tagName >= tagValue
subquery = "tagName": {$lt: tagValue} - WHERE tagName < tagValue
subquery = "tagName": {$lte: tagValue} - WHERE tagName <= tagValue
subquery = "tagName": {$like: tagValue} - WHERE tagName LIKE tagValue
subquery = "tagName": {$in: [tagValue, ..., tagValue]} - WHERE tagName IN (tagValue, ..., tagValue)

 

Separation of libindy secrets from non-secrets

아이디어는 다음과 같습니다.:

  • libindy는 "~did"와 같은 모든 내부 레코드 유형에 특정 접두사를 사용합니다.
  • non-secret 인터페이스의 경우 이 접두사를 사용하는 것은 불가능합니다.
  • 사용자가 엔티티 유형으로 이 접두사를 가진 값을 전달하면 validation error(검증 오류)를 리턴합니다.

 

Separation of libindy defined tags from user defined tags

아이디어는 다음과 같습니다.:

  • libindy는 "indy:tagName"과 같은 모든 내부 레코드 태그에 특정 접두사를 사용합니다.
  • 모든 사용자 인터페이스에서 이 접두사로 태그를 수정하는 것은 불가능합니다.
  • 사용자가 이 접두사를 가진 태그를 태그를 수정하는 아무 함수에 전달하면 libindy는 validation error(검증 오류)를 리턴합니다.
  • 사용자가 애플리케이션이 libindy 정의 태그를 읽고 검색에 이 태그를 사용할 수 있습니다.

 

Wallet Encryption

암호화 스키마는 다음과 같습니다.:

 

Payment Interface

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/004-payment-interface/README.html

이 디자인은 libindy가 Indy 인프라로 구현할 수 있는 지불(payment) 및 토큰(token)을 인식하도록 제안합니다.

 

Goals and ideas

  • Libindy는 Indy 인프라의 지불(payment)에 대한 세부 정보를 알고 있어야합니다.
    • 일반적인 지불(payment) 아이디어. 트랜잭션 비용을 지불해야 할 수도 있고, 트랜잭션은 돈/토큰 송금에 사용될 수 있습니다.
    • libindy에 연결될 수 있는 다른 Payment 메소드의 개념(Sovrin 토큰, Bitcoin 토큰, Visa 등). libindy의 payment 메소드는 접두사(prefix)로 식별될 수 있습니다. "pay:sov"는 Sovrin 토큰 payment 메소드의 접두사가 될 수 있고, "pay:xyz"는 다른 payment 메소드의 접두사가 될 수 있습니다.
    • 지원되는 Payment 메소드에 공통적인 Payment Address 개념. 다른 payment 방식은 다른 형식의 Payment Address를 사용하지만 완전히 해결할 수 있는 Payment Address 형식에 대한 합의가 있습니다. 이것은 이름과 연관된 DID 메소드 스펙이라는 서브 스펙이 있는 일반 DID 스펙의 개념과 매우 유사합니다. Payment Address는 "pay:sov:12345"와 같습니다.
    • Payment 아이디어는 입력과 출력을 취합니다.
    • 발생할 수 있는 일반적인 payment 오류(예: "insufficient funds(자금 부족)").
    • 주소 제어 증명
  • 기본 제공 libindy는 payment 메소드를 지원하지 않지만 payment 메소드를 등록하는 API가 있습니다.
  • 각 payment 메소드는 다음 사항을 알고 있어야합니다.:
    • payment 메소드 접두사와 payment address 형식입니다.
    • transfers sources, mint source, lookup balances와 같은 순수한 payment 트랜잭션을 만드는 방법
    • 수수료를 지불하기 위해 서명되지 않은 non-payment 트랜잭션(예: NYM)을 수정하는 방법
    • payment 메소드를 만족시키는 방식으로 트랜잭션 서명을 수정하는 방법
    • 메소드에 특히 중요한 payment address(예: Sovrin Foundation이 수수료를 받는 payment address)
  • Libindy는 payment address 작성, payment 관련 트랜잭션 작성, 트랜잭션에 수수료 지정을 위한 일반 API를 제공해야합니다.
  • Payment 인터페이스는 다른 payment 메소드 사이에서 가능한 한 상호 운용 가능해야합니다.

 

Payment Method API

Payment 메소드 API는 indy_register_payment_method를 호출하여 사용자 정의 payment 메소드 구현을 등록할 수 있도록 합니다.

/// Register custom payment implementation.
///
/// It allows library user to provide custom payment method implementation as set of handlers.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: The type of payment method also used as sub-prefix for fully resolvable payment address format ("sov" - for example)
/// create_payment_address: "create_payment_address" operation handler
/// add_request_fees: "add_request_fees" operation handler
/// parse_response_with_fees: "parse_response_with_fees" operation handler
/// build_get_payment_sources_request: "build_get_payment_sources_request" operation handler
/// parse_get_payment_sources_response: "parse_get_payment_sources_response" operation handler
/// build_payment_req: "build_payment_req" operation handler
/// parse_payment_response: "parse_payment_response" operation handler
/// build_mint_req: "build_mint_req" operation handler
/// build_set_txn_fees_req: "build_set_txn_fees_req" operation handler
/// build_get_txn_fees_req: "build_get_txn_fees_req" operation handler
/// parse_get_txn_fees_response: "parse_get_txn_fees_response" operation handler
/// build_verify_payment_req: "build_verify_payment_req" operation handler
/// parse_verify_payment_response: "parse_verify_payment_response" operation handler
///
/// #Returns
/// Error code
#[no_mangle]
pub extern fn indy_register_payment_method(command_handle: i32,
                                           payment_method: *const c_char,

                                           create_payment_address: Option<CreatePaymentAddressCB>,
                                           add_request_fees: Option<AddRequestFeesCB>,
                                           parse_response_with_fees: Option<ParseResponseWithFeesCB>,
                                           build_get_payment_sources_request: Option<BuildGetPaymentSourcesRequestCB>,
                                           parse_get_payment_sources_response: Option<ParseGetPaymentSourcesResponseCB>,
                                           build_payment_req: Option<BuildPaymentReqCB>,
                                           parse_payment_response: Option<ParsePaymentResponseCB>,
                                           build_mint_req: Option<BuildMintReqCB>,
                                           build_set_txn_fees_req: Option<BuildSetTxnFeesReqCB>,
                                           build_get_txn_fees_req: Option<BuildGetTxnFeesReqCB>,
                                           parse_get_txn_fees_response: Option<ParseGetTxnFeesResponseCB>,
                                           build_verify_req: Option<BuildVerifyReqCB>,
                                           parse_verify_response: Option<ParseVerifyResponseCB>,
                                           cb: Option<extern fn(command_handle_: i32,
                                                                err: ErrorCode) -> ErrorCode>) -> ErrorCode {}

 

Payment Method Handler Interface

등록된 함수는 libindy API 호출 처리의 일부로 libindy에 의해 호출됩니다. Libindy는 자체 콜백을 함수에 전달하여 타사 함수 구현 결과를 검색합니다. 아래 목록은 등록된 호출에 대한 유형 설명입니다.

/// Create the payment address for this payment method.
///
/// This method generates private part of payment address
/// and stores it in a secure place. Ideally it should be
/// secret in libindy wallet (see crypto module).
///
/// Note that payment method should be able to resolve this
/// secret by fully resolvable payment address format.
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle where keys for signature are stored
/// config: payment address config as json:
///   {
///     seed: <str>, // allows deterministic creation of payment address
///   }
///
/// #Returns
/// payment_address - public identifier of payment address in fully resolvable payment address format
type CreatePaymentAddressCB = extern fn(command_handle: i32,
                                        wallet_handle: i32,
                                        config: *const c_char,
                                        cb: Option<extern fn(command_handle_: i32,
                                                             err: ErrorCode,
                                                             payment_address: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Modifies Indy request by adding information how to pay fees for this transaction
/// according to this payment method.
///
/// This method consumes set of inputs and outputs. The difference between inputs balance
/// and outputs balance is the fee for this transaction.
///
/// Not that this method also produces correct fee signatures.
///
/// Format of inputs is specific for payment method. Usually it should reference payment transaction
/// with at least one output that corresponds to payment address that user owns.
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// req_json: initial transaction request as json
/// inputs_json: The list of payment sources as json array:
///   ["source1", ...]
///   Note that each source should reference payment address
/// outputs_json: The list of outputs as json array:
///   [{
///     recipient: <str>, // payment address of recipient
///     amount: <int>, // amount
///   }]
/// extra: // optional information for payment operation
///
/// #Returns
/// req_with_fees_json - modified Indy request with added fees info
type AddRequestFeesCB = extern fn(command_handle: i32,
                                  wallet_handle: i32,
                                  submitter_did: *const c_char,
                                  req_json: *const c_char,
                                  inputs_json: *const c_char,
                                  outputs_json: *const c_char,
                                  cb: Option<extern fn(command_handle_: i32,
                                                       err: ErrorCode,
                                                       req_with_fees_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Parses response for Indy request with fees.
///
/// #Params
/// command_handle: command handle to map callback to context
/// resp_json: response for Indy request with fees
///
/// #Returns
/// receipts_json - parsed (payment method and node version agnostic) receipts info as json:
///   [{
///      receipt: <str>, // receipt that can be used for payment referencing and verification
///      recipient: <str>, //payment address for this recipient
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
type ParseResponseWithFeesCB = extern fn(command_handle: i32,
                                         resp_json: *const c_char,
                                         cb: Option<extern fn(command_handle_: i32,
                                                              err: ErrorCode,
                                                              receipts_json: *const c_char) -> ErrorCode>) -> ErrorCode;
                                                       
/// Builds Indy request for getting sources list for payment address
/// according to this payment method.
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// payment_address: target payment address
///
/// #Returns
/// get_sources_txn_json - Indy request for getting sources list for payment address
type BuildGetPaymentSourcesRequestCB = extern fn(command_handle: i32,
                                       wallet_handle: i32,
                                       submitter_did: *const c_char,
                                       payment_address: *const c_char,
                                       cb: Option<extern fn(command_handle_: i32,
                                                            err: ErrorCode,
                                                            get_sources_txn_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Parses response for Indy request for getting sources list.
///
/// #Params
/// command_handle: command handle to map callback to context
/// resp_json: response for Indy request for getting sources list
///
/// #Returns
/// sources_json - parsed (payment method and node version agnostic) sources info as json:
///   [{
///      source: <str>, // source input
///      paymentAddress: <str>, //payment address for this source
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
type ParseGetPaymentSourcesResponseCB = extern fn(command_handle: i32,
                                        resp_json: *const c_char,
                                        cb: Option<extern fn(command_handle_: i32,
                                                             err: ErrorCode,
                                                             sources_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Builds Indy request for doing payment
/// according to this payment method.
///
/// This method consumes set of inputs and outputs.
///
/// Format of inputs is specific for payment method. Usually it should reference payment transaction
/// with at least one output that corresponds to payment address that user owns.
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// inputs_json: The list of payment sources as json array:
///   ["source1", ...]
///   Note that each source should reference payment address
/// outputs_json: The list of outputs as json array:
///   [{
///     recipient: <str>, // payment address of recipient
///     amount: <int>, // amount
///   }]
/// extra: // optional information for payment operation
///
/// #Returns
/// payment_req_json - Indy request for doing payment
type BuildPaymentReqCB = extern fn(command_handle: i32,
                                   wallet_handle: i32,
                                   submitter_did: *const c_char,
                                   inputs_json: *const c_char,
                                   outputs_json: *const c_char,
                                   cb: Option<extern fn(command_handle_: i32,
                                                        err: ErrorCode,
                                                        payment_req_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Parses response for Indy request for payment txn.
///
/// #Params
/// command_handle: command handle to map callback to context
/// resp_json: response for Indy request for payment txn
///
/// #Returns
/// receipts_json - parsed (payment method and node version agnostic) receipts info as json:
///   [{
///      receipt: <str>, // receipt that can be used for payment referencing and verification
///      recipient: <str>, //payment address for this receipt
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
type ParsePaymentResponseCB = extern fn(command_handle: i32,
                                        resp_json: *const c_char,
                                        cb: Option<extern fn(command_handle_: i32,
                                                             err: ErrorCode,
                                                             receipts_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Builds Indy request for doing minting
/// according to this payment method.
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// outputs_json: The list of outputs as json array:
///   [{
///     recipient: <str>, // payment address of recipient
///     amount: <int>, // amount
///   }]
/// extra: // optional information for payment operation
///
/// #Returns
/// mint_req_json - Indy request for doing minting
type BuildMintReqCB = extern fn(command_handle: i32,
                                wallet_handle: i32,
                                submitter_did: *const c_char,
                                outputs_json: *const c_char,
                                cb: Option<extern fn(command_handle_: i32,
                                                     err: ErrorCode,
                                                     mint_req_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Builds Indy request for setting fees for transactions in the ledger
///
/// # Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// fees_json {
///   txnType1: amount1,
///   txnType2: amount2,
///   .................
///   txnTypeN: amountN,
/// }
///
/// # Return
/// set_txn_fees_json - Indy request for setting fees for transactions in the ledger
type BuildSetTxnFeesReqCB = extern fn(command_handle: i32,
                                      wallet_handle: i32,
                                      submitter_did: *const c_char,
                                      fees_json: *const c_char,
                                      cb: Option<extern fn(command_handle_: i32,
                                                           err: ErrorCode,
                                                           set_txn_fees_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Builds Indy get request for getting fees for transactions in the ledger
///
/// # Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
///
/// # Return
/// get_txn_fees_json - Indy request for getting fees for transactions in the ledger
type BuildGetTxnFeesReqCB = extern fn(command_handle: i32,
                                      wallet_handle: i32,
                                      submitter_did: *const c_char,
                                      cb: Option<extern fn(command_handle_: i32,
                                                           err: ErrorCode,
                                                           get_txn_fees_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Parses response for Indy request for getting fees
///
/// # Params
/// command_handle: command handle to map callback to context
/// resp_json: response for Indy request for getting fees
///
/// # Return
/// fees_json {
///   txnType1: amount1,
///   txnType2: amount2,
///   .................
///   txnTypeN: amountN,
/// }                                          
type ParseGetTxnFeesResponseCB = extern fn(command_handle: i32,
                                           resp_json: *const c_char,
                                           cb: Option<extern fn(command_handle_: i32,
                                                                err: ErrorCode,
                                                                fees_json: *const c_char) -> ErrorCode>) -> ErrorCode;                                                       

/// Builds Indy request for getting information to verify the payment receipt
///
/// # Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// receipt: payment receipt to verify
///
/// # Return
/// verify_txn_json -- request to be sent to ledger
pub type BuildVerifyPaymentReqCB = extern fn(command_handle: i32,
                                             wallet_handle: i32,
                                             submitter_did: *const c_char,
                                             receipt: *const c_char,
                                             cb: Option<extern fn(command_handle_: i32,
                                                                  err: ErrorCode,
                                                                  verify_txn_json: *const c_char) -> ErrorCode>) -> ErrorCode;

/// Parses Indy response with information to verify receipt
///
/// # Params
/// command_handle: command handle to map callback to context
/// resp_json: response for Indy request for information to verify the payment receipt
///
/// # Return
/// txn_json: {
///     sources: [<str>, ]
///     receipts: [ {
///         recipient: <str>, // payment address of recipient
///         receipt: <str>, // receipt that can be used for payment referencing and verification
///         amount: <int>, // amount
///     }, ]
///     extra: <str>, //optional data
/// }
pub type ParseVerifyPaymentResponseCB = extern fn(command_handle: i32,
                                                  resp_json: *const c_char,
                                                  cb: Option<extern fn(command_handle_: i32,
                                                                       err: ErrorCode,
                                                                       txn_json: *const c_char) -> ErrorCode>) -> ErrorCode;

 

Payment API

일부 API 호출에는 payment_method를 결정하기 위한 전용 매개 변수가 있습니다. 호출의 다른 부분은 입력 매개 변수 형식에 대한 가정을 사용하여 payment_method를 결정합니다.

/// Create the payment address for specified payment method
///
///
/// This method generates private part of payment address
/// and stores it in a secure place. Ideally it should be
/// secret in libindy wallet (see crypto module).
///
/// Note that payment method should be able to resolve this
/// secret by fully resolvable payment address format.
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet handle where to save new address
/// payment_method: Payment method to use (for example, 'sov')
/// config: payment address config as json:
///   {
///     seed: <str>, // allows deterministic creation of payment address
///   }
///
/// #Returns
/// payment_address - public identifier of payment address in fully resolvable payment address format
pub extern fn indy_create_payment_address(command_handle: i32,
                                          wallet_handle: i32,
                                          payment_method: *const c_char,
                                          config: *const c_char,
                                          cb: Option<extern fn(command_handle_: i32,
                                                               err: ErrorCode,
                                                               payment_address: *const c_char) -> ErrorCode>) -> ErrorCode {}
                                                               
/// Lists all payment addresses that are stored in the wallet
///
/// #Params
/// command_handle: command handle to map callback to context
/// wallet_handle: wallet to search for payment_addresses in
///
/// #Returns
/// payment_addresses_json - json array of string with json addresses
pub extern fn indy_list_payment_addresses(command_handle: i32,
                                          wallet_handle: i32,
                                          cb: Option<extern fn(command_handle_: i32,
                                                               err: ErrorCode,
                                                               payment_addresses_json: *const c_char)>) -> ErrorCode {}

/// Modifies Indy request by adding information how to pay fees for this transaction
/// according to this payment method.
///
/// This method consumes set of inputs and outputs. The difference between inputs balance
/// and outputs balance is the fee for this transaction.
///
/// Not that this method also produces correct fee signatures.
///
/// Format of inputs is specific for payment method. Usually it should reference payment transaction
/// with at least one output that corresponds to payment address that user owns.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// req_json: initial transaction request as json
/// inputs_json: The list of payment sources as json array:
///   ["source1", ...]
///     - each input should reference paymentAddress
///     - this param will be used to determine payment_method
/// outputs_json: The list of outputs as json array:
///   [{
///     recipient: <str>, // payment address of recipient
///     amount: <int>, // amount
///   }]
/// extra: // optional information for payment operation
///
/// #Returns
/// req_with_fees_json - modified Indy request with added fees info
/// payment_method - used payment method
pub extern fn indy_add_request_fees(command_handle: i32,
                                    wallet_handle: i32,
                                    submitter_did: *const c_char,
                                    req_json: *const c_char,
                                    inputs_json: *const c_char,
                                    outputs_json: *const c_char,
                                    extra: *const c_char,
                                    cb: Option<extern fn(command_handle_: i32,
                                                         err: ErrorCode,
                                                         req_with_fees_json: *const c_char,
                                                         payment_method: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Parses response for Indy request with fees.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use
/// resp_json: response for Indy request with fees
///
/// #Returns
/// receipts_json - parsed (payment method and node version agnostic) receipts info as json:
///   [{
///      receipt: <str>, // receipt that can be used for payment referencing and verification
///      recipient: <str>, //payment address of recipient
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
pub extern fn indy_parse_response_with_fees(command_handle: i32,
                                            payment_method: *const c_char,
                                            resp_json: *const c_char,
                                            cb: Option<extern fn(command_handle_: i32,
                                                                 err: ErrorCode,
                                                                 receipts_json: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Builds Indy request for getting sources list for payment address
/// according to this payment method.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// payment_address: target payment address
///
/// #Returns
/// get_sources_txn_json - Indy request for getting sources list for payment address
/// payment_method - used payment method
pub extern fn indy_build_get_payment_sources_request(command_handle: i32,
                                                     wallet_handle: i32,
                                                     submitter_did: *const c_char,
                                                     payment_address: *const c_char,
                                                     cb: Option<extern fn(command_handle_: i32,
                                                                          err: ErrorCode,
                                                                          get_sources_txn_json: *const c_char,
                                                                          payment_method: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Parses response for Indy request for getting sources list.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use.
/// resp_json: response for Indy request for getting sources list
///
/// #Returns
/// sources_json - parsed (payment method and node version agnostic) sources info as json:
///   [{
///      source: <str>, // source input
///      paymentAddress: <str>, //payment address for this source
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
pub extern fn indy_parse_get_payment_sources_response(command_handle: i32,
                                                      payment_method: *const c_char,
                                                      resp_json: *const c_char,
                                                      cb: Option<extern fn(command_handle_: i32,
                                                                           err: ErrorCode,
                                                                           sources_json: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Builds Indy request for doing payment
/// according to this payment method.
///
/// This method consumes set of inputs and outputs.
///
/// Format of inputs is specific for payment method. Usually it should reference payment transaction
/// with at least one output that corresponds to payment address that user owns.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// inputs_json: The list of payment sources as json array:
///   ["source1", ...]
///   Note that each source should reference payment address
/// outputs_json: The list of outputs as json array:
///   [{
///     recipient: <str>, // payment address of recipient
///     amount: <int>, // amount
///   }]
/// extra: // optional information for payment operation
///
/// #Returns
/// payment_req_json - Indy request for doing payment
/// payment_method - used payment method
pub extern fn indy_build_payment_req(command_handle: i32,
                                     wallet_handle: i32,
                                     submitter_did: *const c_char,
                                     inputs_json: *const c_char,
                                     outputs_json: *const c_char,
                                     extra: *const c_char,
                                     cb: Option<extern fn(command_handle_: i32,
                                                          err: ErrorCode,
                                                          payment_req_json: *const c_char,
                                                          payment_method: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Parses response for Indy request for payment txn.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use
/// resp_json: response for Indy request for payment txn
///
/// #Returns
/// receipts_json - parsed (payment method and node version agnostic) receipts info as json:
///   [{
///      receipt: <str>, // receipt that can be used for payment referencing and verification
///      recipient: <str>, // payment address of recipient
///      amount: <int>, // amount
///      extra: <str>, // optional data from payment transaction
///   }]
pub extern fn indy_parse_payment_response(command_handle: i32,
                                          payment_method: *const c_char,
                                          resp_json: *const c_char,
                                          cb: Option<extern fn(command_handle_: i32,
                                                               err: ErrorCode,
                                                               receipts_json_json: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Builds Indy request for doing minting
/// according to this payment method.
///
/// #Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// outputs_json: The list of outputs as json array:
///   [{
///     recipient: <str>, // payment address of recipient
///     amount: <int>, // amount
///   }]
/// extra: // optional information for mint operation
///
/// #Returns
/// mint_req_json - Indy request for doing minting
/// payment_method - used payment method
pub extern fn indy_build_mint_req(command_handle: i32,
                                  wallet_handle: i32,
                                  submitter_did: *const c_char,
                                  outputs_json: *const c_char,
                                  extra: *const c_char,
                                  cb: Option<extern fn(command_handle_: i32,
                                                       err: ErrorCode,
                                                       mint_req_json: *const c_char,
                                                       payment_method: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Builds Indy request for setting fees for transactions in the ledger
///
/// # Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// payment_method: payment method to use
/// fees_json {
///   txnType1: amount1,
///   txnType2: amount2,
///   .................
///   txnTypeN: amountN,
/// }
/// # Return
/// set_txn_fees_json - Indy request for setting fees for transactions in the ledger
pub extern fn indy_build_set_txn_fees_req(command_handle: i32,
                                          wallet_handle: i32,
                                          submitter_did: *const c_char,
                                          payment_method: *const c_char,
                                          fees_json: *const c_char,
                                          cb: Option<extern fn(command_handle_: i32,
                                                               err: ErrorCode,
                                                               set_txn_fees_json: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Builds Indy get request for getting fees for transactions in the ledger
///
/// # Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// payment_method: payment method to use
///
/// # Return
/// get_txn_fees_json - Indy request for getting fees for transactions in the ledger
pub extern fn indy_build_get_txn_fees_req(command_handle: i32,
                                          wallet_handle: i32,
                                          submitter_did: *const c_char,
                                          payment_method: *const c_char,
                                          cb: Option<extern fn(command_handle_: i32,
                                                               err: ErrorCode,
                                                               get_txn_fees_json: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Parses response for Indy request for getting fees
///
/// # Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use
/// resp_json: response for Indy request for getting fees
///
/// # Return
/// fees_json {
///   txnType1: amount1,
///   txnType2: amount2,
///   .................
///   txnTypeN: amountN,
/// }
pub extern fn indy_parse_get_txn_fees_response(command_handle: i32,
                                               payment_method: *const c_char,
                                               resp_json: *const c_char,
                                               cb: Option<extern fn(command_handle_: i32,
                                                                    err: ErrorCode,
                                                                    fees_json: *const c_char) -> ErrorCode>) -> ErrorCode {}

/// Builds Indy request for information to verify the payment receipt
///
/// # Params
/// command_handle: Command handle to map callback to caller context.
/// wallet_handle: wallet handle
/// submitter_did : DID of request sender
/// receipt: payment receipt to verify
///
/// # Return
/// verify_txn_json: Indy request for verification receipt
/// payment_method: used payment method
#[no_mangle]
pub extern fn indy_build_verify_payment_req(command_handle: i32,
                                            wallet_handle: i32,
                                            submitter_did: *const c_char,
                                            receipt: *const c_char,
                                            cb: Option<extern fn(command_handle_: i32,
                                                                 err: ErrorCode,
                                                                 verify_txn_json: *const c_char,
                                                                 payment_method: *const c_char)>) -> ErrorCode {}

/// Parses Indy response with information to verify receipt
///
/// # Params
/// command_handle: Command handle to map callback to caller context.
/// payment_method: payment method to use
/// resp_json: response of the ledger for verify txn
///
/// # Return
/// txn_json: {
///     sources: [<str>, ]
///     receipts: [ {
///         recipient: <str>, // payment address of recipient
///         receipt: <str>, // receipt that can be used for payment referencing and verification
///         amount: <int>, // amount
///     } ],
///     extra: <str>, //optional data
/// }
#[no_mangle]
pub extern fn indy_parse_verify_payment_response(command_handle: i32,
                                                 payment_method: *const c_char,
                                                 resp_json: *const c_char,
                                                 cb: Option<extern fn(command_handle_: i32,
                                                                      err: ErrorCode,
                                                                      txn_json: *const c_char)>) -> ErrorCode {}

/// Signs a message with a payment address.
///
/// #Params
/// command_handle: command handle to map callback to user context.
/// wallet_handle: wallet handler (created by open_wallet).
/// address: payment address of message signer. The key must be created by calling indy_create_address
/// message_raw: a pointer to first byte of message to be signed
/// message_len: a message length
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// a signature string
///
/// #Errors
/// Common*
/// Wallet*
/// Crypto*
#[no_mangle]
pub extern fn indy_sign_with_address(command_handle: CommandHandle,
                                     wallet_handle: WalletHandle,
                                     address: *const c_char,
                                     message_raw: *const u8,
                                     message_len: u32,
                                     cb: Option<extern fn(command_handle_: CommandHandle,
                                                          err: ErrorCode,
                                                          signature_raw: *const u8,
                                                          signature_len: u32)>) -> ErrorCode {
    trace!("indy_sign_with_address: >>> wallet_handle: {:?}, address: {:?}, message_raw: {:?}, message_len: {:?}",
           wallet_handle, address, message_raw, message_len);
    check_useful_c_str!(address, ErrorCode::CommonInvalidParam3);
    check_useful_c_byte_array!(message_raw, message_len, ErrorCode::CommonInvalidParam4, ErrorCode::CommonInvalidParam5);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam6);

    trace!("indy_sign_with_address: entities >>> wallet_handle: {:?}, address: {:?}, message_raw: {:?}, message_len: {:?}",
           wallet_handle, address, message_raw, message_len);

    let result = CommandExecutor::instance()
        .send(Command::Payments(
            PaymentsCommand::SignWithAddressReq(wallet_handle,
                                                address,
                                                message_raw,
                                                Box::new(move |result| {
                                                    let (err, signature) = prepare_result_1!(result, Vec::new());
                                                    trace!("indy_sign_with_address: signature: {:?}", signature);
                                                    let (signature_raw, signature_len) = ctypes::vec_to_pointer(&signature);
                                                    cb(command_handle, err, signature_raw, signature_len)
                                        }))
        ));


    let res = prepare_result!(result);

    trace!("indy_sign_with_address: <<< res: {:?}", res);

    res
}

/// Verify a signature with a payment address.
///
/// #Params
/// command_handle: command handle to map callback to user context.
/// address: payment address of the message signer
/// message_raw: a pointer to first byte of message that has been signed
/// message_len: a message length
/// signature_raw: a pointer to first byte of signature to be verified
/// signature_len: a signature length
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// valid: true - if signature is valid, false - otherwise
///
/// #Errors
/// Common*
/// Wallet*
/// Ledger*
/// Crypto*
#[no_mangle]
pub extern fn indy_verify_with_address(command_handle: CommandHandle,
                                       address: *const c_char,
                                       message_raw: *const u8,
                                       message_len: u32,
                                       signature_raw: *const u8,
                                       signature_len: u32,
                                       cb: Option<extern fn(command_handle_: CommandHandle,
                                                            err: ErrorCode,
                                                            result: bool)>) -> ErrorCode {
    trace!("indy_verify_with_address: >>> address: {:?}, message_raw: {:?}, message_len: {:?}, signature_raw: {:?}, signature_len: {:?}",
           address, message_raw, message_len, signature_raw, signature_len);

    check_useful_c_str!(address, ErrorCode::CommonInvalidParam2);
    check_useful_c_byte_array!(message_raw, message_len, ErrorCode::CommonInvalidParam3, ErrorCode::CommonInvalidParam4);
    check_useful_c_byte_array!(signature_raw, signature_len, ErrorCode::CommonInvalidParam5, ErrorCode::CommonInvalidParam6);
    check_useful_c_callback!(cb, ErrorCode::CommonInvalidParam7);

    trace!("indy_verify_with_address: entities >>> address: {:?}, message_raw: {:?}, message_len: {:?}, signature_raw: {:?}, signature_len: {:?}",
           address, message_raw, message_len, signature_raw, signature_len);

    let result = CommandExecutor::instance()
        .send(Command::Payments(PaymentsCommand::VerifyWithAddressReq(
            address,
            message_raw,
            signature_raw,
            Box::new(move |result| {
                let (err, valid) = prepare_result_1!(result, false);
                trace!("indy_verify_with_address: valid: {:?}", valid);
                cb(command_handle, err, valid)
            })
        )));

    let res = prepare_result!(result);

    trace!("indy_verify_with_address: <<< res: {:?}", res);

    res
}

 

Decentralized Key Management

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/005-dkms/README.html

 

Introduction(소개)

분산 키 관리 시스템(DKMS: Decentralized Key Management System)은 중앙 권한이 없는 암호화 키 관리 방법입니다. DKMS는 분산 원장의 보안, 불변성, 가용성 및 복원력 속성을 활용하여 확장성이 뛰어난 키 배포, 확인 및 복구를 제공합니다.

 

Key Types(키 타입)

DKMS는 다음 키 유형을 사용합니다.

  1. Master keys(마스터 키): 암호로 보호되지 않은 키. 이들은 절차 제어와 물리적 또는 전자적 격리에 의해 수동으로 또는 초기에 설치되고 보호됩니다.
  2. Key encrypting keys(키 암호화 키): 키 전송 또는 다른 키 저장에 사용되는 대칭 또는 공개 키
  3. Data keys(데이터 키): 사용자 데이터에 대한 암호화 작업을 제공하는 데 사용됩니다(예: 암호화, 인증).

한 레벨의 키는 하위 레벨의 항목을 보호하는 데 사용됩니다. 따라서 액세스 및 사용을 엄격하게 제한하고 하드웨어를 보호하고 공유 제어 하에서만 키에 대한 액세스를 제공하는 등 Master keys(마스터 키)를 보호하기 위한 특별한 조치가 사용됩니다.

 

Key Loss(키 손실)

키 손실은 소유자가 더 이상 키를 제어하지 않으며 더 이상 손상될 위험이 없다고 가정할 수 있음을 의미합니다. 예를 들어 물, 전기, 파손, 화재, 하드웨어 고장, 신의 행위 등으로 인해 장치가 작동하지 않을 수 있습니다.

 

Compromise(타협)

키 타협은 개인 키 및/또는 마스터 키가 수동 또는 능동적으로 알려지거나 알려질 수 있음을 의미합니다.

 

Recovery(복구)

분산 신원 관리에서는 identity 소유자가 복구를 위한 "높은 권한"을 가지지 않기 때문에 복구가 중요합니다.

  1. 오프라인 복구는 실제 미디어 또는 이동식 디지털 미디어를 사용하여 복구 키를 저장합니다.
  2. 소셜 복구는 일반적으로 trustee 자신의 agent(s)에 identity 소유자를 대신하여 복구 제이터를 저장하는 "trustees"라는 identity 소유자가 신뢰하는 엔티티를 사용합니다.

이러한 방법은 배타적이지 않으며 적절한 보안을 위해 키 순환 및 해지와 결합되어야합니다.

  1. Design and architecture
  2. Agent 인증 정책을 위핸 공개 레지스트리(Public Registry for Agent Authorization Policy). identity 소유자는 원장에 Agent 및 권한을 정의하는 정책을 생성합니다. identity 소유자를 대신하여 행동하는 Agent는 권한이 있음을 증명해야합니다. 자세한 내용

 

Additional Info(추가 정보)

 

CLI plugins

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/006-cli-plugins/README.html

이 디자인은 Indy CLI에서 플러그인을 지원하는 방법을 제안합니다.

 

Goals and ideas

  • Libindy는 현재 두 가지 유형의 기능을 연결할 수 있습니다.
    • custom wallet 보관
    • custom payment 메소드
  • 플러그인을 등록하기 위해 libindy는 각 유형의 연결 조작에 대해 C-handler를 등록할 수 있는 API 호출을 제공합니다.
  • libindy 플러그인을 구현하는 현재 비전 라이브러리에서는 핸들러를 등록하기 위해 내부적으로 libindy API를 호출하는 일종의 퍼블릭 "init" 기능을 제공해야합니다. 플러그인 등록은 C 함수를 호출하는 것입니다.
  • "init" 함수에는 매개 변수가 하나만 있어야합니다. 이 함수는 libindy 에러 코드를 반환하는 콜백입니다.
  • CLI는 플러그인 동적 라이브러리의 이름과 "init" 함수의 이름을 지정할 수 있는 명령 줄 옵션을 제공할 수 있습니다. 시작 시 CLI는 올바른 옵션으로 dlopen(또는 LoadLibrary)을 호출하여 이름 링크를 수행합니다. CLI는 이름별로 init 함수를 찾아서 호출합니다.
  • 또한 플러그인과 비슷한 방법으로 CLI 명령을 제공해야합니다.

 

Linking

 

Command line param to load plugins on start(시작시 플러그인을 로드하는 명령 줄 매개 변수)

indy-cli --plugins <lib-1-name>:<init-func-1-name>,...,<lib-n-name>:<init-func-n-name>

예:

indy-cli --plugins libnullpay:nullpay_init,libstorage:storage_init

 

Command to load plugin(플러그인을 로드하는 명령)

indy> load-plugin library=<library-name> initializer=<init-func-name>

예:

indy> load-plugin library=libnullpay initializer=nullpay_init

 

Payment Interface

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/007-cli-payments/README.html

이 디자인은 결제(payment)를 처리하기 위해 Indy CLI에 명령 목록을 제안합니다.

 

Goals and ideas

  • Indy CLI는 주요 결제(payment) 작업을 수행할 수 있는 기능을 제공해야합니다.:
    • 결제 주소 생성
    • 결제 주소 목록
    • 결제 주소에 대한 소스 목록 가져오기
    • 결제 트랜잭션 전송
    • 트랜잭션 수수로 추가
    • 트랜잭션 수수로 받기
  • 추상화 수준은 Indy SDK와 일치해야합니다. 예를 들어 소스(source) 추상화를 숨기지 마십시오. 앞으로 추상화 레벨을 높이기 위해 새로운 명령을 추가할 수 있습니다.

 

New CLI commands

Create payment address(결제 주소 생성)

wallet에서 특정 결제 방법에 대한 결제 주소를 만듭니다.

indy> payment-address create payment_method=<payment-method> seed=[<seed>]

Returns:

  • 성공 또는 오류 메시지

 

List payment addresses(결제 주소 목록)

wallet에 결제 주소를 나열하십시오.

indy> payment-address list

Returns:

  • 열이 있는 표: 결제 주소, 결제 방법

 

Send GET_PAYMENT_SOURCES request(GET_PAYMENT_SOURCES 요청 전송)

지정된 결제 주소에 대한 소스 목록을 얻기 위해 요청을 보냅니다.

indy> ledger get-payment-sources payment_address=<payment-address>

Returns:

  • 열이 있는 표: 소스, 결제 주소, 금액, 기타

 

Send PAYMENT transaction(결제 트랜잭션 전송)

결제 트랜잭션을 전송합니다.

indy> ledger payment inputs=<source-1>,..,<source-n> outputs=(<recipient-0>,<amount>),..,(<recipient-n>,<amount>) [extra=<extra>]

 

Returns:

  • 열이 있는 표: 영수증, 수취인 결제 주소, 금액, 기타

"source-n"은 ledger get-sources 명령 출력의 "Source" 열에 표시되는 식별자입니다.

 

Send GET_FEES request(GET_FEES 요청 전송)

원장 트랜잭션에 대한 수수료를 받기 위해 요청을 보냅니다.

indy> ledger get-fees payment_method=<payment_method>

Returns:

  • 열이 있는 표: 트랜잭션, 금액

 

Prepare MINT transaction(MINT 트랜잭션 준비)

MINT 트랜잭션을 json으로 준비하십시오.

indy> ledger mint-prepare outputs=(<recipient-0>,<amount-0>),..,(<recipient-n>,<amount-n>) [extra=<extra>]

Returns:

  • MINT 트랜잭션 JSON

MINT 프로세스 전송은 다음과 같습니다.:

  • Steward 1은 ledger mint-prepare를 호출합니다.
  • ledger sign-multi를 호출해 서명합니다.
  • 요청 json을 Steward 2로 보냅니다(이제 1 개의 서명이 있음).
  • Steward 2는 ledger sign-multi를 호출하여 서명합니다.
  • 요청 json을 Steward 3에게 보냅니다(이제 2 개의 서명이 있음).
  • 모든 Steward가 요청에 서명합니다.
  • 모든 Steward가 서명한 요청을 보내기 위해 최신 Steward는 ledger send-custom을 호출합니다.

 

Prepare SET_FEES transaction(SET_FEES 트랜잭션 준비)

SET_FEES 트랜잭션을 json으로 준비하십시오.

indy> ledger set-fees-prepare payment_method=<payment_method> fees=<txn-type-1>:<amount-1>,...,<txn-type-n>:<amount-n>

Returns:

  • SET_FEES 트랜잭션 JSON

SET_FEES 프로세스 전송은 다음과 같습니다.:

  • Steward 1은 ledger set-fees-prepare를 호출합니다.
  • ledger sign-multi를 호출해 서명합니다.
  • 요청 json을 Steward 2로 보냅니다(이제 1 개의 서명이 있음).
  • Steward 2는 ledger sign-multi를 호출하여 서명합니다.
  • 요청 json을 Steward 3에게 보냅니다(이제 2 개의 서명이 있음).
  • 모든 Steward가 요청에 서명합니다.
  • 모든 Steward가 서명한 요청을 보내기 위해 최신 Steward는 ledger send-custom을 호출합니다.

 

Send VERIFY_PAYMENT_RECEIPT request(VERIFY_PAYMENT_RECEIPT 요청 전송)

결제 영수증을 검증하기 위한 정보를 얻기 위해 요청을 보냅니다.

ledger verify-payment-receipt <receipts>

Returns:

  • 영수증 정보 JSON

 

Sign the transaction (for multi-sign case) (트랜잭션에 서명(다중 서명 케이스))

트랜잭션에 JSON에 현재 DID별로 서명(다중 서명의 경우)을 추가하십시오.

indy> ledger sign-multi txn=<txn-json>

Returns:

  • 서명이 추가된 트랜잭션 JSON

 

Existing commands update(기존 명령 업데이트)

도메인 트랜잭션을 전송하는 모든 명령에는 트랜잭션 수수료를 추가하기 위해 새로운 선택적 매개 변수가 필요합니다.

[fees_inputs=<source-1>,..,<source-n>] [fees_outputs=(<recipient-0>,<amount>),..,(<recipient-n>,<amount>)] [extra=<extra>]

"source-n"은 ledger get-sources 명령 출력의 "Source" 열에 표시되는 식별자입니다.

 

Legend

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/008-state-proof-pluggable-parsing/README.html

클라이언트-노드 통신에서 StateProof(SP) 최적화 사용을 허용하는 Pool의 노드에 대한 request 유형이 있습니다. 클라이언트는 Pool의 모든 노드에 request를 보내는 대신, 단일 노드에 request를 보내고 Boneh-Lynn-Shacham(BLS) 다중 서명으로 서명된 StateProof를 기대할 수 있습니다.

BLS 다중 서명(BLS MS)은 State RootHash에 의해 식별된 일부 State에 서명한 노드에 대한 합의가 있음을 보증합니다. StateProof(SP)는 RootHash에 대한 특정 값을 확인할 수 있는 소량의 데이터입니다. BLS MS와 SP의 조합으로 클라이언트는 단일 노드의 응답이 충분한 수의 노드로 서명된 상태의 일부인지 확인할 수 있습니다.

 

Goals

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/008-state-proof-pluggable-parsing/README.html#goals

Libindy는 또한 플러그 가능한 인터페이스를 통해 지원되는 request를 작성하고 보낼 수 있습니다. 이러한 연결된 트랜잭션에 대해 BLS MS 및 SP 검증을 지원할 수 있는 방법이 좋습니다.

SP 검증을 위한 수학적 구현은 플러그인 로직에 포함하기에는 약간 복잡합니다. 따라서 libindy는 SDK 내에서 모든 수학 계산을 수행해야합니다. 플러그인은 사용자 정의 응답을 듣고 고정된 데이터 구조로 구문 분석하기 위한 핸들러를 제공해야합니다.

 

API

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/008-state-proof-pluggable-parsing/README.html#api

핸들러의 서명은 result 데이터를 할당 해제하기 위한 custom free 호출과 함께 아래에 설명되어 있습니다.

extern fn CustomTransactionParser(reply_from_node: *const c_char, parsed_sp: *mut *const c_char) -> ErrorCode;
extern fn CustomFree(data: *mut c_char) -> ErrorCode;

libindy API에는 특정 트랜잭션 유형에 대한 핸들러를 등록하기 위한 호출이 포함됩니다.:

extern fn indy_register_transaction_parser_for_sp(command_handle: i32,
                                                  txn_type: *const c_char,
                                                  parser: CustomTransactionParser,
                                                  free: CustomFree,
                                                  cb: extern fn(command_handle_: i32, err: ErrorCode)) -> ErrorCode;

 

Parsed Data structure

플러그인은 reply_from_node를 구문 분석하고 구문 분석된 데이터를 libindy에 JSON 문자열로 다시 리턴해야합니다. 실제로 이 데이터는 엔티티의 배열이며 각각은 SP Trie 및 이 Trie에 대해 검증하기 위한 key-value 쌍 집합으로 설명됩니다. JSON으로 직렬화된 Vec<ParsedSP>로 표시될 수 있습니다.

/**
 Single item to verification:
 - SP Trie with RootHash
 - BLS MS
 - set of key-value to verify
*/
struct ParsedSP {
    /// encoded SP Trie transferred from Node to Client
    proof_nodes: String,
    /// RootHash of the Trie, start point for verification. Should be same with appropriate filed in BLS MS data
    root_hash: String,
    /// entities to verification against current SP Trie
    kvs_to_verify: KeyValuesInSP,
    /// BLS MS data for verification
    multi_signature: serde_json::Value,
}

/**
 Variants of representation for items to verify against SP Trie
 Right now 2 options are specified:
 - simple array of key-value pair
 - whole subtrie
*/
enum KeyValuesInSP {
    Simple(KeyValueSimpleData),
    SubTrie(KeyValuesSubTrieData),
}

/**
 Simple variant of `KeyValuesInSP`.

 All required data already present in parent SP Trie (built from `proof_nodes`).
 `kvs` can be verified directly in parent trie

 Encoding of `key` in `kvs` is defined by verification type
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct KeyValueSimpleData {
    pub kvs: Vec<(String /* key */, Option<String /* val */>)>,
    #[serde(default)]
    pub verification_type: KeyValueSimpleDataVerificationType
}

/**
 Options of common state proof check process
*/
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
#[serde(tag = "type")]
pub enum KeyValueSimpleDataVerificationType {
    /* key should be base64-encoded string */
    Simple,
    /* key should be plain string */
    NumericalSuffixAscendingNoGaps(NumericalSuffixAscendingNoGapsData)
}

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct NumericalSuffixAscendingNoGapsData {
    pub from: Option<u64>,
    pub next: Option<u64>,
    pub prefix: String
}

/**
 Subtrie variant of `KeyValuesInSP`.

 In this case Client (libindy) should construct subtrie and append it into trie based on `proof_nodes`.
 After this preparation each kv pair can be checked.
*/
struct KeyValuesSubTrieData {
    /// base64-encoded common prefix of each pair in `kvs`. Should be used to correct merging initial trie and subtrie
    sub_trie_prefix: Option<String>,
    kvs: Vec<(String /* b64-encoded key_suffix */, Option<String /* val */>)>,
}

예상되는 libindy 및 플러그인 워크 플로우는 다음과 같습니다.

  1. Libindy는 노드로부터 응답을 수신하고, 초기 프로세싱을 수행하며 raw 응답을 플러그인에 전달합니다.
  2. 플러그인은 노드의 응답을 구문 분석하고 메타 데이터 및 검증 항목으로 하나 이상의 SP Trie를 지정합니다.
  3. 각 SP Trie는 플러그인에 의해 ParsedSP로 설명됩니다.:
    1. 노드에서 수신한 SP Trie의 인코딩된 노드 세트 - proof_nodes. "as is" 응답에서 가져올 수 있습니다.
    2. 이 Trie의 RootHash. "as is" 응답에서 가져올 수 있습니다.
    3. BLS MS 데이터. "as is" 응답에서 가져올 수 있습니다.
    4. 검증을 위한 key-value 항목. 여기에서 플러그인은 올바른 키(trie의 경로)와 해당 값을 정의해야합니다.
  4. 플러그인은 ParsedSP의 JSON 배열로 직렬화를 반환합니다.
  5. 각 ParsedSP 라이브러리에 대해:
    1. proof_nodes에서 기본 trie 빌드
    2. 검증할 항목이 SubTrie인 경우, (key-suffix, value) 쌍으로 이 subtrie를 구성하고 위의 trie from 절과 병합하십시오.
    3. 다른 key-value 쌍을 반복하고 trie(서명된 root_hash 포함)에 지정된 key의 value가 포함되어 있는지 확인하십시오.
    4. 다중 서명을 검증하십시오.
  6. 검증에 실패하면 libindy는 해당 특정 SP + BLS MS를 무시하고 다른 노드에서 동일한 데이터를 요청하거나 충분한 수의 노드에서 동일한 응답에 대한 합의를 수집합니다.

다음은 Simple 케이스의 JSON 구조입니다.

[
 {
   "proof_nodes": "string with serialized SP tree",
   "root_hash": "string with root hash",
   "kvs_to_verify": {
     "type": "simple",
     "kvs": [["key1", "value1"], ["key2", "value2"]]
   },
   "multi_signature": "JSON object from Node`s reply as is"
 }
]

 

Simple and SubTrie Verification

일부 유즈 케이스에서는 한 Trie에서 여러 key-value 쌍을 검증해야합니다. 또한, 클라이언트가 전체 subtrie를 확인하려는 상황이 있을 수 있습니다. 이 경우, 노드에서 클라이언트로 전송되는 데이터의 양을 크게 줄일 수 있습니다. proof_nodes에 대한 SP 검증을 위해 모든 노드를 포함시키는 대신, 노드는 subtrie까지의 접두사(prefix) 경로만 포함할 수 있습니다. 검증할 전체 subtrie는 key-value 쌍에서 클라이언트 측으로 복원되고 접두사(prefix)와 결합될 수 있습니다.

 

Wallet Export/Import Design

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/009-wallet-export-import/README.html

현재 wallet의 모든 암호화는 libindy에서 수행됩니다. 스토리지 구현이 플러그인될 수 있습니다. 이 디자인은 휴대용 export/import 기능을 제안하므로 사용자가 wallet을 만든 소프트웨어에 대한 "lock-in"을 피할 수 있습니다.

 

Goals and ideas(목표 및 아이디어)

  • 사용자가 wallet을 내보내 백업을 수행하거나 secret data를 다른 agency 또는 다른 기기로 옮길 수 있습니다.
    • export 파일은 export 키로 암호화됩니다.
    • export는 전체 wallet 데이터(secret 포함)를 포함해야합니다.
    • 보수적인 메모리가 있는 머신에서 큰 wallet을 export할 수 있도록 스트리밍 방식으로 export를 수행해야합니다.
  • 사용자가 export한 wallet을 import할 수 있습니다.
    • import는 빈 wallet에서만 허용되므로 import는 하나의 create + import 조작으로 수행됩니다.
    • export에 사용되는 키를 제공해야 export 파일이 해독될 수 있습니다.
    • 사용자는 import에서 새로 생성된 wallet을 여는 데 사용되는 새로운 master key를 제공해야합니다.
    • 보수적인 메모리가 있는 머신에서 큰 wallet을 import할 수 있도록 스트리밍 방식으로 import를 수행해야합니다.
  • Export/Import는 모든 스토리지 구현에서 작동합니다.
  • export 및 create + import wallet을 위한 두 가지 공용 API 함수를 노출하십시오.

 

Public API

/// Exports opened wallet's content using key and path provided in export_config_json
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// wallet_handle: wallet handle (created by open_wallet)
/// export_config_json: JSON containing settings for input operation.
///   {
///     "path": path of the file in which the wallet will be exported
///     "key": passphrase used to derive export key
///   }
///
/// #Returns
/// Error code
///
/// #Errors
/// Common*
/// Wallet*
extern pub fn indy_error_t indy_export_wallet(command_handle: i32,
                                              wallet_handle: i32,
                                              export_config_json: *const c_char,
                                              cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode)>) -> ErrorCode {}

/// Creates a new secure wallet with the given unique name and then imports its content
/// according to fields provided in import_config
///
/// #Params
/// command_handle: command handle to map callback to caller context
/// pool_name: Name of the pool that corresponds to this wallet
/// name: Name of the wallet
/// storage_type(optional): Type of the wallet storage. Defaults to 'default'.
///                  Custom storage types can be registered with indy_register_wallet_storage call.
/// config(optional): Wallet configuration json.
///   {
///       "storage": <object>  List of supported keys are defined by wallet type.
///   }
/// credentials: Wallet credentials json
///   {
///       "key": string,
///       "storage": Optional<object>  List of supported keys are defined by wallet type.
///
///   }
/// import_config_json: JSON containing settings for input operation.
///   {
///     "path": path of the file that contains exported wallet content
///     "key": passphrase used to derive export key
///   }
///
/// #Returns
/// Error code
///
/// #Errors
/// Common*
/// Wallet*
extern pub fn indy_import_wallet(command_handle: i32,
                                 pool_name: *const c_char,
                                 name: *const c_char,
                                 storage_type: *const c_char,
                                 config: *const c_char,
                                 credentials: *const c_char,
                                 import_config_json: *const c_char,
                                 cb: Option<extern fn(xcommand_handle: i32, err: ErrorCode)>) -> ErrorCode {}

 

 

Deriving the key from passphrase(암호문에서 키 추출)

암호문에서 키를 추출하기 위해 Argon2 메모리 하드 기능은 random salt와 함께 사용됩니다.

 

File format(파일 형식)

-- plain stream(일반 스트림) --

  • header_length : 4b insigned little endian integer로 직렬화된 헤더의 길이
  • header : MessagePack은 레코드 엔티티를 직렬화합니다.

-- encrypted stream(암호화된 스트림) --

  • header_hash : 헤더의 32B SHA-256 해시
  • record1_length : 4b unsigned little endian integer로 직렬화된 레코드의 길이
  • record1 : MessagePack은 레코드 엔티티를 직렬화합니다.
  • ...
  • recordN_length : 4b unsigned little endian integer로 직렬화된 레코드의 길이
  • recordN : MessagePack은 레코드 엔티티를 직렬화합니다.
  • STOP : 4 zero bytes. export 파일이 잘리지 않았는지 확인할 수 있습니다.

Where:

pub struct Header {
    pub encryption_method: EncryptionMethod, // Method of encryption for encrypted stram
    pub time: u64, // Export time in seconds from UNIX Epoch
    pub version: u32, // Version of header
}

pub enum EncryptionMethod {
    ChaCha20Poly1305IETF { // **ChaCha20-Poly1305-IETF** cypher in blocks per chunk_size bytes
        salt: Vec<u8>,  // pwhash_argon2i13::Salt as bytes. Random salt used for deriving of key from passphrase
        nonce: Vec<u8>, // chacha20poly1305_ietf::Nonce as bytes. Random start nonce. We increment nonce for each chunk to be sure in export file consistency
        chunk_size: usize, // size of encrypted chunk
    },
}

// Note that we use externally tagged enum serialization and header will be represented as:
//
// {
//   "encryption_method": {
//     "ChaCha20Poly1305IETF": {
//       "salt": ..,
//       "nonce": ..,
//       "chunk_size": ..,
//     },
//   },
//   "time": ..,
//   "version": ..,
// }

pub struct Record {
    #[serde(rename = "type")]
    pub type_: String, // Wallet record type
    pub id: String, // Wallet record id
    pub value: String, // Wallet record value
    pub tags: HashMap<String, String>, // Wallet record tags
}

최초의 암호화 방법에서 지원되는 것은 1024 바이트 당 블록 단위의 ChaCha20-Poly1305-IETF 암호입니다(스트리밍 허용). 이것은 libsodium secretstream에서 권장되는 암호화와 유사하지만 Rust wrapper에서는 secretstream을 사용할 수 없습니다. random salt는 암호문에서 키를 추출하는 데 사용됩니다. export 파일의 일관성을 보장하기 위해 각 블록마다 nonce를 증가시킵니다. 또한 export 파일이 잘리지 않도록 STOP 메시지를 암호화된 스트림으로 사용합니다.

 

Payment Interface

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/010-cli-wallet-export-import/README.html

이 디자인은 wallet export/import 작업을 처리하기 위해 Indy CLI에 명령 목록을 제안합니다.

 

Goals and ideas(목표 및 아이디어)

Indy CLI는 다음 작업을 수행할 수 있는 기능을 제공해야합니다.

  • 사용자가 wallet을 export해서 백업을 수행하거나 다른 디바이스로 이동할 수 있도록 합니다.
  • 사용자가 export한 wallet을 import할 수 있습니다.

 

New CLI commands

Export wallet

오픈된 wallet을 지정된 파일로 export합니다.

indy> wallet export export_path=<path-to-file> export_key=[<export key>]

Returns:

  • 성공 또는 오류 메시지

 

Import wallet

새로운 wallet을 생성한 다음 지정된 파일에서 컨텐츠를 import합니다.

indy> wallet import <wallet name> key=<key> export_path=<path-to-file> export_key=<key used for export>  [storage_type=<storage_type>] [storage_config={config json}]

Returns:

  • 성공 또는 오류 메시지

 

Wallet Query Language

원본 사이트 : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/docs/design/011-wallet-query-language/README.html

이 언어는 Non-secret, Anoncreds 검색 API에서 쿼리를 정의하는 데 사용됩니다.

query = {subquery}
subquery = {subquery, ..., subquery} - WHERE subquery AND ... AND subquery
subquery = $or: [{subquery},..., {subquery}] - WHERE subquery OR ... OR subquery
subquery = $not: {subquery} - Where NOT (subquery)
subquery = "tagName": tagValue - WHERE tagName == tagValue
subquery = "tagName": {$neq: tagValue} - WHERE tagName != tagValue
subquery = "tagName": {$gt: tagValue} - WHERE tagName > tagValue
subquery = "tagName": {$gte: tagValue} - WHERE tagName >= tagValue
subquery = "tagName": {$lt: tagValue} - WHERE tagName < tagValue
subquery = "tagName": {$lte: tagValue} - WHERE tagName <= tagValue
subquery = "tagName": {$like: tagValue} - WHERE tagName LIKE tagValue
subquery = "tagName": {$in: [tagValue, ..., tagValue]} - WHERE tagName IN (tagValue, ..., tagValue)

 

Tag types(태그 유형)

태그에는 두 가지 유형이 있습니다.

  • Un-encrypted(암호화되지 않음) - 태그 이름은 "~"로 시작합니다. 해당 태그는 암호화되지 않은 상태로 저장되어 복잡한 검색 쿼리(비교, 조건자)에서 이 태그를 사용할 수 있습니다.
  • Encrypted(암호화됨) - 해당 태그는 암호화되어 저장됩니다. 정확히 일치하는 태그만 검색할 수 있습니다.

참고: $or, $and, $not 조합은 두 태그 유형 모두에 사용할 수 있습니다.

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함