-
Notifications
You must be signed in to change notification settings - Fork 5
/
oneside.html
190 lines (151 loc) · 6.69 KB
/
oneside.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="css/chessboard-0.3.0.min.css">
<title>One-sided Chess Steganography</title>
</head>
<body>
<div class="container">
<h1>One-sided Chess Steganography</h1>
<p>(See also <a href="index.html">the two-sided mode</a>, for when you can control both side's moves).</p>
<p>This is a tool to encode/decode data in chess games. It first encodes the input data as a bignum, and then encodes the bignum in the move choices of one of the players in the game. The "without blunders" mode uses <a href="https://github.com/douglasbagnall/p4wn">p4wn</a> to try to avoid playing bad moves. This mode is less likely to arouse suspicion among actual chess players, but results in longer games.</p>
<p>Compared to the two-sided mode, this one-sided mode results in games that are approximately twice as long, as it can only encode half as much information per move. The advantage is that it can be used when playing a game against an opponent who is not complicit in the steganography.</p>
<p>Also check out <a href="https://github.com/Alheimsins/chess-steg-cli">Jonas Enge's CLI implementation</a>.</p>
<p>Make sure to select which side the moves are stored in before clicking the "Steg" or "Unsteg" buttons:<br>
<label><input type="radio" name="colour" value="white"> Play as white</label>
<label><input type="radio" name="colour" value="black"> Play as black</label></p>
<div class="row">
<div class="col-md-6">
<div id="give-input">
<button class="btn btn-primary" id="steg">Steg »</button>
<button class="btn btn-primary" id="stegb">Steg without blunders »</button>
<textarea rows="6" class="form-control" id="data" placeholder="Data..."></textarea>
</div>
<div id="play-game" style="display:none">
<button class="btn btn-danger" id="cancel">Close</button>
<br>
<i><span id="status">What was your opponent's move?</span></i>
<div id="chessboard" style="width:80%"></div>
<span id="debug"></span>
</div>
</div>
<div class="col-md-6">
<button class="btn btn-primary" id="unsteg">Unsteg «</button>
<button class="btn btn-primary" id="unstegb">Unsteg without blunders «</button>
<form target="_blank" action="https://lichess.org/import" method="POST">
<textarea rows="6" class="form-control" id="pgn" name="pgn" placeholder="Chess game PGN..."></textarea>
<button class="btn btn-primary" type="submit">View on lichess »</button>
</form>
</div>
</div>
<i>By <a href="https://incoherency.co.uk/">James Sanley</a>.</i><br>
<i>Source <a href="https://github.com/jes/chess-steg">on github</a>.</i>
</div>
<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/chessboard-0.3.0.min.js"></script>
<script src="js/chess.js"></script>
<script src="js/BigInteger.min.js"></script>
<script src="js/engine.js"></script>
<script src="js/chess-steg.js"></script>
<script type="text/javascript">
$('#steg').click(function() { steg(false); });
$('#stegb').click(function() { steg(true); });
$('#unsteg').click(function() { unsteg(false); });
$('#unstegb').click(function() { unsteg(true); });
$('#cancel').click(function() {
$('#give-input').show();
$('#play-game').hide();
});
let chessboard;
let chessgame;
let playing_as;
let numin;
function steg(use_engine) {
$('#give-input').hide();
$('#play-game').show();
playing_as = $('input[name=colour]:checked').val();
chessgame = new Chess();
chessboard = ChessBoard('chessboard', {
orientation: playing_as,
position: 'start',
draggable: true,
onDragStart: function(source, piece, position, orientation) {
// you can't play the computer's moves
if (chessgame.turn() == playing_as.charAt(0))
return false;
// you can't move pieces of the wrong colour
if (piece.charAt(0) != chessgame.turn())
return false;
// I'll allow it.
return true;
},
onDrop: function(oldpos, newpos, source, piece, position, orientation) {
// try to play the move
// TODO: pawn promotion
let r = chessgame.move({from: oldpos, to: newpos});
// disallow the move if chess.js doesn't accept it
if (r == undefined)
return 'snapback';
$('#pgn').val(chessgame.pgn());
if (numin.compare(0) == 1) {
$('#status').html("Thinking...");
// calculate computer move in a timeout so that the
// ui can update
window.setTimeout(function() {
state = chess_steg_move(chessgame, numin, use_engine);
numin = state.numin;
chessgame.move(state.move);
chessboard.position(chessgame.fen());
$('#status').html("Play <b>" + state.move + "</b>, then tell me how your opponent responds");
$('#pgn').val(chessgame.pgn());
$('#debug').html("Still to encode: " + numin);
}, 0);
} else {
$('#status').html("Finished, " + playing_as + " resigns.");
var pgn = chessgame.pgn();
if (chessgame.turn() == 'b') {
pgn += " { Black resigns. } 1-0";
} else {
pgn += " { White resigns. } 0-1";
}
$('#pgn').val(pgn);
}
return true;
},
});
numin = data2bignum($('#data').val());
if (playing_as == 'white') {
// play our first move
state = chess_steg_move(chessgame, numin, use_engine);
numin = state.numin;
chessgame.move(state.move);
chessboard.position(chessgame.fen());
$('#status').html("Play <b>" + state.move + "</b>, then tell me how your opponent responds");
$('#pgn').val(chessgame.pgn());
} else {
// wait for input of first move
$('#status').html("Tell me what your opponent played");
}
$('#debug').html("Still to encode: " + numin);
}
function unsteg(use_engine) {
chessgame = new Chess();
playing_as = $('input[name=colour]:checked').val();
chessgame.load_pgn($('#pgn').val());
let numdata = bigInt(0);
while (true) {
let pickedmove = chessgame.undo();
// ignore the other player's moves
if (chessgame.turn() != playing_as.charAt(0))
pickedmove = chessgame.undo();
if (pickedmove == undefined)
break;
numdata = chess_unsteg_move(chessgame, pickedmove.san, numdata, use_engine);
}
$('#data').val(bignum2data(numdata));
$('#give-input').show();
$('#play-game').hide();
}
</script>
</body>