Skip to content

Commit 12d82c7

Browse files
authored
Merge pull request #63 from arkade-os/agent/update-vm-opcodes
Align compiler with unified VM opcodes
2 parents 02d10ff + cf73e6b commit 12d82c7

35 files changed

Lines changed: 1508 additions & 904 deletions

arkade-bindgen/src/ir.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ pub enum Encoding {
1515
Raw32,
1616
/// Bitcoin CScriptNum (variable-length LE integer)
1717
ScriptNum,
18-
/// 8-byte unsigned little-endian int64
19-
Le64,
20-
/// 4-byte unsigned little-endian int32
21-
Le32,
2218
/// Unrecognized encoding string
2319
Unknown(String),
2420
}
@@ -33,8 +29,6 @@ impl Encoding {
3329
"raw-20" => Encoding::Raw20,
3430
"raw-32" => Encoding::Raw32,
3531
"scriptnum" => Encoding::ScriptNum,
36-
"le64" => Encoding::Le64,
37-
"le32" => Encoding::Le32,
3832
other => Encoding::Unknown(other.to_string()),
3933
}
4034
}
@@ -63,8 +57,6 @@ impl Encoding {
6357
Encoding::Raw20 => "raw-20",
6458
Encoding::Raw32 => "raw-32",
6559
Encoding::ScriptNum => "scriptnum",
66-
Encoding::Le64 => "le64",
67-
Encoding::Le32 => "le32",
6860
Encoding::Unknown(s) => s.as_str(),
6961
}
7062
}

arkade-bindgen/src/targets/go.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ fn go_type_for_field(field: &Field) -> &'static str {
3434
"int64"
3535
}
3636
}
37-
Encoding::Le64 => "uint64",
38-
Encoding::Le32 => "uint32",
3937
Encoding::Unknown(_) => "[]byte",
4038
}
4139
}
@@ -57,8 +55,6 @@ fn encoding_const(encoding: &Encoding) -> &'static str {
5755
Encoding::Raw20 => "ark.Raw20",
5856
Encoding::Raw32 => "ark.Raw32",
5957
Encoding::ScriptNum => "ark.ScriptNum",
60-
Encoding::Le64 => "ark.Le64",
61-
Encoding::Le32 => "ark.Le32",
6258
Encoding::Unknown(_) => "ark.Raw",
6359
}
6460
}
@@ -74,8 +70,6 @@ fn value_expr(field: &Field, prefix: &str) -> String {
7470
format!("ark.EncodeScriptNum({}.{})", prefix, go_name)
7571
}
7672
}
77-
Encoding::Le64 => format!("ark.EncodeLe64({}.{})", prefix, go_name),
78-
Encoding::Le32 => format!("ark.EncodeLe32({}.{})", prefix, go_name),
7973
_ if is_fixed_array(&field.encoding) => format!("{}.{}[:]", prefix, go_name),
8074
_ => format!("{}.{}", prefix, go_name),
8175
}

arkade-bindgen/src/targets/typescript.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ fn ts_type(encoding: &Encoding) -> &'static str {
2727
| Encoding::Raw
2828
| Encoding::Raw20
2929
| Encoding::Raw32 => "Uint8Array",
30-
Encoding::ScriptNum | Encoding::Le64 => "bigint",
31-
Encoding::Le32 => "number",
30+
Encoding::ScriptNum => "bigint",
3231
Encoding::Unknown(_) => "Uint8Array",
3332
}
3433
}

arkade-bindgen/tests/ir_test.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ fn test_encoding_roundtrip() {
9797
("raw-20", Encoding::Raw20),
9898
("raw-32", Encoding::Raw32),
9999
("scriptnum", Encoding::ScriptNum),
100-
("le64", Encoding::Le64),
101-
("le32", Encoding::Le32),
102100
];
103101

104102
for (s, expected) in encodings {

examples/bonds/repayment_pool.ark

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ contract RepaymentPool(
9090
int oracleAge = tx.offchainTime - oracleTime;
9191
require(oracleAge >= 0, "future-dated oracle");
9292
require(oracleAge <= oracleMaxAgeSeconds, "stale oracle");
93-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
93+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
9494
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
9595

9696
int collateralValue = collateral * oraclePrice / 100000000;
@@ -240,7 +240,7 @@ contract RepaymentPool(
240240
int oracleAge = tx.offchainTime - oracleTime;
241241
require(oracleAge >= 0, "future-dated oracle");
242242
require(oracleAge <= oracleMaxAgeSeconds, "stale oracle");
243-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
243+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
244244
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
245245

246246
int collateralValue = newCollateral * oraclePrice / 100000000;
@@ -298,7 +298,7 @@ contract RepaymentPool(
298298
int oracleAge = tx.offchainTime - oracleTime;
299299
require(oracleAge >= 0, "future-dated oracle");
300300
require(oracleAge <= oracleMaxAgeSeconds, "stale oracle");
301-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
301+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
302302
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
303303

304304
require(
@@ -380,7 +380,7 @@ contract RepaymentPool(
380380
int oracleAge = tx.offchainTime - oracleTime;
381381
require(oracleAge >= 0, "future-dated oracle");
382382
require(oracleAge <= oracleMaxAgeSeconds, "stale oracle");
383-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
383+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
384384
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
385385

386386
require(

examples/stability/stability.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,10 @@ The oracle signs BTC/USD prices off-chain as `sha256(ticker || price || timestam
144144
1. Enforces freshness: `tx.offchainTime - oracleTime <= 600` seconds (10 minutes).
145145
2. Reconstructs the message hash on-stack with `+` (OP_CAT) and one-shot `sha256` (OP_SHA256):
146146
```ark
147-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
147+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
148148
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
149149
```
150-
`+` dispatches on type: when at least one operand is bytes-like the compiler emits OP_CAT, auto-coercing int sides via OP_SCRIPTNUMTOLE64 to keep on-chain and off-chain hashing byte-identical.
150+
`+` dispatches on type: when at least one operand is bytes-like the compiler emits OP_CAT. Int operands must be converted with an explicit `num2bin(value, width)` — the compiler never picks a width, because the width is what an off-chain signer has to reproduce byte for byte. `num2bin` writes little-endian sign-magnitude (sign in the top bit of the last byte), which matches an unsigned LE64 only for non-negative values, so an off-chain signer must encode negatives the same way; a value that does not fit the requested width fails the script rather than truncating.
151151

152152
Three layers of replay protection are baked into the signed message:
153153

examples/stability/stability_offer.ark

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ contract StabilityOffer(
6868
require(oracleAge >= 0, "future-dated oracle");
6969
require(oracleAge <= 600, "stale oracle");
7070

71-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
71+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
7272
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
7373

7474
int targetUSD = userBTC * oraclePrice / 100000000;

examples/stability/stability_vault.ark

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ contract StabilityVault(
227227
require(oracleAge >= 0, "future-dated oracle");
228228
require(oracleAge <= 600, "stale oracle");
229229

230-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
230+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
231231
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
232232

233233
int elapsed = tx.offchainTime - lastUpdate;
@@ -269,7 +269,7 @@ contract StabilityVault(
269269
require(oracleAge >= 0, "future-dated oracle");
270270
require(oracleAge <= 600, "stale oracle");
271271

272-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
272+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
273273
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
274274

275275
int elapsed = tx.offchainTime - lastUpdate;
@@ -315,7 +315,7 @@ contract StabilityVault(
315315
require(oracleAge >= 0, "future-dated oracle");
316316
require(oracleAge <= 600, "stale oracle");
317317

318-
let oracleMsg = sha256(ticker + oraclePrice + oracleTime);
318+
let oracleMsg = sha256(ticker + num2bin(oraclePrice, 8) + num2bin(oracleTime, 8));
319319
require(checkSigFromStack(oracleSig, oraclePk, oracleMsg), "invalid oracle signature");
320320

321321
int elapsed = tx.offchainTime - lastUpdate;

playground/arkade-language.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ const arkadeMonarch = {
1717
builtinFunctions: [
1818
'checkSig', 'checkMultisig', 'checkSigFromStack', 'checkSigFromStackVerify',
1919
'sha256', 'sha256Initialize', 'sha256Update', 'sha256Finalize',
20-
'neg64', 'le64ToScriptNum', 'le32ToLe64', 'ecMulScalarVerify', 'tweakVerify',
20+
'digest', 'sighash', 'modExp', 'reverseBytes',
21+
'ecAdd', 'ecMul', 'ecPairing', 'ecMulScalarVerify', 'tweakVerify',
2122
'older', 'after', 'tweak'
2223
],
2324

@@ -41,7 +42,7 @@ const arkadeMonarch = {
4142
[/\b(pubkey|signature|bytes32|bytes20|bytes|asset|int|bool)\b/, 'type'],
4243

4344
// Built-in functions
44-
[/\b(checkSig|checkMultisig|checkSigFromStack|checkSigFromStackVerify|sha256|sha256Initialize|sha256Update|sha256Finalize|neg64|le64ToScriptNum|le32ToLe64|ecMulScalarVerify|tweakVerify|older|after|tweak)\b/, 'predefined'],
45+
[/\b(checkSig|checkMultisig|checkSigFromStack|checkSigFromStackVerify|sha256|sha256Initialize|sha256Update|sha256Finalize|digest|sighash|modExp|reverseBytes|ecAdd|ecMul|ecPairing|ecMulScalarVerify|tweakVerify|older|after|tweak)\b/, 'predefined'],
4546

4647
// Transaction/this keywords
4748
[/\b(tx|this)\b/, 'variable.predefined'],

playground/codegen.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function leafSuffix(groupName, leafName) {
100100
const TS_TYPE_MAP = {
101101
'compressed-33': 'Pubkey', 'schnorr-64': 'Signature',
102102
'raw': 'Bytes', 'raw-20': 'Bytes20', 'raw-32': 'Bytes32',
103-
'scriptnum': 'bigint', 'le64': 'bigint', 'le32': 'number',
103+
'scriptnum': 'bigint',
104104
};
105105

106106
function tsTypeForField(field) {
@@ -186,7 +186,7 @@ function generateTypeScript(ir) {
186186
const GO_TYPE_MAP = {
187187
'compressed-33': '[33]byte', 'schnorr-64': '[64]byte',
188188
'raw': '[]byte', 'raw-20': '[20]byte', 'raw-32': '[32]byte',
189-
'scriptnum': 'int64', 'le64': 'uint64', 'le32': 'uint32',
189+
'scriptnum': 'int64',
190190
};
191191

192192
function goTypeForField(field) {
@@ -201,7 +201,7 @@ function isFixedArray(encoding) {
201201
const ENCODING_CONST = {
202202
'compressed-33': 'ark.Compressed33', 'schnorr-64': 'ark.Schnorr64',
203203
'raw': 'ark.Raw', 'raw-20': 'ark.Raw20', 'raw-32': 'ark.Raw32',
204-
'scriptnum': 'ark.ScriptNum', 'le64': 'ark.Le64', 'le32': 'ark.Le32',
204+
'scriptnum': 'ark.ScriptNum',
205205
};
206206

207207
function goValueExpr(field, prefix) {
@@ -211,8 +211,6 @@ function goValueExpr(field, prefix) {
211211
? `ark.EncodeBool(${prefix}.${goName})`
212212
: `ark.EncodeScriptNum(${prefix}.${goName})`;
213213
}
214-
if (field.encoding === 'le64') return `ark.EncodeLe64(${prefix}.${goName})`;
215-
if (field.encoding === 'le32') return `ark.EncodeLe32(${prefix}.${goName})`;
216214
if (isFixedArray(field.encoding)) return `${prefix}.${goName}[:]`;
217215
return `${prefix}.${goName}`;
218216
}

0 commit comments

Comments
 (0)