@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 +30 -0
- package/dist/deck.d.ts.map +1 -1
- package/dist/index.d.ts +32 -0
- package/dist/index.esm.js +96 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -1
- package/dist/types/game.d.ts +2 -0
- package/dist/types/game.d.ts.map +1 -1
- package/package.json +2 -1
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[];
|
package/dist/deck.d.ts.map
CHANGED
|
@@ -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;
|
|
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.
|