Added BIP32Derive, which uses bip32 from bitcoinjs. Modified a few more operations. Code compiles with 20.3.0

This commit is contained in:
David C Goldenberg 2024-08-19 20:37:12 -04:00
parent 810c94803d
commit f474ffaf72
17 changed files with 764 additions and 170 deletions

219
package-lock.json generated
View file

@ -12,12 +12,14 @@
"dependencies": { "dependencies": {
"@astronautlabs/amf": "^0.0.6", "@astronautlabs/amf": "^0.0.6",
"@babel/polyfill": "^7.12.1", "@babel/polyfill": "^7.12.1",
"@bitcoinerlab/secp256k1": "^1.0.5",
"@blu3r4y/lzma": "^2.3.3", "@blu3r4y/lzma": "^2.3.3",
"argon2-browser": "^1.18.0", "argon2-browser": "^1.18.0",
"arrive": "^2.4.1", "arrive": "^2.4.1",
"avsc": "^5.7.7", "avsc": "^5.7.7",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"bignumber.js": "^9.1.1", "bignumber.js": "^9.1.1",
"bip32": "^4.0.0",
"blakejs": "^1.2.1", "blakejs": "^1.2.1",
"bootstrap": "4.6.2", "bootstrap": "4.6.2",
"bootstrap-colorpicker": "^3.4.0", "bootstrap-colorpicker": "^3.4.0",
@ -1906,6 +1908,15 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@bitcoinerlab/secp256k1": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@bitcoinerlab/secp256k1/-/secp256k1-1.0.5.tgz",
"integrity": "sha512-8gT+ukTCFN2rTxn4hD9Jq3k+UJwcprgYjfK/SQUSLgznXoIgsBnlPuARMkyyuEjycQK9VvnPiejKdszVTflh+w==",
"dependencies": {
"@noble/hashes": "^1.1.5",
"@noble/secp256k1": "^1.7.1"
}
},
"node_modules/@blu3r4y/lzma": { "node_modules/@blu3r4y/lzma": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/@blu3r4y/lzma/-/lzma-2.3.3.tgz", "resolved": "https://registry.npmjs.org/@blu3r4y/lzma/-/lzma-2.3.3.tgz",
@ -2657,6 +2668,28 @@
"integrity": "sha512-GEBeGoXVmTYPtNC4Yq34vfgxf6mlFyEagxpsfH18Qe5BvctF2rprX+wI5dKBm9p5IqHo6ZOcXHCufOeP3cjuOw==", "integrity": "sha512-GEBeGoXVmTYPtNC4Yq34vfgxf6mlFyEagxpsfH18Qe5BvctF2rprX+wI5dKBm9p5IqHo6ZOcXHCufOeP3cjuOw==",
"dev": true "dev": true
}, },
"node_modules/@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@noble/secp256k1": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
"integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -2749,6 +2782,17 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
}, },
"node_modules/@scure/base": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
"integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
]
},
"node_modules/@testim/chrome-version": { "node_modules/@testim/chrome-version": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz",
@ -3851,6 +3895,14 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"node_modules/base-x": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/base64-js": { "node_modules/base64-js": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -3931,6 +3983,20 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/bip32": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
"integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
"dependencies": {
"@noble/hashes": "^1.2.0",
"@scure/base": "^1.1.1",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/bl": { "node_modules/bl": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@ -4412,6 +4478,24 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
"dependencies": {
"base-x": "^3.0.2"
}
},
"node_modules/bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"dependencies": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"node_modules/bson": { "node_modules/bson": {
"version": "4.7.2", "version": "4.7.2",
"resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
@ -9458,9 +9542,9 @@
} }
}, },
"node_modules/jsonwebtoken/node_modules/semver": { "node_modules/jsonwebtoken/node_modules/semver": {
"version": "5.7.1", "version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
"bin": { "bin": {
"semver": "bin/semver" "semver": "bin/semver"
} }
@ -14444,9 +14528,9 @@
"dev": true "dev": true
}, },
"node_modules/protobufjs": { "node_modules/protobufjs": {
"version": "7.2.3", "version": "7.2.5",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz",
"integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@protobufjs/aspromise": "^1.1.2", "@protobufjs/aspromise": "^1.1.2",
@ -15183,9 +15267,9 @@
} }
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "6.3.0", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true, "dev": true,
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
@ -16170,6 +16254,11 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"node_modules/ua-parser-js": { "node_modules/ua-parser-js": {
"version": "1.0.35", "version": "1.0.35",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz",
@ -16962,6 +17051,14 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
"dependencies": {
"bs58check": "<3.0.0"
}
},
"node_modules/winston": { "node_modules/winston": {
"version": "2.4.7", "version": "2.4.7",
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz",
@ -16998,9 +17095,9 @@
} }
}, },
"node_modules/word-wrap": { "node_modules/word-wrap": {
"version": "1.2.3", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@ -18520,6 +18617,15 @@
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }
}, },
"@bitcoinerlab/secp256k1": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@bitcoinerlab/secp256k1/-/secp256k1-1.0.5.tgz",
"integrity": "sha512-8gT+ukTCFN2rTxn4hD9Jq3k+UJwcprgYjfK/SQUSLgznXoIgsBnlPuARMkyyuEjycQK9VvnPiejKdszVTflh+w==",
"requires": {
"@noble/hashes": "^1.1.5",
"@noble/secp256k1": "^1.7.1"
}
},
"@blu3r4y/lzma": { "@blu3r4y/lzma": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/@blu3r4y/lzma/-/lzma-2.3.3.tgz", "resolved": "https://registry.npmjs.org/@blu3r4y/lzma/-/lzma-2.3.3.tgz",
@ -19104,6 +19210,16 @@
"integrity": "sha512-GEBeGoXVmTYPtNC4Yq34vfgxf6mlFyEagxpsfH18Qe5BvctF2rprX+wI5dKBm9p5IqHo6ZOcXHCufOeP3cjuOw==", "integrity": "sha512-GEBeGoXVmTYPtNC4Yq34vfgxf6mlFyEagxpsfH18Qe5BvctF2rprX+wI5dKBm9p5IqHo6ZOcXHCufOeP3cjuOw==",
"dev": true "dev": true
}, },
"@noble/hashes": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ=="
},
"@noble/secp256k1": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
"integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw=="
},
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -19187,6 +19303,11 @@
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
}, },
"@scure/base": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
"integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="
},
"@testim/chrome-version": { "@testim/chrome-version": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz", "resolved": "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.3.tgz",
@ -20145,6 +20266,14 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"base-x": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"base64-js": { "base64-js": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -20201,6 +20330,17 @@
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true "dev": true
}, },
"bip32": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/bip32/-/bip32-4.0.0.tgz",
"integrity": "sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==",
"requires": {
"@noble/hashes": "^1.2.0",
"@scure/base": "^1.1.1",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
}
},
"bl": { "bl": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
@ -20583,6 +20723,24 @@
"update-browserslist-db": "^1.0.11" "update-browserslist-db": "^1.0.11"
} }
}, },
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==",
"requires": {
"base-x": "^3.0.2"
}
},
"bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"requires": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"bson": { "bson": {
"version": "4.7.2", "version": "4.7.2",
"resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz",
@ -24397,9 +24555,9 @@
}, },
"dependencies": { "dependencies": {
"semver": { "semver": {
"version": "5.7.1", "version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
} }
} }
}, },
@ -28032,9 +28190,9 @@
} }
}, },
"protobufjs": { "protobufjs": {
"version": "7.2.3", "version": "7.2.5",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.3.tgz", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz",
"integrity": "sha512-TtpvOqwB5Gdz/PQmOjgsrGH1nHjAQVCN7JG4A6r1sXRWESL5rNMAiRcBQlCAdKxZcAbstExQePYG8xof/JVRgg==", "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==",
"requires": { "requires": {
"@protobufjs/aspromise": "^1.1.2", "@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2", "@protobufjs/base64": "^1.1.2",
@ -28614,9 +28772,9 @@
} }
}, },
"semver": { "semver": {
"version": "6.3.0", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true "dev": true
}, },
"send": { "send": {
@ -29413,6 +29571,11 @@
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
} }
}, },
"typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"ua-parser-js": { "ua-parser-js": {
"version": "1.0.35", "version": "1.0.35",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.35.tgz",
@ -29997,6 +30160,14 @@
"string-width": "^4.0.0" "string-width": "^4.0.0"
} }
}, },
"wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==",
"requires": {
"bs58check": "<3.0.0"
}
},
"winston": { "winston": {
"version": "2.4.7", "version": "2.4.7",
"resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz",
@ -30029,9 +30200,9 @@
} }
}, },
"word-wrap": { "word-wrap": {
"version": "1.2.3", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="
}, },
"worker-loader": { "worker-loader": {
"version": "3.0.8", "version": "3.0.8",

View file

@ -94,12 +94,14 @@
"dependencies": { "dependencies": {
"@astronautlabs/amf": "^0.0.6", "@astronautlabs/amf": "^0.0.6",
"@babel/polyfill": "^7.12.1", "@babel/polyfill": "^7.12.1",
"@bitcoinerlab/secp256k1": "^1.0.5",
"@blu3r4y/lzma": "^2.3.3", "@blu3r4y/lzma": "^2.3.3",
"argon2-browser": "^1.18.0", "argon2-browser": "^1.18.0",
"arrive": "^2.4.1", "arrive": "^2.4.1",
"avsc": "^5.7.7", "avsc": "^5.7.7",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"bignumber.js": "^9.1.1", "bignumber.js": "^9.1.1",
"bip32": "^4.0.0",
"blakejs": "^1.2.1", "blakejs": "^1.2.1",
"bootstrap": "4.6.2", "bootstrap": "4.6.2",
"bootstrap-colorpicker": "^3.4.0", "bootstrap-colorpicker": "^3.4.0",

View file

@ -320,7 +320,9 @@
"Seedphrase To Seed", "Seedphrase To Seed",
"Change Extended Key Version", "Change Extended Key Version",
"Seed To Master Key", "Seed To Master Key",
"Decrypt Keystore File" "Decrypt Keystore File",
"BIP32Derive",
"Public Key To ETH Style Address"
] ]
}, },
{ {

View file

@ -12,6 +12,126 @@ import {toHex} from "crypto-api/src/encoder/hex.mjs";
import Utils from "../Utils.mjs"; import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs"; import OperationError from "../errors/OperationError.mjs";
/**
* Validates the length of the passed in input as one of the allowable lengths.
* @param {*} input
* @param {*} allowableLengths
* @returns
*/
function validateLengths(input, allowableLengths) {
return allowableLengths.includes(input.length);
}
/**
* Returns true if input is a valid hex string, false otherwise.
* @param {*} input
*/
function isHex(input) {
const re = /^[0-9A-Fa-f]{2,}$/g;
return re.test(input);
}
/**
* Returns true if input could be interpreted as a byte string, false otherwise.
*/
function isValidBytes(input) {
for (let i=0; i < input.length; i ++) {
if (input.charCodeAt(i) > 255) {
return false;
}
}
return true;
}
/**
* We validate a passed in input to see if it could be a valid private key.
* A valid private key is string of length 64 that is valid hex, or of length 32 that could be valid bytes.
* @param {*} input
*/
export function validatePrivateKey(input) {
const curInput = input.trim();
if (!validateLengths(curInput, [32, 64])) {
return "Invalid length. We want either 32 or 64 but we got: " + curInput.length;
}
if (curInput.length === 64 && !isHex(curInput)) {
return "We have a string of length 64, but not valid hex. Cannot be interpreted as a private key.";
}
if (curInput.length === 32 && !isValidBytes(curInput)) {
return "We have a string of length 32 but cannot cannot be interpreted as valid bytes.";
}
return "";
}
/**
* We validate a passed in input to see if it could be a valid public key.
* A valid public key (in bytes) is either:
* 65 bytes beginning with 04
* 33 bytes beginning with 02 or 03
* @param {*} input
*/
export function validatePublicKey(input) {
const curInput = input.trim();
if (!validateLengths(curInput, [33, 65, 66, 130])) {
return "Invalid length. We want either 33, 65 (if bytes) or 66, 130 (if hex) but we got: " + curInput.length;
}
if (isHex(curInput)) {
if (!validateLengths(curInput, [66, 130])) {
return "We have a hex string, but its length is wrong. We want 66, 130 but we got: " + curInput.length;
}
if (curInput.length === 66 && (curInput.slice(0, 2) !== "02" && curInput.slice(0, 2) !== "03")) {
return "We have a valid hex string, of reasonable length, (66) but doesn't start with the right value. Correct values are 02, or 03 but we have: " + curInput.slice(0, 2);
}
if (curInput.length === 130 && curInput.slice(0, 2) !== "04") {
return "We have a valid hex string of reasonable length, (130) but doesn't start with the right value. Correct values are 04 but we have: " + curInput.slice(0, 2);
}
return "";
}
if (isValidBytes(curInput)) {
if (!validateLengths(curInput, [33, 65])) {
return "We have a byte string, but its length is wrong. We want 33 or 65 but we got: " + curInput.length;
}
if (curInput.length === 33 && toHex(curInput[0]) !== "02" && toHex(curInput[0]) !== "03") {
return "We have a valid byte string, of reasonable length, (33) but doesn't start with the right value. Correct values are 02, or 03 but we have: " + toHex(curInput[0]) ;
}
if (curInput.length === 65 && toHex(curInput[0]) !== "04") {
return "We have a valid byte string, of reasonable length, (65) but doesn't start with the right value. Correct value is 04 but we have: " + toHex(curInput[0]);
}
return "";
}
}
/**
* We make sure the input is a valid hex string, regardless of if its hex or bytes.
* If not valid bytes or hex, we throw TypeError.
* @param {*} input
* @returns
*/
export function makeSureIsHex(input) {
if (!(isValidBytes(input)) && !(isHex(input))) {
throw TypeError("Input: " + input + " is not valid bytes or hex.");
}
if (isValidBytes(input) && !isHex(input)) {
return toHex(input);
}
return input;
}
/**
* We make sure the input is valid bytes, regardless of if its hex or bytes.
* If not valid bytes or hex, we throw TypeError.
* @param {*} input
*/
export function makeSureIsBytes(input) {
if (!(isValidBytes(input)) && !(isHex(input))) {
throw TypeError("Input: " + input + " is not valid bytes or hex.");
}
if (isHex(input)) {
return fromArrayBuffer(Utils.convertToByteArray(input, "hex"));
}
return input;
}
// ################################################ BEGIN HELPER HASH FUNCTIONS ################################################# // ################################################ BEGIN HELPER HASH FUNCTIONS #################################################
// SHA256(SHA256(input)) // SHA256(SHA256(input))
@ -212,6 +332,35 @@ export function deserializeExtendedKeyFunc (input) {
} }
} }
// Reverse lookup for version bytes
const versionString = {
"043587cf": "tpub",
"04358394": "tprv",
"044a5262": "upub",
"044a4e28": "uprv",
"045f1cf6": "vpub",
"045f18bc": "vprv",
"024289ef": "Upub",
"024285b5": "Uprv",
"02575483": "Vpub",
"02575048": "Vprv",
"0488b21e": "xpub",
"0488ade4": "xprv",
"049d7cb2": "ypub",
"049d7878": "yprv",
"04b24746": "zpub",
"04b2430c": "zprv",
"02aa7ed3": "Zpub",
"02aa7a99": "Zprv",
"0295b43f": "Ypub",
"0295b005": "Yprv",
"019da462": "Ltub",
"019d9cfe": "Ltpv",
"01b26ef6": "Mtub",
"01b26792": "Mtpv",
"0436f6e1": "ttub",
"0436ef7d": "ttpv"
};
// Version byte dictionary. // Version byte dictionary.
const versionBytes = { const versionBytes = {
@ -253,6 +402,16 @@ export function getExtendedKeyVersion(input) {
} }
/**
* Reverse lookup for version string. We take in bytes, output string.
* @param {*} input
* @returns
*/
export function getExtendedKeyString(input) {
return versionString[input];
}
/** /**
* We serialize the extended key based off of the passed in data. * We serialize the extended key based off of the passed in data.
* We assume that the i value should be interpreted as a Uint32 LE. * We assume that the i value should be interpreted as a Uint32 LE.
@ -296,6 +455,12 @@ const versionByteInfo = {
"P2SH": "C4", "P2SH": "C4",
"WIF": "EF", "WIF": "EF",
"hrp": "tb" "hrp": "tb"
},
"LTC": {
"hrp": "ltc",
"P2PKH": "30",
"P2SH": "32",
"WIF": "B0"
} }
}; };

View file

@ -0,0 +1,93 @@
/**
* @author dgoldenberg [virtualcurrency@mitre.org]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
// import OperationError from "../errors/OperationError.mjs";
import { b58DoubleSHAChecksum} from "../lib/Bitcoin.mjs";
import { BIP32Factory} from "bip32";
import ecc from "@bitcoinerlab/secp256k1";
/**
* Sanity checks a derivation path.
* @param {*} input
*/
function verifyDerivationPath(input) {
const splitResults = input.split("/");
let startIndex = 0;
// We skip the first index if its m, as that's common.
if (splitResults[0] === "m") {
startIndex = 1;
}
for (let i =startIndex; i < splitResults.length; i++) {
const re = /^[0-9]{1,}[']{0,1}$/g;
if (!re.test(splitResults[i])) {
return false;
}
}
return true;
}
/**
* BIP32Derive operation
*/
class BIP32Derive extends Operation {
/**
* BIP32Derive constructor
*/
constructor() {
super();
this.name = "BIP32Derive";
this.module = "Default";
this.description = "Takes in an extended key, performs BIP32 key derivation on the extended key, and returns the result as an extended key.";
this.infoURL = "https://en.bitcoin.it/wiki/BIP_0032";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Derivation Path",
"type": "string",
"value": ""
},
];
this.checks = [
{
"pattern": "^(X|x|Y|y|Z|z|L|l|T|t)[pub|prv|tbv|tub][A-HJ-NP-Za-km-z1-9]{2,}$",
"flags": "",
"args": []
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
// We check if input is blank.
// If its blank or just whitespace, we don't need to bother dealing with it.
if (input.trim().length === 0) {
return "";
}
input = input.trim();
if (!verifyDerivationPath(args[0])) {
return "Invalid derivation path: " + args[0] + "\n";
}
const xkeyRe = /^(X|x|Y|y|Z|z|L|l|T|t)[pub|prv|tbv|tub][A-HJ-NP-Za-km-z1-9]{2,}$/g;
if (!b58DoubleSHAChecksum(input) || !xkeyRe.test(input)) {
return "Possibly invalid Extended Key: " + input + "\n";
}
const bip32 = BIP32Factory(ecc);
const node = bip32.fromBase58(input);
const child = node.derivePath(args[0]);
return child.toBase58();
}
}
export default BIP32Derive;

View file

@ -7,9 +7,11 @@
*/ */
import Operation from "../Operation.mjs"; import Operation from "../Operation.mjs";
import {toHex} from "../lib/Hex.mjs";
import ec from "elliptic"; import ec from "elliptic";
import { validatePrivateKey, makeSureIsHex} from "../lib/Bitcoin.mjs";
// import { toHex } from "crypto-api/src/encoder/hex.mjs";
// const curves = ["secp256k1", "ed25519", "curve25519", "p521", "p384", "p256", "p224", "p192"];
/** /**
* Class that takes in a private key, and returns the public key, either in compressed or uncompressed form(s). * Class that takes in a private key, and returns the public key, either in compressed or uncompressed form(s).
*/ */
@ -56,24 +58,15 @@ class PrivateECKeyToPublic extends Operation {
return ""; return "";
} }
input = input.trim(); input = input.trim();
const re = /^[0-9A-Fa-f]{2,}$/g;
if (!(input.length === 64 && re.test(input)) && !(input.length === 32)) {
return "Must pass a hex string of length 64, or a byte string of length 32. Got length " + input.length;
}
// If we have bytes, we need to turn the bytes to hex.
if (input.length !== undefined && input.length === 32) {
const buf = new Uint8Array(new ArrayBuffer(32));
for (let i= 0; i < 32; i ++) { const privKeyCheck = validatePrivateKey(input);
if (input.charCodeAt(i) > 255) {
return "Cannot interpret this 32 character string as bytes."; if (privKeyCheck.trim().length !== 0) {
} return "Error with the input as private key. Error is:\n\t" + privKeyCheck;
buf[i] = input.charCodeAt(i);
}
input = toHex(buf, "", 2, "", 0);
} }
const processedInput = makeSureIsHex(input);
const ecContext = ec.ec("secp256k1"); const ecContext = ec.ec("secp256k1");
const key = ecContext.keyFromPrivate(input); const key = ecContext.keyFromPrivate(processedInput);
const pubkey = key.getPublic(args[0], "hex"); const pubkey = key.getPublic(args[0], "hex");
return pubkey; return pubkey;

View file

@ -7,10 +7,10 @@
*/ */
import Operation from "../Operation.mjs"; import Operation from "../Operation.mjs";
import { base58Encode, getWIFVersionByte, doubleSHA} from "../lib/Bitcoin.mjs"; import { base58Encode, getWIFVersionByte, doubleSHA, validatePrivateKey, makeSureIsHex} from "../lib/Bitcoin.mjs";
import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs"; import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs";
import {toHex} from "crypto-api/src/encoder/hex.mjs"; import {toHex} from "crypto-api/src/encoder/hex.mjs";
import {toHex as toHexOther} from "../lib/Hex.mjs"; // import {toHex as toHexOther} from "../lib/Hex.mjs";
import Utils from "../Utils.mjs"; import Utils from "../Utils.mjs";
@ -65,26 +65,13 @@ class PrivateKeyToWIF extends Operation {
return ""; return "";
} }
input = input.trim(); input = input.trim();
// We check to see if the input is hex or not. const privateKeyCheck = validatePrivateKey(input);
// If it is not, we convert it back to hex if (privateKeyCheck.trim().length !== 0) {
const re = /[0-9A-Fa-f]{2,}/g; return "Error parsing private key. Error is:\n\t" + privateKeyCheck;
if (!(input.length === 64 && re.test(input)) && !(input.length === 32)) {
return "Must pass a hex string of length 64, or a byte string of length 32. Got length: " + input.length;
} }
if (input.length === 32) { const processedKey = makeSureIsHex(input);
const buf = new Uint8Array(new ArrayBuffer(32));
for (let i= 0; i < 32; i ++) {
if (input.charCodeAt(i) > 255) {
return "Cannot interpret this 32 character string as bytes.";
}
buf[i] = input.charCodeAt(i);
}
input = toHexOther(buf, "", 2, "", 0);
}
const versionByte = getWIFVersionByte(args[0]); const versionByte = getWIFVersionByte(args[0]);
let extendedPrivateKey = versionByte + input; let extendedPrivateKey = versionByte + processedKey;
if (args[1]) { if (args[1]) {
extendedPrivateKey += "01"; extendedPrivateKey += "01";
} }

View file

@ -0,0 +1,87 @@
/**
* @author dgoldenberg [virtualcurrency@mitre.org]
* @copyright Crown Copyright 2023
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import { makeSureIsBytes, validatePublicKey} from "../lib/Bitcoin.mjs";
import JSSHA3 from "js-sha3";
import Utils from "../Utils.mjs";
import ec from "elliptic";
/**
* Turns a public key into an ETH address.
* @param {*} input Input, a public key in hex or bytes.
*/
function pubKeyToETHAddress(input) {
// Ethereum addresses require uncompressed public keys.
// We convert if the public key is compressed.
let curKey = makeSureIsBytes(input);
if (curKey[0] !== 0x04 || curKey.length !== 65) {
const ecContext = ec.ec("secp256k1");
const thisKey = ecContext.keyFromPublic(curKey);
curKey = thisKey.getPublic(false, "hex");
}
const algo = JSSHA3.keccak256;
// We need to redo the hex-> bytes transformation here because Javascript is silly.
// sometimes what is desired is an array of ints.
// Other times a string
// Here, the Keccak algorithm seems to want an array of ints. (sigh)
const result = algo(Utils.convertToByteArray(curKey, "hex").slice(1,));
return "0x" + result.slice(-40);
}
/**
* PublicKeyToETHStyleAddress operation
*/
class PublicKeyToETHStyleAddress extends Operation {
/**
* PublicKeyToETHStyleAddress constructor
*/
constructor() {
super();
this.name = "Public Key To ETH Style Address";
this.module = "Default";
this.description = "Converts a public key (compressed or uncompressed) to an Ethereum style address.";
this.infoURL = "https://www.freecodecamp.org/news/how-to-create-an-ethereum-wallet-address-from-a-private-key-ae72b0eee27b/";
this.inputType = "string";
this.outputType = "string";
this.args = [];
this.checks = [
{
pattern: "^0[3|2][a-fA-F0-9]{64}$",
flags: "",
args: []
},
{
pattern: "^04[a-fA-F0-9]{128}$",
flags: "",
args: []
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
// We check if input is blank.
// If its blank or just whitespace, we don't need to bother dealing with it.
if (input.trim().length === 0) {
return "";
}
if (validatePublicKey(input) !== "") {
return validatePublicKey(input);
}
return pubKeyToETHAddress(input);
}
}
export default PublicKeyToETHStyleAddress;

View file

@ -9,11 +9,11 @@
import Operation from "../Operation.mjs"; import Operation from "../Operation.mjs";
import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs"; import { fromArrayBuffer } from "crypto-api/src/encoder/array-buffer.mjs";
import {toHex} from "crypto-api/src/encoder/hex.mjs"; import {toHex} from "crypto-api/src/encoder/hex.mjs";
import { base58Encode, getP2PKHVersionByte, getP2SHVersionByte, hash160Func, doubleSHA, getHumanReadablePart} from "../lib/Bitcoin.mjs"; import { base58Encode, getP2PKHVersionByte, getP2SHVersionByte, hash160Func, doubleSHA, getHumanReadablePart, makeSureIsBytes, validatePublicKey} from "../lib/Bitcoin.mjs";
import {encodeProgramToSegwit} from "../lib/Bech32.mjs"; import {encodeProgramToSegwit} from "../lib/Bech32.mjs";
import JSSHA3 from "js-sha3";
import Utils from "../Utils.mjs"; import Utils from "../Utils.mjs";
/** /**
* Converts a Public Key to a P2PKH Address of the given type. * Converts a Public Key to a P2PKH Address of the given type.
*/ */
@ -27,19 +27,19 @@ class PublicKeyToP2PKHAddress extends Operation {
this.name = "Public Key To Cryptocurrency Address"; this.name = "Public Key To Cryptocurrency Address";
this.module = "Default"; this.module = "Default";
this.description = "Turns a public key into a cryptocurrency address."; this.description = "Turns a public key into a cryptocurrency address. Can select P2PKH, P2SH-P2WPKH and P2WPKH addresses for Bitcoin and Testnet.";
this.inputType = "string"; this.inputType = "string";
this.outputType = "string"; this.outputType = "string";
this.args = [ this.args = [
{ {
"name": "Currency Type", "name": "Currency Type",
"type": "option", "type": "option",
"value": ["BTC", "Testnet", "Ethereum"] "value": ["BTC", "Testnet", "LTC"]
}, },
{ {
"name": "Address Type", "name": "Address Type",
"type": "option", "type": "option",
"value": ["P2PKH (V1 BTC Addresses)", "P2SH-P2PWPKH (Segwit Compatible)", "Segwit (P2WPKH)"] "value": ["P2PKH (V1 BTC Addresses)", "P2SH-P2PWPKH (Segwit Compatible V3 Addresses)", "Segwit (P2WPKH bc1 Addresses)"]
} }
]; ];
this.checks = [ this.checks = [
@ -48,11 +48,6 @@ class PublicKeyToP2PKHAddress extends Operation {
flags: "", flags: "",
args: ["BTC", "P2PKH (V1 BTC Addresses)"] args: ["BTC", "P2PKH (V1 BTC Addresses)"]
}, },
{
pattern: "^04[a-fA-F0-9]{128}$",
flags: "",
args: ["Ethereum", "P2PKH (V1 BTC Addresses)"]
}
]; ];
} }
@ -68,75 +63,39 @@ class PublicKeyToP2PKHAddress extends Operation {
if (input.trim().length === 0) { if (input.trim().length === 0) {
return ""; return "";
} }
// We check to see if the input is hex or not. if (validatePublicKey(input) !== "") {
// If it is, we convert back to bytes. return validatePublicKey(input);
const re = /([0-9A-Fa-f]{2,})/g;
let inputIsHex = false;
let curInput = input;
if (re.test(input)) {
inputIsHex = true;
}
if (inputIsHex) {
curInput = fromArrayBuffer(Utils.convertToByteArray(input, "hex"));
} }
// We sanity check the input // We hash the input
const startByte = toHex(curInput[0]); const curInput = makeSureIsBytes(input);
if (curInput.length !== 33 && curInput.length !== 65) { const hash160 = toHex(hash160Func(curInput));
return "Input is wrong length. Should be either 33 or 65 bytes, but is: " + curInput.length; // We do segwit addresses first.
} if (args[1] === "Segwit (P2WPKH bc1 Addresses)") {
if (curInput.length === 33 && startByte !== "03" && startByte !== "02") { const redeemScript = hash160;
return "Input is 33 bytes, but begins with invalid byte: " + startByte; const hrp = getHumanReadablePart(args[0]);
} if (hrp !== "") {
if (curInput.length === 65 && startByte !== "04") {
return "Input is 65 bytes, but begins with invalid byte: " + startByte;
}
if (args[0] === "Ethereum") {
// Ethereum addresses require uncompressed public keys.
if (startByte !== "04" || curInput.length !== 65) {
return "Ethereum addresses require uncompressed public keys.";
}
const algo = JSSHA3.keccak256;
// We need to redo the hex-> bytes transformation here because Javascript is silly.
// sometimes what is desired is an array of ints.
// Other times a string
// Here, the Keccak algorithm seems to want an array of ints. (sigh)
let result;
if (inputIsHex) {
result = algo(Utils.convertToByteArray(input, "hex").slice(1,));
} else {
result = algo(Utils.convertToByteArray(toHex(input), "hex").slice(1,));
}
return "0x" + result.slice(-40);
} else {
// We hash the input
const hash160 = toHex(hash160Func(curInput));
// We do segwit addresses first.
if (args[1] === "Segwit (P2WPKH)") {
const redeemScript = hash160;
const hrp = getHumanReadablePart(args[0]);
return encodeProgramToSegwit(hrp, 0, Utils.convertToByteArray(redeemScript, "hex")); return encodeProgramToSegwit(hrp, 0, Utils.convertToByteArray(redeemScript, "hex"));
}
// It its not segwit, we create the redeemScript either for P2PKH or P2SH-P2WPKH addresses.
const versionByte = "P2PKH (V1 BTC Addresses)" === args[1] ? getP2PKHVersionByte(args[0]) : getP2SHVersionByte(args[0]);
// If its a P2SH-P2WPKH address, we have to prepend some extra bytes and hash again. Either way we prepend the version byte.
let hashRedeemedScript;
if (args[1] === "P2SH-P2PWPKH (Segwit Compatible)") {
const redeemScript = "0014" + hash160;
hashRedeemedScript = versionByte + toHex(hash160Func(fromArrayBuffer(Utils.convertToByteArray(redeemScript, "hex"))));
} else { } else {
hashRedeemedScript = versionByte + hash160; return args[0] + " does not support Segwit Addresses.";
} }
// We calculate the checksum, convert to Base58 and then we're done!
const checksumHash = toHex(doubleSHA(fromArrayBuffer(Utils.convertToByteArray(hashRedeemedScript, "hex"))));
const finalString = hashRedeemedScript + checksumHash.slice(0, 8);
const address = base58Encode(Utils.convertToByteArray(finalString, "hex"));
return address;
} }
// It its not segwit, we create the redeemScript either for P2PKH or P2SH-P2WPKH addresses.
const versionByte = "P2PKH (V1 BTC Addresses)" === args[1] ? getP2PKHVersionByte(args[0]) : getP2SHVersionByte(args[0]);
// If its a P2SH-P2WPKH address, we have to prepend some extra bytes and hash again. Either way we prepend the version byte.
let hashRedeemedScript;
if (args[1] === "P2SH-P2PWPKH (Segwit Compatible V3 Addresses)") {
const redeemScript = "0014" + hash160;
hashRedeemedScript = versionByte + toHex(hash160Func(fromArrayBuffer(Utils.convertToByteArray(redeemScript, "hex"))));
} else {
hashRedeemedScript = versionByte + hash160;
}
// We calculate the checksum, convert to Base58 and then we're done!
const checksumHash = toHex(doubleSHA(fromArrayBuffer(Utils.convertToByteArray(hashRedeemedScript, "hex"))));
const finalString = hashRedeemedScript + checksumHash.slice(0, 8);
const address = base58Encode(Utils.convertToByteArray(finalString, "hex"));
return address;
} }

View file

@ -129,6 +129,7 @@ import "./tests/DecryptKeyStoreFile.mjs";
import "./tests/WIFToPrivateKey.mjs"; import "./tests/WIFToPrivateKey.mjs";
import "./tests/SeedphraseToSeed.mjs"; import "./tests/SeedphraseToSeed.mjs";
import "./tests/DeserializeExtendedKey.mjs"; import "./tests/DeserializeExtendedKey.mjs";
import "./tests/PublicKeyToETHStyleAddress.mjs";
import "./tests/GetAllCasings.mjs"; import "./tests/GetAllCasings.mjs";
import "./tests/SIGABA.mjs"; import "./tests/SIGABA.mjs";
import "./tests/ELFInfo.mjs"; import "./tests/ELFInfo.mjs";

View file

@ -34,8 +34,8 @@ TestRegister.addTests([
"args": [false] "args": [false]
}, },
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To ETH Style Address",
"args": ["Ethereum", "P2PKH (V1 BTC Addresses)"] "args": []
} }
] ]

View file

@ -50,7 +50,7 @@ TestRegister.addTests([
{ {
name: "Private EC Key to Public (Wrong Length)", name: "Private EC Key to Public (Wrong Length)",
input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08", input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08",
expectedOutput: "Must pass a hex string of length 64, or a byte string of length 32. Got length 66", expectedOutput: "Error with the input as private key. Error is:\n\tInvalid length. We want either 32 or 64 but we got: 66",
recipeConfig: [ recipeConfig: [
{ {
"op": "Private EC Key to Public Key", "op": "Private EC Key to Public Key",
@ -61,7 +61,7 @@ TestRegister.addTests([
{ {
name: "Private EC Key to Public (From Bytes Uncompressed Wrong Length)", name: "Private EC Key to Public (From Bytes Uncompressed Wrong Length)",
input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08", input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08",
expectedOutput: "Must pass a hex string of length 64, or a byte string of length 32. Got length 33", expectedOutput: "Error with the input as private key. Error is:\n\tInvalid length. We want either 32 or 64 but we got: 33",
recipeConfig: [ recipeConfig: [
{ {
"op": "From Hex", "op": "From Hex",

View file

@ -61,7 +61,7 @@ TestRegister.addTests([
{ {
name: "Private Key To WIF (BTC, Compressed, Wrong Number of Bytes)", name: "Private Key To WIF (BTC, Compressed, Wrong Number of Bytes)",
input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08", input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08",
expectedOutput: "Must pass a hex string of length 64, or a byte string of length 32. Got length: 66", expectedOutput: "Error parsing private key. Error is:\n\tInvalid length. We want either 32 or 64 but we got: 66",
recipeConfig: [ recipeConfig: [
{ {
"op": "To WIF Format", "op": "To WIF Format",
@ -72,7 +72,7 @@ TestRegister.addTests([
{ {
name: "Private Key To WIF (BTC, Compressed, Wrong Number of Bytes)", name: "Private Key To WIF (BTC, Compressed, Wrong Number of Bytes)",
input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08", input: "5E2A8FDE9F861056607208F512287CFBD634E124044EE23EBF7289E8E7B3822E08",
expectedOutput: "Must pass a hex string of length 64, or a byte string of length 32. Got length: 33", expectedOutput: "Error parsing private key. Error is:\n\tInvalid length. We want either 32 or 64 but we got: 33",
recipeConfig: [ recipeConfig: [
{ {
"op": "From Hex", "op": "From Hex",

View file

@ -0,0 +1,110 @@
/**
* Public Key to ETH Style Address Cryptocurrency Address tests.
*
* @author dgoldenberg [virtualcurrency@mitre.org]
* @copyright MITRE 2023
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Public Key To ETH Style Address",
input: "04d26bcecd763bdf6bdb89ba929d2485429fbda73bae723d525ef55554ef45350582085bd24055079f6deebad5b6af612c14587c6862391d330484afe750fbf144",
expectedOutput: "0x63e8b85679d29235791a0f558d6485c7ed51c9e6",
recipeConfig: [
{
"op": "Public Key To ETH Style Address",
"args": []
},
],
},
{
name: "Public Key To ETH Style Address 2",
input: "047d3e5107b46421c3ddf7292fcbe1f5805952279926c325d119f6ddfed1e5e7ea9a9f5dceadc57b897cb286479450b66a6422f8f270bcd2a61ab4eea800911956",
expectedOutput: "0x099f75d5bc069026531394d5c6d6c37a41158d31",
recipeConfig: [
{
"op": "Public Key To ETH Style Address",
"args": []
},
],
},
{
name: "Public Key to ETH Style Address: Compressed Key",
input: "027d3e5107b46421c3ddf7292fcbe1f5805952279926c325d119f6ddfed1e5e7ea",
expectedOutput: "0x099f75d5bc069026531394d5c6d6c37a41158d31",
recipeConfig: [
{
"op": "Public Key To ETH Style Address",
"args": []
},
],
},
{
name: "Public Key to ETH Style Address: Compressed Key 2",
input: "039d491d3f5a2a79b422b76b8115b175b38e42c6103b1a84c88fb6221fe9072bbe",
expectedOutput: "0x345029d286159d516ca1169edf0a80ff6c855ac0",
recipeConfig: [
{
"op": "Public Key To ETH Style Address",
"args": [],
},
],
},
{
name: "Public Key to ETH Style Address: Compressed Key (From Hex)",
input: "027d3e5107b46421c3ddf7292fcbe1f5805952279926c325d119f6ddfed1e5e7ea",
expectedOutput: "0x099f75d5bc069026531394d5c6d6c37a41158d31",
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Public Key To ETH Style Address",
"args": []
},
],
},
{
name: "Public Key to ETH Style Address: Compressed Key 2 (From Hex)",
input: "039d491d3f5a2a79b422b76b8115b175b38e42c6103b1a84c88fb6221fe9072bbe",
expectedOutput: "0x345029d286159d516ca1169edf0a80ff6c855ac0",
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Public Key To ETH Style Address",
"args": [],
},
],
},
{
name: "Public Key To ETH Style Address (From Hex)",
input: "04d26bcecd763bdf6bdb89ba929d2485429fbda73bae723d525ef55554ef45350582085bd24055079f6deebad5b6af612c14587c6862391d330484afe750fbf144",
expectedOutput: "0x63e8b85679d29235791a0f558d6485c7ed51c9e6",
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Public Key To ETH Style Address",
"args": []
},
],
},
]);

View file

@ -32,6 +32,17 @@ TestRegister.addTests([
}, },
], ],
}, },
{
name: "Public Key To Address: P2PKH LTC",
input: "037b39f764a10f31bfd47038738ca27bffeefce1fe4ccbfb9343fcb69d9363b27b",
expectedOutput: "LPTR2TBuF8vbwWaJdNeCAQemW4SC7q7zJP",
recipeConfig: [
{
"op": "Public Key To Cryptocurrency Address",
"args": ["LTC", "P2PKH (V1 BTC Addresses)"]
},
],
},
{ {
name: "Public Key To Address: P2PKH (Long)", name: "Public Key To Address: P2PKH (Long)",
input: "04219A19E157B5FEDDF7EBDD3C7A58D7AB4F6565E84226691B6A5F80BBCE8E0100B49D6AB503CA4B701626E941EB8D2460F154992D7AD4EC671CF1CFB8C1DE8164", input: "04219A19E157B5FEDDF7EBDD3C7A58D7AB4F6565E84226691B6A5F80BBCE8E0100B49D6AB503CA4B701626E941EB8D2460F154992D7AD4EC671CF1CFB8C1DE8164",
@ -50,7 +61,7 @@ TestRegister.addTests([
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["BTC", "P2SH-P2PWPKH (Segwit Compatible)"] "args": ["BTC", "P2SH-P2PWPKH (Segwit Compatible V3 Addresses)"]
}, },
], ],
}, },
@ -61,7 +72,18 @@ TestRegister.addTests([
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["BTC", "P2SH-P2PWPKH (Segwit Compatible)"] "args": ["BTC", "P2SH-P2PWPKH (Segwit Compatible V3 Addresses)"]
},
],
},
{
name: "Public Key To Address: P2SH-P2WPKH LTC",
input: "02f442a169ca36702bbcbb268319295bece8fe1cbc6ca095b2669d13ef56c759de",
expectedOutput: "MMwYiJmkxDKqiP2WWAHMMgkeRt2nLxGqih",
recipeConfig: [
{
"op": "Public Key To Cryptocurrency Address",
"args": ["LTC", "P2SH-P2PWPKH (Segwit Compatible V3 Addresses)"]
}, },
], ],
}, },
@ -72,7 +94,7 @@ TestRegister.addTests([
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["BTC", "Segwit (P2WPKH)"] "args": ["BTC", "Segwit (P2WPKH bc1 Addresses)"]
}, },
], ],
}, },
@ -83,21 +105,20 @@ TestRegister.addTests([
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["BTC", "Segwit (P2WPKH)"] "args": ["BTC", "Segwit (P2WPKH bc1 Addresses)"]
}, },
], ],
}, },
{ {
name: "Public Key To Address: (ETH)", name: "Public Key To Address: P2WPKH LTC",
input: "04d26bcecd763bdf6bdb89ba929d2485429fbda73bae723d525ef55554ef45350582085bd24055079f6deebad5b6af612c14587c6862391d330484afe750fbf144", input: "026a532c31184b94edf540ad60c3cc208342be4f51cc764a373a420731dd198a59",
expectedOutput: "0x63e8b85679d29235791a0f558d6485c7ed51c9e6", expectedOutput: "ltc1qj587punda8h0r4m83k794xseqlnl3az4ktu2zp",
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["Ethereum", "Segwit (P2WPKH)"] "args": ["LTC", "Segwit (P2WPKH bc1 Addresses)"]
}, },
], ],
}, },
{ {
name: "Public Key To Address: (Testnet)", name: "Public Key To Address: (Testnet)",
@ -114,29 +135,29 @@ TestRegister.addTests([
{ {
name: "Public Key To Address: P2WPKH (Wrong Length)", name: "Public Key To Address: P2WPKH (Wrong Length)",
input: "03bc32bdc5dc96c9fb56e2481fefd321ebe9e17a807bbb337dea1df5e68b1f075642", input: "03bc32bdc5dc96c9fb56e2481fefd321ebe9e17a807bbb337dea1df5e68b1f075642",
expectedOutput: "Input is wrong length. Should be either 33 or 65 bytes, but is: 34", expectedOutput: "Invalid length. We want either 33, 65 (if bytes) or 66, 130 (if hex) but we got: 68",
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["BTC", "Segwit (P2WPKH)"] "args": ["BTC", "Segwit (P2WPKH bc1 Addresses)"]
}, },
], ],
}, },
{ {
name: "Public Key To Address: P2WPKH (Wrong Start)", name: "Public Key To Address: P2WPKH (Wrong Start)",
input: "05bc32bdc5dc96c9fb56e2481fefd321ebe9e17a807bbb337dea1df5e68b1f0756", input: "05bc32bdc5dc96c9fb56e2481fefd321ebe9e17a807bbb337dea1df5e68b1f0756",
expectedOutput: "Input is 33 bytes, but begins with invalid byte: 05", expectedOutput: "We have a valid hex string, of reasonable length, (66) but doesn't start with the right value. Correct values are 02, or 03 but we have: 05",
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
"args": ["BTC", "Segwit (P2WPKH)"] "args": ["BTC", "Segwit (P2WPKH bc1 Addresses)"]
}, },
], ],
}, },
{ {
name: "Public Key To Address: P2PKH (Long With Error)", name: "Public Key To Address: P2PKH (Long With Error)",
input: "06219A19E157B5FEDDF7EBDD3C7A58D7AB4F6565E84226691B6A5F80BBCE8E0100B49D6AB503CA4B701626E941EB8D2460F154992D7AD4EC671CF1CFB8C1DE8164", input: "06219A19E157B5FEDDF7EBDD3C7A58D7AB4F6565E84226691B6A5F80BBCE8E0100B49D6AB503CA4B701626E941EB8D2460F154992D7AD4EC671CF1CFB8C1DE8164",
expectedOutput: "Input is 65 bytes, but begins with invalid byte: 06", expectedOutput: "We have a valid hex string of reasonable length, (130) but doesn't start with the right value. Correct values are 04 but we have: 06",
recipeConfig: [ recipeConfig: [
{ {
"op": "Public Key To Cryptocurrency Address", "op": "Public Key To Cryptocurrency Address",
@ -159,16 +180,4 @@ TestRegister.addTests([
} }
], ],
}, },
{
name: "Public Key To Address: (ETH Compressed Key)",
input: "03ebf60a619da2fbc6239089ca0a93878ea53baa3d22188cacad4033b103237ae9",
expectedOutput: "Ethereum addresses require uncompressed public keys.",
recipeConfig: [
{
"op": "Public Key To Cryptocurrency Address",
"args": ["Ethereum", "Segwit (P2WPKH)"]
},
],
}
]); ]);

View file

@ -21,6 +21,21 @@ TestRegister.addTests([
} }
], ],
}, },
{
name: "Seed To Master Private Key (xprv) From Hex",
input: "c766f48d3729a16249b5d0171c678d458d31454b2bb7791b61169b5541a130719714ebd41f22a2515246d013e9a4e978aee48dd5140b73a540108d58008c4aa9",
expectedOutput: "xprv9s21ZrQH143K2nwujwREGif1wyBwt5Jh9BdFVSgSeYdrUp1qPxKsHrmnpJ8xKpKPDvXJMmBRpsZ3X64MeafyURs8Xoj53kGu7hb48Yg7unj",
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Seed To Master Key",
"args": ["xprv"]
}
],
},
{ {
name: "Seed To Master Private Key (tprv)", name: "Seed To Master Private Key (tprv)",
input: "c766f48d3729a16249b5d0171c678d458d31454b2bb7791b61169b5541a130719714ebd41f22a2515246d013e9a4e978aee48dd5140b73a540108d58008c4aa9", input: "c766f48d3729a16249b5d0171c678d458d31454b2bb7791b61169b5541a130719714ebd41f22a2515246d013e9a4e978aee48dd5140b73a540108d58008c4aa9",