Cedar 규칙 작성

이 페이지에서는 다자간 계산 (MPC) 정책 엔진에서 트랜잭션을 검증하기 위해 Cedar 정책 규칙을 작성하는 방법을 설명합니다.

정책 엔진은 안전한 신뢰할 수 있는 실행 환경 (TEE) 내에서 수신되는 트랜잭션 페이로드를 디코딩하고 트랜잭션 의도 속성을 Cedar 평가 컨텍스트에 투영합니다.

Cedar 규칙 구조

정책 엔진에 대한 Cedar 규칙을 작성할 때는 중첩된 조건 집합을 사용하여 규칙을 지정합니다.

  • 주 구성원: API를 호출하는 Google Cloud IAM ID (사용자 또는 서비스 계정)가 아닌 다자간 계산 작업공간 (예: User::"alice") 내 트랜잭션 요청자 (트랜잭션 개시자)의 논리적 ID입니다.
  • 작업: 요청된 암호화 작업 (예: Action::"sign_transaction")
  • 리소스: 작업 중인 타겟 애셋 또는 작업 클래스입니다 (예: Resource::"mpc_operation").
  • 컨텍스트: 파싱된 트랜잭션 메타데이터 및 매개변수 (context.transaction에서 액세스 가능)

이더리움 트랜잭션 스키마 참조

프로토콜에 구애받지 않는 프레임워크를 사용하면 규칙에서 스키마 검사를 생략하여 다양한 블록체인 네트워크에서 재사용할 수 있습니다. 하지만 규칙을 Ethereum 트랜잭션 페이로드로 명시적으로 제한하려면 context.transaction.schema == "ethereum.transaction.v2"를 확인하세요.

context.transaction 레코드 내에서 지원되는 속성은 다음과 같습니다.

속성 유형 설명
schema 문자열 형식 스키마입니다. 이더리움 트랜잭션의 경우 항상 "ethereum.transaction.v2"입니다.
operation 문자열 트랜잭션 작업 유형입니다. 지원되는 값:
  • "NATIVE_TRANSFER": 기본 체인 통화 (예: ETH)의 직접 전송입니다.
  • "TOKEN_TRANSFER": ERC-20 토큰 전송 (예: USDC, USDT, DAI)
  • "TOKEN_APPROVE": 계약에서 토큰을 사용할 수 있도록 하는 ERC-20 토큰 승인입니다.
  • "CONTRACT_CALL": 일반적인 스마트 계약 상호작용 (예: 스테이킹 또는 스왑)입니다.
chain_id 문자열 대상 블록체인 네트워크 ID (예: Ethereum 메인넷의 경우 "1", Sepolia 테스트넷의 경우 "11155111")
asset_symbol 문자열 전송되는 토큰의 티커 기호입니다 (예: "ETH", "USDC", "DAI", "WBTC"). 상장되지 않은 토큰은 "UNKNOWN"를 반환합니다.
asset_contract_address 문자열 ERC-20 토큰의 스마트 계약 주소입니다 (대소문자 혼합 EIP-55 체크섬 형식). 표준 ETH 전송의 경우 빈 문자열 ("")로 확인됩니다.
recipient 문자열 대상 수신자 주소 (대소문자 혼합 EIP-55 체크섬 형식)입니다. 토큰 승인의 경우 지출자 주소를 나타냅니다.
spend_amount_scaled 길이 토큰 전송 금액이 고정된 소수점 이하 9자리 정밀도 (나노코인 형식)로 정규화되어 규칙을 작성할 때 다양한 토큰 소수점 이하 자릿수 (예: 6, 8, 18)를 추적할 필요가 없습니다.

계산 방법: 사람이 읽을 수 있는 자산 금액 (예: 1.5 ETH 또는 5,000 USDC)에 1,000,000,000 (109)을 곱하여 규칙의 값을 구합니다.
  • 0.1 ETH → 100000000 (0.1 × 109)
  • 모든 애셋의 1.0 → 1000000000 (1.0 × 109)
  • 5,000 USDC → 5000000000000 (5,000 × 109)
spend_amount_dust 길이 소수점 이하 9자리 정밀도 기준 미만인 거래 금액의 나머지입니다. 소수점 이하 자릿수가 9자리 이상인 자산 (예: 18자리인 ETH)의 경우 조정되지 않은 하위 Gwei 값 (나머지 Wei)이 포함됩니다. 소수점 이하 자릿수가 9자리 이하인 자산 (예: USDC 또는 WBTC)의 경우 항상 0입니다.
max_fee_atomic 길이 최대 총 거래 수수료 한도 (109로 조정, Gwei를 나타냄)입니다.
gas_limit 길이 트랜잭션 실행에 할당된 최대 가스 양입니다.
destination_type 문자열 수신자 주소의 분류입니다. 지원되는 값: "EOA" (일반 사용자 지갑), "CONTRACT" (스마트 계약), "INTERNAL_TREASURY" (내부 저장소)
temporal_validity 길이 거래 계정 nonce (거래 재생 공격을 방지하는 데 사용됨)

비트코인 트랜잭션 스키마 참조

규칙을 비트코인 BIP 174 PSBT 트랜잭션 페이로드로 명시적으로 제한하려면 context.transaction.schema == "bitcoin.transaction.v2"를 확인하세요.

context.transaction 레코드 내에서 지원되는 속성은 다음과 같습니다.

속성 유형 설명
schema 문자열 형식 스키마입니다. 비트코인 거래의 경우 항상 "bitcoin.transaction.v2"입니다.
operation 문자열 트랜잭션 작업 유형입니다. 지원되는 값:
  • "NATIVE_TRANSFER": 비트코인 (BTC)의 직접 전송입니다.
  • "OP_RETURN": 사용할 수 없는 데이터 앵커링 / null 데이터 출력입니다.
chain_id 문자열 대상 네트워크 Bech32 인간이 읽을 수 있는 부분 (HRP): "bc" (비트코인 메인넷), "tb" (테스트넷 / 테스트넷4) 또는 "bcrt" (Regtest)
asset_symbol 문자열 애셋 티커 기호: "BTC"
recipient 문자열 기본 도착지 주소입니다. OP_RETURN 거래의 경우 "unaddressable"입니다. 내부 통합 스윕 (100% 변경)의 경우 첫 번째 변경 주소로 확인됩니다.
spend_amount_scaled 길이 고정 9자리 소수점 정밀도 (10-9 단위)로 정규화된 순 아웃바운드 전송 금액입니다. 1사토시는 10나노코인 단위 (1sat = 10단위, 1BTC = 109단위)이므로 내부 변경 금액은 제외됩니다. 내부 스윕 / 100% 변경 트랜잭션의 경우 0로 평가됩니다.
max_fee_atomic 길이 소수점 이하 9자리 정밀도로 정규화된 계산된 채굴자 수수료 한도: (∑ 입력 − ∑ 출력) × 10.
destination_type 문자열 수신자 스크립트의 분류입니다. 지원되는 값: "P2WPKH" (Native SegWit), "P2TR" (Taproot), "P2PKH" (Legacy), "P2SH" (Nested SegWit / Script Hash), "TREASURY_CHANGE" (내부 변경 스윕) 또는 ""
temporal_validity 길이 트랜잭션 nLockTime 필드
outputs Set<Record> 모든 트랜잭션 출력의 정규화된 집합: [{ address: String, amount_scaled: Long, is_change: Bool }]

핵심 비트코인 정책 개념

  1. 범용 9자리 소수점 스케일링 수학: 비트코인 정책의 금액은 정규화된 9자리 소수점 나노코인 정밀도 (1 sat = 10단위, 1 BTC = 109단위)를 사용합니다.

    Amountscaled = Satoshis × 10 = BTC × 109

    • 0.0005 BTC (50,000사토시) → 500000 (50,000 × 10)
    • 0.0025 BTC (250,000사토시) → 2500000 (250,000 × 10)
    • 1.0 BTC (100,000,000사토시) → 1000000000 (100,000,000 × 10)
  2. 변경 출력 분리: 파서는 BIP-32 파생 경로 (m/.../1/*)를 검사하고 입력 스크립트를 상호 연결하여 내부 변경 출력을 자동으로 식별합니다. 잔액은 spend_amount_scaled에서 제외되므로 지출 한도 정책은 서드 파티로 전송된 순 송금액을 기준으로 엄격하게 평가됩니다.

  3. 단일 비변경 수신자 규칙: 모호한 다중 수신자 라우팅 공격을 방지하기 위해 여러 개의 고유한 외부 서드 파티 수신자가 포함된 트랜잭션은 실패로 종료됩니다 (ErrUnsupportedTx).


Cedar 규칙 예시

다음 예시에서는 이더리움 및 비트코인 트랜잭션에 Cedar를 사용하여 허용 목록, 한도 규칙, 재생 경계를 구성하는 방법을 보여줍니다.

Ethereum 예시

다음 규칙은 이더리움 및 ERC-20 트랜잭션의 일반적인 정책 패턴을 보여줍니다.

1. 직접 ETH 전송 한도

이 규칙은 Alice가 기본 체인 ETH를 전송할 수 있도록 허용하며, 조정된 전송 금액이 1.0 ETH (조정된 Gwei 단위 1,000,000,000개)를 초과하지 않는지 확인합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "NATIVE_TRANSFER" &&
    context.transaction.asset_symbol == "ETH" &&
    context.transaction.spend_amount_scaled <= 1000000000
};

2. ERC-20 토큰 허용 목록 규칙

이 규칙은 최대 5,000 USDC의 USDC 토큰 전송을 허용합니다. 허용 목록에 있는 수신자 주소로의 전송을 제한합니다. Cedar 문자열은 대소문자를 구분하므로 수신자 주소는 대소문자가 혼합된 EIP-55 형식과 일치해야 합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "TOKEN_TRANSFER" &&
    context.transaction.asset_symbol == "USDC" &&
    context.transaction.recipient == "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B" &&
    context.transaction.spend_amount_scaled <= 5000000000000
};

3. 스마트 계약 및 DeFi 호출 대체

이 규칙은 자산 지출 전송 작업이 아닌 경우 금액 제한 없이 일반적인 계약 상호작용 (예: 스테이킹 또는 스왑)을 허용합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "CONTRACT_CALL"
};

4. 엄격한 재생 보호 (체인 ID 경계)

테스트넷 체인에 서명된 페이로드가 프로덕션 메인넷에 다시 제출되는 트랜잭션 재생 공격을 방지하려면 규칙의 범위를 특정 체인 ID (예: Sepolia의 경우 11155111)로 지정하면 됩니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.chain_id == "11155111"
};

비트코인 예시

다음 규칙은 비트코인 PSBT 트랜잭션의 일반적인 정책 패턴을 보여줍니다.

1. 지출 한도 및 채굴자 수수료 한도

이 규칙은 순 송금액이 0.0025BTC (250,000사토시 → 2,500,000배율 단위)를 초과하지 않고 채굴자 수수료가 10,000사토시 (100,000원자 단위)를 초과하지 않는 직접 비트코인 (BTC) 송금을 허용합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "NATIVE_TRANSFER" &&
    context.transaction.asset_symbol == "BTC" &&
    context.transaction.spend_amount_scaled <= 2500000 &&
    context.transaction.max_fee_atomic <= 100000
};

2. SegWit (P2WPKH) 및 Taproot (P2TR) 주소 허용 목록

이 규칙은 비트코인 전송을 승인된 SegWit 또는 Taproot 대상 주소로 제한합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.schema == "bitcoin.transaction.v2" &&
    (context.transaction.destination_type == "P2WPKH" || context.transaction.destination_type == "P2TR") &&
    context.transaction.recipient == "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
};

3. UTXO 통합 및 재무 스윕

이 규칙은 모든 출력이 내부 잔액 주소 (destination_type == "TREASURY_CHANGE" 및 spend_amount_scaled == 0)로 반환되는 내부 UTXO 통합 스윕을 허용하면서 통합 수수료를 제한합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.schema == "bitcoin.transaction.v2" &&
    context.transaction.destination_type == "TREASURY_CHANGE" &&
    context.transaction.spend_amount_scaled == 0 &&
    context.transaction.max_fee_atomic <= 50000
};

4. 출력 세트 검사

이 규칙은 트랜잭션 출력 세트에 특정 대상 출력과 금액이 포함되어 있는지 확인합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.outputs.contains({
        address: "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
        amount_scaled: 500000,
        is_change: false
    })
};

5. 네트워크 범위 지정 (메인넷과 테스트넷)

이 규칙은 승인 범위를 비트코인 테스트넷 (tb) 트랜잭션으로 제한하여 비트코인 메인넷 (bc)에서 실행되지 않도록 합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.schema == "bitcoin.transaction.v2" &&
    context.transaction.chain_id == "tb"
};

6. OP_RETURN 데이터 앵커링

이 규칙은 사용할 수 없는 OP_RETURN 데이터 앵커링 트랜잭션 (spend_amount_scaled == 0 및 recipient == "unaddressable")을 허용하여 엄격한 수수료 한도를 적용합니다.

permit (
    principal == User::"alice",
    action == Action::"sign_transaction",
    resource == Resource::"mpc_operation"
)
when {
    context.transaction.operation == "OP_RETURN" &&
    context.transaction.recipient == "unaddressable" &&
    context.transaction.spend_amount_scaled == 0 &&
    context.transaction.max_fee_atomic <= 10000
};

파서 안전 방어

프로덕션 환경에서 트랜잭션 작업을 보호하기 위해 정책 엔진은 페이로드를 엄격하게 파싱하고 Cedar 규칙을 평가하기 전에 게이트웨이 레이어에서 잘못된 구조를 거부합니다.

  • 0값 기본 통화 적용: 파서는 0이 아닌 기본 전송 애셋을 번들로 묶으려는 이더리움 토큰 전송 작업 (TOKEN_TRANSFER)을 명시적으로 거부합니다. 이렇게 하면 악성 페이로드가 거래를 표준 토큰 전송으로 표시하면서 표준 기본 자산 가치를 전송하는 것을 방지할 수 있습니다.
  • UTXO 및 위트니스 검증: 비트코인 PSBT 트랜잭션의 경우 파서는 모든 입력이 유효한 witness_utxo 데이터를 제공하는지 검증하여 수수료 계산 스푸핑이나 확인되지 않은 서명을 방지합니다.
  • 변경 출력 스크립트 확인: 내부 변경 출력은 입력 스크립트 pubkey 또는 알려진 BIP-32 변경 경로 (m/.../1/*)와 일치해야 합니다. 변경 출력을 서드 파티 주소로 스푸핑하려는 페이로드는 실패합니다.
  • 단일 외부 수신자 시행: 여러 외부 비변경 대상 주소가 포함된 비트코인 페이로드는 모호한 다중 수신자 정책 승인을 방지하기 위해 실패 시 종료 (ErrUnsupportedTx)됩니다.
  • 정수 오버플로 및 언더플로 보호: 안전 경계 (MaxInt64)를 초과하거나 언더플로를 생성하는 (예: 총 출력 값이 총 입력 값을 초과하는 경우) nonce, locktime, 가스 또는 수수료 한도, 금액은 즉시 거부됩니다.
  • 수수료 확인 누락: 적절한 채굴자 수수료 또는 가스 매개변수를 정의하지 못한 거래는 자동으로 종료됩니다.