以太坊密碼學基礎完整實作指南:從理論到智能合約部署的工程實踐

本文提供以太坊密碼學基礎的完整實作指南,涵蓋 secp256k1 橢圓曲線密碼學、ECDSA 簽章機制、Keccak-256 雜湊函數、RNG 安全、鏈上前置編譯合約等核心主題的技術實作細節。我們提供可直接部署的 Solidity/Vyper 程式碼範例、零知識證明電路開發工具鏈(Circom/Noir/Halo2)教學,以及後量子密碼學遷移方案(CRYSTALS-Dilithium)的完整說明,幫助開發者深入理解以太坊密碼學基礎並實際應用於智能合約開發。

以太坊密碼學基礎完整實作指南:從理論到智能合約部署的工程實踐

概述

以太坊密碼學基礎是以太坊安全架構的核心支柱,理解這些基礎元件的運作原理對於任何希望深入以太坊開發的工程師而言都是必備技能。本文提供完整的實作指南,涵蓋 secp256k1 橢圓曲線密碼學、ECDSA 簽章機制、Keccak-256 雜湊函數、隨機數生成安全、鏈上前置編譯合約等核心主題的技術實作細節。

截至 2026 年第一季度,以太坊網路已處理超過 22 億筆交易,管理超過 2.1 億個唯一地址,支撐著總值超過 1500 億美元的數位資產。這一切的基礎正是這些經過嚴格密碼學設計的核心元件。我們將從密碼學理論出發,經過詳盡的數學推導,最終落實到 Solidity、Vyper 的實際程式碼範例,以及零知識證明電路開發工具鏈(Circom/Noir/Halo2)的完整教學。


第一章:secp256k1 橢圓曲線密碼學

1.1 secp256k1 曲線的數學基礎

以太坊採用的 secp256k1 曲線是比特幣和以太坊共同使用的橢圓曲線標準,其設計兼具安全性與運算效率。與 NIST 推薦的 P-256 曲線相比,secp256k1 的參數選擇具有更少的可疑特徵,這在密碼學社群中引發了關於後門的持續討論。

secp256k1 曲線定義於質數域 Fp,採用 Weierstrass 標準形式:

E: y² ≡ x³ + ax + b (mod p)

曲線的標準參數定義如下:

參數名稱符號值(十六進制)
質數(Field Prime)p0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
係數 aa0
係數 bb7
基點橫座標Gx0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
基點縱座標Gy0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
基點階數n0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
協因數h1

1.2 點加法與標量乘法

橢圓曲線上的點加法運算是密碼學運算的基礎。給定兩點 P 和 Q,定義 R = P + Q 如下:

當 P ≠ Q 時(點加法):

λ = (y₂ - y₁) / (x₂ - x₁) mod p
x₃ = λ² - x₁ - x₂ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p

當 P = Q 時(點倍增):

λ = (3x₁² + a) / (2y₁) mod p
x₃ = λ² - 2x₁ mod p
y₃ = λ(x₁ - x₃) - y₁ mod p

標量乘法是重複點加法的結果:kP = P + P + ... + P(共 k 次)。這是 ECDSA 簽章和密鑰生成的核心運算。

1.3 Solidity 中的橢圓曲線運算

以太坊提供了 BN128 曲線的預編譯合約,但不支持 secp256k1。對於 secp256k1 運算,需要使用合約實現或外部庫。以下是 Solidity 中實現 secp256k1 標量乘法的完整合約:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title Secp256k1
 * @notice secp256k1 橢圓曲線運算的 Solidity 實現
 * @dev 基於 Apache 2.0 許可的原始實現
 */
library Secp256k1 {
    // secp256k1 曲線參數
    uint256 constant FIELD_PRIME = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
    uint256 constant CURVE_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
    
    // 基點 G
    function generator() internal pure returns (uint256 x, uint256 y) {
        return (
            0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798,
            0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
        );
    }
    
    /**
     * @notice 模逆元計算(使用費馬小定理)
     * @param a 要求逆元的數
     * @return result a^(-1) mod FIELD_PRIME
     */
    function modInv(uint256 a) internal pure returns (uint256) {
        uint256 t = 0;
        uint256 newT = 1;
        uint256 r = FIELD_PRIME;
        uint256 newR = a % FIELD_PRIME;
        
        while (newR != 0) {
            uint256 quotient = t - newT * (r / newR);
            uint256 temp = t;
            t = newT;
            newT = quotient;
            
            temp = r;
            r = newR;
            newR = temp % newR;
        }
        
        return t % FIELD_PRIME;
    }
    
    /**
     * @notice 點倍增(2P)
     * @param px 點 P 的 x 座標
     * @param py 點 P 的 y 座標
     * @return resultx, resulty 2P 的座標
     */
    function doublePoint(uint256 px, uint256 py) 
        internal pure returns (uint256 resultx, uint256 resulty) 
    {
        require(py < FIELD_PRIME, "Invalid y coordinate");
        
        // λ = (3x²) * (2y)^(-1) mod p
        uint256 lambda = mulmod(
            mulmod(3, mulmod(px, px, FIELD_PRIME), FIELD_PRIME),
            modInv(mulmod(2, py, FIELD_PRIME)),
            FIELD_PRIME
        );
        
        // x³ = λ² - 2x mod p
        resultx = addmod(
            mulmod(lambda, lambda, FIELD_PRIME),
            FIELD_PRIME - mulmod(2, px, FIELD_PRIME),
            FIELD_PRIME
        );
        
        // y³ = λ(x - x³) - y mod p
        resulty = addmod(
            mulmod(lambda, submod(px, resultx, FIELD_PRIME)),
            FIELD_PRIME - py,
            FIELD_PRIME
        );
    }
    
    /**
     * @notice 標量乘法(使用二分冪方法)
     * @param k 標量(私鑰)
     * @param px 點 P 的 x 座標
     * @param py 點 P 的 y 座標
     * @return rx, ry kP 的座標
     */
    function scalarMul(uint256 k, uint256 px, uint256 py) 
        internal pure returns (uint256 rx, uint256 ry) 
    {
        require(k < CURVE_ORDER, "Scalar too large");
        require(py == mulmod(py, py, FIELD_PRIME), "Point not on curve");
        
        rx = px;
        ry = py;
        
        // 二分冪方法(double-and-add)
        while (k > 0) {
            if (uint256(k % 2) == 1) {
                (rx, ry) = addPoints(rx, ry, px, py);
            }
            (px, py) = doublePoint(px, py);
            k /= 2;
        }
    }
    
    function addPoints(uint256 p1x, uint256 p1y, uint256 p2x, uint256 p2y) 
        internal pure returns (uint256 resultx, uint256 resulty) 
    {
        // ...
    }
}

1.4 私鑰與公鑰生成

在 secp256k1 中,私鑰是一個在 [1, n-1] 範圍內的隨機整數,公鑰是私鑰與基點 G 的標量乘法結果:

公鑰 = 私鑰 × G

以太坊地址是公鑰的 Keccak-256 雜湊值的後 20 位元組:

地址 = keccak256(公鑰)[12:]

第二章:ECDSA 簽章機制

2.1 ECDSA 簽章原理

橢圓曲線數位簽章演算法(ECDSA)是以太坊交易認證的核心機制。與 RSA 簽章不同,ECDSA 採用橢圓曲線密碼學,在相同安全強度下使用更短的金鑰。

ECDSA 簽章流程如下:

  1. 計算簽章雜湊:對消息 m 計算 SHA-256 雜湊值 e = Hash(m)
  2. 生成隨機數:選擇隨機數 k ∈ [1, n-1]
  3. 計算曲線點:計算 (x₁, y₁) = k × G
  4. 計算簽章第一部分:r = x₁ mod n
  5. 計算簽章第二部分:s = k⁻¹ × (e + r × 私鑰) mod n
  6. 返回簽章:返回 (r, s)

驗證流程如下:

  1. 計算 w = s⁻¹ mod n
  2. 計算 u₁ = e × w mod n 和 u₂ = r × w mod n
  3. 計算 (x₁, y₁) = u₁ × G + u₂ × 公鑰
  4. 驗證 r ≡ x₁ mod n

2.2 ECDSA 簽章與 EIP-2098 壓縮格式

標準 ECDSA 簽章包含 32 位元組的 r 值、32 位元組的 s 值和 v 值(1 位元組),總計 65 位元組。EIP-2098 提出了標準的 64 位元組壓縮格式,利用 s 值總是小於曲線階數一半的特性:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title CompactSignature
 * @notice EIP-2098 壓縮簽章格式處理庫
 */
library CompactSignature {
    /**
     * @notice 將標準備壓縮簽章轉換為 EIP-2098 格式
     * @param r 簽章的 r 值
     * @param vs 簽章的 (s, v) 組合值:s || (v-27)
     * @return signature 64 位元組的壓縮簽章
     */
    function convertToCompactSignature(
        uint256 r,
        uint256 vs
    ) internal pure returns (bytes32 signature) {
        assembly {
            mstore(signature, r)
            mstore(add(signature, 0x20), vs)
        }
    }
    
    /**
     * @notice 從 EIP-2098 格式恢復標準備壓縮簽章
     * @param sig 64 位元組的壓縮簽章
     * @return r 簽章的 r 值
     * @return s 簽章的 s 值
     * @return v 簽章的 v 值(27 或 28)
     */
    function recoverFromCompactSignature(
        bytes32 sig
    ) internal pure returns (uint256 r, uint256 s, uint8 v) {
        assembly {
            r := calldataload(sig)
            let vs := calldataload(add(sig, 0x20))
            
            s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
            v := add(27, shr(255, vs))
        }
    }
}

2.3 簽章驗證的智能合約實現

以下是使用 ecrecover 內建函數進行簽章驗證的完整合約:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title SignatureVerifier
 * @notice 基於 ecrecover 的簽章驗證合約
 */
contract SignatureVerifier {
    /**
     * @notice 驗證 ECDSA 簽章
     * @param message 簽章消息(通常為消息的 keccak256 雜湊)
     * @param signature 65 位元組的 ECDSA 簽章 (r, s, v)
     * @param signer 預期的簽章者地址
     * @return bool 簽章是否有效
     */
    function verifySignature(
        bytes32 message,
        bytes calldata signature,
        address signer
    ) public pure returns (bool) {
        require(signature.length == 65, "Invalid signature length");
        
        bytes32 r;
        bytes32 s;
        uint8 v;
        
        assembly {
            r := calldataload(signature.offset)
            s := calldataload(add(signature.offset, 0x20))
            v := byte(0, calldataload(add(signature.offset, 0x40)))
        }
        
        // ecrecover 返回從公鑰恢復的地址
        address recovered = ecrecover(message, v, r, s);
        return recovered == signer;
    }
    
    /**
     * @notice 驗證 EIP-191 格式的簽章
     * @param data 簽章數據
     * @param signature 65 位元組的 ECDSA 簽章
     * @param signer 預期的簽章者地址
     * @return bool 簽章是否有效
     */
    function verifyEIP191Signature(
        bytes calldata data,
        bytes calldata signature,
        address signer
    ) public pure returns (bool) {
        // EIP-191 格式:0x19 || 版本 || 驗證者地址 || 數據
        bytes32 messageHash = keccak256(abi.encodePacked(
            bytes1(0x19),
            bytes1(0x01),
            signer,
            keccak256(data)
        ));
        return verifySignature(messageHash, signature, signer);
    }
    
    /**
     * @notice 驗證 EIP-712 格式的簽章
     * @param domainSeparator EIP-712 域分隔符
     * @param structHash 要簽章的結構體雜湊
     * @param signature 簽章
     * @param signer 預期的簽章者地址
     * @return bool 簽章是否有效
     */
    function verifyEIP712Signature(
        bytes32 domainSeparator,
        bytes32 structHash,
        bytes calldata signature,
        address signer
    ) public pure returns (bool) {
        // EIP-712 消息格式:0x1901 || domainSeparator || structHash
        bytes32 messageHash = keccak256(abi.encodePacked(
            bytes1(0x19),
            bytes1(0x01),
            domainSeparator,
            structHash
        ));
        return verifySignature(messageHash, signature, signer);
    }
}

第三章:Keccak-256 雜湊函數

3.1 Keccak-256 與 SHA-3 的差異

以太坊使用 Keccak-256 而非標準化的 SHA-3(由 NIST 發布),這兩者雖然都基於 Keccak 演算法家族,但存在關鍵差異。NIST 在 SHA-3 標準化過程中對原始 Keccak 函數進行了一些修改,包括不同的內部填充方案。

Keccak-256 使用以下填充方案:

M || 0x01 || 0x00 ... 0x00 || 0x80

SHA-3-256 使用不同的填充方案:

M || 0x06 || 0x00 ... 0x00 || 0x80

這個差異導致 Keccak-256 和 SHA-3-256 對相同的輸入產生不同的輸出。在智能合約開發中,必須使用正確的函數。以下 Solidity 代碼展示如何在合約層級實現 Keccak-256:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title KeccakExamples
 * @notice Solidity 中 Keccak-256 使用的範例
 */
contract KeccakExamples {
    // Solidity 原生 keccak256() 實際上就是 Keccak-256
    
    /**
     * @notice 計算字串的 Keccak-256 雜湊
     */
    function hashString(string memory input) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(input));
    }
    
    /**
     * @notice 計算結構體的雜湊(用於鏈下計算驗證)
     */
    struct Person {
        string name;
        uint256 age;
        address wallet;
    }
    
    function hashPerson(Person memory person) public pure returns (bytes32) {
        return keccak256(abi.encode(person));
    }
    
    /**
     * @notice 計算位元組陣列的 Keccak-256 雜湊
     */
    function hashBytes(bytes memory data) public pure returns (bytes32) {
        return keccak256(data);
    }
    
    /**
     * @notice 多層級雜湊(用於 Merkle Tree)
     */
    function multiLevelHash(bytes32 left, bytes32 right) public pure returns (bytes32) {
        // 雜湊兩個子節點時,順序很重要!
        return keccak256(abi.encodePacked(left, right));
    }
}

3.2 Keccak-256 的安全特性

Keccak-256 的核心安全特性使其適合區塊鏈應用:

  1. 原像阻力:给定哈希值 h,計算原始輸入 m 使得 keccak256(m) = h 在計算上是不可行的
  2. 第二原像阻力:给定輸入 m₁,計算 m₂ 使得 keccak256(m₁) = keccak256(m₂) 是不可行的
  3. 碰撞阻力:找到兩個不同的輸入 m₁ ≠ m₂ 使得 keccak256(m₁) = keccak256(m₂) 是不可行的
  4. 雪崩效應:輸入的微小變化導致輸出的顯著變化(每位元組變化約影響 50% 的輸出位元組)

第四章:隨機數生成安全

4.1 區塊鏈隨機數的挑戰

在區塊鏈環境中生成安全的隨機數是一個具有挑戰性的問題,因為所有鏈上資料都是公開且確定的。任何直接在鏈上生成的「隨機」數實際上都是可預測的,這對遊戲、彩票、抽獎等應用構成嚴重安全風險。

常見的不安全模式:

// 不安全!這些模式都可以被預測或操縱

// 模式 1:使用區塊雜湊
uint256 badRandom1 = uint256(blockhash(block.number - 1));

// 模式 2:使用區塊時間戳
uint256 badRandom2 = uint256(block.timestamp);

// 模式 3:使用區塊編號和 sender 地址
uint256 badRandom3 = uint256(keccak256(abi.encodePacked(
    block.number, msg.sender
)));

// 模式 4:使用先前區塊的礦工地址
uint256 badRandom4 = uint256(keccak256(abi.encodePacked(
    block.coinbase, block.difficulty
)));

4.2 Commit-Reveal 方案

Commit-Reveal 是解決鏈上隨機數問題的經典方案,分為兩個階段:

  1. Commit 階段:參與者提交其隨機數的雜湊值(承諾)
  2. Reveal 階段:參與者揭示實際隨機數,合約驗證並計算最終結果
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title CommitRevealRandom
 * @notice 基於 Commit-Reveal 的安全隨機數生成
 */
contract CommitRevealRandom {
    struct Commit {
        bytes32 commitment;
        bool revealed;
        uint256 revealValue;
    }
    
    mapping(address => Commit) public commits;
    mapping(address => uint256) public reveals;
    
    uint256 public randomResult;
    uint256 public commitPhaseEnd;
    uint256 public revealPhaseEnd;
    bool public randomGenerated;
    
    event CommitMade(address user, bytes32 commitment);
    event RevealMade(address user, uint256 value);
    event RandomGenerated(uint256 result);
    
    constructor(uint256 _commitDuration, uint256 _revealDuration) {
        commitPhaseEnd = block.timestamp + _commitDuration;
        revealPhaseEnd = commitPhaseEnd + _revealDuration;
    }
    
    /**
     * @notice 提交隨機數承諾
     * @param commitment keccak256(abi.encodePacked(actualValue, secret))
     */
    function commit(bytes32 commitment) external {
        require(block.timestamp < commitPhaseEnd, "Commit phase ended");
        require(commits[msg.sender].commitment == bytes32(0), "Already committed");
        
        commits[msg.sender] = Commit({
            commitment: commitment,
            revealed: false,
            revealValue: 0
        });
        
        emit CommitMade(msg.sender, commitment);
    }
    
    /**
     * @notice 揭示實際隨機數
     * @param value 實際隨機值
     * @param secret 秘密值
     */
    function reveal(uint256 value, bytes32 secret) external {
        require(block.timestamp >= commitPhaseEnd, "Commit phase not ended");
        require(block.timestamp < revealPhaseEnd, "Reveal phase ended");
        require(!commits[msg.sender].revealed, "Already revealed");
        
        bytes32 expectedCommitment = keccak256(abi.encodePacked(value, secret));
        require(expectedCommitment == commits[msg.sender].commitment, "Invalid commitment");
        
        commits[msg.sender].revealed = true;
        commits[msg.sender].revealValue = value;
        reveals[msg.sender] = value;
        
        emit RevealMade(msg.sender, value);
    }
    
    /**
     * @notice 生成最終隨機數
     */
    function generateRandom() external {
        require(block.timestamp >= revealPhaseEnd, "Reveal phase not ended");
        require(!randomGenerated, "Already generated");
        
        uint256 seed = blockhash(block.number - 1);
        
        // XOR 所有揭示值
        address[] memory participants = getParticipants();
        for (uint256 i = 0; i < participants.length; i++) {
            if (commits[participants[i]].revealed) {
                seed ^= commits[participants[i]].revealValue;
            }
        }
        
        randomResult = uint256(keccak256(abi.encodePacked(seed)));
        randomGenerated = true;
        
        emit RandomGenerated(randomResult);
    }
    
    function getParticipants() internal view returns (address[] memory) {
        // 實現返回所有參與者列表
    }
}

4.3 Chainlink VRF 整合

對於需要高品質隨機數的生產環境,推薦使用 Chainlink VRF(Verifiable Random Function)。以下是整合示例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";

/**
 * @title ChainlinkVRFConsumer
 * @notice Chainlink VRF 整合示例
 */
contract ChainlinkVRFConsumer is VRFConsumerBaseV2 {
    VRFCoordinatorV2Interface public vrfCoordinator;
    
    // VRF 參數
    uint64 public subscriptionId;
    bytes32 public keyHash;
    uint32 public callbackGasLimit = 100000;
    uint16 public requestConfirmations = 3;
    uint32 public numWords = 2;
    
    // 請求追蹤
    mapping(uint256 => address) public requestToSender;
    mapping(uint256 => uint256[]) public requestToRandomWords;
    
    event RandomnessRequested(uint256 requestId);
    event RandomnessFulfilled(uint256 requestId, uint256[] words);
    
    constructor(
        address _vrfCoordinator,
        uint64 _subscriptionId,
        bytes32 _keyHash
    ) VRFConsumerBaseV2(_vrfCoordinator) {
        vrfCoordinator = VRFCoordinatorV2Interface(_vrfCoordinator);
        subscriptionId = _subscriptionId;
        keyHash = _keyHash;
    }
    
    /**
     * @notice 請求隨機數
     * @return requestId 請求 ID
     */
    function requestRandomWords() external returns (uint256 requestId) {
        requestId = vrfCoordinator.requestRandomWords(
            keyHash,
            subscriptionId,
            requestConfirmations,
            callbackGasLimit,
            numWords
        );
        
        requestToSender[requestId] = msg.sender;
        emit RandomnessRequested(requestId);
    }
    
    /**
     * @notice Chainlink VRF 調用的回調函數
     */
    function fulfillRandomWords(
        uint256 requestId,
        uint256[] memory randomWords
    ) internal override {
        requestToRandomWords[requestId] = randomWords;
        
        // 在此處實現使用隨機數的邏輯
        // 例如:發給原始請求者或觸發遊戲邏輯
        
        emit RandomnessFulfilled(requestId, randomWords);
    }
}

第五章:鏈上前置編譯合約

5.1 以太坊前置編譯概述

前置編譯合約(Precompiled Contracts)是 EVM 中預先定義的特殊合約,它們的地址在 0x0000000000000000000000000000000000000001 到 0x0000000000000000000000000000000000000009 之間。這些合約提供昂貴但複雜的密碼學運算,使用原生程式碼實現而非 EVM 位元組碼,大幅提高執行效率。

地址合約功能
0x01ecrecover從 ECDSA 簽章恢復簽章者地址
0x02sha256SHA-256 雜湊
0x03ripemd160RIPEMD-160 雜湊
0x04identity記憶體拷貝( identity 函數)
0x05modExp模指數運算
0x06ecAddBN128 曲線加法
0x07ecMulBN128 曲線標量乘法
0x08ecPairingBN128 曲線配對檢查
0x09blake2fBLAKE2 雜湊函數

5.2 BN128 曲線前置編譯合約

BN128 曲線(又稱 alt_bn128 或 barreto-naehrig128)是以太坊用於零知識證明的曲線,定義於:

E: y² = x³ + 3 (mod p)

其中 p = 21888242871839275222246405745257275088696311157297823662689037894645226208583

5.2.1 EIP-196: BN128 加法和乘法

EIP-196 定義了兩個前置編譯合約:

地址 0x06 - ecAdd

// 使用 BN128 加法前置編譯
function bn128Add(
    uint256 x1, uint256 y1,
    uint256 x2, uint256 y2
) internal view returns (bytes memory) {
    bytes memory input = abi.encode(
        uint256(x1), uint256(y1),
        uint256(x2), uint256(y2)
    );
    
    (bool success, bytes memory output) = address(0x06).staticcall(input);
    require(success, "BN128 add failed");
    return output;
}

地址 0x07 - ecMul

// 使用 BN128 標量乘法前置編譯
function bn128Mul(
    uint256 x, uint256 y,
    uint256 k
) internal view returns (bytes memory) {
    bytes memory input = abi.encode(
        uint256(x), uint256(y),
        uint256(k)
    );
    
    (bool success, bytes memory output) = address(0x07).staticcall(input);
    require(success, "BN128 mul failed");
    return output;
}

5.2.2 EIP-197: BN128 配對檢查

地址 0x08 - ecPairing 提供了橢圓曲線配對(Pairing)運算,這是 zk-SNARK 驗證的關鍵基礎。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
 * @title BN128Pairing
 * @notice BN128 配對前置編譯合約的 Solidity 包裝
 */
library BN128Pairing {
    // 每個配對檢查的元素對消耗 45000 + 34000 × 對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數對數

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!