Skip to content

Instantly share code, notes, and snippets.

@xrchz
Created February 23, 2023 17:03
Show Gist options
  • Save xrchz/3cb122902ed66f11a6f56b96f534c3bc to your computer and use it in GitHub Desktop.
Save xrchz/3cb122902ed66f11a6f56b96f534c3bc to your computer and use it in GitHub Desktop.
Vyper InvalidType error
# @version ^0.3.7
# mental poker deck protocol
#
# Implements the paper
# A Fast Mental Poker Protocol by Tzer-Jen Wei & Lih-Chung Wang
# https://ia.cr/2009/439
# using the alt-bn128's G1 (https://neuromancer.sk/std/bn/bn254) for G
#
# For discrete log equality non-interactive ZK proofs, we use the scheme
# described in Wallet Databases with Observers by David Chaum & Torben Pryds Pederson
# https://dx.doi.org/10.1007/3-540-48071-4_7
# section 3.2
GROUP_ORDER: constant(uint256) = 21888242871839275222246405745257275088696311157297823662689037894645226208583
# arbitrary limits on deck size and number of players sharing a deck
# note: MAX_SIZE must be < GROUP_ORDER
# TODO: we inline these because of https://github.com/vyperlang/vyper/issues/3294
MAX_SIZE: constant(uint256) = 9000
MAX_PLAYERS: constant(uint256) = 8000 # to distinguish from MAX_SIZE when inlining
MAX_SECURITY: constant(uint256) = 256
struct Proof:
# signature to confirm log_g(gx) = log_h(hx)
# s is a random secret scalar
gs: uint256[2] # g ** s
hs: uint256[2] # h ** s
scx: uint256 # s + cx (mod q), where c = hash(g, h, gx, hx, gs, hs)
struct CP:
# g and h are random points, x is a random secret scalar
g: uint256[2]
h: uint256[2]
gx: uint256[2] # g ** x
hx: uint256[2] # h ** x
p: Proof
struct DeckPrep:
cards: DynArray[CP, 9000]
struct DrawCard:
# successive decryptions
c: DynArray[uint256[2], 8000]
# 1 + index of player the card is initially drawn to (i.e. they skip decryption)
# note: a card can only be drawn to a single player
drawnTo: uint256
# 1 + original index after reveal
opensAs: uint256
struct Deck:
# authorised address for drawing cards and reshuffling
dealer: address
# authorised address for each player
addrs: DynArray[address, 8000]
# shuffle[0] is the unencrypted cards (including base card at index 0)
# shuffle[j+1] is the shuffled encrypted cards from player index j
shuffle: DynArray[DynArray[uint256[2], 9000], 8001] # 8000 + 1] <- another Vyper bug with importing
challengeReq: DynArray[uint256, 8000]
challengeRes: DynArray[DynArray[DynArray[uint256[2], 9000], 256], 8000]
challengeRnd: uint256
# for decrypting shuffled cards
# note: cards[i] corresponds to shuffle[_][i+1]
cards: DynArray[DrawCard, 9000]
# data for deck preparation
prep: DynArray[DeckPrep, 8000]
# @version ^0.3.7
# no-limit hold'em sit-n-go single-table tournaments
# copied from Deck.vy because https://github.com/vyperlang/vyper/issues/2670
MAX_SIZE: constant(uint256) = 9000
MAX_PLAYERS: constant(uint256) = 8000 # to distinguish from MAX_SIZE when inlining
MAX_SECURITY: constant(uint256) = 256
struct Proof:
# signature to confirm log_g(gx) = log_h(hx)
# s is a random secret scalar
gs: uint256[2] # g ** s
hs: uint256[2] # h ** s
scx: uint256 # s + cx (mod q), where c = hash(g, h, gx, hx, gs, hs)
struct CB:
# g and h are random points, x is a random secret scalar
g: uint256[2]
h: uint256[2]
gx: uint256[2] # g ** x
hx: uint256[2] # h ** x
p: Proof
struct DeckPrep:
cards: DynArray[CB, MAX_SIZE]
# end of copy
import Deck as DeckManager
# copied from Table.vy
MAX_SEATS: constant(uint256) = 9 # maximum seats per table
MAX_LEVELS: constant(uint256) = 100 # maximum number of levels in tournament structure
struct Config:
gameAddress: address # address of game manager
buyIn: uint256 # entry ticket price per player
bond: uint256 # liveness bond for each player
startsWith: uint256 # game can start when this many players are seated
untilLeft: uint256 # game ends when this many players are left
structure: uint256[MAX_LEVELS] # small blind levels (right-padded with blanks)
levelBlocks: uint256 # blocks between levels
verifRounds: uint256 # number of shuffle verifications required
prepBlocks: uint256 # blocks to submit deck preparation
shuffBlocks: uint256 # blocks to submit shuffle
verifBlocks: uint256 # blocks to submit shuffle verification
dealBlocks: uint256 # blocks to submit card decryptions
actBlocks: uint256 # blocks to act before folding can be triggered
Phase_JOIN: constant(uint256) = 0 # before the game has started, taking seats
Phase_PREP: constant(uint256) = 1 # all players seated, preparing the deck
Phase_SHUFFLE: constant(uint256) = 2 # submitting shuffles and verifications in order
Phase_DEAL: constant(uint256) = 3 # drawing and possibly opening cards as currently required
Phase_PLAY: constant(uint256) = 4 # betting; new card revelations may become required
Phase_SHOW: constant(uint256) = 5 # showdown TODO
# end copy
import Table as TableManager
T: immutable(TableManager)
@external
def __init__(tableAddress: address):
T = TableManager(tableAddress)
# TODO: add rake (rewards tabs for progress txns)?
# TODO: add penalties (instead of full abort on failure)?
struct Hand:
startBlock: uint256 # block number when game started
stack: uint256[MAX_SEATS] # stack at each seat (zero for eliminated or all-in players)
dealer: uint256 # seat index of current dealer
board: uint256[5] # board cards
bet: uint256[MAX_SEATS] # current round bet of each player
lastBet: uint256 # size of last bet or raise
live: bool[MAX_SEATS] # whether this player has a live hand
betIndex: uint256 # seat index of player who introduced the current bet
actionIndex: uint256 # seat index of currently active player
actionBlock: uint256 # block from which action was on the active player
pot: uint256 # pot for the hand (from previous rounds)
nextHandId: uint256
hands: HashMap[uint256, Hand]
PENDING_REVEAL: constant(uint256) = 53
# @version ^0.3.7
# copied from Deck.vy because https://github.com/vyperlang/vyper/issues/2670
MAX_SIZE: constant(uint256) = 9000
MAX_SECURITY: constant(uint256) = 256
struct Proof:
# signature to confirm log_g(gx) = log_h(hx)
# s is a random secret scalar
gs: uint256[2] # g ** s
hs: uint256[2] # h ** s
scx: uint256 # s + cx (mod q), where c = hash(g, h, gx, hx, gs, hs)
struct CP:
# g and h are random points, x is a random secret scalar
g: uint256[2]
h: uint256[2]
gx: uint256[2] # g ** x
hx: uint256[2] # h ** x
p: Proof
struct DeckPrep:
cards: DynArray[CP, 9000]
# end of copy
import Deck as DeckManager
# player registry
nextPlayerId: public(uint256)
playerAddress: public(HashMap[uint256, address])
pendingPlayerAddress: public(HashMap[uint256, address])
@external
def register() -> uint256:
playerId: uint256 = self.nextPlayerId
self.playerAddress[playerId] = msg.sender
self.nextPlayerId = unsafe_add(playerId, 1)
return playerId
@external
def changePlayerAddress(_playerId: uint256, _newAddress: address):
assert self.playerAddress[_playerId] == msg.sender, "unauthorised"
self.pendingPlayerAddress[_playerId] = _newAddress
@external
def confirmChangePlayerAddress(_playerId: uint256):
assert self.pendingPlayerAddress[_playerId] == msg.sender, "unauthorised"
self.pendingPlayerAddress[_playerId] = empty(address)
self.playerAddress[_playerId] = msg.sender
MAX_SEATS: constant(uint256) = 9 # maximum seats per table
MAX_LEVELS: constant(uint256) = 100 # maximum number of levels in tournament structure
Req_DECK: constant(uint256) = 0 # not drawn
Req_HAND: constant(uint256) = 1 # drawn to hand
Req_MUCK: constant(uint256) = 2 # may be revealed, not required
Req_SHOW: constant(uint256) = 3 # must be shown
# not using Vyper enum because of this bug
# https://github.com/vyperlang/vyper/pull/3196/files#r1062141796
Phase_JOIN: constant(uint256) = 0 # before the game has started, taking seats
Phase_PREP: constant(uint256) = 1 # all players seated, preparing the deck
Phase_SHUFFLE: constant(uint256) = 2 # submitting shuffles and verifications in order
Phase_DEAL: constant(uint256) = 3 # drawing and possibly opening cards as currently required
Phase_PLAY: constant(uint256) = 4 # betting; new card revelations may become required
Phase_SHOW: constant(uint256) = 5 # showdown TODO
struct Config:
gameAddress: address # address of game manager
buyIn: uint256 # entry ticket price per player
bond: uint256 # liveness bond for each player
startsWith: uint256 # game can start when this many players are seated
untilLeft: uint256 # game ends when this many players are left
structure: uint256[100] # small blind levels (right-padded with blanks)
levelBlocks: uint256 # blocks between levels
verifRounds: uint256 # number of shuffle verifications required
prepBlocks: uint256 # blocks to submit deck preparation
shuffBlocks: uint256 # blocks to submit shuffle
verifBlocks: uint256 # blocks to submit shuffle verification
dealBlocks: uint256 # blocks to submit card decryptions
actBlocks: uint256 # blocks to act before folding can be triggered
struct Table:
tableId: uint256
config: Config
seats: uint256[9] # playerIds in seats as at the start of the game
deck: DeckManager # deck contract
deckId: uint256 # id of deck in deck contract
phase: uint256
present: bool[9] # whether each player contributes to the current shuffle
handId: uint256 # id of hand in hand contract
commitBlock: uint256 # block from which new commitments were required
deckIndex: uint256 # index of next card in deck
drawIndex: uint256[26] # player the card is drawn to
requirement: uint256[26] # revelation requirement level
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment