다중 서명 지갑을 통한 블록체인 보안 강화

디자인 랩의 다중 서명 기술을 사용하면 여러 개의 키가 필요한 블록체인 지갑을 만들 수 있습니다.

다중 서명 지갑을 통한 블록체인 보안 강화

다중 서명 지갑( Sui )은 두 개 이상의 암호화 키가 필요하기 때문에 공유 자산 관리를 위한 고유한 수단을 제공합니다. 전통적인 사용 사례의 예는 고객과 은행이 각각 금고의 잠금을 해제하는 데 필요한 물리적 키를 가지고 있는 대여금고로 거슬러 올라갑니다.

디자인 랩에서는 이 기술을 통합하고자 하는 빌더를 위한 다중 서명 SDK와 개인과 조직의 공유 계정을 관리할 수 있는 다중 서명, 다중 체인 지갑을 모두 개발했습니다.

대여금고와 비슷하지만, 이 유형의 지갑은 더 다양한 사용 사례를 제공합니다. 사용자는 지갑을 열기 위해 원하는 수의 암호화 키 또는 서명을 요구하도록 구성할 수 있습니다. 더욱 유용한 점은 다중 서명 지갑은 지갑을 여는 데 필요한 것보다 더 많은 수의 승인된 서명을 가질 수 있다는 것입니다. 예를 들어, 40명으로 구성된 위원회가 각각 승인된 키를 가지고 있지만 지갑의 디지털 자산에 액세스하는 데 필요한 키는 10개뿐이라고 가정해 보겠습니다.

Sui 에서 이 지갑에 다양한 디지털 자산을 보관할 수 있습니다. 에스크로를 예로 들어보겠습니다. 한 당사자가 다른 당사자로부터 실물 상품을 구매하는 데 동의할 수 있습니다. 구매자는 양쪽 당사자가 키를 가지고 있는 다중 서명 지갑에 결제금을 넣을 수 있습니다. 구매자가 상품을 받으면 키로 지갑을 잠금 해제하고 판매자가 지갑을 잠금 해제하고 자금을 인출할 수 있습니다.

이 예는 판매자가 상품을 배송하지 않았더라도 구매자가 키를 사용할 때까지 자금을 인출할 수 없으므로 사기를 방지할 수 있습니다. 구매에 대해 이견이 있는 경우 당사자가 해결할 때까지 자금에 액세스할 수 없습니다.

3개의 키가 표시된 이미지로, 그 중 2개는 자물쇠를 열기 위해 강조 표시되어 있습니다.
다중 서명 지갑을 열려면 두 개 이상의 암호화 키가 필요하며, 지갑 잠금을 해제하는 데 필요한 키의 개수보다 더 많은 키가 있을 수 있습니다.

다중 서명 지갑은 공유 계정 사용 사례 외에도 더 높은 투명성을 제공합니다. 모든 거래 정책, 서명자, 실제 거래는 블록체인에 공개되어 완벽한 가시성과 책임성을 제공합니다. 이러한 투명성은 거래 추적과 감사를 더욱 쉽게 만들어주며, 이는 규제 요건을 준수해야 하는 조직과 기관에 필수적인 요소입니다.

다중 서명 발전

기존의 다중 서명 지갑은 한동안 사용되어 왔지만, 연구자들은 고급 보안 기능에 대한 증가하는 수요를 충족하기 위해 더욱 새롭고 정교한 솔루션을 개발해 왔습니다. 위에서 설명한 것처럼, 디지털 다중 서명 지갑의 초기 사례는 거래를 승인하기 위해 여러 개의 키가 필요했으며, 다양한 구성이 가능했습니다.

계정 추상화

새로운 ERC-4337 표준은 스마트 콘트랙트가 거래에 관여할 필요 없이 다중 서명 지갑에 자금을 보관할 수 있도록 합니다. 이더리움 블록체인의 기여자들은 기존 디지털 지갑을 만드는 데 따르는 마찰을 줄이고 최신 뱅킹 앱에서 흔히 볼 수 있는 유형의 거래를 가능하게 하기 위해 이 기술을 개발했습니다. 사용자는 시드 문구가 필요하지 않으며 자동 및 반복 결제를 설정할 수 있습니다.

이 기술은 트랜잭션에 대한 유연성과 제어력을 높여주므로, 높은 수준의 보안을 유지하면서도 스마트 컨트랙트의 이점을 누리고자 하는 분들에게 인기가 높습니다.

임계값 서명 체계 및 다자간 계산

저희 다중 서명 지갑에는 임계값 서명 체계 및 다자간 계산 (TSS-MPC)이라는 일련의 기술을 사용합니다. 이러한 기술은 새로운 기술은 아니지만 다중 서명 지갑의 훌륭한 사용 사례를 제시합니다.

TSS는 여러 개의 암호화 키를 만드는 대신 개인 키를 여러 조각으로 분할하여 여러 당사자에게 배포합니다. 각 조각이 제출되면 하나의 마스터 키가 생성됩니다. 온체인에서 이 키는 단일 키 지갑 서명과 유사하게 작동합니다.

MPC는 키 공유를 저장하는 안전한 방법으로 TSS를 보완합니다. MPC는 각 당사자의 개인 데이터를 공개하지 않고 함수를 계산하는 데 사용되는 노드 네트워크입니다. 이 조합을 사용하면 한 당사자가 전체 개인 키에 액세스할 수 없으므로 공격자가 시스템을 손상시키기가 더 어려워집니다.

다음에 TSS 적용 SUI

Sui 지원 kn 다중 서명 트랜잭션 k 는 임계값이고 n은 참여하는 모든 파티의 총 가중치입니다. 최대 파티 수는 다음과 같아야 합니다. <= 10.

워크플로 예시

다음 예는 Sui 의 명령줄 인터페이스에서 다중 서명 트랜잭션에 사용할 키를 생성하는 방법을 보여 줍니다.

1단계: Sui 키스토어에 키 추가하기

다음 명령은 지원되는 각 키 체계에 대해 Sui 주소와 키를 생성하고 이를 sui.keystore를 클릭한 다음 키를 나열합니다.

SUI_BINARY 클라이언트 새 주소 ed25519
SUI_BINARY 클라이언트 새 주소 secp256k1
SUI_BINARY 클라이언트 새 주소 secp256r1

SUI_BINARY 키도구 목록

응답은 다음과 비슷하지만 실제 주소와 키를 표시합니다:

Sui 주소 | 공개 키(Base64) | 스키마
-----------------------------------------------------------------------
ADDR_1 | $PK_1 | secp256r1
ADDR_2 | $PK_2 | secp256k1
ADDR_3 | $PK_3 | ed25519

2단계: 다중 서명 주소 만들기

아래와 같이 공개 키 목록과 해당 가중치를 입력하면 다중 서명 주소가 만들어집니다.

SUI_BINARY 키툴 다중 서명 주소 --pks $PK_1 $PK_2 $PK_3 --가중치 1 2 3 --임계값 3

멀티시그 주소: 멀티시그 주소: $MULTISIG_ADDR

응답은 다음과 유사합니다:

참여 당사자:
Sui 주소 | 공개 키 (Base64)| 가중치
------------------------------------------
ADDR_1 | PK_1 | 1
ADDR_2 | PK_2 | 2
ADDR_3 | PK_3 | 3

3단계: 다중 서명 주소로 개체 보내기

아래 코드 스니펫은 Sui 설명서의 지침에 따라 기본 URL을 사용하여 로컬 네트워크에서 가스를 요청합니다.

curl --location --request POST '<http://127.0.0.1:9123/gas>' --header 'Content-Type: application/json' --data-raw "{ \\"FixedAmountRequest\\": { \\"recipient\\": \\"$MULTISIG_ADDR\\" } }"

응답은 다음과 유사합니다:

{"transferred_gas_objects":[{"amount":200000,"id":"$OBJECT_ID", ...}]}

4단계: 트랜잭션 직렬화

이 단계에서는 다중 서명 주소에 속한 개체를 사용하여 서명할 전송을 직렬화하는 방법을 설명합니다. 다음 사항에 유의하세요. TX_BYTES 는 발신자가 다중 서명 주소인 모든 직렬화된 트랜잭션 데이터일 수 있습니다. 단순히 --직렬화 출력 플래그를 사용하여 Base64로 인코딩된 트랜잭션 바이트를 출력합니다.

SUI_BINARY 클라이언트 전송 --to $MULTISIG_ADDR --object-id $OBJECT_ID --gas-budget 1000 --serialize-output

실행할 원시 tx_bytes: $TX_BYTES

5단계: 두 개의 키로 거래에 서명하기

다음 코드 샘플을 사용하여 두 개의 키를 사용하여 트랜잭션에 서명합니다. sui.keystore. 트랜잭션이 직렬화되어 있는 한 다른 도구를 사용하여 서명할 수 있습니다. 플래그 || 시그 || PK.

SUI_BINARY 키툴 서명 --주소 $ADDR_1 --data $TX_BYTES

실행할 원시 tx_byte: $TX_BYTES
직렬화된 서명(Base64의 `flag || sig || pk`): SIG_1

SUI_BINARY 키도구 서명 --주소 $ADDR_2 -데이터 $TX_BYTES

실행할 원시 tx_byte: $TX_BYTES
직렬화된 서명(Base64의 `flag || sig || pk`): SIG_2

6단계: 개별 서명을 다중 서명 주소로 결합하기

다음 샘플은 두 서명을 결합하는 방법을 보여줍니다.

SUI_BINARY 키툴 멀티-서명-결합-부분-서명 --pks $PK_1 $PK_2 $PK_3 --가중치 1 2 3 --임계치 3 --sigs $SIG_1 $SIG_2

멀티시그 주소: 멀티서명 주소: $MULTISIG_ADDRESS # 정보
멀티시그 구문 분석: $HUMAN_READABLE_STRUCT # 정보 제공
직렬화된 멀티시그: $SERIALIZED_MULTISIG

7단계: 다중 서명 주소로 트랜잭션 실행하기

이 샘플은 다중 서명 주소를 사용하여 트랜잭션을 실행합니다.

SUI_BINARY 클라이언트 실행-서명된-tx --tx-bytes $TX_BYTES --signatures $SERIALIZED_MULTISIG

MPC 기반 다중 서명 켜기 SUI

MPC 방식은 위 섹션에서 생성된 다양한 키 공유를 저장합니다. 저희의 MPC 구현에서는 샤미르의 비밀 공유 (SSS)라는 알고리즘을 사용하는데, 이 알고리즘은 그룹 내 임계값 수의 사람들이 지식을 합쳐야만 비밀을 복구할 수 있다는 제한이 있지만, 여러 사람 간에 비밀을 공유할 수 있습니다.

SSS를 사용하면 전체 비밀(이 경우 키)을 특정 수량의 비밀 조각에서 수학적으로 도출할 수 있습니다. 예를 들어 20개의 조각으로 나뉜 키의 경우, 전체 키를 도출하려면 그 중 최소 10개가 필요할 수 있습니다. 해커가 해당 키의 조각을 5개만 훔쳐도 전체 키를 도출할 수 없습니다.

이 기능은 블록체인과 같은 분산 시스템에서 매우 잘 작동합니다. 환경 자체가 데이터 무결성을 보장하고 리소스 공유 원칙을 기반으로 구축되어 있기 때문입니다.

TSS-MPC에 SSS를 구축하면 여러 가지 이점이 있습니다. 우선, 해킹당하거나 분실할 수 있는 중앙 비밀번호가 없습니다. 키의 일부가 여러 사람에게 분산되어 있기 때문에 전체 키를 얻으려면 상당수의 사용자를 해킹해야 합니다. 마찬가지로, 이 그룹에 속한 몇몇 사람이 키의 일부를 분실하더라도 충분한 부분이 남아 있으면 전체 키를 유추할 수 있습니다. 커뮤니티 관점에서 이 기술은 키를 사용하려면 정족수의 동의를 얻어야 하므로 임계값에 미달하는 한 사람이 키를 얻지 못하도록 합니다.

TSS-MPC의 복잡성은 구현에 어느 정도의 전문 지식이 필요하며, 단순한 방식보다 더 많은 계산 리소스를 사용한다는 것을 의미합니다. 이러한 점이 네트워크 문제와 결합되면 처음 키를 생성할 때 사용자에게 지연이 발생할 수 있습니다. 대규모 그룹 간의 키 공유를 조정하는 것도 문제가 될 수 있으며, 일반적으로 원활하고 명확한 커뮤니케이션이 필요합니다.

TSS-MPC 다중 서명 빌드하기 SUI

TSS-MPC 구현과 아래 코드 샘플을 통해 빌더가 다중 서명 기술을 프로젝트에 쉽게 추가할 수 있기를 바랍니다. 시작하려면 다음을 설치해야 합니다. @desig/web3 를 사용하여 원사 패키지 관리자. 명령줄 인터페이스에서 다음을 입력합니다. yarn 추가 @desig/web3.

예시 1:

아래 코드 샘플은 다중 서명, 잠금 해제 작업 제안, 충분한 키 보유자가 동의할 경우 잠금 해제되는 트랜잭션을 빠르게 생성하는 방법을 보여줍니다.

import { encode } from 'bs58'
import { utils } from '@noble/ed25519'
import { DesigKeypair, Multisig, Signer, Proposal, Transaction } from '@desig/web3'

const cluster = '<https://mainnet.desig.io>'
const privkey = encode(utils.randomPrivateKey())
const secretShare = 'ed25519/<master>/<share>'
const keypair = DesigKeypair.fromSecret(secret)

// Create multisig instance
const dMultisig = new Multisig(cluster, privkey)
await dMultisig.getMultisigs()
await dMultisig.getMultisig('multisigId')

// Create signer instance
const dSigner = new Signer(cluster, privkey)
await dSigner.getAllSigners()
await dSigner.getSigner('signerId')

// Create proposal instance
const dProposal = new Proposal(cluster, privkey, keypair)
await dProposal.approveProposal('proposalId')
await dProposal.initializeProposal({ raw: ..., msg: ..., chainId: ... })

// Create transaction instance
const dTransaction = new Transaction(cluster, privkey, keypair)
await dTransaction.initializeTransaction({ type: ..., params: { ... }})

await dTransaction.getTransaction('transactionId')
await dTransaction.signTransaction('transactionId')

예 2:

아래 샘플 코드는 다중 서명을 사용하여 SUI 전송을 승인하는 전체 프로세스를 설명합니다.

1단계: 다중 서명 만들기

import { encode } from 'bs58'
import { utils } from '@noble/ed25519'
import { Multisig } from '@desig/web3'
import { EdCurve } from '@desig/core'
import { Curve } from '@desig/supported-chains'

const privkey = encode(utils.randomPrivateKey())
const pubkey = encode(EdCurve.getPublicKey(decode(privkey)))

const dMultisig = new Multisig('<https://mainnet.desig.io>', privkey)
const t = 2 // threshold
const n = 2 // total weights
const pubkeys = [pubkey, pubkey] // You can change it to other members' pubkey
const curve = Curve.ed25519 // Refer <https://chainlist.desig.io/> to find the corresponding chain
const multisig = await dMultisig.initializeMultisig(curve, {
	t,
	n,
	pubkeys,
})

2단계: 이전 제안서 만들기 SUI

import { decode } from 'bs58'
import { DesigKeypair, Proposal } from '@desig/web3'
import { toSuiAddress, SuiDevnet } from '@desig/supported-chains'
import { blake2b } from '@noble/hashes/blake2b'
import {
	Connection,
	JsonRpcProvider,
	messageWithIntent,
	IntentScope,
	Ed25519PublicKey,
	toSerializedSignature,
} from '@mysten/sui.js'
import { transfer, sendAndConfirm } from '<appendix_transfer_sui'

const connection = new Connection({ fullnode: '<sui_fullnode>' })
const provider = new JsonRpcProvider(connection)

// Create alice keypair and bob keypair from secrets sent to the emails
const aliceKeypair = new DesigKeypair('<alice_secret_share>')
const bobKeypair = new DesigKeypair('<bob_secret_share>')

// aliceKeypair.masterkey === bobKeypair.masterkey is true
const masterkey = toSuiAddress(aliceKeypair.masterkey)

/**
	* Alice initializes a transaction
	*/
const aliceProposal = new Proposal(
	'<https://mainnet.desig.io>',
	alicePrivkey,
	aliceKeypair,
)
const bobProposal = new Proposal(
	'<https://mainnet.desig.io>',
	bobPrivkey,
	bobKeypair,
)

const tx = await transfer(masterkey, 5000)
const txSerialize = await tx.build({ provider })
const msg = messageWithIntent(IntentScope.TransactionData, txSerialize)
const digest = blake2b(msg, { dkLen: 32 })

const { id: proposalId } = await 
aliceProposal.initializeProposal({
	raw: txSerialize,
	msg: digest,
	chainId: new SuiDevnet().chainId,
})

/**
	* Alice approves the transaction
	*/
await aliceProposal.approveProposal(proposalId)
/**
	* Bob approves the transaction
	*/
await bobProposal.approveProposal(proposalId)

/**
	* Bob finalizes the transaction
*/
const { sig } = await bobProposal.finalizeSignature(proposalId)
const { raw } = await bobProposal.getProposal(proposalId)

const rawTx = decode(raw)
const serializedSig = toSerializedSignature({
	pubKey: new Ed25519PublicKey(masterkey),
	signature: sig,
	signatureScheme: 'ED25519',
})
/**
	* Bob submits the transaction
*/
const txHash = await sendAndConfirm(serializedSig, rawTx)

3단계: SUI 금액 이체

import { TransactionBlock, Connection, JsonRpcProvider } from '@mysten/sui.js'

const connection = new Connection({ fullnode: '<sui_fullnode>' })
const provider = new JsonRpcProvider(connection)

// Init transaction transfer
export const transfer = async (payer: string, amount: number) => 
{
	const tx = new TransactionBlock()
	const [coin] = tx.splitCoins(tx.gas, [tx.pure(amount.toString())])
	tx.transferObjects([coin], tx.pure(payer))
	tx.setSender(payer)
	return tx
}

export const sendAndConfirm = async (
	signature: string,
	txBlock: Uint8Array,
) => {
	const { digest } = await provider.executeTransactionBlock({
		signature,
		transactionBlock: txBlock,
	})
	return digest
}

공유 보안

디자인 랩스에서 개발한 다중 서명 기술은 에스크로처럼 일시적이든, 그룹 재무부처럼 영구적이든, 공유 자산에 대한 보안과 중요한 솔루션을 제공합니다. Sui 탈중앙화를 통해 다중 서명 지갑이 제공하는 공유 제어 기능을 보완할 수 있는 환경을 제공합니다.

다중 서명 문서를 살펴보고 위의 코드 샘플을 사용해 여러분의 프로젝트에 통합해 보세요. 궁금한 점이 있으면 문의해 주세요.

프로젝트에서 다중 서명 보안을 다양하게 활용할 수 있게 되어 기대가 큽니다.