본문으로 건너뛰기

다중 서명 인증

Sui는 단일 key signature가 아니라 여러 key를 authorization에 요구하는 multi-signature(multisig) transaction을 지원한다. Sui는 k out of n multisig transaction을 지원하며, 여기서 k는 threshold이고 n은 모든 참여 party의 total weight이다. 최대 party 수는 10이다. 지원되는 single key signature에 대해 더 알아보려면 서명을 참조한다.

multisig에 참여할 수 있는 유효한 key는 다음과 같다:

  1. Pure Ed25519

  2. ECDSA Secp256k1

  3. ECDSA Secp256r1.

각 participating key에는 u8 weight가 설정되며 threshold는 u16으로 설정할 수 있다. serialized multisig에 충분한 valid signature가 포함되어 있고 그 weight 합이 threshold를 넘으면 Sui는 multisig를 valid로 간주하고 transaction을 실행한다.

multisig application

Sui에서는 하나의 multisig account 안에서 key scheme을 섞어 사용할 수 있다. 예를 들어 Ed25519 mnemonic 기반 key 하나와 ECDSA Secp256r1 key 두 개를 선택해, 항상 Ed25519 key가 필요하면서도 ECDSA Secp256r1 key 중 하나도 서명해야 하는 multisig account를 만들 수 있다. 이 구조를 mobile secure enclave stored key를 사용하는 two-factor authentication에 활용할 수 있다.

정보

현재 iPhone과 일부 Android device는 ECDSA Secp256r1 enclave-stored key만 지원한다.

threshold signature와 비교하면 multisig account는 일반적으로 복잡한 multi-party computation(MPC) account setup ceremony와 관련 software, threshold crypto provider에 대한 dependency 없이 더 유연하고 구현 및 사용이 간단하다. 또한 key scheme을 섞어 쓰고 각 key에 서로 다른 weight를 설정할 수 있다는 점(이는 threshold cryptography에서는 복잡함) 외에도, multisig account는 참여 party와 observer가 각 transaction에 누가 서명했는지 볼 수 있으므로 설계상 accountable하고 transparent하다. 반면 threshold signature는 threshold policy를 숨기는 이점이 있지만 single signature payload를 만들기 때문에 single-key account와 구별하기 어렵다.

Multisig structure diagram Sui에서 지원되는 multisig structure.

다음 단계는 다중 서명(multisig) transaction을 생성한 다음 Sui CLI를 사용해 network에 제출하는 방법을 보여준다. transaction은 object transfer, package publish 또는 upgrade, SUI payment 등이 될 수 있다.

TypeScript SDK를 사용해 다중 서명 주소(multisig address)를 만들고 다중 서명 transaction을 생성하는 방법을 더 알아보려면 SDK documentation을 참조한다.

Click to open

Create Sui account and setup CLI environment

$ sui client

If this is the first time running the sui client CLI tool, it asks you to provide a Sui full node server URL and a meaningful environment alias. It also generates an address with a random key pair in sui.keystore and a config client.yaml.

By default, the client.yaml and sui.keystore files are located in ~/.sui/sui_config. For more information, refer to the Sui client CLI tutorial.

If this is not your first time running sui client, then you already have a client.yaml file in your local environment. If you'd like to create a new address for this tutorial, use the command:

$ sui client new-address ed25519
  • Obtain test tokens.
Click to open

How to obtain tokens

If you are connected to Devnet or Testnet networks, use the Faucet UI to request tokens.

If you are connected to a local full node, learn how to get local network tokens.

이 문서는 Sui CLI, 특히 sui clientsui keytool command에 어느 정도 익숙하다고 가정한다. 따라서 어떤 command는 별도의 맥락 설명 없이 소개될 수 있다. 참조된 command의 세부사항이 확실하지 않다면 Sui CLI documentation에서 자세한 정보를 확인한다.

object를 받으려면 작업 중인 network에 이미 존재하는 address가 하나 필요하다. 이 문서는 이 address가 현재 active address(sui client active-address)라고 가정하지만, 접근 가능한 어떤 address여도 괜찮다.

이 문서는 또한 active environment가 Testnet(sui client active-env)이라고 가정한다. 이 단계는 Devnet 또는 local network에서도 수행할 수 있지만, command를 그에 맞게 조정해야 한다.

multisig transaction 실행

다중 서명을 보여주기 위해 이 문서는 Sui CLI를 사용해 다중 서명 transaction을 설정하고 실행하는 과정을 안내한다.

다른 scheme으로 address 생성

먼저 나중에 instruction에서 수행할 transaction의 signer 역할을 할 address 세 개를 만든다. sui client new-address command를 사용해 지원되는 세 가지 key scheme에 대한 Sui address와 public key를 생성한다.

$ sui client new-address ed25519
$ sui client new-address secp256k1
$ sui client new-address secp256r1

console은 각 성공적인 호출에 대해 다음과 비슷한 response를 표시한다:

╭──────────────────────────────────────────────────╮
│ Created new key pair and saved it to keystore. │
├────────────────┬─────────────────────────────────┤
│ alias │ <ALIAS> │
│ address │ <SUI-ADDRESS> │
│ keyScheme │ <KEY-SCHEME> │
│ recoveryPhrase │ <RECOVERY-PHRASE> │
╰────────────────┴─────────────────────────────────╯

blockchain data를 다룰 때 address와 hashed value는 CLI 환경에서 다루기 번거로운 긴 string을 만든다. 후속 command에서 값을 더 쉽게 참조하고(그리고 copy and paste를 쉽게 하기 위해) 이 문서는 shell variable을 사용한다. console response에서 받은 값을 사용해 이 address들에 대한 shell variable을 설정하되, <SUI-ADDRESS-*> 변수는 적절한 address로 바꾼다.

$ ADDRESS1=<SUI-ADDRESS-ED25519>
$ ADDRESS2=<SUI-ADDRESS-SECP256K1>
$ ADDRESS3=<SUI-ADDRESS-SECP256R1>

active address를 할당한 shell variable도 하나 더 만든다.

$ ACTIVE=<ACTIVE-ADDRESS>

원한다면 shell variable에 address 대신 alias 값을 설정해도 된다.

address verify

sui keytool을 사용해 이전 section에서 만든 address를 나열한다.

$ sui keytool list

response는 다음과 비슷하지만 실제 alias 이름, address, key, peer ID를 표시한다:

╭────────────────────────────────────────────────────────────────────╮
│ ╭─────────────────┬──────────────────────────────────────────────╮ │
| | alias | <ALIAS-NAME> | |
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ ed25519 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────╮ │
| | alias | <ALIAS-NAME> | |
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256k1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────╯ │
│ ╭─────────────────┬──────────────────────────────────────────────╮ │
| | alias | <ALIAS-NAME> | |
│ │ suiAddress │ <SUI-ADDRESS> │ │
│ │ publicBase64Key │ <PUBLIC-KEY> │ │
│ │ keyScheme │ secp256r1 │ │
│ │ flag │ 0 │ │
│ │ peerId │ <PEER-ID> │ │
│ ╰─────────────────┴──────────────────────────────────────────────╯ │
╰────────────────────────────────────────────────────────────────────╯

output에는 나중에 사용할 public key 데이터가 포함되어 있으므로, 이 정보를 저장할 shell variable을 만든다. <PUBLIC-KEY-*>를 이전 console response에서 받은 실제 값으로 바꾸는 것을 잊지 않는다.

$ PKEY_1=<PUBLIC-KEY-ED25519>
$ PKEY_2=<PUBLIC-KEY-SECP256K1>
$ PKEY_3=<PUBLIC-KEY-SECP256R1>

multisig address 생성

다중 서명을 사용해 transaction에 서명하려면 sui keytool multi-sig-address를 사용해 다중 서명 주소를 만들어야 한다. 다중 서명 주소는 각 개별 참여 address의 public key를 사용해 생성된다. 또한 각 address에는 유효한 signature를 만드는 데 얼마나 필요한지를 결정하는 weight 값이 할당된다. 합산했을 때 포함된 signature의 weight는 command에서 함께 설정하는 threshold 값 이상이어야 한다. 이 예시에서는 다음 command를 사용하며, 이는 첫 번째 두 address는 유효한 다중 서명을 만들기 위해 적어도 하나의 signature가 더 필요하다는 뜻이다. 마지막 address는 threshold 값과 같은 3의 weight를 가지므로 그 소유자만으로도 유효한 signature를 만들 수 있다.

$ sui keytool multi-sig-address --pks $PKEY_1 $PKEY_2 $PKEY_3 --weights 1 2 3 --threshold 3

response는 다음과 비슷하다:

╭─────────────────┬─────────────────────────────────────────────────────────╮
│ multisigAddress │ <MULTISIG-ADDRESS> │
│ multisig │ ╭─────────────────────────────────────────────────────╮ │
│ │ │ ╭─────────────────┬───────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 1 │ │ │
│ │ │ ╰─────────────────┴───────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬───────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 2 │ │ │
│ │ │ ╰─────────────────┴───────────────────────────────╯ │ │
│ │ │ ╭─────────────────┬───────────────────────────────╮ │ │
│ │ │ │ address │ <SUI-ADDRESS> │ │ │
│ │ │ │ publicBase64Key │ <PUBLIC-KEY> │ │ │
│ │ │ │ weight │ 3 │ │ │
│ │ │ ╰─────────────────┴───────────────────────────────╯ │ │
│ │ ╰─────────────────────────────────────────────────────╯ │
╰─────────────────┴─────────────────────────────────────────────────────────╯

multisig address에 SUI 추가

SUI를 받기 전에 이전 response의 맨 위에 있는 다중 서명 주소를 MULTISIG shell variable에 설정한다(<MULTISIG-ADDRESS>를 실제 address로 대체한다).

$ MULTISIG=<MULTISIG-ADDRESS>

sui client objects $MULTISIG command를 사용하면 새로 만든 다중 서명 주소에 object가 없다는 것을 볼 수 있다. 이는 transaction을 수행하기 전에 SUI를 받아야 함을 뜻한다. 다중 서명 계정에 SUI를 받으려면 sui client faucet command를 사용하고 --address flag로 다중 서명 주소를 제공한다. 이 command를 두 번 실행하여 다중 서명 주소가 적어도 SUI 두 개를 소유하게 한다. 이 예시에서는 하나는 transfer에 사용하고 다른 하나는 gas를 지불하는 데 사용하기 위해 SUI 두 개를 사용한다.

$ sui client faucet --address $MULTISIG

sui client gas command를 사용해 이제 해당 address에 적어도 SUI 두 개가 있는지 확인한다.

$ sui client gas $MULTISIG

active address로 SUI transfer

이제 다중 서명 주소에서 object를 transfer할 차례이다. 단순화를 위해 이 예시는 다중 서명 주소가 소유한 coin 중 하나를 transfer object로 사용한다. address의 coin 하나에 대한 object ID를 복사하고 이를 사용해 shell variable 값을 설정한다.

$ COIN=<COIN-OBJECT-ID>

sui client transfer command를 사용해 transfer를 설정한다. --serialize-unsigned-transaction flag는 Base64로 인코딩된 transaction bytes를 출력한다.

Beginning with the Sui v1.24.1 release, the --gas-budget option is no longer required for CLI commands.

$ sui client transfer --to $ACTIVE --object-id $COIN --gas-budget <GAS-AMOUNT> --serialize-unsigned-transaction

console은 결과값(<TX-BYTES-RESULT>)을 표시하며, 이를 다른 shell variable에 할당할 수 있다.

$ TXBYTES=<TX-BYTES-RESULT>

두 public key로 transaction sign

sui keytool sign command를 사용해 앞서 만든 address 중 두 개로 transaction에 서명한다.

정보

flag || sig || pk로 serialize하기만 하면 다른 도구를 사용해 signature를 생성할 수도 있다.

$ sui keytool sign --address $ADDRESS1 --data $TXBYTES
$ sui keytool sign --address $ADDRESS2 --data $TXBYTES

command를 성공적으로 호출할 때마다 다음과 비슷한 response를 받는다.

╭──────────────┬─────────────────────────────╮
│ suiAddress │ <ADDRESS> │
│ rawTxData │ <TRANSACTION-HASH> │
│ intent │ ╭─────────┬─────╮ │
│ │ │ scope │ 0 │ |
│ │ │ version │ 0 │ |
│ │ │ app_id │ 0 │ |
| | ╰─────────┴─────╯ │
│ rawIntentMsg │ <INTENT-MSG-HASH> │
│ digest │ <DIGEST-HASH> │
│ suiSignature │ <SIGNATURE-HASH> │
╰──────────────┴─────────────────────────────╯

signature를 저장할 shell variable 두 개를 더 만들되, <SIGNATURE-HASH-*>는 이전 command response의 값으로 바꾼다.

$ SIG_1=<SIGNATURE-HASH-ED25519>
$ SIG_2=<SIGNATURE-HASH-SECP256K1>

개별 signature를 multisig로 결합

앞서 언급했듯 다중 서명은 참여 signer의 weight 합이 threshold 값 이상이 되도록 충분한 개별 signature로 구성되어야 한다. sui keytool multi-sig-combine-partial-sig command를 사용해 ed25519 signature(weight: 1)와 secp256k1(weight: 2)를 결합한다. command를 완성하려면 다중 서명 주소를 정의했던 모든 public key, 각 weight, threshold를 제공해야 한다.

$ sui keytool multi-sig-combine-partial-sig --pks $PKEY_1 $PKEY_2 $PKEY_3 --weights 1 2 3 --threshold 3 --sigs $SIG_1 $SIG_2

성공하면 console은 다음과 비슷한 메시지로 응답한다.

╭────────────────────┬──────────────────────────────╮
│ multisigAddress │ <MULTISIG-ADDRESS> │
│ multisigParsed │ <MULTISIG-PARSED-HASH> │
│ multisigSerialized │ <MULTISIG-SERIALIZED-HASH> │
╰────────────────────┴──────────────────────────────╯

transaction 실행

sui client execute-signed-tx를 사용해 다중 서명 transaction을 실행한다. 이전 response에서 받은 multisigSerialized 값을 shell variable로 설정한 다음, 이를 사용해 execute-signed-tx command를 구성한다.

$ MULTISIG_SERIALIZED=<MULTISIG-SERIALIZED-HASH>
$ sui client execute-signed-tx --tx-bytes $TXBYTES --signatures $MULTISIG_SERIALIZED

성공하면 console은 transaction detail을 응답한다.

Click to open

Transaction response

이 response는 테스트 서명에서 나온 실제 값을 담고 있다. response의 형식은 같아야 하지만, 여러분이 받는 값은 다를 것이다.

Transaction Digest: 7mBWUxT6HUVDa8bii3PZJc7nhWqefTLNTsGbHYnx7ZA4
╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Data │
├─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Sender: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ Gas Owner: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ Gas Budget: 2997880 MIST │
│ Gas Price: 1000 MIST │
│ Gas Payment: │
│ ┌── │
│ │ ID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Version: 289574879 │
│ │ Digest: 2PMc8L67YbZmna4hoaryX9cZZFSgFNPEYPEeCqcDPCcX │
│ └── │
│ │
│ Transaction Kind: Programmable │
│ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │
│ │ Input Objects │ │
│ ├──────────────────────────────────────────────────────────────────────────────────────────────────────────┤ │
│ │ 0 Pure Arg: Type: address, Value: "0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241" │ │
│ │ 1 Imm/Owned Object ID: 0xe7acb59c190d7fcfcb622916e929c92007f6da15128fd84c8a2afd94a39edf11 │ │
│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │
│ ╭──────────────────────╮ │
│ │ Commands │ │
│ ├──────────────────────┤ │
│ │ 0 TransferObjects: │ │
│ │ ┌ │ │
│ │ │ Arguments: │ │
│ │ │ Input 1 │ │
│ │ │ Address: Input 0 │ │
│ │ └ │ │
│ ╰──────────────────────╯ │
│ │
│ Signatures: │
│ AwICIrr3sYG1hx2DaVkS3levGuTv68GA1RL+6ZFbtnFV5PBPkEHuysjme9nG0hZ3hQ0eDds2CedbKkLqDyCUXMNQDwEUtr9SYWRGiJJih21cAXgpSxf5Y53HFcmzJPWfxac54l21YVx6hc7vhI1xunMzhVeQlCa53vVJiAtWKLKz+H7FBgADAPZrm85y/Gn83R6kUhXme9J8W2ilJyda6cAObtuyJ3CqAQICAwSWHr3Q2vGVFH4SQckaQs76X89S6hX3NUarydSY3jgCAQNqj1MFWmTysOPFDXdNfD2kJlQhWTiT3AbxdlJDDWozIgMDAA== │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Transaction Effects │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Digest: 7mBWUxT6HUVDa8bii3PZJc7nhWqefTLNTsGbHYnx7ZA4 │
│ Status: Success │
│ Executed Epoch: 600 │
│ Mutated Objects: │
│ ┌── │
│ │ ID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ Version: 289574880 │
│ │ Digest: DWmLziJZEHwhkAfdBWVhn8HnJU7DMepDmjVLps2peSx8 │
│ └── │
│ ┌── │
│ │ ID: 0xe7acb59c190d7fcfcb622916e929c92007f6da15128fd84c8a2afd94a39edf11 │
│ │ Owner: Account Address ( 0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241 ) │
│ │ Version: 289574880 │
│ │ Digest: JBA6PrhWuTUJ3P8NXBpgBetFBaSJacEvQKS4USK9EfAr │
│ └── │
│ Gas Object: │
│ ┌── │
│ │ ID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ Version: 289574880 │
│ │ Digest: DWmLziJZEHwhkAfdBWVhn8HnJU7DMepDmjVLps2peSx8 │
│ └── │
│ Gas Cost Summary: │
│ Storage Cost: 1976000 MIST │
│ Computation Cost: 1000000 MIST │
│ Storage Rebate: 1956240 MIST │
│ Non-refundable Storage Fee: 19760 MIST │
│ │
│ Transaction Dependencies: │
│ F6TBXbvdK9fi4BnxZMBkL7QeNyv1612778i12ZPhafJD │
│ HFi4TniDvgL1jDzgPHjzJhxR8nbavLmPH3LLDnNL5Tqd │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯
╭─────────────────────────────╮
│ No transaction block events │
╰─────────────────────────────╯

╭──────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Object Changes │
├──────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Mutated Objects: │
│ ┌── │
│ │ ObjectID: 0xc62a5e163e599729509d6cebde097cac04e5d1b3bbc9a169144e8dfa602a0768 │
│ │ Sender: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 289574880 │
│ │ Digest: DWmLziJZEHwhkAfdBWVhn8HnJU7DMepDmjVLps2peSx8 │
│ └── │
│ ┌── │
│ │ ObjectID: 0xe7acb59c190d7fcfcb622916e929c92007f6da15128fd84c8a2afd94a39edf11 │
│ │ Sender: 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 │
│ │ Owner: Account Address ( 0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241 ) │
│ │ ObjectType: 0x2::coin::Coin<0x2::sui::SUI> │
│ │ Version: 289574880 │
│ │ Digest: JBA6PrhWuTUJ3P8NXBpgBetFBaSJacEvQKS4USK9EfAr │
│ └── │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────────────────────────────────────────────────────╮
│ Balance Changes │
├───────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ┌── │
│ │ Owner: Account Address ( 0x65437300e280695a40df8cf524c7bca6ad62574cac3a52d3b085ad628c797241 ) │
│ │ CoinType: 0x2::sui::SUI │
│ │ Amount: 1000000000 │
│ └── │
│ ┌── │
│ │ Owner: Account Address ( 0xfc9a64c928a09725cfe01478ad50c2418320b4c079d944ed430eff0f30666a35 ) │
│ │ CoinType: 0x2::sui::SUI │
│ │ Amount: -1001019760 │
│ └── │
╰───────────────────────────────────────────────────────────────────────────────────────────────────╯