@block52/poker-vm-sdk 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/deck.d.ts CHANGED
@@ -16,6 +16,36 @@ export declare class Deck implements IDeck, IJSONModel {
16
16
  private top;
17
17
  constructor(deck?: string);
18
18
  shuffle(seed: number[]): void;
19
+ /**
20
+ * Shuffle deterministically from a 32-byte client entropy seed, byte-for-byte
21
+ * matching the Cosmos chain so the PVM and the chain derive the SAME deck for
22
+ * the same seed. This is a faithful port of
23
+ * `pokerchain/x/poker/types/deck.go:ShuffleFromVRF` (poker-vm#2460): without
24
+ * it the PVM forks from the chain on a client-seed new-hand (#2418).
25
+ *
26
+ * DEPRECATED interim: the client-chosen seed is grindable. Superseded by the
27
+ * validator-entropy VRF re-hardening tracked in poker-vm#2459.
28
+ *
29
+ * @param seedHex 32-byte seed as 64 hex chars (the FE's `seed=` value).
30
+ */
31
+ shuffleFromSeed(seedHex: string): void;
32
+ private static readonly PLAYER_SEED_LEN;
33
+ private static readonly VRF_INFO;
34
+ /**
35
+ * Streaming HKDF-Expand (RFC 5869, SHA-256), matching Go
36
+ * `hkdf.New(sha256.New, ikm, salt, info).Read`:
37
+ * PRK = HMAC(salt, ikm); output = T(1)||T(2)||…, T(n) = HMAC(PRK, T(n-1)||info||n).
38
+ * salt is HashLen zero bytes (Go's nil-salt default). Returns a reader that
39
+ * yields the next `n` stream bytes on each call.
40
+ */
41
+ private static hkdfExpandReader;
42
+ /**
43
+ * Uniform integer in [0, max) by rejection sampling — a port of Go
44
+ * `crypto/rand.Int`. The byte count, high-byte mask and reject test match
45
+ * the stdlib exactly so the HKDF byte stream is consumed the same way the
46
+ * chain consumes it. `max` here is always ≤ 52, so the result fits a number.
47
+ */
48
+ private static randInt;
19
49
  getCardMnemonic(suit: SUIT, rank: number): string;
20
50
  getNext(): Card;
21
51
  deal(amount: number): Card[];
@@ -1 +1 @@
1
- {"version":3,"file":"deck.d.ts","sourceRoot":"","sources":["../src/deck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,KAAK;IAClB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/B,OAAO,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,IAAI,OAAO,CAAC;CACrB;AAED,qBAAa,IAAK,YAAW,KAAK,EAAE,UAAU;IAC1C,gBAAuB,SAAS,MAAM;IAEtC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAM9B;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAK9B;IAEF,OAAO,CAAC,KAAK,CAAc;IACpB,IAAI,EAAE,MAAM,CAAM;IAClB,QAAQ,EAAE,MAAM,CAAM;IAC7B,OAAO,CAAC,GAAG,CAAa;gBAEZ,IAAI,CAAC,EAAE,MAAM;IA0BlB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAa7B,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAOjD,OAAO,IAAI,IAAI;IAIf,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE;IAQ5B,MAAM,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE;IAM3B,QAAQ,IAAI,MAAM;IAsBzB,OAAO,CAAC,UAAU;WAMJ,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAwChD,OAAO,CAAC,cAAc;CAazB"}
1
+ {"version":3,"file":"deck.d.ts","sourceRoot":"","sources":["../src/deck.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,WAAW,KAAK;IAClB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/B,OAAO,IAAI,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,IAAI,OAAO,CAAC;CACrB;AAED,qBAAa,IAAK,YAAW,KAAK,EAAE,UAAU;IAC1C,gBAAuB,SAAS,MAAM;IAEtC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAM9B;IAEF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAK9B;IAEF,OAAO,CAAC,KAAK,CAAc;IACpB,IAAI,EAAE,MAAM,CAAM;IAClB,QAAQ,EAAE,MAAM,CAAM;IAC7B,OAAO,CAAC,GAAG,CAAa;gBAEZ,IAAI,CAAC,EAAE,MAAM;IA0BlB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IAapC;;;;;;;;;;;OAWG;IACI,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAuB7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAM;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAEnD;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAsB/B;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,OAAO;IAwBf,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAOjD,OAAO,IAAI,IAAI;IAIf,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE;IAQ5B,MAAM,IAAI;QAAE,KAAK,EAAE,IAAI,EAAE,CAAA;KAAE;IAM3B,QAAQ,IAAI,MAAM;IAsBzB,OAAO,CAAC,UAAU;WAMJ,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAwChD,OAAO,CAAC,cAAc;CAazB"}
package/dist/index.d.ts CHANGED
@@ -45239,6 +45239,7 @@ declare enum NonPlayerActionType {
45239
45239
  JOIN = "join",
45240
45240
  LEAVE = "leave",
45241
45241
  NEW_HAND = "new-hand",
45242
+ POST = "post",
45242
45243
  SIT_IN = "sit-in",
45243
45244
  SIT_IN_AND_WAIT = "sit-in-and-wait",
45244
45245
  SIT_OUT = "sit-out",
@@ -45251,6 +45252,7 @@ declare const AllPlayerActions: {
45251
45252
  JOIN: NonPlayerActionType.JOIN;
45252
45253
  LEAVE: NonPlayerActionType.LEAVE;
45253
45254
  NEW_HAND: NonPlayerActionType.NEW_HAND;
45255
+ POST: NonPlayerActionType.POST;
45254
45256
  SIT_IN: NonPlayerActionType.SIT_IN;
45255
45257
  SIT_IN_AND_WAIT: NonPlayerActionType.SIT_IN_AND_WAIT;
45256
45258
  SIT_OUT: NonPlayerActionType.SIT_OUT;
@@ -46113,6 +46115,36 @@ declare class Deck implements IDeck, IJSONModel {
46113
46115
  private top;
46114
46116
  constructor(deck?: string);
46115
46117
  shuffle(seed: number[]): void;
46118
+ /**
46119
+ * Shuffle deterministically from a 32-byte client entropy seed, byte-for-byte
46120
+ * matching the Cosmos chain so the PVM and the chain derive the SAME deck for
46121
+ * the same seed. This is a faithful port of
46122
+ * `pokerchain/x/poker/types/deck.go:ShuffleFromVRF` (poker-vm#2460): without
46123
+ * it the PVM forks from the chain on a client-seed new-hand (#2418).
46124
+ *
46125
+ * DEPRECATED interim: the client-chosen seed is grindable. Superseded by the
46126
+ * validator-entropy VRF re-hardening tracked in poker-vm#2459.
46127
+ *
46128
+ * @param seedHex 32-byte seed as 64 hex chars (the FE's `seed=` value).
46129
+ */
46130
+ shuffleFromSeed(seedHex: string): void;
46131
+ private static readonly PLAYER_SEED_LEN;
46132
+ private static readonly VRF_INFO;
46133
+ /**
46134
+ * Streaming HKDF-Expand (RFC 5869, SHA-256), matching Go
46135
+ * `hkdf.New(sha256.New, ikm, salt, info).Read`:
46136
+ * PRK = HMAC(salt, ikm); output = T(1)||T(2)||…, T(n) = HMAC(PRK, T(n-1)||info||n).
46137
+ * salt is HashLen zero bytes (Go's nil-salt default). Returns a reader that
46138
+ * yields the next `n` stream bytes on each call.
46139
+ */
46140
+ private static hkdfExpandReader;
46141
+ /**
46142
+ * Uniform integer in [0, max) by rejection sampling — a port of Go
46143
+ * `crypto/rand.Int`. The byte count, high-byte mask and reject test match
46144
+ * the stdlib exactly so the HKDF byte stream is consumed the same way the
46145
+ * chain consumes it. `max` here is always ≤ 52, so the result fits a number.
46146
+ */
46147
+ private static randInt;
46116
46148
  getCardMnemonic(suit: SUIT, rank: number): string;
46117
46149
  getNext(): Card;
46118
46150
  deal(amount: number): Card[];
package/dist/index.esm.js CHANGED
@@ -2,7 +2,7 @@ import { Registry, DirectSecp256k1HdWallet, encodePubkey, makeAuthInfoBytes, mak
2
2
  import { SigningStargateClient, GasPrice } from '@cosmjs/stargate';
3
3
  import { EventEmitter } from 'events';
4
4
  import { stringToPath } from '@cosmjs/crypto';
5
- import { createHash } from 'crypto';
5
+ import { createHash, createHmac } from 'crypto';
6
6
  import { toBase64, fromBase64 } from '@cosmjs/encoding';
7
7
  import { encodeSecp256k1Pubkey } from '@cosmjs/amino';
8
8
 
@@ -56051,6 +56051,11 @@ var NonPlayerActionType;
56051
56051
  NonPlayerActionType["JOIN"] = "join";
56052
56052
  NonPlayerActionType["LEAVE"] = "leave";
56053
56053
  NonPlayerActionType["NEW_HAND"] = "new-hand";
56054
+ // Entry big blind auto-posted when a post-now joiner activates off the blind
56055
+ // seats (poker-vm#2553). Recorded in ANTE; counted toward the pot + the
56056
+ // player's bet (they're matched) but excluded from the first-to-act /
56057
+ // has-acted scans (it's a non-player action, like DEAD_SMALL_BLIND).
56058
+ NonPlayerActionType["POST"] = "post";
56054
56059
  NonPlayerActionType["SIT_IN"] = "sit-in";
56055
56060
  // Sit in and wait for the big blind — distinct action from SIT_IN (post now)
56056
56061
  // so each has a single responsibility. Sets WAITING_FOR_BIG_BLIND. (#2139)
@@ -57191,6 +57196,92 @@ class Deck {
57191
57196
  // Explicitly update hash after shuffling
57192
57197
  this.createHash();
57193
57198
  }
57199
+ /**
57200
+ * Shuffle deterministically from a 32-byte client entropy seed, byte-for-byte
57201
+ * matching the Cosmos chain so the PVM and the chain derive the SAME deck for
57202
+ * the same seed. This is a faithful port of
57203
+ * `pokerchain/x/poker/types/deck.go:ShuffleFromVRF` (poker-vm#2460): without
57204
+ * it the PVM forks from the chain on a client-seed new-hand (#2418).
57205
+ *
57206
+ * DEPRECATED interim: the client-chosen seed is grindable. Superseded by the
57207
+ * validator-entropy VRF re-hardening tracked in poker-vm#2459.
57208
+ *
57209
+ * @param seedHex 32-byte seed as 64 hex chars (the FE's `seed=` value).
57210
+ */
57211
+ shuffleFromSeed(seedHex) {
57212
+ const seed = Buffer.from(seedHex, "hex");
57213
+ if (seed.length !== Deck.PLAYER_SEED_LEN) {
57214
+ throw new Error(`player seed must be ${Deck.PLAYER_SEED_LEN} bytes, got ${seed.length}`);
57215
+ }
57216
+ this.seedHash = createHash("sha256").update(seed).digest("hex");
57217
+ // HKDF-SHA256 expand (salt = HashLen zero bytes, info = VRF_INFO),
57218
+ // consumed as an on-demand byte stream — mirrors Go hkdf.New(...).Read.
57219
+ const read = Deck.hkdfExpandReader(seed, Buffer.alloc(32), Buffer.from(Deck.VRF_INFO));
57220
+ // Fisher-Yates with crypto/rand.Int rejection sampling (Go semantics),
57221
+ // so the HKDF stream is consumed identically to the chain.
57222
+ for (let i = this.cards.length - 1; i > 0; i--) {
57223
+ const j = Deck.randInt(read, i + 1);
57224
+ [this.cards[i], this.cards[j]] = [this.cards[j], this.cards[i]];
57225
+ }
57226
+ this.createHash();
57227
+ }
57228
+ /**
57229
+ * Streaming HKDF-Expand (RFC 5869, SHA-256), matching Go
57230
+ * `hkdf.New(sha256.New, ikm, salt, info).Read`:
57231
+ * PRK = HMAC(salt, ikm); output = T(1)||T(2)||…, T(n) = HMAC(PRK, T(n-1)||info||n).
57232
+ * salt is HashLen zero bytes (Go's nil-salt default). Returns a reader that
57233
+ * yields the next `n` stream bytes on each call.
57234
+ */
57235
+ static hkdfExpandReader(ikm, salt, info) {
57236
+ const prk = createHmac("sha256", salt).update(ikm).digest();
57237
+ let buffer = Buffer.alloc(0);
57238
+ let t = Buffer.alloc(0);
57239
+ let counter = 1;
57240
+ return (n) => {
57241
+ while (buffer.length < n) {
57242
+ if (counter > 255) {
57243
+ throw new Error("HKDF stream exhausted (>255 blocks)");
57244
+ }
57245
+ t = createHmac("sha256", prk)
57246
+ .update(Buffer.concat([t, info, Buffer.from([counter])]))
57247
+ .digest();
57248
+ buffer = Buffer.concat([buffer, t]);
57249
+ counter++;
57250
+ }
57251
+ const out = Buffer.from(buffer.subarray(0, n)); // copy before advancing
57252
+ buffer = buffer.subarray(n);
57253
+ return out;
57254
+ };
57255
+ }
57256
+ /**
57257
+ * Uniform integer in [0, max) by rejection sampling — a port of Go
57258
+ * `crypto/rand.Int`. The byte count, high-byte mask and reject test match
57259
+ * the stdlib exactly so the HKDF byte stream is consumed the same way the
57260
+ * chain consumes it. `max` here is always ≤ 52, so the result fits a number.
57261
+ */
57262
+ static randInt(read, max) {
57263
+ const nMax = max - 1; // largest valid value; bit length is taken over max-1
57264
+ if (nMax === 0) {
57265
+ return 0; // max === 1: only 0 is valid, no bytes consumed
57266
+ }
57267
+ const bitLen = 32 - Math.clz32(nMax);
57268
+ const k = Math.ceil(bitLen / 8);
57269
+ let b = bitLen % 8;
57270
+ if (b === 0) {
57271
+ b = 8;
57272
+ }
57273
+ for (;;) {
57274
+ const bytes = read(k);
57275
+ bytes[0] &= (1 << b) - 1; // clear high bits of the top byte
57276
+ let n = 0;
57277
+ for (const byte of bytes) {
57278
+ n = n * 256 + byte; // big-endian, matching big.Int.SetBytes
57279
+ }
57280
+ if (n < max) {
57281
+ return n;
57282
+ }
57283
+ }
57284
+ }
57194
57285
  getCardMnemonic(suit, rank) {
57195
57286
  const rankNum = Number(rank);
57196
57287
  const rankStr = Deck.RANK_MAP[rankNum] !== undefined ? Deck.RANK_MAP[rankNum] : rankNum.toString();
@@ -57317,6 +57408,10 @@ Deck.SUIT_MAP = {
57317
57408
  [SUIT.HEARTS]: "H",
57318
57409
  [SUIT.SPADES]: "S"
57319
57410
  };
57411
+ // Matches pokerchain types.PlayerSeedLen and VRFInputPrefix — the two sides
57412
+ // MUST agree on these or the derived decks diverge.
57413
+ Deck.PLAYER_SEED_LEN = 32;
57414
+ Deck.VRF_INFO = "poker/deck/v1";
57320
57415
 
57321
57416
  /**
57322
57417
  * The community board for a Texas Hold'em hand.