Skip to content

Commit 543646a

Browse files
committed
wip: create identity transition (invalid signature)
1 parent c60846a commit 543646a

File tree

1 file changed

+393
-0
lines changed

1 file changed

+393
-0
lines changed

2-create-identity-transition.js

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
let Fs = require("node:fs/promises");
2+
3+
let DashKeys = require("dashkeys");
4+
let DashTx = require("dashtx");
5+
let Bincode = require("./bincode.js");
6+
7+
let KeyUtils = require("./key-utils.js");
8+
9+
const ST_CREATE_IDENTITY = 2;
10+
const L2_VERSION_PLATFORM = 1; // actually constant "0" ??
11+
12+
let KEY_LEVELS = {
13+
0: "MASTER",
14+
1: "CRITICAL",
15+
2: "HIGH",
16+
3: "MEDIUM",
17+
MASTER: 0,
18+
CRITICAL: 1,
19+
HIGH: 2,
20+
MEDIUM: 3,
21+
};
22+
23+
let KEY_PURPOSES = {
24+
0: "AUTHENTICATION",
25+
1: "ENCRYPTION",
26+
2: "DECRYPTION",
27+
3: "TRANSFER",
28+
4: "SYSTEM",
29+
5: "VOTING",
30+
AUTHENTICATION: 0,
31+
ENCRYPTION: 1,
32+
DECRYPTION: 2,
33+
TRANSFER: 3,
34+
SYSTEM: 4,
35+
VOTING: 5,
36+
};
37+
38+
let KEY_TYPES = {
39+
0: "ECDSA_SECP256K1",
40+
ECDSA_SECP256K1: 0,
41+
};
42+
43+
async function main() {
44+
// let fundingWif = await readWif("./funding.wif");
45+
// let fundingInfo = await wifToInfo(fundingWif, "testnet");
46+
47+
// KeyUtils.set(fundingInfo.address, {
48+
// address: fundingInfo.address,
49+
// privateKey: fundingInfo.privateKey,
50+
// publicKey: fundingInfo.publicKey,
51+
// pubKeyHash: fundingInfo.pubKeyHashHex,
52+
// });
53+
54+
// let changeWif = await readWif("./change.wif");
55+
// let changeInfo = await wifToInfo(changeWif, "testnet");
56+
57+
let assetWif = await readWif("./asset.wif");
58+
let assetInfo = await wifToInfo(assetWif, "testnet");
59+
60+
let masterWif = await readWif("./master.wif");
61+
let masterInfo = await wifToInfo(masterWif, "testnet");
62+
63+
let otherWif = await readWif("./other.wif");
64+
let otherInfo = await wifToInfo(otherWif, "testnet");
65+
66+
let identityIdHex = await readHex("./identity-id.hex");
67+
68+
let txlocksigHex = await readHex("./rawtxlocksig.hex");
69+
{
70+
let len = txlocksigHex.length / 2;
71+
console.log();
72+
console.log(`Tx Lock Sig Hex (${len}):`);
73+
console.log(txlocksigHex);
74+
}
75+
76+
let vout = -1;
77+
let instantLockTxHex = "";
78+
let instantLockSigHex = "";
79+
{
80+
let txlocksig = DashTx.parseUnknown(txlocksigHex);
81+
vout = txlocksig.outputs.findIndex(function (output) {
82+
//@ts-expect-error
83+
return output.script === "6a00"; // TODO match the burn
84+
});
85+
console.log(txlocksig.outputs);
86+
//@ts-expect-error
87+
instantLockSigHex = txlocksig.sigHashTypeHex;
88+
let isLen = instantLockSigHex.length / 2;
89+
let len = txlocksigHex.length / 2;
90+
len -= isLen;
91+
instantLockTxHex = txlocksigHex.slice(0, len * 2);
92+
console.log();
93+
console.log(`Tx Hex (${len})`);
94+
console.log(instantLockTxHex);
95+
console.log();
96+
console.log(`Tx Lock Sig Instant Lock Hex (${isLen})`);
97+
//@ts-expect-error
98+
console.log(txlocksig.sigHashTypeHex);
99+
}
100+
101+
// let txid = await DashTx.utils.rpc(
102+
// rpcAuthUrl,
103+
// "sendrawtransaction",
104+
// txSigned.transaction,
105+
// );
106+
107+
// const INSTANT_ALP = 0;
108+
// const CHAIN_ALP = 1;
109+
110+
// let blockchaininfo = await DashTx.utils.rpc(rpcAuthUrl, "getblockchaininfo");
111+
// let nextBlock = blockchaininfo.blocks + 1;
112+
113+
// TODO - AJ is here
114+
115+
/** @param {any} magicZmqEmitter */
116+
async function getAssetLockInstantProof(magicZmqEmitter) {
117+
let assetLockInstantProof = {
118+
// type: INSTANT_ALP,
119+
instant_lock: DashTx.utils.hexToBytes(instantLockSigHex),
120+
transaction: DashTx.utils.hexToBytes(instantLockTxHex), // TODO this may need the proof, not the signed tx
121+
// output_index: DashTx.utils.hexToBytes(vout),
122+
output_index: vout,
123+
};
124+
return assetLockInstantProof;
125+
}
126+
127+
async function getAssetLockChainProof() {
128+
let assetLockChainProof = {
129+
// type: CHAIN_ALP,
130+
core_chain_locked_height: nextBlock,
131+
// out_point: fundingOutPointHex,
132+
out_point: {
133+
txid: outpoint.txid,
134+
vout: vout,
135+
},
136+
};
137+
return assetLockChainProof;
138+
}
139+
140+
let assetLockProof;
141+
let weEvenKnowHowToGetIsdlock = true;
142+
if (weEvenKnowHowToGetIsdlock) {
143+
assetLockProof = await getAssetLockInstantProof(null);
144+
} else {
145+
assetLockProof = await getAssetLockChainProof();
146+
}
147+
148+
let identityKeys = await getKnownIdentityKeys(
149+
{ privateKey: masterInfo.privateKey, publicKey: masterInfo.publicKey },
150+
{ privateKey: otherInfo.privateKey, publicKey: otherInfo.publicKey },
151+
);
152+
let stKeys = await getIdentityTransitionKeys(identityKeys);
153+
154+
let stateTransition = {
155+
//protocolVersion: L2_VERSION_PLATFORM,
156+
$version: L2_VERSION_PLATFORM.toString(),
157+
type: ST_CREATE_IDENTITY,
158+
// ecdsaSig(assetLockPrivateKey, CBOR(thisStateTransition))
159+
// "signature":"IBTTgge+/VDa/9+n2q3pb4tAqZYI48AX8X3H/uedRLH5dN8Ekh/sxRRQQS9LaOPwZSCVED6XIYD+vravF2dhYOE=",
160+
asset_lock_proof: assetLockProof,
161+
// publicKeys: stKeys,
162+
public_keys: stKeys,
163+
// [
164+
// {
165+
// id: 0,
166+
// type: 0,
167+
// purpose: 0,
168+
// securityLevel: 0,
169+
// data: "AkWRfl3DJiyyy6YPUDQnNx5KERRnR8CoTiFUvfdaYSDS",
170+
// readOnly: false,
171+
// },
172+
// ],
173+
user_fee_increase: 0,
174+
};
175+
console.log(`stKeys:`);
176+
console.log(stKeys);
177+
178+
let bcAb = Bincode.encode(Bincode.StateTransition, stateTransition, {
179+
signable: true,
180+
});
181+
console.log(`bc (ready-to-sign) AB:`, bcAb);
182+
let bc = new Uint8Array(bcAb);
183+
console.log(`bc (ready-to-sign):`);
184+
console.log(DashTx.utils.bytesToHex(bc));
185+
console.log(bytesToBase64(bc));
186+
187+
let ethBytes = await KeyUtils.signEth(assetInfo.privateKey, bc);
188+
// let sigHex = DashTx.utils.bytesToHex(sigBytes);
189+
Object.assign(stateTransition, {
190+
identity_id: DashTx.utils.hexToBytes(identityIdHex),
191+
// signature: sigHex,
192+
signature: ethBytes,
193+
});
194+
for (let i = 0; i < identityKeys.length; i += 1) {
195+
let key = identityKeys[i];
196+
let stPub = stateTransition.public_keys[i];
197+
let ethBytes = await KeyUtils.signEth(key.privateKey, bc);
198+
// let sigHex = DashTx.utils.bytesToHex(sigBytes);
199+
Object.assign(stPub, {
200+
// signature: sigHex,
201+
signature: ethBytes,
202+
});
203+
}
204+
205+
console.log(JSON.stringify(stateTransition, null, 2));
206+
207+
{
208+
let bcAb = Bincode.encode(Bincode.StateTransition, stateTransition, {
209+
signable: false,
210+
});
211+
let bc = new Uint8Array(bcAb);
212+
console.log(`bc (signed):`);
213+
console.log(DashTx.utils.bytesToHex(bc));
214+
console.log(bytesToBase64(bc));
215+
}
216+
217+
// let identityId = assetLockProof.createIdentifier();
218+
// let identity = Dpp.identity.create(identityId, dppKeys);
219+
// let signedTransition = signTransition(
220+
// identity,
221+
// assetLockProof,
222+
// assetLockPrivateKeyBuffer,
223+
// );
224+
225+
console.log("");
226+
console.log("TODO");
227+
console.log(` - how to serialize and broadcast transition via grpc?`);
228+
}
229+
230+
/**
231+
* @param {Required<Pick<import('dashhd').HDXKey, "privateKey"|"publicKey">>} masterKey
232+
* @param {Required<Pick<import('dashhd').HDXKey, "privateKey"|"publicKey">>} otherKey
233+
* @returns {Promise<Array<EvoKey>>}
234+
*/
235+
async function getKnownIdentityKeys(masterKey, otherKey) {
236+
if (!masterKey.privateKey) {
237+
throw new Error("linter fail");
238+
}
239+
if (!otherKey.privateKey) {
240+
throw new Error("linter fail");
241+
}
242+
let keyDescs = [
243+
// {"$version":"0","id":0,"purpose":0,"securityLevel":0,"contractBounds":null,"type":0,"readOnly":false,"data":[3,58,154,139,30,76,88,26,25,135,114,76,102,151,19,93,49,192,126,231,172,130,126,106,89,206,192,34,176,77,81,5,95],"disabledAt":null}
244+
{
245+
id: 0,
246+
type: KEY_TYPES.ECDSA_SECP256K1,
247+
purpose: KEY_PURPOSES.AUTHENTICATION,
248+
securityLevel: KEY_LEVELS.MASTER,
249+
readOnly: false,
250+
publicKey: masterKey.publicKey,
251+
privateKey: masterKey.privateKey,
252+
data: "",
253+
},
254+
// {"$version":"0","id":1,"purpose":0,"securityLevel":1,"contractBounds":null,"type":0,"readOnly":false,"data":[2,1,70,3,1,141,196,55,100,45,218,22,244,199,252,80,228,130,221,35,226,70,128,188,179,165,150,108,59,52,56,72,226],"disabledAt":null}
255+
{
256+
id: 1,
257+
type: KEY_TYPES.ECDSA_SECP256K1,
258+
purpose: KEY_PURPOSES.AUTHENTICATION,
259+
securityLevel: KEY_LEVELS.CRITICAL,
260+
readOnly: false,
261+
privateKey: otherKey.privateKey,
262+
publicKey: otherKey.publicKey,
263+
data: "",
264+
},
265+
];
266+
return keyDescs;
267+
}
268+
269+
/**
270+
* @typedef EvoKey
271+
* @prop {Uint8} id
272+
* @prop {Uint8} type - TODO constrain to members of KEY_TYPES
273+
* @prop {Uint8} purpose - TODO constrain to members of KEY_PURPOSES
274+
* @prop {Uint8} securityLevel - TODO constrain to members of KEY_LEVELS
275+
* @prop {Boolean} readOnly
276+
* @prop {Uint8Array} publicKey
277+
* @prop {Uint8Array} privateKey
278+
*/
279+
280+
/**
281+
* @typedef STKey
282+
* @prop {Uint8} id
283+
* @prop {Uint8} type - TODO constrain to members of KEY_TYPES
284+
* @prop {Uint8} purpose - TODO constrain to members of KEY_PURPOSES
285+
* @prop {Base64} data - base64-encoded publicKey (compact)
286+
* @prop {Uint8} securityLevel - TODO constrain to members of KEY_LEVELS
287+
* @prop {Boolean} readOnly
288+
*/
289+
290+
/**
291+
* @param {Array<EvoKey>} identityKeys - TODO
292+
*/
293+
function getIdentityTransitionKeys(identityKeys) {
294+
let stKeys = [];
295+
for (let key of identityKeys) {
296+
// let data = bytesToBase64(key.publicKey);
297+
let stKey = {
298+
$version: "0",
299+
id: key.id,
300+
type: key.type,
301+
purpose: key.purpose,
302+
security_level: key.securityLevel,
303+
contract_bounds: null,
304+
// readOnly: key.readOnly,
305+
read_only: key.readOnly || false,
306+
// data: data,
307+
data: key.publicKey,
308+
// signature: "TODO",
309+
};
310+
// if ("readOnly" in key) {
311+
// Object.assign(stKey, { readOnly: key.readOnly });
312+
// }
313+
stKeys.push(stKey);
314+
}
315+
return stKeys;
316+
}
317+
318+
/**
319+
* @param {Uint8Array} bytes
320+
*/
321+
function bytesToBase64(bytes) {
322+
let binstr = "";
323+
for (let i = 0; i < bytes.length; i += 1) {
324+
binstr += String.fromCharCode(bytes[i]);
325+
}
326+
327+
return btoa(binstr);
328+
}
329+
330+
/**
331+
* Reads a hex file as text, stripping comments (anything including and after a non-hex character), removing whitespace, and joining as a single string
332+
* @param {String} path
333+
*/
334+
async function readHex(path) {
335+
let text = await Fs.readFile(path, "utf8");
336+
let lines = text.split("\n");
337+
let hexes = [];
338+
for (let line of lines) {
339+
line = line.replace(/\s/g, "");
340+
line = line.replace(/[^0-9a-f].*/i, "");
341+
hexes.push(line);
342+
}
343+
344+
let hex = hexes.join("");
345+
return hex;
346+
}
347+
348+
/**
349+
* @param {String} path
350+
*/
351+
async function readWif(path) {
352+
let wif = await Fs.readFile(path, "utf8");
353+
wif = wif.trim();
354+
355+
return wif;
356+
}
357+
358+
/**
359+
* @param {String} wif
360+
* @param {DashKeys.VERSION_PRIVATE} version - mainnet, testnet
361+
*/
362+
async function wifToInfo(wif, version) {
363+
let privateKey = await DashKeys.wifToPrivKey(wif, { version });
364+
let publicKey = await KeyUtils.toPublicKey(privateKey);
365+
let pubKeyHash = await DashKeys.pubkeyToPkh(publicKey);
366+
let address = await DashKeys.pkhToAddr(pubKeyHash, {
367+
version,
368+
});
369+
370+
let privateKeyHex = DashKeys.utils.bytesToHex(privateKey);
371+
let publicKeyHex = DashKeys.utils.bytesToHex(publicKey);
372+
let pubKeyHashHex = DashKeys.utils.bytesToHex(pubKeyHash);
373+
374+
return {
375+
wif,
376+
privateKey,
377+
privateKeyHex,
378+
publicKey,
379+
publicKeyHex,
380+
pubKeyHash,
381+
pubKeyHashHex,
382+
address,
383+
};
384+
}
385+
386+
main();
387+
388+
/** @typedef {String} Base58 */
389+
/** @typedef {String} Base64 */
390+
/** @typedef {String} Hex */
391+
/** @typedef {Number} Uint53 */
392+
/** @typedef {Number} Uint32 */
393+
/** @typedef {Number} Uint8 */

0 commit comments

Comments
 (0)