比特币的蒙提霍尔问题

2023-09-20 13:46:57

把钱放在嘴边

我们在比特币上建立了蒙提霍尔问题模拟。 如果您知道概率谜题的正确答案,不仅炫耀您的数学技能,还会获得金钱奖励。 它完全无需信任地在链上运行。

蒙提霍尔问题

蒙提霍尔问题(三门问题)是一个以蒙提霍尔命名的概率谜题,蒙提霍尔是电视节目《让我们做个交易》的原主持人。 这是一个著名的反直觉统计难题,其解决方案非常荒谬,即使被证明是真的,大多数人也拒绝相信。 它的工作原理如下:

假设你在参加一个游戏节目,你可以选择三扇门:一扇门后面是一辆汽车; 在其他人之后,山羊。 你选择一扇门,比如 1 号,知道门后面是什么的主持人打开另一扇门,比如 3 号,里面有一只山羊。 然后他对你说,“你想选择 2 号门吗?” 改变你的选择对你有利吗?

令人惊讶的是,赔率不是 50–50。 如果你换门,你会赢概率是 2/3 ! 有许多解释数学的文章/视频,我们不在这里深入探讨。 下面列出了一些很好的例子。

展示位置的可能性

Stay vs. Switch 的可能场景

密码学的门

为了在比特币中模拟 Monty Hall,我们需要一种方法来隐藏汽车/山羊,这样:

  1. 玩家看不到每扇门后面的东西;
  2. 比赛开始后,主持人不能移动汽车/山羊。

承诺方案是实现这两者的标准方法。 我们使用单个位 1 表示汽车,位 0 表示山羊。 像往常一样,我们还在位前添加一个随机数,以防止暴力攻击。

实现

我们使用 scryptTS(一种 TypeScript DSL)在比特币智能合约中实施了蒙提霍尔问题。 在游戏开始之前,玩家和主机都将等量的比特币锁定到以下合约中。 部署合约后,游戏将按以下步骤进行:

  1. 玩家选择一扇门,比如 0 号门,当然希望有车
  2. 主持人打开一扇门,另外两扇门里有一只山羊
  3. 玩家决定是坚持使用 0 号门(最初的猜测)还是切换到剩余的未打开的门
  4. 主持人揭晓结果:如果玩家选中有车的门,他拿走合约中的所有比特币; 否则主持人拿走。
// this contract simulates the Monty Hall problem
class MontyHall extends SmartContract {
    @prop()
    player: PubKey

    @prop()
    host: PubKey

    @prop(true)
    step: bigint

    // player's choice
    @prop(true)
    choice: bigint

    // door opened by host
    @prop(true)
    openedDoor: bigint

    // number of doors
    static readonly N: number = 3

    // what's behind each door
    @prop()
    doorHashes: FixedArray<Sha256, 3>


    constructor(
        player: PubKey,
        host: PubKey,
        doorHashes: FixedArray<Sha256, 3>
    ) {
        super(...arguments)
        this.player = player
        this.host = host
        this.step = 0n
        this.choice = -1n
        this.openedDoor = -1n
        this.doorHashes = doorHashes
    }


    // step 1: the player chooses initially a random door that s/he believes has the prize
    @method()
    public choose(choice: bigint, sig: Sig) {
        assert(++this.step == 1n, 'step number unexpected')

        this.choice = choice

        // game goes on
        assert(this.ctx.hashOutputs == hash256(this.buildStateOutput(this.ctx.utxo.value)), 'hashOutputs check failed')
    }

    // step 2: host opens a goat door
    @method()
    public open(goatDoorNum: bigint, behindDoor: ByteString, sig: Sig) {
        assert(++this.step == 2n, 'step number unexpected')

        this.openedDoor = goatDoorNum
        const goatDoorHash = this.doorHashes[Number(goatDoorNum)]
        assert(sha256(behindDoor) == goatDoorHash)
        assert(!this.isCar(behindDoor), "expect goat, but got car")

        assert(this.ctx.hashOutputs == hash256(this.buildStateOutput(this.ctx.utxo.value)), 'hashOutputs check failed')
    }

    // step 3: player stays or switches
    @method()
    public stay(stay: boolean, sig: Sig) {
        assert(++this.step == 3n, 'step number unexpected')

        if (!stay) {
            // switch
            this.choice = this.findUnopenedDoor()
        }

        assert(this.ctx.hashOutputs == hash256(this.buildStateOutput(this.ctx.utxo.value)), 'hashOutputs check failed')
    }

    // step 4: reveal
    @method()
    public reveal(behindDoor: ByteString) {
        assert(++this.step == 4n, 'step number unexpected')

        const doorHash = this.doorHashes[Number(this.choice)]
        assert(sha256(behindDoor) == doorHash)

        // does the play choose a door, behind which is a car
        const won = this.isCar(behindDoor)
        const winner = won ? this.player : this.host

        // pay full amount to winner
        const winnerScript: ByteString = Utils.buildPublicKeyHashScript(winner)
        const payoutOutput: ByteString = Utils.buildOutput(winnerScript, this.ctx.utxo.value)
        assert(this.ctx.hashOutputs == hash256(payoutOutput))
    }

    // if last bit is set, it is a car; otherwise, a goat
    @method()
    isCar(behindDoor: ByteString): boolean {
        return unpack(behindDoor) % 2n == 1n
    }

    // find the remaining unopened door
    @method()
    findUnopenedDoor(): bigint {
        let result: bigint = -1n
        for (let i = 0n; i < MontyHall.N; i++) {
            if (i != this.choice && i != this.openedDoor)
                result = i
        }
        return result
    }
}
Montyhall 合约

在第 25 行,主持人提交汽车的位置。 他通过打开 SHA256 承诺“打开”了一扇门。 在每个公共方法的开始,我们确保按顺序执行正确的步骤。 第 51 行使用有状态合约技术。

如果游戏重复多次,一个玩家选择一直留下会赢大约 1/3 的时间,而如果他总是切换,他的获胜几率可以提高到 2/3

主持人作弊怎么办?

主持人作弊有两种可能的方式:

  1. 如果玩家在步骤 4 中正确选择了汽车,他拒绝开门;

  2. 他把三只山羊放在门后,但没有车。

为防止(1),我们可以使用定时承诺方案,如果主持人在截止日期前未打开承诺,则没收主持人的押金。

(2) 同样可以预防。 主持人最终必须打开所有三扇门,如果它们都是山羊,他将失去押金。 或者他可以使用零知识证明让玩家相信门后确实有一辆车,但没有透露它在哪扇门后面。


[1] 为了便于说明,我们忽略了交易费用,这可以很容易地在合同中说明,例如,通过使用 ANYONECANPAY

更多推荐

LuatOS-SOC接口文档(air780E)--eink - 墨水屏操作库

常量常量类型解释eink.MODEL_1in02dnumber1.02寸deink.MODEL_1in54number1.54寸eink.MODEL_1in54_V2number1.54寸_V2eink.MODEL_1in54bnumber1.54寸beink.MODEL_1in54b_V2number1.54寸b_V

Node.js 20 —— 几个令人大开眼界的特性

前言:欢迎来到Node.js20Node.js20已经发布,带来了创新和激动人心的新时代。这个开创性的版本于2023年4月18日首次亮相,并将在2023年10月发布长期支持(LTS)版本,并且将持续支持至2026年4月,下面小编就为大家介绍一下Node.js20的几个新特性:1.Node.js权限访问Node.js20

JS案例:在浏览器实现自定义菜单

目录前言设计思路BaseElemMenuCustomElementBaseDragDragResize最终效果总结相关代码前言分享一下之前公司实现自定义菜单的思路,禁用浏览器右键菜单,使用自定义的菜单将其代替,主要功能有:鼠标右键调出菜单,双击选中/取消选中标签,新建标签,删除标签,调整位置,调整大小,取消拖拽,关闭菜

详解JS中常见的5 种 for 循环

for循环在平时开发中使用频率最高的,前后端数据交互时,常见的数据类型就是数组和对象,处理对象和数组时经常使用到for遍历,因此需要彻底搞懂这5种for循环。它们分别为:forfor...infor...offorawait..offorEachmap一、各个for介绍1、forfor循环是出现最早,也是应用最普遍的一

联表查询 && 索引 && 事务 && JDBC使用 &&CPU工作原理 && 线程概念 && Thread类的用法

第1题(单选题)题目名称:已知表T1中有2行数据,T2中有3行数据,执行SQL语句,“selecta.*fromT1a,T2b”后,返回的行数为题目内容:A.2B.3C.5D.6第2题(单选题)题目名称:Mysql查询时,只有满足联接条件的记录才包含在查询结果,这种联接是题目内容:A.左联接B.右联接C.内联接D.全联

Vue.js和TypeScript:如何完美结合

🌷🍁博主猫头虎(🐅🐾)带您GotoNewWorld✨🍁🦄博客首页——🐅🐾猫头虎的博客🎐🐳《面试题大全专栏》🦕文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》🐾学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》🐅学会Gol

Redis SCAN命令操作实战(详细)

目录SCAN介绍SCAN命令基本用法MATCH选项用法COUNT选项用法TYPE选项用法补充并发执行多个迭代中途停止迭代使用错误的游标进行增量式迭代迭代终结的保证SCAN介绍SCANcursor[MATCHpattern][COUNTcount][TYPEtype]:SCAN命令及其相关的SSCAN命令、HSCAN命令

抽象轻松的C语言

四个基本元素标识符,数据,运算符,关键字标识符:是指计算机用来识别信息的符号数据:是事物或观察的结果运算符,关键字:具体内容具体分析由四个基本元素组合成6个基本语句标号语句,复合语句,表达式语句,选择语句,迭代语句,跳转语句PS:之前的那个标识语句呢?在最近的疯狂啃食之下,出现了点问题,于是我回过头重看不看不知道,一看

接口自动化中cookies的处理技术

一,理论知识为什么有cookie和session?因为http协议是一种无状态的协议,即每次服务端接受到客户端的请求时都时一个全新的请求,服务器并不知道客户端的请求记录,session和cookie主要目的就是弥补http的无状态特性cookiecookie是服务器发送到用户浏览器并保存到用户本地的一小块数据,会在浏览

C语言进阶第三课-----------指针的进阶----------后续版

作者前言🎂✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂​🎂作者介绍:🎂🎂🎂🎉🎉🎉🎉🎉🎉🎉🎂🎂作者id:老秦包你会,🎂简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨🎂🎂🎂🎂🎂

SpringCloud Ribbon--负载均衡 原理及应用实例

😀前言本篇博文是关于SpringCloudRibbon的基本介绍,希望你能够喜欢🏠个人主页:晨犀主页🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,感谢大家的观看🥰如果文章有什么需要改进的地方还请大佬不吝赐教先

热文推荐